问题
I am trying to add a close button on the tab pages of TabControl and change the color of the close button from light gray to black when mouse hovers over it. However, the color never changes.
The DrawEventArgsCustom class is created to indicate that the mouse is hovering over the close button. When it's true, the statement to change the color is executed but color never changes.
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
try
{
Rectangle r = e.Bounds;
r = this.tabControl1.GetTabRect(e.Index);
r.Offset(2, 2);
Brush TitleBrush = new SolidBrush(Color.Black);
Brush CloseBrush = new SolidBrush(Color.Gray);
Brush CloseBrushSelected = 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 (e is DrawEventArgsCustom)
{
if (((DrawEventArgsCustom)e) != null && ((DrawEventArgsCustom)e).HoverTrue == true)
e.Graphics.DrawString("x", f, CloseBrushSelected, new PointF
(r.X + (this.tabControl1.GetTabRect(e.Index).Width - _imageLocation.X), _imageLocation.Y));
}
e.Graphics.DrawString("x", f, CloseBrush, new PointF
(r.X + (this.tabControl1.GetTabRect(e.Index).Width - _imageLocation.X), _imageLocation.Y));
}
catch (Exception ex)
{
}
}
private void tabControl1_MouseMove(object sender, MouseEventArgs e)
{
Rectangle mouseRect = new Rectangle(e.X, e.Y, 1, 1);
Graphics graphics = CreateGraphics();
for (int i = 0; i < tabControl1.TabCount; i++)
{
if (tabControl1.GetTabRect(i).IntersectsWith(mouseRect))
{
tabControl1_DrawItem(this, new DrawEventArgsCustom(hoverTrue: true, graphics, this.Font, mouseRect, i, DrawItemState.Focus));
}
}
}
class DrawEventArgsCustom : DrawItemEventArgs
{
public DrawEventArgsCustom(bool hoverTrue, Graphics graphics, Font font, Rectangle rect, int index, DrawItemState drawItemState)
: base(graphics, font, rect, index, drawItemState)
{
this.HoverTrue = hoverTrue;
this.Graph = graphics;
this.Fnt = font;
this.Rect = rect;
this.ind = index;
this.drawItemSt = drawItemState;
}
public bool HoverTrue { get; private set; }
public Graphics Graph { get; private set; }
public Font Fnt { get; private set; }
public Rectangle Rect { get; private set; }
public int ind { get; private set; }
public DrawItemState drawItemSt { get; private set; }
}
回答1:
No need to create new Graphics
objects like that, you should do all the drawings in the DrawItem
event. For example in this context:
//a class level variable.
private int HoverIndex = -1;
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
var g = e.Graphics;
var tp = tabControl1.TabPages[e.Index];
var rt = e.Bounds;
var rx = new Rectangle(rt.Right - 20, (rt.Y + (rt.Height - 12)) / 2 + 1, 12, 12);
if ((e.State & DrawItemState.Selected) != DrawItemState.Selected)
{
rx.Offset(0, 2);
}
rt.Inflate(-rx.Width, 0);
rt.Offset(-(rx.Width / 2), 0);
using (Font f = new Font("Marlett", 8f))
using (StringFormat sf = new StringFormat()
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center,
Trimming = StringTrimming.EllipsisCharacter,
FormatFlags = StringFormatFlags.NoWrap,
})
{
g.DrawString(tp.Text, tp.Font ?? Font, Brushes.Black, rt, sf);
g.DrawString("r", f, HoverIndex == e.Index ? Brushes.Black : Brushes.LightGray, rx, sf);
}
tp.Tag = rx;
}
Note that, now the Tag
property of each TabPage
control holds a rectangle for the x
button.
In the MouseMove
event iterate through the TabPages
, cast the x
rectangle from the Tag
property, check if the x
rectangle contains the current e.Location
, and call Invalidate();
method of the TabControl
to update the drawing:
private void tabControl1_MouseMove(object sender, MouseEventArgs e)
{
for (int i = 0; i < tabControl1.TabCount; i++)
{
var rx =(Rectangle)tabControl1.TabPages[i].Tag;
if (rx.Contains(e.Location))
{
//To avoid the redundant calls.
if (HoverIndex != i)
{
HoverIndex = i;
tabControl1.Invalidate();
}
return;
}
}
//To avoid the redundant calls.
if (HoverIndex != -1)
{
HoverIndex = -1;
tabControl1.Invalidate();
}
}
In the MouseLeave
event invalidate if necessary:
private void tabControl1_MouseLeave(object sender, EventArgs e)
{
if (HoverIndex != -1)
{
HoverIndex = -1;
tabControl1.Invalidate();
}
}
And to close/dispose a page, handle the MouseUp
event:
private void tabControl1_MouseUp(object sender, MouseEventArgs e)
{
for(int i = 0; i < tabControl1.TabCount; i++)
{
var rx = (Rectangle)tabControl1.TabPages[i].Tag;
if (rx.Contains(e.Location))
{
tabControl1.TabPages[i].Dispose();
return;
}
}
}
Related Posts
TabControl with Close and Add Button
来源:https://stackoverflow.com/questions/59206526/close-button-on-tab-pages-in-winforms