使用MouseMove闪烁选项卡控件确定要绘制的内容

时间:2015-05-18 18:47:25

标签: c# winforms paint flicker

我整天都在研究这个问题,(继续笑笑),我也没有看到任何解决闪烁控制的古老形式问题的方法。我的控件是TabControl,我正在使用DrawMode OwnerDrawFixed。我挂钩了以下事件。总之,我正在创建一个TabControl,可以关闭" X" 12x12 png资源的按钮。关闭按钮都是灰色的,但是如果我鼠标悬停在一个上,它应该使用不同的图像(红色X)。

  1. MouseDown:循环显示所有TabPages并检查我是否点击了我正在绘制关闭按钮图像的矩形。

  2. MouseLeave:当我离开TabControl以确保所有内容都正确绘制时我需要无效

  3. MouseMove:循环显示所有TabPages并检查我是否已将鼠标悬停在我正在绘制关闭按钮图像的矩形上。如果我将鼠标移除,那么我保存标签页索引,以便我的画颜料可以更改用于关闭按钮的图像。

  4. DrawItem:这里我只是绘制图像

  5. 我测试的东西但没有运气......

    1. 创建我自己的继承TabControl的TabControl类,并在构造函数中使用SetStyles for OptimizedDoubleBuffering为true(我将其他建议标志设置为true)

    2. 我试过覆盖CreateParams所以我可以或者这个值... createParams.ExStyle | = 0x00000020; (我不知道这是做什么的,但是读了一个建议这样做的用户。

    3. 设置表单DoubleBuffered(什么都不做)

    4. 无论如何,我无法思考该怎么做,而且我已经读了一段时间。

      这是我所有活动的代码。我只想在我的标签上设置关闭按钮,当我将鼠标悬停在它们上时会突出显示。感谢。

          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();
          }
      

2 个答案:

答案 0 :(得分:1)

看起来你经常无效。尝试过滤它,以便只在需要重新绘制控件时使其无效:

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控件,你可能永远不会完全消除一些闪烁。

答案 1 :(得分:0)

您也可以尝试通过

设置控件的DoubleBuffered属性
Control.DoubleBuffered = true;

我知道这适用于DataGridViews,ListViews,Forms和Panel。

可在MSDN上找到文档。