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;
}
}
Related
I'm drawing a custom toolstrip using ToolStripProfessionalRender and editing the OnRenderItemText event as follows:
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
e.Item.ForeColor = Clr.White;
e.Item.TextAlign = ContentAlignment.MiddleLeft;
e.Item.Alignment = ToolStripItemAlignment.Left;
base.OnRenderItemText(e);
if (e.Item.GetType() == typeof(ToolStripDropDownButton))
{
ToolStripDropDownButton tsmi = (ToolStripDropDownButton)e.Item;
if (tsmi.HasDropDownItems && tsmi.OwnerItem == null)
{
Rectangle bounds = tsmi.Bounds;
bounds.X = bounds.Right - 25;
bounds.Width = 25;
bounds.Y = 10;
// Draw the corner
Graphics G = e.Graphics;
SolidBrush brushw = new SolidBrush(Color.FromArgb(70,70,70));
Point[] points =
{
new Point(bounds.Right - 3, bounds.Height - 11), // point top right
new Point(bounds.Right - 3, bounds.Bottom - 14), // point bottom right
new Point(bounds.Right - 10, bounds.Bottom - 14) // point bottom left
};
G.FillPolygon(brushw, points);
}
}
}
and basically the output i'm trying to obtain is the following:
So drawing a little triangle on the bottom right corner when i got a ToolStripDropDownButton. The problem is that the little triangle is drawn only first item.
To end up the question i draw this toolstrip dynamically using a function that adds a dropdownbutton at each call.
ToolStripDropDownButton m_Item = new ToolStripDropDownButton(text, image);
m_Item.ImageAlign = ContentAlignment.MiddleCenter;
m_Item.ImageScaling = ToolStripItemImageScaling.None;
m_Item.Name = name;
m_Item.ForeColor = Color.White;
m_Item.BackColor = Color.FromArgb(95, 95, 95);
m_Item.Padding = new Padding(5);
m_Item.ShowDropDownArrow = false;
m_Item.Paint += new PaintEventHandler(this.PaintButtonBorder);
if (tabPage != null)
m_Item.Click += (sender, e) => AddClickTab(sender, e, tabPage);
((ToolStripDropDownMenu)m_Item.DropDown).ShowImageMargin = false;
((ToolStripDropDownMenu)m_Item.DropDown).ShowCheckMargin = false;
((ToolStripDropDownMenu)m_Item.DropDown).Cursor = Cursors.Hand;
toolStrip1.Items.Add(m_Item);
if (SubItems != null)
{
for(int i = 0; i < SubItems.Length; i++)
{
object[] subitem = (object[])SubItems[i];
FnAddToolStripMenuItem(
subitem[0].ToString(),
subitem[1].ToString(),
(Bitmap)subitem[2],
m_Item,
(TabPage)subitem[3]
);
}
}
Am i missing some "new" maybe?
Override the OnRenderItemText method only to draw the text part as it says, and/or to set the default properties used when rendering the text. To change the look and the shape of the arrows of the dropdown items, override the OnRenderArrow method.
Example
using System.Drawing;
using System.Drawing.Drawing2D;
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
// Optional: to be the default color of the arrows.
e.ArrowColor = Color.FromArgb(70, 70, 70);
if (e.Item is ToolStripDropDownButton item && item.OwnerItem == null)
{
var g = e.Graphics;
var r = new Rectangle(item.Bounds.Width - 10, item.Bounds.Height - 10, 8, 8);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.Half;
using (var br = new SolidBrush(e.ArrowColor))
g.FillPolygon(br, new[]
{
new Point(r.Left, r.Bottom),
new Point(r.Right, r.Top),
new Point(r.Right, r.Bottom)
});
g.SmoothingMode = SmoothingMode.None;
g.PixelOffsetMode = PixelOffsetMode.Default;
}
else
base.OnRenderArrow(e);
}
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
e.Item.ForeColor = Color.White;
e.Item.TextAlign = ContentAlignment.MiddleLeft;
e.Item.Alignment = ToolStripItemAlignment.Left;
base.OnRenderItemText(e);
}
Make sure to enable the ShowDropDownArrow property of the dropdown buttons. So comment this m_Item.ShowDropDownArrow = false;.
If you are also interested to change the color according to the current state of the dropdown button (Selected, Pressed), then you can do for example:
using (var br = new SolidBrush(item.Selected
? Color.FromArgb(150, 150, 150) : item.Pressed
? Color.FromArgb(100, 100, 100) :
Color.FromArgb(70, 70, 70)))
//...
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.
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);
}
}
I have a png image that have transparent parts, how to set this png image like background image for my WinForms form and not lose transparency? i Use C#. Thanks!
Here I have written a code for painting the form. You can change the color and transparency according to our requirement. I used colors as background of the form. You can change it as picture as per your requirement. It is a sample code.
First you need to create a static class containing these functions
public enum FormType
{
MDI,
Child
}
public static void PaintFrom(Form frm, PaintEventArgs e, FormType formType)
{
if (formType == FormType.MDI)
{
Graphics mGraphics = e.Graphics;
Pen pen1 = new Pen(Color.FromArgb(96, 155, 173), 1);
Rectangle Area1 = new Rectangle(0, 0, frm.Width - 1, frm.Height - 1);
LinearGradientBrush LGB = new LinearGradientBrush(Area1, Color.FromArgb(96, 155, 173), Color.FromArgb(245, 251, 251), LinearGradientMode.Vertical);
mGraphics.FillRectangle(LGB, Area1);
mGraphics.DrawRectangle(pen1, Area1);
PictureBox picBox = new PictureBox();
Color backColor = Color.Transparent;
Bitmap bm = new Bitmap(ImagePath + "title_bar.png");
//frm.Controls.Add(picBox);
Point pt = new Point(0, 0);
picBox.Location = pt;
picBox.Image = bm;
picBox.Width = frm.Width - 1;
picBox.Height = 24;//frm.Height - 1;
picBox.BackColor = backColor;
picBox.BackgroundImageLayout = ImageLayout.Stretch;
PictureBox closeBox = new PictureBox();
//frm.Controls.Add(closeBox);
bm = new Bitmap(ImagePath + "close.gif");
pt = new Point(frm.Width - (bm.Width), -1);
closeBox.Location = pt;
closeBox.Image = bm;
closeBox.Width = bm.Width + 1;
closeBox.Height = bm.Width + 1;
closeBox.BackColor = backColor;
closeBox.BackgroundImageLayout = ImageLayout.Stretch;
PictureBox minBox = new PictureBox();
//frm.Controls.Add(closeBox);
bm = new Bitmap(ImagePath + "close.gif");
pt = new Point(frm.Width - (2*(bm.Width))-1, bm.Width);
minBox.Location = pt;
minBox.Image = bm;
minBox.Width = bm.Width + 1;
minBox.Height = bm.Width + 1;
minBox.BackColor = backColor;
minBox.BackgroundImageLayout = ImageLayout.Stretch;
frm.Controls.Add(picBox);
picBox.Controls.Add(closeBox);
picBox.Controls.Add(minBox);
minBox.Click+=new EventHandler(minBox_Click);
closeBox.Click += new EventHandler(closeBox_Click);
}
else
{
PaintForm(frm, e);
}
}
public static void PaintForm(Form frm, PaintEventArgs e)
{
Graphics mGraphics = e.Graphics;
Pen pen1 = new Pen(Color.FromArgb(96, 155, 173), 1);
Rectangle Area1 = new Rectangle(0, 0, frm.Width - 1, frm.Height - 1);
LinearGradientBrush LGB = new LinearGradientBrush(Area1, Color.FromArgb(96, 155, 173), Color.FromArgb(245, 251, 251), LinearGradientMode.Vertical);
mGraphics.FillRectangle(LGB, Area1);
mGraphics.DrawRectangle(pen1, Area1);
PictureBox picBox=new PictureBox();
Color backColor = Color.Transparent;
Bitmap bm=new Bitmap(ImagePath+"title_bar.png");
//frm.Controls.Add(picBox);
Point pt=new Point(0,0);
picBox.Location = pt;
picBox.Image = bm;
picBox.Width = frm.Width - 1;
picBox.Height = 24;//frm.Height - 1;
picBox.BackColor = backColor;
picBox.BackgroundImageLayout = ImageLayout.Stretch;
PictureBox closeBox = new PictureBox();
//frm.Controls.Add(closeBox);
bm = new Bitmap(ImagePath + "close.gif");
pt = new Point(frm.Width - (bm.Width), -1);
closeBox.Location = pt;
closeBox.Image = bm;
closeBox.Width = bm.Width + 1;
closeBox.Height = bm.Width + 1;
closeBox.BackColor = backColor;
closeBox.BackgroundImageLayout = ImageLayout.Stretch;
foreach (Control ctr in frm.Controls)
{
if (ctr.HasChildren)
{
if (ctr is DataGridView)
{
DataGridView dtg = ctr as DataGridView;
DataGridViewCellStyle dtstyle=new DataGridViewCellStyle();
dtstyle.BackColor = Color.FromArgb(96, 155, 173);
dtg.ColumnHeadersDefaultCellStyle = dtstyle;
}
else if (ctr is TextBox)
{
}
else if (ctr is TabControl)
{
}
else
{
ctr.BackColor = backColor;
}
}
if (ctr is Label)
{
ctr.BackColor = backColor;
}
}
frm.Controls.Add(picBox);
picBox.Controls.Add(closeBox);
closeBox.Click+=new EventHandler(closeBox_Click);
}
static void closeBox_Click(object sender, EventArgs e)
{
PictureBox close = sender as PictureBox;
PictureBox pic = close.Parent as PictureBox;
Form fm = pic.Parent as Form;
fm.Close();
}
static void minBox_Click(object sender, EventArgs e)
{
PictureBox min = sender as PictureBox;
PictureBox pic = min.Parent as PictureBox;
Form fm = pic.Parent as Form;
fm.WindowState = FormWindowState.Minimized;
}
Then you need to call a Paint Event for the form and in this event you can paint the form like this
private void frmComplaints_Paint(object sender, PaintEventArgs e)
{
UI.Common.PaintForm(this, e);
}
I have used a static class UI.Common for this function and i used an image for titlebar. In your case you can use a png image for background. The ImagePath in the code is a constant variable where you can set the path for directory where the image is saved
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...
}
}