[高难度]如何解决设置TransparencyKey属性后窗体闪烁问题?

大狗狗 2010-09-21 02:31:51
环境:VS2005 C# WinForm

窗口设置TransparencyKey属性后(不管设成什么颜色),窗口加载时,未被透明的部分会先出现黑块,然后刷新成正常颜色,从而造成了闪烁。

双缓冲、屏蔽WM_ERASEBKGND这些方法都不管用(重载WndProc或采用下面代码)

SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景.
SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲


我觉得这黑块是系统为了画出透明部分而产生的。因此和是否擦除背景无关。(一篇资料上说VC下可以重载OnEraseBkgnd来防止设置透明色后带来的闪烁http://www.vckbase.com/document/viewdoc/?id=1148)


哪位朋友能够解决这个问题?
...全文
719 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
BG 2012-03-08
  • 打赏
  • 举报
回复
学习了,同样纠结于闪烁问题。
大狗狗 2010-09-22
  • 打赏
  • 举报
回复
非常感谢!

bloodish朋友的方案:不需要额外代码。但界面上不能存在黑色部分,不然会被透明掉。

我认为设置了TransparencyKey后,窗口启动时会先进行透明处理。这个透明处理应该是一系列颜色运算。
对于背景色等于TransparencyKey的部分,运算结果是透明色。否则是黑色。

如果TransparencyKey设为黑色,即使背景色不同于TransparencyKey,运算结果也是透明色。但透明处理过后系统还会发出一个WM_PAINT(这个经过了我测试), 这部分就能刷新显示出来了。


xxc168朋友方法的原理我认为是通过延迟显示窗体来把显示黑块那段时间给跨过。

总结:
现在已经有两种解决办法了。具体内部原理可以接下来慢慢探讨。今天起床时我还在发愁这个问题有没有解,多亏了你们帮忙!再次感谢!(这个问题对我太重要了,起码应该请你们吃顿饭,加我QQ吧:184263203)
ElfSundae 2010-09-22
  • 打赏
  • 举报
回复
另外,如果最小化后还原时还有黑框闪烁,处理WndProc就行了。最小化时Opacity = 0,还原时启动timer。
例如:


Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case &H5
' 为避免加载窗体或还原窗体时绘制出现黑框,处理Windows消息
'change size: WM_SIZE
If True Then
Dim newState As FormWindowState = FormWindowState.Normal
Select Case m.WParam.ToInt32()
Case 0
'SIZE_RESTORED
Me.Timer1.Enabled = True
Case 1
'SIZE_MINIMIZED
Me.Opacity = 0
Case 2
'SIZE_MAXIMIZED
Case Else
Exit Select
End Select

End If
Exit Select
Case Else
Exit Select
End Select
MyBase.WndProc(m)
End Sub

ElfSundae 2010-09-22
  • 打赏
  • 举报
回复
我想我可以解决你的问题。我起初遇到这个问题是尝试了N中方案,都无济于事,最后发现了一个“不成文”但很凑效的办法:
需要一个Timer,
先设置要加载窗体的Opacity=0,然后执行加载,最后启动Timer。
Timer的Interval随便,效果是一样的。我一般都是设为1ms。Timer_Tick事件里设置窗体的Opacity=1,停止Timer1即可。

效果:相比现在的黑框,修改后的程序加载时会稍微顿一下,但没有任何闪烁或黑框!


例如,我有一个项目几乎所有控件和图像资源都是在运行时生成的,需要从远程加载图片。而Form是个不规则的窗体,必须设置TransparencyKey。加载时黑的很恐怖。。我的解决办法就是:

首先:
this.Visible = False
this.Opacity = 0

然后设置窗体大小布局等,连接远程主机,读取数据库,加载图片资源,生成控件等。

最后;this.timer1.Enabled = True
(Load结束)

Sub timer1_Tick()
{
this.Opacity = 1
timer1.Enabled = False
}

这个方法我已经在多个项目中使用并且非常奏效。
bloodish 2010-09-21
  • 打赏
  • 举报
回复
确实有这个问题.
但是当TransparencyKey=Black就不会出黑块了,
只是文本如果是黑色,全部变成透明,继续找原因,很有意思.
大狗狗 2010-09-21
  • 打赏
  • 举报
回复
再up up up
problc 2010-09-21
  • 打赏
  • 举报
回复
帮up,闪烁问题太烦人了
大狗狗 2010-09-21
  • 打赏
  • 举报
回复
再up下
大狗狗 2010-09-21
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 bloodish 的回复:]
引用 4 楼 win32fanex 的回复:
如果不透明区放的是系统控件,那么肯定会出现闪烁。用下面方法可以确定黑块是否存在:

确实没有你说的问题,没有闪烁...
我放了近百个Panel,背景色设置成跟TransparencyKey不同的颜色.
[/Quote]

不是panel,光panel不行,你放个其它控件试下,比如edit.
大狗狗 2010-09-21
  • 打赏
  • 举报
回复
试了下稍复杂的自定义控件,只要有绘制操作,黑块就会出现。
bloodish 2010-09-21
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 win32fanex 的回复:]
如果不透明区放的是系统控件,那么肯定会出现闪烁。用下面方法可以确定黑块是否存在:
[/Quote]
确实没有你说的问题,没有闪烁...
我放了近百个Panel,背景色设置成跟TransparencyKey不同的颜色.
porschev 2010-09-21
  • 打赏
  • 举报
回复
帮顶一下。。。
大狗狗 2010-09-21
  • 打赏
  • 举报
回复
楼上朋友:

我测试了下:如果不透明区放的是系统控件,那么肯定会出现闪烁。用下面方法可以确定黑块是否存在:


protected override void WndProc(ref Message m)
{
const int WM_PAINT = 0xF;

switch (m.Msg)
{
case WM_PAINT:
return;
}
base.WndProc(ref m);
}


如果不透明区放的是一个最简单的自定义控件,则没有黑块出现。接下来我试一下复杂的用户控件如何。
bloodish 2010-09-21
  • 打赏
  • 举报
回复
试了一下,没有出现楼主说的问题(Win7+VS2005)

UI控件很多?

Form的构造函数代码贴上来看看
大狗狗 2010-09-21
  • 打赏
  • 举报
回复
再顶upupup
无涯大者 2010-09-21
  • 打赏
  • 举报
回复
沙发,没有遇到过不怎懂,路过帮忙顶下~

110,539

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧