【问题标题】:Windows Forms: What's the right way to allow overlapping Controls?Windows 窗体:允许重叠控件的正确方法是什么?
【发布时间】:2012-12-12 11:47:29
【问题描述】:

我正在制作一个测试程序,看看我可以如何将事件添加到自定义绘制的 System.Windows.Form.Control 对象。如果我把这个做得好,那么我可以在以后做一些更高级的东西。

我遇到的问题与附加图片有关。我有目的地画了两个圆圈,它们彼此靠近。目标是让一个圆圈与另一个圆圈重叠。为了这个测试程序的目的,我不在乎哪个圆圈与哪个圆圈重叠。但是,我确实关心角落。

上图显示中心圆被左圆掩埋,但左圆也在画角并用它们覆盖中心圆。我希望隐藏这些角落,或者至少让它们透明。我确实读到有一种方法可以make a control transparent,但是由于某种原因在 BackColor 上使用 Color.Transparent 给了我黑色,而不是与油漆面板的颜色相匹配。

下面是GUI的代码部分(不包括设计器,但关键部分应该很明显)。

namespace PaintingFirstAttempt
{
    using System;
    using System.Drawing;
    using System.Windows.Forms;

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void BtnExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void BtnClear_Click(object sender, EventArgs e)
        {
            Graphics g1 = this.paintPanel.CreateGraphics();
            g1.Clear(this.paintPanel.BackColor);
            g1.Dispose();
        }

        private void PaintPanel_MouseDown(object sender, MouseEventArgs e)
        {
            this.paintPanel.Controls.Add(new EventableCircle { Location = new Point(e.X - 16, e.Y - 16), Size = new Size(32, 32) });
        }
    }
}

下面是自定义圈子。

namespace PaintingFirstAttempt
{
    using System;
    using System.Drawing;
    using System.Windows.Forms;

    public class EventableCircle : Control
    {
        public EventableCircle()
        {
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            // this.BackColor = Color.Transparent;
        }

        private static SolidBrush fillColor = new SolidBrush(Color.Red);
        protected override void OnClick(EventArgs e)
        {
            MessageBox.Show("TODO: Bring up a combo box on right click.");
        }

        private void DrawCircle(Pen pen)
        {
            Graphics g = this.CreateGraphics();
            g.Clear(this.BackColor);
            g.FillRectangle(new SolidBrush(Color.Transparent), 0, 0, 32, 32);
            g.FillEllipse(fillColor, 0, 0, 32, 32);
            g.DrawEllipse(pen, 0, 0, 32, 32);
            g.Dispose();

        }

        protected override void OnPaint(PaintEventArgs e)
        {
            this.DrawCircle(Pens.Black);
        }

        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            this.DrawCircle(Pens.Blue);
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            this.DrawCircle(Pens.Black);
        }
    }
}

考虑到这些信息,我如何才能让圆圈的角不显示,或者找到解决此问题的方法?

【问题讨论】:

  • 这应该会有所帮助:c-sharpcorner.com/UploadFile/mahesh/… - 还可以考虑保留坐标列表以检测点击和重绘图形对象,而不是从 Control 派生
  • 我不理解您的评论 Jeremy。首先,即使不使用图像,该链接也会起作用吗?我现在仍然希望从头开始生成。其次,列出坐标究竟有什么好处?你是在建议我只在我围成一圈时计算?
  • 我应该更清楚。使用内存中的坐标列表绘制红色圆圈比创建一堆 Red-Circle UserControl 更有效。看来您只需要绘制图形对象,然后就能够检测并响应点击事件。我认为这也是问题所在,在控件中绘制对象失去了对透明度的控制,这就是为什么我建议将它们视为图形对象的原因。进一步阅读C# Graphic Programming with Rod Stephens.
  • ...这就是首先设计简单应用程序的问题。我不会争辩说,让他们自己控制简单的圆圈可以提高记忆力。如果我想将更多项目绘制到圆圈中,或者如果我想调用转换,那么相同的坐标技术会起作用吗?
  • 如果您在 @JeremyThompson 那里,我想授予您批准的复选标记,但您需要在此处输入您所说的作为单独的答案。

标签: c# winforms controls


【解决方案1】:

好的,只需放入一个主窗体form1,不需要任何代码。这是用户控件的代码,在窗体上绘制 3 或 4,以便它们向右移动时可以重叠。

然后点击它们!有效率低下,但是宝宝哭了我要走了,还不如自己做保留对象编辑器!

Public Class linectl   

    Public Sub DrawMe(ByVal g As Graphics, ByVal otherctl As Control)
        Dim where As New Rectangle(otherctl.Left - Left, otherctl.Top - Top, otherctl.Width - 1, otherctl.Height - 1)
        g.FillEllipse(Brushes.Red, where)
        g.DrawEllipse(Pens.Black, where)
    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaintBackground(e)
        DrawMe(e.Graphics, Me)
        drawneighbors()
    End Sub

    Private Sub linectl_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click
        Me.Left += 10
    End Sub

    Private Sub linectl_MoveResize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Move, Me.Resize
        If Parent IsNot Nothing Then
            For Each c In From ctl In Parent.Controls Where TypeOf ctl Is linectl Select CType(ctl, linectl)
                Using g = c.CreateGraphics
                    g.Clear(c.BackColor)
                    c.DrawMe(g, c)
                    c.drawneighbors()
                End Using
            Next
        End If
    End Sub

    Public Sub drawneighbors()
        If Parent IsNot Nothing Then
            Dim ctls = (From ctl In Parent.Controls Where TypeOf ctl Is linectl Let c = CType(ctl, linectl) _
                        Select New With {.ctl = c, _
                            .rect = New Rectangle(c.Left, c.Top, c.Width, c.Height)}).ToArray.Reverse
            For Each ctl In ctls
                Dim ctl_unclosed = ctl
                For Each ictl In (From c In ctls Where ctl_unclosed.rect.IntersectsWith(c.rect))
                    Using g = ictl.ctl.CreateGraphics
                        ictl.ctl.DrawMe(g, Me)
                    End Using
                    Using g = Me.CreateGraphics
                        Me.DrawMe(g, ictl.ctl)
                    End Using
                Next
            Next
        End If
    End Sub

End Class

【讨论】:

    猜你喜欢
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    相关资源
    最近更新 更多