WinForm界面闪烁问题

blacksource 2009-12-28 12:41:25
现在描述:
1.mdi窗体切换(A页面切换到B页面)的时候出现闪烁现象,表现为:如果先把A隐藏再把B显示,则B显示的时候label、button等控件的位置会闪烁一下(显示主页面的背景色);如果先把B显示再隐藏A,同样在控件位置会闪烁(显示为A页面的内容)

2.最大化时,由于页面用了自动拉伸。所以最大化时页面会自动扩展。但仔细观察会发现,他是先把原来的页面移动到左上角,然后再实现拉伸,所以也就导致了闪烁现象

3.从最小化还原时,每个控件位置也同样会闪烁一下
...全文
4391 72 打赏 收藏 转发到动态 举报
写回复
用AI写文章
72 条回复
切换为时间正序
请发表友善的回复…
发表回复
pfworld 2011-03-16
  • 打赏
  • 举报
回复
不要使用pictureBox 就用最底层的Graphics类直接在panel里面绘制 绘制类实例如下:

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Runtime.InteropServices;

namespace PlantFarm
{
\*<p>
* 类名称:Base
* <p>
* <p>
* 功能描述:实体类的基类
* </p>
* <p>
* 创建人:***
* </p>
* <p>
* 创建时间:2009-12-08
* </p>
* <p>
* 当前版本:0.1
* </p>
*
* *\
abstract class Base
{
//抽象绘制方法
public abstract void draw(Graphics g);

\*
* <p>
* 方法名:Base
* </p>
* <p>
* 方法描述:构造函数,定义常用变量
* </p>
* <p>
* 创建人:***
* </p>
* <p>
* 创建时间:2009-12-08
* </p>
*\
public Base()
{
imgAttr = new System.Drawing.Imaging.ImageAttributes();
imgAttr.SetColorKey(Color.White, Color.White);
}

\*
* <p>
* 方法名:drawTransBGImage
* </p>
* <p>
* 方法描述:绘制背景透明图片
* </p>
* <p>
* 输入参数:Graphics grap:绘图类;Image img:需要绘制的图片对象;int x:绘制横坐标;int y:绘制纵坐标。
* </p>
* <p>
* 输出参数:void:任意类型。
* </p>
* <p>
* 创建人:***
* </p>
* <p>
* 创建时间:2009-12-08
* </p>
*\
public void drawTransBGImage(Graphics grap, Image img, int x, int y)
{
grap.DrawImage(img, new Rectangle(x, y, img.Width, img.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, this.imgAttr);
}

\*
* <p>
* 方法名:drawClipImage
* </p>
* <p>
* 方法描述:绘制切割区域图片
* </p>
* <p>
* 输入参数:Graphics g:绘图类;Image image:需要绘制的图片对象;int x:绘制横坐标;int y:绘制纵坐标;int row:图片总行数;int col:图片总列数;int index:子图片的索引。
* </p>
* <p>
* 输出参数:void:任意类型
* </p>
* <p>
* 创建人:***
* </p>
* <p>
* 创建时间:2009-12-09
* </p>
*\
protected void drawClipImage(Graphics g, Image image, int x, int y, int row, int col, int index)
{
Region rect = g.Clip;
int sgWidth = image.Width / col;
int sgHeight = image.Height / row;
g.Clip = new Region(new Rectangle(x, y, sgWidth, sgHeight));
this.drawTransBGImage(g, image, x - index % col * sgWidth, y - index / col * sgHeight);
g.Clip = rect;
}

protected void drawText(Graphics g, string txt, Font font, Color color, int x, int y)
{
if (font == null)
{
font = new Font("宋体", 8, FontStyle.Regular);
}
g.DrawString(txt, font, new SolidBrush(color), x, y);
font.Dispose();
}

\*
* <p>
* 方法名:getClipImage
* </p>
* <p>
* 方法描述:获取一张剪切图片
* </p>
* <p>
* 输入参数:Image image:被截取的整体图片;int row:整体图片的行数;int col:整体图片的列数;int index:索引。
* </p>
* <p>
* 输出参数:Image:获得的截取图片。
* </p>
*\
protected Image getClipImage(Image image, int row, int col, int index)
{
Image clipImg = new Bitmap(image.Width / col, image.Height / row);
Graphics grap = Graphics.FromImage(clipImg);
grap.Clear(Color.White);
this.drawClipImage(grap, image, 0, 0, row, col, index);
grap.Dispose();
return clipImg;
}

\*
* <p>
* 方法名:getFileStream
* </p>
* <p>
* 方法描述:从文件中获取流
* </p>
* <p>
* 输入参数:string filename:文件的相对路径。
* </p>
* <p>
* 输出参数:Stream:文件的流。
* </p>
* <p>
* 创建人:***
* </p>
* <p>
* 创建时间:2009-12-08
* </p>
*\
protected System.IO.Stream getFileStream(string filename)
{
System.Type tp = this.GetType();
System.IO.Stream stream = tp.Assembly.GetManifestResourceStream(tp.Namespace + ".res." + filename);
return stream;
}
protected System.Drawing.Imaging.ImageAttributes imgAttr;//图片的属性
}



//或者用以下DLL接口代码 都可以实现的
\*
* <p>
* 类名称:DrawTransp
* </p>
* <p>
* 功能描述:图片图像的处理类
* </p>
* <p>
* 创建人:***
* </p>
* <p>
* 创建时间:2009-12-08
* </p>
* <p>
* 版本:0.1
* </p>
*\
public class DrawTransp
{
private struct BlendFunction
{
public byte BlendOp;//源混合操作
public byte BlendFlags;//必须是0
public byte SourceConstantAlpha;//0到255间的值,这里0表示完全透明,255表示完全不透明。
public byte AlphaFormat;//有两个值 0表示常量alpha值,AC_SRC_ALPHA表示每个像素有各自的alpha通道

}

private enum BlendOperation : byte
{
AC_SRC_OVER = 0x00//表示根据源alpha值把源图像叠加到目标图像上
}

private enum BlendFlags : byte
{
Zero = 0x00
}

private enum SourceConstantAlpha : byte
{
Transparent = 0x00,
Opaque = 0xFF
}

private enum AlphaFormat : byte
{
AC_SRC_ALPHA = 0x01
}

private class PlatformAPIs
{
/// <summary>
/// 用于绘制透明或半透明的位图,WinCE5.0+的版本支持,
/// </summary>
/// <param name="hdcDest">目标设备图面的句柄</param>
/// <param name="xDest">绘制目标图面的x轴坐标</param>
/// <param name="yDest">绘制目标图面的y轴坐标</param>
/// <param name="cxDest">目标矩形的宽</param>
/// <param name="cyDest">目标矩形的高</param>
/// <param name="hdcSrc">源设备图面的句柄</param>
/// <param name="xSrc">源x坐标</param>
/// <param name="ySrc">源y坐标</param>
/// <param name="cxSrc">源图宽</param>
/// <param name="cySrc">源图高</param>
/// <param name="blendFunction">BLENDFUNCTION结构,控制源和目标位图的混合方式</param>
/// <returns></returns>
[DllImport("coredll.dll")]
extern public static Int32 AlphaBlend(IntPtr hdcDest, Int32 xDest, Int32 yDest, Int32 cxDest, Int32 cyDest, IntPtr hdcSrc, Int32 xSrc, Int32 ySrc, Int32 cxSrc, Int32 cySrc, BlendFunction blendFunction);

}

public DrawTransp()
{

}

public static void DrawTime(string time, Graphics gx, int x, int y)
{
Font timeFont = new Font("Tahoma", 32, FontStyle.Regular);
SizeF size = gx.MeasureString(time, timeFont);
gx.DrawString(time, timeFont, new SolidBrush(Color.WhiteSmoke), x, y);

}

/// <summary>
/// 绘制透明图像
/// </summary>
/// <param name="gx">绘图图面</param>
/// <param name="image">需要绘制的位图</param>
/// <param name="transp">透明度trasp/250</param>
/// <param name="x">绘图起点的横坐标</param>
/// <param name="y">绘图起点的纵坐标</param>
public static void DrawAlpha(Graphics gx, Image image, byte transp, int x, int y)
{
using (Graphics gxSrc = Graphics.FromImage(image))
{
IntPtr hdcDst = gx.GetHdc();
IntPtr hdcSrc = gxSrc.GetHdc();
BlendFunction blendFunction = new BlendFunction();
blendFunction.BlendOp = (byte)BlendOperation.AC_SRC_OVER;
blendFunction.BlendFlags = (byte)BlendFlags.Zero;
blendFunction.SourceConstantAlpha = transp;
blendFunction.AlphaFormat = (byte)0;
PlatformAPIs.AlphaBlend(hdcDst, x, y, image.Width, image.Height, hdcSrc, 0, 0, image.Width, image.Height, blendFunction);
gx.ReleaseHdc(hdcDst);
gxSrc.ReleaseHdc(hdcSrc);
}
}
}
}

pfworld 2011-03-16
  • 打赏
  • 举报
回复
解决Lable透明闪耀问题【第二版】

最终解决方案: 将lable.Dock 从原来的Fill 改为None. 在其父控件的resize事件实现Dock功能

需要主窗体设置

this.BackgroundImageLayout = ImageLayout.None;

程序的自动刷新在刷新设置了dock的控件时(至少lable似乎是的),由于dock拉伸的部分的刷新和原始大小的部分的刷新是不同步的,所以造成闪烁.
pfworld 2011-03-16
  • 打赏
  • 举报
回复
解决Lable透明闪耀问题【第一版】

1、先设置界面双缓存

SetStyle(ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
UpdateStyles();



2、注册界面绘制事件
this.Paint += new PaintEventHandler(pictureBox1_Paint);



3、设置要显示的Lable不显示

this.lbl_Test..Visible = false;



4、添加要绘制的事件

//背景是一个pictureBox
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
TransparentLabel(this.lbl_Test, e.Graphics);
}



5、设置方法重绘方法


/// <summary>
/// 透明Label控件
/// 注意,将Label的Visible设置为false;适合背景为图片(PictureBox)
/// </summary>
/// <param name="label"></param>
/// <param name="g"></param>
public static void TransparentLabel(Label label, Graphics g)
{
Rectangle rect = label.Bounds;
SolidBrush sb = new SolidBrush(label.ForeColor);
SizeF size;
//计算字符串的位置
switch (label.TextAlign)
{
case ContentAlignment.TopLeft:
break;
case ContentAlignment.MiddleLeft:
rect.Y += 4; //为MiddleLeft时Lable要靠下4点
break;
case ContentAlignment.TopCenter:
//计算字符串长度
size = g.MeasureString(label.Text, label.Font);
rect.X += (int)((rect.Width - size.Width) / 2);
rect.Y += (int)((rect.Height - size.Height) / 2);
break;
case ContentAlignment.TopRight:
size = g.MeasureString(label.Text, label.Font);
rect.X += rect.Width - (int)size.Width;
rect.Y += rect.Height - (int)size.Height;
break;
}
g.DrawString(label.Text, label.Font, sb, rect);
sb.Dispose();
}

angelababa~ 2011-03-15
  • 打赏
  • 举报
回复
换C++不闪
小牛小骆驼 2011-03-15
  • 打赏
  • 举报
回复
有个成功解决了的示例,想要M我!这问题咱也纠结了好长时间!
qianqian 2010-09-14
  • 打赏
  • 举报
回复
这个问题只能说明winform的处理速度有较大问题,另外控件一多就非常明细,在背景界面不是buttonface的时候会比较突出。
这个问题琢磨了很多解决方案都不爽,只能用一个变态的方法解决。我随后写到我日志空间里
blacksource 2010-08-17
  • 打赏
  • 举报
回复
只能说是缓解,并没有完全解决
yuquan1987 2010-08-17
  • 打赏
  • 举报
回复
楼主解决这个问题了吗?我现在也遇到这个问题了,很是恼火,望楼主指点!
bruceyue 2010-03-03
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace FlashWindows
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();

}
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool FlashWindow(IntPtr handle,bool bInvert);
private void pictureBox1_Click(object sender, EventArgs e)
{

}

private void timer1_Tick(object sender, EventArgs e)
{
FlashWindow(this.Handle ,true);
}

private void button1_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
}

private void button2_Click(object sender, EventArgs e)
{
timer1.Stop();
}
}
}
xingyuebuyu 2010-03-03
  • 打赏
  • 举报
回复
将背景图片用photoshop处理成背景透明的PNG格式的图片就可以
kwork 2010-03-03
  • 打赏
  • 举报
回复
我也来解释下,仅供楼主参考。

使用控件的双缓冲输出,这样就会不闪烁了。

给篇MSDN的资料先了解下相关知识
http://msdn.microsoft.com/zh-cn/library/b367a457(VS.80).aspx

代码实现:
重构一下控件的函数

//使用双缓冲绘图,解决更新中的闪烁问题
SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.AllPaintingInWmPaint,
true);
UpdateStyles();
zengdili 2010-03-03
  • 打赏
  • 举报
回复
也不知道我这个方法适合不。
图片的话最好不要用panel,用PictureBox.
还有就上面说的闪烁的原理,白帧的问题,是因为是先form的paint事件再control的paint事件.
可以设置control.visable=false;控件就不会响应paint事件。
下面就是用form的paint事件绘画有图片的control.
如:
foreach (Control C in this.Controls)
{
if (C is PictureBox)
{
PictureBox P = (PictureBox)C;
e.Graphics.DrawImage(Image.FromFile(P.ImageLocation), P.Left,P.Top,P.Width, P.Height);
}
}
WTPMCheng 2010-01-11
  • 打赏
  • 举报
回复
王楼主解决了,共享解决方案!关注中。。。。
guyehanxinlei 2010-01-11
  • 打赏
  • 举报
回复
学习
RuslanC 2010-01-11
  • 打赏
  • 举报
回复
学习一下
天府荣城 2010-01-11
  • 打赏
  • 举报
回复
顶下
dudou 2010-01-11
  • 打赏
  • 举报
回复
dd
hualiang_ll 2010-01-11
  • 打赏
  • 举报
回复
关注中......
blacksource 2010-01-11
  • 打赏
  • 举报
回复
[Quote=引用 50 楼 leonbyron 的回复:]
上边那段摘录你解释的不对,说的不是form上的控件多导致人眼可发觉的闪烁,是重画的次数过多,结合其他人给出的例子。你需要做的是不要让操作系统不受控的帮你刷新,因为可能会导致多次的刷新,而是由你在合适的时间指挥它进行刷新。具体做法,上边已经有人给出了说明。
[/Quote]
我那不是直译,是针对于我的情况的意译。不让系统去刷新是个不错的方案。可是我试了下好像会出问题,整个界面都卡在那不动了。请问您说的“具体做法,上边已经有人给出了说明。”是哪指哪位呀
灰鸟会灰 2010-01-11
  • 打赏
  • 举报
回复
关注中......
加载更多回复(52)
介绍: 本案例教你如何使用CSkin界面库 在winform平台做出《彗星小助手》的界面效果 本案例实现了部分功能 主要是展现界面的属性设置流程和界面库的使用 更新时间:2014 8 26 更新功能: 1 修复SkinPanel滚动条不显示的问题 2 修复SkinPanel右下边框不显示的问题 3 修复好友列表头像闪烁的一些BUG 4 修复SkinMain异形窗体点击任务栏最小化操作 5 加入内置工具类FastBitmap 此类用来快速Bitmap读写像素 如何使用看:http: bbs cskin net thread 83 1 1 html 6 修复截图控件的未选框双击错误BUG 增加截图控件属性BmpLayerCurrent:控件所截图的图片 7 SkinToolStrip添加BaseItemNorml属性 BaseItem默认背景图 8 修复SkinComboBox下拉框项的细节样式 9 加入SkinFileTansfersContainer控件与SkinFileTransfersItem控件 SkinFileTansfersContainer:文件传输列表容器 这里面内置Add Remove Search等操作ItemList方法 SkinFileTransfersItem:文件传输列表项 用于添加进列表容器 10 SkinToolStrip控件添加BindTabControl 绑定要操作的TabControl 属性 绑定后点击ToolStripButton就可以根据ToolStripButton中的Tag TabPage的Index值 进行切换TabPage 11 优化设计时SkinTabControl略卡的问题 12 SkinTabePage添加属性(BorderColor:边框颜色) 13 修复好友列表闪烁状态下好友被删除 分组依然闪烁 14 SkinButton SkinCheckBox SkinRadioButton添加属性(IsEnabledDraw:是否画禁用状态下的效果 默认true) 15 好友列表添加三个事件: (DownSubItem:用鼠标按下子项时发生) (UpSubItem:用鼠标按下并释放子项时发生) (ClickSubItem:用鼠标单击子项时发生) 16 SkinTabControl添加两个事件: (TabePageClosed:TabPage容器关闭后 ) (TabePageClosing:TabPage容器关闭前 ) 17 加入彗星小助手案例DEMO(不带Html编辑器版本CSkin dll) 注意: 由于部分免费用户无法加入工具箱 经检测是里面的一个Html编辑器控件不兼容的问题问题兼容之前 现在分发两个版本(一个:带Html编辑器版本 一个:不带Html编辑器版本) 本案例资源来自:CSkin论坛 http: bbs cskin net">介绍: 本案例教你如何使用CSkin界面库 在winform平台做出《彗星小助手》的界面效果 本案例实现了部分功能 主要是展现界面的属性设置流程和界面库的使用 更新时间:2014 8 26 更新功能: 1 修复SkinPanel滚动条不显示 [更多]

110,533

社区成员

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

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

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