locked
two titles on the title bar RRS feed

  • Question

  • I want to have my form title on the left side of the title bar as usual... but I also want to have a form ID like FRM123 on the right side on the form just beside the minimize button or right most if no buttons..

    how can I do that?


    Jassim Rahma
    Wednesday, January 20, 2010 1:44 PM

Answers

  • Hi Jassim.
    here is some code we used... it may need some refinements but it should give you a good start.

    // some declarations first (to be used later):
    /// <summary>
        /// The <b>RECT</b> structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            /// <summary>
            /// Specifies the x-coordinate of the upper-left corner of the rectangle.
            /// </summary>
            public int left;
    
            /// <summary>
            /// Specifies the y-coordinate of the upper-left corner of the rectangle.
            /// </summary>
            public int top;
    
            /// <summary>
            /// Specifies the x-coordinate of the lower-right corner of the rectangle.
            /// </summary>
            public int right;
    
            /// <summary>
            /// Specifies the y-coordinate of the lower-right corner of the rectangle.
            /// </summary>
            public int bottom;
        }
    
        /// <summary>
        /// The <b>TITLEBARINFO</b> structure contains title bar information.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct TITLEBARINFO
        {
            private const int CCHILDREN_TITLEBAR = 5;
    
            /// <summary>
            /// Specifies the size, in bytes, of the structure. The caller must set this to sizeof(TITLEBARINFO).
            /// </summary>
            public uint cbSize;
    
            /// <summary>
            /// Pointer to a <b>RECT</b> structure that receives the coordinates of the title bar. These coordinates include all title-bar elements except the window menu.
            /// </summary>
            public RECT rcTitleBar;
    
            /// <summary>
            /// Pointer to an array that receives a DWORD value for each element of the title bar.
            /// </summary>
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN_TITLEBAR + 1)]
            public uint[] rgstate;
        }
    
        /// <summary>
        /// Specifies that state of the title bar buttons.
        /// </summary>
        [Flags]
        public enum TBBStates
        {
            /// <summary>
            /// Specifies that the element is unavailable.
            /// </summary>
            STATE_SYSTEM_UNAVAILABLE = 0x1,
    
            /// <summary>
            /// Specifies that the element is in the pressed state.
            /// </summary>
            STATE_SYSTEM_PRESSED = 0x8,
    
            /// <summary>
            /// Specifies that the element is invisible.
            /// </summary>
            STATE_SYSTEM_INVISIBLE = 0x8000,
    
            /// <summary>
            /// Specifies that the element has no visible representation.
            /// </summary>
            STATE_SYSTEM_OFFSCREEN = 0x10000,
    
            /// <summary>
            /// Specifies that the element can accept the focus.
            /// </summary>
            STATE_SYSTEM_FOCUSABLE = 0x100000
        }
    then, (inside the class code) some P/Invoke statements:
    [DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);
    
    [DllImport("user32.dll")]
    public static extern int GetSystemMetrics(int nIndex);
    
    [DllImport("user32.dll")]
    public static extern bool GetTitleBarInfo(IntPtr hwnd, ref TITLEBARINFO pti);
    
    and a couple of constants:
    public const int SM_CXSIZE = 30;
    
    public const int WM_NCPAINT = 0x0085;
    Now, add the following method:
            private void DrawStringOnTheRight(IntPtr hWnd, string caption)
            {
                // Get the HDC of the window's title bar.
                IntPtr hDC = GetWindowDC(hWnd);
                Graphics g = Graphics.FromHdc(hDC);
    
                // get the total buttons width.
                // first get a single buttons' width
                int buttonWidth = GetSystemMetrics(SM_CXSIZE);
                int captionHeight = 10;
                // now get the number of buttons
                TITLEBARINFO titleBarInfo = new TITLEBARINFO();
                titleBarInfo.cbSize = (uint)Marshal.SizeOf(titleBarInfo);
                GetTitleBarInfo(hWnd, ref titleBarInfo);
                int numButtons = 0;
                for (int i = 2; i < titleBarInfo.rgstate.Length; ++i)
                {
                    if (((int)titleBarInfo.rgstate[i] & (int)TBBStates.STATE_SYSTEM_INVISIBLE) == 0)
                    {
                        numButtons++;
                    }
                }
    
                // measure the size of the string
                SolidBrush brush = new SolidBrush(SystemColors.ActiveCaptionText);
                Font font = new Font(this.Font.FontFamily, captionHeight);           
                SizeF captionSize = g.MeasureString(caption, font, (int)g.VisibleClipBounds.Width);
    
                // get the rectangle in which you would draw the string
                int x = (int)g.VisibleClipBounds.Width - (int)captionSize.Width - (numButtons * buttonWidth);
                Rectangle rect = new Rectangle(x, 4, (int)(Math.Ceiling(captionSize.Width)), captionHeight);
    
                // draw the string
                g.DrawString(caption, font, brush, rect.X - 20, rect.Y + 4);
                
                // dispose unused objects
                brush.Dispose();
                g.Dispose();
    
            }
    
    
    and last - override the WndProc and catch the WM_NCPAINT message (NC stands for Non-Client like the title bar and the form borders):
    protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);
                if (m.Msg == WM_NCPAINT)
                {
                    DrawStringOnTheRight(m.HWnd, "this is the caption");
                }
            }
    hth,
    Lior.
    • Marked as answer by Aland Li Friday, January 22, 2010 7:29 AM
    • Unmarked as answer by Jassim Rahma Friday, January 22, 2010 11:40 PM
    • Marked as answer by Jassim Rahma Friday, January 22, 2010 11:40 PM
    Wednesday, January 20, 2010 2:43 PM