圆上的位置控件

Position controls on a circle

我正在尝试在我绘制的圆上展开面板(在我的示例中为 9 个)。

我正在使用 c# winforms。

我已经尝试了我的代码的许多变体,但我没有得到我想要的并且开始感到困惑。

最终我想要这样的东西:

我不太确定如何使用角度将面板的中心放在圆上的相应点上。 这是我的代码:

public partial class Form1 : Form
{
    List<Panel> plist = new List<Panel>();
    Rectangle circ_rect = new Rectangle();
    const int Num_Screens = 9;
    const int margin = 15;

    public Form1()
    {
        InitializeComponent();
        WindowState = FormWindowState.Maximized;
    }

    private void Generate_Panels()
    {
        for (int i = 0; i < 9; i++)
        {
            Panel p = new Panel();
            p.BackColor = Color.LightSkyBlue;
            p.Size = new Size(250, 150);
            p.BorderStyle = BorderStyle.FixedSingle;
            p.Name = "panel_" + ((i + 1).ToString());
            plist.Add(p);
        }
    }

    private void Generate_Circle()
    {
        //Create panels
        Generate_Panels();

        //Set circle coord
        Point circ_center = new Point(Width / 2, Height / 2);
        Size circ_Size = new Size(Height - margin, Height - margin);
        circ_center = new Point((circ_center.X - (circ_Size.Width  / 2)), 
                                (circ_center.Y - (circ_Size.Height / 2)));
        circ_rect = new Rectangle(circ_center, circ_Size);

        float radius = circ_Size.Width / 2;
        float angle = 0.0f;
        Point loc = Point.Empty;
        Point rect_center = Point.Empty;

        for (int i = 0; i < plist.Count; i++)
        {
            rect_center = new Point((plist[i].Width / 2), (plist[i].Height / 2));
            angle = 360 * ((i + 1f) / 9);
            loc.X = (int)(radius * Math.Cos(angle * Math.PI / 180)) + circ_center.X;
            loc.Y = (int)(radius * Math.Sin(angle * Math.PI / 180)) + circ_center.Y;

            plist[i].Location = new Point(loc.X - (plist[i].Width  / 2) + circ_rect.X,
                                          loc.Y - (plist[i].Height / 2) + circ_rect.Y);

            this.Controls.Add(plist[i]);
        }
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        e.Graphics.DrawEllipse(Pens.Red, circ_rect);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Generate_Circle();

    }
}

在直角坐标系中以r为圆心(0,0)的圆的半径,我们可以根据角度计算出a在圆上的坐标:

  • x = r * cos(degree)y = r * sin(degree)

在 C# SinCos 方法中,接受弧度,因此我们应该使用以下公式将度数转换为弧度。

  • radians = Math.PI * degree / 180.0

下一步是将笛卡尔坐标系值转换为窗体坐标值:

  • panel.X = x + center.X - panel.Width/2
  • panel.Y = center.Y - y - panel.Height/2

下一步是计算角度。您可以手动设置角度,也可以通过将角度设置为起始角度(例如 90)并添加一个值(例如 40、360/计数)作为角度的步长来计算它们。

例子

public partial class Form1 : Form {
    Rectangle circle;
    List<Panel> panels;
    List<int> angles;
    public Form1() {
        InitializeComponent();
        ResizeRedraw = true;
        angles = Enumerable.Range(0, 9).Select(x => 90 + x * 40).ToList();
        panels = Enumerable.Range(0, 9).Select(x => new Panel() {
            Size = new Size(100, 40),
            BackColor = Color.LightSkyBlue
        }).ToList();
        this.Controls.AddRange(panels.ToArray());
    }
    protected override void OnLayout(LayoutEventArgs levent) {
        base.OnLayout(levent);
        int padding = 50;
        int radius = Math.Min(ClientSize.Width, ClientSize.Height) / 2 - padding;
        Point center = new Point(ClientSize.Width / 2, ClientSize.Height / 2);
        circle = new Rectangle(center.X - radius, center.Y - radius,
             2 * radius, 2 * radius);
        for (int i = 0; i < 9; i++) {
            var x = (int)(radius * Math.Cos(Math.PI * angles[i] / 180.0)) + center.X;
            var y = center.Y - (int)(radius * Math.Sin(Math.PI * angles[i] / 180.0));
            panels[i].Left = x - (panels[i].Width / 2);
            panels[i].Top = y - (panels[i].Height / 2);
        }
    }
    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.DrawEllipse(Pens.Red, circle);
    }
}