如何更改组合框下拉列表的位置?

时间:2018-10-08 10:55:48

标签: delphi combobox delphi-2009

我想更改下拉列表的宽度以适合项目文本。这样做可能会使列表扩展到屏幕之外。我想做的是在屏幕内移动下拉列表,使其再次可见。

该问题在this article中进行了描述。但我尝试过,但不起作用。我从没有收到WM_CTLCOLORLISTBOX消息。我还尝试将MoveWindow方法与ComboBox.ListHandle一起使用,但是列表是在默认位置绘制的。

2 个答案:

答案 0 :(得分:1)

这就是我要创建一个具有自动列表宽度的ComboBox的方法,下拉列表时不会出现在屏幕上:

  TNewComboBox = class(TComboBox)
  private
    FAutoListWidth: Boolean;
  protected
    procedure WndProc(var Msg: TMessage); override;
    procedure DropDown; override;
    procedure SetDropDownCount(const Value: Integer); override;
    procedure CreateWnd; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property AutoListWidth: Boolean read FAutoListWidth write FAutoListWidth default False;
    property DropDownCount default 20;
  end;

constructor TNewComboBox.Create(AOwner: TComponent);
begin
 inherited;
 FAutoListWidth:= False;
 DropDownCount:= 20;
end;

procedure TNewComboBox.CreateWnd;
begin
 if HandleAllocated then SetDropDownCount(DropDownCount);
end;

procedure TNewComboBox.WndProc(var Msg: TMessage);
var ListR, ComboR: TRect;
    Wdt, Hgt: Integer;
begin
 if (Msg.Msg = WM_CTLCOLORLISTBOX) then begin
  GetWindowRect(Handle, ComboR);
  GetWindowRect(Msg.LParam, ListR);
  Wdt:= ListR.Right - ListR.Left;
  Hgt:= ListR.Bottom - ListR.Top;
  if ListR.Right > (Screen.Width - 5) then ListR.Left:= Screen.Width - 5 - Wdt
   else if ListR.Left < 5 then ListR.Left:= 5;
  MoveWindow(Msg.LParam, ListR.Left, ListR.Top, Wdt, Hgt, True);
 end;
 inherited WndProc(Msg);
end;

procedure TNewComboBox.DropDown;
var I, item_width, max_width: Integer;
begin
 max_width:= 0;
 if FAutoListWidth then begin
  for I:= 0 to Items.Count -1 do begin
   item_width:= Canvas.TextWidth(Items[I]) + 10;
   if item_width > max_width then max_width:= item_width;
  end;
  if DropDownCount < Items.Count then
   max_width:= max_width + GetSystemMetrics(SM_CXVSCROLL);
 end;
 SendMessage(Handle, CB_SETDROPPEDWIDTH, max_width, 0);
 inherited;
end;

procedure TNewComboBox.SetDropDownCount(const Value: Integer);
begin
 inherited;
 if HandleAllocated then
  SendMessage(Handle, CB_SETMINVISIBLE, WPARAM(Value), 0);
end;

感谢您的提示!

答案 1 :(得分:0)

您可以使用GetComboBoxInfo:

const
    WM_AFTER_DROPDOWN = WM_USER + 123;

type
TForm2 = class(TForm)
    ComboBox1: TComboBox;
    procedure ComboBox1DropDown(Sender: TObject);
private
    procedure WMAfterDropDown(var Msg: TMessage); message WM_AFTER_DROPDOWN;
    procedure MoveListWindow;
end;

var
Form2: TForm2;

implementation

procedure TForm2.MoveListWindow;
var
    cbi: TComboBoxInfo;
    r: TRect;
begin
    cbi.cbSize := SizeOf(cbi);
    GetComboBoxInfo(Combobox1.Handle, cbi);
    GetWindowRect(cbi.hwndList, r);
    MoveWindow(cbi.hwndList, 0, 0, r.Width, r.Height, true);
end;

procedure TForm2.WMAfterDropDown(var Msg: TMessage);
begin
    MoveListWindow;
end;

procedure TForm2.ComboBox1DropDown(Sender: TObject);
begin
    PostMessage(Handle, WM_AFTER_DROPDOWN, 0, 0);
end;