- redo FinishCreateWindow to allow window subclassing,
  - subclass combobox to get access to the first messages that control receives
ideintf: remove workaround with ValueComboBox handle check in MeasureItem

git-svn-id: trunk@24686 -
This commit is contained in:
paul 2010-04-17 19:53:55 +00:00
parent 3fce5af5cc
commit f95b2f63d5
5 changed files with 110 additions and 33 deletions

View File

@ -1468,7 +1468,7 @@ procedure TOICustomPropertyGrid.ValueComboBoxMeasureItem(Control: TWinControl;
var var
CurRow: TOIPropertyGridRow; CurRow: TOIPropertyGridRow;
begin begin
if (FItemIndex >= 0) and (FItemIndex < FRows.Count) and (ValueComboBox.HandleAllocated) then if (FItemIndex >= 0) and (FItemIndex < FRows.Count) then
begin begin
CurRow := Rows[FItemIndex]; CurRow := Rows[FItemIndex];
CurRow.Editor.ListMeasureHeight('Fj', Index, ValueComboBox.Canvas, AHeight); CurRow.Editor.ListMeasureHeight('Fj', Index, ValueComboBox.Canvas, AHeight);

View File

@ -85,7 +85,7 @@ function CallDefaultWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
var var
Info: TComboboxInfo; Info: TComboboxInfo;
begin begin
Result := WndClassName(Window) = ComboboxClsName; Result := WndClassName(Window) = LCLComboboxClsName;
if not Result then if not Result then
Exit; Exit;
Info.cbSize := SizeOf(Info); Info.cbSize := SizeOf(Info);

View File

@ -221,6 +221,7 @@ const
TabControlClsName: array[0..15] of char = 'SysTabControl32'#0; TabControlClsName: array[0..15] of char = 'SysTabControl32'#0;
ListViewClsName: array[0..13] of char = 'SysListView32'#0; ListViewClsName: array[0..13] of char = 'SysListView32'#0;
LCLComboboxClsName: array[0..11] of char = 'LCLComboBox'#0;
ClsNameW: array[0..6] of WideChar = ('W', 'i', 'n', 'd', 'o', 'w', #0); ClsNameW: array[0..6] of WideChar = ('W', 'i', 'n', 'd', 'o', 'w', #0);
ClsHintNameW: array[0..10] of WideChar = ('H', 'i', 'n', 't', 'W', 'i', 'n', 'd', 'o', 'w', #0); ClsHintNameW: array[0..10] of WideChar = ('H', 'i', 'n', 't', 'W', 'i', 'n', 'd', 'o', 'w', #0);

View File

@ -117,15 +117,23 @@ type
SubClassWndProc: pointer; SubClassWndProc: pointer;
StrCaption, WindowTitle: String; StrCaption, WindowTitle: String;
pClassName: PChar; pClassName: PChar;
pSubClassName: PChar;
end; end;
TNCCreateParams = record
WinControl: TWinControl;
DefWndProc: WNDPROC;
Handled: Boolean;
end;
PNCCreateParams = ^TNCCreateParams;
// TODO: better names? // TODO: better names?
procedure PrepareCreateWindow(const AWinControl: TWinControl; procedure PrepareCreateWindow(const AWinControl: TWinControl;
const CreateParams: TCreateParams; var Params: TCreateWindowExParams); const CreateParams: TCreateParams; var Params: TCreateWindowExParams);
procedure FinishCreateWindow(const AWinControl: TWinControl; var Params: TCreateWindowExParams; procedure FinishCreateWindow(const AWinControl: TWinControl; var Params: TCreateWindowExParams;
const AlternateCreateWindow: boolean); const AlternateCreateWindow: boolean; SubClass: Boolean = False);
procedure WindowCreateInitBuddy(const AWinControl: TWinControl; procedure WindowCreateInitBuddy(const AWinControl: TWinControl;
var Params: TCreateWindowExParams); var Params: TCreateWindowExParams);
@ -186,36 +194,84 @@ begin
end; end;
procedure FinishCreateWindow(const AWinControl: TWinControl; var Params: TCreateWindowExParams; procedure FinishCreateWindow(const AWinControl: TWinControl; var Params: TCreateWindowExParams;
const AlternateCreateWindow: boolean); const AlternateCreateWindow: boolean; SubClass: Boolean = False);
var var
lhFont: HFONT; lhFont: HFONT;
AErrorCode: Cardinal; AErrorCode: Cardinal;
NCCreateParams: TNCCreateParams;
WindowClass, DummyClass: WndClass;
{$ifdef WindowsUnicodeSupport}
WindowClassW, DummyClassW: WndClassW;
{$endif}
begin begin
NCCreateParams.DefWndProc := nil;
NCCreateParams.WinControl := AWinControl;
NCCreateParams.Handled := False;
if not AlternateCreateWindow then if not AlternateCreateWindow then
begin begin
with Params do with Params do
begin begin
if (Flags and WS_CHILD) <> 0 then if SubClass then
begin begin
// menu handle is also for specifying a control id if this is a child {$ifdef WindowsUnicodeSupport}
MenuHandle := HMENU(AWinControl); if UnicodeEnabledOS then
end else begin begin
MenuHandle := HMENU(nil); if GetClassInfoW(System.HInstance, PWideChar(WideString(pClassName)), @WindowClassW) then
begin
NCCreateParams.DefWndProc := WndProc(WindowClassW.lpfnWndProc);
if not GetClassInfoW(System.HInstance, PWideChar(WideString(pSubClassName)), @DummyClassW) then
begin
with WindowClassW do
begin
LPFnWndProc := SubClassWndProc;
hInstance := System.HInstance;
lpszClassName := PWideChar(WideString(pSubClassName));
end;
Windows.RegisterClassW(@WindowClassW);
end;
pClassName := pSubClassName;
end;
end
else
{$endif}
begin
if GetClassInfo(System.HInstance, pClassName, @WindowClass) then
begin
NCCreateParams.DefWndProc := WndProc(WindowClass.lpfnWndProc);
if not GetClassInfo(System.HInstance, pSubClassName, @DummyClass) then
begin
with WindowClass do
begin
LPFnWndProc := SubClassWndProc;
hInstance := System.HInstance;
lpszClassName := pSubClassName;
end;
Windows.RegisterClass(@WindowClass);
end;
pClassName := pSubClassName;
end;
end;
end; end;
if (Flags and WS_CHILD) <> 0 then
// menu handle is also for specifying a control id if this is a child
MenuHandle := HMENU(AWinControl)
else
MenuHandle := HMENU(nil);
{$ifdef WindowsUnicodeSupport} {$ifdef WindowsUnicodeSupport}
if UnicodeEnabledOS then if UnicodeEnabledOS then
Window := CreateWindowExW(FlagsEx, PWideChar(WideString(pClassName)), Window := CreateWindowExW(FlagsEx, PWideChar(WideString(pClassName)),
PWideChar(UTF8ToUTF16(WindowTitle)), Flags, PWideChar(UTF8ToUTF16(WindowTitle)), Flags,
Left, Top, Width, Height, Parent, MenuHandle, HInstance, nil) Left, Top, Width, Height, Parent, MenuHandle, HInstance, @NCCreateParams)
else else
Window := CreateWindowEx(FlagsEx, pClassName, Window := CreateWindowEx(FlagsEx, pClassName,
PChar(Utf8ToAnsi(WindowTitle)), Flags, PChar(Utf8ToAnsi(WindowTitle)), Flags,
Left, Top, Width, Height, Parent, MenuHandle, HInstance, nil); Left, Top, Width, Height, Parent, MenuHandle, HInstance, @NCCreateParams);
{$else} {$else}
Window := CreateWindowEx(FlagsEx, pClassName, Window := CreateWindowEx(FlagsEx, pClassName,
PChar(WindowTitle), Flags, PChar(WindowTitle), Flags,
Left, Top, Width, Height, Parent, MenuHandle, HInstance, nil); Left, Top, Width, Height, Parent, MenuHandle, HInstance, @NCCreateParams);
{$endif} {$endif}
if Window = 0 then if Window = 0 then
@ -240,14 +296,18 @@ begin
if Window <> HWND(Nil) then if Window <> HWND(Nil) then
begin begin
// some controls (combobox) immediately send a message upon setting font // some controls (combobox) immediately send a message upon setting font
WindowInfo := AllocWindowInfo(Window); if not NCCreateParams.Handled then
if GetWin32WindowInfo(Parent)^.needParentPaint then begin
WindowInfo^.needParentPaint := true; WindowInfo := AllocWindowInfo(Window);
WindowInfo^.WinControl := AWinControl; if GetWin32WindowInfo(Parent)^.needParentPaint then
AWinControl.Handle := Window; WindowInfo^.needParentPaint := true;
if SubClassWndProc <> nil then WindowInfo^.WinControl := AWinControl;
WindowInfo^.DefWndProc := Windows.WNDPROC(SetWindowLong( AWinControl.Handle := Window;
Window, GWL_WNDPROC, PtrInt(SubClassWndProc))); if Assigned(SubClassWndProc) then
WindowInfo^.DefWndProc := Windows.WNDPROC(SetWindowLong(
Window, GWL_WNDPROC, PtrInt(SubClassWndProc)));
end;
if AWinControl.Font.IsDefault then if AWinControl.Font.IsDefault then
lhFont := Win32WidgetSet.DefaultFont lhFont := Win32WidgetSet.DefaultFont
else else

View File

@ -350,21 +350,38 @@ function ComboBoxWindowProc(Window: HWnd; Msg: UInt; WParam: Windows.WParam;
LParam: Windows.LParam): LResult; stdcall; LParam: Windows.LParam): LResult; stdcall;
var var
Info: TComboboxInfo; Info: TComboboxInfo;
WindowInfo: PWin32WindowInfo;
NCCreateParams: PNCCreateParams;
begin begin
// darn MS: if combobox has edit control, and combobox receives focus, it // darn MS: if combobox has edit control, and combobox receives focus, it
// passes it on to the edit, so it will send a WM_KILLFOCUS; inhibit // passes it on to the edit, so it will send a WM_KILLFOCUS; inhibit
// also don't pass WM_SETFOCUS to the lcl, // also don't pass WM_SETFOCUS to the lcl,
// it will get one from the edit control // it will get one from the edit control
if ((Msg = WM_KILLFOCUS) or (Msg = WM_SETFOCUS)) then case Msg of
begin WM_NCCREATE:
Info.cbSize := SizeOf(Info); begin
Win32Extra.GetComboBoxInfo(Window, @Info); NCCreateParams := PCREATESTRUCT(lParam)^.lpCreateParams;
if (HWND(WParam) = Info.hwndItem) or (HWND(WParam) = Info.hwndList) then if Assigned(NCCreateParams) then
begin begin
// continue normal processing, don't send to lcl WindowInfo := AllocWindowInfo(Window);
Result := CallDefaultWindowProc(Window, Msg, WParam, LParam); WindowInfo^.WinControl := NCCreateParams^.WinControl;
Exit; WindowInfo^.WinControl.Handle := Window;
end; WindowInfo^.DefWndProc := NCCreateParams^.DefWndProc;
WindowInfo^.needParentPaint := False;
NCCreateParams^.Handled := True;
end;
end;
WM_KILLFOCUS, WM_SETFOCUS:
begin
Info.cbSize := SizeOf(Info);
Win32Extra.GetComboBoxInfo(Window, @Info);
if (HWND(WParam) = Info.hwndItem) or (HWND(WParam) = Info.hwndList) then
begin
// continue normal processing, don't send to lcl
Result := CallDefaultWindowProc(Window, Msg, WParam, LParam);
Exit;
end;
end;
end; end;
// normal processing // normal processing
Result := WindowProc(Window, Msg, WParam, LParam); Result := WindowProc(Window, Msg, WParam, LParam);
@ -799,13 +816,12 @@ begin
if TComboBox(AWinControl).Sorted Then if TComboBox(AWinControl).Sorted Then
Flags:= Flags or CBS_SORT; Flags:= Flags or CBS_SORT;
pClassName := ComboboxClsName; pClassName := ComboboxClsName;
pSubClassName := LCLComboboxClsName;
Flags := Flags or (WS_VSCROLL or CBS_AUTOHSCROLL or CBS_HASSTRINGS); Flags := Flags or (WS_VSCROLL or CBS_AUTOHSCROLL or CBS_HASSTRINGS);
SubClassWndProc := @ComboBoxWindowProc; SubClassWndProc := @ComboBoxWindowProc;
end; end;
// create window // create window
FinishCreateWindow(AWinControl, Params, false); FinishCreateWindow(AWinControl, Params, False, True);
// combobox is not a transparent control -> no need for parentpainting
Params.WindowInfo^.needParentPaint := false;
Info.cbSize:= SizeOf(Info); Info.cbSize:= SizeOf(Info);
Win32Extra.GetComboBoxInfo(Params.Window, @Info); Win32Extra.GetComboBoxInfo(Params.Window, @Info);