[Windows] Form in Taskleiste
-
- Beiträge: 351
- Registriert: Mi 25. Nov 2015, 17:06
- OS, Lazarus, FPC: Win 10 Pro | Lazarus 1.8.2 | FPC 3.0.4
- CPU-Target: i386 + x86_64
- Wohnort: in der Nähe von Stuttgart
- Kontaktdaten:
[Windows] Form in Taskleiste
Guten Abend allerseits,
da ich zwei Monitore besitze ist mir schon öfter aufgefallen dass bei allen meinen bisherigen GUI-Projekten die Anwendung/Main Form in der Taskleiste immer auf dem ersten Monitor angezeigt wird, auch wenn
1. die Form vom ersten auf den zweiten Monitor verschoben wird.
2. die Form auf dem zweiten Monitor erscheint (bspw. durch poDesigned).
Mit der WinApi Funktion MonitorFromWindow und dem Parameter MONITOR_DEFAULTTONEAREST erkennt windows korrekt dass sich die Form auf einem andern Monitor befindet (was ja auch Sinn macht, weil Windows alle Fenster managed).
Wie es sich auf andere Systeme bzw grafische Oberflächen auswirkt ist mir nicht bekannt.
Habt ihr ähnliche Erfahrungen oder ist das schon bekannt?
FPC 3.0.4 32-Bit
Laz 1.8.2 32-Bit
Win 10 Pro 64-Bit
da ich zwei Monitore besitze ist mir schon öfter aufgefallen dass bei allen meinen bisherigen GUI-Projekten die Anwendung/Main Form in der Taskleiste immer auf dem ersten Monitor angezeigt wird, auch wenn
1. die Form vom ersten auf den zweiten Monitor verschoben wird.
2. die Form auf dem zweiten Monitor erscheint (bspw. durch poDesigned).
Mit der WinApi Funktion MonitorFromWindow und dem Parameter MONITOR_DEFAULTTONEAREST erkennt windows korrekt dass sich die Form auf einem andern Monitor befindet (was ja auch Sinn macht, weil Windows alle Fenster managed).
Wie es sich auf andere Systeme bzw grafische Oberflächen auswirkt ist mir nicht bekannt.
Habt ihr ähnliche Erfahrungen oder ist das schon bekannt?
FPC 3.0.4 32-Bit
Laz 1.8.2 32-Bit
Win 10 Pro 64-Bit
Code: Alles auswählen
InitiateSystemShutdownExA(nil, nil, 0, true, false, $0005000F);
-
- Beiträge: 582
- Registriert: Sa 22. Okt 2016, 23:12
- OS, Lazarus, FPC: W10, L 3.8
- CPU-Target: 32+64bit
- Wohnort: Dresden
Re: [Windows] Form in Taskleiste
Hi, ist mir selber noch nicht aufgefallen bzw. habe ich noch nicht darauf geachtet. Probieren kann ich es aber erst wenn ich wieder auf Arbeit bin, da ich hier zuhause nur einen habe.
Habe mal gesucht wo die API in Lazarus steht, dazu habe ich folgendes gefunden:
In der customform.inc gibt es eine Funktion "GetMonitor":
Auszug:
LG und guten Rutsch, Maik
Habe mal gesucht wo die API in Lazarus steht, dazu habe ich folgendes gefunden:
In der customform.inc gibt es eine Funktion "GetMonitor":
Auszug:
Code: Alles auswählen
function TCustomForm.GetMonitor: TMonitor;
var
ParentForm: TCustomForm;
begin
if Assigned(Parent) then
begin
ParentForm := GetParentForm(Self);
if Assigned(ParentForm) then
Result := ParentForm.Monitor
else
Result := nil;
end else
begin
if HandleAllocated then
Result := Screen.MonitorFromWindow(Handle, mdNearest)
else
Result := Screen.MonitorFromPoint(point(Left,Top));
end;
end;
LG und guten Rutsch, Maik
LG Maik
Windows 10,
- Lazarus 3.8 (stable) + fpc 3.2.2 (stable)
- Lazarus 4.99 (trunk) + fpc 3.3.1 (main/trunk)
Windows 10,
- Lazarus 3.8 (stable) + fpc 3.2.2 (stable)
- Lazarus 4.99 (trunk) + fpc 3.3.1 (main/trunk)
-
- Beiträge: 351
- Registriert: Mi 25. Nov 2015, 17:06
- OS, Lazarus, FPC: Win 10 Pro | Lazarus 1.8.2 | FPC 3.0.4
- CPU-Target: i386 + x86_64
- Wohnort: in der Nähe von Stuttgart
- Kontaktdaten:
Re: [Windows] Form in Taskleiste
Ich hatte die MonitorFromWindow Funktion direkt aus der User32.dll eingebunden da ich sie in der unit windows nicht gefunden habe, aber so wie du gehts natürlich einfacher.
Edit: Hab sie gefunden, ist in LCLIntf.
Edit: Hab sie gefunden, ist in LCLIntf.
Code: Alles auswählen
InitiateSystemShutdownExA(nil, nil, 0, true, false, $0005000F);
-
- Beiträge: 351
- Registriert: Mi 25. Nov 2015, 17:06
- OS, Lazarus, FPC: Win 10 Pro | Lazarus 1.8.2 | FPC 3.0.4
- CPU-Target: i386 + x86_64
- Wohnort: in der Nähe von Stuttgart
- Kontaktdaten:
Re: [Windows] Form in Taskleiste
So, ich hab noch mal ein bisschen rumprobiert. Dazu wollte ich das Taskbar item mit ITaskbarList (un)sichtbar machen. Hier eine Möglichkeit wie es in Delphi funktionieren sollte (laut Delphi-Praxis Forenbeiträgen):Für diesen Fall würde auch ITaskbarList (statt ITaskbarList3) reichen, aber darum geht es nicht. Beim Klick auf die Buttons passiert nichts.
Nun habe ich versucht das ganze bei fremden Fenstern zu machen: Mit Erfolg. Wenn man ein Application.Title Wert (nicht Form Caption!) mit FindWindow() sucht und das ganze macht funktioniert es. So kann man auch sein eigenes Taskbar Item (un)sichtbar machen. Dazu habe ich in die Form ein Edit namens Edt_AppTitle gepackt. Der von mir modifizierte Code hat funktioniert:Beim Eingeben des Application.Title Wertes in das Edit Feld und anschließendes Klicken auf die Button funktioniert es.
Das führt mich zu meiner Theorie: Das Taskbar Item von LCL Anwendungen ist gar nicht von der eigenen Form, sondern von einer im nicht sichtbaren Bereich befindlichen Form, was dazu führt dass Verschiebungen der eigenen Form auf den anderen Monitor zu keiner Änderung des Taskbar Items führen, weil dieses ja zu der unsichtbaren Form gehört, welche sich noch auf dem ersten Monitor befindet
Code: Alles auswählen
...
uses shlobj, comobj, windows;
...
private
FTaskbar: ITaskbarList3;
...
procedure TWnd_Test.FormShow(Sender: TObject);
begin
FTaskbar := CreateComObject(CLSID_TaskbarList) as ITaskbarList3;
FTaskbar.HrInit;
end;
procedure TWnd_Test.Btn_AddTabClick(Sender: TObject);
begin
FTaskbar.AddTab(Handle);
end;
procedure TWnd_Test.Btn_DeleteTabClick(Sender: TObject);
begin
FTaskbar.DeleteTab(Handle);
end;
Nun habe ich versucht das ganze bei fremden Fenstern zu machen: Mit Erfolg. Wenn man ein Application.Title Wert (nicht Form Caption!) mit FindWindow() sucht und das ganze macht funktioniert es. So kann man auch sein eigenes Taskbar Item (un)sichtbar machen. Dazu habe ich in die Form ein Edit namens Edt_AppTitle gepackt. Der von mir modifizierte Code hat funktioniert:
Code: Alles auswählen
procedure TWnd_Test.Btn_AddTabClick(Sender: TObject);
var
h: HWND;
begin
h := FindWindow(nil, LPCSTR(Edt_AppTitle.Caption));
if h <> INVALID_HANDLE_VALUE then begin
FTaskbar.AddTab(h);
// um zu zeigen dass Form und Taskbar Item ein unterschiedliches Handle haben:
Caption := 'Form: ' + IntToStr(Handle) + ' | Taskbar Item: ' + IntToStr(h);
end;
end;
procedure TWnd_Test.Btn_DeleteTabClick(Sender: TObject);
var
h: HWND;
begin
h := FindWindow(nil, LPCSTR(Edt_AppTitle.Caption));
if h <> INVALID_HANDLE_VALUE then begin
FTaskbar.DeleteTab(h);
// um zu zeigen dass Form und Taskbar Item ein unterschiedliches Handle haben:
Caption := 'Form: ' + IntToStr(Handle) + ' | Taskbar Item: ' + IntToStr(h);
end;
end;
Das führt mich zu meiner Theorie: Das Taskbar Item von LCL Anwendungen ist gar nicht von der eigenen Form, sondern von einer im nicht sichtbaren Bereich befindlichen Form, was dazu führt dass Verschiebungen der eigenen Form auf den anderen Monitor zu keiner Änderung des Taskbar Items führen, weil dieses ja zu der unsichtbaren Form gehört, welche sich noch auf dem ersten Monitor befindet
- Dateianhänge
-
TaskbarList.zip
- Taskbar Item Beispielprojekt
- (4.56 KiB) 206-mal heruntergeladen
-
- Man sieht dass Form und Taskbar Item ein unterschiedliches Handle besitzen
- TaskbarListTest.png (3.49 KiB) 3176 mal betrachtet
Code: Alles auswählen
InitiateSystemShutdownExA(nil, nil, 0, true, false, $0005000F);
-
- Beiträge: 351
- Registriert: Mi 25. Nov 2015, 17:06
- OS, Lazarus, FPC: Win 10 Pro | Lazarus 1.8.2 | FPC 3.0.4
- CPU-Target: i386 + x86_64
- Wohnort: in der Nähe von Stuttgart
- Kontaktdaten:
Re: [Windows] Form in Taskleiste
Ich bins nochmal. Hab es jetzt hinbekommen:Beim Verschieben des eigenen Fensters wird das ominöse Fenster in die Mitte des eigenen Fensters mit der Größe 1x1 gesetzt (0x0 geht nicht), ist aber dennoch nicht sichtbar und nicht aktiv (SWP_NOACTIVATE), damit die eigene Form nicht flackert. Das hier ist eine Art Notlösung für Leute die eine solche Funktion benötigen. Die IFDEFs habe ich gleich reingemacht damit man das ohne Änderung unter Windows und Linux nutzen kann. Dennoch sollte das mal überarbeitet werden, auch wenn es nur ein kleines Detail ist.
Edit: Die Größe ist nur noch 1x1 statt so groß wie das eigene Fenster, da sonst beim maximieren und wiederherstellen ein schwarzer Balken links neben der eigenen Form entstand.
Code: Alles auswählen
uses ... {$ifdef mswindows}, windows {$endif};
...
private
{$ifdef mswindows}
FTaskbarItemHandle: HWND;
{$endif}
...
procedure TWnd_Test.FormChangeBounds(Sender: TObject);
begin
{$ifdef mswindows}
if FTaskbarItemHandle <> INVALID_HANDLE_VALUE then begin
SetWindowPos(FTaskbarItemHandle, HWND_TOP, Left + (Width div 2), Top + (Height div 2), 1, 1, SWP_NOACTIVATE);
end;
{$endif}
end;
procedure TWnd_Test.FormCreate(Sender: TObject);
var
AppTitle: String;
begin
{$ifdef mswindows}
// das temporäre umsetzen des Application Titles wird gemacht um die Form eindeutig zu identifizieren, sollten mehrere Instanzen dieser Anwendung laufen.
// Sichtbar für den Endnutzer ist das jedoch nicht.
AppTitle := Application.Title;
Application.Title := Application.ExeName;
FTaskbarItemHandle := FindWindow(nil, LPCSTR(Application.Title));
Application.Title := AppTitle;
{$endif}
end;
Edit: Die Größe ist nur noch 1x1 statt so groß wie das eigene Fenster, da sonst beim maximieren und wiederherstellen ein schwarzer Balken links neben der eigenen Form entstand.
Code: Alles auswählen
InitiateSystemShutdownExA(nil, nil, 0, true, false, $0005000F);