Unterstrich auf Buttons (Accelerator)

Rund um die LCL und andere Komponenten
Antworten
siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Unterstrich auf Buttons (Accelerator)

Beitrag von siro »

Einen schönen guten Abend allerseits,

beim implementieren meines eigenen Buttons, frage ich mich grade wie das mit den
Unterstrichen in Caption generell funktioniert, bzw. wer dafür verantwortlich ist.

Dabei ist mir dann auch gleich eine Merkwürdigkeit beim TButton aufgefallen,
welche ich hier mal als erstes beschreiben möchte:

Windows 8.1 Lazarus v1.6.4
Wenn ich bei TButton Caption auf "&Button" setze, wird das "B" nicht unterstrichen dargestellt.
Wenn ich mein Programm starte wird das "B" immer noch nicht unterstrichen dargestellt.
Wenn ich aber einmal die ALT Taste betätigt habe. wird bei allen Tasten auch der entsprechende Buchstabe unterstrichen dargestellt.
Soll das so sein ?

------------------
Nun zu meiner eigentlichen Frage:
Wenn ich in meiner Komponente Caption "&Button" eingebe, soll das & Zeichen ja nicht angezeigt werden,
sondern dient der Info, dass der folgende Buchstabe unterstrichen ausgegeben werden soll.
Meine Komponente ist abgeleitet von TCustomControl und hat lediglich
property Caption bekommen.

TCaption ist ja wie folgt definiert:
TCaption = TTranslateString;
TTranslateString = type String;

Also ist das ja ein ganz normaler String und genau so verhält es sich bei meiner Komponenten auch
und zeigt das &Zeichen direkt an. Wie kann ich denn dafür sorgen, dass bei meiner Paint Methode
der Unterstrich angezeigt wird ?
canvas.TextOut gibt den Text als reinen String aus und betrachtet das "&" als ganz normalen Character.

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Unterstrich auf Buttons (Accelerator)

Beitrag von wp_xyz »

siro hat geschrieben:Soll das so sein ?

Ja. Microsoft hat sich irgendwann gedacht, diese unterstrichenen Buchstaben sind hässlich und wir zeigen sie nur noch an, wenn der Benutzer einen entsprechenden Tastaturbefehl ausführen will, also ALT gedrückt ist.

Das Verhalten kann man aber systemweit ausschalten, so dass die Unterstreichungen immer sichtbar sind: http://www.produktivampc.com/2012/01/al ... n-und.html

siro hat geschrieben:Wie kann ich denn dafür sorgen, dass bei meiner Paint Methode der Unterstrich angezeigt wird ?

Zusätzliche Parameter für die Textausgabe kann man über den Record TTextStyle angeben, darunter auch das Feld ShowPrefix - wenn es true ist, werden die Unterstreichungen statt des &-Zeichen angezeigt. Den TextStyle kann man entweder im canvas setzen oder als zusätzlichen Parameter der Routine TextRect angeben (geht leider nicht bei TextOut):

Code: Alles auswählen

procedure TForm1.FormPaint(Sender: TObject);
var
  ts: TTextStyle;
begin
  ts := Canvas.TextStyle;
  ts.ShowPrefix := true;
  Canvas.TextRect(Rect(0, 0, 100, 100), 20, 50, '&abc', ts);
end;
 
// zur Information: aus graphics
type
  TTextLayout = (tlTop, tlCenter, tlBottom);
  TTextStyle = packed record
    Alignment : TAlignment;  // TextRect Only: horizontal alignment
 
    Layout    : TTextLayout; // TextRect Only: vertical alignment
 
    SingleLine: boolean;     // If WordBreak is false then process #13, #10 as
                             // standard chars and perform no Line breaking.
 
    Clipping  : boolean;     // TextRect Only: Clip Text to passed Rectangle
 
    ExpandTabs: boolean;     // Replace #9 by apropriate amount of spaces (default is usually 8)
 
    ShowPrefix: boolean;     // TextRect Only: Process first single '&' per
                             //    line as an underscore and draw '&&' as '&'
 
    Wordbreak : boolean;     // TextRect Only: If line of text is too long
                             //    too fit between left and right boundaries
                             //    try to break into multiple lines between
                             //    words
                             //    See also EndEllipsis.
 
    Opaque    : boolean;     // TextRect: Fills background with current Brush
                             // TextOut : Fills background with current
                             //            foreground color
 
    SystemFont: Boolean;     // Use the system font instead of Canvas Font
 
    RightToLeft: Boolean;    //For RightToLeft text reading (Text Direction)
 
    EndEllipsis: Boolean;    // TextRect Only: If line of text is too long
                             //    to fit between left and right boundaries
                             //    truncates the text and adds "..."
                             //    If Wordbreak is set as well, Workbreak will
                             //    dominate.
  end;
 

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Unterstrich auf Buttons (Accelerator)

Beitrag von siro »

Zunächst einmal wieder vielen Dank an wp_xyp:

Das funktioniert soweit ganz ausgezeichnet.
Bei meiner Komponente wird nun auch während der Designphase sowie zur Laufzeit der Unterstrich richtig angezeigt.

Ich habe jetzt noch ein Problemchen, daß TextWidth mir ein falsches Ergebnis liefert.
In meiner Methode CalculatePreferredSize wird unter anderem die Textbreite benötigt, welche nun nicht mehr stimmt.
So habe ich das momentan gelöst:

Code: Alles auswählen

  tw:=canvas.TextWidth(caption);
  if pos('&',caption) > 0 then tw:=tw-canvas.TextWidth('&');


Das ist natürlich nicht ganz sauber, aber es funktioniert erst einmal.
Gibt es dafür auch noch eine bessere Möglichkeit ?

Siro
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Unterstrich auf Buttons (Accelerator)

Beitrag von wp_xyz »

Das geht mit der Windows-Funktion DrawText, wobei das Bit CALC_RECT in den Flags gesetzt sein muss. In Lazarus ist die Funktion allerdings Cross-Platform

Code: Alles auswählen

uses
  LCLIntf, LCLType;
function MyTextWidth(ACanvas: TCanvas; const s: String): Integer;
var
  R: TRect;
begin
  R := Rect(0, 0, 0, 0);
  DrawText(ACanvas.Handle, PChar(s), Length(s), R, DT_CALCRECT);     
    // um das &-Zeichen zu sehen, müsste man DT_NOPREFIX dazunehmen
  Result := R.Right - R.Left;
end;

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Unterstrich auf Buttons (Accelerator)

Beitrag von siro »

Ja, supi und vielen Dank wp_xyz

so funktioniert das einwandfrei.
Die beiden Units LCLIntf,LCLType werden benötigt weil:

DrawText in LCLIntf
DT_CALCRECDT in LCLType

hab jetzt dafür eine interne protected Methode in meine Komponente aufgenommen:

Code: Alles auswählen

 
function TSiroButton._TextWidth:Integer;
var r:Trect;
begin
  r := Rect(0, 0, 0, 0);
  DrawText(Canvas.Handle, PChar(caption), Length(caption), R, DT_CALCRECT);
  result := r.Right - r.Left;
end;
 

Problem gelöst.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Unterstrich auf Buttons (Accelerator)

Beitrag von wp_xyz »

Eigentlich könnte man einen Feature Request machen, dass die Canvas-Methoden TextOut, TextExtent, TextWidth (evtl auch TextHeight) so wie TextRect mit einem optionalen TextStyle-Parameter aufgerufen werden können. Denn an der Implementierung von TextRect sieht man, das TextStyle eigentlich nichts anderes macht, als diese DT_XXXX Bits setzt bzw. löscht.

Obwohl... Die meisten Parameter in TextStyle machen nur Sinn, wenn man die Größe des Rechtecks übergibt, in dem die Textausgabe erfolgen soll (z.B. Zeilenumbruch, oder EndEllipsis (...)), aber für ExpandTabs, ShowPrefix, Opaque, SystemFont und RightToLeft würde es Sinn machen, auch wenn man das Ausgaberechteck nicht kennt.

Antworten