如何在跟踪期间消除头部伪像 - HDN_TRACK?

问题描述 投票:2回答:1

在进行“实时”跟踪时,标题控件偶尔会留下伪影,如下图所示:

image

前两个图像来自附加程序。第三个图像(没有蓝色)来自Windows资源管理器。

要获取工件,只需将分隔符拖离程序窗口右边缘的右侧,然后快速将其移回视图中。可能需要几次尝试,具体取决于您将分隔符带回窗口的速度。

Windows资源管理器通过在拖动时使标题不绘制黑色垂直条来避免此问题。

编辑:正如Sertac所指出的,Windows资源管理器使用不同的控件,这就是它没有出现问题的原因。

我有两(2)个问题:

  1. 如何告诉标题控件不要绘制垂直黑条?我在文档中找不到任何内容。
  2. 如果没有“拥有者绘制”标题就不可能摆脱黑条,是否有某种方法可以防止出现神器?

我用来测试标题控件的程序如下。

{$LONGSTRINGS    OFF}
{$WRITEABLECONST ON}

{$ifdef WIN32}           { tell Windows we want v6 of commctrl                }
  {$R Manifest32.res}
{$endif}

{$ifdef WIN64}
  {$R Manifest64.res}
{$endif}

program _Header_Track;

uses Windows, Messages, CommCtrl;

const
  ProgramName  = 'Header_Track';

{-----------------------------------------------------------------------------}

{$ifdef VER90} { Delphi 2.0 }
type
  ptrint  = longint;
  ptruint = dword;

const
  ICC_WIN95_CLASSES     = $000000FF;              { missing in Delphi 2       }

type
  TINITCOMMONCONTROLSEX = packed record
    dwSize                  : DWORD;
    dwICC                   : DWORD;
  end;
  PINITCOMMONCONTROLSEX = ^TINITCOMMONCONTROLSEX;

  function InitCommonControlsEx(var InitClasses : TINITCOMMONCONTROLSEX)
           : BOOL; stdcall; external comctl32;
{$endif}


{$ifdef VER90}
  // for Delphi 2.0 define GetWindowLongPtr and SetWindowLongPtr as synonyms of
  // GetWindowLong and SetWindowLong respectively.

  function GetWindowLongPtr(Wnd   : HWND;
                            Index : ptrint)
           : ptruint; stdcall; external 'user32' name 'GetWindowLongA';

  function SetWindowLongPtr(Wnd     : HWND;
                            Index   : ptrint;
                            NewLong : DWORD)
           : ptruint; stdcall; external 'user32' name 'SetWindowLongA';

  function GetClassLongPtr(Wnd      : HWND;
                           Index    : ptrint)
           : ptruint; stdcall; external 'user32' name 'GetClassLongA';

  function SetClassLongPtr(Wnd      : HWND;
                           Index    : ptrint;
                           NewLong  : ptruint)
           : ptruint; stdcall; external 'user32' name 'SetClassLongA';
{$endif}


{$ifdef FPC}
  { make the FPC definitions match Delphi's                                   }

type
  THDLAYOUT = record
    Rect        : PRECT;
    WindowPos   : PWINDOWPOS;
  end;
  PHDLAYOUT = ^THDLAYOUT;

function Header_Layout(Wnd : HWND; Layout : PHDLAYOUT) : WINBOOL; inline;
begin
  Header_Layout := WINBOOL(SendMessage(Wnd, HDM_LAYOUT, 0, ptruint(Layout)));
end;
{$endif}

{-----------------------------------------------------------------------------}

function WndProc (Wnd : HWND; Msg : UINT; wParam, lParam : ptrint)
         : ptrint; stdcall;
  { main application/window handler function                                  }
const
  HEADER_ID                = 1000;
  HEADER_ITEMS_WIDTH       =  100;

  Header          : HWND   =    0;

  HeaderText      : packed array[0..2] of pchar =
  (
    'Name',
    'Date modified',
    'Type'
  );

var
  ControlsInit       : TINITCOMMONCONTROLSEX;

  HeaderPos          : TWINDOWPOS;
  HeaderRect         : TRECT;
  HeaderNotification : PHDNOTIFY absolute lParam;  { note overlay on lParam   }

  HeaderLayout       : THDLAYOUT;

  HeaderItem         : THDITEM;

  ClientRect         : TRECT;

  Style              : ptruint;

  i                  : integer;

begin
  WndProc := 0;

  case Msg of
    WM_CREATE:
    begin
      { initialize the common controls library                                }

      with ControlsInit do
      begin
        dwSize := sizeof(ControlsInit);
        dwICC  := ICC_WIN95_CLASSES;                       { includes headers }
      end;

      InitCommonControlsEx(ControlsInit);

      { create the header control                                             }

      Header := CreateWindowEx(0,
                               WC_HEADER,                  { class name       }
                               nil,                        { caption          }
                               HDS_BUTTONS            or
                               WS_CHILD               or
                               WS_VISIBLE             or
                               WS_CLIPCHILDREN        or
                               WS_CLIPSIBLINGS,
                               0,                          { at parent x = 0  }
                               0,                          {           y = 0  }
                               0,                          { width            }
                               0,                          { height           }
                               Wnd,                        { parent           }
                               HEADER_ID,                  { child id         }
                               hInstance,
                               nil);

      if Header = 0 then
      begin
        MessageBox(Wnd,
                   'Couldn''t create a header',
                   'Main Window - WM_CREATE',
                   MB_ICONERROR or MB_OK);

        WndProc := -1;                             { abort window creation    }

        exit;
      end;

      { remove the annoying double click behavior of the header buttons       }

      Style := GetClassLongPtr(Header, GCL_STYLE);
      Style := Style and (not CS_DBLCLKS);
      SetClassLongPtr(Header, GCL_STYLE, Style);

      { tell the header which font to use                                     }

      SendMessage(Header, WM_SETFONT, GetStockObject(DEFAULT_GUI_FONT), 0);

      { insert the column header in the header control                        }

      with HeaderItem do
      for i := low(HeaderText) to high(HeaderText) do
      begin
        mask    := HDI_FORMAT or HDI_TEXT or HDI_WIDTH;
        pszText := HeaderText[i];
        fmt     := HDF_STRING;
        cxy     := HEADER_ITEMS_WIDTH;             { width                    }

        Header_InsertItem(Header, i, HeaderItem);
      end;

      exit;
    end;

    WM_SIZE:
    begin
      { update the header size and location                                   }

      with HeaderLayout do
      begin
        WindowPos := @HeaderPos;
        Rect      := @HeaderRect;
      end;

      GetClientRect(Wnd, ClientRect);
      CopyRect(HeaderRect, ClientRect);

      ZeroMemory(@HeaderPos,  sizeof(HeaderPos));

      Header_Layout(Header, @HeaderLayout);     { updates HeaderPos           }

      { use HeaderPos to place the header where it should be in the window    }

      with HeaderPos do
      begin
        SetWindowPos(Header,
                     Wnd, x, y, cx, cy,
                     Flags);
      end;

      exit;
    end; { WM_SIZE }


    WM_NOTIFY:
    begin
      case HeaderNotification^.Hdr.Code of
        HDN_BEGINTRACK:
        begin
          { Allow dragging using the left mouse button only                   }

          if HeaderNotification^.Button <> 0 then
          begin
            WndProc := ptrint(TRUE);   { don't track                          }
            exit;
          end;

          exit;
        end;

        HDN_TRACK:
        begin
          { tell the header to resize itself                                  }

          Header_SetItem(Header,
                         HeaderNotification^.Item,
                         HeaderNotification^.pitem^);

          exit;
        end;
      end;
    end;

    WM_DESTROY:
    begin
      PostQuitMessage(0);

      exit;
    end;
  end; { case msg }

  WndProc := DefWindowProc (Wnd, Msg, wParam, lParam);
end;

{-----------------------------------------------------------------------------}

function InitAppClass: WordBool;
  { registers the application's window classes                                }
var
  cls : TWndClassEx;

begin
  cls.cbSize          := sizeof(TWndClassEx);           { must be initialized }

  if not GetClassInfoEx (hInstance, ProgramName, cls) then
  begin
    with cls do
    begin
      style           := CS_BYTEALIGNCLIENT;
      lpfnWndProc     := @WndProc;
      cbClsExtra      := 0;
      cbWndExtra      := 0;
      hInstance       := system.hInstance;
      hIcon           := 0;
      hCursor         := LoadCursor(0, IDC_ARROW);
      hbrBackground   := COLOR_WINDOW + 1;
      lpszMenuName    := nil;
      lpszClassName   := ProgramName;
      hIconSm         := 0;
    end;

    InitAppClass := WordBool(RegisterClassEx(cls));
  end
  else InitAppClass := TRUE;
end;

{-----------------------------------------------------------------------------}

function WinMain : integer;
  { application entry point                                                   }
var
  Wnd : HWND;
  Msg : TMsg;

begin
  if not InitAppClass then Halt (255);  { register application's class        }

  { Create the main application window                                        }

  Wnd := CreateWindowEx(WS_EX_CLIENTEDGE,
                        ProgramName,            { class name                  }
                        ProgramName,            { window caption text         }
                        ws_OverlappedWindow or  { window style                }
                        ws_SysMenu          or
                        ws_MinimizeBox      or
                        ws_ClipSiblings     or
                        ws_ClipChildren     or  { don't affect children       }
                        ws_visible,             { make showwindow unnecessary }
                        20,                     { x pos on screen             }
                        20,                     { y pos on screen             }
                        600,                    { window width                }
                        200,                    { window height               }
                        0,                      { parent window handle        }
                        0,                      { menu handle 0 = use class   }
                        hInstance,              { instance handle             }
                        nil);                   { parameter sent to WM_CREATE }

  if Wnd = 0 then Halt;                         { could not create the window }

  while GetMessage (Msg, 0, 0, 0) do            { wait for message            }
  begin
    TranslateMessage (Msg);                     { key conversions             }
    DispatchMessage  (Msg);                     { send to window procedure    }
  end;

  WinMain := Msg.wParam;                        { terminate with return code  }
end;

begin
  WinMain;
end.
delphi winapi controls freepascal
1个回答
5
投票

这是由于尝试同时在两种不同的功能模式下使用控件而导致的伪像。那,当然还有快速鼠标移动......

黑色垂直线实际上是指示器,当释放鼠标按钮时提示最终分隔符位置。当然,只有在标题控件不能实时反映列大小调整时才会使用此指示符。

但是,您正在响应跟踪通知实时调整列的大小。您应该在实时列拖动模式中使用标题控件,以便根本不会绘制指示符。

总之,包括HDS_FULLDRAG控件样式:

  Header := CreateWindowEx(0,
                           WC_HEADER,                  { class name       }
                           nil,                        { caption          }
                           HDS_BUTTONS            or
                           WS_CHILD               or
                           WS_VISIBLE             or
                           WS_CLIPCHILDREN        or
                           WS_CLIPSIBLINGS        or
                           HDS_FULLDRAG,
                           0,                          { at parent x = 0  }
                           0,                          {           y = 0  }
                           0,                          { width            }
                           0,                          { height           }
                           Wnd,                        { parent           }
                           HEADER_ID,                  { child id         }
                           hInstance,
                           nil);

并省略赛道通知:

    ...
 { // don't tell the header to resize, it will do it itself
    HDN_TRACK:
    begin
      // tell the header to resize itself                                  

      Header_SetItem(Header,
                     HeaderNotification^.Item,
                     HeaderNotification^.pitem^);

      exit;
    end;
 }
    ...
© www.soinside.com 2019 - 2024. All rights reserved.