The end goal is a somewhat playable memory game. Currently, I'm stuck on a rendering problem. I have the following classes:
Field, which is an abstract 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, which derives from 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;
}
// ...
}
And finally, MainForm which is an entry point for my application:
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);
}
}
}
}
Here's where my problem lies:
In those for
loops I'm trying to generate a 6x10 grid of Field
s (with each containing a PictureBox
100x100 px in size). I do that almost successfully, as my second field is not rendered correctly:
Only thing I found that works (fixes the problem completely) is making field bigger (i.e. 150px). On the other hand, making it smaller (i.e. 50px) makes the problem even bigger:
Maybe useful information and things I've tried:
AutoSize = true;
with AutoSizeMode = GrowAndShrink;
menuStrip
and label
PictureBox.Image
property, that didn't work.PictureBox
controls (not using Field
as a PictureBox
wrapper), that did work.labelTimer
in that "problematic area" which does fix the problem depending on where exactly I put it. (because field positioning depends on labelTimer
's position and height)Of course, I could just change the size to 150px and move on, but I'm really curious to see what's the root of this problem. Thanks!
The easiest thing to do to fix the problem is something you've already tried - using directly a PictureBox
instead of a Field
. Now, considering that you only use Field
to wrap a PictureBox
, you could inherit from PictureBox
instead of just wrapping it.
Changing your classes to these will fix the issue as you've noticed:
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);
}
// ...
}
The real reason it was not working has to do with both sizing and positioning of each Field
and their subcomponents. You should not set the Location
of each _pictureBox
relatively to its parent MemoryField
, but rather change the Location
of the MemoryField
relatively to its parent Form
.
You should also set the size of your MemoryField
to the size of its child _pictureBox
otherwise it won't size correctly to fit its content.
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
}
// ...
}
and change your creation inner loop to
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);
}