C# vertical tab control with horizontal text - c#

I want to display some information in tab control This is what I want.
I have used the methods that I found on your side to make changes in properties of tab control and using Draw Event but the output is not like what i needed.The output comes likeThis is what I am getting..
I want the text to be horizontal. Also my VS is 2008

I followed these instructions in VB and converted them to C#. Worked for me. Basically in tab control properties set the following:
Alignment = Left
SizeMode = Fixed
ItemSize = 30, 120: Width = 30 Height = 120
DrawMode = OwnerDrawFixed
Then you have to handle DrawItem event like that:
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
var g = e.Graphics;
var text = this.tabControl1.TabPages[e.Index].Text;
var sizeText = g.MeasureString(text, this.tabControl1.Font);
var x = e.Bounds.Left + 3;
var y = e.Bounds.Top + (e.Bounds.Height - sizeText.Height) / 2;
g.DrawString(text, this.tabControl1.Font, Brushes.Black, x, y);
}
And the result is:

Set the SizeMode property to Fixed, so that all tabs are the same width.
Set the ItemSize property to the preferred fixed size for the tabs. Keep in mind that the ItemSize property behaves as though the tabs were on top, although they are left-aligned. As a result, in order to make the tabs wider, you must change the Height property, and in order to make them taller, you must change the Width property. [I set the ItemSize as: 25, 150].
Set the DrawMode property to OwnerDrawFixed.
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _textBrush;
// Get the item from the collection.
TabPage _tabPage = tabControl1.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _tabBounds = tabControl1.GetTabRect(e.Index);
if (e.State == DrawItemState.Selected)
{
// Draw a different background color, and don't paint a focus rectangle.
_textBrush = new SolidBrush(Color.Red);
g.FillRectangle(Brushes.Gray, e.Bounds);
}
else
{
_textBrush = new System.Drawing.SolidBrush(e.ForeColor);
e.DrawBackground();
}
// Use our own font.
Font _tabFont = new Font("Arial", (float)10.0, FontStyle.Bold, GraphicsUnit.Pixel);
// Draw string. Center the text.
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Center;
_stringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags));
}

Related

Side-aligned tabs in tabcontrol

Since I'm a C# beginner I don't know what's to do in my case. I wanted a side-aligned tab control so I have found this:
https://msdn.microsoft.com/en-us/library/ms404305%28v=vs.110%29.aspx
Now the tabpage names are not getting displayed at all. How do I "draw" them? I hope someone can help me. The DrawItem method:
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _textBrush;
// Get the item from the collection.
TabPage _tabPage = tabControl1.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _tabBounds = tabControl1.GetTabRect(e.Index);
if (e.State == DrawItemState.Selected)
{
// Draw a different background color, and don't paint a focus rectangle.
_textBrush = new SolidBrush(Color.Red);
g.FillRectangle(Brushes.Gray, e.Bounds);
}
else
{
_textBrush = new System.Drawing.SolidBrush(e.ForeColor);
e.DrawBackground();
}
// Use our own font.
Font _tabFont = new Font("Arial", (float)10.0, FontStyle.Bold, GraphicsUnit.Pixel);
// Draw string. Center the text.
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Center;
_stringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags));
}

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..

What is the most simple way to write a number in the middle of a panel?

I have a series of panels and a click event on the panel. Originally I had labels in the panel but it made things too cluttered and complicated my click event. Is there anyway I can just write text in the center of the panel because by placing a label in the middle it interferes with the click. All I need is a square/rectangle like object that I can a)dock b)change the color c)put dynamic text in the middle. Maybe I am overlooking a control preferable to panel?
Add Paint event to the Panel(s) and draw number as string using DrawString method of the Graphics class. Check this code as an example:
//Add the Paint event, you can set the same handler for each panel you are using
panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint);
//create the font with size you want to use, measure the string with that font
//and the Graphics class, calculate the origin point and draw your number:
private void panel1_Paint(object sender, PaintEventArgs e)
{
Panel p = (Panel)sender;
Font font = new System.Drawing.Font(new FontFamily("Times New Roman"),30);
string number = "10";
SizeF textSize = e.Graphics.MeasureString(number, font);
PointF origin = new PointF(p.Width/2 - textSize.Width/2, p.Height/2 - textSize.Height/2);
e.Graphics.DrawString("10", font, Brushes.Black, origin);
}
Since this code is executing very often, you would might want to declare and instantiate the the Font outside of the Paint handler:
Font font = new System.Drawing.Font(new FontFamily("Times New Roman"),30);
private void panel1_Paint(object sender, PaintEventArgs e)
{
Panel p = (Panel)sender;
string number = "10";
SizeF textSize = e.Graphics.MeasureString(number, font);
PointF origin = new PointF(p.Width/2 - textSize.Width/2, p.Height/2 - textSize.Height/2);
e.Graphics.DrawString("10", font, Brushes.Black, origin);
}
EDIT:
Added after the OP's comment:
Finding the largest font size for which the string still fits into the Panel
string number = "10";
float emSize = 10f;
SizeF textSize = SizeF.Empty;
Font font = null;
do
{
emSize++;
font = new System.Drawing.Font(new FontFamily("Times New Roman"), emSize);
textSize = e.Graphics.MeasureString(number, font);
}
while (panel1.Width > textSize.Width && panel1.Height > textSize.Height);
font = new System.Drawing.Font(new FontFamily("Times New Roman"), --emSize);
Disclaimer: I didn't take into account float to int casting, but that is something that should be taken care of also.

How to change BackColor of Tab?

I have two windows forms. 1st one is mdiParent form named as main. 2nd one is presentation form which is the child form of main form. presentaion form has a tabbed layout. presentation form has a preferences button. when I click on preferences button a new form('prefs') opens asking to click on a set color button. clicking that button opens a dialogResult to change color. when I select a color, the prefs backcolor changes. but dows not changes the tabbed layout('presentation form') backcolor. I'm building this application in n-tier architecture. so help me how can I change the backcolor of a tab. I will upload code if you didn't understand my question.
TabControls do not have a BackColor property exposed since they typically draw based on the current window system theme.
It's usually not worth the effort, but the TabControl does has a DrawMode property where you would draw the tab yourself in the DrawItem event.
Each individual TabPage control does have a BackColor property available.
here's my custom event handler I have to create a colored box that surrounds the text. The selected tab is one color and unselected is another...
private void ChangeTabColor(Object sender, DrawItemEventArgs e)
{
Font TabFont;
Brush BackBrush;// = new SolidBrush(Color.Green); //Set background color
Brush ForeBrush = new SolidBrush(Color.Black);//Set foreground color
Brush borderBrush = new SolidBrush(Color.Black);//Set foreground color
if (e.Index == this.tabMain.SelectedIndex)
{
TabFont = new Font(e.Font, FontStyle.Bold);
BackBrush = new SolidBrush(Color.MediumSeaGreen); //Set background color
//ForeBrush = new SolidBrush(Color.Black);//Set foreground color
}
else
{
TabFont = e.Font;
BackBrush = new SolidBrush(Color.LightSteelBlue); //Set background color
//ForeBrush = new SolidBrush(Color.Yellow);//Set foreground color
}
string TabName = this.tabMain.TabPages[e.Index].Text;
StringFormat sf = new StringFormat();
sf.Alignment = StringAlignment.Center;
Rectangle r = e.Bounds;
r = new Rectangle(r.X, r.Y + 5, r.Width, r.Height - 3);
if (e.Index == this.tabMain.SelectedIndex)
{
Pen rectPen = new Pen(borderBrush, 1.0f);
r.Y -= 2;
r.X += 3;
r.Height -= 9;
r.Width -= 8;
e.Graphics.FillRectangle(BackBrush, r);
e.Graphics.DrawString(TabName, TabFont, ForeBrush, r, sf);
e.Graphics.DrawRectangle(rectPen, r);
}
else
{
Pen rectPen = new Pen(borderBrush, 1.0f);
r.Y -= 2;
r.Height -= 4;
r.Width -= 2;
e.Graphics.FillRectangle(BackBrush, r);
e.Graphics.DrawString(TabName, TabFont, ForeBrush, r, sf);
e.Graphics.DrawRectangle(rectPen, r);
}
//Dispose objects
sf.Dispose();
if (e.Index == this.tabMain.SelectedIndex)
{
TabFont.Dispose();
BackBrush.Dispose();
}
else
{
BackBrush.Dispose();
ForeBrush.Dispose();
}
}
of course "tabMain" refers to the tab control name. I hope this helps with what you are trying to do...probably a bit fancier, but the code isn't that difficult, and I think it looks a bit cleaner...plus in order to do this i made sure to set the approprate properties for font and item size:
Font = Arial, 9pt, style=Bold
ItemSize = 95, 25
...the height is the important part, as long as you set SizeMode = Normal

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