Hi everyone. :?:

I have a big problem. I have different classes: Square, Circle, Star, Triangle. They allow me to draw figures on the picturebox. I have different buttons on my form. Example button "Circle" works like that:

Circle circle = new Circle();
      list.Add(circle);  
      circle.Draw(this.pictureBox1, circle.mypen, circle.pos, circle.num);

When I create a new object I store it in list:

static public List<Object> list = new List<Object>();

And here is the problem:
When I do smth (move, spin) with figures I need to redraw them again. I have an example how to draw circles:

foreach (Object elem in list)
      {                     
        Circle gh1 = elem as Cirlce;
        gh1.Draw(pictureBox1, gh1.mypen, gh1.pos, gh1.num);
      }

And it draws circles on the picturebox. The problem is that my list has 4 types of figures. So, I need to get the type of the current object in list and call method for it. Because all figures have different methods of drawing. When I create

Object obj = elem as Object;
        obj.Draw(pictureBox1,obj.mypen,obj.pos,obj.num);

Compiler say that there is no method Draw() for obj. I don't know how to make it possible to analyze type of object automatically and call appropriate method.

Can you help me please? How to realize it? I am newbie to C#.
Thank you for your help.

Recommended Answers

All 8 Replies

Check out Interfaces.
You can have a list of Interface elements that will let you define a required Draw() method.
Anything that goes in the list will have a Draw() method and will be referenced as the interface type itself.

Check out this thread:

Thank you for your help. Sorry for answering so late.

Sounds like polymorphism and base class inheritance may be your friend here, although using interfaces is just as valid. If you need any help with these concepts, post your specific questions here =)

Check this out.

foreach (Object elem in list)
    {
    if(elem == "Circle")
    {
    Circle gh1 = elem as Cirlce;
    gh1.Draw(pictureBox1, gh1.mypen, gh1.pos, gh1.num);
     }
     else if (elem == "Square")
     {
     Square gh2 = elem as Square;
     gh2.Draw(..., ..., ,...);
     }
    }

This, for some reason makes more sense:

public abstract class Shape
    {
        protected int x;
        protected int y;
        protected int size;
        public abstract void Draw(Graphics gr, Pen p);
        public Shape(int iX, int iY, int iSize)
        {
            size = iSize;
            x = iX;
            y = iY;
        }
    }
    public class Circle : Shape
    {
        public override void Draw(Graphics gr, Pen p)
        {
            gr.DrawEllipse(p, x, y, size, size); 
        }
        public Circle(int iX, int iY, int iSize)
            : base(iX, iY, iSize)
        {
        }
    }
    public class Square : Shape
    {
        public override void Draw(Graphics gr, Pen p)
        {
            gr.DrawRectangle(p, x, y, size, size);
        }
        public Square(int iX, int iY, int iSize)
            : base(iX, iY, iSize)
        {
        }
    }

And to draw a list of these shapes:

foreach (Shape s in myShapeList)
   s.Draw(myGraphics, myPen);
commented: a very good example +10
commented: good explanation +1

Thank you for your code. But maybe that it is not the right example: :-/

Just let's take this part:

foreach (Object elem in list)
    {
      if(elem == "Circle")
      {
        Circle gh1 = elem as Cirlce;
        gh1.Draw(pictureBox1, gh1.mypen, gh1.pos, gh1.num);
      }
    }

Here you offering to compare "elem" which has type Object with type String? Is it possible?
I mean I checked and nothing happened. There is warning: Possible unintended reference comparison; to get a value comparison, cast the left hand side to type 'string'. Well,
you sure that it will work? Maybe in other case?

Hope to get your explanation because I am newbie to C#.

Thank you for attending. ;)

Thank you for your great example. It looks like my program. :icon_cool:

But there is one problem. I don't have constuctors for x,y, size. So, when I call method for object Circle he generates numbers randomly for this type. One more thing I have Draw method as virtual. Will it differentiate from your example?

Thank you for your help.
Hope to hear from you.:?:

Thank you for your great example. It looks like my program. :icon_cool:

But there is one problem. I don't have constuctors for x,y, size. So, when I call method for object Circle he generates numbers randomly for this type. One more thing I have Draw method as virtual. Will it differentiate from your example?

Thank you for your help.
Hope to hear from you.:?:

Methods marked as Abstract in the base class MUST be overridden in derived classes (since there is no body for it in the abstract class), where as methods marked as Virtual CAN be overriden, but a body must be defined in the base class. For this purpose, I would use abstract over virtual (since you are not able to draw a shape since it is an abstract class) but either will do if implemented correctly.

If you want the coordinates to be generated randomly:

public abstract class Shape
    {
        const int X_MAX = 100  //Hardcode your maximums here
        const int Y_MAX = 100
        const int SIZE_MAX = 50
        protected int x;
        protected int y;
        protected int size;
        public abstract void Draw(Graphics gr, Pen p);
        public Shape()
        {
            Random r = new Random((int)DateTime.Now.Ticks);  //Init a random object, seeded with a number that should be different every time a class is instantiated
        
            size = r.Next(SIZE_MAX);
            x = r.Next(X_MAX);
            y = r.NEXT(Y_MAX);
        }
    }
    public class Circle : Shape
    {
        public override void Draw(Graphics gr, Pen p)
        {
            gr.DrawEllipse(p, x, y, size, size); 
        }
        public Circle()
        {
        }
    }
    public class Square : Shape
    {
        public override void Draw(Graphics gr, Pen p)
        {
            gr.DrawRectangle(p, x, y, size, size);
        }
        public Square()        
        {
        }
    }

Note that it is much more robust to leave the constructors intact and just generate the random numbers when you call them.

Consider yourself lucky, I don't normally write this much code for people on here lol.

To address arunkumars post - instead of using if (elem == "circle") use if (elem is Circle) . Note that using 'is' implies that you want to RTTI the object type. This can be a fairly costly thing to do performance wise, so don't make a habit out of it (instead, use polymorphism like I showed you :) )

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.