I'm drawing part of the title bar in my WinForm applications. Is working Ok (placing the name of the company centered and in Orange)
This is the code to do that at the form code:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
private Rectangle PosicionTexto()
{
string sTexto = String.Format("{0} : {1}", this.Text, "Trevo I.T.");
sTexto = "Trevo I.T.";
Graphics oG = this.CreateGraphics();
SizeF oS = oG.MeasureString(sTexto, new Font("Tahoma", 8f, FontStyle.Bold));
Rectangle rect = new Rectangle();
rect.X = (this.Width/2) - (int)(oS.Width/2);
rect.Y = SystemInformation.FrameBorderSize.Height + 4;
rect.Width = (int)oS.Width;
rect.Height = SystemInformation.CaptionButtonSize.Height;
return rect;
}
private void DrawTitleBar(IntPtr hwnd)
{
// Obtenemos el Canvas a partir del DC de la ventana
IntPtr hdc = GetWindowDC(hwnd);
Graphics gBarra = Graphics.FromHdc(hdc);
Rectangle rect = PosicionTexto();
string sTexto = String.Format("{0} : {1}", this.Text, "Trevo I.T.");
sTexto = "Trevo I.T.";
gBarra.DrawString(sTexto, new Font("Tahoma", 8f, FontStyle.Bold), Brushes.Orange, new PointF(rect.X, rect.Y));
// Liberamos la memoria*/
gBarra.Flush();
ReleaseDC(hwnd, hdc);
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x000F: // WM_PAINT
case 0x0085: // WM_NCPAINT:
base.WndProc(ref m);
DrawTitleBar(m.HWnd);
break;
default:
// Invocamos a la funcion original
base.WndProc(ref m);
break;
}
}
The issue is resizing the window. The text is not cleared and shown several times. Is there a way to "Refresh" the title bar before drawing my text?
Thanks in advance.
EDIT Almost solved. Added two more methods:
// Rectangle of the title bar
private Rectangle TitleBarRectangle()
{
Rectangle rect = new Rectangle();
rect.X = 1 + SystemInformation.CaptionButtonSize.Width; // Avoid to draw over the icon
rect.Y = 1;
rect.Width = Width - (SystemInformation.CaptionButtonSize.Width * 4); // Avoid to draw over the buttons
rect.Height = SystemInformation.CaptionButtonSize.Height;
return rect;
}
// Draw a filled rectangle
private void ClearTitleBar(IntPtr hwnd)
{
// Obtenemos el Canvas a partir del DC de la ventana
IntPtr hdc = GetWindowDC(hwnd);
try
{
using (Graphics gBarra = Graphics.FromHdc(hdc))
{
Rectangle rect = TitleBarRectangle();
gBarra.FillRectangle(new SolidBrush(SystemColors.ActiveCaption), rect);
gBarra.Flush();
}
}
finally
{
ReleaseDC(hwnd, hdc);
}
}
and modified one:
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x0085: // WM_NCPAINT:
case 0x0005: // WM_SIZE
base.WndProc(ref m);
DrawTitleBar(m.HWnd);
break;
case 0x214: // WM_SIZING
base.WndProc(ref m);
ClearTitleBar(m.HWnd);
break;
default:
// Invocamos a la funcion original
base.WndProc(ref m);
break;
}
}
By the way, the whole idea started from Copstone
Thanks Lars, Zach and of course, Jim. Your comments and answers put me on the way.
A simple solution is to call
gBarra.FillRectangle
to fill the title bar with the background color before you draw the string.Are you sure you need to do this in WM_PAINT? Seems like WM_NCPAINT would be enough.
I strongly recommend that you use
try...finally
to ensure that the DC gets released. That is: