2

だから私がやろうとしているのは、さまざまな色のパネルからランダムな画像のように作成することです. ユーザーは、必要なパネル (つまりピクセル) の数と異なる色の数を選択でき、プログラムがその画像を自動的に生成します。後でこの画像が必要になり、すべてのピクセルを変更する必要があるため、これにはパネルを使用したいと思います。私はパネルに慣れているので、パネルをそのままにして、他のものは使用したくありません。

したがって、このパネルを作成するために使用しているコードは次のとおりです。

//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 回ループする必要があるため、これは非常に遅くなります。

パフォーマンスを向上させるために何をしますか? 私はパネルに慣れているので、パネルでやり続けたいと言いましたが、パネルを使用するのが思ったよりも馬鹿げている場合は、他のオプションを受け入れることができます. プログラムは、作成済みのパネルが増えるほど遅くなります。それは、リストに追加することで、ますます大きくなったためだと思いますか?

現在の出力は次のようになります。 取り消し線の部分はまだ重要ではありません

これは、後で「写真」でやりたいことです。基本的には、シェリング モデルを実行したいと考えています。このモデルは、自分のグループに属している特定のパーセンテージの人々を周囲に持ちたい場合に、さまざまなグループ (つまり、さまざまな色) がどのように分離されるかを示しています。つまり、後で各パネル/ピクセルの隣にあるものを確認し、各ピクセルの色を個別に変更できるようにする必要があります。

すぐに解決できる解決策は必要ありません。画像作成プロセスの速度を向上させるためのヒントが欲しいだけです。

どうもありがとうございました

4

4 に答える 4

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追加し、を Dock->Fill に設定します。このデモンストレーションではデフォルトのままにしておきます。ColouredSquareHolderColouredSquareHoldercolouredSquareHolder1

次に 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()、フォーム内のコントロールを呼び出して、新しい色で再描画する必要があります。

于 2013-05-18T10:21:49.383 に答える
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));
        }
}
于 2013-05-18T08:26:53.447 に答える
0

代わりにGDI +を使用することをお勧めします。色を2次元配列に保存できるため、それに基づいて目的の画像を描画できます。また、それらをループしてさらに処理することもできます。このコードとデモプロジェクトを見てください:

あなたが gdi+ に慣れていないと言ったように、デモプロジェクトが含まれているので、自分でチェックして gdi+ でどのように行われるかを確認できます:

デモ プロジェクト: ColorsTableDemoProject

    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;
    } 
于 2013-05-18T08:48:00.847 に答える