C#当窗体大小改变时,控件的位置和大小随之改变

本文介绍四种实现C#窗体控件随窗体大小变化的方法,包括利用OnResize事件、SizeChanged事件等技术手段,确保控件在窗体缩放时保持布局不变。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:http://www.cnblogs.com/slyzly/articles/1965965.html。因为需要,因为经典,所以必须转。再加上自己对于第四种方法的一些心得。这算转载还是原创呢?


第一种:推荐


在窗体中加上如下代码即可实现,但窗体点击放大按钮时却不能改变控件大小。

复制代码
private  Size beforeResizeSize  =  Size.Empty;

protected override void  OnResizeBegin(EventArgs e)
{
base .OnResizeBegin(e);
      beforeResizeSize 
= this .Size;
}
protected override void  OnResizeEnd(EventArgs e)
{
      
base .OnResizeEnd(e);
      
// 窗口resize之后的大小
      Size endResizeSize  = this .Size;
      
// 获得变化比例
       float  percentWidth  =  ( float )endResizeSize.Width  /  beforeResizeSize.Width;
      
float  percentHeight  =  ( float )endResizeSize.Height  /  beforeResizeSize.Height;
      
foreach  (Control control  in this .Controls)
      {
if  (control  is  DataGridView)
continue ;
            
// 按比例改变控件大小
            control.Width  =  ( int )(control.Width  *  percentWidth);
            control.Height 
=  ( int )(control.Height  *  percentHeight);
            
// 为了不使控件之间覆盖 位置也要按比例变化
            control.Left  =  ( int )(control.Left  *  percentWidth);
            control.Top 
=  ( int )(control.Top  *  percentHeight);
     }
}
复制代码

第二种:效果很差

在加载事件中写 AutoScale(this);

复制代码
// 设置窗口控件随窗口大小改变而改变
public new void  AutoScale(Form frm)
{
      frm.Tag 
=  frm.Width.ToString()  + " , " +  frm.Height.ToString();
      frm.SizeChanged 
+= new EventHandler(frm_SizeChanged);
}
public void  frm_SizeChanged( object  sender, EventArgs e)
{
      
string [] tmp  =  ((Form)sender).Tag.ToString().Split( ' , ' );
      
float  width  =  ( float )((Form)sender).Width  /  ( float )Convert.ToInt32(tmp[ 0 ]);
      
float  height  =  ( float )((Form)sender).Height  /  ( float )Convert.ToInt32(tmp[ 1 ]);
      ((Form)sender).Tag 
=  ((Form)sender).Width.ToString()  + " , " +  ((Form)sender).Height;
      
string  str  =  ((Form)sender).Tag.ToString();
      
//  int font_size = Int32.Parse(str.Substring(0, str.IndexOf(','))) / 100;
       // 也可使字体随之改变
       float  tempWidth = 0F;
      
float  tempHeight = 0F;
      
foreach  (Control control  in  ((Form)sender).Controls)
      {
           
if  (control  is  DataGridView)
continue ;
           
if  (control  is  TextBox)
           {
                tempHeight 
=  height;
                tempWidth 
= width;
           } 
           
if  (control  is  Button)
           {
                
if  ( this .WindowState  ==  FormWindowState.Maximized)
tempHeight 
-= 0.4F ;
                
else
tempHeight 
+= 0.2F ;
                control.Scale(
new  SizeF(tempWidth, tempHeight));
           }
           
else
           {
                control.Scale(
new  SizeF(width, height));
           }
      }
}
复制代码

第三种:http://www.cnblogs.com/kenkao/archive/2008/11/10/1330623.html

复制代码
using  System;
using  System.Collections.Generic;
using  System.ComponentModel;
using  System.Data;
using  System.Drawing;
using  System.Text;
using  System.Windows.Forms;
using  System.Collections; 

namespace  WindowsApplication3
{
public partial class  Form1 : Form
{
/* ******************设定程序中可能要用到的用以存储初始数据的动态数组及相关私有变量***************************** */  

private  ArrayList InitialCrl  = new  ArrayList(); // 用以存储窗体中所有的控件名称
private  ArrayList CrlLocationX  = new  ArrayList(); // 用以存储窗体中所有的控件原始位置
private  ArrayList CrlLocationY  = new  ArrayList(); // 用以存储窗体中所有的控件原始位置
private  ArrayList CrlSizeWidth  = new  ArrayList(); // 用以存储窗体中所有的控件原始的水平尺寸
private  ArrayList CrlSizeHeight  = new  ArrayList(); // 用以存储窗体中所有的控件原始的垂直尺寸
private int  FormSizeWidth; // 用以存储窗体原始的水平尺寸
private int  FormSizeHeight; // 用以存储窗体原始的垂直尺寸
private double  FormSizeChangedX; // 用以存储相关父窗体/容器的水平变化量
private double  FormSizeChangedY; // 用以存储相关父窗体/容器的垂直变化量 
private int  Wcounter  = 0 ; // 为防止递归遍历控件时产生混乱,故专门设定一个全局计数器


public  Form1()
{
InitializeComponent();


private void  Form1_Load( object  sender, EventArgs e)
{
GetInitialFormSize();
// this.AutoScroll = true;
// this.SetAutoSizeMode(FormSizeWidth,FormSizeHeight);
// this.AutoScrollMinSize.Width = FormSizeWidth;
// this.AutoScrollMinSize.Height = FormSizeHeight;
GetAllCrlLocation( this );
GetAllCrlSize(
this );
}
public void  GetAllCrlLocation(Control CrlContainer) // 获得并存储窗体中各控件的初始位置
{
foreach  (Control iCrl  in  CrlContainer.Controls)

if  (iCrl.Controls.Count  > 0 )
GetAllCrlLocation(iCrl); 
InitialCrl.Add(iCrl);
CrlLocationX.Add(iCrl.Location.X);
CrlLocationY.Add(iCrl.Location.Y); 
}


public void  GetAllCrlSize(Control CrlContainer) // 获得并存储窗体中各控件的初始尺寸
{
foreach  (Control iCrl  in  CrlContainer.Controls)
{
if  (iCrl.Controls.Count  > 0 )
GetAllCrlSize(iCrl);
CrlSizeWidth.Add(iCrl.Width);
CrlSizeHeight.Add(iCrl.Height);



public void  GetInitialFormSize() // 获得并存储窗体的初始尺寸

FormSizeWidth 
= this .Size.Width;
FormSizeHeight 
= this .Size.Height;


private void  Form1_SizeChanged( object  sender, EventArgs e)
{
//  MessageBox.Show("窗体尺寸改变");
Wcounter  = 0 ;
int  counter  = 0 ;
if  ( this .Size.Width  <  FormSizeWidth  || this .Size.Height  <  FormSizeHeight)
// 如果窗体的大小在改变过程中小于窗体尺寸的初始值,则窗体中的各个控件自动重置为初始尺寸,且窗体自动添加滚动条
{
foreach  (Control iniCrl  in  InitialCrl)
{
iniCrl.Width 
=  ( int )CrlSizeWidth[counter];
iniCrl.Height 
=  ( int )CrlSizeHeight[counter];
Point point 
= new  Point();
point.X 
=  ( int )CrlLocationX[counter];
point.Y 
=  ( int )CrlLocationY[counter];
iniCrl.Bounds 
= new  Rectangle(point, iniCrl.Size);
counter
++ ;
}
this .AutoScroll  = true ;
}
else
// 否则,重新设定窗体中所有控件的大小(窗体内所有控件的大小随窗体大小的变化而变化)
{
this .AutoScroll  = false ;
ResetAllCrlState(
this );
}


public void  ResetAllCrlState(Control CrlContainer) // 重新设定窗体中各控件的状态(在与原状态的对比中计算而来)

FormSizeChangedX 
=  ( double ) this .Size.Width  /  ( double )FormSizeWidth;
FormSizeChangedY 
=  ( double ) this .Size.Height  /  ( double )FormSizeHeight;

foreach  (Control kCrl  in  CrlContainer.Controls)

/* string name = kCrl.Name.ToString();
MessageBox.Show(name);
MessageBox.Show(Wcounter.ToString());
*/  
if  (kCrl.Controls.Count  > 0 )
{
ResetAllCrlState(kCrl); 

Point point 
= new  Point();
point.X 
=  ( int )(( int )CrlLocationX[Wcounter]  *  FormSizeChangedX);
point.Y 
=  ( int )(( int )CrlLocationY[Wcounter]  *  FormSizeChangedY);
kCrl.Width 
=  ( int )(( int )CrlSizeWidth[Wcounter]  *  FormSizeChangedX);
kCrl.Height 
=  ( int )(( int )CrlSizeHeight[Wcounter]  *  FormSizeChangedY);
kCrl.Bounds 
= new  Rectangle(point, kCrl.Size);
Wcounter
++
}


}
 
 
复制代码
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 )
            {
		//if (con is Button)	//判断是何种类型的控件(比方)
                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)
        {
     //newx,newy象征变化的比例
	    float  newx = (this.Width )/ X;
            float newy = this.Height / Y;
//当小到一定程度就不要再调用了,否则抛出异常
//if (this.Width > 300 && this.Width >300)
//            {
//                setControls(newx, newy, this);
//            }
            setControls(newx, newy, this);
            this.Text = this.Width.ToString() +" "+ this.Height.ToString();

        }

 

在Form_Load里面添加:  

this.Resize += new EventHandler(Form1_Resize);    
//form最开始时候的大小 :X,Y
X = this.Width; Y = this.Height; setTag (this); Form1_Resize(new object(),new EventArgs());//x,y可在实例化时赋值,最后这句是新加的,在MDI时有用





<think>我们正在讨论如何使C# WinForms控件窗体大小变化自动调整尺寸位置。根据引用,主要使用AnchorDock属性,同注意解决可能出现的闪屏问题。 方法总结: 1. Anchor属性:设置控件窗体边缘的距离保持不变,从而在窗体大小改变控件会按比例移动或调整大小。 2. Dock属性:将控件停靠在窗体的某个边缘或填充整个窗体,当窗体大小改变控件随之调整以保持停靠边缘的贴合。 3. 自定义调整:通过响应窗体的Resize事件,手动计算控件的新位置大小,实现更复杂的布局调整。 此外,引用[2]提到了一种解决闪屏问题的方法:设置窗体的TransparencyKey属性。 下面我将详细说明这些方法,并提供示例代码。 方法一:使用Anchor属性(适用于简单布局) 步骤: - 选择控件,在属性窗口中找到Anchor属性。 - 默认是Top, Left,即控件窗体顶部左边的距离固定。 - 可以设置Top, Bottom, Left, Right的组合。例如,设置Anchor为Top, Bottom, Left, Right,则控件会随窗体大小变化在四个方向拉伸。 方法二:使用Dock属性(适用于区域划分) - 将控件Dock属性设置为Top, Bottom, Left, Right或Fill。 - 注意:多个控件设置Dock,会按照添加顺序停靠,后添加的控件会占据剩余空间。 方法三:使用TableLayoutPanelSplitContainer(复杂布局) - 使用容器控件(如TableLayoutPanel)可以更灵活地布局。将控件放入单元格,设置单元格的Dock或Anchor属性。 方法四:在Resize事件中手动调整(最灵活) - 记录窗体初始大小控件初始位置大小。 - 在窗体的Resize事件中,计算窗体当前大小与初始大小的比例,然后按比例调整控件位置大小。 示例代码(方法四): - 定义初始窗体大小控件位置大小的变量。 - 在窗体加载记录初始值。 - 在Resize事件中计算比例,更新控件。 同,为了解决调整过程中可能出现的闪屏问题(引用[2]),可以设置窗体的双缓冲或使用TransparencyKey属性。 下面提供完整示例代码:</think># C# WinForm 控件自适应窗体大小调整指南 在C# WinForm中实现控件窗体大小自动调整尺寸位置,主要有三种方法:使用Anchor属性、Dock属性手动调整。下面我将详细说明每种方法的实现步骤最佳实践。 ## 一、Anchor属性实现自适应 Anchor属性是最简单直接的方法,它允许控件保持与窗体边缘的相对位置大小关系。 ```csharp public partial class MainForm : Form { public MainForm() { InitializeComponent(); SetupAnchor(); } private void SetupAnchor() { // 按钮固定在右下角 btnSubmit.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; // 文本框固定在左上右 txtContent.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; // 数据网格视图填充整个空间(除底部按钮区域) dataGridView1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom; // 标签固定在左上 lblStatus.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; } } ``` **Anchor属性说明**: - `Top`:保持与顶部的距离 - `Bottom`:保持与底部的距离 - `Left`:保持与左侧的距离 - `Right`:保持与右侧的距离 - 组合使用可实现多种布局效果 ## 二、Dock属性实现自适应 Dock属性允许控件"停靠"在窗体的特定边缘或填充整个窗体空间。 ```csharp public partial class MainForm : Form { public MainForm() { InitializeComponent(); SetupDocking(); } private void SetupDocking() { // 顶部菜单栏 menuStrip1.Dock = DockStyle.Top; // 左侧导航面板 panelNavigation.Dock = DockStyle.Left; panelNavigation.Width = 200; // 固定宽度 // 底部状态栏 statusStrip1.Dock = DockStyle.Bottom; // 主内容区域填充剩余空间 panelMainContent.Dock = DockStyle.Fill; // 内容区域内的控件使用Anchor txtEditor.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom; } } ``` **Dock属性使用技巧**: - 多个控件使用Dock,按添加顺序停靠 - 结合Panel容器使用效果更佳 - 设置Dock后,控件会填充所在区域 ## 三、手动调整实现复杂布局 对于更复杂的布局需求,可以在窗体的Resize事件中手动计算控件位置大小。 ```csharp public partial class MainForm : Form { // 存储初始位置大小 private Dictionary<Control, Rectangle> originalBounds = new Dictionary<Control, Rectangle>(); private Size originalFormSize; public MainForm() { InitializeComponent(); originalFormSize = this.Size; StoreOriginalBounds(); } private void StoreOriginalBounds() { originalBounds.Clear(); foreach (Control ctrl in this.Controls) { originalBounds.Add(ctrl, new Rectangle(ctrl.Location, ctrl.Size)); } } private void MainForm_Resize(object sender, EventArgs e) { if (originalBounds.Count == 0) return; float widthRatio = (float)this.Width / originalFormSize.Width; float heightRatio = (float)this.Height / originalFormSize.Height; foreach (Control ctrl in this.Controls) { if (originalBounds.ContainsKey(ctrl)) { Rectangle originalRect = originalBounds[ctrl]; // 计算新位置大小 int newX = (int)(originalRect.X * widthRatio); int newY = (int)(originalRect.Y * heightRatio); int newWidth = (int)(originalRect.Width * widthRatio); int newHeight = (int)(originalRect.Height * heightRatio); ctrl.Location = new Point(newX, newY); ctrl.Size = new Size(newWidth, newHeight); } } // 解决闪屏问题(引用[2]) this.SuspendLayout(); UpdateControlsSize(widthRatio, heightRatio); this.ResumeLayout(); this.TransparencyKey = System.Drawing.Color.LightGray; } private void UpdateControlsSize(float widthRatio, float heightRatio) { // 对特殊控件进行额外调整 // 例如:pictureBox1.Size = new Size((int)(originalSize.Width * widthRatio), ...); } } ``` ## 四、解决闪屏问题 当窗体包含大量控件,调整大小可能出现闪屏现象。以下是解决方案: ```csharp protected override void OnResizeBegin(EventArgs e) { this.SuspendLayout(); // 暂停布局更新 base.OnResizeBegin(e); } protected override void OnResizeEnd(EventArgs e) { base.OnResizeEnd(e); this.ResumeLayout(); // 恢复布局更新 this.Refresh(); // 强制重绘 } // 或者使用双缓冲技术 public MainForm() { InitializeComponent(); this.DoubleBuffered = true; // 启用双缓冲 this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true); } ``` ## 五、最佳实践总结 1. **组合使用布局方法**: - 主框架使用Dock属性 - 容器内部使用Anchor属性 - 特殊布局需求使用手动调整 2. **性能优化**: ```csharp // 批量更新控件使用 this.SuspendLayout(); // 更新多个控件... this.ResumeLayout(true); ``` 3. **使用布局容器**: - TableLayoutPanel:表格布局 - FlowLayoutPanel:流式布局 - SplitContainer:可调整区域大小的分割布局 4. **响应式设计原则**: - 设置控件最小/最大尺寸 - 使用MarginPadding控制间距 - 不同尺寸下显示不同内容 ## 六、完整示例:自适应窗体实现 ```csharp public partial class ResponsiveForm : Form { private TableLayoutPanel mainLayout; private Button btnAction; private TextBox txtContent; private DataGridView dataGrid; private StatusStrip statusBar; public ResponsiveForm() { InitializeComponent(); CreateLayout(); this.DoubleBuffered = true; // 防止闪烁 this.Resize += ResponsiveForm_Resize; } private void CreateLayout() { // 主布局面板 mainLayout = new TableLayoutPanel(); mainLayout.Dock = DockStyle.Fill; mainLayout.ColumnCount = 3; mainLayout.RowCount = 4; mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20)); mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 60)); mainLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20)); mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 40)); mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 70)); mainLayout.RowStyles.Add(new RowStyle(SizeType.Percent, 30)); mainLayout.RowStyles.Add(new RowStyle(SizeType.Absolute, 30)); // 创建控件 btnAction = new Button { Text = "执行操作", Dock = DockStyle.Fill }; txtContent = new TextBox { Multiline = true, ScrollBars = ScrollBars.Vertical }; dataGrid = new DataGridView { Dock = DockStyle.Fill }; statusBar = new StatusStrip(); // 添加控件到布局 mainLayout.Controls.Add(btnAction, 1, 0); mainLayout.Controls.Add(txtContent, 0, 1); mainLayout.SetColumnSpan(txtContent, 3); mainLayout.Controls.Add(dataGrid, 0, 2); mainLayout.SetColumnSpan(dataGrid, 3); mainLayout.Controls.Add(statusBar, 0, 3); mainLayout.SetColumnSpan(statusBar, 3); this.Controls.Add(mainLayout); } private void ResponsiveForm_Resize(object sender, EventArgs e) { // 响应式调整:小屏幕改变布局 if (this.Width < 800) { mainLayout.ColumnStyles[0].Width = 0; mainLayout.ColumnStyles[1].Width = 100; mainLayout.ColumnStyles[2].Width = 0; } else { mainLayout.ColumnStyles[0].Width = 20; mainLayout.ColumnStyles[1].Width = 60; mainLayout.ColumnStyles[2].Width = 20; } } } ``` ## 七、常见问题解决方案 1. **控件重叠问题**: - 确保使用正确的Anchor组合 - 避免同使用AnchorDock - 使用Panel容器分组控件 2. **布局错乱问题**: - 设置控件的MinimumSizeMaximumSize - 使用TableLayoutPanel固定比例 - 在Resize事件中检查边界条件 3. **性能优化**: ```csharp // 仅在实际需要更新 private void MainForm_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) return; // 更新逻辑... } ``` 通过以上方法,您可以实现各种复杂度的自适应窗体布局。根据实际需求选择合适的方法,通常组合使用Anchor、Dock手动调整可以获得最佳效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值