Re: How Tabs In Memos Work
From: Henry B (hambar_at_Spamlock.microtech.com.au)
Date: Sun, 19 Oct 2003 12:07:08 +1100
Doug Horton <email@example.com> wrote
> > Assuming noc is the number of characters that have been output on
> > the current line so far, you have to add 9-((noc+1) mod 8) spaces
> > at that point, so your best option is to parse each line character
> > by character (counting them up) and do the replacement when you
> > encounter a tab.
> And if I'm not mistaken, you will have to forget about TrueType
> fonts and go with a fixed-width font.
Not necessarily. It's certainly possible to change tab-settings in
tMemo and to make them work satisfactorily with most True-type fonts.
I faced this problem a few years ago when using Delphi 1 and Peter
Below helped me out
These are my notes of what he wrote:
Date: Fri, 13 Aug 1999 15:56:39 +0200
From: "Peter Below (TeamB)" <100113.1101@compuXXserve.com>
> I am working in Delphi 1 and have a routine to send the contents of
> a tMemo to the printer. Everything is working well except when the
> memo lines contain tab characters.
> 1. How can I change the printer tab settings?
Depends on how you output to the printer. If you use AssignPrn/WriteLn
you have no control. If you use the Printer.Canvas you can use
TabbedTextout to handle tabs. Unfortunately DrawtextEx will not work
on all printers, it would be even more useful.
> 2. How can I find out the default tMemo tab settings?
> 3. Is it possible to change the tab settings in a tMemo? (*not* the
> WantTabs setting)
There is a big hole in the API here, you can *set* the tab settings
using an EM_SETTABSTOPS message but you cannot get the current
settings. The memo also sets tabstops in an arcane unit called dialog
units for historical reasons. I think the default is a tab each 32
dialog units, where a dialog unit is 1/4 of the average character
width of the system font (see GetDialogBaseUnits).
procedure TForm1.Button1Click(Sender: TObject);
tabs: Array [0..2] of Integer;
(* set first tabstop at 12, second at 24, third at 44 character
position, using the average width as base, converted to dialog
units. 4 dialog units make one average char width. *)
tabs := 12 * 4;
tabs := 24 * 4;
tabs := 44 * 4;
Memo1.Perform( EM_SETTABSTOPS, 3, LongInt(@tabs));
I used this info to help write a set of routines for handling tabs in
tMemo and which I can dig out if you are interested.
I managed to contrive a work-around for the missing GetTabStops
Peter includes a version of the above code in his snippets file
(UPLOADS.TXT, File version: 2002-12-19) and adds this:
Note that the message expects the position in an arcane unit called
"dialog unit", 4 of which should theoretically equal the average
character width of the memos font. But using div 4 does not give the
correct positioning, while using div 2 does. Don't ask me why, dialog
units are really only sensible in dialogs (which are based on a dialog
resource) and are relative to the font used for the dialog itself, not
the controls on it.
> GetDialogBaseUnits seems allways return the value based on the
> system font instead the font I used for TListBox (i.e. Arial). In my
> machine, it always return value 8. Any hints?
Try to use the way i calculated the average character width with the
listbox font and the same test string, that should yield 4 times the
dialog unit for the listbox if it does indeed use a different one than
GetDialogbaseunit returns. I got this method out of an old MSKB
article ages past if memory serves. Don't make the error of using
averagecharwidth div 4 as unit, that will introduce severe rounding
errors. Use numPixels * 4 div averagecharwidth (or the MulDiv
function) to convert pixels to dialog units.
-- Henry Bartlett HABit utilities ( http://www.hotkey.net.au/~hambar/habit/ ) email: hambar@Spamlock.microtech.com.au. Please remove the "Spamlock." from my address when replying.