25

Found a glitch with VCL styles: when you update the form caption, other controls previously redrawn within the same procedure don't get repainted, and you are forced to call Repaint, losing valuable processing time to redraw.

Example: (set project options/vcl style manually)

unit Unit11;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm11 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form11: TForm11;

implementation

{$R *.dfm}

procedure TForm11.Button1Click(Sender: TObject);
begin
  Panel1.Caption := 'test';
  caption := 'glitch';
end;

end.

object Form11: TForm11
  Left = 0
  Top = 0
  Caption = 'Form11'
  ClientHeight = 89
  ClientWidth = 352
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 8
    Top = 8
    Width = 121
    Height = 57
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Panel1: TPanel
    Left = 135
    Top = 8
    Width = 185
    Height = 57
    Caption = 'Panel1'
    TabOrder = 1
  end
end

program Project10;

uses
  Vcl.Forms,
  Unit11 in 'Unit11.pas' {Form11},
  Vcl.Themes,
  Vcl.Styles;

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  TStyleManager.TrySetStyle('Cobalt XEMedia');
  Application.CreateForm(TForm11, Form11);
  Application.Run;
end.
hikari
  • 3,393
  • 1
  • 33
  • 72
  • 1
    That's just an example to clearly show the issue. – hikari Apr 06 '12 at 01:54
  • 1
    Alright modified the code, though it was unnecessary, I don't get your complaining here, the issue was pretty clear with the initial example. – hikari Apr 06 '12 at 02:07
  • 1
    It's not complaining. If you have a problem with your code, posting made-up code won't help you get an answer. Read my last comment - I can make up code to duplicate almost any problem you want to create, but that doesn't mean my made-up code is what's causing the problem in real life. If you want help, post your code. And BTW - taking an attitude toward people you're asking for free help is not usually a good idea - it makes people not want to help. :) – Ken White Apr 06 '12 at 02:11
  • 1
    Well, my application has a lot of controls it needs to update every second, as well as the form caption. If the caption is modified at the end, -after- the other controls, they don't get invalidated. So I just posted a clear example to show and easily reproduce the issue. – hikari Apr 06 '12 at 02:13
  • 1
    That's not false code, I obviously tested it myself first before posting, clicking on the button doesn't update the panel caption for me, only if I move the form offscreen or another window on top of it to force the repaint. – hikari Apr 06 '12 at 02:20
  • 1
    Did you set the theme style manually? Most likely just copying the code didn't include it in the program resources. – hikari Apr 06 '12 at 02:37
  • 1
    I used the code you posted, including `TStyleManager.TrySetStyle('Cobalt XEMedia');` from the project file. The build included the style properly in the resources, or I wouldn't have seen the style take effect. – Ken White Apr 06 '12 at 02:46
  • 1
    I see. Well I don't know then, it glitches for me: http://i.imgur.com/qeMei.png I will test on another computer. – hikari Apr 06 '12 at 02:54
  • 1
    Moving the window half way offscreen causes the window to redraw the affected area: http://i.imgur.com/MLc4I.png – hikari Apr 06 '12 at 03:00
  • 11
    I can reproduce the issue, is very weird, it seems related to the message queu. When you set caption two messages are sent to the control WM_SETTEXT and CM_TEXTCHANGED, in some point the second message is swallowed, maybe i can found the root of the issue but that will require some time, as workaround you can call Application.ProcessMessages; in this way `Panel1.Caption := 'test'; Application.ProcessMessages; Caption := 'glitch';` – RRUZ Apr 06 '12 at 03:03
  • 1
    Tested on different hardware, reproduced 100% of the time: - Desktop with nVidia card (w7 x64) - Laptop with AMD card (w7 x64) - Vmware (w7 x64) - Vmware (windows8 x64 consumer preview) – hikari Apr 06 '12 at 03:05
  • 1
    Oh yep, processmessages is a much better workaround than repainting :) – hikari Apr 06 '12 at 03:11
  • 1
    I think this belongs on QualityCentral. And maybe here, or maybe not. not sure. – Warren P Apr 06 '12 at 12:53
  • 1
    Yeah, I was gonna submit this to QC as well. Thought it had a place here as well since most people looking for help come to SO first, and it's easy to find at least some hint of something going wrong. I'll update the question with the QC later. – hikari Apr 06 '12 at 14:08
  • 3
    http://qc.embarcadero.com/wc/qcmain.aspx?d=105067 – hikari Apr 21 '12 at 08:03
  • Please have a look at my answer. – moskito-x Feb 26 '13 at 11:35

1 Answers1

2

Set the caption calls in the sequence.

  • First form.caption, then child.caption.

Once you've called the wrong sequence, then stopped working the correct sequence. That's why I use here, the "set default" button.

This proceed, as long as there is no fix for it, I can live with that.

enter image description here

procedure TForm11.Button1Click(Sender: TObject);
begin // wrong order
  Panel1.Caption := 'test';
  caption := 'glitch';
end;

procedure TForm11.Button2Click(Sender: TObject);
begin // right order
  caption := 'glitch';
  Panel1.Caption := 'test';
end;

procedure TForm11.Button3Click(Sender: TObject);
var
i:integer;
begin // count no refresh
  for  i:= 1 to 300 do begin
  caption := 'glitch '+intToStr(i);
  Panel1.Caption := 'test '+intToStr(i);
  end;
end;

procedure TForm11.Button4Click(Sender: TObject);
var
i:integer;
begin // count with refresh
  for  i:= 1 to 300 do begin
  caption := 'glitch '+intToStr(i);
  Panel1.Caption := 'test '+intToStr(i);
  Panel1.Refresh;
  end;
end;

procedure TForm11.Button5Click(Sender: TObject);
begin // set default
  caption := 'Form11';
  Panel1.Caption := 'Panel1';
  Panel1.Refresh;
end;

end.

If you found another solution. Please tell me.

moskito-x
  • 11,832
  • 5
  • 47
  • 60