Extracting an Event (tabControl_DrawItem) to Class Library - c#

I have the following code under a TabConttrols DrawItem event that I am trying to extract into a class file. I am having trouble since it is tied to an event. Any hints or pointers would be greatly appreciated.
private void tabCaseNotes_DrawItem(object sender, DrawItemEventArgs e)
{
TabPage currentTab = tabCaseNotes.TabPages[e.Index];
Rectangle itemRect = tabCaseNotes.GetTabRect(e.Index);
SolidBrush fillBrush = new SolidBrush(Color.Linen);
SolidBrush textBrush = new SolidBrush(Color.Black);
StringFormat sf = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center
};
//If we are currently painting the Selected TabItem we'll
//change the brush colors and inflate the rectangle.
if (System.Convert.ToBoolean(e.State & DrawItemState.Selected))
{
fillBrush.Color = Color.LightSteelBlue;
textBrush.Color = Color.Black;
itemRect.Inflate(2, 2);
}
//Set up rotation for left and right aligned tabs
if (tabCaseNotes.Alignment == TabAlignment.Left || tabCaseNotes.Alignment == TabAlignment.Right)
{
float rotateAngle = 90;
if (tabCaseNotes.Alignment == TabAlignment.Left)
rotateAngle = 270;
PointF cp = new PointF(itemRect.Left + (itemRect.Width / 2), itemRect.Top + (itemRect.Height / 2));
e.Graphics.TranslateTransform(cp.X, cp.Y);
e.Graphics.RotateTransform(rotateAngle);
itemRect = new Rectangle(-(itemRect.Height / 2), -(itemRect.Width / 2), itemRect.Height, itemRect.Width);
}
//Next we'll paint the TabItem with our Fill Brush
e.Graphics.FillRectangle(fillBrush, itemRect);
//Now draw the text.
e.Graphics.DrawString(currentTab.Text, e.Font, textBrush, (RectangleF)itemRect, sf);
//Reset any Graphics rotation
e.Graphics.ResetTransform();
//Finally, we should Dispose of our brushes.
fillBrush.Dispose();
textBrush.Dispose();
}

Depends on what you're trying to achieve. You could always sub class TabControl or you could encapsulate the drawing code in a class that you pass a TabControl to.
public class TabRenderer
{
private TabControl _tabControl;
public TabRenderer(TabControl tabControl)
{
_tabControl = tabControl;
_tabControl.DrawMode = TabDrawMode.OwnerDrawFixed;
_tabControl.DrawItem += TabControlDrawItem;
}
private void TabControlDrawItem(object sender, DrawItemEventArgs e)
{
// Your drawing code...
}
}

Related

How to add callout in picturebox using C#?

I need to add WedgeRectCallout callout on picturebox using C#.
Is there a way to do it?
please refer image using below link to know about the callout.
In word document, I can do the same using Spire.Doc library and writing below code:
ShapeObject Shape1 = para1.AppendShape(30, 50, ShapeType.WedgeRectCallout);
Here is a minimal example. It creates a Panel subclass with a nested TextBox.
Note that you can't add controls to a PictureBox in the designer. Instead you can put it on top and use the Nest function to embed it in the PBox..
(I use a trick to simplify the drawing of the border: since shrinking a GraphicsPath is hard and I am too lazy to write out two of them, I draw the border twice and add a little offset. The effect is a shadow effect, which looks rather nice for a cheat..)
Here is the class in action:
And here is the class code:
class WedgeCallout : Panel
{
public WedgeCallout()
{
tb = new TextBox();
Controls.Add(tb);
}
TextBox tb = null;
GraphicsPath gp = new GraphicsPath();
protected override void OnLayout(LayoutEventArgs levent)
{
tb.Size = new Size(Width - 10, (int)(Height * 0.66));
tb.Location = new Point(5, 5);
tb.BackColor = BackColor;
tb.ForeColor = ForeColor ;
tb.BorderStyle = BorderStyle.None;
tb.Text = "Hiho";
tb.Multiline = true;
tb.TextAlign = HorizontalAlignment.Center;
tb.Font = Font;
SetRegion();
base.OnLayout(levent);
}
protected override void OnBackColorChanged(EventArgs e)
{
base.OnBackColorChanged(e);
if (BackColor != Color.Transparent)
tb.BackColor = BackColor;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (Tag == null) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using(SolidBrush brush = new SolidBrush(tb.BackColor))
e.Graphics.FillPath(brush, (GraphicsPath)Tag);
using (Pen pen = new Pen(Color.DarkGray, 2f))
e.Graphics.DrawPath(pen, (GraphicsPath)Tag);
e.Graphics.TranslateTransform(-1, -1);
using (Pen pen = new Pen(ForeColor, 2f))
e.Graphics.DrawPath(pen, (GraphicsPath)Tag);
}
void SetRegion()
{
Rectangle r = ClientRectangle;
int h = (int)(r.Height * 0.75f);
if (gp != null) gp.Dispose();
gp = new GraphicsPath();
gp.AddPolygon(new PointF[]{ new Point(0,0),
new Point(r.Width-1, 0), new Point(r.Width-1, h),
new PointF(50, h) , new Point(0, r.Height-1),
new PointF(20, h), new PointF(0, h)});
Region = new Region(gp);
Tag = gp;
}
}
You can set the colors and the Font in the designer..
And the Nest function:
void Nest(Control child, Control parent)
{
Point p0 = parent.PointToScreen(Point.Empty);
Point p1 = child.PointToScreen(Point.Empty);
child.Location = new Point(p1.X - p0.X, p1.Y - p0.Y);
child.Parent = parent;
}
It is called from the Form where the controls sit: Nest(wedgeCallout1, pictureBox1);
Note that to save to callout with the pbox in one image you need to
Nest the callout in the PBox
Use pbox.DrawToBitmap
Temporarily set the backcolor to transparent
Example:
private void saveBtn_Click(object sender, EventArgs e)
{
Size sz = pictureBox1.ClientSize;
using (Bitmap bmp = new Bitmap(sz.Width, sz.Height))
{
Color old = wedgeCallout1.BackColor;
wedgeCallout1.BackColor = Color.Transparent;
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
bmp.Save(filename, ImageFormat.Png);
wedgeCallout1.BackColor = old;
}
}

CheckedListBox: How to increase size of checkbox and change color of tick mark

I want to override default look of CheckedListBox as below:
Please Note the increased size of checkbox and colored tick mark.
For this you need to create own custom control by inheriting CheckedListbox and need to override OnDrawItem(DrawItemEventArgs e) event
Below is the Code :
class BigCheckedListBox : CheckedListBox
{
public BigCheckedListBox()
{
ForeColor = Color.Turquoise;
Font = new Font("Segoe UI", 12f);
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
var b = e.Bounds;
var state = GetItemChecked(e.Index) ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal;
Size glyphSize = CheckBoxRenderer.GetGlyphSize(e.Graphics, state);
int checkPad = (b.Height - glyphSize.Height) / 2;
var pt = new Point(b.X + checkPad, b.Y + checkPad);
Rectangle rect = new Rectangle(pt, new Size(20, 20));
e.Graphics.DrawRectangle(Pens.Green, rect);//This is for Checkbox rectangle
//This is for drawing string text
using (SolidBrush brush = new SolidBrush(ForeColor))
e.Graphics.DrawString(this.Items[e.Index].ToString(), Font, brush, pt.X + 27f, pt.Y);
if (state == CheckBoxState.CheckedNormal)
{
using (SolidBrush brush = new SolidBrush(ForeColor))
using (Font wing = new Font("Wingdings", 17f, FontStyle.Bold))
e.Graphics.DrawString("ü", wing, brush, pt.X-4, pt.Y-1); //This is For tick mark
}
}
}
Hope this will serve the purpose.

How to change the background color of unused space tab in C# winforms?

Ex
|Tab1|Tab2|Tab3| { }
| |
| |
| |
| |
|_____________________|
I am able to change the backcolor and forecolor of Tab.. but I want to change the color of that { } -- > Empty space is this possible to do that. .. It shows default winforms color..help me in dis..
private void Form1_Load(object sender, EventArgs e)
{
}
private void tabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
Font fntTab;
Brush bshBack;
Brush bshFore;
if ( e.Index == this.tabControl1.SelectedIndex)
{
fntTab = new Font(e.Font, FontStyle.Bold);
bshBack = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, SystemColors.Control, SystemColors.Control, System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal);
bshFore = Brushes.Black;
//bshBack = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, Color.LightSkyBlue , Color.LightGreen, System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal);
//bshFore = Brushes.Blue;
}
else
{
fntTab = e.Font;
bshBack = new SolidBrush(Color.Red);
bshFore = new SolidBrush(Color.Aqua);
//bshBack = new SolidBrush(Color.White);
//bshFore = new SolidBrush(Color.Black);
}
string tabName = this.tabControl1.TabPages[e.Index].Text;
StringFormat sftTab = new StringFormat();
e.Graphics.FillRectangle(bshBack, e.Bounds);
Rectangle recTab = e.Bounds;
recTab = new Rectangle( recTab.X, recTab.Y + 4, recTab.Width, recTab.Height - 4);
e.Graphics.DrawString(tabName, fntTab, bshFore, recTab, sftTab);
}
Try adding the following code to your DrawItem event handler. Don't forget to set the DrawMode to "OwnerdrawFixed".
You might have to tweak it a bit to cover some margins which aren't painted.
private void tabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
SolidBrush fillbrush= new SolidBrush(Color.Red);
//draw rectangle behind the tabs
Rectangle lasttabrect = tabControl1.GetTabRect(tabControl1.TabPages.Count - 1);
Rectangle background = new Rectangle();
background.Location = new Point(lasttabrect.Right, 0);
//pad the rectangle to cover the 1 pixel line between the top of the tabpage and the start of the tabs
background.Size = new Size(tabControl1.Right - background.Left, lasttabrect.Height+1);
e.Graphics.FillRectangle(fillBrush, background);
}
'This answer is much better than prior one. But the tabCtrl is not defined. It has to be tabControl1 control.
I think the only way to give that space a color is to override the OnPaintBackground method of the window, so just paste this on your form (window)
you must also change the Appearance Property to "Normal"
private void Form1_Load(object sender, EventArgs e)
{
}
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
Rectangle lasttabrect = tabControl1.GetTabRect(tabControl1.TabPages.Count - 1);
RectangleF emptyspacerect = new RectangleF(
lasttabrect.X + lasttabrect.Width + tabControl1.Left,
tabControl1.Top + lasttabrect.Y,
tabControl1.Width - (lasttabrect.X + lasttabrect.Width),
lasttabrect.Height);
Brush b = Brushes.BlueViolet; // the color you want
e.Graphics.FillRectangle(b, emptyspacerect );
}
for me it's working perfectly
you can also create a custom tabcontrol as you did
public class mytab : TabControl
{
public mytab()
: base()
{
this.DrawMode = TabDrawMode.OwnerDrawFixed;
this.DrawItem += new DrawItemEventHandler(tabControl1_DrawItem);
}
private void tabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
Font fntTab;
Brush bshBack;
Brush bshFore;
if (e.Index == this.SelectedIndex)
{
fntTab = new Font(e.Font, FontStyle.Bold);
bshBack = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, SystemColors.Control, SystemColors.Control, System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal);
bshFore = Brushes.Black;
//bshBack = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, Color.LightSkyBlue , Color.LightGreen, System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal);
//bshFore = Brushes.Blue;
}
else
{
fntTab = e.Font;
bshBack = new SolidBrush(Color.Red);
bshFore = new SolidBrush(Color.Aqua);
//bshBack = new SolidBrush(Color.White);
//bshFore = new SolidBrush(Color.Black);
}
string tabName = this.TabPages[e.Index].Text;
StringFormat sftTab = new StringFormat();
e.Graphics.FillRectangle(bshBack, e.Bounds);
Rectangle recTab = e.Bounds;
recTab = new Rectangle(recTab.X, recTab.Y + 4, recTab.Width, recTab.Height - 4);
e.Graphics.DrawString(tabName, fntTab, bshFore, recTab, sftTab);
Rectangle r = this.GetTabRect(this.TabPages.Count - 1);
RectangleF tf =
new RectangleF(r.X + r.Width,
r.Y-5, this.Width - (r.X + r.Width)+5, r.Height+5);
Brush b = Brushes.BlueViolet;
e.Graphics.FillRectangle(b, tf);
}
}

Set TabPage Header Color

Greetings,
I have a tab control and I want to have 1 of the tabs have it's text color changed on a event.
I've found answers like C# - TabPage Color event
and C# Winform: How to set the Base Color of a TabControl (not the tabpage)
but using these sets all colors instead of one.
So I was hoping there is a way to implement this with the tab I wish to change as a method instead of a event?
Something like:
public void SetTabPageHeaderColor(TabPage page, Color color)
{
//Text Here
}
If you want to color the tabs, try the following code:
this.tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
this.tabControl1.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.tabControl1_DrawItem);
private Dictionary<TabPage, Color> TabColors = new Dictionary<TabPage, Color>();
private void SetTabHeader(TabPage page, Color color)
{
TabColors[page] = color;
tabControl1.Invalidate();
}
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
//e.DrawBackground();
using (Brush br = new SolidBrush (TabColors[tabControl1.TabPages[e.Index]]))
{
e.Graphics.FillRectangle(br, e.Bounds);
SizeF sz = e.Graphics.MeasureString(tabControl1.TabPages[e.Index].Text, e.Font);
e.Graphics.DrawString(tabControl1.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();
}
}
For WinForms users reading this - This ONLY works if you set your tab control's DrawMode to OwnerDrawFixed - the DrawItem event never fires if it's set to Normal.
To add to Fun Mun Pieng's answer which works beautifully on Horizontal tabs, if you were to use Vertical tabs (like I was) then you would need something like this:
private void tabControl2_DrawItem(object sender, DrawItemEventArgs e)
{
using (Brush br = new SolidBrush(tabColorDictionary[tabControl2.TabPages[e.Index]]))
{
// Color the Tab Header
e.Graphics.FillRectangle(br, e.Bounds);
// swap our height and width dimensions
var rotatedRectangle = new Rectangle(0, 0, e.Bounds.Height, e.Bounds.Width);
// Rotate
e.Graphics.ResetTransform();
e.Graphics.RotateTransform(-90);
// Translate to move the rectangle to the correct position.
e.Graphics.TranslateTransform(e.Bounds.Left, e.Bounds.Bottom, System.Drawing.Drawing2D.MatrixOrder.Append);
// Format String
var drawFormat = new System.Drawing.StringFormat();
drawFormat.Alignment = StringAlignment.Center;
drawFormat.LineAlignment = StringAlignment.Center;
// Draw Header Text
e.Graphics.DrawString(tabControl2.TabPages[e.Index].Text, e.Font, Brushes.Black, rotatedRectangle, drawFormat);
}
}
I will echo the point that ROJO1969 made, if this is in WinForms - then you must set DrawMode to OwnerDrawFixed.
Special thanks goes out to this wonderful blog entry which described how to do a rotation of text on a form.
private void MainForm_Load(object sender, EventArgs e)
{
...
this.tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
this.tabControl1.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.tabControl1_DrawItem);
...
}
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
try
{
// Draw the background of the control for each item.
//e.DrawBackground();
if (e.Index == this.tabControl1.SelectedIndex)
{
Brush _BackBrush = new SolidBrush(tabControl1.TabPages[e.Index].BackColor);
Rectangle rect = e.Bounds;
e.Graphics.FillRectangle(_BackBrush, (rect.X) + 4, rect.Y, (rect.Width) - 4, rect.Height);
SizeF sz = e.Graphics.MeasureString(tabControl1.TabPages[e.Index].Text, e.Font);
e.Graphics.DrawString(tabControl1.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);
}
else
{
// 파스톤계 배경색 없앨려면 FromArgb 를 없애면 된다.
Brush _BackBrush = new SolidBrush(Color.FromArgb(50, tabControl1.TabPages[e.Index].BackColor));
Rectangle rect = e.Bounds;
e.Graphics.FillRectangle(_BackBrush, rect.X, (rect.Y)-0, rect.Width, (rect.Height)+6);
SizeF sz = e.Graphics.MeasureString(tabControl1.TabPages[e.Index].Text, e.Font);
e.Graphics.DrawString(tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black,
e.Bounds.Left + (e.Bounds.Width - sz.Width) / 2,
e.Bounds.Top + 5);
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message, "Error Occured", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
If any one need to put color for tab header use try this. My tab name tabControl
tabControl.DrawMode = TabDrawMode.OwnerDrawFixed;
tabControl.DrawItem += tabControl1_DrawItem;
declear this under main class
then,
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
Color tabTextColor = Color.FromArgb(0x000001);
var color = Color.FromArgb(tabTextColor.R, tabTextColor.G, tabTextColor.B);
TextRenderer.DrawText(e.Graphics, tabControl.TabPages[e.Index].Text, e.Font, e.Bounds, color);
}
declare this function it will generate output
final out

Graphics DrawString to Exactly Place Text on a System.Label

I have overridden the OnPaint method of my Label control in VS2008:
void Label_OnPaint(object sender, PaintEventArgs e) {
base.OnPaint(e);
dim lbl = sender as Label;
if (lbl != null) {
string Text = lbl.Text;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (myShowShadow) { // draw the shadow first!
e.Graphics.DrawString(Text, lbl.Font, new SolidBrush(myShadowColor), myShadowOffset, StringFormat.GenericDefault);
}
e.Graphics.DrawString(Text, lbl.Font, new SolidBrush(lbl.ForeColor), 0, 0, StringFormat.GenericDefault);
}
}
This works, but I really want to find out how to center the text both vertically and horizontally. I've heard of the MeasureString() method, but my "Text" complicates matters because it could include page breaks.
Could someone guide me with how to do this?
Alternatively you can create your own StringFormat object and pass it in using an overload of DrawString that supports a RectangleF:
StringFormat formatter = new StringFormat();
formatter.LineAlignment = StringAlignment.Center;
formatter.Alignment = StringAlignment.Center;
RectangleF rectangle = new RectangleF(0, 0, lbl.Width, lbl.Height);
e.Graphics.DrawString(Text, lbl.Font, new SolidBrush(lbl.ForeColor), rectangle, formatter);
You can call TextRenderer.DrawText with the HorizontalCenter and VerticalCenter flags.
Here is the code i'm using at the moment,
SizeF size;
string text = "Text goes here";
size = e.Graphics.MeasureString(text, font);
x = (lineWidth / 2) - (size.Width / 2);
y = top;
e.Graphics.DrawString(text, font, Brushes.Black, x, y);
I just wanted to add (a year later) a tool I created because StringAlignment turned out to be not very dependable. It turns out to be very similar to Neo's version.
The code below does an excellent job of centering the text both vertically and horizontally. Also, I wrote it with various overloads so that different options could be supplied to make this control behave exactly like I want.
Here are my overloads:
private static void DrawCenter(Label label, Graphics graphics) {
DrawCenter(label.Text, label, label.Location, label.ForeColor, graphics);
}
private void DrawCenter(string text, Label label, Graphics graphics) {
DrawCenter(text, label, label.Location, label.ForeColor, graphics);
}
private static void DrawCenter(string text, Label label, Point location, Graphics graphics) {
DrawCenter(text, label, location, label.ForeColor, graphics);
}
private static void DrawCenter(string text, Label label, Point location, Color fontColor, Graphics graphics) {
Rectangle rect = new Rectangle(location, label.Size);
SizeF lSize = graphics.MeasureString(text, label.Font, rect.Width);
PointF lPoint = new PointF(rect.X + (rect.Width - lSize.Width) / 2, rect.Y + (rect.Height - lSize.Height) / 2);
graphics.DrawString(text, label.Font, new SolidBrush(fontColor), lPoint);
}
To use these for the Label's OnPaint event, simply modify my original code in the question to following:
private void Label_OnPaint(object sender, PaintEventArgs e) {
base.OnPaint(e);
Label lbl = sender as Label;
if (lbl != null) {
string txt = lbl.Text;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (myShowShadow) { // draw the shadow first!
Point offset = new Point(lbl.Location.X - 1, lbl.Location.Y - 1)
DrawCenter(txt, lbl, offset, myShadowColor, e.Graphics);
}
DrawCenter(lbl, e.Graphics);
}
}
For a Print_Document event, I have a version that will also print a box around the label if there is already a box around it in the designer:
private static void DrawCenter(string text, Label label, Point location, Color fontColor, Graphics graphics) {
Rectangle rect = new Rectangle(location, label.Size);
SizeF lSize = graphics.MeasureString(text, label.Font, rect.Width);
PointF lPoint = new PointF((rect.Width - lSize.Width) / 2, (rect.Height - lSize.Height) / 2);
graphics.DrawString(text, label.Font, new SolidBrush(fontColor), lPoint);
if (label.BorderStyle != BorderStyle.None) {
using (Pen p = new Pen(Color.Black)) {
graphics.DrawRectangle(p, rect);
}
}
}
If you find this at all useful, give me a +1.
~Joe

Categories

Resources