所以我要做的就是从不同颜色的面板中创建一个随机图像。用户可以选择他想要的面板(即像素)数量和不同颜色的数量,然后程序自动生成该图像。我真的很想使用面板,因为我稍后需要这张图片,需要修改每一个像素。因为我对面板感到满意,所以我想保留它们,而不是使用其他任何东西。
所以这是我用来创建这个面板的代码:
//Creates two lists of panels
//Add items to list so that these places in the list can be used later.
//nudSizeX.Value is the user-chosen number of panels in x-direction
for (int a = 0; a < nudSizeX.Value; a++)
{
horizontalRows.Add(null);
}
//nudSizeY.Value is the user-chosen number of panels in y-direction
for (int b = 0; b < nudSizeY.Value; b++)
{
allRows.Add(null);
}
for (int i = 0; i < nudSizeY.Value; i++)
{
for (int j = 0; j < nudSizeX.Value; j++)
{
// new panel is created, random values for background color are assigned, position and size is calculated
//pnlBack is a panel used as a canvas on whoch the other panels are shown
Panel pnl = new Panel();
pnl.Size = new System.Drawing.Size((Convert.ToInt32(pnlBack.Size.Width)) / Convert.ToInt32(nudSizeX.Value), (Convert.ToInt32(pnlBack.Size.Height) / Convert.ToInt32(nudSizeY.Value)));
pnl.Location = new Point(Convert.ToInt32((j * pnl.Size.Width)), (Convert.ToInt32((i * pnl.Size.Height))));
//There are different types of panels that vary in color. nudTypesNumber iis the user-chosen value for howmany types there should be.
int z = r.Next(0, Convert.ToInt32(nudTypesNumber.Value));
//A user given percentage of the panels shall be free, i.e. white.
int w = r.Next(0, 100);
if (w < nudPercentFree.Value)
{
pnl.BackColor = Color.White;
}
//If a panel is not free/white, another rendom color is assigned to it. The random number determinig the Color is storede in int z.
else
{
switch (z)
{
case 0:
pnl.BackColor = Color.Red;
break;
case 1:
pnl.BackColor = Color.Blue;
break;
case 2:
pnl.BackColor = Color.Lime;
break;
case 3:
pnl.BackColor = Color.Yellow;
break;
}
}
//Every panel has to be added to a list called horizontal rows. This list is later added to a List<List<Panel>> calles allRows.
horizontalRows[j] = (pnl);
//The panel has also to be added to the "canvas-panel" pnl back. The advantage of using the canvas panel is that it is easier to determine the coordinates on this panel then on the whole form.
pnlBack.Controls.Add(pnl);
}
allRows[i] = horizontalRows;
}
正如您可能想象的那样,创建99x99的棋盘时速度非常慢,因为程序必须循环几乎10000次。
您将如何提高绩效?我说我想继续使用面板,因为我对它们很满意,但如果使用面板比我想象的更愚蠢,我会接受其他选择。它已经创建的面板越多,程序越慢越慢。我想这是因为添加到列表越来越大?
这就是输出现在的样子:
这就是我以后想要做的“图片”:我基本上想做Schellings模型。该模型显示了不同的人群(即不同的颜色)如何在他们希望周围有一定比例的人属于他们的群体时进行隔离。这意味着稍后我必须能够检查每个面板/像素邻居是什么,并且必须能够单独改变每个像素的颜色。
我不想要一个现成的解决方案,我只是希望提供如何提高图片创建过程速度的提示。
非常感谢
答案 0 :(得分:1)
使用矩阵来存储您需要的颜色和其他信息,而不是使用Panels
。
在OnPaint
事件中,使用此矩阵使用GDI+
绘制矩形。
如果你有一个包含颜色的矩阵,这是一个如何绘制10x10“像素”的例子:
private void myPanel_Paint(object sender, PaintEventArgs e)
{
for (var y=0; y < matrix.GetUpperBound(0); y++)
for (var x=0; x < matrix.GetUpperBound(1); x++)
{
var Brush = new SolidBrush(matrix[y,x]);
e.Graphics.FillRectangle(Brush, new Rectangle(x*10, y*10, 10, 10));
}
}
答案 1 :(得分:1)
使用图片框进行绘图。你已经有了代码来查看每个面板的位置,只需更改它就可以在每个位置绘制一个矩形。这样,您只需在板上绘制几个矩形,而不是使用10.000 GUI对象。
哦,保持你的模型/逻辑和视图分开。保留一个包含所有信息的矩阵,然后使用“绘制方法”绘制它。
您的模型可能如下所示:
MyPanel[,] panels;
class MyPanel
{
Color color;
}
通过这种方式,可以轻松检查面板的所有邻居,只需检查面板矩阵。
你的观点应该是这样的:
class View
{
Paint(MyPanel[,] panels)
{
//Draw
}
}
答案 2 :(得分:1)
我认为你最好的方法是编写一个自定义的Control类来绘制正方形,并使用一个自定义的集合类来保存正方形。
你的方形集合类可能如下所示:
public sealed class ColouredSquareCollection
{
readonly int _width;
readonly int _height;
readonly Color[,] _colours;
public ColouredSquareCollection(int width, int height)
{
_width = width;
_height = height;
_colours = new Color[_width, _height];
intialiseColours();
}
public Color this[int x, int y]
{
get { return _colours[x, y]; }
set { _colours[x, y] = value; }
}
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}
void intialiseColours()
{
for (int y = 0; y < _height; ++y)
for (int x = 0; x < _width; ++x)
_colours[x, y] = Color.White;
}
}
然后你编写一个自定义控件。为此,请通过Add new item -> Windows Forms -> Custom Control
添加新的自定义控件,并将其命名为ColouredSquareHolder
。
然后将代码更改为如下所示。注意它是如何负责绘制所有正方形的:
public sealed partial class ColouredSquareHolder: Control
{
ColouredSquareCollection _squares;
public ColouredSquareHolder()
{
ResizeRedraw = true;
DoubleBuffered = true;
InitializeComponent();
}
public ColouredSquareCollection Squares
{
get
{
return _squares;
}
set
{
_squares = value;
Invalidate(); // Redraw after squares change.
}
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
if (_squares == null)
return;
int w = Width;
int h = Height;
int nx = _squares.Width;
int ny = _squares.Height;
var canvas = pe.Graphics;
for (int yi = 0; yi < ny; ++yi)
{
for (int xi = 0; xi < nx; ++xi)
{
int x1 = (xi*w)/nx;
int dx = ((xi + 1)*w)/nx - x1;
int y1 = (yi*h)/ny;
int dy = ((yi+1)*h)/ny - y1;
using (var brush = new SolidBrush(_squares[xi, yi]))
canvas.FillRectangle(brush, x1, y1, dx, dy);
}
}
}
}
现在,您需要设置方形集合,将其添加到ColouredSquareHolder,然后将其添加到表单。
首先,将ColouredSquareHolder添加到您的测试程序并进行编译,以便它将显示在Windows窗体编辑器的工具箱中。
然后创建一个名为Form1
的新默认表单,并从工具箱中添加ColouredSquareHolder
,并将ColouredSquareHolder
设置为Dock-&gt;填充。对于此演示,请将其称为默认colouredSquareHolder1
。
然后将Form1类更改为:
public partial class Form1: Form
{
readonly ColouredSquareCollection _squares;
readonly Random _rng = new Random();
public Form1()
{
InitializeComponent();
_squares = new ColouredSquareCollection(100, 100);
for (int x = 0; x < _squares.Width; ++x)
for (int y = 0; y < _squares.Height; ++y)
_squares[x, y] = randomColour();
colouredSquareHolder1.Squares = _squares;
}
Color randomColour()
{
return Color.FromArgb(_rng.Next(256), _rng.Next(256), _rng.Next(256));
}
}
运行程序,看看绘制正方形的速度有多快。
希望这能为您提供可以构建的基础。
注意:如果更改方形集合中的颜色,则需要在表单中的控件上调用.Invalidate()
,以使用新颜色重绘。
答案 3 :(得分:0)
我建议您使用GDI +,您可以将颜色存储在二维数组中,这样您就可以根据它绘制所需的图像,并且您可以循环浏览它们以进行进一步处理,看一下这段代码,演示项目:
如你所说,你不熟悉gdi +,有一个演示项目,所以你可以自己查看,看看它是如何在gdi +中完成的:
Color[,] colorsTable;
Bitmap b;
Graphics g;
int size = 80; // size of table
int pixelWidth = 5; // size of each pixel
Random r = new Random();
int rand;
// CMDDraw is my Form button which draws the image
private void CMDDraw_Click(object sender, EventArgs e)
{
colorsTable = new Color[size, size];
pictureBox1.Size = new Size(size * pixelWidth, size * pixelWidth);
b = new Bitmap(size * pixelWidth, size * pixelWidth);
g = Graphics.FromImage(b);
for (int y = 0; y < size; y++)
{
for (int x = 0; x < size; x++)
{
rand = r.Next(0, 4);
switch (rand)
{
case 0: colorsTable[x, y] = Color.White; break;
case 1: colorsTable[x, y] = Color.Red; break;
case 2: colorsTable[x, y] = Color.Blue; break;
case 3: colorsTable[x, y] = Color.Lime; break;
default: break;
}
g.FillRectangle(new SolidBrush(colorsTable[x, y]), x * pixelWidth, y * pixelWidth, pixelWidth, pixelWidth);
}
}
pictureBox1.Image = b;
}