在 C# 中绘制形状不起作用

Drawing Shapes in C# Not Working

我有一个 C# 程序,我正在尝试为其绘制 GUI。该程序是一个二维数组,其中数组中的每个点都可以有不同类型的 Space 对象:AsteroidEmptySpaceGravityWell.

我的 SpaceProbeView class 将传递二维数组,然后在每个 space 中绘制一个小矩形,根据 Space 不同的颜色对象。

我 运行 遇到了我的程序实际上没有绘制任何东西的问题。我可以添加一个随机矩形并从 Graphics 对象中绘制它,但仅此而已。难道我做错了什么?我对 Windows 表单完全陌生。

这里是 SpaceProbeView class:

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections;

namespace SpaceProbe
{
    class SpaceProbeView : Form
    {
        private int squareSize;
        public int SquareSize
        {
            get { return squareSize; }
            set { squareSize = value; }
        }

        private Space[,] map;
        public void setMap(Space[,] aMap) { map = aMap; }

        private int mapSize;
        private int rowSize;

        public SpaceProbeView(int numberOfSpaces)
        {
            mapSize = numberOfSpaces;
            rowSize = (int)Math.Sqrt(mapSize);
            Size = new System.Drawing.Size(mapSize *5, mapSize * 5);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics graphics = e.Graphics;
            for(int row = 0; row < rowSize; row++)
            {
                for(int column = 0; column < rowSize; column++)
                {
                    graphics.FillRectangle(map[row, column].getBrush(), row * SquareSize, 
                        column * SquareSize, SquareSize, SquareSize);
                }
            }
        }
    }
}

我的Space界面是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace SpaceProbe
{
    public interface Space
    {
        SolidBrush getBrush();
    }
}

Space subclasses 之一的代码,EmptySpace(添加所有 subclasses 似乎没有必要,它们都遵循这种模式) :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;

namespace SpaceProbe
{
    class EmptySpace : Space
    {
        private static EmptySpace instance = new EmptySpace();
        public static  EmptySpace Instance
        {
            get { return instance; }
            set { }
        }

        private SolidBrush brush = new SolidBrush(Color.DeepPink);
        public SolidBrush getBrush() { return brush; }

        private EmptySpace() { }
    }
}

Map class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;

namespace SpaceProbe
{
    class Map
    {
        private Space[,] map;

        public Space[,] TheMap
        {
            get { return map; }
            set { }
        }

        public Map(int size) 
        {
            map = new Space[size, size];
            Random random = new Random();

                for (int row = 0; row < size; row++)
                {
                    for (int column = 0; column < size; column++)
                    {
                        //TODO: make this so that it enforces the right quantity of each, not just a vague percentage
                        int randomInt = random.Next(11);
                        if (randomInt <= 1)
                            map[row, column] = GravityWell.Instance;
                        else if (randomInt > 1 && randomInt <= 7)
                            map[row, column] = EmptySpace.Instance;
                        else if (randomInt > 7 && randomInt <= 10)
                            map[row, column] = Asteroid.Instance;
                    }
                }
        }
    }
}

全部 运行 在:

using System;
using System.Windows.Forms;

namespace SpaceProbe
{
    class Program
    {
        static void Main(string[] args)
        {
            Map map = new Map(10);
            SpaceProbeView view = new SpaceProbeView(100);
            view.setMap(map.TheMap);
            Application.Run(view);
        }
    }
}

这实际上是完整代码示例吗?如果是这样,那么您的问题是您从未初始化 SquareSize 属性。由于它是 0,您的矩形是空的,因此当您调用 FillRectangle().

时当然不会绘制任何内容

只要我在这里:),我也会推荐一些其他的改变。例如,以下是更惯用的 C#(不像 Java),并且还包括更好的实现实践:

class EmptySpace : Space
{
    private static readonly EmptySpace instance = new EmptySpace();
    public static EmptySpace Instance
    {
        get { return instance; }
    }

    private static readonly SolidBrush brush = new SolidBrush(Color.DeepPink);
    public SolidBrush Brush { get { return brush; } }

    private EmptySpace() { }
}

换句话说,当你有类似 属性 的语义时,你应该使用真实的属性。此外,如果不应更改某个字段,请使用 readonly 声明(类似于 Java 中的 final,至少在此上下文中)。最后,您不妨将 brush 字段设置为静态,因为即使您有多个 EmptySpace 实例(我知道,您不会),所有实例都会共享同一个画笔。

其他 Space 子 class 也是如此,包括根据需要制作 brush 字段 readonlystatic

我还会注意到 class 持有像 Brush 这样的一次性资源的 es 应该实现 IDisposable。当然,当你用完这些 classes 时,你应该释放它们。

在你的 SpaceProbeView class:

    private Space[,] map;
    public void setMap(Space[,] aMap) { map = aMap; }

同样,更好的是:

    private Space[,] map;
    public Space[,] Map
    {
        get { return map; } // avoid write-only properties
        set { map = value; }
    }

因为它同时用于行和列,所以:

    private int mapSize;
    private int rowSize;

应该是:

    private int mapSize;
    private int rowAndColumnSize;

(或类似的东西......只要明确它用于两者)

这段代码,我不是很懂:

    public SpaceProbeView(int numberOfSpaces)
    {
        mapSize = numberOfSpaces;
        rowSize = (int)Math.Sqrt(mapSize);
        Size = new System.Drawing.Size(mapSize *5, mapSize * 5);
    }

我以为我看懂了mapSizerowSize的初始化,后来看到了Size的初始化。 5 是从哪里来的?为什么您的表单大小是空格总数的 5 倍,而不仅仅是任一维度(行或列)中的空格数?

考虑到用法,我会直接将 map 对象传递给构造函数。只要调用者为 numberOfSpaces 传递有效值,您在此处的代码就可以工作,但您实际上没有任何方法可以确保它与稍后设置的 map 对象的实际尺寸相匹配。

如果您传递 map 对象本身,则可以简单地从该对象中检索行和列维度,您甚至不必要求调用者传递方形地图。在那种情况下,您可能会完全摆脱 mapSize 变量;根本不清楚你为什么要拥有它。