Popup menu with MDI

Posted January 11, 2007 by toom
Categories: delphi, popup

Situation: we have a MDI application whose main form (FormStyle = fsMDIForm) has a TPopupMenu (MainForm.PopupMenu = PopupMenu1) for some shortcut functions when user clicks mouse on the main form.

Problem: this PopupMenu1 is popping up everywhere in all the MDI children windows, but we want to use for example the Windows default popup menu in edit boxes:

editbox_popupmenu.png

Solution: Remove the PopupMenu1 from main form’s properties and create an OnContextPopup event handler:

procedure TMainForm.FormContextPopup(Sender: TObject;
  MousePos: TPoint; var Handled: Boolean);
var
  ScreenPoint: TPoint;
begin
  // convert client area coordinates
  // to global screen coordinates
  ScreenPoint := ClientToScreen(MousePos);
  // see if the control under cursor in our main form
  if (FindDragTarget(ScreenPoint, True) is TMainForm)
  then begin
    // show our shortcut menu
    PopupMenu1.Popup(ScreenPoint.X, ScreenPoint.Y);
    // we handled the request for context menu
    Handled := True;
  end;
end;
Advertisements

Testing Estonian National identification number (isikukood)

Posted January 7, 2007 by toom
Categories: delphi

As a followup to the SOTU checking function, here’s a function that checks the validity of Estonian National identification number.

 Read the rest of this post »

Testing Finnish National identification number (SOTU)

Posted January 5, 2007 by toom
Categories: delphi, string

Here’s a sample function to test the validity of Finnish National identification number (henkilötunnus (HETU)), formerly known as sosiaaliturvatunnus (SOTU)).

 Read the rest of this post »

Align values separated by TAB in dropdown

Posted December 24, 2006 by toom
Categories: combobox, delphi

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.

Change the dropdown width of a combobox

Posted December 16, 2006 by toom
Categories: combobox, delphi

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”

Posted December 12, 2006 by toom
Categories: delphi, string

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 😉

Passing NULL as InterBase stored procedure parameter

Posted November 22, 2006 by toom
Categories: delphi, interbase

I had to pass a NULL value to an InterBase stored procedure. OK, first I tried:

IBStoredProc1.ParamByName('param1').Clear();

That ended up with ‘Required parameter not set’ SQL error. One has to ‘bind’ the parameter manually:

IBStoredProc1.ParamByName('param1').Clear();
IBStoredProc1.ParamByName('param1').Bound := True;

Another solution I came up while trying to figure out the “Bound := True” fix, is simply to use:

IBStoredProc1.ParamByName('param1').Value := null;

Believe it or not, this one works as well 🙂