How to make ComboBox drop-down list be *Narrower* than the ComboBox itself

筅森魡賤 提交于 2019-12-11 09:03:32

问题


Is it possible to make a ComboBox Drop-down list be Narrower than the Combobox itself?

There are plenty of examples setting the width using SendMessage(Handle, CB_SETDROPPEDWIDTH, 100, 200);

but the minimum value is taken from the combobox itself, regardless of what is specificed here.

All these examples make it bigger.


回答1:


Before the drop-down list is to be painted, a WM_CTLCOLORLISTBOX message is issued.

By overriding the combobox WindowProc it is possible to shrink the drop down list width.

The WM_CTLCOLORLISTBOX message is detected and since the message supplies the handle of the list window, we can grab the list bounds and call MoveWindow with a shrinked width.

type
  TMyForm = class(TForm)
    ...
    ComboBox1 : TComboBox;
    procedure FormCreate(Sender: TObject);
    ...
  private
    { Private declarations }
    ComboBox1WindowProcORIGINAL : TWndMethod;
    procedure ComboBox1WindowProc(var Message: TMessage);
    ...
  end;

procedure TMyForm.ComboBox1WindowProc(var Message: TMessage);
var
  lbr: TRect;
begin
  //drawing the list box with combobox items
  if Message.Msg = WM_CTLCOLORLISTBOX then
  begin
    //list box rectangle
    GetWindowRect(Message.LParam, lbr);
    //Shrink window width
    MoveWindow( Message.LParam,
                lbr.Left,
                lbr.Top,
                50,                  // New width
                lbr.Bottom-lbr.Top,
                false); 
  end;
  ComboBox1WindowProcORIGINAL(Message);  
end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
  //attach custom WindowProc for ComboBox1
  ComboBox1WindowProcORIGINAL := ComboBox1.WindowProc;
  ComboBox1.WindowProc := ComboBox1WindowProc;
end;


You can make a small hack by creating an interposer class. Either put it in a separate unit and declare it after vcl.StdCtrls, or put it in your form unit.

type
  TComboBox = class(vcl.StdCtrls.TComboBox)
    private
      FDropDownWidth : Integer;
      function GetDropDownWidth : Integer;
    protected
      procedure WndProc(var Mess: TMessage); override;
    public
      Constructor Create( aOwner: TComponent ); override;
      property DropDownWidth : Integer read GetDropDownWidth write FDropDownWidth;
  end;

constructor TComboBox.Create(aOwner: TComponent);
begin
  inherited;
  DropDownWidth := -1;  // Default state
end;

function TComboBox.GetDropDownWidth: Integer;
begin
  if FDropDownWidth = -1 then // Just keep a default state
    Result := Self.Width
  else
    Result := FDropDownWidth;
end;

procedure TComboBox.WndProc(var Mess: TMessage);
var
  lbr: TRect;
begin    
  if Mess.Msg = WM_CTLCOLORLISTBOX then
  begin
    //list box rectangle
    GetWindowRect(Mess.LParam, lbr);
    //Shrink window width
    MoveWindow( Mess.LParam,
                lbr.Left,
                lbr.Top,
                DropDownWidth,
                lbr.Bottom-lbr.Top,
                false);
  end
  else
  if Mess.Msg = CB_SETDROPPEDWIDTH then
    DropDownWidth := Mess.WParam;

  Inherited WndProc(Mess);
end;

Either set the drop-down width with cb.Perform(CB_SETDROPPEDWIDTH,newWidth,0); or cb.DropDownWidth := newWidth;



来源:https://stackoverflow.com/questions/50116385/how-to-make-combobox-drop-down-list-be-narrower-than-the-combobox-itself

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!