Ask the Delphi Pro 10-Minute Solutions

Resizing the Drop-down List of a TComboBox
By Brendan Delumpa

Can I resize the drop-down list of a TComboBox so that I can see the complete text of its items?

You can approach this problem in two ways. One's quick and dirty—the other's a bit more involved, but is much more reusable since it's a component. You can decide which one you want to use. Let's start out with the quick and dirty method, shall we?

To resize the list box of a combo box, you merely need to send the Windows API message CB_SETDROPPEDWIDTH to the combo box. Using the procedure function to implement the message, your call would be as follows:


ComboBox1.Perform(CB_SETDROPPEDWIDTH, <PixelWidth as Integer>, 0);
The best place to put this call would be in the OnDropDown method of the combo box. Here's how I implemented it:

procedure TForm1.ComboBox1DropDown(Sender: TObject);
begin
  //Set the width of the list to 200
  ComboBox1.Perform(CB_SETDROPPEDWIDTH, 200, 0);
end;
Pretty straight-forward, right? But there's one glaring weakness with this methodology. Your string items almost invariably will be different lengths, so the size you set may not be big enough. In that case, you have to loop through each item in the list and figure what the biggest one is, then set the size based on your results. I could give you the code that does this—in fact, you could probably figure that part out yourself. But think about this for a moment. This behavior would be pretty useful in all your applications that use combo boxes, and having to cut and paste code would be a real chore every time you wanted to implement it. Do you see what I'm getting at? Right. Let's build a component.

The TEnhCombo Component

Below is the code listing for my enhanced combo box component. Take a look at it, then I'll discuss it below:


{=================================================================
 Enhanced TComboBox - Copyright © 1998 Brendan V. Delumpa

 With this component, you have two ways to resize the drop-down
 list. The first way is to directly set the DropDownFixedWidth
 property to some integer value greater than zero. The second way
 involves leaving the DropDownFixedWidth property at 0, and the
 list will automatigically be sized to the longest string.
 =================================================================}
unit EnhCombo;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TEnhCombo = class(TComboBox)
  private
    FItemWidth : Integer;
    FDropDownFixedWidth: Integer;
    procedure SetDropDownFixedWidth(const Value: Integer);
    function GetTextWidth(S : String) : Integer;
  protected
    procedure DropDown; override;
  public
    constructor Create(AOwner : TComponent); override;
    property ItemWidth : Integer read FItemWidth write FItemWidth;
  published
    property DropDownFixedWidth : Integer read FDropDownFixedWidth
                                          write SetDropDownFixedWidth;
  end;

procedure Register;

implementation

constructor TEnhCombo.Create(AOwner : TComponent);
begin
  inherited Create(AOwner);
end;

procedure TEnhCombo.DropDown;
var
  I : Integer;
begin
  inherited DropDown;
  ItemWidth := 0;
  {Check to see if DropDownFixed Width > 0. Then just set the
   width of the list box. Otherwise, loop through the items
   and set the width of the list box to 8 pixels > than the
   widest string to buffer the right side. Anything less than
   8 for some reason touches the end of the item on high-res
   monitor settings.}
  if (FDropDownFixedWidth > 0) then
    Self.Perform(CB_SETDROPPEDWIDTH, FDropDownFixedWidth, 0)
  else
    begin
      for I := 0 to Items.Count - 1 do
        if (GetTextWidth(Items[I]) > ItemWidth) then
          ItemWidth := GetTextWidth(Items[I]) + 8;
      Self.Perform(CB_SETDROPPEDWIDTH, ItemWidth, 0);
    end;
end;

function TEnhCombo.GetTextWidth(S : String) : Integer;
begin
  Result := TForm(Owner).Canvas.TextWidth(S);
end;

procedure TEnhCombo.SetDropDownFixedWidth(const Value: Integer);
begin
  FDropDownFixedWidth := Value;
end;

procedure Register;
begin
  RegisterComponents('BD', [TEnhCombo]);
end;

end.
The comments pretty much explain all the logic behind the component, so I won't bore you with those details. But you should note that I implemented both sizing behaviors in the code through the DropDownFixedWidth property in order to provide greater flexibility when using the component. If the value of DropDownFixedWidth is greater than zero, then the component will size its list box to the size set for the property. If the value is zero, then it'll dynamically size to the largest string in the Items list. While I'd personally just let the component decide the size of the list box, there just might be times when you want to set the width explicitly. This component allows you to do that.

There's a weakness in the way this code is designed, though. Can you figure it out? Install the component, drop it into a new test application, and run it. Read no further until you've done that....

Flawed Design?

If you haven't figured it out, place the component near the right edge of the form. Run your program again, and drop down the list. It gets cut off. For time's sake, I haven't researched how to move the list box to accommodate form alignment of the combo box. If you figure it out, please let me know. I'll add your solution to this article and put your name in lights! Well, that's it for now!

 
Other 10-Minute Solutions
 Trapping Messages Sent to an Application
 Getting the Number of Records From a Fixed-Length ASCII File
 Performing Incremental Searches with a TListbox
 Resizing the Drop-down List of a TComboBo
 Disabling the System Keys from Your Application
 Making A Secondary Form Independent of the Main Form
 Creating a System Tray Application
 Opening and Closing a CD Tray
 Hiding an Application from Windows
 Make a List Box Track the Mouse
 Running a Program at Startup
 Creating A Skin Component
 Dynamically Load Components From Packages at Run Time
 Obtain All Values from Multivalue Input Fields in WebBroker Applications
 Migrate Your BDE Applications to Linux with dbExpress
 Create a Multiline Button Component
 Update and Maintain dbExpress's Unidirectional, Read-Only Datasets
 Use ActionBands to Enable End Users to Customize Your Delphi Applications
 Produce HTML Reporting Output with WebBroker Components
  Convert XML Documents into Different Formats with the XSL Template Language


Ask the Delphi Pro | Who is the Pro? | Usage Policies | Ask a Question | Search | Feedback


Sponsored Links


Advertising Info  |   Member Services  |   Contact Us  |   Help  |   Feedback  |   Site Map
Jupiterweb networks

internet.comearthweb.comDevx.comClickZ

Search Jupiterweb:

Jupitermedia Corporation has four divisions:
JupiterWeb, JupiterResearch, JupiterEvents, and JupiterImages

Copyright 2004 Jupitermedia Corporation All Rights Reserved.
Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

Jupitermedia Corporate Info | Newsletters | Tech Jobs | E-mail Offers