![]() |
Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Auch wenn ein paar Dinge dagegen sprechen TTrayIcon abzuschaffen, würde ich das dennoch gerne tun.
Als Ersatz dafür war meine Grundidee, dass bei jeder Meldung im Systembereich ein eigenes, kleines Form ohne Titelzeile angezeigt wird. Jetzt ist nur die Frage, wie geht man mit mehreren Meldungen im Systembereich um. Idee 1: ein Formular mit mehreren Seiten? Die Seiten werden dynamisch erzeugt, eine pro Meldung? Idee 2: mehrere Formulare dynamisch erzeugt? Wenn aktuell bereits eine Meldung angezeigt wird, zeige die nächste über dieser Meldung an. Sobald die erste Meldung verschwunden ist, lasse die zweite Meldung "mitwandern" (ausfaden oder das Formular einfach kleiner werden lassen und Top-Position ändern). Meldung 1 verschwindet beispielsweise nacht unten, raus aus dem Bildschirm und Meldung 2, die oberhalb von Meldung 1 ist, soll dann mitwandern und an die Position gehen wo Meldung 1 war. Wie geht man sowas am besten an? Es geht mir um das Management der Fenster und der Animation/Bewegung der Fenster, sollte es zu Idee 2 kommen. Falls es der ein oder andere kennt: Steam hat das früher so gemacht oder macht es noch immer. Ich möchte nicht den Stil übernehmen, sondern die Funktionalität. Meine ersten echt unschönen Gehversuche sehen so aus. Noch nichts wirklich in Units aufgeteilt, einfach in ein leeres Projekt geschrieben.
Delphi-Quellcode:
// Mainform
uses Toast; // Button TToast.Create(Self).Show('Titel 1', 'Dies ist eine Toast-Meldung 1.'); TToast.Create(Self).Show('Titel 2', 'Dies ist eine Toast-Meldung 2.');
Delphi-Quellcode:
unit Toast;
interface uses Windows, ShellAPI, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TToast = class(TObject) private const FMaxTimeDisplayed = 6000; var FForm: TForm; FTimer: TTimer; FDisplayTime: Integer; procedure FadeOutWindow(N: Integer); procedure Timer1Timer(Sender: TObject); procedure FFormClose(Sender: TObject; var Action: TCloseAction); public constructor Create(AParent: TComponent); procedure Show(ACaption: string; AMessage: string); end; implementation uses ToastList; {TToast} type TTaskBarPos = (_TOP, _BOTTOM, _LEFT, _RIGHT, _NONE); function GetTaskBarPos(Handle: THandle): TTaskBarPos; var tabd: TAppBarData; begin Result := _BOTTOM; FillChar(tabd, SizeOf(TAppBarData), 0); tabd.cbSize := SizeOf(TAppBarData); if SHAppBarMessage(ABM_GETTASKBARPOS, tabd) = 0 then Exit; case tabd.uEdge of ABE_LEFT: Result := _LEFT; ABE_TOP: Result := _TOP; ABE_RIGHT: Result := _RIGHT; ABE_BOTTOM: Result := _BOTTOM; end; end; function GetTaskBarDimension(Handle: THandle): Integer; var CurrentScreen: TMonitor; begin CurrentScreen := Screen.MonitorFromWindow(Handle); Result := (CurrentScreen.Width - CurrentScreen.WorkAreaRect.Width) + (CurrentScreen.Height - CurrentScreen.WorkAreaRect.Height); end; constructor TToast.Create(AParent: TComponent); begin inherited Create; FForm := TForm.Create(AParent); FForm.OnClose := FFormClose; end; procedure TToast.Show(ACaption: string; AMessage: string); var TaskbarPos: TTaskBarPos; TaskBarHeight: Integer; CurrentScreen: TMonitor; begin FForm.Position := poDesigned; FForm.Height := 100; FForm.Width := 250; CurrentScreen := Screen.MonitorFromWindow(FForm.Handle); TaskbarPos := GetTaskBarPos(FForm.Handle); TaskBarHeight := GetTaskBarDimension(FForm.Handle); case TaskbarPos of _TOP: begin FForm.Top := CurrentScreen.Top + TaskBarHeight; FForm.Left := CurrentScreen.Left + CurrentScreen.Width - FForm.Width; end; _BOTTOM: begin FForm.Top := CurrentScreen.Top + CurrentScreen.Height - TaskBarHeight - FForm.Height; FForm.Left := CurrentScreen.Left + CurrentScreen.Width - FForm.Width; end; _LEFT: begin FForm.Top := CurrentScreen.Top + CurrentScreen.Height - FForm.Height; FForm.Left := CurrentScreen.Left + TaskBarHeight; end; _RIGHT: begin FForm.Top := CurrentScreen.Top + CurrentScreen.Height - FForm.Height; FForm.Left := CurrentScreen.Left + CurrentScreen.Width - FForm.Width - TaskBarHeight; end; end; FForm.Left := Screen.WorkAreaWidth - FForm.Width; FForm.Top := Screen.WorkAreaHeight - FForm.Height; FForm.AlphaBlend := True; FForm.Show; FDisplayTime := 0; FTimer := TTimer.Create(FForm); FTimer.Interval := 1000; FTimer.Enabled := True; FTimer.OnTimer := Timer1Timer; end; procedure TToast.FadeOutWindow(N: Integer); begin // end; procedure TToast.Timer1Timer(Sender: TObject); begin FDisplayTime := FDisplayTime + FTimer.Interval; FForm.Caption := FDisplayTime.ToString; if FDisplayTime >= FMaxTimeDisplayed then begin FTimer.Enabled := False; FForm.Close; end; end; procedure TToast.FFormClose(Sender: TObject; var Action: TCloseAction); begin end; end. |
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Wäre es nicht viel sinnvoller, die vorhandene Systemfunktionalität für solche Benachrichtigungen zu verwenden? Ansonsten hast du z.B. das Problem, dass deine Benachrichtigungen andere verdecken oder umgekehrt, wenn beide gleichzeitig ausgelöst werden. Windows zeigt diese automatisch untereinander an. Außerdem kann man diese hinterher bequem in der Mitteilungszentrale finden.
Zudem funktioniert TNotificationCenter mit Android, iOS, OS X und Windows gleichermaßen. Ein TTrayIcon brauchst du dafür nicht. |
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Ok das sieht vielversprechend aus. Kann man in Toasts auch Icons anzeigen lassen, so wie es TTrayIcon macht? Das TNotificationCenter kann ich tatsächlich an ein zwei Stellen gebrauchen.
ABER. Meine ursprüngliche Idee wäre mir lieber weil ich auf diese Art und Weise noch zwei andere Arten von Meldungen anzeigen lassen kann. Beispielsweise kann, je nachdem wo die Taskbar sitzt, z.B. unten rechts ein kleines Fenster mit einer Fortschrittsanzeite und anderen Dingen angezeigt werden. Jetzt soll es aber die Möglichkeit geben, dass ein weiteres Fenster dieser Größe über dem Fenster angezeigt wird, welches schon sichtbar ist. Deswegen ein eigenes System. |
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Die Kapselung in Delphi unterstützt das nicht. Aber wie alleine schon das aktuelle Snipping Tool, das unter Windows 11 nun bei einem Druck auf die Drucken Taste erscheint, zeigt, gibt es die Möglichkeit, eine Grafik hinzuzufügen unter Windows.
Dafür müsste man aber die entsprechende Delphi-Unit kopieren und anpassen. Klar, wenn du weitere Anforderungen hast, die über eine Benachrichtigung hinaus gehen, macht ein eigenes System Sinn. Für eine Fortschrittsanzeige ist aber an der Stelle die Anzeige am Icon in der Taskbar gedacht... |
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Zitat:
Dass dieses Notification-Teil mein Problem nicht löst, weiß ich. Deswegen möchte ich ja was eigenes haben - zusätzlich. Mein erster Versuch ist oben. Der Code oben zeigt nur ganz simpel ein Fenster an der richtigen Stelle an. Aber das zweite soll über dem ersten angezeigt werden mit der Möglichkeit, dass die Fenster automatisch verschwinden und Nachrutschen bzw wenn man das untere schließt, soll das obere nachrutschen. Mein Problem ist, dass ich diese Verwaltung mit automatischer Schließgung ohne Speicherlecks nicht entwickelt bekomme. |
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Liste der Anhänge anzeigen (Anzahl: 1)
Dafür brauchst du eine übergeordnete Klasse, die sich um die Verwaltung kümmert, im Grunde so wie das TNotificationCenter. Dann zeigt das TToastCenter die Fenster an und verschiebt sie bei Bedarf. Der einzelne Toast kann z.B. ein Event haben, das beim Ausblenden gefeuert wird. Dann kann das TToastCenter ggf. weitere sichtbare Fenster verschieben.
Wie wäre es so... mal schnell runtergetippt... Anhang 56533 Das ist nur ein Beispiel, um eine mögliche Architektur zu zeigen. |
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Ich habe mir das angeguckt und habe jetzt verstanden, was ich gestern falsch gemacht habe. Vielen Dank.
|
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe den Code an meine Bedürfnisse angepasst, möchtest du dir das angucken? Kannst mir ja sagen, ob es eine Note "mangehaft" oder "ausreichend" ist :P
|
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Die Logik verstehe ich nicht so ganz. Warum übergibst du nicht einfach den Typ des Formulars, damit der Toast dieses erstellen kann?
Wenn du die Instanz selbst übergibst, musst du die vorher selbst erstellen. Und wenn du wie aktuell die globale Variable übergibst, kannst du immer nur einen Toast pro Formular absetzen. Also so:
Delphi-Quellcode:
Nebenbei:
TToast<T: TForm> = class
private FForm: T; public constructor Create; property Form: T read FForm; end; { TToast<T> } constructor TToast<T>.Create; begin inherited Create; FForm := T.Create(nil); FForm.OnShow := FormShowEvent; FForm.OnClose := FormCloseEvent; FTimer := TTimer.Create(nil); end; Deine Quelltextformatierung ist ja der aus dem offiziellen Styleguide sehr ähnlich. Das ist sehr gut. Wie wäre es, wenn du auch die Einrückung auf dem Standard lässt (2 Zeichen)? Bei 1 Zeichen sieht man kaum die Struktur, braucht daher länger um den Quelltext zu lesen. |
AW: Eigene Tray-Benachrichtigungen anzeigen statt TTrayIcon
Zitat:
In dem von mir hochgeladenen Code übergebe ich Form1 und Form2, weil es im Endprodukt auch so sein würde. Das Erzeugen dieser Formulare geschieht vorher. Auch mache ich das so, weil ich dann genau eine zentrale Stelle habe, an der Instanzen für Formulare erzeugt werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:44 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