das ist nett Ally! Icons sehen spitze aus!
Dank wp_xyz konnte ich über GetDialogIcon alle Icons vom System nehmen.
Das ist natürlich einfacher, als eine Resource einzubinden.
function GetBKType(str:string):TBitBtnKind;
var
value: Integer;
begin
value := GetEnumValue(TypeInfo(TBitBtnKind), 'bk' + str);
if value > -1 then
Result := TBitBtnKind(value)
else
Result := bkCancel;
end;
Lizenz: Du möchtest Creative Commons. ok. Aber wenn ich die Unit in mein ExCtrls Package aufnehme, in der ich "LGPL2 with linking exception (like Lazarus LCL)" festgelegt habe, hätte ich ein Lizenz-Chaos, das ich vermeiden möchte. Wärst du damit einverstanden, LGPL2/Linking Exception mit als zweite Lizenz in deinen Text aufzunehmen?
Font des Dialogs: Ich würde den in "meiner" Version auf "default" und Größe 0 zurücksetzen, damit das Meldungsfenster bei einer Standard-Anwendung nicht aus dem Rahmen fällt. Der User kann ja beim Aufruf über CreateQuestionDialogEx den Font nach Belieben ändern (er muss sich halt sinnvollerweise eine eigene Aufruf-Prozedur a la QuestionDialogEx schreiben).
QuestionDialogEx: Es ist m.E. nicht nötig zu prüfen, ob ein Help-Button vorhanden ist, denn der User kann immer F1 drücken, auch ohne Help-Button. Das Hilfe-System ist so ausgelegt, dass mit F1 der per HelpContext oder HelpKeyword festgelegte Hilfetext erscheint.
Zentrierung des Dialogs: Ich habe keine zwei Monitore, aber ich bin ziemlich sicher, dass Screen.Width die gesamte Monitorbreite umfasst. Mit Screen.Width div 2 wäre der Dialog dann genau zwischen beiden Monitoren aufgeteilt... --> Statt Screen QForm.Monitor verwenden. Außerdem haben ist am Rand oft noch die Taskleiste --> WorkAreaRect verwenden.
Idee: Man könnte z.B. negative Werte von X/Y als ord(TPosition) interpretieren, so dass man den Dialog z.B. über dem Hauptformular zentrieren könnte (X = ord(poMainFormCenter). Also
if (X < 0) and (Y = -1) then QForm.Position := TPosition(-X);
Die Prüfung, ob der Dialog horizontal über den rechten Bildschirmrand (Screen.Width, besser: Monitor.WorkArea.Right) hinausragt, müsste noch um die Vertikale (Monitor.WorkArea.Bottom) ergänzt werden.
Ally hat geschrieben: Fr 19. Nov 2021, 12:00
im Anhang habe ich mal einen Satz mt-Icons beigelegt.
Wenn das so "mehrheitsfähig" wäre, würde ich auch noch die mb-Icons beisteuern.
Danke. Ich werden die Icons wie üblich in Lazarus aufnehmen. Man könnte ja sogar die Prozedur GetDialogIcon so überarbeiten, dass die zur aktuellen Auflösung passende Größe genommen wird.
Die mbIcons sind meiner Meinung nach schon von dir (lcl/images/buttons).
Also mit der Hilfe, das ist mir nicht klar.
Soll ich AHelpKeyword oder AHelpCtx der QForm zuweisen?
Ich habe mir zuerst das Sample htmlhelp in Lazarus angeschaut, dann in Google gesucht nach "Lazarus bkhelp bitbtn" und kein einziges Beispiel gefunden.
Soll ich dem Help Button ein onClick zuweisen und ShowHelpOrErrorForKeyword('','HTML/index.html'); aufrufen?
Beim setzen eines Font NACH dem Erstellen der QForm, darf man den Font nicht der QForm (als Parent Font) zuweisen, da dann die Positionierung der Buttons nicht mehr stimmt.
Hier kann man lediglich den Label Font ändern über z.B. (QForm.findcomponent('QMsg') as TLabel).Font.Name:='Consolas'; (was eigentlich auch nicht geht, da die Schriftgröße entscheidet, was in der vorberechneten Zeichenfläche noch sichtbar ist!) Wird eine einheitliche Schrift gewünscht, muss man das bei der Erzeugung der Qform in CreateQuestionDlgEx erledigen.
Hast recht. Ich hatte da nichts ausprobiert, als ich das geschrieben habe...
Es sieht so aus, als ob bkHelp nur provisorisch implementiert ist. Bei einem "Search in Files" finde ich keine Stellen, aus denen hervorgeht, was bei Klicken eines Help-Buttons passiert. Man könnte natürlich dem Help-Button in dem QuestionDlg-Formular einen OnClick-Handler zuweisen, der ShowHelpOrErrorForKeyword('...) mit dem HelpCtx/HelpKeyword aufruft. Allerdings sollte bei einem allgemein verwendbaren Dialog die Option offen bleiben, etwas ganz anderes zu tun, z.b. ein eigenes Hilfe-System aufzurufen.
Daher würde ich die Methode ShowHelp des aktuell fokussierten Controls (hier: der Help-Button) aufrufen - der weiß sicher nicht, was alles intern passiert, und man hat alle Möglichkeiten offen; insbesondere kann man über Application.OnHelp eine eigene Hilfe-Routine einbauen.
Damit der Help-Button auf einen Klick reagiert, brauchen wir einen OnClick-Handler. Nur: wir arbeiten hier innerhalb einer Prozedur, keine Möglichkeit für einen Event-Handler. Ich habe daher kurzerhand eine Hilfsklasse THelpClickHandler deklariert, die einen OnClick-Handler bereitstellt, der dem Help-Button zugewiesen wird. THelpClickHandler habe ich von TComponent abgeleitet, Owner ist das Formular (QForm), das die Instanz erzeugt und daher auch wieder freigibt. Damit kennt die Instanz das Formular und kann dessen ShowHelp-Methode aufrufen.
Beim Testen auf Speicherlecks bin ich auf eine üble Falle gestoßen, in die du getappt bist: QImage.Picture.Assign(GetDialogIcon(IconKind)) - das macht ein Speicherleck, weil GetDialogIcon ein Bitmap erzeugt, das hier nicht wieder mehr freigegeben werden kann, weil der Funktionswert von GetDialogIcon bei dem Assign verloren geht.
Und wie macht man das mit dem HelpContext/HelpKeyword? Ich hatte mir gedacht, man könnte das CreateQuestionDlgEx einmal für HelpContext und einmal für HelpKeyword bereitstellen. Damit man nicht jedesmal den ganzen Code duplizieren muss, würde ich alles in eine interne Prozedur InternalCreateQuestionDlgEx auslagern, die als zusätzliche Parameter den HelpCtx und das HelpKeyword hat. Wenn das HelpKeyword kein Leerstring ist, wird dieses in InternalCreateQuestionDlgEx dem Formular zugewiesen, andernfalls wird der HelpCtx zugewiesen. CreateQuestionDlgEx ruft dann InternalCreateQuestionDlgEx auf und setzt entweder den HelpCtx oder das HelpKeyword und lässt das jeweils andere auf dem Default-Wert.
--------
Um den Font auch nach dem Erstellen des Formulars verändern zu können, solltest du die Button-Positionen nicht selbst berechnen, sondern Anchoring und AutoSizing verwenden. Ich habe das in dem beigefügten Projekt (das auch die Hilfe mit implementiert) versucht zu realisieren. (Beachte aber, dass meine Version deiner Unit auf dem Stand des letzten Posts hier ist).
Wäre es nicht auch ausreichend, auf QForm einen Eventhandler für HelpButton.OnClick einzurichten, zuzuweisen und in diesem dann je nachdem Application.HelpContext oder Application.HelpKeyword aufzurufen? Application.OnHelp stünde dann für den äußeren, dem User zugänglichen Eventhandler zur Verfügung. Dazu müsste man nur eine entsprechende Klasse zB TQForm definieren, die anstelle von TForm.Create() mit TQForm.CreateNew() aufgerufen würde.
wp_xyz hat geschrieben: Fr 19. Nov 2021, 12:17
Ich werden die Icons wie üblich in Lazarus aufnehmen.
prima, dann hat sich meine Arbeit ja gelohnt.
Erledigt.
Leider führen diese Dialog-Icons ein Schatten-Dasein, da in der Regel die System-Icons genommen werden (zumindest unter Windows). Ich konnte die neuen Icons nur zu Gesicht bekommen, nachdem ich in GetDialogIcon (unit Dialogs) temporär das erste "if" zu einem "if not" gemacht habe, so dass die Icons aus der Resource geladen wurden und nicht von den ThemeServices.
In dem lcl/images/dialogs-Ordner gibt es noch ein Shield-Icon. Um das zu sehen, waren zusätzlich noch ein paar Änderungen nötig (--> Laz/main). Im Screenshot sieht man das System-Shield-Icon für Win 11 und Win 7.
Mit dem beigefügten Test-Programm kann man die vier Standard-MessageDialoge für alle Msg-Typen aufrufen.
Dateianhänge
shield_icon_win7.png (12.52 KiB) 1930 mal betrachtet
shield_icon_Win11.png (5.47 KiB) 1930 mal betrachtet
Hi wp_xyz,
Deine Änderungen gefallen mir gut, insbesondere die Korrektur zum Speicherleck!
Ein kleiner Fehler ist beim Vorbelegen des Focus auf einen BitBtn noch drin:
in Zeile 226 einfügen: btn.Name:='BitBtn'+inttostr(i);
Zeile 318 ersezen:
if setfocus > -1 then
QForm.ActiveControl:=(QForm.FindComponent('BitBtn'+inttostr(setfocus)) as TBitBtn);
Die Positionierung innerhalb des Bildschirms habe ich ergänzt.
Windows Ansicht
Image5.jpg (10.3 KiB) 1877 mal betrachtet
Linux Ansicht (Debian 9, XFCE)
Image2.jpg (11.46 KiB) 1877 mal betrachtet
Ich werde das jetzt produktiv einsetzen.
Es erfüllt ALLE meine Ansprüche und ergibt ein einheitliches Bild in meiner Anwendung.
Endlich erscheint ein Dialogfeld so, wie man das erwartet und hat dabei die Möglichkeit der freien Beschriftung!
Danke wp_xyz!
six1 hat geschrieben: Sa 20. Nov 2021, 12:34
in Zeile 226 einfügen: btn.Name:='BitBtn'+inttostr(i);
Zeile 318 ersezen:
if setfocus > -1 then
QForm.ActiveControl:=(QForm.FindComponent('BitBtn'+inttostr(setfocus)) as TBitBtn);
Warum so kompliziert? Die Buttons stehen doch im Array QButtonArray, und der Index, nach dem FindComponent suchen soll, ist gerade der Array-Index. Daher kannst du einfach auf die Zuweisung des Namens verzichten (was man sich wegen Problemen bei Namensgleichheit gar nicht angewöhnen sollte) und QForm.ActiveControl direkt auf QButtonArray[setFocus] setzen (letzteres hatte ich in meinem Code übersehen).
Es gibt noch eine weitere Optimierungsstelle:
Wenn die Buttons erzeugt und ins QButtonArray geschrieben werden, ist eigentlich schon bekannt, wieviele Buttons es gibt, und du kannst außerhalb der Schleife SetLength(QButtonArray, Length(PreButton)) setzen (statt das Array bei jedem Schleifen-Durchlauf um ein Element länger zu machen), und du kannst dann am Ende jedes Durchlaufs QButtonsArray[ i ] mit dem aktuell erzeugten btn besetzen.
Was mich noch stört, ist das der Dialog beim Erscheinen flackert. Ich habe das Gefühl, er erscheint, wird sofort wieder ausgeblendet oder verkleinert und erscheint erst dann endgültig. Ob das mit meinen AutoSize-Änderungen zu tun hat? Leider habe ich die alte Version nicht mehr, und finde sie auch hier nicht mehr zum Runterladen (Hinweis an mich selbst: eigentlich sollte man jede noch so kleine Entwicklung unter Versionskontrolle machen (git, svn, ...) ).