Part 3: Polishing Your Kylix Application Windows

Brian Long (www.blong.com)

In this second instalment of our Kylix Open Edition tutorial series, Brian Long add some polish to our text processing application and gives some tips on how to improve your use of Kylix.


This article first appeared in Linux Format Issue 21, December 2001.

Click here to download the files associated with this article.

If you find this article useful then please consider making a donation. It will be appreciated however big or small it might be and will encourage Brian to continue researching and writing about interesting subjects in the future.


Introduction

Last month we built a simple text processing application that could load and save files, as well as create new files. This month, we will continue working with this project to see how it can be improved. So, without further ado, open up last month’s project (TextEditor.dpr in the attached files) and we will proceed.

If you have not worked on the project recently, open it with File | Open Project..., or Ctrl+F11. If you have opened the project recently, you will find it in the history list (File | Reopen), but note that there are two sections to the list. The files at the top are project files (typically opened with File | Open Project...) and those at the bottom are units (typically opened with File | Open...) - in this case, we need to open a project, so choose the right file.

Exceptions – Don’t Panic!

Before doing anything with the project, we perhaps should broach the idea of exceptions. CLX uses a rich error-handling model based around exceptions, which are programmatic representations of errors. Whenever any type of error occurs, an exception is raised. By default, the application automatically displays the exception in the form of a message dialog and, when the dialog is dismissed, the application carries on as normal. You can write custom error handling for any exceptions you choose, but even without this, the application handles errors gracefully.

We’ll leave coverage of custom exception handling until another time, but for now, let’s see how the Kylix IDE deals with application exceptions. Run the text editor application by pressing F9 (or choosing Run | Run). Choose File | Open... in the program and enter the name of a non-existent file (such as xyz), then press OK.

What happens next is the IDE pops up to the foreground with a message saying your program raised an EFOpenError exception, which has an associated message. It also says your process has been stopped and that you can either step it in the debugger, or allow it to continue running (see Figure 1).

Figure 1: The IDE reporting an application exception

The situation is thus: when you ran your application, the Kylix debugger started actively tracking it. When the debugger detected an exception being raised in your program, it immediately suspended it, just as if there were a breakpoint there.

If you were developing a real application with lots of code and you needed to debug an unexpected exception, this might be useful as the debugger will position you on the offending line of code in the editor. However, to newcomers to Kylix, this feature can be a bit confusing.

What you should do now is close the message box and press F9 again to let the program continue execution, which it will do by reporting the error itself - this is normal behaviour. You can continue using the program as normal now and then close it when you are done.

If you are happy with the debugger popping up every time there is an exception in your program, then fine. However, if you would prefer the debugger to remain silent on these occasions then we can tell it so. Choose Tools | Debugger Options... and on the Language Exceptions page of the dialog, uncheck the Stop on Delphi Exceptions checkbox (see Figure 2). We’ll ignore the product name faux pas there.

Figure 2: Telling the debugger to ignore application exceptions

The Plan

The improvements we will make to the text editor application this month include adding a word wrap option (handy in text editor’s) and enhancing the UI with menu images, a toolbar supporting hot images, tooltips and a status bar displaying hint information.

Let’s start with the word wrap option. Double-click on the menu component, mnuMainMenu, to get back the Menu Designer. Here we will insert an Options menu by selecting the Help menu in the Designer and pressing the Insert key (or right-clicking and selecting Insert). Give it a suitable caption and name, then click back on the Menu Designer and select the empty menu item below it. Give this item a name of mniWordWrap, a caption of &Word Wrap and a shortcut of Ctrl+W.

Now create an OnClick event handler for the item that will toggle the checkmark that can be associated with a menu item and set the memo’s WordWrap property accordingly.

procedure TfrmTextEditor.mniWordWrapClick(Sender: TObject);
begin
  mniWordWrap.Checked := not mniWordWrap.Checked;
  memText.WordWrap := mniWordWrap.Checked
end;

To finish the job, we should realise that word wrap is on by default, so you should set either the menu item’s Checked property to True (see Figure 3) or the memo’s WordWrap property to False, to match. You can also set the memo’s ScrollBars property to ssAutoBoth to ensure that if enough text is entered width-wise or height-wise, scrollbars will appear to help the user.

Figure 3: Adding a new menu

Menu Images

To get a visually enhanced menu with little images embedded to the left of each item, we need an image list component (from the Common Controls page of the component palette). Call it imlHotImages (we will see the significance of the term “hot” later) and connect the menu component’s Images property to it. This now allows the menu items to index into the image list and make use of the images therein. So, we now need to add some images.

When Kylix is installed, it includes a number of sample images for buttons, menus or whatever, installed in Kylix’s images directory. They actually look rather dated, as they are the same images that were supplied with Delphi 1 back in 1995, but since all Kylix installations have them, they will do for now

.

Double-click the image list and it will invoke the associated editor that allows you to add new images (you can see it in Figure 6 and Figure 7). Press the Add... button and navigate to your Kylix installation directory, then into the images/buttons subdirectory. You can now choose a bitmap file to add to the image list. We recommend you add one image at a time to the image list, otherwise the image order will go wrong and we may get inappropriate images.

The first image is filenew.bmp (see Figure 4). When you look at it there are a couple of things to notice. Firstly, it has an unpleasant olive background (which becomes transparent when used in your program), and secondly the bitmap is actually made of two square images. The left image is a coloured version and the right image is a colourless version.

Figure 4: One of Kylix’s sample images (looking a bit of a mess)

All the images in this directory will share these attributes and you will find that when you add an image to the image list, it will ask you if you want to split the bitmap into two images (see Figure 5). You should accept all such offers. The full list of bitmaps for the menu items that will be decorated includes: filenew.bmp, fileopen.bmp, filesave.bmp, dooropen.bmp, cut.bmp, copy.bmp, paste.bmp, npadwrit.bmp (this one is not very appropriate but was the best I could find in the supplied bitmaps).

Figure 5: The image list editor asking a sensible question

When all are added, you end up with an image list with coloured and colourless versions of eight bitmaps (see Figure 6). Now we need to duplicate the image list component so, having selected the image list on the form designer, choose Edit | Copy and Edit | Paste, then name the new image list imlImages.

Figure 6: All the images have been added, both enabled and disabled

In the image list editor for imlHotImages, select each disabled image and delete it, then delete all the enabled images in imlImages. This leaves an image list of coloured, or “hot”, images and one of colourless images.

Figure 7: The hot image list

Now we can set up the images used by each menu item. Double-click the mnuMainMenu component and, in the Menu Designer, select each menu item that should be given an image and set its ImageIndex property to the corresponding image index (which can be browsed in the image list editor, as shown in Figure 7). Now the application menu looks much more professional (see Figure 8), although we have not yet made use of the colourless images.

Figure 8: The menu looking more colourful

Status Bar Hints

You can find a status bar component on the Common Controls page of the Component Palette. Drop one of these on your form (calling it sbInfo) and it will stick to the bottom of the form because its Align property defaults to alBottom. The Kylix editor uses a status bar component to display several pieces of information such as the cursor location, whether the file is modified and whether you are in insert or overwrite mode. Each piece of information is displayed in a separate status panel on the status bar.

To add status panels to your status bar, you use the status panel collection editor, which can be invoked by double-clicking the status bar or invoking the property editor for the Panels property. Press the collection editor’s yellow button (or the Insert key) twice and you will have two status panels, each represented as an object.

When either status panel is selected in the collection editor, the Object Inspector shows its property values (see Figure 9). The instance list at the top of the Object Inspector also informs you of the syntax required to refer to this particular status panel object. Figure 9 shows the first status panel selected, which can be referred to as sbInfo.Panels[0]. Change the width of this status panel to 200 pixels (it defaults to 50).

Figure 9: Properties of an area on a status bar

This first panel will be used to display hint information about items under the mouse cursor (such as menu items and, later, toolbuttons). This happens automatically if you set the status bar’s AutoHint property to True. To test this out, go back to as many menu items as you like in the Menu Designer (or simply select them with the Object Inspector’s instance list) and enter a descriptive string for the Hint property.

Next, we should use the second panel for something, perhaps to display the date and time. Since this will need to be updated at least every second a timer component from the Component Palette’s Additional page should be used. Give it a name of timClock and an Interval of 250 (this is measured in milliseconds, so represents 1/4 second). Every quarter of a second the OnTimer event will execute, so make an event handler for OnTimer (you can double-click on the timer component on the Form Designer to achieve this) and enter this code.

procedure TfrmTextEditor.timClockTimer(Sender: TObject);
begin
  sbInfo.Panels[1].Text := FormatDateTime(
    'h:nn:ss am/pm "on" ddd, d mmm, yyy', Now)
end;

This calls the BaseCLX routine Now, which returns the date and time as a TDateTime value, and passes it to FormatDateTime to generate a custom string representation of it based on simple substitution of known character sequences (you can find more information on both of these routines in the Kylix help). Notice that the word on is an arbitrary word we want in the result, so it is enclosed in double quote characters to prevent substitution of any of its characters, such as “n”.

Now run the program and see the results. Figure 10 shows the status bar displaying the hint for the selected File | Exit menu item, as well as the date and time.

Figure 10: Automatic hint display on a status bar

Adding A Toolbar

The next improvement will be to add a toolbar component, which can be found on the Palette’s Common Controls page. This will automatically migrate to the top of the form thanks to its Align property defaulting to alTop. Change the name to tbMainToolBar, set Flat to True (this gives the effect of a completely flat toolbar, like those in Kylix, whose buttons become 3D as the mouse moves over them), ShowCaptions to True (the toolbuttons on the toolbar can show a caption as well as a picture) and AutoSize to True.

A right-click on the toolbar reveals two new menu items: New Button and New Separator. Add as many buttons as you wish (each one will be a shortcut for a menu item), separating items from different menus with separators. For each toolbutton, the behaviour it needs to invoke has already been implemented last month in menu item OnClick event handlers.

A nice feature of Kylix is that we can typically share event handlers between different events of different components, unless the expected event handlers have incompatible parameter lists. So rather than making a new event handler for each toolbutton, we can connect its OnClick event to an existing event handler by choosing a suitable one from the list (see Figure 11).

Figure 11: An excellent opportunity for code reuse

A nice feature of Kylix is that we can typically share event handlers between different events of different components, unless the expected event handlers have incompatible parameter lists. So rather than making a new event handler for each toolbutton, we can connect its OnClick event to an existing event handler by choosing a suitable one from the list (see Figure 11).

The sample project TextEditor2.dpr has toolbuttons with the following properties (we’ve ignored the separators in this list):

Name=tbnNew,	 Caption=New,	 OnClick=mniNewClick
Name=tbnOpen,	 Caption=Open,	 OnClick=mniOpenClick
Name=tbnSave,	 Caption=Save,	 OnClick=mniSaveClick
Name=tbnCut,	 Caption=Cut,	 OnClick=mniCutClick
Name=tbnCopy,	 Caption=Copy,	 OnClick=mniCopyClick
Name=tbnPaste,	 Caption=Paste,	 OnClick=mniPasteClick
Name=tbnWordWrap,	 Caption=Wrap,	 OnClick=mniWordWrapClick

Some final touches are necessary to finish the job off. For example, the Word Wrap toolbutton needs to either be up or down to reflect the state of the memo’s WordWrap property. To allow it to be toggled up and down set its Grouped property to True, and then set Down to True (assuming you left the memo’s WordWrap set to True earlier).

Now we can ask the toolbuttons on the toolbar to use the images in the image lists we set up earlier. Connect the toolbar’s Images property to imlImages and its HotImages property to imlHotImages. Many toolbars will only use an Images property, to provide the images required by the toolbuttons.

The HotImages property provides an extra feature whereby as the mouse moves over a toolbutton, its image is replaced by the corresponding hot image, to accentuate the fact that it is available and under the mouse. Hot images are supposed to help the user follow what is going on. We already set the Flat property earlier, meaning the flat toolbutton becomes 3D as the mouse moves over it, but with the HotImages property set as we have, the toolbutton also changes from having a colourless image to a colourful image.

Adding Tooltips

The last item on the agenda for this month is to get some tooltips showing for the toolbuttons. We already have control hints being displayed automatically in the status bar, but we can also have real tooltips (popup hint windows) if we choose.

Every control that can display a tooltip has a ShowHint property, which defaults to False. If you set the form’s ShowHint property to True, it will propagate down through all the child controls on the form (thanks to the common ParentShowHint property defaulting to True). This is the first step.

The next thing to do is to give each toolbutton a descriptive tooltip string to display (this is again controlled by the Hint property). However, if you think about it (or indeed test it), this will cause the hint string to be displayed twice for every toolbutton, once in the status bar and once in a tooltip.

To improve upon this situation, the Hint property of any control can optionally contain two strings, separated by a pipe sign. For example, the Open toolbutton in the supplied version of this project has a Hint property of:

Open file|Open an existing document

The status bar displays the second (typically lengthier) string, whilst the tooltip displays the first string. You can see the final version of the program running in Figure 12, showing a tooltip, a status bar hint and also the Open toolbutton’s hot image.

Figure 12: Toolbars, menu images, tooltips, status bars and hints... what more do you want?

Appendix A: Kylix Tips

Figure 13: A quick way of getting the recent file list

Appendix B: Recommended Settings

There are a number of options in the Kylix IDE that, in our opinion, can provide a slightly better development experience. Here are some of them:

Figure 14: The environment options dialog with some useful settings

Summary

We have seen the UI of our text editor application coming on in leaps and bounds, due to the rich components and properties available in the CLX library. However, there are still areas that warrant improving.

For example, if we want to have the toolbar and menu system context-sensitive, where buttons/items are only enabled when they are relevant, things can be a bit tricky. Every time something happens in the program, we will need to disable or enable both the menu item and the toolbutton (and any other controls that can invoke the same behaviour).

Next time we will look at actions, which are CLX objects that are specifically designed to improve exactly this situation.

Before finishing, I should mention that everything we have done so far with Kylix Open Edition and practically everything you can do with it can also be done with Delphi, Borland's commercial application development systems for Microsoft Windows. Delphi 6 Enterprise Edition is a product comparable to Kylix 1 Server Developer and Kylix 2 Enterprise Edition, Delphi 6 Professional Edition is comparable to Kylix 1 Desktop Developer and Kylix 2 Professional Edition, and Delphi 6 Personal Edition is similar to Kylix 1 and 2 Open Edition, but does not permit the generation of GPL applications and does not permit then distribution of applications.

You can take our Kylix projects, load them directly into Delphi and run them as Windows applications due to the source-level cross-platform nature of the CLX component library.

About Brian Long

Brian Long used to work at Borland UK, performing a number of duties including Technical Support on all the programming tools. Since leaving in 1995, Brian has spent the intervening years as a trainer, trouble-shooter and mentor focusing on the use of the C#, Delphi and C++ languages, and of the Win32 and .NET platforms. In his spare time Brian actively researches and employs strategies for the convenient identification, isolation and removal of malware.

If you need training in these areas or need solutions to problems you have with them, please get in touch or visit Brian's Web site.

Brian authored a Borland Pascal problem-solving book in 1994 and occasionally acts as a Technical Editor for Wiley (previously Sybex); he was the Technical Editor for Mastering Delphi 7 and Mastering Delphi 2005 and also contributed a chapter to Delphi for .NET Developer Guide. Brian is a regular columnist in The Delphi Magazine and has had numerous articles published in Developer's Review, Computing, Delphi Developer's Journal and EXE Magazine. He was nominated for the Spirit of Delphi 2000 award.


Back to top