使用 MouseMove 确定绘制内容的闪烁选项卡控件
Flickering Tab Control with MouseMove Determining What To Draw
我一整天都在研究这个问题,(继续笑哈哈)但我没有看到任何解决闪烁控件的古老表单问题的方法。我的控件是 TabControl,我使用的是 DrawMode OwnerDrawFixed。我正在挂接以下事件。简而言之,我正在创建一个带有可关闭 "X" 按钮的 TabControl,这些按钮是 12x12 png 资源。关闭按钮都是灰色的,但如果我将鼠标悬停在一个按钮上,它应该使用不同的图像(红色 X)。
MouseDown:循环所有 TabPage 并检查我是否单击了我正在绘制关闭按钮图像的矩形。
MouseLeave:当我离开 TabControl 时我需要 Invalidate 以确保正确绘制所有内容
MouseMove:循环所有 TabPage 并检查我是否将鼠标悬停在我正在绘制关闭按钮图像的矩形上。如果我将鼠标悬停在上方,那么我会保存标签页索引,以便我的绘图可以更改用于关闭按钮的图像。
DrawItem:这里我简单画一下图
我测试过但运气不好...
制作我自己的 TabControl class 它继承了 TabControl 并且在构造函数中我将 OptimizedDoubleBuffering 的 SetStyles 设置为 true(我将其他建议的标志设置为 true)
我尝试覆盖 CreateParams 以便我可以或这个值... createParams.ExStyle |= 0x00000020; (我不知道这是做什么的,但看到一位用户建议这样做。
设置表单 DoubleBuffered(什么都不做)
无论如何,我不知道该怎么做,我已经读了一段时间了。
这是我所有活动的代码。我只想在我的选项卡上设置关闭按钮,当我将鼠标悬停在它们上方时这些按钮会突出显示。谢谢
private int mousedOver = -1;//indicates which close button is moused over
private void tabControl_DrawItem(object sender, DrawItemEventArgs e)
{
e.Graphics.DrawImage(e.Index == mousedOver ? Resources.redX : Resources.grayX, e.Bounds.Right - 15, e.Bounds.Top + 4);
}
private void tabControl_MouseDown(object sender, MouseEventArgs e)
{
TabControl tc = sender as TabControl;
if (tc.TabCount == 1) return;
for (int i = 0; i < tc.TabPages.Count; i++)
{
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location))
{
TabPage tp = tc.TabPages[i];
tc.TabPages.Remove(tp);
tp.Dispose();
break;
}
}
}
private void tabControl_MouseMove(object sender, MouseEventArgs e)
{
TabControl tc = sender as TabControl;
for (int i = 0; i < tc.TabPages.Count; i++)
{
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location))
{
mousedOver = i;
tc.Invalidate();
return;
}
}
mousedOver = -1;
tc.Invalidate();
}
private void tabControl_MouseLeave(object sender, EventArgs e)
{
TabControl tc = sender as TabControl;
mousedOver = -1;
tc.Invalidate();
}
看来您的无效化太频繁了。尝试过滤它,以便仅在需要重新绘制控件时才使它无效:
private void tabControl_MouseMove(object sender, MouseEventArgs e) {
TabControl tc = sender as TabControl;
for (int i = 0; i < tc.TabPages.Count; i++) {
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location)) {
if (mousedOver != i) {
mousedOver = i;
tc.Invalidate(r);
}
} else if (mousedOver == i) {
int oldMouse = mousedOver;
mousedOver = -1;
tc.Invalidate(tc.GetTabRect(oldMouse));
}
}
}
我会保留 CreateParams 覆盖,但作为本机 windows 控件,您可能永远无法完全消除一些闪烁。
您也可以尝试设置控件的 DoubleBuffered 属性,方法是
Control.DoubleBuffered = true;
我知道这适用于 DataGridView、ListView、表单和面板。
可以在 MSDN 上找到文档。
我一整天都在研究这个问题,(继续笑哈哈)但我没有看到任何解决闪烁控件的古老表单问题的方法。我的控件是 TabControl,我使用的是 DrawMode OwnerDrawFixed。我正在挂接以下事件。简而言之,我正在创建一个带有可关闭 "X" 按钮的 TabControl,这些按钮是 12x12 png 资源。关闭按钮都是灰色的,但如果我将鼠标悬停在一个按钮上,它应该使用不同的图像(红色 X)。
MouseDown:循环所有 TabPage 并检查我是否单击了我正在绘制关闭按钮图像的矩形。
MouseLeave:当我离开 TabControl 时我需要 Invalidate 以确保正确绘制所有内容
MouseMove:循环所有 TabPage 并检查我是否将鼠标悬停在我正在绘制关闭按钮图像的矩形上。如果我将鼠标悬停在上方,那么我会保存标签页索引,以便我的绘图可以更改用于关闭按钮的图像。
DrawItem:这里我简单画一下图
我测试过但运气不好...
制作我自己的 TabControl class 它继承了 TabControl 并且在构造函数中我将 OptimizedDoubleBuffering 的 SetStyles 设置为 true(我将其他建议的标志设置为 true)
我尝试覆盖 CreateParams 以便我可以或这个值... createParams.ExStyle |= 0x00000020; (我不知道这是做什么的,但看到一位用户建议这样做。
设置表单 DoubleBuffered(什么都不做)
无论如何,我不知道该怎么做,我已经读了一段时间了。
这是我所有活动的代码。我只想在我的选项卡上设置关闭按钮,当我将鼠标悬停在它们上方时这些按钮会突出显示。谢谢
private int mousedOver = -1;//indicates which close button is moused over
private void tabControl_DrawItem(object sender, DrawItemEventArgs e)
{
e.Graphics.DrawImage(e.Index == mousedOver ? Resources.redX : Resources.grayX, e.Bounds.Right - 15, e.Bounds.Top + 4);
}
private void tabControl_MouseDown(object sender, MouseEventArgs e)
{
TabControl tc = sender as TabControl;
if (tc.TabCount == 1) return;
for (int i = 0; i < tc.TabPages.Count; i++)
{
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location))
{
TabPage tp = tc.TabPages[i];
tc.TabPages.Remove(tp);
tp.Dispose();
break;
}
}
}
private void tabControl_MouseMove(object sender, MouseEventArgs e)
{
TabControl tc = sender as TabControl;
for (int i = 0; i < tc.TabPages.Count; i++)
{
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location))
{
mousedOver = i;
tc.Invalidate();
return;
}
}
mousedOver = -1;
tc.Invalidate();
}
private void tabControl_MouseLeave(object sender, EventArgs e)
{
TabControl tc = sender as TabControl;
mousedOver = -1;
tc.Invalidate();
}
看来您的无效化太频繁了。尝试过滤它,以便仅在需要重新绘制控件时才使它无效:
private void tabControl_MouseMove(object sender, MouseEventArgs e) {
TabControl tc = sender as TabControl;
for (int i = 0; i < tc.TabPages.Count; i++) {
Rectangle r = tc.GetTabRect(i);
Rectangle closeButton = new Rectangle(r.Right - 15, r.Top + 4, 12, 12);
if (closeButton.Contains(e.Location)) {
if (mousedOver != i) {
mousedOver = i;
tc.Invalidate(r);
}
} else if (mousedOver == i) {
int oldMouse = mousedOver;
mousedOver = -1;
tc.Invalidate(tc.GetTabRect(oldMouse));
}
}
}
我会保留 CreateParams 覆盖,但作为本机 windows 控件,您可能永远无法完全消除一些闪烁。
您也可以尝试设置控件的 DoubleBuffered 属性,方法是
Control.DoubleBuffered = true;
我知道这适用于 DataGridView、ListView、表单和面板。
可以在 MSDN 上找到文档。