Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows Forms: What's the right way to allow overlapping Controls?

I'm making a test program to see how well I can add events to a custom drawn System.Windows.Form.Control object. Should I do well with this, then I can make something more advanced for later.

The issue I'm having deals with the attached image. I have drawn two circles purposefully close to each other. The goal is to have one circle overlap another. For the purpose of this test program, I do not care which circle overlaps which. I do, however, care about the corners.

Wish that the two circles just overlapped properly instead of having the jutting corners.

The image above shows that the center circle is buried by the left circle, but the left circle is also drawing the corners and covering the center circle with them. I'm hoping to hide those corners, or at least make them transparent. I did read that there is a way to make a control transparent, but using Color.Transparent on the BackColor was giving me black for some reason instead of matching up with the paint panel's color.

Below is the code part of the GUI (the designer is not included, but the key parts should be obvious).

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) });
        }
    }
}

Below is the custom circle.

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);
        }
    }
}

With this information in mind, how do I either get the corners of the circles to not show, or find a way to work around this?

like image 474
Wolfman2000 Avatar asked Dec 27 '12 02:12

Wolfman2000


1 Answers

OK just put in a mainform form1, doesn't need any code. Here is code for the usercontrol, Draw 3 or 4 on the form so they can overlap if they move to the right.

Then click on them! There are inefficiencies, but the baby's crying and I have to go, and it beats making your own retained object editor!

enter image description here

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
like image 194
FastAl Avatar answered Oct 23 '22 08:10

FastAl