3
votes

I we got few TEdit forms inserted on another form, but their labels are not displaying until I change size of the window. This happens just on Windows Vista / Windows 7. Windows XP has everything labeled correctly.

Ive already tested repaint / refresh (just TEdit / all form etc.) with no result.

Delphi 7.

Thank you for your answer

bad version enter image description here

Correct version enter image description here

code will be added soon enough :)

6
What is a TEdit form? TEdit does not have labels. Could you give us some code, preferably enough source to reproduce.David Heffernan
I'm with David on being confused... do you mean TLabeledEdit? Only point I can add is that TLabels are not windowed controls and therefore will appear behind windowed controls. If the TLabels do not share the same parent as the TEdits then you may not see them. If that is a TPanel they are both sitting on in your screen shots then make sure the TLabels are on that panel and not the form.Jerry Gagnon
Do you really inserted a Form into another? Or do you talk about tFrame-Objects? tFames are very special (or bugy if you like that term more ;)) especially at the older Delphi Versions. In that Version the ugly "resize Window after Creation" trick could be the best workaround for a problem like yours :(.knowledge stacker
View the DFM as text and paste the content of the DFM just the part that contains the labels that are missing. Is it a scrollbox containing the edits? Also please list the complete chain of parents from the missing edits, up to the top, by class (a form contains a form, containing a groupbox, containing a panel, containing the labels. or whatever)Warren P
Here is an open source application with source code that exhibits the same behavior: sourceforge.net/projects/poptray/files/PopTray/3.2 In particular, the labels on uFrameDefaults, for example, do not paint on Vista, however, if one drags the window under the taskbar and drags back vertically up, sometimes it will repaint correctly, but not consistently. The buttons on that form also have problems with disappearing and appearing at random on Vista. This screen displays fine on XP.Jessica Brown

6 Answers

2
votes

I was able to mostly resolve this same problem on my project. It seems to be a painting order problem. The solution ultimately was to call frame.Refresh; on the frame that was not displaying properly. But, figuring out the right place to put that Refresh was a little tricky, I tried several places before I found a spot that worked. Where it worked for me was, in the method where I choose which nested frame to show on the options panel, and physically display the nested frame, to call frame.Refresh; on the inner-most frame surrounding the labels that are not drawing properly. Calling refresh on the inner frame rather than the frame for the entire window seemed to be key.

From the screen-shots you are showing, you look like you probably have a similar complex setup of frames where there are likely to be frames displayed on top of frames, which may change dynamically after the frame is displayed initially. That seemed to be the setup that would create the problem in the first place, the initially shown frame never seemed to have problems.

One note, however, is if the window moves off the screen or is re-sized, another window is dragged in front of it, or mouse-over buttons that are disappearing is that these actions could cause the problem to re-appear spontaneously. There may be additional places, such as in a special handler for window resize, etc. or on a timer where you to call refresh on the frame periodically, similar to some of the solutions mentioned for the ALT Key bug. There seems to be some overlap in the type of problem and how to fix it but does not the exact same cause (this bug seems to happen regardless of the Alt key)

0
votes
{ Labels no Windows Vista, 7, 8 to Fix the problem, Delphi 7 32 bits }

on FormShow:

var
  i : Integer;
begin
   For i := 0 to (Form1.ComponentCount - 1) do
     begin
        If (Form1.Components[i].ClassType = TLabel) then
            TLabel(Form1.Components[i]).Refresh;
     end;
end;

Just run this.

0
votes

I'm getting the same thing, except it only seems to be a problem while the application is themed. If it is unthemed (ie Project->Options->Application->Appearance->Default Style = Windows) it works fine, no refresh or repaint needed.

Seems to be related specifically to the TFrame class so I wonder if something about the redraw handler isn't amok (related to Invalidate). Something in the ChangeNotify process or the Windows message pump in the VCL might not making its way up the parent control chain and responding with a cascading repaint funnelling back down on everything "invalidated".

One other cludge I did try with success was setting the host control Visible property to False on one line and then to true in the next line ie:

procedure TFrame1.UpdatePanel;
  Panel1.Visible := False;
  Panel1.Visible := True;
end;

Then calling this method where the proper drawing is needed.

All of the other child controls of Panel1 were drawn perfectly. You might have to cache the location of the text cursor if your update occurs while modifying the contents of one of the child controls like a TEdit or TMemo. This should be trivial compared to hours of hunting down the cause of the problem. Maybe looking into the VCL source of the Setter method for the Visible property on the offending control host (such as the TPanel) might provide some insight to the overall problem of why Repaint and Refresh don't seem to work as they should in this case.

0
votes

Actually it is much simpler than any of the solutions presented so far. The only thing needed is to respond to the WM_UPDATEUISTATE message. Add a procedure like the one bellow to the form:

...
  protected
  procedure WmUpdateUIState(var Msg: TMessage); message WM_UPDATEUISTATE;
...

procedure TForm1.WmUpdateUIState(var Msg: TMessage);
begin
  inherited;
  Invalidate;
end; { WmUpdateUIState }

Done!

Tested on Windows 10 64 bits.

One can speed things up by creating a unit like this:

unit FixAltKeyForm;

interface

uses
  Windows, Messages, Classes, Forms;


type
  TForm = class(Forms.TForm)
  protected
    procedure WmUpdateUIState(var Msg: TMessage); message WM_UPDATEUISTATE;
  end; { TForm }

implementation

{ TForm }

procedure TForm.WmUpdateUIState(var Msg: TMessage);
begin
  inherited;
  Invalidate;
end; { WmUpdateUIState }

end.

Add the unit's name to the uses clause of the interface session of any form where this behavior is wanted and you are done. Only be sure to put the unit's name AFTER 'Forms' in the uses clause. No need to create a package nor to install anything at all. That's what I call Visual Subclassing, for lack of a better term.

0
votes

There are bugs in TButton when running with windows Themes. You can search 'ThemesEnabled' in StdCtrls.pas, remove/comment all its related branch, like this:

procedure TButton.CNCtlColorBtn(var Message: TWMCtlColorBtn);
begin
    with ThemeServices do
    {
        if ThemesEnabled then
        begin
            DrawParentBackground(Handle, Message.ChildDC, nil, False);
            // Return an empty brush to prevent Windows from overpainting we just have created. 
        Message.Result := GetStockObject(NULL_BRUSH);
        end
        else
    }
    inherited;
end;

Then compile it, and replaced lib/StdCtrls.dcu with your patched version.