Динамически создаваемая проблема рендеринга PictureBox - PullRequest
1 голос
/ 10 ноября 2019

Конечной целью является играбельная игра памяти. В настоящее время я застрял в проблеме рендеринга. У меня есть следующие классы:

Поле , которое является абстрактным UserControl:

public abstract class Field : UserControl
{
    protected PictureBox _pictureBox;

    public Field()
    {
        _pictureBox = new PictureBox();
        _pictureBox.Image = Properties.Resources.empty;
        _pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
        _pictureBox.BorderStyle = BorderStyle.FixedSingle;
        this.Controls.Add(_pictureBox);
    }

    // ...
    // some abstract methods, not currently important
}

MemoryField , которое происходит от поля:

public class MemoryField : Field
{
    public MemoryField(Form parent, int xPos, int yPos, int xSize, int ySize)
    {
        _pictureBox.ClientSize = new Size(xSize, ySize);
        _pictureBox.Location = new Point(xPos, yPos);
        _pictureBox.Parent = parent;
    }

    // ...
}

И, наконец, MainForm , который является точкой входа для моего приложения:

public partial class MainForm : Form
{
    private readonly int fieldWidth = 100; // 150 no rendering problems at all
    private readonly int fieldHeight = 100;

    public MainForm() { InitializeComponent(); }

    private void MainForm_Load(object sender, EventArgs e)
    {
        for (int y = 0; y < 6; y++) // 6 rows
        {
            for (int x = 0; x < 10; x++) // 10 columns
            {
                Field field = new MemoryField(this, 
                    x * (fieldWidth + 3), // xPos, 3 is for a small space between fields
                    labelTimer.Location.Y + labelTimer.Height + y * (fieldHeight + 3), // yPos
                    fieldWidth, 
                    fieldHeight);

                this.Controls.Add(field);
            }
        }
    }
}

Вот где моя проблема: в этих for петли Я пытаюсь сгенерировать сетку 6x10 размером Field с (каждый из которых содержит PictureBox 100x100 пикселей в размере). Я делаю это почти успешно, так как мое второе поле отображается неправильно: Rendering problem with field size of 100x100 px

Единственное, что я обнаружил, что работает (полностью устраняет проблему), делает поле больше (т.е. 150px),С другой стороны, уменьшение его (т. Е. 50 пикселей) делает проблему еще больше:

Rendering problem with field size of 50x50 px


Может быть полезная информация и вещиЯ пробовал:

  • Моя MainForm AutoSize = true; с AutoSizeMode = GrowAndShrink;
  • Моя MainForm (изначально) не содержит никаких компонентов, кроме menuStrip и label
  • Я попытался изменить свойство PictureBox.Image, чтобы не работало.
  • Я попытался создать сетку только с элементами управления PictureBox (без использования Field как оболочка * 1056), что сработало .
  • Я попытался поместить labelTimer в эту "проблемную область", которая действительно решает проблему в зависимости откуда именно я это положил. (потому что расположение поля зависит от положения и высоты labelTimer)
  • Я пытался перезапустить Visual Studio 2017, не работал.

КонечноЯ мог бы просто изменить размер на 150px и двигаться дальше, но мне действительно любопытно посмотреть, в чем корень этой проблемы. Спасибо!

1 Ответ

1 голос
/ 10 ноября 2019

Самое простое, что можно сделать, чтобы решить проблему - это то, что вы уже пробовали - напрямую использовать PictureBox вместо Field. Теперь, учитывая, что вы используете Field для переноса PictureBox, вы можете наследовать от PictureBox вместо того, чтобы просто обернуть его. Изменение ваших классов на эти исправит проблему, как вы заметили:

public abstract class Field : PictureBox {

    public Field() {
        Image = Image.FromFile(@"Bomb01.jpg");
        SizeMode = PictureBoxSizeMode.StretchImage;
        BorderStyle = BorderStyle.FixedSingle;
        Size = new Size(100, 100);
    }

    // ...
    // some abstract methods, not currently important
}

public class MemoryField : Field {
    public MemoryField(Form parent, int xPos, int yPos, int xSize, int ySize) {
        ClientSize = new Size(xSize, ySize);
        Location = new Point(xPos, yPos);
    }

    // ...
}

Реальная причина, по которой он не работал, связана как с sizing , так и с позиционированием каждого Field и их подкомпонентов. Вам не следует устанавливать Location каждого _pictureBox относительно его родителя MemoryField, а вместо этого изменять Location MemoryField относительно его родителя Form.

Вам также следуетустановите размер вашего MemoryField равным размеру его дочернего элемента _pictureBox, иначе он не будет корректно соответствовать его содержимому.

public class MemoryField : Field {
    public MemoryField(Form parent, int xSize, int ySize) {
        _pictureBox.ClientSize = new Size(xSize, ySize);
        // I removed the setting of Location for the _pictureBox.
        this.Size = _pictureBox.ClientSize; // size container to its wrapped PictureBox
        this.Parent = parent; // not needed
    }
    // ...
}

и измените внутренний цикл создания на

for (int x = 0; x < 10; x++) // 10 columns
{
    Field field = new MemoryField(this,
        fieldWidth,
        fieldHeight);
    field.Location = new Point(x * (fieldWidth + 3), 0 + 0 + y * (fieldHeight + 3)); // Set the Location here instead!
    this.Controls.Add(field);
}
...