在 C# 中为面板创建布局时遇到问题

Posted

技术标签:

【中文标题】在 C# 中为面板创建布局时遇到问题【英文标题】:Trouble creating a Layout for a Panel in C# 【发布时间】:2012-10-16 13:21:05 【问题描述】:

我想创建一个布局管理器,它将面板划分为多个单元格,并且可以将一个组件添加到指定单元格(行、列)的面板中。重新调整面板大小时应更新单元格的宽度和高度(这是问题所在,它不会重新调整单元格的大小)。这些类本身可以工作,但是在调整大小时不会更新单元格大小,它甚至似乎都没有调用LayoutManager::SetBounds(int, int)。我创建一个单独的类的原因是因为我将为其他容器使用相同的布局管理器,例如GroupBox。这是我的代码

public class Insets

    public int bottom = 0;
    public int top = 0;
    public int left = 0;
    public int right = 0;

    public Insets(int top, int left, int bottom, int right) 
        this.top = top;
        this.left = left;
        this.bottom = bottom;
        this.right = right;
    


/*
*  LayoutManager class
*/

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Collections.Generic;



public class LayoutManager

    public enum Constraints
        HORIZONTAL,
        VERTICAL,
        NONE
    ;

    public Insets insets = new Insets(0, 0, 0, 0);
    public Constraints fill = Constraints.NONE;
    public Panel container = null;
    public int cellheight = 1;
    public int cellwidth = 1;

    private List <int> indices = new List <int>();
    private int columns = 1;
    private int rows = 1;
    private int dh = 0;
    private int dw = 0;

    public LayoutManager()
    
    private int Index2DTo1D(int row, int column)
        return (column + (row * columns));
    
    private int Index1DToRow2D(int index)
        return index / columns;
    
    private int Index1DToColumn2D(int index)
        return index / rows;
    
    private void SetGridMatrix(int rows, int columns) 
        if (rows >= this.rows)
            this.rows = rows + 1;
        
        if (columns >= this.columns)
            this.columns = columns + 1;
        
    
    public void RepaintChildrenComponents() 
        if(container != null)
            foreach(Control control in container.Controls)
                ((CheckBox)control).Text = container.Width.ToString();
                   
        
    
    public void SetBounds(int width, int height) 
        SetCellsDimensions(width, height);
        RepaintChildrenComponents();
    
    public void SetCellsDimensions(int width, int height)
        this.dw = width / columns;
        this.dh = height / rows;
    
    public void SetContainer(ref Panel container) 
        this.container = container;
    
    public Point GetChildComponentXY(int x, int y)
        if(x >= 0 && y >= 0)
            return new Point((x * dw) + insets.right, (y * dh) + insets.top);
        
        throw new System.ArgumentOutOfRangeException("");
    
    public Size GetComputedComponentSize()
        return new Size((cellwidth * dw) - (insets.left + insets.right),
                        (cellheight * dh) - (insets.top + insets.bottom));            
    
    public void AddComponent(Control control, Point location, LayoutManager.Constraints fill)
        if(container != null && control != null)
            indices.Insert(container.Controls.Count, Index2DTo1D(location.X, location.Y));
            container.Controls.Add(SetChildComponentBounds(control, location));
            SetGridMatrix(location.X, location.Y);
            SetCellsDimensions(container.Width, container.Height);
        else
            throw new NullReferenceException("");
        
    
    protected Control SetChildComponentBounds(Control control, Point location) 
        control.Location = GetChildComponentXY(location.X, location.Y);
        control.Size = GetComputedComponentSize();
        return control;
    
    public void AddComponent(Control control, Point location)
        AddComponent(control, location, LayoutManager.Constraints.NONE);
    


/*
*
* JPanel class
*/


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;


class JPanel : Panel

    private LayoutManager layman;

    public JPanel()
        layman = new JComponent.LayoutManager();

        Panel container = this;
        layman.SetContainer(ref container);


        string[] elems =  "Multiplication", "Division", "Addition", "Subtraction";
        int e = 0;

        this.Size = new Size(300, 125);

        foreach(string str in elems)

            CheckBox box = new CheckBox();
            box.Text = str;
            layman.AddComponent(box, new Point(0, e++));
            //this.Controls.Add(box);
        

    
    public JPanel(LayoutManager layman) 
        LayoutManager = layman;
    

    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        if(layman != null)
            layman.SetBounds(width, height);
        
        base.SetBoundsCore(x, y, width, height, specified);
    
    public LayoutManager LayoutManager
        set
            layman = value;
        
        get
            return layman;
        
    

【问题讨论】:

您是否尝试创建自定义数据网格(UserControl/OwnerDraw)? 我同意上面的海报,在我看来这正是 Grid 所做的。如果您希望将 Grid 功能添加到其他控件,为什么不直接将 Grid 添加到控件子项,并按照您的需要进行设置。您可以轻松创建一个自动为您执行此操作的方法。 【参考方案1】:

请看一下 TableLayoutPanel 类。我认为这个控制正是你想要实现的。 TableLayoutPanel 允许您在表单编辑器中定义行/列,并以编程方式将控件放置在单元格内,合并行/列,根据内容自动调整面板大小或根据面板大小自动调整内容大小。

这是一个非常有趣的文档,介绍了如何在 Windows 窗体中进行布局:

https://docs.google.com/viewer?a=v&q=cache:nePz-uaPReYJ:www.windowsclient.net/samples/go%2520to%2520market/layout/layoutgtm.doc+Whidbey+Layout+tablelayoutpanel&hl=de&gl=de&pid=bl&srcid=ADGEEShlobh-RfSTegC1NuOc72m0vRPu6RsF3USTSPnSasU-9qSklTbJzclRol6Nxg5sxEUXZOWYZwgrSdZdAjJ5EXhCft7qj5jBr4-kkkX6380-0itVaHkG-TAvK4KvNtDymEFlUXM6&sig=AHIEtbTnyasKOG5tuZwub59LBw8UeZL8Lg

不幸的是,我只能通过谷歌搜索缓存找到文档。原来的链接好像被删了。

【讨论】:

以上是关于在 C# 中为面板创建布局时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中为我的控件添加移动效果?

在 Android 中为不同设备管理软底栏时遇到问题

在 Visual C# 中获取 Components 类以在面板中放置图像

更新面板textchanged问题asp.net c#

Android相对布局放置问题

如何在 C# 中为 ID3 标签编码字符串