I have custom tab control where OnPaint method is override.
Then strange growth of tabs occurs. Tabs getting bigger (padding getting bigger) and they width depends on length of the text.
When I use default Tab Control - padding is OK. How to avoid this situation when I use UserPaint?
partial class Tab : TabControl
{
public Tab()
{
InitializeComponent();
Init();
}
private void Init()
{
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.DoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
}
protected override void OnPaint(PaintEventArgs e)
{
DrawTabPane(e.Graphics);
}
private void DrawTabPane(Graphics g)
{
if (!Visible)
return;
// here we draw our tabs
for (int i = 0; i < this.TabCount; i++)
DrawTab(g, this.TabPages[i], i);
}
internal void DrawTab(Graphics g, TabPage tabPage, int nIndex)
{
Rectangle recBounds = this.GetTabRect(nIndex);
RectangleF tabTextArea = recBounds;
Point[] pt = new Point[4];
pt[0] = new Point(recBounds.Left + 1, recBounds.Bottom);
pt[1] = new Point(recBounds.Left + 1, recBounds.Top + 1);
pt[2] = new Point(recBounds.Right - 1, recBounds.Top + 1);
pt[3] = new Point(recBounds.Right - 1, recBounds.Bottom);
Brush br = new SolidBrush(clr_tab_norm);
g.FillPolygon(br, pt);
br.Dispose();
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
br = new SolidBrush(clr_txt);
g.DrawString(tabPage.Text, Font, br, tabTextArea, stringFormat);
}
}
Turning on ControlStyles.UserPaint for controls that are built into Windows, like TabControl, is not the proper thing to do. I assume the bug is in GetTabRect(), it isn't visible in the snippet.
Instead, you should use the TabControl.DrawMode property and implement the DrawItem event. There's a good example in the MSDN Library.
It would appear from the image that your code is setting the size of the tabs to be wider than they need to be. The extra padding is present in all your tabs but it is just more visible in the tabs with longer text.
I can't be sure why this is but I'd guess that the code to calculate the size of the tabs (based on font metrics) is using a different font from that used to draw the tabs.
Related
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
I need to graph a polygonal on a panel (size 400, 400)
I try this, but it doesn't work.
PointF[] points = new PointF[totalpaso + 1];
for (int d = 0; d <= totalpaso; d++)
{
s = (float)(hola1[d] + 200);
w = (float)(hola2[d] + 200);
j = new PointF(s, w);
points[d] = j;
}
grafico.DrawPolygon(lapiz, points);
I think you should take a look at this post:
https://msdn.microsoft.com/en-us/library/07e699tw(v=vs.110).aspx
But with only that method you won't get far. It'll be drawn in a OnPaint Method:
C# Forms - Using Paint methods?
You will probably want to make your own control based on Panel.
A really basic example is this:
public sealed class MyPanel: Panel
{
public MyPanel()
{
this.ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var brush = new SolidBrush(this.ForeColor))
{
e.Graphics.FillEllipse(brush, 0, 0, this.Width, this.Height);
}
}
}
To test it, add the class to a Windows Forms project, compile, and then drop it onto a form and set it to "Dock" in the designer.
Then set the BackColor to, say, red and the ForeColor to blue, then run the program.
You can then add your required drawing code to the OnPaint() override.
How would I go about drawing a border with a specified width and color around a listbox?
Can this be done without overriding the OnPaint method?
Following Neutone's suggestion, here is a handy function to add and remove a Panel-based border around any control, even if it is nested..
Simply pass in the Color and size you want, and if you want a BorderStyle. To remove it again pass in Color.Transparent!
void setBorder(Control ctl, Color col, int width, BorderStyle style)
{
if (col == Color.Transparent)
{
Panel pan = ctl.Parent as Panel;
if (pan == null) { throw new Exception("control not in border panel!");}
ctl.Location = new Point(pan.Left + width, pan.Top + width);
ctl.Parent = pan.Parent;
pan.Dispose();
}
else
{
Panel pan = new Panel();
pan.BorderStyle = style;
pan.Size = new Size(ctl.Width + width * 2, ctl.Height + width * 2);
pan.Location = new Point(ctl.Left - width, ctl.Top - width);
pan.BackColor = col;
pan.Parent = ctl.Parent;
ctl.Parent = pan;
ctl.Location = new Point(width, width);
}
}
You can place a list box within a panel and have the panel serve as a border. The panel backcolor can be used to create a colored border. This doesn't require much code. Having a colored border around a form component can be an effective way of conveying status.
The problem with the ListBox control is that it does not raise the OnPaint method so you can not use it to draw a border around the control.
There are two methods to paint a custom border around the ListBox:
Use SetStyle(ControlStyles.UserPaint, True) in the constructor, then you can use the OnPaint method to draw the border.
Override WndProc method that handles operating system messages identified in the Message structure.
I used the last method to paint a custom border around the control, this will eliminate the need to use a Panel to provide a custom border for the ListBox.
public partial class MyListBox : ListBox
{
public MyListBox()
{
// SetStyle(ControlStyles.UserPaint, True)
BorderStyle = BorderStyle.None;
}
protected override void WndProc(ref Message m)
{
base.WndProc(m);
var switchExpr = m.Msg;
switch (switchExpr)
{
case 0xF:
{
Graphics g = this.CreateGraphics;
g.SmoothingMode = Drawing2D.SmoothingMode.Default;
int borderWidth = 4;
Rectangle rect = ClientRectangle;
using (var p = new Pen(Color.Red, borderWidth) { Alignment = Drawing2D.PenAlignment.Center })
{
g.DrawRectangle(p, rect);
}
break;
}
default:
{
break;
}
}
}
}
Sorry for this question, but I've been Googling "C# vertical menu bar" for a while, and I can't find one that looks something like this:
No, I'm not making a survey locker, but that's the only image I could find of what I'm looking for.
Could anyone tell me how to do this?
You can creat custom User Control that Inherit from Tab Control.
For Windows Forms, Follow Below Steps:
Right Click Project -> Add New Item -> User Control(C#)
Inherit from TabControl and write below code in Default Constructor
3 Override OnPaint Method to manually Design Tab Control
Save it
Add it to your Form from toolbox.
Set Dock Property to Fill and Alignment Property to Left of Control
Add more Tabs
Hope this Helps!
class CustomControl : TabControl
{
public CustomControl()
{
SetStyle(ControlStyles.AllPaintingInWmPaint , true);
SetStyle(ControlStyles.OptimizedDoubleBuffer , true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.UserPaint, true);
DoubleBuffered = true;
SizeMode = TabSizeMode.Fixed;
ItemSize = new System.Drawing.Size(30, 120);
}
protected override void OnPaint(PaintEventArgs e)
{
var B = new Bitmap(Width, Height);
var G = (Graphics)Graphics.FromImage(B);
G.Clear(Color.Gainsboro);
for (int i = 0; i < TabCount -1; i++)
{
var TabRectangle = (Rectangle)GetTabRect(i);
if (i == SelectedIndex)
{
G.FillRectangle(Brushes.Navy, TabRectangle);
}
else
{
G.FillRectangle(Brushes.BlueViolet, TabRectangle);
}
G.DrawString(TabPages[i].Text, Font, Brushes.White, TabRectangle, new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
TabPages[i].Font = new Font(TabPages[i].Font, FontStyle.Strikeout);
}
e.Graphics.DrawImage((Image)B.Clone(),0,0);
G.Dispose();
B.Dispose();
base.OnPaint(e);
}
Happy Coding!
Assuming WPF, just plop a menu thats taller than its wider and add menu items
A clear omission seems to be that after applying this approach:
Vertical Tab Control with horizontal text in Winforms
Which is also recommended by Microsoft:
How to: Display Side-Aligned Tabs with TabControl
There is no text on tabs at design time, so further development and support becomes a nightmare.
Is there a way to make tab text also display at design time?
Just create your own control so the custom drawing also works at design time. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form. I tweaked it a bit to make it no so garish.
using System;
using System.Drawing;
using System.Windows.Forms;
class VerticalTabControl : TabControl {
public VerticalTabControl() {
this.Alignment = TabAlignment.Right;
this.DrawMode = TabDrawMode.OwnerDrawFixed;
this.SizeMode = TabSizeMode.Fixed;
this.ItemSize = new Size(this.Font.Height * 3 / 2, 75);
}
public override Font Font {
get { return base.Font; }
set {
base.Font = value;
this.ItemSize = new Size(value.Height * 3 / 2, base.ItemSize.Height);
}
}
protected override void OnDrawItem(DrawItemEventArgs e) {
using (var _textBrush = new SolidBrush(this.ForeColor)) {
TabPage _tabPage = this.TabPages[e.Index];
Rectangle _tabBounds = this.GetTabRect(e.Index);
if (e.State != DrawItemState.Selected) e.DrawBackground();
else {
using (var brush = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, Color.White, Color.LightGray, 90f)) {
e.Graphics.FillRectangle(brush, e.Bounds);
}
}
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Center;
_stringFlags.LineAlignment = StringAlignment.Center;
e.Graphics.DrawString(_tabPage.Text, this.Font, _textBrush, _tabBounds, new StringFormat(_stringFlags));
}
}
}
You need to subclass the TabControl and override OnDrawItem. Here's an example:
Public Class UITabControl
Inherits TabControl
Protected Overrides Sub OnDrawItem(e As DrawItemEventArgs)
Using brush As New SolidBrush(Me.ForeColor)
Using format As New StringFormat() With {.LineAlignment = StringAlignment.Center}
Select Case Me.Alignment
Case TabAlignment.Left
format.Alignment = StringAlignment.Near
Case TabAlignment.Top
format.Alignment = StringAlignment.Far
End Select
format.FormatFlags = (format.FormatFlags Or StringFormatFlags.NoWrap)
Dim rect As Rectangle = e.Bounds
rect.X += 3
rect.Width -= 6
e.Graphics.DrawString(Me.TabPages(e.Index).Text, Me.Font, brush, rect, format)
End Using
End Using
MyBase.OnDrawItem(e)
End Sub
End Class
Since you linked to my question, I thought it expedient to inform you of updates to my question thread.
I have, in an answer to my question, uploaded my code for the control in the interest of the programming community.
This is a screenshot of the control at runtime.
It features full design time support, automatic resizing of tabs (up to 128px wide) and tab icons as well.
The code can be downloaded from here.