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;
resize函数c++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);
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。