【问题标题】:Dynamically created PictureBox rendering problem动态创建的PictureBox渲染问题
【发布时间】:2020-03-06 10:15:31
【问题描述】:

最终目标是一个有点可玩的记忆游戏。目前,我陷入了渲染问题。我有以下课程:

字段,这是一个抽象的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,派生自Field:

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 循环中,我试图生成一个Fields 的6x10 网格(每个都包含PictureBox 100x100 像素大小)。我几乎成功地做到了,因为我的第二个字段没有正确呈现:

我发现唯一有效(完全解决问题)是使字段更大(即 150 像素)。另一方面,将其缩小(即 50px)会使问题变得更大:


也许有用的信息和我尝试过的事情:

  • 我的 MainForm 是 AutoSize = true;AutoSizeMode = GrowAndShrink;
  • 我的 MainForm(最初)不包含除 menuStriplabel 之外的任何组件
  • 我尝试更改 PictureBox.Image 属性,但没有工作。
  • 我尝试仅使用 PictureBox 控件创建网格(不使用 Field 作为 PictureBox 包装器),确实工作。
  • 我尝试将labelTimer 放在那个确实解决问题的“问题区域”中,具体取决于我将它放在哪里。 (因为字段定位取决于labelTimer 的位置和高度)
  • 我尝试重新启动 Visual Studio 2017,没有工作。

当然,我可以将大小更改为 150 像素然后继续,但我真的很想知道这个问题的根源是什么。谢谢!

【问题讨论】:

  • 你为什么要这样做:_pictureBox.Parent = parent;?不要那样做。 PictureBox 应由 UserControl 处理。顺便说一句,UserControl 已经知道它的父级,它是[UC].ParentForm(继承自 ContainerControl)。至少,设置_PictureBox.BringToFront();。但你不应该,真的。
  • 我还以为是图片框中的平假名,直到我仔细观察 :) 这可能与您的用户控件无关,它是另一个控件,它隐藏了以较低 z 顺序呈现的部分内容.尝试自下而上,从右到左创建所有内容,以便将其覆盖,或者识别它是什么并将其删除(labelTimer?)除此之外,考虑派生自PictureBox(子类化)的Field -在您的控制层次结构中减少一层。
  • 这里是 IMO 不必要的抽象。将Pictureboxes 直接放在TableLayoutPanel 中即可。
  • 未设置 UserControl 的 Size 属性。这是你唯一能看到的,其他的也太大了,但是被 PictureBox 控件重叠了。
  • 谢谢大家的建议!确实,主要问题是为_pictureBox 设置大小和位置,而不是为Field 设置任何这些(如@hans-passant 所建议并在所选答案中涵盖)。我还删除了.Parent = parent,因为它不需要(@jimi 建议)。现在让我考虑TableLayoutPanel 和/或从PictureBox 派生Field 而不是包装它。再次感谢!

标签: c# .net winforms picturebox


【解决方案1】:

解决问题的最简单方法是您已经尝试过 - 直接使用 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);
    }

    // ...
}

它不起作用的真正原因与每个Field 及其子组件的sizingpositioning 有关。您不应该将每个_pictureBoxLocation 设置为相对于其父级MemoryField,而应将MemoryFieldLocation 相对于其父级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);
}

【讨论】:

  • 很好的答案!解决了我的情况,提出了更好的整体解决方案,并解释了我以前不太了解的所有内容。谢谢!
猜你喜欢
  • 2020-07-12
  • 1970-01-01
  • 2017-02-25
  • 1970-01-01
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多