普通的Windows ComboBox(csDropDown或csDropDownList样式)将在其下方打开其下拉列表,如果下方没有空格,则在组合上方打开.我可以控制此列表的位置(至少按Y坐标)吗?
解决方法
发布将正确显示下拉列表动画的代码示例,并强制显示ComboBox1上方的下拉列表.这个代码子类ComboBox 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,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,R.Left,R.Top - DY,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;
笔记:
>我完全同意David和其他人的意见,这对于改变TComboBox的这种特定默认行为是一个坏主意. OP尚未回应为什么他想要这样的行为.>上面的代码是用D5 / XP测试的.