How to align separator in ContextMenuStrip - c#

Here is my code for ContextMenuStrip:
ContextMenuStrip _menuStrip = new ContextMenuStrip();
Image image = new Bitmap("icon_main.ico");
_menuStrip.Items.Add("First item", image);
ToolStripSeparator stripSeparator1 = new ToolStripSeparator();
stripSeparator1.Alignment = ToolStripItemAlignment.Right;//right alignment
_menuStrip.Items.Add(stripSeparator1);
_menuStrip.Items.Add("Second item", image);
ToolStripSeparator stripSeparator = new ToolStripSeparator();
stripSeparator.Alignment = ToolStripItemAlignment.Left;//left alignment
_menuStrip.Items.Add(stripSeparator);
_menuStrip.Items.Add("Exit", image, OnClickExit);
_mainIcon.ContextMenuStrip = _menuStrip;
Strange thing is that separators are not aligned - I have a little space between edge of ContextMenuStrip and separator, even if I try to align the separator (I've tried both - left and right alignment):
It's not a big graphical failure, but I'm asking myself how this can be aligned perfectly:
Any ideas what should I do?

You should use Paint event (msdn):
...
ToolStripSeparator stripSeparator = new ToolStripSeparator();
stripSeparator.Paint += stripSeparator_Paint;
_menuStrip.Items.Add(stripSeparator);
...
Paint event handler:
void stripSeparator_Paint(object sender, PaintEventArgs e)
{
ToolStripSeparator stripSeparator = sender as ToolStripSeparator;
ContextMenuStrip menuStrip = stripSeparator.Owner as ContextMenuStrip;
e.Graphics.FillRectangle(new SolidBrush(Color.Transparent), new Rectangle(0, 0, stripSeparator.Width, stripSeparator.Height));
using (Pen pen = new Pen(Color.LightGray, 1))
{
e.Graphics.DrawLine(pen, new Point(23, stripSeparator.Height / 2), new Point(menuStrip.Width, stripSeparator.Height / 2));
}
}

Related

Styling Windows Form Tab

I am creating windows Tabbed Application. Everything is good but the tabs are quiet faded and borders are very dull. I have tried changing the border style to 3D as well but no effect. Below is the screenshot
There are forums where people have suggested to use third party library to make Google Chrome type tabs. But I want the native way to get beautiful tabs.
You can take control of how the tabs are drawn by setting the DrawMode = TabDrawMode.OwnerDrawFixed. The example below assumes you have a TabControl named tabControl1 on the form, this will add a new tab with a blue box.
private Rectangle myTabRect;
private Rectangle myInsideRect;
private Rectangle myOutsideRect;
public Form1()
{
InitializeComponent();
TabPage tabPage1 = new TabPage();
// Sets the tabs to be drawn by the parent window Form1.
// OwnerDrawFixed allows access to DrawItem.
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
tabControl1.Controls.Add(tabPage1);
tabControl1.Location = new Point(25, 25);
tabControl1.Size = new Size(250, 250);
tabPage1.TabIndex = 0;
myTabRect = tabControl1.GetTabRect(0);
myInsideRect = new Rectangle(tabControl1.DisplayRectangle.X -1, tabControl1.DisplayRectangle.Y -1, tabControl1.DisplayRectangle.Width + 1, tabControl1.DisplayRectangle.Height + 1);
myOutsideRect = tabControl1.ClientRectangle;
myOutsideRect.Width--;
myOutsideRect.Height--;
ClientSize = new Size(300, 500);
Controls.Add(tabControl1);
tabControl1.DrawItem += new DrawItemEventHandler(OnDrawItem);
}
private void OnDrawItem(object sender, DrawItemEventArgs e)
{
// Draw your tab graphics here
Graphics g = e.Graphics;
Pen p = new Pen(Color.Blue);
g.DrawRectangle(p, myTabRect);
p = new Pen(Color.Red);
g.DrawRectangle(p, myInsideRect);
p = new Pen(Color.Green);
g.DrawRectangle(p, myOutsideRect);
}
You can draw whatever style you like into the graphic context, add text, images, etc

My code complies but doesn't show the ellipse in C#

So I am trying to make a red ellipse flash in the middle but for some reason my codes runs and complies but no ellipse is drawn
As you can see in the code part I have put the drawing part in the default constructor, I have also tried creating a private function that draws it and tried calling it in the default constructor but that didn't work either
using System;
using System.Drawing;
using System.Windows.Forms;
public class RedLuserinterface : Form
{
private Panel panelTop = new Panel();
private Panel panelMid = new Panel();
private Panel panelBot = new Panel();
private Label title = new Label();
private Button pauseBut = new Button();
private Button resumeBut = new Button();
private Button exitBut = new Button();
private Size minInterfaceSize = new Size(400, 600);
private Size maxInterfaceSize = new Size(400, 600);
public RedLuserinterface()
{ //Set the size of the user interface box.
MaximumSize = minInterfaceSize;
MinimumSize = maxInterfaceSize;
//Initialize text strings
Text = "Red Light Assignment";
title.Text = "Red Light Program";
pauseBut.Text = "Pause";
resumeBut.Text = "Resume";
exitBut.Text = "Exit";
//Set Sizes
Size = new Size(400, 600);
panelTop.Size = new Size(400, 30);
panelMid.Size = new Size(400, 160);
panelBot.Size = new Size(400, 50);
title.Size = new Size(120, 30);
pauseBut.Size = new Size(85, 30);
resumeBut.Size = new Size(85, 30);
exitBut.Size = new Size(85, 30);
//Set Locations
title.Location = new Point(140, 20);
panelTop.Location = new Point(0, 0);
panelMid.Location = new Point(0, 30);
panelBot.Location = new Point(0, 480);
pauseBut.Location = new Point(50, 500);
resumeBut.Location = new Point(40, 150);
exitBut.Location = new Point(250, 500);
//Add controls to the form
Controls.Add(title);
Controls.Add(panelTop);
Controls.Add(panelMid);
Controls.Add(panelBot);
Controls.Add(pauseBut);
Controls.Add(resumeBut);
Controls.Add(exitBut);
//Set Color
panelTop.BackColor = Color.Green;
panelMid.BackColor = Color.Blue;
panelBot.BackColor = Color.Yellow;
//Create solid brush and draw ellipse
SolidBrush redBrush = new SolidBrush(Color.Red);
Graphics circle = this.CreateGraphics();
circle.FillEllipse(redBrush, 0, 0, 200, 200);
//send some stuff to the back
panelTop.SendToBack();
panelMid.SendToBack();
panelBot.SendToBack();
pauseBut.Enabled = true;
resumeBut.Enabled = false;
exitBut.Click += new EventHandler(stoprun);
//dispose stuff
redBrush.Dispose();
circle.Dispose();
}
}
You need to paint your ellipse when the Form engine requires you to do it. The form engine will call the Paint event handler if you define one and will pass the Graphics object to use to paint the ellipse. So you should remove the lines in the form constructor and add the proper delegate for the Paint event, then in the Paint event draw the ellipse
public RedLuserinterface()
{
.....
// Remove these lines
// SolidBrush redBrush = new SolidBrush(Color.Red);
// Graphics circle = this.CreateGraphics();
// circle.FillEllipse(redBrush, 0, 0, 200, 200)
....
exitBut.Click += new EventHandler(stoprun);
this.Paint += onFormPaint;
// No more needed here
// redBrush.Dispose();
// circle.Dispose()
}
private void onFormPain(object sender, PaintEventArgs e)
{
SolidBrush redBrush = new SolidBrush(Color.Red);
e.Graphics.FillEllipse(redBrush, 50,250, 200, 200);
redBrush.Dispose();
}

Run method at application start [duplicate]

I'm drawing up a day schedule and representing timeslots with panels, and appointments are yet more panels on top.
The user is able to scroll up and down so that the range they can see is shifted earlier or later. When an appointment runs off the end of the visible range, I want there to be a zig-zag indicating that the appointment extends beyond the visible bounds.
I've identified the case where this occurs, and I call a private function drawZigZag(Panel p, int direction); to draw it. The day is spread horizontally, and the direction -1 indicates a zigzag on the left and 1 indicates a zigzag on the right.
So far, I'm not up to the zigzag yet, I'm just experimenting with CreateGraphics() and FillPolygon(). So far I have:
private void drawZigZag(Panel p, int direction) // 1 = right, -1 = left
{
Graphics g = p.CreateGraphics();
g.FillRectangle(new SolidBrush(Color.FromArgb(0, Color.Black)), p.DisplayRectangle);
Point[] points = new Point[4];
points[0] = new Point(0, 0);
points[1] = new Point(0, p.Height);
points[2] = new Point(p.Width, p.Height);
points[3] = new Point(p.Width, 0);
Brush brush = new SolidBrush(Color.DarkGreen);
g.FillPolygon(brush, points);
}
The first FillRectangle() I didn't originally have. I only added that when the FillPolygon() didn't work.
Basically, it's not working and I'm not sure why. The panel is the original colour - it hasn't been filled DarkGreen. I've used CreateGraphics() before for other things, and I'm not really sure why it's not working in this instance. Any ideas?
Edit: Sorry, I thought I should mention: There are several Label controls on my Panel which describe the appointment. These shouldn't be covered if possible.
You need to call this method from the paint event handler, not just whenever you like. So in your constructor you might have:
panel1.Paint += new PaintEventHandler(panel1_Paint);
and then the implementation:
private void panel1_Paint( object sender, PaintEventArgs e )
{
var p = sender as Panel;
var g = e.Graphics;
g.FillRectangle( new SolidBrush( Color.FromArgb( 0, Color.Black ) ), p.DisplayRectangle );
Point[] points = new Point[4];
points[0] = new Point( 0, 0 );
points[1] = new Point( 0, p.Height );
points[2] = new Point( p.Width, p.Height);
points[3] = new Point( p.Width, 0 );
Brush brush = new SolidBrush( Color.DarkGreen );
g.FillPolygon( brush, points );
}
For example we have this drawing event which is drawing a text from textBox1:
private void panel1_draw(object sender, PaintEventArgs e)
{
var g = e.Graphics;
Pen myp = new Pen(System.Drawing.Color.Red, 4);
Font fy = new Font("Helvetica", 10, FontStyle.Bold);
Brush br = new SolidBrush(System.Drawing.Color.Red);
g.DrawString(textBox1.Text, fy, br, 0,0);
}
In order to draw on your panel1, you need to write this code in your button event handler:
private void button1_Click(object sender, EventArgs e)
{
panel1.Paint+=new PaintEventHandler(panel1_draw);
panel1.Refresh();
}
The first line draws the text in your panel and if you want the text to appear you must refresh the panel.
The main thing is in using the panel1.Pain += new PaintEventHandler(your void name); and panel1.Refresh();

Change Specific Tab Page Tab Color / Losing formatting when selecting DrawMode=OwnerDrawFixed

While trying to change the color of the tab based on button click event I came across this page:
Set TabPage Header Color
It appears to work, however I lost all the other formatting of my tabs and they now appear blank after I set the DrawMode=OwnerDrawFixed. How do I set the color of the tab of a specific page and still show the tabs as normal?
Code:
private void button3_Click(object sender, EventArgs e)
{
this.TabControlMain.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.TabControlMain_DrawItem);
SetTabHeader (tabDownload, System.Drawing.Color.Green);
}
private Dictionary<TabPage, Color> TabColors = new Dictionary<TabPage, Color>();
private void SetTabHeader(TabPage page, Color color)
{
TabColors[page] = color;
tabDownload.Invalidate();
}
private void TabControlMain_DrawItem(object sender, DrawItemEventArgs e)
{
//e.DrawBackground();
using (Brush br = new SolidBrush(TabColors[TabControlMain.TabPages[e.Index]]))
{
e.Graphics.FillRectangle(br, e.Bounds);
SizeF sz = e.Graphics.MeasureString(TabControlMain.TabPages[e.Index].Text, e.Font);
e.Graphics.DrawString(TabControlMain.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + (e.Bounds.Width - sz.Width) / 2, e.Bounds.Top + (e.Bounds.Height - sz.Height) / 2 + 1);
Rectangle rect = e.Bounds;
rect.Offset(0, 1);
rect.Inflate(0, -1);
e.Graphics.DrawRectangle(Pens.DarkGray, rect);
e.DrawFocusRectangle();
}
}
Below is a screenshot
Use Y(et)A(nother)TabControl
Gives you the possibly to draw own custom headers:
public override void DrawTab( Color foreColor,
Color backColor,
Color highlightColor,
Color shadowColor,
Color borderColor,
bool active,
bool mouseOver,
DockStyle dock,
Graphics graphics,
SizeF tabSize )
{
if( active )
{
Pen p = new Pen( borderColor );
graphics.DrawRectangle( p, 0, 0, tabSize.Width, tabSize.Height );
p.Dispose();
}
else
{
Brush b = Brushes.Peru;
float dif = tabSize.Height / 4.0f;
RectangleF r = new RectangleF( 0.0f, dif,
tabSize.Width, tabSize.Height - dif - dif );
graphics.FillRectangle( b, r );
}
}
In principle your code works, if not fine then at least sufficiently.
But you need to fix a few simple issues:
Of course, if your Tab is OwnerDrawn you need to do it from the start, not just after pressing the Button! So hook up the event right from the start, best in the Property-Event Tab so that it is placed in the Desgner.cs file where it belongs.
Now the Tabs are drawn and their Label texts show.
If you want to change a color you need to Invalidate the Tab Control, not the TabPage!
so change
tabDownload.Invalidate();
to
TabControlMain.Invalidate();
To make the example complete I have done only this:
private void Form1_Load(object sender, EventArgs e)
{
foreach (TabPage tp in TabControlMain.TabPages)
TabColors.Add(tp, tp.BackColor);
}
This sets all Tab colors in the Dictionary to the Colors of the Pages.
The code to draw the FocusRectangle could be improved.
First set the Padding like this:
this.TabControlMain.Padding = new System.Drawing.Point(10, 4);
This gives us enough room to draw a nice FocusRectangle..
Then change the code to draw it only on the selected Tab, maybe like this:
if (TabControlMain.SelectedIndex == e.Index)
using (Pen pen = new Pen(Color.Gray))
{
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
Rectangle rect = e.Bounds;
rect.Offset(0, 1);
rect.Inflate(-3,-2);
e.Graphics.DrawRectangle(pen, rect);
}
Now it looks like this:
Of course managing the colors is up to you..

C# Winforms - Owner-drawn listbox with multiple colors in the same line

I found an article that does exactly what I need. It draws multiple colors on the same line on a text box. But the problem is that it was written in VB.NET and I'm writing my program in C#. Any good soul can convert this to C# if it is possible and if it isn't can you give me other options? Thanks.
This is the article: http://www.vbrad.com/article.aspx?id=34.
here is the conversion of what you posted Nicolas
if you need to change / get anything else working you will need to test it on your end..
Happy coding
private void MeasureItemHandler(object sender, MeasureItemEventArgs e)
{
Graphics g = Graphics.FromHwnd(lstColor.Handle);
StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
SizeF size = default(SizeF);
float height = 0;
Font oFont = new Font("Arial", 10);
//measure the height of what you are about to draw
//and let the listbox know this
size = g.MeasureString(data(e.Index), oFont, 500, sf);
height = size.Height + 5;
e.ItemHeight = height;
}
private void DrawItemHandler(object sender, DrawItemEventArgs e)
{
Graphics g = Graphics.FromHwnd(lstColor.Handle);
StringFormat sf = new StringFormat(StringFormat.GenericTypographic);
SizeF size = default(SizeF);
float width = 0;
Font oFont = new Font("Arial", 10);
//get the width of the string you are about to write
//this info is needed so that we can offset the next
//string that will be drawn in a different color.
size = g.MeasureString(data(e.Index), oFont, 500, sf);
width = size.Width + 16;
//prepare the list for drawing
e.DrawBackground();
e.DrawFocusRectangle();
//draw the first string in a certain color
e.Graphics.DrawString(data(e.Index), oFont, new SolidBrush(color(e.Index)), e.Bounds.X, e.Bounds.Y);
//draw the second string in a different color
e.Graphics.DrawString(data(data.Length - 1 - e.Index), oFont, new SolidBrush(color(color.Length - 1 - e.Index)), width, e.Bounds.Y);
}
First of all, they aren't using a Textbox in this article, they are using a Listbox but what follows is a conversion of the code from VB.Net to C# like you asked. It needs tidied up a bit but it does the job.
Just create a new Windows Form, place a Listbox called lstColor onto this form, change the DrawMode property to OwnerDrawFixed inside the properties window, then add event handlers for DrawItem and MeasureItem (you can add event handlers by clicking on the lightning bolt in the Properties window, and double clicking the whitespace beside these two words in the list).
In the DrawItem event handler, add the following:
private void lstColor_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
var size = g.MeasureString(data[e.Index], oFont, 500, sf);
var width = size.Width + 16;
e.DrawBackground();
e.DrawFocusRectangle();
e.Graphics.DrawString(data[e.Index], oFont, new SolidBrush(color[e.Index]), e.Bounds.X, e.Bounds.Y);
e.Graphics.DrawString(data[data.Length - 1 - e.Index], oFont, new SolidBrush(color[color.Length - 1 - e.Index]), width, e.Bounds.Y);
}
In the MeasureItem event handler, add this:
private void lstColor_MeasureItem(object sender, MeasureItemEventArgs e)
{
var size = g.MeasureString(data[e.Index], oFont, 500, sf);
var height = size.Height;
e.ItemHeight = Convert.ToInt32(height);
}
Add five private fields outside the scope of any methods but inside your Form1 (or whatever you've called your form) class like so:
private string[] data;
private Color[] color;
private Font oFont;
private Graphics g;
private StringFormat sf;
Put the following three lines inside your Form1_Load event:
private void Form1_Load(object sender, EventArgs e)
{
oFont = new Font("Arial", 10);
data = new string[] { "This is Red", "This is Blue", "This is Green", "This is Yellow", "This is Black", "This is Aqua", "This is Brown", "This is Cyan", "This is Gray", "This is Pink" };
color = new Color[] {Color.Red, Color.Blue, Color.Green, Color.Yellow, Color.Black, Color.Aqua, Color.Brown, Color.Cyan, Color.Gray,Color.Pink};
lstColor.DataSource = data;
g = Graphics.FromHwnd(lstColor.Handle);
sf = new StringFormat(StringFormat.GenericTypographic);
}
And you are all set.
Hope this helps
Check out http://converter.telerik.com/ It converts code from VB.NET to C# and C# to VB.NET. It wont work on complex code, but could prove useful to you.

Categories