Windows 将多个控件合二为一

Posted

技术标签:

【中文标题】Windows 将多个控件合二为一【英文标题】:Windows Forms Multiple Controls In One 【发布时间】:2021-02-18 07:07:37 【问题描述】:

我想请教一些建议。我在 Windows 窗体编程方面没有足够的经验,所以我不知道处理此任务的适当方法是什么。

我目前正在从四个面板创建一个矩形。 (这些矩形不代表下面的代码,它们使用不同的大小)

private System.Windows.Forms.Panel rectangleLeftVertical;
private System.Windows.Forms.Panel rectangleRightVertical;
private System.Windows.Forms.Panel rectangleTopHorizontal;
private System.Windows.Forms.Panel rectangleBottomHorizontal;

// ...

this.rectangleLeftVertical.Location = new System.Drawing.Point(100, 100);
this.rectangleLeftVertical.Size = new System.Drawing.Size(3, 100);

this.rectangleRightVertical.Location = new System.Drawing.Point(200, 100);
this.rectangleRightVertical.Size = new System.Drawing.Size(3, 100);

this.rectangleTopHorizontal.Location = new System.Drawing.Point(100, 100);
this.rectangleTopHorizontal.Size = new System.Drawing.Size(100, 3);

this.rectangleBottomHorizontal.Location = new System.Drawing.Point(100, 200);
this.rectangleBottomHorizontal.Size = new System.Drawing.Size(103, 3);

它完全按照我的意愿工作,我只想将所有内容封装到一个自定义 Windows 控件中。 自定义组件大小当然应该调整面板的大小。它还有一个属性来决定边框的大小。

我不想改变任何东西,我不想以不同的方式进行绘图(使用 graphics.paint 解决方案)。它不适合我的用例。

我尝试使用 UserControl,但是它不合适,因为它会绘制矩形的整个内部 - 这是我要避免的。

如果它也可以在 Windows 窗体设计器中使用,那就更好了 - 但这是非常不必要的。不过那真的很好。

你们建议我如何解决这个问题?任何帮助将非常感激。这可能不是一个难题,我只是缺乏经验。谢谢!

【问题讨论】:

当你说绘画时,你的意思是面板被重新绘画以响应调整大小事件? 如果你需要一条不同颜色的线你会怎么做?像你这样画线非常效率低下,我怀疑你有支持你的“用户案例”的论据,而且你已经遇到了处理背景的问题。 @RossBush 我不确定你指的是什么。我需要矩形的内部完全透明,因为我有另一个进程停靠在它下面的面板上 - 因此使用任何类型的 Color.Transparent 都不起作用(它将隐藏边框内的内容)。 控件使用完全相同的“缓慢且非常闪烁”技术重新绘制自己。换句话说,您不是在快速绘制线条,而是在创建另一个窗口,所有开销(事件循环、内存、资源)都......绘制线条。无意冒犯,我试图说服您编写自定义控件(就像我之前评论中的那个),为其添加属性并正确进行。 这个问题可能会导致xy problem 【参考方案1】:

您可以通过创建一个表示您要保留/丢弃的表单区域的 GraphicsPath 对象来实现此目的。从覆盖整个表单的矩形开始,然后删除面板的中间部分,只留下边框。然后从该 GraphicsPath 构建一个 Region 并将其分配给 Form 的 Region 属性。这将产生一个仅存在于边框所在的表单。从 GraphicsPath 中删除的中间区域在您的表单中实际上将不存在,因此覆盖下方的任何内容都将直接显示。

这里有一个简单的例子,它制作了一个可以通过窗格的边框拖动的四窗格“窗口”:

public partial class Form1 : Form


    public Form1()
    
        InitializeComponent();
        this.TopMost = true;
        this.BackColor = Color.Red; // just so you can see it better
        this.FormBorderStyle = FormBorderStyle.None;
    

    private void Form1_Shown(object sender, EventArgs e)
    
        GraphicsPath path = new GraphicsPath();
        // add the main rectangle:
        path.AddRectangle(new Rectangle(new Point(0, 0), this.Size));
        // punch some holes in our main rectangle
        // this will make a standard "windowpane" with four panes
        // and a border width of ten pixels
        Size sz = new Size((this.Width - (3 * 10))/2, (this.Height - (3 * 10))/2);
        path.FillMode = FillMode.Alternate;
        path.AddRectangle(new Rectangle(new Point(10, 10), sz));
        path.AddRectangle(new Rectangle(new Point(20 + sz.Width, 10), sz));
        path.AddRectangle(new Rectangle(new Point(10, 20 + sz.Height), sz));
        path.AddRectangle(new Rectangle(new Point(20 + sz.Width, 20 + sz.Height), sz));
        // build a region from our path and set the forms region to that:
        this.Region = new Region(path);
    

    public const int HTCAPTION = 0x2;
    public const int WM_NCHITTEST = 0x84;
    public const int HTCLIENT = 1;
    protected override void WndProc(ref Message m)
    
        base.WndProc(ref m);

        if (m.Msg == WM_NCHITTEST)
        
            if (m.Result.ToInt32() == HTCLIENT)
                m.Result = (IntPtr)HTCAPTION;
        
    


在我编辑时在此页面顶部运行的示例:

如果您的叠加层可以调整大小和/或调整,只需重建一个新的 GraphicsPath,更改矩形并重新分配从新 GraphicsPath 构建的区域。

您也可以删除主窗体的.Opacity,这样您就可以看到部分边框了。

【讨论】:

太棒了!这比我想要的还要好。非常感谢!我在 UserControl 而不是单独的表单中使用它,这当然也适用于相同的逻辑。竖起大拇指?

以上是关于Windows 将多个控件合二为一的主要内容,如果未能解决你的问题,请参考以下文章

将随机颜色分类为一种原色 Windows Phone

具有多个页面的 Windows Phone 8.1 自定义控件

我可以在 Windows Phone 8 的 Web 浏览器控件中显示多个选择单词的选项吗?

将 WPF 控件放入 Windows 窗体窗体?

如何在windows窗体里面添加窗口

C# wpf Frame 实现一次加载多个page