Resize ALL Controls at Runtime in C# và Visual Basic 6
Khi lập trình winform, các control thường được bố trí hợp lý so với kích thước form của nó. Nhưng vấn đề là: các phần mềm mình viết ra không chỉ chạy trên mật máy tính với kích thước màn hình cố định (độ phân giải cố định) và người dùng muốn thay đổi kích thước form thì các control trên đó "bị vỡ".
A> Resize ALL Controls at Runtime in C#
Có nhiều người sử dụng : Dock và Anchor nhưng cũng có những bất tiện nhất định
Tôi đã tìm thấy trên codeproject một class trong c# có thể thực hiện việc này khá hay
1. Thêm vào chương trình của mình một calss và copy đoạn code sau:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; public class clsResize { List < System.Drawing.Rectangle > _arr_control_storage = new List < System.Drawing.Rectangle > (); private bool showRowHeader = false; public clsResize(Form _form_) { form = _form_; //the calling form _formSize = _form_.ClientSize; //Save initial form size _fontsize = _form_.Font.Size; //Font size } private float _fontsize { get; set; } private System.Drawing.SizeF _formSize { get; set; } private Form form { get; set; } public void _get_initial_size() //get initial size// { var _controls = _get_all_controls(form); //call the enumerator foreach(Control control in _controls) //Loop through the controls { _arr_control_storage.Add(control.Bounds); //saves control bounds/dimension //If you have datagridview if (control.GetType() == typeof(DataGridView)) _dgv_Column_Adjust(((DataGridView) control), showRowHeader); } } public void _resize() //Set the resize { double _form_ratio_width = (double) form.ClientSize.Width / (double) _formSize.Width; //ratio could be greater or less than 1 double _form_ratio_height = (double) form.ClientSize.Height / (double) _formSize.Height; // this one too var _controls = _get_all_controls(form); //reenumerate the control collection int _pos = -1; //do not change this value unless you know what you are doing foreach(Control control in _controls) { // do some math calc _pos += 1; //increment by 1; System.Drawing.Size _controlSize = new System.Drawing.Size((int)(_arr_control_storage[_pos].Width * _form_ratio_width), (int)(_arr_control_storage[_pos].Height * _form_ratio_height)); //use for sizing System.Drawing.Point _controlposition = new System.Drawing.Point((int) (_arr_control_storage[_pos].X * _form_ratio_width), (int)(_arr_control_storage[_pos].Y * _form_ratio_height)); //use for location //set bounds control.Bounds = new System.Drawing.Rectangle(_controlposition, _controlSize); //Put together //Assuming you have a datagridview inside a form() //if you want to show the row header, replace the false statement of //showRowHeader on top/public declaration to true; if (control.GetType() == typeof(DataGridView)) _dgv_Column_Adjust(((DataGridView) control), showRowHeader); //Font AutoSize control.Font = new System.Drawing.Font(form.Font.FontFamily, (float)(((Convert.ToDouble(_fontsize) * _form_ratio_width) / 2) + ((Convert.ToDouble(_fontsize) * _form_ratio_height) / 2))); } } private void _dgv_Column_Adjust(DataGridView dgv, bool _showRowHeader) //if you have Datagridview //and want to resize the column base on its dimension. { int intRowHeader = 0; const int Hscrollbarwidth = 5; if (_showRowHeader) intRowHeader = dgv.RowHeadersWidth; else dgv.RowHeadersVisible = false; for (int i = 0; i < dgv.ColumnCount; i++) { if (dgv.Dock == DockStyle.Fill) //in case the datagridview is docked dgv.Columns[i].Width = ((dgv.Width - intRowHeader) / dgv.ColumnCount); else dgv.Columns[i].Width = ((dgv.Width - intRowHeader - Hscrollbarwidth) / dgv.ColumnCount); } } private static IEnumerable < Control > _get_all_controls(Control c) { return c.Controls.Cast < Control > ().SelectMany(item => _get_all_controls(item)).Concat(c.Controls.Cast < Control > ()).Where(control => control.Name != string.Empty); } }
2. Trong form của mình:
public partial class Form1: Form { clsResize _form_resize; public Form1() { InitializeComponent(); _form_resize = new clsResize(this); this.Load += _Load; this.Resize += _Resize; } private void _Load(object sender, EventArgs e) { _form_resize._get_initial_size(); } private void _Resize(object sender, EventArgs e) { _form_resize._resize(); } .....................................
Như vậy khi thay đổi kích thước form thì các control cũng thay đổi theo tỷ lệ thích hợp
B> Resize ALL Controls at Runtime in Visual Basic 6
Trong Visual Basic 6 không có tính năng Dock hay Anchor và tôi cũng đã từng sử dụng một modul có tính năng tương tự: "AutoResize.bas "
1. Toàn bộ code của modul như sau:
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 FontSize As Integer End Type Private FormRecord() As ctrObj Private ControlRecord() As ctrObj Private bRunning As Boolean Private MaxForm As Long Private MaxControl As Long Private Function ActualPos(plLeft As Long) As Long If plLeft < 0 Then ActualPos = plLeft + 75000 Else ActualPos = plLeft End If End Function Private 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 Private 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) Next FormControl End Function Private 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 Private 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 ' If TypeOf inControl Is Label Or TypeOf inControl Is TextBox Then If TypeOf inControl Is Station Then ControlRecord(MaxControl).FontSize = inControl.Font.Size End If ControlRecord(MaxControl).FontSize = inControl.Font.Size End If inControl.IntegralHeight = False On Error GoTo 0 AddControl = MaxControl MaxControl = MaxControl + 1 End Function Private Function PerWidth(pfrmIn As Form) As Long Dim i As Long i = FindForm(pfrmIn) If i < 0 Then i = AddForm(pfrmIn) PerWidth = (pfrmIn.ScaleWidth * 100) \ FormRecord(i).ScaleWidth End Function Private Function PerHeight(pfrmIn As Form) As Single Dim i As Long i = FindForm(pfrmIn) If i < 0 Then i = AddForm(pfrmIn) PerHeight = (pfrmIn.ScaleHeight * 100) \ FormRecord(i).ScaleHeight End Function Private 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, lFontSize 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 If TypeOf inControl Is Label Or TypeOf inControl Is TextBox Then lFontSize = CLng((ControlRecord(i).FontSize * yRatio) \ 100) inControl.Font.Size = lFontSize 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 If FormControl.Top + FormControl.Height + 500 > MaxY Then _ MaxY = FormControl.Top + FormControl.Height + 500 If FormControl.x1 + 200 > MaxX Then _ MaxX = FormControl.x1 + 200 If FormControl.y1 + 500 > MaxY Then _ MaxY = FormControl.y1 + 500 If FormControl.x2 + 200 > MaxX Then _ MaxX = FormControl.x2 + 200 If FormControl.y2 + 500 > MaxY Then _ MaxY = FormControl.y2 + 500 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
2. Sử dụng trong form:
chỉ cần thêm đoạn code này vào trong code của form
Private Sub Form_Resize() ResizeForm Me End Sub
Hảy thử và tận hưởng thành quả.
Bình luận gần đây