Witam,
Mam pytanie do Was w jaki sposób mogę zapisać pozycję kursora na danym oknie, tak aby po jego zmniejszeniu, przesunięciu - kursor zawsze ustawił się w tym samym miejscu. Ale, żeby nie było tak łatwo - to trzeba wziąć pod uwagę możliwość przesunięcia komponentu na formie.
W związku z tym obecnie w swoim projekcie przy zapisywaniu pozycji kursora robię to na 3 sposoby pobierając wszystkie możliwe koordynaty okna/kontrolki:
Zapis do bazy:
// funkcje pobierające dane koordynacyjne
WinControl_Handle := WindowFromPoint(pt); // uchwyt kontrolki nad którą znajduje się kursor
Window_ClassName := GetWindowClass(pt); // nazwa klasy okna np. TForm
Control_ClassName := string(Trim(GetWinControlName(WinControl_Handle))); // nazwa projektowa np. btnPolacz
Control_Caption := GetCaptionAtPoint(pt); // caption komponentu np. 'Połącz'
Control_Pos_Left := GetControlPos(WinControl_Handle).Left;
Control_Pos_Top := GetControlPos(WinControl_Handle).Top;
Window_Pos_Left := GetWindowPos(Window_ClassName).Left;
Window_Pos_Top := GetWindowPos(Window_ClassName).Top;
// pt.X i pt.Y to pozycja aktualnej pozycji kursora na ekranie
IBSQL1.SQL.Add('insert into tasks ' +
'(window_name, control_name, control_caption, mouse_pos_x, mouse_pos_y, ' +
'mouse_control_click_left, mouse_control_click_top, mouse_control_left, mouse_control_top) ' +
'VALUES ' +
'(:window_name, :control_name, :control_caption, :mouse_pos_x, :mouse_pos_y, ' +
':mouse_control_click_left, :mouse_control_click_top, :mouse_control_left, :mouse_control_top)');
IBSQL1.ParamByName('window_name').Value := Window_ClassName;
IBSQL1.ParamByName('control_name').Value := Control_ClassName;
IBSQL1.ParamByName('control_caption').Value := Control_Caption;
// 1 sposób
IBSQL1.ParamByName('mouse_pos_x').Value := IntToStr(pt.X - Window_Pos_Left); // pozycja myszki na okienku
IBSQL1.ParamByName('mouse_pos_y').Value := IntToStr(pt.Y - Window_Pos_Top); // pozycja myszki na okienku
// 2 sposób
IBSQL1.ParamByName('mouse_control_click_left').Value := IntToStr(pt.X - Control_Pos_Left); // pozycja klikniecia na kontrolce
IBSQL1.ParamByName('mouse_control_click_top').Value := IntToStr(pt.Y - Control_Pos_Top); // pozycja klikniecia na kontrolce
// 3 sposób
IBSQL1.ParamByName('mouse_control_left').Value := IntToStr(Control_Pos_Left); // pozycja kontrolki na oknie
IBSQL1.ParamByName('mouse_control_top').Value := IntToStr(Control_Pos_Top); // pozycja kontrolki na oknie
Mając takie dane jak:
pozycja kursora na okienku (czyli okienko X = 0. Y = 0, Kursor: X = 30, Y = 60)
pozycja klikniecia na kontrolce (czyli button.X = 2 button.Y = 4)
pozycja kontrolki na oknie (czyli button.left = 120, button.top = 200)
teoretycznie powinienem móc później bez problemu odczytać pozycję danej kontrolki w oknie nie zależnie w którym miejscu się znajduje sama kontrolka jak i okno.
ODCZYT
W dalszej części projektu szukam okienka poprzez FindWindow podając jako paramentr zmienną WINDOW_NAME, gdzie przechowywana jest wcześniej zapisana nazwa okna (klasa oraz caption z CONTROL_CAPTION) oraz pobieram jego HWND.
Następnie na okienku robię
EnumChildWindows(HWND, @EnumChildWinProc, 0);
co zwraca mi listę komponentów na oknie i ładuję je do KBM.
function EnumChildWinProc(AHandle: HWND): boolean; stdcall;
var
ControlClass, ControlText : array[0..255] of Char;
begin
Result := True;
GetClassName(AHandle, ControlClass, SizeOf(ControlClass));
SendMessage(AHandle, WM_GETTEXT, SizeOf(ControlText), integer(@ControlText));
with frmMenu do
begin
// Dodaj do kbmControlInfo informacje o kontrolkach
kbmControlInfo.Append;
kbmControlInfoHandle.Value := AHandle;
kbmControlInfoControlName.Value := GetWinControlName(AHandle);
kbmControlInfoControlClass.Value := ControlClass;
kbmControlInfoControlCaption.Value := ControlText;
kbmControlInfoControlCount.Value := ControlCnt;
kbmControlInfoControlPos_Left.Value := GetControlPos(AHandle).Left; // pozycja kontrolki na oknie
kbmControlInfoControlPos_Top.Value := GetControlPos(AHandle).Top; // pozycja kontrolki na oknie
kbmControlInfo.Post;
ControlCnt := ControlCnt + 1;
end;
end;
Przypisuję zmienne z datasetu w którym trzymam wcześniej zapisane instrukcje:
Window_ClassName := IBDataSet_InstructionsWINDOW_NAME.Value;
Control_ClassName := IBDataSet_InstructionsCONTROL_NAME.Value;
Control_Caption := IBDataSet_InstructionsCONTROL_CAPTION.Value;
Kolejnym krokiem jest wyszukanie w KBM kontrolki która wcześniej zapisaliśmy i wczytaliśmy do grida. Robię to poprzez funkcję LOCATE:
var
ControlFound: boolean
begin // znajdź wiersz z nazwą kontrolki
ControlFound := kbmControlInfo.Locate('ControlName', Control_ClassName, []);
W ten sposób odnajduję np. button o nazwie 'Połącz' lub Panel.
Kolejnym krokiem jest pobranie AKTUALNYCH danych pozycji okienka i kontrolki i przypisanie z datasetu do zmiennych.
MouseClick_Pos_X := IBDataSet_InstructionsMOUSE_POS_X.Value;
MouseClick_Pos_Y := IBDataSet_InstructionsMOUSE_POS_Y.Value;
MouseControlClick_Left := IBDataSet_InstructionsMOUSE_CONTROL_CLICK_LEFT.Value;
MouseControlClick_Top := IBDataSet_InstructionsMOUSE_CONTROL_CLICK_TOP.Value;
MouseControl_Pos_Left := IBDataSet_InstructionsMOUSE_CONTROL_LEFT.Value;
MouseControl_Pos_Top := IBDataSet_InstructionsMOUSE_CONTROL_TOP.Value;
Window_Pos_Left := GetWindowPos(Window_ClassName).Left;
Window_Pos_Top := GetWindowPos(Window_ClassName).Top;
kmbControl_Pos_Left := kbmControlInfoControlPos_Left.Value;
kmbControl_Pos_Top := kbmControlInfoControlPos_Top.Value;
A tera zaczyna się MAGIA:
Ustawienie kursora na pozycji realizuję poprzez:
// Jeśli Caption jest pusty lub nie znaleziono kontrolki na formie i nazwa klasy kontrolki nie jest pusta
if ((Trim(Control_Caption) = '') or not ControlFound) and not (Control_ClassName = '') then
begin // ustaw pozycję kursora w okienku w miejscu gdzie zapisaliśmy pozycję kursora
SetCursorPos(Window_Pos_Left + MouseClick_Pos_X, Window_Pos_Top + MouseClick_Pos_Y)
// tu właśnie jest pewien problem bo w niektórych przypadkach działa powyższa funkcja a w niektórych poniższa
//SetCursorPos(MouseControlClick_Left + kmbControl_Pos_Left, MouseControlClick_Top + kmbControl_Pos_Top);
end else // jeśli caption nie jest pusty lub kontrolka jest na formie i nie ma nazwy klasy
begin
if (Control_Caption <> '') then // jesli ma caption
begin // wyszukaj na liście po captionie np. Buttona o nazwie 'Połącz'
if kbmControlInfo.Locate('ControlCaption', Control_Caption, []) then
SetCursorPos(Window_Pos_Left + MouseClick_Pos_X, Window_Pos_Top + MouseClick_Pos_Y) // znalazł
else
SetCursorPos(MouseControlClick_Left + kmbControl_Pos_Left, MouseControlClick_Top + kmbControl_Pos_Top);
end else
begin
SetCursorPos(MouseControlClick_Left + MouseControl_Pos_Left, MouseControlClick_Top + MouseControl_Pos_Top);
end;
end;
Szczerze to kod powyżej jest straszny i założę się, że odczyt można zrobić w prostszy sposób max 1 IF.
Dość obszerny kod ale mam nadzieję, że wszystko jest jasne i będziecie w stanie mi pomóc.
Reasumując wszystko:
Potrzebuję funkcję która ustawi mi dokładnie kursor na pozycji w którą wcześniej zapisaliśmy do bazy.
**Dane jakie mam: **
- Pozycja okna na ekranie
- Pozycja kontrolki na oknie
- Pozycja kliknięcia na kontrolce
- Nazwa klasy okna (jest zawsze)
- Nazwa klasy kontrolki (nie zawsze jest)
- Caption kontrolki/okna (nie zawsze jest)
Powyższy schemat działa w większości dobrze, ale NIE ZAWSZE a musi zawsze bo inaczej jestem w dupie. ;/