【问题标题】:How do I use winforms with abstract class如何使用带有抽象类的winforms
【发布时间】:2021-07-20 13:27:09
【问题描述】:

我有一个抽象类“元素”,它的实例必须使用 System.Drawing 中的函数 DrawRectangle()。 问题是因为这个类是抽象的,所以它不能从 FORM 继承,所以程序不能识别这些类。 我该如何解决这个问题? 我尝试在 Element 中放置一个 Form 类型的变量,但没有成功。 我也尝试了相反的方法,将一个 Element 变量放在 Form 中。 这是我第一次使用 Winform 和 C#... 它应该是一个鼠标竞赛游戏,页面中绘制的对象应该是追逐鼠标或向其他方向移动,但我需要它是面向对象的。

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace MyMouseGame
{
    public abstract class Element
    {
        //Form1 myForm = new Form1();// not sure I need it
        public enum EnumShape { Square, Circle, Triangle }
        public enum EnumType { Chase, Escape, Random }

        //variables
        private double X { get; set; }
        private double Y { get; set; }
        private int Size { get; }
        private int Speed { get; }
        private EnumShape Shape { get; set; }
        protected EnumType Type { get; set; }

        private static Random R = new Random();

        //methods

        public int generateRandomNum()
        {
            int randomNum = R.Next(20, 100);
            return randomNum;
        }

        public Element()
        {
            X= 0;
            Y = 0;
            Shape = 0;
            Size = generateRandomNum();
            Speed = generateRandomNum();
            Type = 0;
        }

        public void ElementsFactory()
        {

        }

        public void hitTarget(e) { }
        public abstract void Draw(Form1 g); //here I tried to pass a form inside 
        public abstract void Move();
    }
}

//example of one of the instances classes of element
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;


namespace MyMouseGame
{
    class E_Escape : Element
    {
        int move_circleX = 0;
        int move_circleY = 0;

        bool flag = false;

        Rectangle circle = new Rectangle(10, 70, 35, 35);
        Pen p = new Pen(Color.Black);

        //circle
        public E_Escape()
        {
        }
        public override void Draw(Form1 g) {
            g.DrawEllipse(p, circle);
            g.FillEllipse(new SolidBrush(Color.Red), circle);
        }

        public override void Move() {
            if (!flag)
            {
                if (circle.X >= panel1.Width - 2)
                    flag = true;
                circle.X += 10;
            }
            else
            {
                if (circle.X <= 30)
                    flag = false;
                circle.X -= 10;
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;


namespace MyMouseGame
{
    public partial class Form1 : Form
    {
        Graphics g;
        Element [] elements= new Element[3];

        public Form1()
        {
            this.DoubleBuffered = true;
            InitializeComponent();
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
    
            g = panel1.CreateGraphics();

            //timer set
            t.Interval = 100;
            t.Tick += new EventHandler(timer1_Tick);
            t.Start();

        }

        private void recThreadTracker()
        {
            //move rectangle
            while (true)//here I tried to call element finction draw
            {
                elements[0].Draw(g);
                elements[1].Draw(g);
                elements[2].Draw(g);
            }
        }

        public void threadCounter()
        {
            long counter = 0;
            while (true)
            {
                counter++;
                this.Invoke(new Action(() =>
                {
                    lcountRes.Text = counter.ToString();
                }));
                Thread.Sleep(1000);
            }
        }
        private void Form1_Load(object sender, EventArgs e)
        {
          
           

        }

        private void button1_Click(object sender, EventArgs e)
        {
            Thread counterThread = new Thread(threadCounter);
            counterThread.Start();
            Thread recTrackThread = new Thread(recThreadTracker);
            recTrackThread.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            foreach (Element elements in elements)
            {
                elements.Move();
            }

            //Refresh();
            Invalidate();
        }
    }
}

【问题讨论】:

  • Element 不需要是抽象的,不是吗?
  • 我认为它确实是因为它本身并没有实现它的方法,但它的“孩子”做
  • 表单类不需要继承自Element - 它需要传递具体实例才能进行绘制。
  • g = panel1.CreateGraphics(); Paint 事件应该使用 e.Graphics 参数。另外:如果您想要持久图形,切勿尝试缓存 Graphics 对象。 - 另外:t.Tick += new EventHandler(timer1_Tick); 这会在每次 Paint 调用时添加另一个 Tick 调用。肯定不是你想要的。
  • 从不尝试缓存 Graphics 对象是什么意思?另外: e.CreateGaphics() 无法识别创建图形方法。该怎么办?另外:如果我想绘制不同的元素,我应该在不同的线程中进行吗?非常感谢

标签: c# winforms oop abstract-class factory


【解决方案1】:

绘图例程需要两件事。一个Graphics对象,以及绘图区的Size

例如,在图形区域的中心画一个圆

public void Draw(Graphics g, Size target)
{
    int diameter = 16;
    g.DrawEllipse(Pens.Black, target.Width/2 - diameter/2, target.Height/2 - diameter/2, diameter, diameter);
}

然后在表单的绘制事件中调用所有的绘制函数

void panel1_Paint(object sender, PaintEventArgs e)
{
    foreach(var item in Elements)
    {
        item.Draw(e.Graphics, pictureBox1.ClientSize);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-09
    • 2021-02-13
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多