我注意到,如果在具有图像背景的面板中有TabControl,当鼠标悬停在选项卡上时,它会闪烁并重新绘制。有没有解决办法来防止这种情况发生?如果图像是背景,TabControl闪烁
回答
我明白了。发生这种情况是因为TabControl通过要求父控件在自己的窗口中绘制自己而部分地绘制自己。必要的,因为选项卡不覆盖控制的全部宽度,他们“伸出”。如果BackgroundImage绘制速度慢,则会在所绘制的背景与在其上绘制的选项卡之间看到闪烁。
这将很难解决,TabControl不支持任何类型的双缓冲。您只能通过使BackgroundImage高效绘制来最大限度地降低效果。您需要通过使图像与面板的ClientSize的大小完全一致来实现,以便图像不必调整大小。并用PixelFormat32bppPArgb像素格式创建该位图,通常比其他图像快10倍。
有一种魔法治疗可用,windows有一个样式标志,可以为整个窗口(包括其子控件)启用双缓冲。自XP以来支持,但一些副作用已被报告。这段代码粘贴到您的形式,它修复了TabControl的闪烁:
protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
但要注意的是,视觉风格渲染的TabControl有这种风格的一个标志,而主要的不兼容。如果你的标签溢出,你得到的选择箭头,然后它去香蕉,并开始渲染标签一遍又一遍,产生非常高的闪烁率。
您可以尝试创建一个使用双缓冲的面板。从面板派生并设置DoubleBuffered为true:
public partial class DoubleBufferedPanel : Panel
{
public DoubleBufferedPanel()
{
InitializeComponent();
this.DoubleBuffered = true;
UpdateStyles();
}
}
我已经试过溶液的CreateParams,并介绍了自己的问题。我需要动态地添加和删除选项卡,并且在删除选项卡后,即使在Invalidate()方法之后,带WS_EX_COMPOSITED的TabControl也不会自我重绘。只有当我将鼠标移动到选项卡区域时,TabControl才会开始以非常奇怪的方式重绘自己。
所以最后我来到了这个解决方案:
public class TabControlX : TabControl
{
protected override void WndProc(ref Message m)
{
if(m.Msg == WinAPI.WM_MOUSEMOVE && !HotTrack)
return;
base.WndProc(ref m);
}
}
凡
public const int WM_MOUSEMOVE = 0x0200;
对于一些未知的原因HotTrack财产TabControl控件不工作,所以我其实已经固定它:)
当然,它在调整大小时不起作用,但它对我很好。
感谢来自Hans Passant的多个答案,我能够创建一个只有在需要时才会处于该模式的切换版本,在这种情况下:当选项卡控件由于父窗体而调整大小时。
这并不容易,因为我决定最好让它听取表单的大小调整开始并调整大小的结尾......这就是我所做的,它适合我的需求,tabcontrol不再闪烁从窗体调整大小正在调整大小。
public class NoFlickerTabControl : TabControl
{
#region PInvoke Change Window Rendering Style Params
public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, IntPtr dwNewLong)
{
if (IntPtr.Size == 8)
{
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
}
else
{
return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32()));
}
}
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong);
public enum WindowLongFlags : int
{
GWL_WNDPROC = -4,
GWL_HINSTANCE = -6,
GWL_HWNDPARENT = -8,
GWL_STYLE = -16,
GWL_EXSTYLE = -20,
GWL_USERDATA = -21,
GWL_ID = -12
}
#endregion
#region Tab Control Style!
public NoFlickerTabControl()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
#region Events to use from Parent
private bool bNeedToLinkFormResizeEvents = true;
private void ParentForm_ResizeBegin(object sender, EventArgs e)
{
EnableWS_EX_COMPOSITED();
}
private void ParentForm_ResizeEnd(object sender, EventArgs e)
{
DisableWS_EX_COMPOSITED();
}
#endregion
#region Enable/Disabled WS_EX_COMPOSITED
private const int WS_EX_COMPOSITED = 0x02000000;
private void EnableWS_EX_COMPOSITED()
{
CreateParams cp = CreateParams;
cp.ExStyle |= WS_EX_COMPOSITED; // Turn on WS_EX_COMPOSITED
//Make our call.
HandleRef handleRef = new HandleRef(null, Handle);
IntPtr style = new IntPtr(cp.ExStyle);
SetWindowLong(handleRef, (int)WindowLongFlags.GWL_EXSTYLE, style);
}
private void DisableWS_EX_COMPOSITED()
{
CreateParams cp = CreateParams;
cp.ExStyle &= ~WS_EX_COMPOSITED; // Turn OFF WS_EX_COMPOSITED (in case it's been set)
//Make our call.
HandleRef handleRef = new HandleRef(null, Handle);
IntPtr style = new IntPtr(cp.ExStyle);
SetWindowLong(handleRef, (int)WindowLongFlags.GWL_EXSTYLE, style);
}
#endregion
protected override void WndProc(ref Message m)
{
int WM_MOUSEMOVE = 0x0200;
if (m.Msg == WM_MOUSEMOVE && !HotTrack)
{
return;
}
base.WndProc(ref m);
}
protected override void OnPaint(PaintEventArgs e)
{
if(Width <= 0 || Height <= 0)
{
return;
}
//Paint related, found it was best to do the check here when control finally gets Parent set by the program.
if (bNeedToLinkFormResizeEvents)
{
Form parentForm = FindForm();
if (parentForm != null)
{
bNeedToLinkFormResizeEvents = false;
parentForm.ResizeBegin += ParentForm_ResizeBegin;
parentForm.ResizeEnd += ParentForm_ResizeEnd;
}
}
//~~~~~~ DO THE PAINTING OF THE CONTROL NOW.
}
#endregion
}
- 1. 闪烁背景
- 2. IE7/IE8非背景图像闪烁
- 3. 背景图像闪烁鼠标悬停
- 4. jquery闪烁的背景图像
- 5. Applet背景闪烁?
- 6. 图片背景在页面加载时闪烁白色闪烁
- 7. 使UITextField背景闪烁
- 8. Visual Studio 2010背景闪烁
- 9. 被加载的背景图片闪烁
- 10. 如何保持内容加载的背景图像“闪烁”?
- 11. 如何防止Internet Explorer/Edge中的背景图像闪烁?
- 12. 使用数据绑定设置背景图像闪烁
- 13. 鼠标悬停时背景图像闪烁 - IE
- 14. jquery动画导致背景图像闪烁
- 15. 当背景图像缩放时,它开始在Chrome中闪烁
- 16. 在winforms中的tabcontrol背景图像
- 17. 在IE页面闪烁闪烁,mozilla显示白色背景
- 18. 图像不闪烁
- 19. DataGridViewImageColumn,图像闪烁
- 20. 首选项背景颜色闪烁
- 21. VB.NET中的标签背景闪烁
- 22. Internet Explorer中的背景闪烁问题
- 23. SWT链接闪烁渐变背景
- 24. 背景颜色变化闪烁
- 25. 背景瞬间加载闪烁
- 26. 布局背景资源闪烁进出
- 27. 背景在Fancybox iframe中闪烁白色
- 28. 在XNA中滚动背景闪烁
- 29. jquery悬停IE中的背景闪烁
- 30. 动画LinearLayout背景在Android中闪烁
这样做的窍门,谢谢! – jwarzech 2010-06-24 18:19:17
忘记标记答案为答案,这解决了我的问题,谢谢:0) – jwarzech 2010-06-25 19:09:15
真棒,拯救了我的一天! – BerggreenDK 2012-01-06 12:57:07