0
votes

In the main window of Delphi VCL application I'd like to have the caption this way:

text1 text2 text3

occupying all space available for the caption. Text1 is aligned to left of caption, text2 in the middle and text3 to the right. If I knew the current caption max length, could calculate spaces between text1 and text2 and spaces between text2 and text3 to get them aligned as wanted. The problem is that with different form sizes, the caption changes size. How can I know current max length of (TForm).caption ? Thanks

Edit
I tried to set caption to a way long 300 characters string and wait for the show event to present the caption with '...' at the end (meaning overflow). But when tried to search '...' in the caption, didn´t find it. If it had found '...' then could know caption's length. How can I find '...' ?

1
Yeah my bad that was shortstringIlyes
@Hector: This sound like a very bad idea. Window title bars aren't supposed to be used like this in Windows. Fighting against the system is prone to fail.Andreas Rejbrand
I think there is a character limit that kicks in before you even reach the space limit. What you are attempting is probably a bad ideaDavid Heffernan
You will likely have to handle the 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 the Caption blank, then handle WM_NCPAINT by first calling the default handler, and then draw your text on top of whatever the OS drawsRemy Lebeau
@Andreas: Windows title bars were not made to contain main menus either, and yet the Firefox I am typing this in has that. But as Remy says, it would have to be a non-client paint. I agree that it may not be a good idea, but that is his decision.Rudy Velthuis

1 Answers

1
votes

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.