Entwickler-Ecke

Grafische Benutzeroberflächen (VCL & FireMonkey) - TEdit mit eingebautem Button - EM_SETMARGINS Fehler


jaenicke - Mo 27.12.10 18:32
Titel: TEdit mit eingebautem Button - EM_SETMARGINS Fehler
Hallo,

ich wollte mal schnell einen selbstgezeichneten Button in ein TEdit legen. Eigentlich kein Problem, nur leider scheint der mit EM_SETMARGINS gesetzte Rand nicht immer verwendet zu werden.

Und zwar erstens, wenn man den Inhalt des Edits komplett markiert und zweitens, wenn man mit der Maus auf das Edit klickt. Dann wird der Hintergrund des Textes über den gesetzten Rand (und damit den gezeichneten Button) hinaus gezeichnet.

Zum Testen einfach ein Edit aufs Formular werfen und den Code hier zum Umbiegen verwenden (sollte natürlich nur zum Testen so gemacht werden...):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
type
  TEdit = class(StdCtrls.TEdit)
  protected
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
    procedure WMSetFont(var Message: TWMPaint); message WM_SETFONT;
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TFormX = class(TForm)
//  ...

implementation

{$R *.dfm}

{ TEdit }

constructor TEdit.Create(AOwner: TComponent);
begin
  inherited;
  PostMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN, MakeLong(0, ClientHeight));
end;

procedure TEdit.WMPaint(var Message: TWMPaint);
var
  EditDC: THandle;
  EditCanvas: TCanvas;
begin
  inherited;
  EditDC := GetDC(Handle);
  try
    EditCanvas := TCanvas.Create;
    try
      EditCanvas.Handle := EditDC;
      EditCanvas.Pen.Color := clGray;
      EditCanvas.Brush.Color := clGray;
      EditCanvas.Ellipse(ClientWidth - ClientHeight, 0, ClientWidth, ClientHeight);
    finally
      EditCanvas.Free;
    end;
  finally
    ReleaseDC(Handle, EditDC);
  end;
end;

procedure TEdit.WMSetFont(var Message: TWMPaint);
begin
  inherited; // hier setzt der Delphi-Code EM_SETMARGINS
  PostMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN, MakeLong(0, ClientHeight));
end;
Wie kann ich dafür sorgen, dass entweder der Rand auch immer benutzt wird oder alternativ den Button über den Text/Hintergrund zeichnen?

Vielen Dank,
schönen Gruß,
Sebastian


Martok - Mo 27.12.10 18:46

Ich hab grad mal in der RXLib nachgesehen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TCustomComboEdit.SetEditRect;
var
  Loc: TRect;
begin
  SetRect(Loc, 0, 0, ClientWidth - FBtnControl.Width{Polaris - 2}, ClientHeight + 1);
  SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@Loc));
//Polaris
//  SendMessage(Handle, EM_SETMARGINS, EC_RIGHTMARGIN, MakeLong(0, FBtnControl.Width));
end;

Ging bei denen also auch nicht... vermutlich muss das so.

Zusätzlich wird noch der Style WS_CLIPCHILDREN gesetzt, falls das relevant ist. ES_MULTILINE muss es jedenfalls sein, schreibt aber auch die MSDN.

Nachtrag: Delphi7-VCL ist noch unterhaltsamer:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure TSpinEdit.SetEditRect;
var
  Loc: TRect;
begin
  SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));
  Loc.Bottom := ClientHeight + 1;  {+1 is workaround for windows paint bug}
  Loc.Right := ClientWidth - FButton.Width - 2;
  Loc.Top := 0;  
  Loc.Left := 0;  
  SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@Loc));
  SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));  {debug}
end;

Man beachte das {debug} :rofl:


jaenicke - Mo 27.12.10 19:00

user profile iconMartok hat folgendes geschrieben Zum zitierten Posting springen:
ES_MULTILINE muss es jedenfalls sein, schreibt aber auch die MSDN.
Genau das wollte ich eigentlich nicht, aber da es bei TSpinEdit verwendet wird, merkt man davon ja nichts, insofern mal schauen. Danke jedenfalls schon einmal. An das TSpinEdit Beispiel hatte ich gar nicht gedacht. ;-)


jaenicke - Di 28.12.10 10:17

Ja, danke noch einmal, ich habe jetzt einfach ein TMemo als Vorfahr benutzt. Damit funktioniert der Code, den du gepostet hast. Schade, dass TEdit nicht geht, aber als Benutzer merkt man davon ja nichts. ;-)