在进行“实时”跟踪时,标题控件偶尔会留下伪影,如下图所示:
前两个图像来自附加程序。第三个图像(没有蓝色)来自Windows资源管理器。
要获取工件,只需将分隔符拖离程序窗口右边缘的右侧,然后快速将其移回视图中。可能需要几次尝试,具体取决于您将分隔符带回窗口的速度。
Windows资源管理器通过在拖动时使标题不绘制黑色垂直条来避免此问题。
编辑:正如Sertac所指出的,Windows资源管理器使用不同的控件,这就是它没有出现问题的原因。
我有两(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.
这是由于尝试同时在两种不同的功能模式下使用控件而导致的伪像。那,当然还有快速鼠标移动......
黑色垂直线实际上是指示器,当释放鼠标按钮时提示最终分隔符位置。当然,只有在标题控件不能实时反映列大小调整时才会使用此指示符。
但是,您正在响应跟踪通知实时调整列的大小。您应该在实时列拖动模式中使用标题控件,以便根本不会绘制指示符。
总之,包括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;
}
...