简体   繁体   中英

How to open sub window and draw/paint the shapes in c# using abstract factory design pattern?

I am working on a simple command-line graphical application in c#. 在此处输入图像描述 Just like above, after clicking debug/run or typing run in below window, Program checks predefined syntax line by line.

        private void execute()
            {
                Output outputWindow = new Output(); //object of output window 
                compiler = new Compiler(outputWindow); //sending object of output window to compiler
                //get all text and save in lines string array
                string output = "";
                string[] lines = GetActiveEditor().Lines;
                lines = lines.Where(x => !string.IsNullOrEmpty(x)).ToArray();
                if (lines == null || lines.Length == 0)
                {
                    consoleBox.Text += "\n Error: Compiling Failed. Empty File.";
                }
                else
                {
                    foreach (var line in lines)
                    {
                        output = compiler.Compile(line);
                        consoleBox.Text += "\n" + output;
                        if (output.Contains("Error"))
                        {
                        break;
                        }
                    }

                }


            }

            private void ToolBtnDebug_Click(object sender, EventArgs e)
            {
                consoleBox.Clear();
                consoleBox.Text = " \n CPaint Compiler:- Compiling Started... \n";
                execute();
            }

    // In Compiler 

        string[] commands = { "clear", "reset", "rectangle", "circle", "triangle", "position pen", "pen draw" };
        Public string Line { get; set; }
        Public Output outputWindow;

        public Compiler(Output form)
            {
                outputWindow = form;
            }

        //checks syntax
        public bool IsSyntax(string syntax)
            {
                bool result = false;
                if (Array.Exists(commands, element => element == syntax.ToLower().Trim()))
                {
                    result = true;
                }
                return result;
            }

    //Compile class 
    public string Compile(string line)
            {
                string output = "";
                //splitting the line by comma"," and small brackets "()" and assigning into an string a`enter code here`rray
                string[] code = line.Split(',', '(', ')');
                //removing extra spaces 
                code = code.Where(x => !string.IsNullOrEmpty(x)).ToArray();
    bool checkSyntax = IsSyntax(code[0]);
                if (checkSyntax == true)
                {
                  if (code[0].Trim().ToLower().Equals("circle"))
                    {
                        try
                        {
                                int parameter1 = Int32.Parse(code[1]);
                                int parameter2 = Int32.Parse(code[2]);
                                //string shapeType = "circle";

                                ShapeFactory shapeFactory = new ShapeFactory();
                                Circle circle = shapeFactory.GetShape("circle").Shape as Circle;
                                circle.Draw(12, 12);
                                output = "command executed successfully: parameter is" + parameter1;
                                //      output = "is numeric ";
                            }

                        }
                        catch (Exception ex)
                        {

                            Console.WriteLine("Exception Message: " + ex.Message);
                            output = "\n Parameter Error : Invalid/Insufficient Parameter. \n";
                        }

                    }

In Shape Factory Method:

class ShapeFactory:AbstractFactory
{
    public override FactoryShape GetShape(string shapeType)
    {
        FactoryShape factoryShape = null;
        if (shapeType.Equals("circle"))
        {
            factoryShape = new FactoryShape(new Circle());
        }

        return factoryShape;
    }
}
        //Circle Method Code: 
            namespace CPaint.Class
            {
            class Circle
            {
                Graphics graphics;
                public void Draw(float initX, float initY)
                {
                    Output outputWindow=new Output();
                    Graphics graphics=outputWindow.outputArea.CreateGraphics();
                    outputWindow.outputArea.Image=Color.Red;
                    Pen pen = new Pen(Color.Black, 4);
                    SolidBrush brush = new SolidBrush(Color.Black);
                    graphics.FillEllipse(brush, 12, 12, 12, 12);
                    graphics.DrawEllipse(pen, 12, 12, 12, 12);
                    Console.WriteLine("ok drawing circle for you" + initX + "   " + initY);
output.show();
                }
            }
            }

This code opens two read empty output window, instead it should draw two circles in same output window. Please help, I got stuck here since three days. Thanks in Advance.

First of all, we need to improve your design.

  1. The factory pattern makes sense only if you are coding to abstraction, which means, the factory should create the concrete type, but you should not know the concrete type but only the abstract type. This is not the case in your design. You say that you are using abstract factory pattern, but you cast the created object to Circle, which is "coding to implementation".

  2. The Compiler both compiles the lines to Shapes, and executes them. A compiler should only transform text (code) into an executable object, and should not execute them. Unfortunately, with your current design, it is not possible to pass the created shapes into the output form and have them drawn.

  3. You need to pass all the compiled Shapes into your output form, and should draw in OnPaint override where the run-time is re-drawing the surface of the Control (form)

The abstraction (Shape):

public abstract class Shape
{
    public abstract void Draw(Graphics surface);
}

And the concrete types:

public class Circle : Shape
{
    public float Radius { get; set; }

    public override void Draw(System.Drawing.Graphics surface)
    {
        surface.DrawEllipse(Pens.Black, 0, 0, Radius, Radius);
    }
}

public class Rectangle : Shape
{
    public float Width { get; set; }
    public float Height { get; set; }

    public override void Draw(System.Drawing.Graphics surface)
    {
        surface.DrawRectangle(Pens.Black, 0, 0, Width, Height);
    }
}

Here is the ShapeFactory in my implementation

public class ShapeFactory
{
    public static Shape CreateShape(string shapeName, params string[] parameters)
    {
        switch (shapeName)
        {
            case "circle":
                return new Circle() { Radius = Convert.ToSingle(parameters[0]) };
            case "rectangle":
                return new Rectangle { Width = Convert.ToSingle(parameters[0]), Height = Convert.ToSingle(parameters[1]) };
            default:
                throw new NotSupportedException("shapeName");
        }
    }
}

The Compiler:

public Shape Compile(string line)
{
    string[] code = line.Split(new char[] { ',', '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
    if (IsSyntax(code[0]))
    {
        try
        {
            return ShapeFactory.CreateShape(code[0], code.Skip(1).ToArray());
        }
        catch (Exception shapeCreationException)
        {
            // Exception handling here.
            // . . .
        }
    }
    else
    {
        // Syntax Error handling here
        // . . .
    }
    return null;
}

And finally the output form:

public partial class Output : Form
{
    public List<Shape> Shapes { get; set; }

    public Output()
    {
        Shapes = new List<Shape>();
        InitializeComponent();
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        foreach (Shape shapeToDraw in Shapes)
        {
            shapeToDraw.Draw(e.Graphics);
        }
    }
}

and the execute() method:

private void execute()
{
    Output outputWindow = new Output();
    Compiler compiler = new Compiler();

    string[] lines = { "circle(24)", "rectangle(80,56)" };

    foreach (var line in lines)
    {
        try
        {
            Shape compiledShape = compiler.Compile(line);
            outputWindow.Shapes.Add(compiledShape);
        }
        catch
        {
            // Exception handling here
            // . . .
        }
    }

    outputWindow.Show();
    outputWindow.Invalidate();
}

This is tested and works.

Please comment if you don't understand something or can't get this work, but unfortunately, your case don't have a simple fix because of its design flaws.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM