C#实现窗体控件随窗体大小改变(包括字体大小)

private float X;
private float Y;
private void setTag(Control cons)
foreach (Control con in cons.Controls)
{
    con.Tag = con.Width +":" + con.Height + ":" + con.Left + ":" + con.Top + ":" + con.Font.Size;
    if (con.Controls.Count > 0)
    setTag(con);
}
}
private void setControls(float newx, float newy, Control cons)
{
	 foreach (Control con in cons .Controls )
{
string[] mytag = con.Tag.ToString().Split(new char[] { ':' });
float a = Convert.ToSingle(mytag[0]) * newx;
con.Width = (int)a;
a=Convert.ToSingle(mytag[1]) * newy;
con.Height = (int)(a);
a=Convert.ToSingle(mytag[2]) * newx;
con.Left = (int)(a);
a=Convert.ToSingle(mytag[3]) * newy;
con.Top = (int)(a);
Single currentSize = Convert.ToSingle (mytag[4]) * Math.Min(newx,newy);
con .Font =new Font (con.Font .Name ,currentSize,con.Font .Style ,con.Font .Unit );
if(con.Controls .Count >0)
{
	 setControls (newx ,newy ,con );
}
}
}
void Form1_Resize(object sender, EventArgs e)
{
    float newx = (this.Width )/ X;
    float newy = this.Height / Y;
    setControls(newx, newy, this);
    this.Text = this.Width.ToString() +" "+ this.Height.ToString();
}

在Form_Load里面添加:
this.Resize += new EventHandler(Form1_Resize);
//X = this.Width;
//Y = this.Height;
setTag (this);
Form1_Resize(new object(),new EventArgs());//x,y可在实例化时赋值,最后这句是新加的,在MDI时有用​
当控件比较多时,每次改变窗体大小都会有明显的闪烁​
为什么会闪烁?
因为窗体控件状态转换时,windows需要负责"擦除"其背景,重新绘制,在一台性能并不优良的终端上(很大可能程度上客户端电脑都不是那么强劲吧) ,这个过程不是一时半会就能完成的,尤其对于很多个子控件的情况,因此就…​
查询一些资料提到的解决方法有:​
1.双缓冲​
SetStyle(ControlStyles.DoubleBuffer, true); ​
效果不是很明显​
2.由于底层重绘每次会清除画布,然后再全部重新绘制,这才是导致闪烁最主要的原因。于是重载消息发送函数操作,禁掉这条消息。代码如下:

protected override void WndProc(ref Message m)
{
    if (m.Msg == 0x0014) // 禁掉清除背景消息
    return;
    base.WndProc(ref m);
}​

但是这样效果依然不明显​
继续研究,看到网上有人写过解决类似问题方法,其原理是参考ListView控件中的两个函数

internal void BeginUpdateInternal()
{
    if (this.IsHandleCreated)
    {
	    if (this.updateCount == 0)
	    {
	   		 this.SendMessage(11, 0, 0);
	    }
   		this.updateCount = (short) (this.updateCount + 1);
    }
}​​

this.SendMessage(11, 0, 0)表示它给自身Send了一个code为11的windows消息,
在windows消息定义中可以看到 WM_SETREDRAW = 0x0B (0x0B也就是11),这行代码的意思是告诉windows对ListView控件停止重绘界面,直到显式要求重新绘制为止.

internal bool EndUpdateInternal(bool invalidate)
{
	    if (this.updateCount <= 0)
	    {
	    	return false;
	    }
	    this.updateCount = (short) (this.updateCount - 1);
	    if (this.updateCount == 0)
	    {
		    this.SendMessage(11, -1, 0);
		    if (invalidate)
		    {
		    	this.Invalidate();
		    }
	    }
	    return true;
}

同样有一行代码: this.SendMessage(11, –1, 0); 11还是同一个意思,此时告知windows可以重绘ListView控件了​
按照这种思路​在Resize函数中增加发送消息​

[DllImport("user32")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, IntPtr lParam);
private const int WM_SETREDRAW = 0xB;​
private void Form2_Resize(object sender, EventArgs e)
{
    SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
    float newx = (this.Width) / X;
    float newy = this.Height / Y;
    setControls(newx, newy, this);
    SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
    this.Invalidate(true);
}​

问题得到解决
转自:http://blog.sina.com.cn/s/blog_1499e59430102vh28.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值