控件随窗体大小而变化

 '当窗体大小改变时,如何动态的改变控件的大小是许多VB程序员头痛的  
  '事。有的人设置窗体Resizable但却不改变控件的大小;有的人则根据控件的  
  '绝对位置与窗口大小相加减的办法来重新定位控件与改变大小,这种办法比  
  '较繁琐,且不可重用;当然也有人则限定窗口干脆不让改变。  
  '下面给出一个一劳永逸的办法,源程序如下:  
   
  Private   FormOldWidth   As   Long  
  '原始宽度  
  Private   FormOldHeight   As   Long  
  '原始高度  
   
  '在调用ResizeForm前先调用本函数  
  Public   Sub   ResizeInit(FormName   As   Form)  
  Dim   Obj   As   Control  
  FormOldWidth   =   FormName.ScaleWidth  
  FormOldHeight   =   FormName.ScaleHeight  
  On   Error   Resume   Next  
  For   Each   Obj   In   FormName  
  Obj.Tag   =   Obj.Left   &   "   "   &   Obj.Top   &   "   "   &   Obj.Width   &   "   "   &   Obj.Height   &   "   "  
  Next   Obj  
  On   Error   GoTo   0  
  End   Sub  
   
  '按比例改变表单内各元件的大小,  
  '在调用ReSizeForm前先调用ReSizeInit函数  
  Public   Sub   ResizeForm(FormName   As   Form)  
  Dim   Pos(4)   As   Double  
  Dim   i   As   Long,   TempPos   As   Long,   StartPos   As   Long  
  Dim   Obj   As   Control  
  Dim   ScaleX   As   Double,   ScaleY   As   Double  
   
  ScaleX   =   FormName.ScaleWidth   /   FormOldWidth  
  '保存窗体宽度缩放比例  
  ScaleY   =   FormName.ScaleHeight   /   FormOldHeight  
  '保存窗体高度缩放比例  
  On   Error   Resume   Next  
  For   Each   Obj   In   FormName  
  StartPos   =   1  
  For   i   =   0   To   4  
  '读取控件的原始位置与大小  
   
  TempPos   =   InStr(StartPos,   Obj.Tag,   "   ",   vbTextCompare)  
  If   TempPos   >   0   Then  
  Pos(i)   =   Mid(Obj.Tag,   StartPos,   TempPos   -   StartPos)  
  StartPos   =   TempPos   +   1  
  Else  
  Pos(i)   =   0  
  End   If  
  '根据控件的原始位置及窗体改变大小  
  '的比例对控件重新定位与改变大小  
  Obj.Move   Pos(0)   *   ScaleX,   Pos(1)   *   ScaleY,   Pos(2)   *   ScaleX,   Pos(3)   *   ScaleY  
  Next   i  
  Next   Obj  
  On   Error   GoTo   0  
  End   Sub  
   
  Private   Sub   Form_Load()  
  Call   ResizeInit(Me)   '在装入时必须加入  
  End   Sub  
   
  Private   Sub   Form_Resize()  
    Call   ResizeForm(Me)   '控件随之改变  
  End   Sub  
   
  方法二  
   
    WINDOWS下的窗口一般都可以通过鼠标拖动来扩   大,有些时候我们需要控制窗口的比例不变,以防窗口比例失调时造成界面的不协调。要做   到这一点,可以利用API函数CallWindwosProc,当得到用户调整窗口的消息时,判断X或Y方   向上的比例是否和原来的比例一样,如果不一样,则调整为一样。下面是一个例子。    
  Private   Sub   Command1_Click()  
  UnloadMe  
  EndSub  
   
  Private   Sub   Form_Load()  
  OldWindowProc=SetWindowLong(hwnd,GWL_WNDPROC,AddressOf   NewWindowProc)  
  EndSub  
   
  模块中:    
   
  Public   OldWindowProc   As   Long  
  声明API函数如下:  
  Declare   Function   CallWindowProc   Lib"user32"Alias"CallWindowProcA"(ByVal   lpPrevWndFunc   As    
  Long,ByVal   hwnd   As   Long,ByValmsg   As   Long,ByVal   wParam   As   Long,lParam   As   WINDOWPOS)As   Long  
  Declare   Function   SetWindowLong   Lib   "user32"Alias"SetWindowLongA"   (alhwnd   As    
  Long,ByValnIndex   As   Long,ByVal   dwNewLong   As   Long)As   Long  
   
  Const   GWL_WNDPROC=-4  
  定义一个窗口位置数据类型  
  Type   WINDOWPOS  
  hwnd   As   Long  
  hWndInsertAfter   As   Long  
  x   As   Long  
  y   As   Long  
  cx   As   Long  
  cy   As   Long  
  flags   As   Long  
  End   Type  
  Const   WM_WINDOWPOSCHANGING=&H46  
  Const   WM_WINDOWPOSCHANGED=&H47  
  处理窗口变化的函数  
  PublicFunctionNewWindowProc(ByVal   hwnd   As   Long,ByVal   msg   As   Long,ByVal   wParam   As    
  Long,lParam   As   WINDOWPOS)As   Long  
  Static   done_before   As   Boolean  
  Static   aspect   As   Single  
  Dim   new_aspect   As   Single  
   
  If   msg=WM_WINDOWPOSCHANGING   Then  
  If   lParam.cy>0   Then  
  保存原来的比例  
  If   Notdone_before   Then  
  aspect=lParam.cx/lParam.cy  
  done_before=True  
  End   If  
   
  new_aspect=lParam.cx/lParam.cy  
  If   new_aspect>aspect   Then  
  lParam.cy=lParam.cx/aspect  
  Else  
  lParam.cx=aspect*lParam.cy  
  End   If  
  End   If  
  End   If  
   
  NewWindowProc=CallWindowProc  
  (OldWindowProc,hwnd,msg,wParam,lParam)  
   
  End   Function  

VB窗体控件大小窗体大小变化自動調整 有时窗体变化后,如改变分辨率后控件大小却不能随之改变。手工代码调整实在麻烦,下面的模块实现自动查找窗体控件并使其改变大小以适应窗体变化。 在Form的Resize事件中调用函数Resize_All就能实现控件自动调整大小,如: Private Sub Form_Resize() Dim H, i As Integer On Error Resume Next Resize_ALL Me 'Me是窗体名,Form1,Form2等等都可以 End Sub 在模块中添加以下代码: Public Type ctrObj Name As String Index As Long Parrent As String Top As Long Left As Long Height As Long Width As Long ScaleHeight As Long ScaleWidth As Long End Type Private FormRecord() As ctrObj Private ControlRecord() As ctrObj Private bRunning As Boolean Private MaxForm As Long Private MaxControl As Long Private Const WM_NCLBUTTONDOWN = &HA1 Private Declare Function SendMessage Lib "USER32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long Private Declare Function ReleaseCapture Lib "USER32" () As Long Function ActualPos(plLeft As Long) As Long If plLeft < 0 Then ActualPos = plLeft + 75000 Else ActualPos = plLeft End If End Function Function FindForm(pfrmIn As Form) As Long Dim i As Long FindForm = -1 If MaxForm > 0 Then For i = 0 To (MaxForm - 1) If FormRecord(i).Name = pfrmIn.Name Then FindForm = i Exit Function End If Next i End If End Function Function AddForm(pfrmIn As Form) As Long Dim FormControl As Control Dim i As Long ReDim Preserve FormRecord(MaxForm + 1) FormRecord(MaxForm).Name = pfrmIn.Name FormRecord(MaxForm).Top = pfrmIn.Top FormRecord(MaxForm).Left = pfrmIn.Left FormRecord(MaxForm).Height = pfrmIn.Height FormRecord(MaxForm).Width = pfrmIn.Width FormRecord(MaxForm).ScaleHeight = pfrmIn.ScaleHeight FormRecord(MaxForm).ScaleWidth = pfrmIn.ScaleWidth AddForm = MaxForm MaxForm = MaxForm + 1 For Each FormControl In pfrmIn i = FindControl(FormControl, pfrmIn.Name) If i < 0 Then i = AddControl(FormControl, pfrmIn.Name) End If Next FormControl End Function Function FindControl(inControl As Control, inName As String) As Long Dim i As Long FindControl = -1 For i = 0 To (MaxControl - 1) If ControlRecord(i).Parrent = inName Then If ControlRecord(i).Name = inControl.Name Then On Error Resume Next If ControlRecord(i).Index = inControl.Index Then FindControl = i Exit Function End If On Error GoTo 0 End If End If Next i End Function Function AddControl(inControl As Control, inName As String) As Long ReDim Preserve ControlRecord(MaxControl + 1) On Error Resume Next ControlRecord(MaxControl).Name = inControl.Name ControlRecord(MaxControl).Index = inControl.Index ControlRecord(MaxControl).Parrent = inName If TypeOf inControl Is Line Then ControlRecord(MaxControl).Top = inControl.Y1 ControlRecord(MaxControl).Left = ActualPos(inControl.X1) ControlRecord(MaxControl).Height = inControl.Y2 ControlRecord(MaxControl).Width = ActualPos(inControl.X2) Else ControlRecord(MaxControl).Top = inControl.Top ControlRecord(MaxControl).Left = ActualPos(inControl.Left) ControlRecord(MaxControl).Height = inControl.Height ControlRecord(MaxControl).Width = inControl.Width End If inControl.IntegralHeight = False On Error GoTo 0 AddControl = MaxControl MaxControl = MaxControl + 1 End Function Function PerWidth(pfrmIn As Form) As Long Dim i As Long i = FindForm(pfrmIn) If i < 0 Then i = AddForm(pfrmIn) End If PerWidth = (pfrmIn.ScaleWidth * 100) \ FormRecord(i).ScaleWidth End Function Function PerHeight(pfrmIn As Form) As Double Dim i As Long i = FindForm(pfrmIn) If i < 0 Then i = AddForm(pfrmIn) End If PerHeight = (pfrmIn.ScaleHeight * 100) \ FormRecord(i).ScaleHeight End Function Public Sub ResizeControl(inControl As Control, pfrmIn As Form) On Error Resume Next Dim i As Long Dim widthfactor As Single, heightfactor As Single Dim minFactor As Single Dim yRatio, xRatio, lTop, lLeft, lWidth, lHeight As Long yRatio = PerHeight(pfrmIn) xRatio = PerWidth(pfrmIn) i = FindControl(inControl, pfrmIn.Name) If inControl.Left < 0 Then lLeft = CLng(((ControlRecord(i).Left * xRatio) \ 100) - 75000) Else lLeft = CLng((ControlRecord(i).Left * xRatio) \ 100) End If lTop = CLng((ControlRecord(i).Top * yRatio) \ 100) lWidth = CLng((ControlRecord(i).Width * xRatio) \ 100) lHeight = CLng((ControlRecord(i).Height * yRatio) \ 100) If TypeOf inControl Is Line Then If inControl.X1 < 0 Then inControl.X1 = CLng(((ControlRecord(i).Left * xRatio) \ 100) - 75000) Else inControl.X1 = CLng((ControlRecord(i).Left * xRatio) \ 100) End If inControl.Y1 = CLng((ControlRecord(i).Top * yRatio) \ 100) If inControl.X2 < 0 Then inControl.X2 = CLng(((ControlRecord(i).Width * xRatio) \ 100) - 75000) Else inControl.X2 = CLng((ControlRecord(i).Width * xRatio) \ 100) End If inControl.Y2 = CLng((ControlRecord(i).Height * yRatio) \ 100) Else inControl.Move lLeft, lTop, lWidth, lHeight inControl.Move lLeft, lTop, lWidth inControl.Move lLeft, lTop End If End Sub Public Sub ResizeForm(pfrmIn As Form) Dim FormControl As Control Dim isVisible As Boolean Dim StartX, StartY, MaxX, MaxY As Long Dim bNew As Boolean If Not bRunning Then bRunning = True If FindForm(pfrmIn) < 0 Then bNew = True Else bNew = False End If If pfrmIn.Top < 30000 Then isVisible = pfrmIn.Visible On Error Resume Next If Not pfrmIn.MDIChild Then On Error GoTo 0 ' ' pfrmIn.Visible = False Else If bNew Then StartY = pfrmIn.Height StartX = pfrmIn.Width On Error Resume Next For Each FormControl In pfrmIn If FormControl.Left + FormControl.Width + 200 > MaxX Then MaxX = FormControl.Left + FormControl.Width + 200 End If If FormControl.Top + FormControl.Height + 500 > MaxY Then MaxY = FormControl.Top + FormControl.Height + 500 End If If FormControl.X1 + 200 > MaxX Then MaxX = FormControl.X1 + 200 End If If FormControl.Y1 + 500 > MaxY Then MaxY = FormControl.Y1 + 500 End If If FormControl.X2 + 200 > MaxX Then MaxX = FormControl.X2 + 200 End If If FormControl.Y2 + 500 > MaxY Then MaxY = FormControl.Y2 + 500 End If Next FormControl On Error GoTo 0 pfrmIn.Height = MaxY pfrmIn.Width = MaxX End If On Error GoTo 0 End If For Each FormControl In pfrmIn ResizeControl FormControl, pfrmIn Next FormControl On Error Resume Next If Not pfrmIn.MDIChild Then On Error GoTo 0 pfrmIn.Visible = isVisible Else If bNew Then pfrmIn.Height = StartY pfrmIn.Width = StartX For Each FormControl In pfrmIn ResizeControl FormControl, pfrmIn Next FormControl End If End If On Error GoTo 0 End If bRunning = False End If End Sub Public Sub SaveFormPosition(pfrmIn As Form) Dim i As Long If MaxForm > 0 Then For i = 0 To (MaxForm - 1) If FormRecord(i).Name = pfrmIn.Name Then FormRecord(i).Top = pfrmIn.Top FormRecord(i).Left = pfrmIn.Left FormRecord(i).Height = pfrmIn.Height FormRecord(i).Width = pfrmIn.Width Exit Sub End If Next i AddForm (pfrmIn) End If End Sub Public Sub RestoreFormPosition(pfrmIn As Form) Dim i As Long If MaxForm > 0 Then For i = 0 To (MaxForm - 1) If FormRecord(i).Name = pfrmIn.Name Then If FormRecord(i).Top < 0 Then pfrmIn.WindowState = 2 ElseIf FormRecord(i).Top < 30000 Then pfrmIn.WindowState = 0 pfrmIn.Move FormRecord(i).Left, FormRecord(i).Top, FormRecord(i).Width, FormRecord(i).Height Else pfrmIn.WindowState = 1 End If Exit Sub End If Next i End If End Sub Public Sub Resize_ALL(Form_Name As Form) Dim OBJ As Object For Each OBJ In Form_Name ResizeControl OBJ, Form_Name Next OBJ End Sub Public Sub DragForm(frm As Form) On Local Error Resume Next Call ReleaseCapture Call SendMessage(frm.hwnd, WM_NCLBUTTONDOWN, 2, 0) End Sub
<think>好的,我现在要帮助用户解决C#控件窗体变化变化的问题。首先,我需要理解用户的需求。他们可能是在开发一个Windows窗体应用程序,希望控件能够根据窗体大小变化自动调整位置和尺寸,以保持界面布局的一致性。这在多分辨率或用户调整窗口大小时特别重要。 接下来,我应该考虑C#中实现这一功能的常用方法。常见的解决方案包括使用Anchor和Dock属性,或者使用布局控件如TableLayoutPanel和FlowLayoutPanel。另外,编写自定义的调整逻辑也是一种可能,但可能比较复杂,适合高级用户。 首先,Anchor属性允许控件固定在窗体的某个或多个边缘,当窗体大小改变时,控件与这些边缘的距离保持不变。例如,设置Anchor为Right和Bottom,控件会保持与右边和下边的距离,当窗体变大时,控件会向右和向下移动。而Dock属性则让控件停靠在窗体的某一边或填充整个区域,比如Dock设置为Top,控件会占据顶部并随窗体宽度变化。 然后,布局控件如TableLayoutPanel和FlowLayoutPanel可以更灵活地管理多个控件的排列。TableLayoutPanel通过行和列来定义布局,设置百分比或固定大小控件可以跨行或跨列,适应窗体变化。FlowLayoutPanel则按顺序排列控件,自动换行或调整位置,适合动态内容的情况。 可能还需要提到响应窗体的Resize事件,编写自定义调整代码,例如计算控件的位置和大小比例,但这需要更多编码工作,对于简单需求可能不太必要。 用户可能的疑问点包括如何选择Anchor和Dock的区别,或者何时使用布局控件。需要解释这两种方法的适用场景,比如Anchor适合简单的单个控件调整,而布局控件适合复杂的多控件布局。 另外,需要注意控件在调整时的重叠问题,尤其是在使用Dock属性时,停靠顺序会影响显示效果。例如,先Dock Top再Dock Bottom的控件会分别占据顶部和底部,中间的区域可能由其他控件填充。 示例部分,给出具体的代码或属性设置步骤会帮助用户更好地理解。比如,如何设置Button的Anchor属性为Right和Bottom,这样按钮会固定在右下角。或者使用TableLayoutPanel将窗体分为两列,左侧占70%,右侧占30%,并添加控件到对应的单元格中。 最后,总结不同方法的优缺点,帮助用户根据具体需求选择最合适的方案。可能还需要提醒一些常见错误,比如忘记设置Anchor导致控件位置不变,或者Dock顺序错误导致布局混乱。</think>在C#中实现控件窗体自动调整,可通过以下方法分步实现: ### 方法1:使用Anchor属性(基础方案) 1. **选中控件**:在窗体设计器中点击目标控件 2. **设置Anchor**:在属性窗口找到Anchor属性 - 点击方向按钮选择要固定的边 - 示例:设置为 `Top, Left, Right` 时 ```csharp // 代码等效设置 button1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; ``` 3. **效果**:控件会随窗体缩放保持与指定边的距离 ### 方法2:使用Dock属性(区域填充) 1. **选择停靠方式**: - Top/Bottom:垂直方向自适应宽度 - Left/Right:水平方向自适应高度 - Fill:填充剩余空间 2. **设置示例**: ```csharp panel1.Dock = DockStyle.Top; // 顶部停靠 dataGridView1.Dock = DockStyle.Fill; // 填充剩余区域 ``` ### 方法3:布局容器(推荐复杂布局) **使用TableLayoutPanel步骤**: 1. 从工具箱拖拽`TableLayoutPanel`到窗体 2. 右键面板选择"行和列"进行网格划分 3. 设置列宽类型: - Absolute:固定像素 - Percent:百分比自适应 - AutoSize:自动调整 4.控件拖入单元格并设置Dock属性 ### 方法4:响应Resize事件(自定义布局) ```csharp private void Form1_Resize(object sender, EventArgs e) { // 按比例调整控件 button1.Width = (int)(this.Width * 0.2); textBox1.Height = (int)(this.Height * 0.3); // 居中定位 panel1.Left = (this.ClientSize.Width - panel1.Width) / 2; } ``` ### ⭐最佳实践组合方案 1. **外层容器**:使用`TableLayoutPanel`划分大区块 2. **中层布局**:使用`FlowLayoutPanel`实现流式排列 3. **具体控件**:结合Anchor/Dock进行微调 4. **特殊需求**:在Resize事件中补充逻辑 ### 常见问题解决 1. **控件重叠**: - 检查Dock顺序(后添加的控件在上层) - 使用布局容器的`Controls.SetChildIndex()`调整层级 2. **闪烁问题**: ```csharp this.DoubleBuffered = true; // 启用双缓冲 SetStyle(ControlStyles.OptimizedDoubleBuffer, true); ``` ### 自适应设计原则 1. 优先使用百分比布局(列宽设为50%) 2. 关键控件设置MinSize/MaxSize限制 3. 高DPI环境下设置`AutoScaleMode = Font` 通过合理组合这些方法,可以创建出适应不同分辨率、支持窗口自由缩放的现代化C#窗体界面。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值