PDA

Ver la Versión Completa : Combobox CB_SETDROPPEDWIDTH y csOwnerDrawFixed


Carlos Arevalo
18-08-2004, 19:11:59
Que tal amigos del foro un saludo para todos.

Tengo dos preguntas

Como controlar el ancho de la lista en un combobox para que sea proporcional con el tamaño de la data que se introdujo en la misma?

Estoy utilizando este codigo pero no logro establecer una relacion con las medidas del ancho:

ancho:=LENGTH(FieldByName(campolista).AsString);
sendmessage(Tcombobox(Sender).Handle,CB_SETDROPPEDWIDTH,(ancho+4),0);

y la siguiente pregunta es como podria establecer la propiedad csOwnerDrawFixed para obtener la apariencia visual de dos columnas en el combobox pero que no quede bloqueada el area para editar.

Muchas gracias por su colaboracion

Carlos Arevalo

Carlos Arevalo
21-08-2004, 21:23:00
Esta es la solucion para el ancho de la lista la encontre en http://home.about.com/

Resizing the Drop-down List of a TComboBox

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

There are two ways to approach this. One's quick and dirty, the other's a bit more involved, but is much more reusable (read: 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 combobox, 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 that.

I could give you the code that does that - in fact, you could probably figure that part out yourself. But think about this a moment. This would be pretty useful in all your applications that use combo boxes, and to have to cut and paste code would be a real chore everytime you wanted to implement this behavior. 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. 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. I did this to provide greater flexibility when using the component. While I'd personally just let the component decide the size of the list box, there just might be times when I'd want to set the width explicitly. With this component, I can do that.

There's a weakness in the design of this code, 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 even researched how to move the list box to accomodate 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!

Copyright © 1998 Brendan V. Delumpa All Rights Reserved