Archive for December 2006

Align values separated by TAB in dropdown

December 24, 2006

We have put a ID-value pair items to TComboBox (using AddItem() method) and want to show both the ID and a value to user (using Additem() Item parameter). We might put the name of the value and append the ID in parentheses like this:

combobox_tabbed_1.png

Not very nice, is it? Another option is to use tabulator (#9) to align the id-value pairs. Let’s try this out:

combobox_tabbed_2.png

UGHH! The tabulator is just ignored. Luckily we have a Win32 API function TabbedTextOut():

The TabbedTextOut function writes a character string at a specified location, expanding tabs to the values specified in an array of tab-stop positions. Text is written in the currently selected font.

Now, we must write our own TComboBox.OnDrawItem event handler:

procedure TForm1.ComboBox1DrawItem(
  Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
var
  cb: TComboBox;
  s: string;
  t: integer;
begin

  // check control type
  Assert(Control is TComboBox);

  // tab position (in pixels)
  t := 50;
  cb := TComboBox(Control);

  // take the font
  cb.Canvas.Font.Assign (cb.Font);

  // take colours
  if (odFocused in State) or
     (odSelected in State) then begin
    cb.Canvas.Brush.Color := clHighlight;
    cb.Canvas.Font.Color := clHighlightText;
  end else begin
    cb.Canvas.Brush.Color := cb.Color;
    if (odDisabled in State) then
      cb.Canvas.Font.Color := clGrayText
     else
      cb.Canvas.Font.Color := cb.Font.Color;
  end;

  // get the item we have to draw
  s := cb.Items[Index];

  // show only the first value as selected value
  if odComboBoxEdit in State then
    s := Copy(s, 1, Pos(#9, s) - 1);

  cb.Canvas.FillRect(Rect);

  // ah boy, win32 rules to some extent
  TabbedTextOut(cb.Canvas.Handle, Rect.Left,
    Rect.Top, pChar(s), Length(s), 1,
    t, Rect.Left);

end;

Let’s take a look at the result:

combobox_tabbed_3.png

Cool! πŸ˜‰

Mind You: TComboBox.Style must be either csOwnerDrawFixed or csOwnerDrawVariable, otherwise the OnDrawItem event is not fired.

Advertisements

Change the dropdown width of a combobox

December 16, 2006

Sometimes it may happen that a combobox on form cannot be stretched enough and we have items in the list that won’t fit in the dropdown list. Here’s an example of the situation:

combobox_droppedwidth_1.png

Delphi’s VCL does not provide us with an option to change the droppeddown list’s width. However we can send a message called CB_SETDROPPEDWIDTH to the TComboBox. From the Win32 API Reference:

An application sends the CB_SETDROPPEDWIDTH message to set the maximum allowable width, in pixels, of the list box of a combo box with the CBS_DROPDOWN or CBS_DROPDOWNLIST style.

One should do this once after creating the TComboBox and the best place for this is of course TForm’s OnCreate event handler:

procedure TForm1.FormCreate(Sender: TObject);
begin
  ComboBox1.Perform(CB_SETDROPPEDWIDTH, 150, 0);
end;

Where wParam of the message is list’s width in pixels. Now, let’s try it:

combobox_droppedwidth_2.png

Reading “DOS files”

December 12, 2006

Today I received a TXT file created from some DOS application and I have to read the data into InterBase database. Everything was fine until I discovered that umlaut characters (Γ€, ΓΆ, etc) end up with totally different symbols (β€ž,”, etc). Win32 API helped me this time as well – OemToChar() and OemToCharBuff() are the functions to look:

The OemToChar function translates a string from the OEM-defined character set into either an ANSI or a wide-character string.

And a simple code example as well:

if s <> '' then
  OemToChar(PChar(s), PChar(s));

Beware not to pass an empty string to the function! Try out to see what happens πŸ˜‰