普通的Windows组合框(csDropDown或csDropDownList样式)将在组合框的正下方打开其下拉列表,如果下方没有空格,则在组合框的上方打开。我可以控制这个列表的位置吗(至少通过Y坐标)?
csDropDown
csDropDownList
zqry0prt1#
张贴一个代码示例,将显示下拉列表动画正确,并将强制显示下拉列表以上ComboBox1。这段代码子类化了ComboBox hwndList:
ComboBox1
hwndList
TForm1 = class(TForm) ComboBox1: TComboBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FComboBoxListDropDown: Boolean; FComboBoxListWnd: HWND; FOldComboBoxListWndProc, FNewComboBoxListWndProc: Pointer; procedure ComboBoxListWndProc(var Message: TMessage); end; .... procedure TForm1.FormCreate(Sender: TObject); var Info: TComboBoxInfo; begin ZeroMemory(@Info, SizeOf(Info)); Info.cbSize := SizeOf(Info); GetComboBoxInfo(ComboBox1.Handle, Info); FComboBoxListWnd := Info.hwndList; FNewComboBoxListWndProc := MakeObjectInstance(ComboBoxListWndProc); FOldComboBoxListWndProc := Pointer(GetWindowLong(FComboBoxListWnd, GWL_WNDPROC)); SetWindowLong(FComboBoxListWnd, GWL_WNDPROC, Integer(FNewComboBoxListWndProc)); end; procedure TForm1.FormDestroy(Sender: TObject); begin SetWindowLong(FComboBoxListWnd, GWL_WNDPROC, Integer(FOldComboBoxListWndProc)); FreeObjectInstance(FNewComboBoxListWndProc); end; procedure TForm1.ComboBoxListWndProc(var Message: TMessage); var R: TRect; DY: Integer; begin if (Message.Msg = WM_MOVE) and not FComboBoxListDropDown then begin FComboBoxListDropDown := True; try GetWindowRect(FComboBoxListWnd, R); DY := (R.Bottom - R.Top) + ComboBox1.Height + 1; // set new Y position for drop-down list: always above ComboBox1 SetWindowPos(FComboBoxListWnd, 0, R.Left, R.Top - DY , 0, 0, SWP_NOOWNERZORDER or SWP_NOZORDER or SWP_NOSIZE or SWP_NOSENDCHANGING); finally FComboBoxListDropDown := False; end; end; Message.Result := CallWindowProc(FOldComboBoxListWndProc, FComboBoxListWnd, Message.Msg, Message.WParam, Message.LParam); end;
字符串
备注:
1.我完全同意大卫和其他人的观点,即更改TComboBox的特定默认行为是一个坏主意。OP还没有回答为什么他想要这样的行为。1.上面的代码是用D5/XP测试的。
TComboBox
ddrv8njm2#
您可以使用GetComboBoxInfo获取用于列表的窗口的句柄,然后移动该窗口。就像这样:
GetComboBoxInfo
type TMyForm = class(TForm) ComboBox1: TComboBox; procedure ComboBox1DropDown(Sender: TObject); protected procedure WMMoveListWindow(var Message: TMessage); message WM_MOVELISTWINDOW; end; .... procedure TMyForm.ComboBox1DropDown(Sender: TObject); begin PostMessage(Handle, WM_MOVELISTWINDOW, 0, 0); end; procedure TMyForm.WMMoveListWindow(var Message: TMessage); var cbi: TComboBoxInfo; Rect: TRect; NewTop: Integer; begin cbi.cbSize := SizeOf(cbi); GetComboBoxInfo(ComboBox1.Handle, cbi); GetWindowRect(cbi.hwndList, Rect); NewTop := ClientToScreen(Point(0, ComboBox1.Top-Rect.Height)).Y; MoveWindow(cbi.hwndList, Rect.Left, NewTop, Rect.Width, Rect.Height, True); end;
字符串我忽略了错误检查的问题,以保持代码简单。然而,要注意的是,它看起来相当可怕,因为下拉动画仍然显示。也许你能找到一种方法来禁用它。但是,你根本不需要做这样的事情,因为Windows已经为你做了。将窗体拖到屏幕底部,然后下拉组合。然后你会看到列表出现在组合上方。就像这样:
的数据
azpvetkf3#
如果Combobox的样式设置为csOwnerDrawVariable,我就可以处理DropDownList的大小!没有高度太小,无法按预期由DropDownCount设置!( Delphi 11.3补丁1)谢啦,谢啦
3条答案
按热度按时间zqry0prt1#
张贴一个代码示例,将显示下拉列表动画正确,并将强制显示下拉列表以上
ComboBox1
。这段代码子类化了ComboBoxhwndList
:字符串
备注:
1.我完全同意大卫和其他人的观点,即更改
TComboBox
的特定默认行为是一个坏主意。OP还没有回答为什么他想要这样的行为。1.上面的代码是用D5/XP测试的。
ddrv8njm2#
您可以使用
GetComboBoxInfo
获取用于列表的窗口的句柄,然后移动该窗口。就像这样:字符串
我忽略了错误检查的问题,以保持代码简单。
然而,要注意的是,它看起来相当可怕,因为下拉动画仍然显示。也许你能找到一种方法来禁用它。
但是,你根本不需要做这样的事情,因为Windows已经为你做了。将窗体拖到屏幕底部,然后下拉组合。然后你会看到列表出现在组合上方。就像这样:
的数据
azpvetkf3#
如果Combobox的样式设置为csOwnerDrawVariable,我就可以处理DropDownList的大小!
没有高度太小,无法按预期由DropDownCount设置!
( Delphi 11.3补丁1)
谢啦,谢啦