C# School Assignment? Project Due Tomorrow? Chat LIVE With A Programming Expert!

Welcome to Dream.In.Code
Become a C# Expert!

Join 307,215 C# Programmers for FREE! Get instant access to thousands of C# experts, tutorials, code snippets, and more! There are 1,576 people online right now. Registration is fast and FREE... Join Now!




Designing a custom title bar

 
Reply to this topicStart new topic

> Designing a custom title bar, And adding FULL functionality

gabehabe
Group Icon



post 24 Sep, 2008 - 02:33 PM
Post #1


I've developed a borderless form, with full functionality, in pure code. I've avoided design view, because... well, just because I felt like it. Coming from a C++ background, I'm quite used to coding everything in myself. smile.gif

NOTE: The output is quite ugly, but this is a basic example to demonstrate the functionality of a custom title bar. (Particularly the event handlers)

Now, down to business.

First off, we start with our using directives. We're actually not using too much:
csharp
using System;
using System.Drawing;
using System.Windows.Forms;


Now for our class variables. The scope of these is important~ If we create them in our functions, we won't have access to them in the custom event handlers:
csharp
		private PictureBox title = new PictureBox(); // create a PictureBox
private Label minimise = new Label(); // this doesn't even have to be a label!
private Label maximise = new Label(); // this will simulate our this.maximise box
private Label close = new Label(); // simulates the this.close box

private bool drag = false; // determine if we should be moving the form
private Point startPoint = new Point(0, 0); // also for the moving


The constructor is also very basic. I've commented it enough to just paste here~ as I said before, it's the event handlers we're interested in. (Most of the constructor is just hard-coding the design anyway)
csharp
		public MainForm()
{
this.FormBorderStyle = FormBorderStyle.None; // get rid of the standard title bar

this.title.Location = this.Location; // assign the location to the form location
this.title.Width = this.Width; // make it the same width as the form
this.title.Height = 50; // give it a default height (you may want it taller/shorter)
this.title.BackColor = Color.Black; // give it a default colour (or load an image)
this.Controls.Add(this.title); // add it to the form's controls, so it gets displayed
// if you have an image to display, you can load it, instead of assigning a bg colour
// this.title.Image = new Bitmap(System.Environment.CurrentDirectory + "\\title.jpg");
// if you displayed an image, alter the SizeMode to get it to display as you want it to
// examples:
// this.title.SizeMode = PictureBoxSizeMode.StretchImage;
// this.title.SizeMode = PictureBoxSizeMode.CenterImage;
// this.title.SizeMode = PictureBoxSizeMode.Zoom;
// etc

// you may want to use PictureBoxes and display images
// or use buttons, there are many alternatives. This is a mere example.
this.minimise.Text = "Minimise"; // Doesn't have to be
this.minimise.Location = new Point(this.Location.X+5, this.Location.Y+5); // give it a default location
this.minimise.ForeColor = Color.Red; // Give it a colour that will make it stand out
// this is why I didn't use an image, just to keep things simple:
this.minimise.BackColor = Color.Black; // make it the same as the PictureBox
this.Controls.Add(this.minimise); // add it to the form's controls
this.minimise.BringToFront(); // bring it to the front, to display it above the picture box

this.maximise.Text = "Maximise";
// remember to make sure it's far enough away so as not to overlap our minimise option
this.maximise.Location = new Point(this.Location.X+60, this.Location.Y+5);
this.maximise.ForeColor = Color.Red;
this.maximise.BackColor = Color.Black; // remember, we want it to match the background
this.maximise.Width = 50;
this.Controls.Add(this.maximise); // add it to the form
this.maximise.BringToFront();

this.close.Text = "Close";
this.close.Location = new Point(this.Location.X+120, this.Location.Y+5);
this.close.ForeColor = Color.Red;
this.close.BackColor = Color.Black;
this.close.Width = 37; // this is just to make it fit nicely
this.Controls.Add(this.close);
this.close.BringToFront();

// now we need to add some functionality. First off, let's give those labels
// MouseHover and MouseLeave events, so they change colour
// Since they're all going to change to the same colour, we can give them the same
// event handler, which saves time of writing out all those extra functions
this.minimise.MouseEnter += new EventHandler(Control_MouseEnter);
this.maximise.MouseEnter += new EventHandler(Control_MouseEnter);
this.close.MouseEnter += new EventHandler(Control_MouseEnter);

// and we need to do the same for MouseLeave events, to change it back
this.minimise.MouseLeave += new EventHandler(Control_MouseLeave);
this.maximise.MouseLeave += new EventHandler(Control_MouseLeave);
this.close.MouseLeave += new EventHandler(Control_MouseLeave);

// and lastly, for these controls, we need to add some functionality
this.minimise.MouseClick += new MouseEventHandler(Control_MouseClick);
this.maximise.MouseClick += new MouseEventHandler(Control_MouseClick);
this.close.MouseClick += new MouseEventHandler(Control_MouseClick);

// finally, wouldn't it be nice to get some moveability on this control?
this.title.MouseDown += new MouseEventHandler(Title_MouseDown);
this.title.MouseUp += new MouseEventHandler(Title_MouseUp);
this.title.MouseMove += new MouseEventHandler(Title_MouseMove);
}


Look how many event handlers we need! But, don't worry. Many of them can be reused, by checking which object is the sender.

This is where the interesting stuff comes into play. Working with those events.

Changing the colour
Appearance is key. While my design may be ugly, it's important to add nice little quirks like colour changing.
First off, let's change the appearance when the mouse enters/leaves our labels.
When the mouse enters the label, we want it to change colour to say "you're about to click me?"
When it exits, we want to change it back:
csharp
		private void Control_MouseEnter(object sender, EventArgs e)
{
if (sender.Equals(this.close))
this.close.ForeColor = Color.White;
else if (sender.Equals(this.maximise))
this.maximise.ForeColor = Color.White;
else // it's the minimise label
this.minimise.ForeColor = Color.White;
}

private void Control_MouseLeave(object sender, EventArgs e)
{ // return them to their default colours
if (sender.Equals(this.close))
this.close.ForeColor = Color.Red;
else if (sender.Equals(this.maximise))
this.maximise.ForeColor = Color.Red;
else // it's the minimise label
this.minimise.ForeColor = Color.Red;
}


Deciding what to do
Now, we've got three options: minimise, maximise, and close. We have a this.Close() function, but we don't have minimise/maximise/restore functions. Looks like we're going to have to code those in ourselves! Simple enough though, we can use FormWindowState like so:
csharp
		private void Control_MouseClick(object sender, MouseEventArgs e)
{
if (sender.Equals(this.close))
this.Close(); // close the form
else if (sender.Equals(this.maximise))
{ // maximise is more interesting. We need to give it different functionality,
// depending on the window state (Maximise/Restore)
if (this.maximise.Text == "Maximise")
{
this.WindowState = FormWindowState.Maximized; // maximise the form
this.maximise.Text = "Restore"; // change the text
this.title.Width = this.Width; // stretch the title bar
}
else // we need to restore
{
this.WindowState = FormWindowState.Normal;
this.maximise.Text = "Maximise";
}
}
else // it's the minimise label
this.WindowState = FormWindowState.Minimized; // minimise the form
}


Moving the form
This is the bit I really enjoyed coding. Making the form move. We do this with the event handlers of MouseUp, MouseDown, and MouseMove. If the mouse is down, we want to move it. If not, we don't want to. This is where drag comes into play, along with startPoint.
csharp
		void Title_MouseUp(object sender, MouseEventArgs e)
{
this.drag = false;
}

void Title_MouseDown(object sender, MouseEventArgs e)
{
this.startPoint = e.Location;
this.drag = true;
}

void Title_MouseMove(object sender, MouseEventArgs e)
{
if (this.drag)
{ // if we should be dragging it, we need to figure out some movement
Point p1 = new Point(e.X, e.Y);
Point p2 = this.PointToScreen(p1);
Point p3 = new Point(p2.X - this.startPoint.X,
p2.Y - this.startPoint.Y);
this.Location = p3;
}
}
}
}


The Final Product
csharp
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Custom_Title_Bar
{
public partial class MainForm : Form
{
private PictureBox title = new PictureBox(); // create a PictureBox
private Label minimise = new Label(); // this doesn't even have to be a label!
private Label maximise = new Label(); // this will simulate our this.maximise box
private Label close = new Label(); // simulates the this.close box

private bool drag = false; // determine if we should be moving the form
private Point startPoint = new Point(0, 0); // also for the moving

public MainForm()
{
this.FormBorderStyle = FormBorderStyle.None; // get rid of the standard title bar

this.title.Location = this.Location; // assign the location to the form location
this.title.Width = this.Width; // make it the same width as the form
this.title.Height = 50; // give it a default height (you may want it taller/shorter)
this.title.BackColor = Color.Black; // give it a default colour (or load an image)
this.Controls.Add(this.title); // add it to the form's controls, so it gets displayed
// if you have an image to display, you can load it, instead of assigning a bg colour
// this.title.Image = new Bitmap(System.Environment.CurrentDirectory + "\\title.jpg");
// if you displayed an image, alter the SizeMode to get it to display as you want it to
// examples:
// this.title.SizeMode = PictureBoxSizeMode.StretchImage;
// this.title.SizeMode = PictureBoxSizeMode.CenterImage;
// this.title.SizeMode = PictureBoxSizeMode.Zoom;
// etc

// you may want to use PictureBoxes and display images
// or use buttons, there are many alternatives. This is a mere example.
this.minimise.Text = "Minimise"; // Doesn't have to be
this.minimise.Location = new Point(this.Location.X+5, this.Location.Y+5); // give it a default location
this.minimise.ForeColor = Color.Red; // Give it a colour that will make it stand out
// this is why I didn't use an image, just to keep things simple:
this.minimise.BackColor = Color.Black; // make it the same as the PictureBox
this.Controls.Add(this.minimise); // add it to the form's controls
this.minimise.BringToFront(); // bring it to the front, to display it above the picture box

this.maximise.Text = "Maximise";
// remember to make sure it's far enough away so as not to overlap our minimise option
this.maximise.Location = new Point(this.Location.X+60, this.Location.Y+5);
this.maximise.ForeColor = Color.Red;
this.maximise.BackColor = Color.Black; // remember, we want it to match the background
this.maximise.Width = 50;
this.Controls.Add(this.maximise); // add it to the form
this.maximise.BringToFront();

this.close.Text = "Close";
this.close.Location = new Point(this.Location.X+120, this.Location.Y+5);
this.close.ForeColor = Color.Red;
this.close.BackColor = Color.Black;
this.close.Width = 37; // this is just to make it fit nicely
this.Controls.Add(this.close);
this.close.BringToFront();

// now we need to add some functionality. First off, let's give those labels
// MouseHover and MouseLeave events, so they change colour
// Since they're all going to change to the same colour, we can give them the same
// event handler, which saves time of writing out all those extra functions
this.minimise.MouseEnter += new EventHandler(Control_MouseEnter);
this.maximise.MouseEnter += new EventHandler(Control_MouseEnter);
this.close.MouseEnter += new EventHandler(Control_MouseEnter);

// and we need to do the same for MouseLeave events, to change it back
this.minimise.MouseLeave += new EventHandler(Control_MouseLeave);
this.maximise.MouseLeave += new EventHandler(Control_MouseLeave);
this.close.MouseLeave += new EventHandler(Control_MouseLeave);

// and lastly, for these controls, we need to add some functionality
this.minimise.MouseClick += new MouseEventHandler(Control_MouseClick);
this.maximise.MouseClick += new MouseEventHandler(Control_MouseClick);
this.close.MouseClick += new MouseEventHandler(Control_MouseClick);

// finally, wouldn't it be nice to get some moveability on this control?
this.title.MouseDown += new MouseEventHandler(Title_MouseDown);
this.title.MouseUp += new MouseEventHandler(Title_MouseUp);
this.title.MouseMove += new MouseEventHandler(Title_MouseMove);
}

private void Control_MouseEnter(object sender, EventArgs e)
{
if (sender.Equals(this.close))
this.close.ForeColor = Color.White;
else if (sender.Equals(this.maximise))
this.maximise.ForeColor = Color.White;
else // it's the minimise label
this.minimise.ForeColor = Color.White;
}

private void Control_MouseLeave(object sender, EventArgs e)
{ // return them to their default colours
if (sender.Equals(this.close))
this.close.ForeColor = Color.Red;
else if (sender.Equals(this.maximise))
this.maximise.ForeColor = Color.Red;
else // it's the minimise label
this.minimise.ForeColor = Color.Red;
}

private void Control_MouseClick(object sender, MouseEventArgs e)
{
if (sender.Equals(this.close))
this.Close(); // close the form
else if (sender.Equals(this.maximise))
{ // maximise is more interesting. We need to give it different functionality,
// depending on the window state (Maximise/Restore)
if (this.maximise.Text == "Maximise")
{
this.WindowState = FormWindowState.Maximized; // maximise the form
this.maximise.Text = "Restore"; // change the text
this.title.Width = this.Width; // stretch the title bar
}
else // we need to restore
{
this.WindowState = FormWindowState.Normal;
this.maximise.Text = "Maximise";
}
}
else // it's the minimise label
this.WindowState = FormWindowState.Minimized; // minimise the form
}

void Title_MouseUp(object sender, MouseEventArgs e)
{
this.drag = false;
}

void Title_MouseDown(object sender, MouseEventArgs e)
{
this.startPoint = e.Location;
this.drag = true;
}

void Title_MouseMove(object sender, MouseEventArgs e)
{
if (this.drag)
{ // if we should be dragging it, we need to figure out some movement
Point p1 = new Point(e.X, e.Y);
Point p2 = this.PointToScreen(p1);
Point p3 = new Point(p2.X - this.startPoint.X,
p2.Y - this.startPoint.Y);
this.Location = p3;
}
}
}
}


Now a challenge for you
What? You're going to want to do something on your own, right?
As an added bonus, you could also add in a context menu. When you have a borderless form, unfortunately, it automatically takes out the context menu when the user right clicks the program in the task bar.

Here's a few hints:
  • The message for the task bar right clicking on your program is 0x0313
  • Try overriding the WndProc method: protected override void WndProc(ref Message m)

Finally, if you don't want to do it, here it is: (you didn't think I'd leave anything unanswered, did you? This is a tutorial, for crying out loud...)

csharp
		protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0313)
{
// contMenu is the ContextMenu which you wish to display
int contMenuX = Cursor.Position.X - this.Location.X;
int contMenuY = Cursor.Position.Y - this.Location.Y;

Point contMenuPos = new Point(contMenuX, contMenuY);

this.contMenu.Show(this, contMenuPos);
}
base.WndProc(ref m);
}


Happy coding! smile.gif
Go to the top of the page
+Quote Post


Register to Make This Ad Go Away!

jacobjordan
Group Icon



post 24 Sep, 2008 - 05:30 PM
Post #2
Nice. Very useful. In my little bar app, i did the same for all the child forms, but it wasn't near as complicated as this.
Go to the top of the page
+Quote Post

Zap-Man
*



post 12 Feb, 2009 - 12:55 PM
Post #3
This works great but, I don't want to get of the windows border. I do like the fixed3d style that it has. But I don't like the standard blue and I don't want others that download my app to see this either. Is there a way to overide the formBorderStyle or to make borders like the windows?
Go to the top of the page
+Quote Post

Zap-Man
*



post 12 Feb, 2009 - 09:53 PM
Post #4
Yo Dude,

I got my border that I wanted in and it looks HOTT. Although with the windows form it makes a beige color retengle. Windows calls the color "Control". And with round corners it was tough to get to to display corectly. I did figure out that you can set the backcolor then use the transparency key with the same color and window background goes away. this making my round coners still round.

I did find out as I was trying to implement in my code that you can't use a split container for some odd reason. it make my whole form out of wake.

I could never get the form to move. I have even tried your code with out all of my crap and I couldn't seem to get it to work. The code is the same so I would think that it would. Could you please or someone else check this for me. It would be nice to move the darn window out of my way. lol

ps email me if you'd like to see the form. It's pretty HOTT!
Go to the top of the page
+Quote Post

unilith_dev
*



post 24 Feb, 2009 - 08:11 PM
Post #5
This is what I use to move a borderless form:

Assuming you have some kind of rectangle area defined as a 'title bar'..
CODE

...
CaptionRectangle = new Rectangle(0,0,this.Width,30);


CODE

private const int HTCAPTION = 2;
private const int WM_NCHITTEST = 0x84;

protected override void DefWndProc(ref Message m)
{
  if(!DesignMode)
    {
      if(m.Msg == WM_NCHITTEST)
      {
         Point pt = new Point(m.LParam.ToInt32());
         if(CaptionRectangle.Contains(pt))
         {
           m.Result = new IntPtr(HTCAPTION);
          }
       }
     }
       base.DefWndProc(ref m);
}
Go to the top of the page
+Quote Post


Fast ReplyReply to this topicStart new topic
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:

 


Lo-Fi Version Time is now: 11/21/09 10:03PM

Live C# Help!

Be Social

Dream.In.Code RSS Feed Dream.In.Code LinkedIn Group Follow Us On Twitter Fan Us On Facebook

C# Tutorials

Reference Sheets

C# Snippets

DIC Chatroom

Bye Bye Ads

Monthly Drawing

Thumb Drive

Top Contributors

Top 10 Kudos This Month