![]() |
Nach BringToFront wieder über Tasten navigieren?
Hallo liebe DPler,
ich schreibe gerade eine kleine Anwendung für einen Freund in Lazarus (0.9.30.4). Im Prinzip werden nur ein paar Werte in eine Liste gepackt (per Button) und abhängig von den bisherigen Werten verschiedene Möglichkeiten in Betracht gezogen. Das tut auch nichts zur Sache. Wichtig bei dieser Anwendung wäre allerdings, dass es sich nach dem "Deaktivieren" durch Klick auf ein anderes Fenster wieder in den Vordergrund bringt und auch wieder per Tastatur steuerbar ist. Folgende Tastatureingaben werden über das KeyDown-Event des Hauptformulars abgefangen und rufen die OnClick-Prozeduren von 4 Buttons auf.
Delphi-Quellcode:
Das Formular ist momentan aus BorderStyle bsDialog und FormStyle fsNormal eingestellt und wird wie folgt im OnShow-Event geTOPMOSTet:
procedure Tfrm_main.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState); begin case Key of 37: // Aktion für VK_LEFT; 40: // Aktion für VK_DOWN; 39: // Aktion für VK_RIGHT; 38: // Aktion für VK_UP; end; end;
Delphi-Quellcode:
Da das aber allein nicht funktioniert hat, habe bringe ich das Fenster mit Hilfe eines Timers immer wieder in den Vordergrund. Das ist die Stelle die mir ganz und garnicht gefällt und sicher nicht zum guten Stil gehört.
procedure Tfrm_main.FormShow(Sender: TObject);
begin SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE); end; Im OnTimer-Event wird also immer wieder BringToFront ausgelöst.
Delphi-Quellcode:
Nochmal das Ziel: Dieses kleine Formular soll auch nach Aktion in einem anderen Fenster (ist soweit ich weiß kein Spiel und auch nicht maximiert/Vollbild, ...) wieder durch die Pfeiltasten navigierbar sein.
procedure Tfrm_main.Timer1Timer(Sender: TObject);
begin if GetForeGroundWindow <> Handle then begin frm_main.BringToFront; end; end; Soweit ich weiß, lassen sich Anwendungen nicht mehr den Focus stehlen. Damit dürfte es dann nicht gehen. |
AW: Nach BringToFront wieder über Tasten navigieren?
Ganz so klar ist mir das nicht geworden, aber ich würde das Window-Handle
dieser 2. Anwendung zwischenspeichern und BringToFront() nur auslösen, wenn diese 2. Anwendung den Focus hat:
Delphi-Quellcode:
Damit kann der Benutzer zwischendurch auch eine andere Anwendung (z.B. Explorer)
Tfrm_main = class(TForm)
private FExtWinHandle : THandle; .... procedure Tfrm_main.Timer1Timer(Sender: TObject); begin if GetForeGroundWindow <> Handle then begin if FExtWinHandle = 0 then begin FExtWinHandle := GetForeGroundWindow; end; if FExtWinHandle = GetForeGroundWindow then BringToFront; end; end; procedure Tfrm_main.FormOnActivate(Sender: TObject); begin FExtWinHandle := 0; end; benützen ohne das deine Anwendung ständig hochpoppt. |
AW: Nach BringToFront wieder über Tasten navigieren?
Zitat:
MfG Dalai |
AW: Nach BringToFront wieder über Tasten navigieren?
@Dalai:
Ein fremdes Programm bzw. das Hauptfenster von diesem. @shmia: Das macht Sinn, guter Vorschlag. Es geht auch "nur" darum in der anderen Anwendung ein paar Klicks zu machen und anschließend mit den Pfeiltasten in meiner kleinen Anwendung ein paar Buttons auszulösen. Praktisch wäre es z.B. auch, wenn die andere Anwendung durch Auslösen einer Taste wieder zu meiner Anwendung springt - dann hätte man selbst die Kontrolle, wann man wieder was in der kleinen App machen möchte. Aber erstmal eins nach dem andern. Ich habe jetzt im Delphi-Treff eine Funktion gefunden, mit der ich nach Fenstername oder einem Teil davon ODER nach dem Klassennamen eines Fensters suchen kann. Ein Editor hat z.B. im Titel immer " - Editor" stehen, so könnte ich dieses Fenster dann finden. Vorausgesetzt natürlich, es gibt nicht noch ein weiteres. Delphi-Treff: Handle auf ein Fenster einer anderen Anwendung bekommen: ![]() Ich hab jetzt ne Weile gebastelt und habs geschafft die Codes vom Delphi-Treff so gut es geht lazarus-konform bzw. 64-bit konform zu machen.
Delphi-Quellcode:
- Der Timer überprüft im Moment dauerhaft, ob ein Fenster mit dem Namen oder Teilnamen " - Editor" vorhanden ist und führt dann BringToFront aus - Wie wird das Fenster nun so nach vorn gehoben, dass ich es wieder mit den Maustasten bedienen kann?
unit MainForm;
{$mode objfpc}{$H+} interface uses Windows, Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls; type PFindWindowStruct = ^TFindWindowStruct; TFindWindowStruct = record Caption: string; ClassName: String; WindowHandle: THandle; end; type Tfrm_main = class(TForm) // Buttons, Labels, ... Timer1: TTimer; procedure FormActivate(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure FormShow(Sender: TObject); procedure Timer1Timer(Sender: TObject); // restliche Prozeduren private FExtWinHandle: THandle; { private declarations } public { public declarations } end; var frm_main: Tfrm_main; function FindAWindow(WinCaption: String; WinClassName: String): THandle; function EnumWindowsProc(hWindow: hWnd; lParam: PtrInt): Bool; stdcall; implementation {$R *.lfm} { Tfrm_main } //------------------------------------------------------------------------------ procedure Tfrm_main.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin case Key of 37: // Aktion für VK_LEFT; 40: // Aktion für VK_DOWN; 39: // Aktion für VK_RIGHT; 38: // Aktion für VK_UP;; end; end; //------------------------------------------------------------------------------ procedure Tfrm_main.FormActivate(Sender: TObject); begin FExtWinHandle := 0; end; //------------------------------------------------------------------------------ function EnumWindowsProc(hWindow: hWnd; lParam: PtrInt): Bool; Stdcall; var lpBuffer: PChar; WindowCaptionFound: Boolean; ClassNameFound: Boolean; begin GetMem(lpBuffer, 255); Result := True; WindowCaptionFound := False; ClassNameFound := False; try if GetWindowText(hWindow, lpBuffer,255)>0 then if Pos(PFindWindowStruct(lParam)^.Caption, StrPas(lpBuffer))>0 then WindowCaptionFound := True; if PFindWindowStruct(lParam)^.ClassName='' then ClassNameFound := True else if GetClassName(hWindow, lpBuffer, 255)>0 then if Pos(PFindWindowStruct(lParam)^.ClassName, StrPas(lpBuffer))>0 then ClassNameFound := True; if (WindowCaptionFound and ClassNameFound) then begin PFindWindowStruct(lParam)^.WindowHandle := hWindow; Result := False; end; finally FreeMem(lpBuffer, SizeOf(lpBuffer^)); end; end; //------------------------------------------------------------------------------ function FindAWindow(WinCaption: String; WinClassName: String): THandle; var WindowInfo: TFindWindowStruct; begin with WindowInfo do begin Caption := WinCaption; ClassName := WinClassName; WindowHandle := 0; EnumWindows(@EnumWindowsProc, PtrInt(@WindowInfo)); Result := WindowHandle; end; end; //------------------------------------------------------------------------------ procedure Tfrm_main.Timer1Timer(Sender: TObject); var FMyHandle: THandle; begin FMyHandle := FindAWindow('- Editor', ''); if GetForeGroundWindow <> Handle then begin if FExtWinHandle = 0 then FExtWinHandle := GetForeGroundWindow; if FExtWinHandle = FMyHandle then begin BringToFront; {if frm_main.WindowState = wsMinimized then frm_main.WindowState := wsNormal; if not frm_main.Active then SetActiveWindow(Application.MainForm.Handle); if not frm_main.Focused then Application.MainForm.SetFocus; SetForegroundWindow(Application.MainForm.Handle);} end; end; end; - Neben BringToFront habe ich auch SetForegroundWindow(Application.MainForm.Handle) bzw. SetActiveWindow(Application.MainForm.Handle), SetFocus, Activate, etc. versucht. Das Fenster kommt nicht vor. weitere Infos: - Das Fenster wird nicht minimiert (Stellt euch 2 Notepads vor, die sich teilweise überlappen und man dann eins anklickt -> das andere liegt dann dahinter) - Das Fenster hat BorderStyle bsDialog und FormStyle fsNormal - die ganzen im Vordergrund bleiben Geschichten hab ich raus genommen |
(push, kann gelöscht werden)
|
AW: Nach BringToFront wieder über Tasten navigieren?
Bietet Lazarus nicht auch einen FormStyle ala StayOnTop?
Tut mir Leid das sagen zu müssen, aber sowas wie mit diesem Timer ist doch totaler Schrott unschön. Und ja, wenn der Eingabefokus nicht bei deiner Form liegt, dann bekommt sie natürlich auch keine Eingabebefehle (Tastenereignisse). :roll: ![]() PS: Zitat:
Delphi-Quellcode:
case Key of
VK_LEFT: ; VK_DOWN: ; VK_RIGHT: ; VK_UP: ; end; |
AW: Nach BringToFront wieder über Tasten navigieren?
Hallo himitsu,
Zunächst mal zum KeyDown-Event. Die Konstanten wurden nicht angenommen, darum habe ich kurzerhand die numerischen Werte verwendet. Damit wollte ich micht nicht lange aufhalten. Die Kommentare sind bei mir auch nicht im Code, weil dort entsprechende Prozeduraufrufe stehen. Das war nur als Hilfe für euch, damit ihr nicht erst schauen müsst wofür jetzt welche Zahl steht. Von diesen "Fenster soll immer oben bleiben" Geschichte hab ich mich schon so halb verabschiedet. Es langt, wenn ich das Fenster wieder Aktivieren kann bzw. ihm ordnungsgemäß den Fokus übergeben kann. Die Sache mit dem Timer war nur ne Quick and Dirty Lösung, um zu testen, welche Möglichkeiten funktionieren, mein Fenster wieder zu reaktivieren. Bisher war mein "Radius" beim Programmieren in Delphi lediglich auf die eigene Anwendung und vielleicht ein paar externe Dateien begrenzt. Mit der Interaktion zu anderen Programmen habe ich wenig bis gar keine Erfahrung. Deshalb ist mir bisher auch noch nichts anderes eingefallen, was ich nutzen könnte, diese lästige Timer-Gesichte zu beseitigen. Falls sich da am Wochenende - wo ich hierfür wieder bisschen Luft hätte - nicht noch was auftut beschäftige ich mal mit GetAsyncKeyState. Danke schon mal für den Tipp :) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:22 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz