View Full Version : بدست اوردن کنترل فعال در یک application
  
bmanfy
دوشنبه 11 مرداد 1389, 15:31 عصر
سلامک دوستان من تو فرم اصلی فرم برنامه ام یک شی application event قرار دادم که با استفاده از اون کلید های سراسری برنامه رو تعریف کردم . 
مثلا اگر کلید F1 در کل برنامه فشرده بشه راهنما ی برنامه باز بشه .
و حالا میخوام وقتی کلید خاصی رو فشرد کنترلی که در کل برنامه مکان نما رو در اختیار داره رو دریافت کنه مثلا فرض کنید تو کل برنامه اگر کلید Cltrl+T فشرده شده بشه و کنترلی که هم اکنون مکان نما رو در اختیا رداشته باشه از نوع TEdit باشه مقدارش رو برابر با زمان فعلی سیستم قرار بده .
عملابا بخش اول(بدست اوردن کلید فشرده شده) و اخر(انتساب زمان) مشکلی ندارم  و تنها مشکل در بخش دوم یعنی بدست اوردن کنترل فعال بر برنامه است .
ممنون از همگی.
مهران رسا
دوشنبه 11 مرداد 1389, 18:02 عصر
مثلا فرض کنید تو کل برنامه اگر کلید Cltrl+T فشرده شده بشه و کنترلی که هم  اکنون مکان نما رو در اختیا رداشته باشه از نوع TEdit باشه مقدارش رو  برابر با زمان فعلی سیستم قرار بده .
خب در رویداد Edit کدتون رو بنویسید !
Felony
دوشنبه 11 مرداد 1389, 18:38 عصر
به وسیله تابع GetFocus میتونید هندل کنترل جاری رو بگیرید ، براتون یه نمونه نوشتم ، کد زیر رو در رویداد OnKeyPress فرم برنامتون بنویسید :
var
  i: Integer;
  CurControl_HWND: THandle;
  CurControl_Str: String;
begin
  // Get current control handle
  CurControl_HWND:= GetFocus;
  // Check all control on form & find control that Handle of it = CurControl
  for i:= 0 to Self.ComponentCount - 1 do
  begin
    if Components[i] is TWinControl then
      if CurControl_HWND<> TWinControl(Components[i]).Handle then
        Continue
      else
      begin
        CurControl_Str:= TWinControl(Components[i]).ClassName;
        if CurControl_Str= 'TEdit' then
          TEdit(Components[i]).Text:= DateToStr(Now);
        if CurControl_Str= 'TMemo' then
          TMemo(Components[i]).Lines.Add(DateToStr(Now));
        if CurControl_Str= 'TButton' then
          ShowMessage('This is a TButton control');
      end;
  end;
tdkhakpur
دوشنبه 11 مرداد 1389, 19:06 عصر
var
 str : string;
begin
 str := 'demo';
 SendMessage(GetFocus(), WM_SETTEXT, 0, WPARAM(str));
end;
Felony
دوشنبه 11 مرداد 1389, 22:22 عصر
var
 str : string;
begin
 str := 'demo';
 SendMessage(GetFocus(), WM_SETTEXT, 0, WPARAM(str));
end;
رو در اختیا رداشته باشه از نوع TEdit باشه مقدارش رو برابر با زمان فعلی سیستم قرار بده .
کد شما درست عمل میکنه ولی نمیشه روش کنترلی داشت ، یعنی نمیشه تعیین کرد اگر کنترل جاری از کلاس TEdit بود بعد متن رو درج کنه ، در این صورت تو برنامه رو هر کنترلی که فوکوس شده باشه متنش عوض میشه .
tdkhakpur
دوشنبه 11 مرداد 1389, 23:59 عصر
یعنی نمیشه تعیین کرد اگر کنترل جاری از کلاس TEdit بود بعد متن رو درج کنه ، در این صورت تو برنامه رو هر کنترلی که فوکوس شده باشه متنش عوض میشه 
کار چندان سختی نیست
var
  ptr    : array [0..256] of char;
  str    : string;
begin
 str := 'Demo';
 GetClassName( GetFocus(), ptr, 256);
 if AnsiString(ptr)= 'TEdit' then
  SendMessage(GetFocus(), WM_SETTEXT, 0, WPARAM(str));
end;
bmanfy
سه شنبه 12 مرداد 1389, 00:16 صبح
ممنون از پاسخ همگی 
خب در رویداد Edit کدتون رو بنویسید
این نمیشه و یه کمی غیر منطقی میشه چون برنامه ای هست که نوشتم و حدودا 100 تا فرم داره و تو هر فرم هم کلی جعبه متن و خیلی سخت و طولانی میشه و ....
و راه حل بعدی :
به وسیله تابع GetFocus میتونید هندل کنترل جاری رو بگیرید ، براتون یه نمونه نوشتم ، کد زیر رو در رویداد OnKeyPress فرم برنامتون بنویسید :
ممنون از نمونه کدی که نوشتید . کدی نوشتید برای تک تک فرم ها نوشته در حالی که من قصد دارم رو فرم اصلی برنامه بنویسم و بتونم کنترل فعال رو در هر فرمی که فعال باشه به دست بیارم .
و در ضمن فکر میکنم یک مقداری کدی که نوشتید رو میشه راحتر تر هم نوشت برای هر فرم به صورت زیر :
    if ActiveControl.ClassType = TEdit then
       TEdit(ActiveControl).Text := 'edit'
    else if ActiveControl.ClassType = TMemo then
       TMemo(ActiveControl).Lines.Text := 'mamo'
bmanfy
سه شنبه 12 مرداد 1389, 00:22 صبح
در باره راه حل tdkhalpur هم که مشکلی که داشت اشاره شد و برای رفع مشکلش هم کدی دوباه ارائه دادند . و البته درست هم است .
اما هنوز کار من رو راه نمیندازه . 
اجازه بدین یه کم صورت مسئله رو باز تر کنم :
حالا بعد از این که نوع کلاس شی فعال مشخص شد میخوام بتونم شی فعال رو به متغیری از همون نوع کلاس ارسال کنم تا بتونم کلیه خصوصیات اون رو بررسی کنم و با توجه به این خصوصیات مقدار جدید که لازم دارم رو به اون انتساب بدم :
فرض کنید میخوام کنترل های نوع TMaskEdit رو دریافت و چک کنم که EditMask اون چیه و توجه به خصوصیت مقدار Text اون رو مشخص کنم .
bmanfy
سه شنبه 12 مرداد 1389, 00:25 صبح
ببخشید یک سوالی که یادم رفت بپرسم درباره THandel این چه نوعیه و یا HWND دقیقا اینا چیه؟ و به چه شکل میشه از اینها استفاده کرد؟ و کجا کاربرد داره ؟
ممنون ار همگی
tdkhakpur
سه شنبه 12 مرداد 1389, 01:34 صبح
فرض کنید میخوام کنترل های نوع TMaskEdit رو دریافت و چک کنم که EditMask اون چیه و توجه به خصوصیت مقدار Text اون رو مشخص کنم 
برای این کار شما باید از تنظیمات خود اشیا استفاده کنید یعنی با استفاده از خصوصیات شی پیدا شده شی جدید از همان نوع ایجاد کنید به این شکل :
var
  tmpEdit : TEdit;
begin
  tmpEdit := TEdit(ActiveControl).
  tmpEdit.Top := tmpEdit.Top+100;
end;
البته این کار صحیح نیست فقط برای زمانی که ساختار هر دو شی یکسان باشد میتواند جواب دقیق دهد چون ممکن هست یک شخص شیئی با همان نام را رجیستر کرده باشد که با شی شما متفاوت باشد.. 
 
درباره THandel این چه نوعیه و یا HWND دقیقا اینا چیه؟ و
هر دو یک مقدار عددی هستند که برای دسترسی به کنترلها استفاده میشود. 
 
به چه شکل میشه از اینها استفاده کرد؟ و کجا کاربرد داره 
خب بیشتر برای ارسال پیغام یا پیدا کردن نام یک کنترل و بسیاری جاهای دیگر .
bmanfy
سه شنبه 12 مرداد 1389, 02:15 صبح
برای این کار شما باید از تنظیمات خود اشیا استفاده کنید یعنی با استفاده از خصوصیات شی پیدا شده شی جدید از همان نوع ایجاد کنید به این شکل :
نه نه . نباید ساخته بشه که . 
اصلا خصوصیات شی پیدا شده رو بدسا اورد ؟
بزارین دقیق بگم میخوام چیکار کنم:
ببینید برنامه نوشتم که کلی فرم  داره و تو این فرم ها ای TMaskEdit  اسفاده کردم  برای ساعت و تاریخ 
حالا تو فرم اصلا برنامه یک aplictionEvent قرار دادم و می خوام مشخص بکنم در هر فرمی از برنامه اگر کلید مثلا f12 فشرده شد اگر شی از نوع TMaskEdit باشه و خصوصیت EditMask اون برابر باشه با 00/00/00  تو اون بیاد تاریخ روز رو وارد کنه و اگر خصوصیت EditMask اون00:00 باشه زمان فعلی رو وارد کنه .
کدهایی که گفتید درسته و خوب کار میکنه فقط میمونه چه ظوری EditMAsk شی رو چک کنم ؟
tdkhakpur
سه شنبه 12 مرداد 1389, 02:32 صبح
به فرض شما توانستید به کنترل دسترسی پیدا کنید و MaskEdit1 همانی هست که شما در نظر دارید خب با یک الگوریتم ساده بررسی کنید!!
var
  DateTime :SYSTEMTIME;
begin
  GetLocalTime(DateTime);
  if  MaskEdit1.Text = '00/00/00' then
    MaskEdit1.Text := IntTostr(DateTime.wYear)+ '/' +
                      IntTostr(DateTime.wMonth)+ '/' +
                      IntTostr(DateTime.wDay)
  else
    if  MaskEdit1.Text = '00:00:00' then
      MaskEdit1.Text := IntTostr(DateTime.wHour)+ ':' +
                      IntTostr(DateTime.wMinute)+ ':' +
                      IntTostr(DateTime.wSecond);
end;
Felony
سه شنبه 12 مرداد 1389, 14:06 عصر
اگر میخواین در تمام فرم های برنامه این کار رو انجام بدید یا باید کلیدهای صفحه کلید رو در سطح برنامه هوک کنید یا در تمام فرمهاتون این کد رو بنویسید ، یا یک تابع بنویسید و نام فرم جاری رو به عنوان پارامتر بهش بدید و تو همه فرم های برنامه تابع رو صدا بزنید و نام فرم جاری رو بهش پاس بدید و داخل تابع با فرم جاری کارهای مورد نظرتون رو انجام بدید .
SAASTN
چهارشنبه 13 مرداد 1389, 00:12 صبح
ربطی به سوال تاپیک نداره ولی به نظر من راه اصولی برای انجام چیزی که شما فرمودید اینه که TMaskEdit بازنویسی بشه:
type
  TMyMaskEdit = class(TMaskEdit)
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  end;
{ TMyMaskEdit }
procedure TMyMaskEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  if Key = VK_F12 then
    if EditMask = '00/00/00' then
      Text := '99/99/99';
end;
bmanfy
چهارشنبه 13 مرداد 1389, 01:32 صبح
فرض شما توانستید به کنترل دسترسی پیدا کنید و MaskEdit1 همانی هست که شما در نظر دارید خب با یک الگوریتم ساده بررسی کنید!!
با تشکر از پاسختون . این الگوریتم ساده رو بردم . مشکل من سر همون فرض ابتدایی است .
یعنی همین که بتونم کنترل رو بدست بیارم .
یعنی تو یه application چه طور میشه یک کنترل فعال رو تمام و کمال بدست اورد ؟
bmanfy
چهارشنبه 13 مرداد 1389, 01:34 صبح
اگر میخواین در تمام فرم های برنامه این کار رو انجام بدید یا باید کلیدهای صفحه کلید رو در سطح برنامه هوک کنید یا در تمام فرمهاتون این کد رو بنویسید ، یا یک تابع بنویسید و نام فرم جاری رو به عنوان پارامتر بهش بدید و تو همه فرم های برنامه تابع رو صدا بزنید و نام فرم جاری رو بهش پاس بدید و داخل تابع با فرم جاری کارهای مورد نظرتون رو انجام بدید . 
خب البته اگر بخوام که تو همه فرم ها بنویسم که ساد است . نه نمیخوام تو تمام فرم ها بنویسم .
فقط تو فرم اصلی برنامه . 
کلید رو هوک کردن یعنی چی ؟
bmanfy
چهارشنبه 13 مرداد 1389, 01:40 صبح
ربطی به سوال تاپیک نداره ولی به نظر من راه اصولی برای انجام چیزی که شما فرمودید اینه که TMaskEdit بازنویسی بشه:
خب اره . راه جل جالبیه . اما خب پروژه نوته شده و نمیشه تمام شی ها رو تعویض کزر دیگه  . 
البته فکر میکنم روشی که دارم خودم میگم خیلی راحت و بی دردسره . فقط مونده یه کاری رو انجام بدم .
بزارید دقیق بگم :
میخوام تو فرم اصلی برنامه کدی رو بنویسم که بتونه کنترلی رو که توی برنامه مکان نما رو در اختیار داره رو بگیره . (و نه اینکه رو خود فرم اصلی بلکه رو هر فرم دیگری هم اگر باشد)و
اصلا فرض کنید یک تایمر تو فرم اصلی قرار داره و مدام کنترلی رو که در سطح برنامه فعال است رو برمیگردونه .
Felony
چهارشنبه 13 مرداد 1389, 06:48 صبح
خب اره . راه جل جالبیه . اما خب پروژه نوته شده و نمیشه تمام شی ها رو تعویض کزر دیگه  . 
البته فکر میکنم روشی که دارم خودم میگم خیلی راحت و بی دردسره . فقط مونده یه کاری رو انجام بدم .
بزارید دقیق بگم :
میخوام تو فرم اصلی برنامه کدی رو بنویسم که بتونه کنترلی رو که توی برنامه مکان نما رو در اختیار داره رو بگیره . (و نه اینکه رو خود فرم اصلی بلکه رو هر فرم دیگری هم اگر باشد)و
اصلا فرض کنید یک تایمر تو فرم اصلی قرار داره و مدام کنترلی رو که در سطح برنامه فعال است رو برمیگردونه .
با استفاده از همون کد قبلی که براتون نوشتم میتونید این کار رو انجام بدید ، فقط باید کمی تغییر درش ایجا بشه ، کد جدیدی که براتون نوشتم این کار رو انجام میده :
var
  FormCount, ControlCount: Integer;
  CurControl_HWND: THandle;
  CurControl_Str: String;
  CurControl_TC: TComponent;
begin
  // Get current control handle
  CurControl_HWND:= GetFocus;
  // Check all control on form & find control that Handle of it = CurControl
  for FormCount:= 0 to Application.ComponentCount - 1 do
    if Application.Components[FormCount] is TForm then
      for ControlCount:= 0 to TForm(Application.Components[FormCount]).ComponentCount - 1 do
      begin
        CurControl_TC:= TForm(Application.Components[FormCount]).Components[ControlCount];
        if  CurControl_TC is TWinControl then
          if CurControl_HWND<> TWinControl(CurControl_TC).Handle then
            Continue
          else
          begin
            CurControl_Str:= TWinControl(CurControl_TC).ClassName;
            if CurControl_Str= 'TEdit' then
              TEdit(CurControl_TC).Text:= DateToStr(Now);
            if CurControl_Str= 'TMemo' then
              TMemo(CurControl_TC).Lines.Add(DateToStr(Now));
            if CurControl_Str= 'TMaskEdit' then
              if TMaskEdit(CurControl_TC).EditMask = '!90:00;1;_' then
                TMaskEdit(CurControl_TC).Text:= '06:15';
          end;
      end;
end;
bmanfy
چهارشنبه 13 مرداد 1389, 12:22 عصر
ممنون از كدي كه نوشتين . 
تو اين كد شما تمام فرم ها و كنترل ها رو پيمايش كردين .
يعني كد مستقيمي وجود نداره كه بتونه كنترل فعال رو بده ؟مثل همين GetFocus.
يا از روي همين Handle كه با تابع GetFocus بدست مياد مستقيم رفت سر كنترل فعال؟
Felony
چهارشنبه 13 مرداد 1389, 14:14 عصر
ممنون از كدي كه نوشتين . 
تو اين كد شما تمام فرم ها و كنترل ها رو پيمايش كردين .
يعني كد مستقيمي وجود نداره كه بتونه كنترل فعال رو بده ؟مثل همين GetFocus.
يا از روي همين Handle كه با تابع GetFocus بدست مياد مستقيم رفت سر كنترل فعال؟
کد مستقیم چه نوع داده ای به شما برگشت بده ؟!
الان شما مثلا تو فرم 7 برنامتون و روی کنترل Edit شماره 20 هستید ، تایع باید چی به عنوان کنترل جاری به شما بده ؟ مثلا تابعی مثل ActiveControl باشه و وقتی صداش زدید مقدار بازگشتیش این باشه : Form7.Edit20 ؟!
در کل همچین فکری غیر منطقی هست ، این کد هم سرعتش خوب هست و هیچ مشکلی در پاسخگویی به نیاز شما نداره .
کد قبلی یک خط اضافی داشت که حذفش کردم :
var
  FormCount, ControlCount: Integer;
  CurControl_HWND: THandle;
  CurControl_Str: String;
  CurControl_TC: TComponent;
begin
  // Get current control handle
  CurControl_HWND:= GetFocus;
  // Check all control on form & find control that Handle of it = CurControl
  for FormCount:= 0 to Application.ComponentCount - 1 do
    if Application.Components[FormCount] is TForm then
      for ControlCount:= 0 to TForm(Application.Components[FormCount]).ComponentCount - 1 do
      begin
        CurControl_TC:= TForm(Application.Components[FormCount]).Components[ControlCount];
        if  CurControl_TC is TWinControl then
          if CurControl_HWND= TWinControl(CurControl_TC).Handle then
          begin
            CurControl_Str:= TWinControl(CurControl_TC).ClassName;
            if CurControl_Str= 'TEdit' then
              TEdit(CurControl_TC).Text:= DateToStr(Now);
            if CurControl_Str= 'TMemo' then
              TMemo(CurControl_TC).Lines.Add(DateToStr(Now));
            if CurControl_Str= 'TMaskEdit' then
              if TMaskEdit(CurControl_TC).EditMask = '!90:00;1;_' then
                TMaskEdit(CurControl_TC).Text:= '06:15';
          end;
      end;
end;
bmanfy
چهارشنبه 13 مرداد 1389, 15:01 عصر
ممنون از لطفتون. 
 اره اين كد رو كه ميدونم جواب ميده و درسته .
الان شما مثلا تو فرم 7 برنامتون و روی کنترل Edit شماره 20 هستید ، تایع باید چی به عنوان کنترل جاری به شما بده ؟ مثلا تابعی مثل ActiveControl باشه و وقتی صداش زدید مقدار بازگشتیش این باشه : Form7.Edit20 ؟!
در کل همچین فکری غیر منطقی هست ، این کد هم سرعتش خوب هست و هیچ مشکلی در پاسخگویی به نیاز شما نداره .
.
 البته اره اين هم هست . 
دستور مستقيم براي بدست اوردن فرمي كه اكتيو هست چي؟
bmanfy
چهارشنبه 13 مرداد 1389, 15:08 عصر
راستش من هميشه سعي ميكنم كوتاهترين كد رو بنويسم.
البته اگر بخواهيم با كد شما كار كنيم . ديگه لازم نيست فرم رو هم پيكايش كنيم . 
با ActiveControl كنترل فعال رو ميگيريم .
                          curControl_HWND := GetFocus;
                          for i:= 0 to Application.ComponentCount-1 do
                              begin
                                  if Application.Components[i] is TForm then
                                     begin
                                         curForm := TForm(Application.Components[i]);
                                         if curForm.Active then
                                            begin
                                                curControl := curForm.ActiveControl;
                                                if curControl.ClassType = TAdvMaskEdit then
                                                   begin
                                                       if TAdvMaskEdit(curControl).EditMask ='99/99/99;1;0' then
                                                          TAdvMaskEdit(curControl).Text := _Date
                                                       else if TAdvMaskEdit(curControl).EditMask ='99/99;1;0' then
                                                               TAdvMaskEdit(curControl).Text := _Time;
                                                   end;
                                            end;
حالا يك كد ميانبر براي فرم فعال ؟!!!!!
bmanfy
چهارشنبه 13 مرداد 1389, 15:35 عصر
ممنون از همگي دوستان 
جواب نهايي رو بدست اوردم كه به شكل زير است :
براي بدست اوردن كنترل فعال در سطح application ميتونيم از دستور زير استفاده كنيم :
screen.ActiveControl;
كه خروجي اون از نوع TWincontrol است .
و براي بدست اوردن فرم فعال نيز از دستور زير :
Screen.ActiveForm;
كه خروجي اين دستور از نوع TForm است .
و كد نهايي كه نوشتم هم به صورت زير است .
                          curControl := Screen.ActiveControl;
                          if (curControl.ClassType = TAdvMaskEdit) then
                              begin
                                  if TAdvMaskEdit(curControl).EditMask='99/99/99;1;0' then
                                     TAdvMaskEdit(curControl).Text := _Date
                                  else if (TAdvMaskEdit(curControl).EditMask='99:99;1;0') then
                                     TAdvMaskEdit(curControl).Text := _Time;
                              end;
 
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.