You can calculate the current maximum length of the caption.
The current ClientWidth of the Form is available at runtime, and using the Form Designer gives an estimate of the space occupied by the icons. The pixel width of an AnsiString is returned by the Canvas->TextWidth function.
AnsiString Words = First + Middle + Last;
// store width of text in pixels
WordsWidthInPixels = Canvas->TextWidth(Words);
The number of spaces can be found with the help of the TextWidth of a space or two.
Update:
Here is some code using system metrics instead of estimating from the designer. I've put almost all the code in a function called GetNumSpacesMetric.
The function header is added to the Form class in the header file :-
class TForm1 : public TForm
{
__published: // IDE-managed Components
void __fastcall FormResize(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
int __fastcall GetNumSpacesMetric(TObject *Sender, TComponent* AForm);
};
On the Form create the Event OnResize, and add the code which updates the Caption when the Form is resized. If the name of the form is not Form1 then it will need to be changed in the code here :-
void __fastcall TForm1::FormResize(TObject *Sender)
{
// strings
const AnsiString First = AnsiString("First");
const AnsiString Middle = AnsiString("Middle");
const AnsiString Last = AnsiString("Last");
// get number of spaces
int NumSpacesMetric = GetNumSpacesMetric(Sender, Form1);
// print the caption
if( NumSpacesMetric > 0 ) {
AnsiString Spaces = AnsiString::StringOfChar(' ', NumSpacesMetric);
AnsiString caption = First + Spaces + Middle + Spaces + Last;
Form1->Caption = caption;
}
}
Next add the GetNumSpacesMetric function definition. at the function head and where the Image is created.
// calculate the number of spaces needed between three words in Form Caption
int __fastcall TForm1::GetNumSpacesMetric(TObject *Sender, TComponent* AForm)
{
const int NumberOfMenuIcons = 3;
const AnsiString Words = "FirstMiddleLast";
const AnsiString TwinSpace = AnsiString::StringOfChar(' ', 2);
const int Squeeze = 7 * 8; // tweak 1 - squeeze string length
//const int FineTune = 840; // tweak 2 - lengthen string when width smaller
//const int LimitLength = 980; // tweak 3
static int WordsPixelWidth;
static int TwinSpacePixelWidth = 1;
// get metric data
static NONCLIENTMETRICS ncm;
static bool done = false;
// do once
if(!done)
{
ncm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo( SPI_GETNONCLIENTMETRICS,
sizeof(NONCLIENTMETRICS), &ncm, NULL);
TImage *tmpImage = new TImage(AForm);
// Font data
tmpImage->Canvas->Font->Handle = CreateFontIndirect(&ncm.lfCaptionFont);
// get pixel widths of Words and double space
WordsPixelWidth = tmpImage->Canvas->TextWidth(Words);
TwinSpacePixelWidth = tmpImage->Canvas->TextWidth(TwinSpace);
DeleteObject(tmpImage->Canvas->Font->Handle);
done = true;
}
int clientwidth = ClientWidth;
/*
// limit length of text if required
if( clientwidth > LimitLength)
clientwidth = LimitLength;
*/
// client width minus icon widths and words width
int NumOfPixelsLeft = clientwidth
- ncm.iCaptionWidth
- (ncm.iMenuWidth * NumberOfMenuIcons)
- WordsPixelWidth
- Squeeze
// + ((8 * (FineTune - clientwidth))/100)
;
// return number of pixels available divided by size of two spaces
return NumOfPixelsLeft / TwinSpacePixelWidth;
}
//---------------------------------------------------------------------------
There are tweaks which can be used to change the program and are given a short description in the code.
Update 2:
Added a parameter to GetNumSpacesMetric, to pass the Form object.
There is a newer set of instructions which can get some of the metrics:-
The TITLEBARINFO structure, TITLEBARINFOEX structure, GetTitleBarInfo function and GetTitleBarInfoEx function.
WM_NCPAINT
message to draw the titlebar yourself. Then you can just draw the three strings separately with calculated coordinates. But then you have to draw the ENTIRE titlebar, and that gets very tricky with each new Windows version. Probably easiest to just leave theCaption
blank, then handleWM_NCPAINT
by first calling the default handler, and then draw your text on top of whatever the OS draws – Remy Lebeau