Saturday, December 12, 2009

Displaying tabs on the right of a TTabControl

I started a new MBA course in 'Organisational Behaviour' yesterday; I should be more excited than I am about it at the moment. I hope that I will become more enthusiastic about it as time passes.

At the moment I'm more excited about a program which I am writing for my occupational psychologist. This program is supposed to be one which manages all non-primary information about the examinees: who everybody is, where they come from, which tests they did, who interviewed them, etc. One of the outputs of the program will be a calculation for each psychologist how many clients they interviewed during the month, and what their fee should be. The program is very much open ended at the moment, so I've configned myself to doing basic design, including a few input screens.

The program's main data structure/table is the docket, to which are connected people, to which are connected treatments (exams), to which are connected pyschologists. I made a nice ERD before I started coding, and so far I've completed everything in that design. But there'll be a lot more to come.

I went through several options before I came upon what is at the moment the final design for the main screen. Instead of displaying a dbgrid with docket numbers and dates, and possibly the names of the people connected to those dockets (utilising a left join, because there can be a docket with no people connected), I decided to take a different approach, utilising a component which I have never used before, the dbNavigator. This component allows one to page back and forth between different dockets, and I've connected a few dbText controls to display the data in the current docket tuple (a docket is never entered manually, as it only has two fields: number and date, both of which are inserted automatically).

For each docket there is a wealth of information to be displayed, although at the moment I only have two screens' worth: the people connected to the docket and the exams that those people did. After considering various options, I decided to use (for the first time) the TTabControl. There is a similar TPageControl, which allows different pages containing different controls; I tried this briefly, but didn't like it. As the the container control will hold a grid and a few buttons, it makes more sense to use the TTabControl (which uses the same child controls for all the 'pages', forcing the programmer to switch the data) as opposed to the TPageControl.

Here is a screen shot of the TTabControl in its naked form:



The TTabControl has two tabs, 'One' and 'Two', along with a grid. This would be ok if the program were working outside of Israel, but we need right to left controls. Although the TTabControl does have a BiDiMode (bidirectional) property, this controls how text appears and not the layout of the tabs. Obviously the solution is draw the tabs on the right hand side of the top of the TTabControl. Easier said than done.

I found a magic invocation which I have used before to get controls to draw themselves from right to left. Here is the result of using a little magic

Whilst the tabs are now drawn as I wanted, on the right, the grid seems to have disappeared. Thus the 'magic option' has very limited uses in the real world (such as none).

There is a property called TabAlign, which can display the tabs on the top (as I originally did), at the bottom, on the left or on the right. Is this the answer? Not really.




But we're nearly there.... All I need to do is to have the tabs draw their text horizontally, and then at least I will have a reasonable solution to what I want. The way to do this is to mark the TTabControl as owner drawn and to handle the tab drawing code by myself.



The sharp of sight will notice two things: the grid is now displayed right to left (by setting its BiDiMode property), and more importantly, the text of the tabs is wider than the tab. So the tab width has to be set manually? Not quite. If one remembers that the tabs have effectively been rotated by 90 degrees, then increasing their width effectively increases their height (at least, as how we see it). So to get the effect that I want, I have to increase their height, which will increase the onscreen width (who said that programming was easy?).

If I'm already owner drawing the tabs, why not add colour to the selected tab? Here is a screen shot of the final dialog, complete with a little data.



In case it isn't clear, there are two tabs on the right of the TTabControl: the selected tab has red text on a light blue background, whereas the tab below it has blue text on the common green background.

I have to say that I much prefer to concentrate on a program's logic, to get it to do what it's supposed to do with the minimum of effort from the user, instead of focusing on what seems to be arcane minutiae of the user interface. But sometimes there's no escaping this, especially if one works in a right to left environment. Looking back, I'm quite pleased with what I accomplished, even if it isn't exactly what I originally wanted. I hope that the client will also be pleased.....


No comments: