Как изменить положение выпадающего списка поля со списком? - PullRequest
0 голосов
/ 08 октября 2018

Я хочу изменить ширину выпадающего списка, чтобы соответствовать тексту элементов.При этом могут быть случаи, когда список расширяется за пределы экрана.Я хочу переместить выпадающий список на экране, чтобы он снова стал видимым.

Проблема описана в этой статье .Но я попробовал, и это не работает.Я никогда не получаю WM_CTLCOLORLISTBOX сообщения.Я также пытался использовать метод MoveWindow с ComboBox.ListHandle, но список нарисован в позиции по умолчанию.

Ответы [ 2 ]

0 голосов
/ 08 октября 2018

Вот так у меня получился 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;

Спасибо за советы!

0 голосов
/ 08 октября 2018

Вы можете использовать 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;
...