2

I'm creating a silverlight application where I have to dynamically create buttons. But I need to place them in a circle around the button that I click to generate the other buttons (picture here, the buttons should go on the black line surrounding the 'test project' button)

I don't know how many buttons will be generated each time but I do know the size of each button is static. I'm not quite sure how to do this. Currently my button creation is as follows

                foreach (Item a in itemList)
                {
                    Button newButton = new Button();
                    newButton.Height = 50;
                    newButton.Width = 50;
                    newButton.Content = a.getName();
                    newButton.Click += new RoutedEventHandler(addedClick);
                    newButton.HorizontalAlignment = HorizontalAlignment.Left;
                    newButton.VerticalAlignment = VerticalAlignment.Top;
                    newButton.Margin = new Thickness(0, 0, 0, 0);
                    newButton.Style = (Style)Application.Current.Resources["RB"];
                    buttons.Add(newButton);
                }

My biggest problem is that I'm not quite sure how to get the center point of the 'test project' button.

EDIT: Okay, now that I have a set of coordinates for each button, how exactly do I go about placing them? I'm not sure how to use a canvas. I tried to set one up but it keeps acting like a stackpanel (no .setLeft/.setTop).

user2084666
  • 831
  • 3
  • 9
  • 14
  • Interesting question. My general idea would be to start by calculating the angle between each button. 4 buttons would have 90 degrees, 8 would have 45 degrees, etc. Then look into some geometry to find (try the [parametric equation](http://stackoverflow.com/a/839931/770270)), based on the angles (assuming you know the radius of the circle), the points at which the buttons should reside. – tnw May 29 '13 at 13:20

3 Answers3

3

You mean something like the circle equation:

Double distanceFromCenter = 5;
Double angleInDegrees = 90;
Double angleAsRadians = (angleInDegrees* Math.PI) / 180.0;
Double centerX = 100;
Double centerY = 100;

Double x = centerX +  Math.Cos(angleAsRadians) * distanceFromCenter;
Double y = centerY + Math.Sin(angleAsRadians) * distanceFromCenter;

that should give you a point that is distanceFromCenter units away from (centerX, center), at an angle of 90-degrees. Note this only works with radians so we have to convert to radians.

sircodesalot
  • 11,231
  • 8
  • 50
  • 83
  • Well, I know the math behind a circle, but I'm not quite sure how to apply it here. I thought about using `int X = (int)(center.X + radius * Math.Cos(angle));` to get x and y values. I'm just not sure how to correctly apply it. – user2084666 May 29 '13 at 13:23
  • Pretty much from here you just need to plug in the information. So you would tell it what center point to use, the distance from that center point, and the angle around the circle you want. If you wanted to have, say, four items in the circle, you would just divide 360-degrees by four and get 90. So you would place an item at 90, 180, 270, and 360. Just need to divide up the circle into the right number of portions at this point. Then you just place your items at the `x` and `y` values produced at the end. – sircodesalot May 29 '13 at 13:25
  • How do I get the center point? There are several of these button-generating buttons on my screen, and some of them will have been dynamically generated. I have no way of knowing what their center points will be until runtime. – user2084666 May 29 '13 at 13:30
  • If they're placed on a Canvas, you should be able to use `Canvas.GetTop(control)`/`Canvas.GetLeft(control)`. Take a look at this http://msdn.microsoft.com/en-us/library/system.windows.controls.canvas.getleft.aspx. Really it just depends on what container you're putting your controls in, but for something like this, where direct control is important, I would of course recommend using a `Canvas`. – sircodesalot May 29 '13 at 13:35
  • They currently are inside of stackpanels. But I can use a canvas, let me try this out. – user2084666 May 29 '13 at 13:36
  • You can continue to use `stackpanels` if you still feel there is some reason to continue using them, just wrap *your* control in a canvas (might even be better to separate it out into it's own `UserControl` honestly). Just make sure you set `Canvas.Left/Canvas.Top` before you try to read it using `GetLeft/GetTop` or you'll get `NaN`, or some nonsense (can't read a value until one is there). – sircodesalot May 29 '13 at 13:38
2
var radius = 100;
var angle = 360 / itmeList.Count * Math.PI / 180.0f;
var center = new Point(100, 100);

for (int i = 0; i < itemList.Count; i++)
            {
                var x = center.X +  Math.Cos(angle * i) * radius;
                var y = center.Y +  Math.Sin(angle * i) * radius;
                Button newButton = new Button();
                newButton.RenderTransformOrigin = new Point(x, y);
                newButton.Height = 50;
                newButton.Width = 50;
                newButton.Content = a.getName();
                newButton.Click += new RoutedEventHandler(addedClick);
                newButton.HorizontalAlignment = HorizontalAlignment.Left;
                newButton.VerticalAlignment = VerticalAlignment.Top;
                newButton.Margin = new Thickness(0, 0, 0, 0);
                newButton.Style = (Style)Application.Current.Resources["RB"];
                buttons.Add(newButton);
            }
Giedrius
  • 8,430
  • 6
  • 50
  • 91
1

Assuming you want your buttons evenly spaced on the circle, you should first generate the list of angles you want them at. E.g.

double eachSection = 2 * Math.PI / count;
var anglesInRadians = Enumerable.Range(0, count).Select(x => x * eachSection);

Then use this formula to find the x/y coordinates of each angle, and use a Canvas or something to position the buttons in those positions

public static Point PointOnCircle(double radius, double angleInRadians, Point origin)
{
    double x = radius * Math.Cos(angleInRadians) + origin.X;
    double y = radius * Math.Sin(angleInRadians) + origin.Y;

    return new Point(x, y);
}
Tim S.
  • 55,448
  • 7
  • 96
  • 122