1. Computing

Understanding Owner Drawing in Delphi

Creating a graphical (popup) menu

By

Owner Draw Delphi PopUp

I guess we all like the idea of graphics displayed in the "Start" menu of Windows XX. Have you ever wondered is it possible to do custom control drawing with Delphi?

Owner Drawing in Delphi

Often it would be nice to modify the behavior or appearance of Delphi's many controls (visual components). When we want to draw a decorative piece of art on a screen (component), Delphi allows us to "create" Owner Drawn controls which let us customize intrinsic controls to look however we want.

In Windows, the system is usually responsible for painting menu items, list boxes, edit boxes, buttons and similar elements of your application GUI.

For some controls the system allows an application to create an owner-drawn control, let's say a PopUp Menu, to take responsibility for painting menu items.

When we set a control's OwnerDraw property to True, Windows no longer draws the control on the screen. This feature permits an application to alter the appearance of a control. Windows generates events for each visible item in the control, and your application handles the events to draw the items. The parent window (a form) of an owner-drawn control receives WM_DRAWITEM messages when a portion of the control needs to be painted. When the message is received it is up to the parent to draw the control however it wants.

Drawing a PopUp Menu

Delphi makes the development of graphical menus (items) quite simple by providing a way to use an ImageList component to add glyphs to menu items. However, if we want even more control of the graphical representation of menu items we'll have to deal with owner drawing techniques.

Let's see how to create an Owner-Drawn PopuUp Menu, that behaves like normal menu but has customized appearance by modifying how it is drawn on screen.

Typically, when creating an owner-drawn menu we start with creating a standard Menu by placing it on a form and setting Menu Items with "Menu Designer". In order to have some images in menu items I have placed an ImageList component and filled it with glyphs. A Memo component is used to show (edit) some text, the first three PopUp menu items can change the Font.Style property by setting Bold/Italic/Underlined; the next 3 items are used to start up the default Web Browser and navigate to some pages on the Delphi Programming site.

To turn a menu into a fully customized graphical element we have to set the OwnerDraw property of a menu component to True and handle each menu items OnMeasureItem and OnDrawItem event.

Coding/Drawing Menu Items

In the OnMeasureItem event we set the size of owner-draw menu items.

The OnDrawItem event contains parameters indicating the index of the item to draw, the rectangle in which to draw, and usually some information about the state of the item (such as whether the item has focus - is selected).

This event is fired when Windows first displays the items and each time the status changes (mouse moves over an item).

Take a look at the following OnDrawItem procedure for the "Bold" menu item (the other five handlers for menu items use similar code):

 procedure TForm1.mnuBoldDrawItem (Sender: TObject; ACanvas: TCanvas; ARect: TRect; Selected: Boolean) ;
 var
  ImgID: integer;
 begin
 
  if Selected then
    ACanvas.Brush.Color := clHighlight
  else
    ACanvas.Brush.Color := clMenu;
 
  {move the rect to make place for the side bar}
  ARect.Left := 20;
 
  ACanvas.FillRect(ARect) ;
 
  if mnuBold.Checked then
    ImgID := 1 {thumb up in the ImageList}
  else
    ImgID := 0; {thumb down in the ImageList}
 
  ImageList1.Draw(ACanvas,22,ARect.Top + 2,ImgID) ;
 
  ACanvas.Font.Style := [fsBold];
 
  {user defined text drawing function:}
  DrawItemText(45,ACanvas,ARect,'Bold') ;
 end; 
The ACanvas parameter provides a drawing surface on which to draw the menu item. The Selected parameter indicates whether the menu item is selected and therefore the menu item's background is filled with the appropriate color (clSelected if selected, clMenu otherwise).

If the Checked property of menu item is True (indicating the Bold font for the Memo component) the "Thumb-Up" picture is displayed by painting it with the Draw method of the ImageList component. Finally, the word "Bold" is drawn onto the Canvas with the DrawItemText procedure.

Coding/Drawing Side Bar

Have you noticed that "delphi.about.com" vertical text on the left side of the popup menu? When all the menu items are drawn we can draw the side bar. The trick is simple: just draw the text rotated 90 degrees.

For the full source download the OwnerDraw project.

Source Code

©2014 About.com. All rights reserved.