简体   繁体   中英

Delphi - TEdit Labels are not displaying (Windows 7/Vista only)

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在此处输入图片说明

Correct version在此处输入图片说明

code will be added soon enough :)

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)

{ 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.

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM