Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/338.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何更改选项卡控件上的图像而不闪烁_C#_Tabcontrol - Fatal编程技术网

C# 如何更改选项卡控件上的图像而不闪烁

C# 如何更改选项卡控件上的图像而不闪烁,c#,tabcontrol,C#,Tabcontrol,我在C#tab控件的标题上放置了一个图像。我想在光标悬停在图像上时更改图像。 现在我调用Control.Refresh方法,如下所示: TabControl tabControl1 = new TabControl(); [...] private void tabControl1_MouseMove(object sender, MouseEventArgs e) { [...] tabControl1.Refresh(); } private void tabControl


我在C#tab控件的标题上放置了一个图像。我想在光标悬停在图像上时更改图像。



现在我调用Control.Refresh方法,如下所示:

TabControl tabControl1 = new TabControl();

[...]

private void tabControl1_MouseMove(object sender, MouseEventArgs e)
{
[...]

    tabControl1.Refresh();
}

private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
    e.Graphics.DrawImage(imagefile, arg1, arg2, arg3, arg4);

[...]
}
通过使用标志,当光标即将放在图像上并离开图像时,将调用Refresh方法,也就是说,一行中不会多次调用Refresh方法。
通过这种方式,图像成功更改,但经常闪烁。

如何更改它而不闪烁?有什么想法吗?

你需要双缓冲区

“双缓冲区是一种技术,我们将所有图形需要绘制到存储在内存(缓冲区)中的图像上,完成所有绘制需要后,我们将从内存中绘制一个完整的图像到屏幕上。这将图形集中到屏幕上(一种严重影响应用程序性能的操作)只进行一次操作,而不是多次小操作。”


请参见

此操作需要双缓冲区

“双缓冲区是一种技术,我们将所有图形需要绘制到存储在内存(缓冲区)中的图像上,完成所有绘制需要后,我们将从内存中绘制一个完整的图像到屏幕上。这将图形集中到屏幕上(一种严重影响应用程序性能的操作)只进行一次操作,而不是多次小操作。”


请参见

选项卡控件
是一种特殊的控件,不能在其上启用双缓冲。这是因为它要求活动选项卡的所有子元素将自己绘制到其内容上。不幸的是,这也会影响选项卡,即使您不想自定义页面图形,而只想自定义选项卡

但是,您可以使用一些技巧来最小化闪烁:

1。切勿使用
Refresh()

Refresh()
方法强制立即重新绘制整个控件,无论您此刻正在做什么。相反,使用
Invalidate
将控件标记为无效,以便在专用刷新会话中将其与其他无效控件一起重新绘制

2。使完整的表单双缓冲

虽然
TabControl
不支持双缓冲,但是您可以将整个
表单
进行双缓冲,这样可以减少闪烁

只需在表单中重写
CreateParams
,即可:

private const int WS_EX_COMPOSITED = 0x02000000;

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= WS_EX_COMPOSITED;
        return cp;
    }
}
3。仅使无效区域无效

如果使整个
选项卡控件无效
,它将与其子项一起完全重新绘制。但是您希望使选项卡中的一些16x16像素矩形无效,这样就可以避免刷新整个控件

private int hoveredIndex = -1;
private Size imageSize = new Size(16, 16);

private void TabControl1_MouseMove(object sender, MouseEventArgs e)
{
    for (int i = 0; i < tabControl1.TabPages.Count; i++)
    {
        Rectangle rect = tabControl1.GetTabRect(i);
        Rectangle closeButton = GetImageLocation(rect);
        if (closeButton.Contains(e.Location))
        {
            if (hoveredIndex != i)
            {
                hoveredIndex = i;
                tabControl1.Invalidate(rect);
            }
        }
        else if (hoveredIndex == i)
        {
            tabControl1.Invalidate(tabControl1.GetTabRect(hoveredIndex));
            hoveredIndex = -1;
        }
    }
}

private void TabControl1_MouseLeave(object sender, EventArgs e)
{
    if (hoveredIndex != -1)
    {
        tabControl1.Invalidate(tabControl1.GetTabRect(hoveredIndex));
        hoveredIndex = -1;
    }
}

private Rectangle GetImageLocation(Rectangle rect)
{
    return new Rectangle(rect.Right - imageSize.Width, rect.Top, imageSize.Width, imageSize.Height);
}

private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
    Image image = e.Index == hoveredIndex ? imageHovered : imageNormal;
    e.Graphics.DrawImage(image, GetImageLocation(e.Bounds));
}
private int hoveredIndex=-1;
私有大小imageSize=新大小(16,16);
私有无效选项卡控件1\u MouseMove(对象发送方,MouseEventArgs e)
{
对于(int i=0;i
TabControl
是一种特殊的控件,您不能在其上启用双缓冲。这是因为它要求活动选项卡的所有子元素将自己绘制到其内容上。不幸的是,这也会影响选项卡,即使您不想自定义页面图形,而只想自定义选项卡

但是,您可以使用一些技巧来最小化闪烁:

1。切勿使用
Refresh()

Refresh()
方法强制立即重新绘制整个控件,无论您此刻正在做什么。相反,使用
Invalidate
将控件标记为无效,以便在专用刷新会话中将其与其他无效控件一起重新绘制

2。使完整的表单双缓冲

虽然
TabControl
不支持双缓冲,但是您可以将整个
表单
进行双缓冲,这样可以减少闪烁

只需在表单中重写
CreateParams
,即可:

private const int WS_EX_COMPOSITED = 0x02000000;

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= WS_EX_COMPOSITED;
        return cp;
    }
}
3。仅使无效区域无效

如果使整个
选项卡控件无效
,它将与其子项一起完全重新绘制。但是您希望使选项卡中的一些16x16像素矩形无效,这样就可以避免刷新整个控件

private int hoveredIndex = -1;
private Size imageSize = new Size(16, 16);

private void TabControl1_MouseMove(object sender, MouseEventArgs e)
{
    for (int i = 0; i < tabControl1.TabPages.Count; i++)
    {
        Rectangle rect = tabControl1.GetTabRect(i);
        Rectangle closeButton = GetImageLocation(rect);
        if (closeButton.Contains(e.Location))
        {
            if (hoveredIndex != i)
            {
                hoveredIndex = i;
                tabControl1.Invalidate(rect);
            }
        }
        else if (hoveredIndex == i)
        {
            tabControl1.Invalidate(tabControl1.GetTabRect(hoveredIndex));
            hoveredIndex = -1;
        }
    }
}

private void TabControl1_MouseLeave(object sender, EventArgs e)
{
    if (hoveredIndex != -1)
    {
        tabControl1.Invalidate(tabControl1.GetTabRect(hoveredIndex));
        hoveredIndex = -1;
    }
}

private Rectangle GetImageLocation(Rectangle rect)
{
    return new Rectangle(rect.Right - imageSize.Width, rect.Top, imageSize.Width, imageSize.Height);
}

private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
    Image image = e.Index == hoveredIndex ? imageHovered : imageNormal;
    e.Graphics.DrawImage(image, GetImageLocation(e.Bounds));
}
private int hoveredIndex=-1;
私有大小imageSize=新大小(16,16);
私有无效选项卡控件1\u MouseMove(对象发送方,MouseEventArgs e)
{
对于(int i=0;i