This question already has answers here:
Close button for TabPages of Right To Left TabControl c#
(2 answers)
Closed 6 years ago.
I wanted to add X button for each tab.
The drawMode is OwnerDrawFixed. it works fine if it left to right.
Once I allow RightToLeftLayout = true and RightToLeft = true, it does not look good because that he still adds the string from left to right, while that tab add from right to left.
How do I make it that string will also be right to left?
private void addCloseButton(object sender, DrawItemEventArgs e)
{
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - 15 , e.Bounds.Top +4 );
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left+4, e.Bounds.Top+4);
e.DrawFocusRectangle();
}
private void actionClose(object sender, MouseEventArgs e)
{
//Looping through the controls.
for (int i = 0; i < this.tabControl1.TabPages.Count; i++)
{
Rectangle r = tabControl1.GetTabRect(i);
//Getting the position of the "x" mark.
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 10);
if (closeButton.Contains(e.Location))
{
if (MessageBox.Show("?האם אתה רוצה לסגור טאב זה", "אישור", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
this.tabControl1.TabPages.RemoveAt(i);
break;
}
}
}
}
Pass StringFormat with FormatFlags flag set to StringFormatFlags.DirectionRightToLeft to the DrawString():
StringFormat drawFormat = new StringFormat(StringFormatFlags.DirectionRightToLeft);
var bounds = new RectangleF(.. set actual bound rectangle for text... )
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, bounds, drawFormat);
check here http://www.microsoft.com/middleeast/msdn/visualstudio2005.aspx you should use textrenderer instead of drawstring
Related
I have one TabControl with multiple pages. Each page has a close mark "X" on tab. I want to the "X" color changed to white when mouse cursor touches (within an area) the "X", so that reminding us that cursor within that area. The codes are as following:
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("X", e.Font, Brushes.Red, e.Bounds.Right - 20, e.Bounds.Top + 4);
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + 24, e.Bounds.Top + 4);
e.Graphics.DrawImage(Properties.Resources.Div1, new Point(e.Bounds.Left, e.Bounds.Top + 2));
e.DrawFocusRectangle();
}
private void tabControl1_MouseMove(object sender, MouseEventArgs e)
{
Rectangle r = tabControl1.GetTabRect(tabControl1.SelectedIndex);
//Getting the position of the "x" mark.
Rectangle closeButton = new Rectangle(r.Right - 20, r.Top + 4, 20, 10);
if (closeButton.Contains(e.Location))
{
//how to write here to change tab caption color or close mark "X" color
}
}
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));
}
I am trying to add close button or 'X' on tabpage panel in tabcontrol and I have successfully done this by reading this stackoverflow question.
The problem is the tabbed page title and X sign is merged together. I discovered that the tabpage title panel is not resizing according to title text.
Here is the code:
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("X", e.Font, Brushes.Black, e.Bounds.Right + 15, e.Bounds.Top + 4);
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left+5, e.Bounds.Top + 4);
e.DrawFocusRectangle();
The result which comes is here I have changed e.bounds.right value but still it's not working.
To fix merged tabPage.Text with additionally drawed "X" just add:
tabControl.Padding = new System.Drawing.Point(21, 3);
It will add some extra space to the end of every tabPage
Make sure you set the DrawMode property of the Tab Control to OwnerDrawFixed. This property is decides whether system or developer painting the captions.
Here is code example that uses TabSizeMode = Fixed is setting the tab size:
public partial class Form1 : Form
{
const int LEADING_SPACE = 12;
const int CLOSE_SPACE = 15;
const int CLOSE_AREA = 15;
public Form1()
{
InitializeComponent();
}
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - CLOSE_AREA, e.Bounds.Top + 4);
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + LEADING_SPACE, e.Bounds.Top + 4);
e.DrawFocusRectangle();
}
private void Form1_Load(object sender, EventArgs e)
{
// get the inital length
int tabLength = tabControl1.ItemSize.Width;
// measure the text in each tab and make adjustment to the size
for (int i = 0; i < this.tabControl1.TabPages.Count; i++)
{
TabPage currentPage = tabControl1.TabPages[i];
int currentTabLength = TextRenderer.MeasureText(currentPage.Text, tabControl1.Font).Width;
// adjust the length for what text is written
currentTabLength += LEADING_SPACE + CLOSE_SPACE + CLOSE_AREA;
if (currentTabLength > tabLength)
{
tabLength = currentTabLength;
}
}
// create the new size
Size newTabSize = new Size(tabLength, tabControl1.ItemSize.Height);
tabControl1.ItemSize = newTabSize;
}
}
Screen shot of sample code from above:
I have a project in which you can add and remove tabs (like a web browser). So far I have this:
//Button to add a new tab page
private void cb_addPage_Click(object sender, EventArgs e)
{
string title = "TabPage " + (tabControl1.TabCount + 1).ToString() + " ";
TabPage myTabPage = new TabPage(title);
tabControl1.TabPages.Add(myTabPage);
tabControl1.SelectedTab = myTabPage;
}
//Form1_Load
private void Form1_Load(object sender, EventArgs e)
{
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
cb_addPage.Top = tabControl1.Top;
cb_addPage.Left = tabControl1.Right - cb_addPage.Width;
foreach (TabPage tp in tabControl1.TabPages) tp.Text += " ";
}
Rectangle closeX = Rectangle.Empty;
//Sets background and places the X button on each tab
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Size xSize = new Size(15, 15);
TabPage tp = tabControl1.TabPages[e.Index];
e.DrawBackground();
using (SolidBrush brush = new SolidBrush(e.ForeColor))
e.Graphics.DrawString(tp.Text + " ", e.Font, brush,
e.Bounds.X + 3, e.Bounds.Y + 4);
if (e.State == DrawItemState.Selected)
{
closeX = new Rectangle(e.Bounds.Right - xSize.Width - 3,
e.Bounds.Top + 5, xSize.Width, xSize.Height);
e.Graphics.DrawImage(imageList1.Images[0], closeX,
new Rectangle(0,0,16,16), GraphicsUnit.Pixel );
}
}
//Removes current tab (from X button)
private void tabControl1_MouseClick(object sender, MouseEventArgs e)
{
if (closeX.Contains(e.Location))
tabControl1.TabPages.Remove(tabControl1.SelectedTab);
}
So all this does is let you add tabs with a button and on each individual tab there is an X button to delete the tab.
I have used Graphics.DrawImage to display the custom X button (that are in an imageList). However how will I go about making custom tabs using Graphics.DrawImage.
To sum up I want tabs, but I want them to be custom images that I have made so it looks better. - Thanks
Your question is not very clear. Probably you want to display a different text on each tab. You can use the TextRenderer to do so:
const TextFormatFlags flags = TextFormatFlags.PreserveGraphicsClipping |
TextFormatFlags.VerticalCenter;
TextRenderer.DrawText(e.Graphics, tp.Text, tp.Font, e.Bounds, tp.ForeColor, flags);
Either prepend some spaces to the text in order to leave space for the X or define new coordiantes for the text
const int XCrossWidth = 20;
Rectangle textRect = new Rectangle(e.Bounds.Left + XCrossWidth, e.Bounds.Top,
e.Width - XCrossWidth, e.Height);
and substitue this for e.Bounds in TextRenderer.DrawText(...).
UPDATE
So you want to display custom images on your tabs. I assume that you have placed these images in the imageList1. How do you know which of them to display on which TabPage?
You could create your own tab page class and use this one instead of TabPage.
public TabPageEx : TabPage
{
public int ImageIndex { get; set }
}
Now set the property to the appropriate image index.
TabPageEx myTabPage = new TabPageEx(title);
myTabPage.ImageIndex = 3; // As an example.
tabControl1.TabPages.Add(myTabPage);
Then you can draw the image with
TabPageEx tp = (TabPageEx)tabControl1.TabPages[e.Index];
...
Rectangle imageRect = new Rectangle(e.Bounds.Left + 20, 0, 16, 16);
e.Graphics.DrawImage(imageList1.Images[tp.ImageIndex], imageRect);
If you want to display Images in addition to the text like a webbrowsers favicon you can use this modified code:
private void tabControl3_DrawItem(object sender, DrawItemEventArgs e)
{
Size xSize = new Size(16,16);
Point imgLoc = new Point(e.Bounds.X + 4, e.Bounds.Y + 4);
TabPage tp = tabControl3.TabPages[e.Index];
e.DrawBackground();
e.Graphics.DrawImage(imageList1.Images[tp.ImageIndex], new Rectangle(imgLoc, xSize),
new Rectangle(Point.Empty, xSize), GraphicsUnit.Pixel);
using (SolidBrush brush = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(tp.Text + " ", e.Font, brush,
e.Bounds.X + 23, e.Bounds.Y + 4);
if (e.State == DrawItemState.Selected)
{
closeX = new Rectangle(e.Bounds.Right - xSize.Width - 3,
e.Bounds.Top + 5, xSize.Width, xSize.Height);
e.Graphics.DrawImage(imageList1.Images[0], closeX,
new Rectangle(Point.Empty, xSize), GraphicsUnit.Pixel);
}
}
}
You need to make sure that:
You have those images you want to show in each tab in your imagelist.
and you know the index of ech one.
Youi must set it when you create the page but you can always change it later.
It is a good idea to have a default icon at index 0 and to set the imageindex to 0 for those you don't know the right index.
Usually you would also have to make your Tab control point to the Imagelist. But since we are drawing it all by ourselves, this is not important.
You can use the more complex format of DrawString, that is used for drawing the close button. Here you don't just use a point to determine the location where to draw; instead this format uses two rectangles to determine the source and the target. This effectively leads to th option of scaling the image to a new size.
But you'll get the best quality if your Images have the right size to begin with. Please note that the text of each TabPage determines the width of the tab; to make it higher you need to chose a larger Fontsize.
is there anyone can tell me how to add close button in each tab in using tabControl in C#?
i plan to use button pic for replacing [x] in my tab..
thank you
Without deriving a class, here is a neat snippet:
http://www.dotnetthoughts.net/implementing-close-button-in-tab-pages/
Set the DrawMode property of the Tab Control to OwnerDrawFixed. This property decides whether system or developer can paint the captions.
Add the code in the DrawItem event of the Tab Control – This event will be invoked for painting each Tab Page.
//This code will render a "x" mark at the end of the Tab caption.
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - 15, e.Bounds.Top + 4);
e.Graphics.DrawString(this.tabControl1.TabPages[e.Index].Text, e.Font, Brushes.Black, e.Bounds.Left + 12, e.Bounds.Top + 4);
e.DrawFocusRectangle();
Now for close button action, we need to add the following code to the MouseDown event of the Tab Control.
//Looping through the controls.
for (int i = 0; i < this.tabControl1.TabPages.Count; i++)
{
Rectangle r = tabControl1.GetTabRect(i);
//Getting the position of the "x" mark.
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 9, 7);
if (closeButton.Contains(e.Location))
{
if (MessageBox.Show("Would you like to Close this Tab?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
this.tabControl1.TabPages.RemoveAt(i);
break;
}
}
}
Adding to the other answers... why iterating through all the tabs on mouse click event when we can just detect the current tab with .SelectedIndex and .SelectedTab ?
Like so:
private void tabControl1_MouseDown(object sender, MouseEventArgs e)
{
Rectangle r = tabControl1.GetTabRect(this.tabControl1.SelectedIndex);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 9, 7);
if (closeButton.Contains(e.Location))
{
this.tabControl1.TabPages.Remove(this.tabControl1.SelectedTab);
}
}
What seems to happen is, the moment you click on a tabPage for closing it, it also gets selected, thus allowing the close button to close the right tabPage.
To me it works but please take this with extra care though as I am not completely sure of possible drawbacks (my initial sentence wasn't a completely rhetorical question since I'm kinda new to .Net...).
Try this code:
private Point _imageLocation = new Point(13, 5);
private Point _imgHitArea = new Point(13, 2);
private void Form1_Load(object sender, EventArgs e)
{
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
tabControl1.DrawItem += tabControl1_DrawItem;
CloseImage = WindowsFormsApplication3.Properties.Resources.closeR;
tabControl1.Padding = new Point(10, 3);
}
private void TabControl1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
try
{
Image img = new Bitmap(CloseImage);
Rectangle r = e.Bounds;
r = this.tabControl1.GetTabRect(e.Index);
r.Offset(2, 2);
Brush TitleBrush = new SolidBrush(Color.Black);
Font f = this.Font;
string title = this.tabControl1.TabPages[e.Index].Text;
e.Graphics.DrawString(title, f, TitleBrush, new PointF(r.X, r.Y));
if (tabControl1.SelectedIndex >= 1)
{
e.Graphics.DrawImage(img, new Point(r.X + (this.tabControl1.GetTabRect(e.Index).Width - _imageLocation.X), _imageLocation.Y));
}
}
catch (Exception) { }
}
private void TabControl1_Mouse_Click(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
TabControl tc = (TabControl)sender;
Point p = e.Location;
int _tabWidth = 0;
_tabWidth = this.tabControl1.GetTabRect(tc.SelectedIndex).Width - (_imgHitArea.X);
Rectangle r = this.tabControl1.GetTabRect(tc.SelectedIndex);
r.Offset(_tabWidth, _imgHitArea.Y);
r.Width = 16;
r.Height = 16;
if (tabControl1.SelectedIndex >= 1)
{
if (r.Contains(p))
{
TabPage TabP = (TabPage)tc.TabPages[tc.SelectedIndex];
tc.TabPages.Remove(TabP);
}
}
}
Look at this code snippet
I ran into this same issue, however, I also wanted to have an image in front of the caption on the tab. Here is the code that will give you an image in front, a caption and a close button. Also, this code includes the ability to use the middle mouse click on the tab to close it.
First under the TabControl's properties change DrawMode from Normal to OwnerDrawFixed. Next, you will need to tweak the X dimension for the TabControl's padding also found under properties.
In this example, my TabControl is called "TabManager" so rename that to the name of your control.
Go under the envents (the little lightning bolt near the top of the properties box) and double click in the white box next to "DrawItem", this will create a trigger. In that method use this code with your adjustments.
private void TabManager_DrawItem(object sender, DrawItemEventArgs e)
{
TabPage thisTab = TabManager.TabPages[e.Index];
string tabTitle = thisTab.Text;
Image icon = imageList1.Images[thisTab.ImageIndex];
//Draw Close button
Point closeLoc = new Point(15, 5);
e.Graphics.DrawRectangle(Pens.Black, e.Bounds.Right - closeLoc.X, e.Bounds.Top + closeLoc.Y, 10, 12);
e.Graphics.FillRectangle(Brushes.LightBlue, e.Bounds.Right - closeLoc.X, e.Bounds.Top + closeLoc.Y, 10, 12);
e.Graphics.DrawString("x", e.Font, Brushes.Black, e.Bounds.Right - (closeLoc.X), e.Bounds.Top + closeLoc.Y-2);
// Draw String of Caption
e.Graphics.DrawString(tabTitle, e.Font, Brushes.Black, e.Bounds.Left + 28, e.Bounds.Top + 4);
// Add Icon to Front
e.Graphics.DrawImage(icon, e.Bounds.Left + 6, e.Bounds.Top + 3);
e.DrawFocusRectangle();
}
Next go back to the events and double click on the white box next to MouseDown. Then use this code:
private void TabManager_MouseDown(object sender, MouseEventArgs e)
{
Point closeLoc = new Point(15, 5);
Rectangle r = TabManager.GetTabRect(TabManager.SelectedIndex);
Rectangle closeButton = new Rectangle(r.Right - closeLoc.X, r.Top + closeLoc.Y, 10, 12);
if (closeButton.Contains(e.Location))
{
TabManager.TabPages.Remove(TabManager.SelectedTab);
return; // Don't keep running logic in method
}
for (int i = 0; i < TabManager.TabCount; i++)
{
r = TabManager.GetTabRect(i);
if (r.Contains(e.Location) && e.Button == MouseButtons.Middle)
{
TabManager.TabPages.RemoveAt(i);
}
}
}