2

I faced a redrawing bug that is not very pleasant to see (Delphi 5, Windows 7 64 bit, Classic theme)

If one creates resizable dialog with client-aligned RichEdit in it and provide the function

procedure TQueryDlg.ShowDialog(const Txt: string);
begin
  RichEdit.Text:=Txt;
  ShowModal;
end;

then at least on Windows 7 when resizing the dialog, the lines are not re-wrapped, but rather the pixels from the chars keeps filling the space and it looks like the whole area is never invalidated. The richedit starts working correctly when the control is activated with the mouse.

I suppose it has something to do with message queue of forms and dialogs in Delphi, but probably is specific to RichEdits of particular version. My

  • System32/Richedit32.dll - v6.1.7601.17514

  • System32/RichEdit20.dll - v3.1, 5.31.23.1230

Probably some workaround information would be great.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
Maksee
  • 2,311
  • 2
  • 24
  • 34

1 Answers1

1

I had a similar problem with the TRichEdit control. I found it wouldn't paint itself unless it was visible (which wasn't always the case in my app). And I found times that it rendered incorrectly until the user set focus to it. Both very irritating.

What worked for me was to create my own class and add a Render() method to it. This way I could tell it to paint whenever I wanted (e.g., when resizing a form, or when the component wasn't visible).

Here is a very stripped down version of what I did:

interface

uses
  Winapi.Messages, Vcl.ComCtrls;

type
  TMyRichEdit = class(TRichEdit)
  private
    procedure WMPaint(var Message: TMessage); message WM_PAINT;
  public
    procedure DoExit; override;
    procedure DoEnter; override;
    procedure Render;
  end;

var
  PaintMsg: TMessage;

implementation

procedure TMyRichEdit.DoEnter;
begin
  inherited;
  WMPaint(PaintMsg);
end;

procedure TMyRichEdit.DoExit;
begin
  inherited;
  WMPaint(PaintMsg);
end;

procedure TMyRichEdit.Render;
begin
  WMPaint(PaintMsg);
end;

procedure TMyRichEdit.WMPaint(var Message: TMessage);
begin
  // eliminated custom code to tweak the text content...
  inherited;
end;

initialization
  PaintMsg.Msg := WM_PAINT;
  PaintMsg.WParam := 0;
  PaintMsg.LParam := 0;
  PaintMsg.Result := 0;

end.

I added WMPaint() because I needed to tweak how the text content before it was rendered. But none of that code is needed for what you are doing. So, instead of declaring WMPaint() and handling the WM_PAINT message, you could probably just post the PaintMsg from the DoExit(), DoEnter() and Render() methods. Sorry I don't have time to compile the code or try eliminating WMPaint() and using PostMessage()...

James L.
  • 9,384
  • 5
  • 38
  • 77
  • Looking at your info, I tried to stop in the WMPaint handler of TCustomRichEdit when the RichEdit in the buggy state and the debugger stopped, so it looks that I won't get anything new if I force to call the handler, will I? – Maksee May 30 '13 at 03:30
  • This is not how you force a repaint. You simply call Repaint. – David Heffernan May 30 '13 at 07:27
  • `Repaint` may be the proper way to force a repaint, but it didn't work years ago when I was working with a RichEdit control that was not visible. The only thing that I found that worked was to queue the WM_PAINT message manually. – James L. May 30 '13 at 16:52
  • @Maksee - If WMPaint is already being called, then you're right - queuing another WMPaint message won't fix anything. Looking at David's suggestion `Repaint`, it just invalidates the control and then calls `Update`. Have you tried `Repaint` or `Update` in the form's resize event? Perhaps they will work in your case? – James L. May 30 '13 at 19:10
  • The invalidating of the RichEdit on the form resize event worked. I will probably keep this solution, but I would like to know at least whether it is something on VCL or on Windows side. – Maksee May 30 '13 at 21:18