Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi TLabel和TGroupbox标题在调整大小时闪烁 因此,我有一个应用程序,它加载不同的插件并创建 TPageControl上的每个新选项卡 每个DLL都有一个与其关联的TForm 创建表单时,将其父hWnd作为新的TTabSheet_Delphi_Delphi Xe_Flicker_Groupbox_Tpagecontrol - Fatal编程技术网

Delphi TLabel和TGroupbox标题在调整大小时闪烁 因此,我有一个应用程序,它加载不同的插件并创建 TPageControl上的每个新选项卡 每个DLL都有一个与其关联的TForm 创建表单时,将其父hWnd作为新的TTabSheet

Delphi TLabel和TGroupbox标题在调整大小时闪烁 因此,我有一个应用程序,它加载不同的插件并创建 TPageControl上的每个新选项卡 每个DLL都有一个与其关联的TForm 创建表单时,将其父hWnd作为新的TTabSheet,delphi,delphi-xe,flicker,groupbox,tpagecontrol,Delphi,Delphi Xe,Flicker,Groupbox,Tpagecontrol,因为就VCL而言,TTabSheets不是表单的父级(不想使用动态RTL和其他语言制作的插件),所以我必须手动处理大小调整。我是这样做的: var ChildHandle : DWORD; begin If Assigned(pcMain.ActivePage) Then begin ChildHandle := FindWindowEx(pcMain.ActivePage.Handle, 0, 'TfrmPluginForm', nil); If ChildHa

因为就VCL而言,TTabSheets不是表单的父级(不想使用动态RTL和其他语言制作的插件),所以我必须手动处理大小调整。我是这样做的:

var
  ChildHandle : DWORD;
begin
  If Assigned(pcMain.ActivePage) Then
    begin
    ChildHandle := FindWindowEx(pcMain.ActivePage.Handle, 0, 'TfrmPluginForm', nil);
    If ChildHandle > 0 Then
      begin
      SetWindowPos(ChildHandle, 0, 0, 0, pcMain.ActivePage.Width, pcMain.ActivePage.Height, SWP_NOZORDER + SWP_NOACTIVATE + SWP_NOCOPYBITS);
    end;
  end;
现在,我的问题是,当应用程序调整大小时,所有的TgroupBox和TgroupBox中的TLabel都会闪烁。不在TGroupBox内的TLabel很好,不会闪烁

我尝试过的事情:

  • WM_SETREDRAW后面跟着一个重画窗口
  • tGroupBox和tLabel上的ParentBackground设置为False
  • 双缓冲区:=真
  • LockWindowUpdate(是的,尽管我知道它非常错误)
  • 透明:=False(甚至覆盖create以编辑ControlState)
有什么想法吗?

使用来自的

另外:不要指定
SWP_NOCOPYBITS
标志,并设置页面控件的
DoubleBuffered

uses
  VCLFixPack;

procedure TForm1.FormCreate(Sender: TObject);
begin
  PageControl1.DoubleBuffered := True;

  //Setup test conditions:
  FForm2 := TForm2.Create(Self);
  FForm2.BorderStyle := bsNone;
  FForm2.BoundsRect := TabSheet1.ClientRect;
  Windows.SetParent(FForm2.Handle, TabSheet1.Handle);
  FForm2.Show;
  PageControl1.Anchors := [akLeft, akTop, akRight, akBottom];
  PageControl1.OnResize := PageControl1Resize;
end;

procedure TForm1.PageControl1Resize(Sender: TObject);
begin
  SetWindowPos(FForm2.Handle, 0, 0, 0, TabSheet1.ClientWidth,
    TabSheet1.ClientHeight, SWP_NOZORDER + SWP_NOACTIVATE);
end;

我发现唯一有效的方法是使用
WS\u EX\u COMPOSITED
窗口样式。这是一个性能限制,所以我只在调整大小循环中启用它。根据我的经验,在我的应用程序中,使用内置控件,只有在调整表单大小时才会出现闪烁

您应该首先执行一个快速测试,看看这种方法是否可以通过简单地将
WS_EX_COMPOSITED
窗口样式添加到所有窗口控件中来帮助您。如果这样的话,你可以考虑下面更先进的方法:

快速黑客

procedure EnableComposited(WinControl: TWinControl);
var
  i: Integer;
  NewExStyle: DWORD;
begin
  NewExStyle := GetWindowLong(WinControl.Handle, GWL_EXSTYLE) or WS_EX_COMPOSITED;
  SetWindowLong(WinControl.Handle, GWL_EXSTYLE, NewExStyle);

  for i := 0 to WinControl.ControlCount-1 do
    if WinControl.Controls[i] is TWinControl then
      EnableComposited(TWinControl(WinControl.Controls[i]));
end;
例如,在
OnShow
中为您的
TForm
调用此函数,并传递表单实例。如果这有帮助的话,那么你真的应该更敏锐地实施它。我将从我的代码中提供相关摘录,以说明我是如何做到这一点的

完整代码

procedure TMyForm.WMEnterSizeMove(var Message: TMessage);
begin
  inherited;
  BeginSizing;
end;

procedure TMyForm.WMExitSizeMove(var Message: TMessage);
begin
  EndSizing;
  inherited;
end;

procedure SetComposited(WinControl: TWinControl; Value: Boolean);
var
  ExStyle, NewExStyle: DWORD;
begin
  ExStyle := GetWindowLong(WinControl.Handle, GWL_EXSTYLE);
  if Value then begin
    NewExStyle := ExStyle or WS_EX_COMPOSITED;
  end else begin
    NewExStyle := ExStyle and not WS_EX_COMPOSITED;
  end;
  if NewExStyle<>ExStyle then begin
    SetWindowLong(WinControl.Handle, GWL_EXSTYLE, NewExStyle);
  end;
end;

function TMyForm.SizingCompositionIsPerformed: Boolean;
begin
  //see The Old New Thing, Taxes: Remote Desktop Connection and painting
  Result := not InRemoteSession;
end;
procedure TMyForm.BeginSizing;
var
  UseCompositedWindowStyleExclusively: Boolean;
  Control: TControl;
  WinControl: TWinControl;
begin
  if SizingCompositionIsPerformed then begin
    UseCompositedWindowStyleExclusively := Win32MajorVersion>=6;//XP can't handle too many windows with WS_EX_COMPOSITED
    for Control in ControlEnumerator(TWinControl) do begin
      WinControl := TWinControl(Control);
      if UseCompositedWindowStyleExclusively then begin
        SetComposited(WinControl, True);
      end else begin
        if WinControl is TPanel then begin
          TPanel(WinControl).FullRepaint := False;
        end;
        if (WinControl is TCustomGroupBox) or (WinControl is TCustomRadioGroup) or (WinControl is TCustomGrid) then begin
          //can't find another way to make these awkward customers stop flickering
          SetComposited(WinControl, True);
        end else if ControlSupportsDoubleBuffered(WinControl) then begin
          WinControl.DoubleBuffered := True;
        end;
      end;
    end;
  end;
end;

procedure TMyForm.EndSizing;
var
  Control: TControl;
  WinControl: TWinControl;
begin
  if SizingCompositionIsPerformed then begin
    for Control in ControlEnumerator(TWinControl) do begin
      WinControl := TWinControl(Control);
      if WinControl is TPanel then begin
        TPanel(WinControl).FullRepaint := True;
      end;
      UpdateDoubleBuffered(WinControl);
      SetComposited(WinControl, False);
    end;
  end;
end;

function TMyForm.ControlSupportsDoubleBuffered(Control: TWinControl): Boolean;
const
  NotSupportedClasses: array [0..1] of TControlClass = (
    TCustomForm,//general policy is not to double buffer forms
    TCustomRichEdit//simply fails to draw if double buffered
  );
var
  i: Integer;
begin
  for i := low(NotSupportedClasses) to high(NotSupportedClasses) do begin
    if Control is NotSupportedClasses[i] then begin
      Result := False;
      exit;
    end;
  end;
  Result := True;
end;

procedure TMyForm.UpdateDoubleBuffered(Control: TWinControl);

  function ControlIsDoubleBuffered: Boolean;
  const
    DoubleBufferedClasses: array [0..2] of TControlClass = (
      TMyCustomGrid,//flickers when updating
      TCustomListView,//flickers when updating
      TCustomStatusBar//drawing infidelities , e.g. my main form status bar during file loading
    );
  var
    i: Integer;
  begin
    if not InRemoteSession then begin
      //see The Old New Thing, Taxes: Remote Desktop Connection and painting
      for i := low(DoubleBufferedClasses) to high(DoubleBufferedClasses) do begin
        if Control is DoubleBufferedClasses[i] then begin
          Result := True;
          exit;
        end;
      end;
    end;
    Result := False;
  end;

var
  DoubleBuffered: Boolean;

begin
  if ControlSupportsDoubleBuffered(Control) then begin
    DoubleBuffered := ControlIsDoubleBuffered;
  end else begin
    DoubleBuffered := False;
  end;
  Control.DoubleBuffered := DoubleBuffered;
end;

procedure TMyForm.UpdateDoubleBuffered;
var
  Control: TControl;
begin
  for Control in ControlEnumerator(TWinControl) do begin
    UpdateDoubleBuffered(TWinControl(Control));
  end;
end;
过程TMyForm.WMEnterSizeMove(var消息:TMessage);
开始
继承;
开始化;
结束;
过程TMyForm.WMExitSizeMove(var消息:TMessage);
开始
端部尺寸;
继承;
结束;
程序集合成(WinControl:TWinControl;值:布尔值);
变量
ExStyle,NewExStyle:DWORD;
开始
ExStyle:=GetWindowLong(WinControl.Handle,GWL_ExStyle);
如果值为,则开始
NewExStyle:=ExStyle或WS_EX_COMPOSITED;
结束,否则开始
NewExStyle:=ExStyle且未合成WS_EX_;
结束;
如果是NewExStyleExStyle,则开始
SetWindowLong(WinControl.Handle、GWL_EXSTYLE、NewExStyle);
结束;
结束;
函数TMyForm.sizingCompositionPerformed:布尔值;
开始
//看看老的新的东西,税收:远程桌面连接和绘画
结果:=未恢复;
结束;
程序TMyForm.BeginSizing;
变量
UseCompositedWindowsTypeExclusive:布尔值;
控制:t控制;
WinControl:双控;
开始
如果执行了SizingComposition,则开始
UseCompositedWindowsTypeExclusive:=Win32MajorVersion>=6//XP无法处理太多WS_EX_合成的窗口
对于ControlEnumerator(TWinControl)中的控件,请执行begin
WinControl:=TWinControl(控制);
如果使用CompositedWindowsTypeExclusive,则开始
设置合成(WinControl,真);
结束,否则开始
如果WinControl为TPanel,则开始
TPanel(WinControl).FullRepaint:=假;
结束;
如果(WinControl为TCustomGroupBox)或(WinControl为TCustomRadioGroup)或(WinControl为TCustomGrid),则开始
//找不到其他方法让这些笨拙的顾客停止闪烁
设置合成(WinControl,真);
如果控制支持双缓冲(WinControl),则结束else,然后开始
WinControl.DoubleBuffered:=真;
结束;
结束;
结束;
结束;
结束;
程序TMyForm.EndSize;
变量
控制:t控制;
WinControl:双控;
开始
如果执行了SizingComposition,则开始
对于ControlEnumerator(TWinControl)中的控件,请执行begin
WinControl:=TWinControl(控制);
如果WinControl为TPanel,则开始
TPanel(WinControl).FullRepaint:=真;
结束;
更新双缓冲(WinControl);
SetComposited(WinControl,假);
结束;
结束;
结束;
函数TMyForm.ControlSupportsDoubleBuffered(控件:TWinControl):布尔值;
常数
NotSupportedClasses:TControlClass的数组[0..1](
TCustomForm,//一般策略是不将缓冲区窗体加倍
TCustomRichEdit//如果使用双缓冲,则无法绘制
);
变量
i:整数;
开始
对于i:=低(NotSupportedClass)到高(NotSupportedClass)不开始
如果不支持控件类[i],则开始
结果:=假;
出口
结束;
结束;
结果:=真;
结束;
程序TMyForm.UpdateDoubleBuffered(控制:TWinControl);
函数控件双缓冲:布尔值;
常数
DoubleBufferedClasses:TControlClass的数组[0..2](
TMyCustomGrid,//更新时闪烁
TCustomListView,//更新时闪烁
TCustomStatusBar//图形不真实,例如文件加载期间的我的主窗体状态栏
);
变量
i:整数;
开始
如果不在RemoteSession中,则开始
//看看老的新的东西,税收:远程桌面连接和绘画
对于i:=低(双缓冲类)到高(双缓冲类)不开始
如果控件为DoubleBufferedClasses[i],则开始
结果:=真;
出口
结束;
结束;
结束;
结果:=假;
结束;
变量
双缓冲:布尔;
开始
如果控制支持双缓冲(控制),则开始
双重缓冲:=控制双重缓冲;
结束,否则开始
双缓冲:=假;
结束;
Control.DoubleBuffered:=双缓冲;
结束;
程序TMyForm.UpdateDoubleBuffered;
变量
控制:t控制;
开始
用于ControlEnumerator(TWinControl)中的控件
typedef LRESULT CALLBACK(*PWndProc)(HWND, UINT, WPARAM, LPARAM);

void SetNonFlickeringWndProc(TWinControl &control, std::map<HWND,PWndProc> &list, PWndProc new_proc)
{
   if (control.Handle == 0)
   {
      return;
   }

   PWndProc oldWndProc = (PWndProc)SetWindowLong(control.Handle, GWL_WNDPROC, (LONG)new_proc);
   list[control.Handle] = oldWndProc;

   int count = control.ControlCount;
   for (int i = 0; i < count; i++)
   {
      TControl *child_control = control.Controls[i];
      TWinControl *child_wnd_control = dynamic_cast<TWinControl*>(child_control);
      if (child_wnd_control == NULL)
      {
         continue;
      }

      SetNonFlickeringWndProc(*child_wnd_control, list, new_proc);
   }
}

void RestoreWndProc(std::map<HWND,PWndProc> &old_wnd_proc)
{
   std::map<HWND,PWndProc>::iterator it;
   for (it = old_wnd_proc.begin(); it != old_wnd_proc.end(); it++)
   {
      LONG res = SetWindowLong(it->first, GWL_WNDPROC, (LONG)it->second);
   }
   old_wnd_proc.clear();
}

std::map<HWND,PWndProc> oldwndproc;   // addresses for window procedures for all components in form

LRESULT CALLBACK NonFlickeringWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg == WM_ERASEBKGND)
    {
        return 1;
    }
    return ((PWndProc)oldwndproc[hwnd])(hwnd, uMsg, wParam, lParam);
}

void __fastcall TForm1::FormShow(TObject *Sender)
{
   oldwndproc.clear();
   SetNonFlickeringWndProc(*this, oldwndproc, &NonFlickeringWndProc);
}

void __fastcall TForm1::FormClose(TObject* Sender, TCloseAction& Action)
{
   RestoreWndProc(oldwndproc_etype);
}
TLabel = class( stdCtrls.TLabel )
  protected
   procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  end;
procedure TLabel.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
 Message.Result:=1; // Fake erase
end;