patterncsharpMinor
Dynamic visual list of images
Viewed 0 times
listimagesvisualdynamic
Problem
Situation
So I have made a list of PictureBoxes on my form that looks as follows:
All images have a panel behind them that is 4px lager (2xp all around the picture box). The images are named
I want this to happen smoothly when one of the 5 PictureBoxes is clicked:
What I made
When form is created, two lists are initialised:
and
All PictureBoxes in views have a click event that points to
```
private void x_Click(object sender, EventArgs e)
{
PictureBox x = sender as PictureBox;
//Only do something if clicked PictureBox is not large
if (x.Size != new Size(62, 62))
{
// This keeps the PictureBox center constant
x.Location = new Point(x.Left - 7, x.Top - 7);
// Resize picturebox
x.Size = new Size(62, 62);
// Get the panel corresponding to the PictureBox
Control y = backviews[int.Parse(x.Name.Replace("x", "")) - 1];
// This keeps the Panel center constant
y.Location = new Point(y.Left - 7, y.Top - 7);
// Resize Panel
y.Size = new Size(66, 66);
// Find the current enlarged PictureBox and reverse what is done above
Control z = views[int.Parse(current.Replace("x", "")) - 1];
So I have made a list of PictureBoxes on my form that looks as follows:
All images have a panel behind them that is 4px lager (2xp all around the picture box). The images are named
x1, x2, xn.. respectively. The panels behind the images are named y1, y2, yn.. respectively.I want this to happen smoothly when one of the 5 PictureBoxes is clicked:
- Before clicked, all pictureboxes are 48x48 and respective panels 52x52
- When one gets clicked, resize the picturebox to 62x62 and the respective panels to 66x66
- When one gets clicked, the image must hold the same center as previously
- When one gets clicked, all other images turn back 'small'
- when a 'enlarged' image gets clicked, nothing happens
What I made
When form is created, two lists are initialised:
List views = new List { x1, x2, x3, x4, x5 }; andList backviews = new List { y1, y2, y3, y4, y5 }; and
PictureBox current which is the name of the current picturebox (x1, x2, etc.)All PictureBoxes in views have a click event that points to
x_Click```
private void x_Click(object sender, EventArgs e)
{
PictureBox x = sender as PictureBox;
//Only do something if clicked PictureBox is not large
if (x.Size != new Size(62, 62))
{
// This keeps the PictureBox center constant
x.Location = new Point(x.Left - 7, x.Top - 7);
// Resize picturebox
x.Size = new Size(62, 62);
// Get the panel corresponding to the PictureBox
Control y = backviews[int.Parse(x.Name.Replace("x", "")) - 1];
// This keeps the Panel center constant
y.Location = new Point(y.Left - 7, y.Top - 7);
// Resize Panel
y.Size = new Size(66, 66);
// Find the current enlarged PictureBox and reverse what is done above
Control z = views[int.Parse(current.Replace("x", "")) - 1];
Solution
There are a few things that you should refactor to be able to optimize your code better. Currently everthing sits inside the
You are not able to focus on particular task like that. You should separate the operations and create new methods and properties for them. Here's how you could start. It's not 100% perfect (like the hard coded picture box
Create a new panel control with a picture box inside (you can create a property for it so that you can set the image later). In this control you can implement all the logic that should handle the resize.
Give it a few properties that you can set and calculate the size and location values dynamiclly and internally. Use a flag (like
You also can create your panels dinamiclly and give them some initial values.
Initialize the panels:
And this is how it looks like:
When one gets clicked, all other images turn back 'small'
Add an event to your new panel and raise it when it gets enlarged. You can then handle this event in the main form and set all other panels to
```
public event EventHandler Enlarged;
public bool IsEnlarged
{
get { return _isEnlarged; }
set
{
// prevents multiple changes
if (value == _isEnlarged)
{
return;
}
_isEnlarged = value;
Size = _isEnlarged ? EnlargedSize : NormalSize;
ResizePictureBox();
TranslatePanel();
Click event handler and it's too much to handle there. You are not able to focus on particular task like that. You should separate the operations and create new methods and properties for them. Here's how you could start. It's not 100% perfect (like the hard coded picture box
BackColor) yet but it should give you an idea how to start refactoring your current solution.Create a new panel control with a picture box inside (you can create a property for it so that you can set the image later). In this control you can implement all the logic that should handle the resize.
Give it a few properties that you can set and calculate the size and location values dynamiclly and internally. Use a flag (like
IsEnlarged) to track whether a panel is in its normal or enlarged size rather than hard coded sizes. Here you can handle the Click event and take proper actions to modify the panel and the picture box.class ResizablePanel : Panel
{
private bool _isEnlarged;
public ResizablePanel()
{
Controls.Add(new PictureBox
{
BackColor = Color.PaleGoldenrod
});
Click += PanelOrPicktureBox_Click;
Controls[0].Click += PanelOrPicktureBox_Click;
}
public bool IsEnlarged
{
get { return _isEnlarged; }
set
{
if (value == _isEnlarged)
{
return;
}
_isEnlarged = value;
Size = _isEnlarged ? EnlargedSize : NormalSize;
ResizePictureBox();
TranslatePanel();
if (IsEnlarged)
{
Enlarged?.Invoke(this, EventArgs.Empty);
}
}
}
public Size NormalSize { get; set; }
public Size EnlargedSize { get; set; }
public Size BorderSize { get; set; }
public void Initialize()
{
Size = _isEnlarged ? EnlargedSize : NormalSize;
ResizePictureBox();
TranslatePanel();
}
private void ResizePictureBox()
{
var pictureBox = Controls[0] as PictureBox;
pictureBox.Location = new Point
{
X = BorderSize.Width,
Y = BorderSize.Height
};
// multiply by 2 becasue border size specifies only its width and we
// need to two of them, one for each side
pictureBox.Size = new Size
{
Width = Size.Width - (BorderSize.Width * 2),
Height = Size.Height - (BorderSize.Height * 2)
};
}
private void TranslatePanel()
{
if (IsEnlarged)
{
Location = new Point
{
X = Location.X - ((EnlargedSize.Width - NormalSize.Width) / 2),
Y = Location.Y - ((EnlargedSize.Height - NormalSize.Height) / 2),
};
}
else
{
Location = new Point
{
X = Location.X + ((EnlargedSize.Width - NormalSize.Width) / 2),
Y = Location.Y + ((EnlargedSize.Height - NormalSize.Height) / 2),
};
}
}
private void PanelOrPicktureBox_Click(object sender, EventArgs e)
{
IsEnlarged = !IsEnlarged;
}
}You also can create your panels dinamiclly and give them some initial values.
private void CreatePictureBoxes()
{
var pictureBoxCount = 4;
var panelNormalSize = new Size(52, 52);
var panelEnlargedSize = new Size(66, 66);
var borderSize = new Size(5, 5);
for (var i = 0; i < pictureBoxCount; i++)
{
var panel = new ResizablePanel
{
NormalSize = panelNormalSize,
EnlargedSize = panelEnlargedSize,
BorderSize = borderSize,
IsEnlarged = false,
// 3 is just a random border width multiplier to create gaps between the controls
Location = new Point
{
X = panelNormalSize.Width * i + borderSize.Width * 3 * (i + 1),
Y = borderSize.Height * 3
},
BackColor = Color.DarkMagenta,
};
panel.Initialize();
Controls.Add(panel);
}
}Initialize the panels:
public Form1()
{
InitializeComponent();
CreatePictureBoxes();
}And this is how it looks like:
When one gets clicked, all other images turn back 'small'
Add an event to your new panel and raise it when it gets enlarged. You can then handle this event in the main form and set all other panels to
IsEnlarged = false```
public event EventHandler Enlarged;
public bool IsEnlarged
{
get { return _isEnlarged; }
set
{
// prevents multiple changes
if (value == _isEnlarged)
{
return;
}
_isEnlarged = value;
Size = _isEnlarged ? EnlargedSize : NormalSize;
ResizePictureBox();
TranslatePanel();
Code Snippets
class ResizablePanel : Panel
{
private bool _isEnlarged;
public ResizablePanel()
{
Controls.Add(new PictureBox
{
BackColor = Color.PaleGoldenrod
});
Click += PanelOrPicktureBox_Click;
Controls[0].Click += PanelOrPicktureBox_Click;
}
public bool IsEnlarged
{
get { return _isEnlarged; }
set
{
if (value == _isEnlarged)
{
return;
}
_isEnlarged = value;
Size = _isEnlarged ? EnlargedSize : NormalSize;
ResizePictureBox();
TranslatePanel();
if (IsEnlarged)
{
Enlarged?.Invoke(this, EventArgs.Empty);
}
}
}
public Size NormalSize { get; set; }
public Size EnlargedSize { get; set; }
public Size BorderSize { get; set; }
public void Initialize()
{
Size = _isEnlarged ? EnlargedSize : NormalSize;
ResizePictureBox();
TranslatePanel();
}
private void ResizePictureBox()
{
var pictureBox = Controls[0] as PictureBox;
pictureBox.Location = new Point
{
X = BorderSize.Width,
Y = BorderSize.Height
};
// multiply by 2 becasue border size specifies only its width and we
// need to two of them, one for each side
pictureBox.Size = new Size
{
Width = Size.Width - (BorderSize.Width * 2),
Height = Size.Height - (BorderSize.Height * 2)
};
}
private void TranslatePanel()
{
if (IsEnlarged)
{
Location = new Point
{
X = Location.X - ((EnlargedSize.Width - NormalSize.Width) / 2),
Y = Location.Y - ((EnlargedSize.Height - NormalSize.Height) / 2),
};
}
else
{
Location = new Point
{
X = Location.X + ((EnlargedSize.Width - NormalSize.Width) / 2),
Y = Location.Y + ((EnlargedSize.Height - NormalSize.Height) / 2),
};
}
}
private void PanelOrPicktureBox_Click(object sender, EventArgs e)
{
IsEnlarged = !IsEnlarged;
}
}private void CreatePictureBoxes()
{
var pictureBoxCount = 4;
var panelNormalSize = new Size(52, 52);
var panelEnlargedSize = new Size(66, 66);
var borderSize = new Size(5, 5);
for (var i = 0; i < pictureBoxCount; i++)
{
var panel = new ResizablePanel
{
NormalSize = panelNormalSize,
EnlargedSize = panelEnlargedSize,
BorderSize = borderSize,
IsEnlarged = false,
// 3 is just a random border width multiplier to create gaps between the controls
Location = new Point
{
X = panelNormalSize.Width * i + borderSize.Width * 3 * (i + 1),
Y = borderSize.Height * 3
},
BackColor = Color.DarkMagenta,
};
panel.Initialize();
Controls.Add(panel);
}
}public Form1()
{
InitializeComponent();
CreatePictureBoxes();
}public event EventHandler Enlarged;
public bool IsEnlarged
{
get { return _isEnlarged; }
set
{
// prevents multiple changes
if (value == _isEnlarged)
{
return;
}
_isEnlarged = value;
Size = _isEnlarged ? EnlargedSize : NormalSize;
ResizePictureBox();
TranslatePanel();
// raise the event (using C# 6)
if (IsEnlarged)
{
Enlarged?.Invoke(this, EventArgs.Empty);
}
}
}panel.Enlarged += Panel_Enlarged;Context
StackExchange Code Review Q#107871, answer score: 3
Revisions (0)
No revisions yet.