How to populate a window with a dictionary of images? - c#

I have a GUI with a button that will open a new window. As soon as the window opens I need it to be filled with a sires of pictures that I have stored in a dictionary of (string,bitmap) with the string representing the path name. Obviously I need to iterate across the dictionary but I don't know what code to use to display the pictures. Is there anyway to make a loop that will automatically display the images in a set size.
For a good example of the output I'm looking for, think windows explorer thumbnails when browsing a folder of pictures.
I know very little about working with images or GUIs so any assistance would be appreciated.
As of now my this is the code I have:
MyPalletGui.Show();
PictureBox myPicBox = new PictureBox();
Dictionary<string,Bitmap> MyPallet = MyImageCollection.ToDictionary();
int xcor = 0;
int ycor = 0;
foreach (Bitmap curtImage in MyPallet.Values){
xcor += 50;
ycor += 50;
myPicBox.Location = new Point(xcor, ycor);
myPicBox.Width = 50;
myPicBox.Height = 50;
myPicBox.Visible = true;
myPicBox.Image = new Bitmap(curtImage);
this.MyPalletGui.Controls.Add(myPicBox);
I need to work with the x and y coordinates more, but the code above displays nothing.

Related

Dynamically display an array of PictureBoxes - Performance issue

I'd like to display coverarts for each album of an MP3 library, a bit like Itunes does (at a later stage, i'd like to click one any of these coverarts to display the list of songs).
I have a form with a panel panel1 and here is the loop i'm using :
int i = 0;
int perCol = 4;
int disBetWeen = 15;
int width = 250;
int height = 250;
foreach(var alb in mp2)
{
myPicBox.Add(new PictureBox());
myPicBox[i].SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
myPicBox[i].Location = new System.Drawing.Point(disBetWeen + (disBetWeen * (i % perCol) +(width * (i % perCol))),
disBetWeen + (disBetWeen * (i / perCol))+ (height * (i / perCol)));
myPicBox[i].Name = "pictureBox" + i;
myPicBox[i].Size = new System.Drawing.Size(width, height);
myPicBox[i].ImageLocation = #"C:/Users/Utilisateur/Music/label.jpg";
panel1.Controls.Add(myPicBox[i]);
i++;
}
I'm using the same picture per picturebox for convenience, but i'll use the coverart embedded in each mp3 file eventually.
It's working fine with an abstract of the library (around 50), but i have several thousands of albums. I tried and as expected, it takes a long time to load and i cannot really scroll afterward.
Is there any way to load only what's displayed ? and then how to assess what is displayed with the scrollbars.
Thanks
Winforms really isn't suited to this sort of thing... Using standard controls, you'd probably need to either provision all the image boxes up front and load images in as they become visible, or manage some overflow placeholder for the appropriate length so the scrollbars work.
Assuming Winforms is your only option, I'd suggest you look into creating a custom control with a scroll bar and manually driving the OnPaint event.
That would allow you to keep a cache of images in memory to draw the current view [and a few either side], while giving you total control over when they're loaded/unloaded [well, as "total" as you can get in a managed language - you may still need tune garbage collection]
To get into some details....
Create a new control
namespace SO61574511 {
// Let's inherit from Panel so we can take advantage of scrolling for free
public class ImageScroller : Panel {
// Some numbers to allow us to calculate layout
private const int BitmapWidth = 100;
private const int BitmapSpacing = 10;
// imageCache will keep the images in memory. Ideally we should unload images we're not using, but that's a problem for the reader
private Bitmap[] imageCache;
public ImageScroller() {
//How many images to put in the cache? If you don't know up-front, use a list instead of an array
imageCache = new Bitmap[100];
//Take advantage of Winforms scrolling
this.AutoScroll = true;
this.AutoScrollMinSize = new Size((BitmapWidth + BitmapSpacing) * imageCache.Length, this.Height);
}
protected override void OnPaint(PaintEventArgs e) {
// Let Winforms paint its bits (like the scroll bar)
base.OnPaint(e);
// Translate whatever _we_ paint by the position of the scrollbar
e.Graphics.TranslateTransform(this.AutoScrollPosition.X,
this.AutoScrollPosition.Y);
// Use this to decide which images are out of sight and can be unloaded
var current_scroll_position = this.HorizontalScroll.Value;
// Loop through the images you want to show (probably not all of them, just those close to the view area)
for (int i = 0; i < imageCache.Length; i++) {
e.Graphics.DrawImage(GetImage(i), new PointF(i * (BitmapSpacing + BitmapWidth), 0));
}
}
//You won't need a random, just for my demo colours below
private Random rnd = new Random();
private Bitmap GetImage(int id) {
// This method is responsible for getting an image.
// If it's already in the cache, use it, otherwise load it
if (imageCache[id] == null) {
//Do something here to load an image into the cache
imageCache[id] = new Bitmap(100, 100);
// For demo purposes, I'll flood fill a random colour
using (var gfx = Graphics.FromImage(imageCache[id])) {
gfx.Clear(Color.FromArgb(255, rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255)));
}
}
return imageCache[id];
}
}
}
And Load it into your form, docking to fill the screen....
public Form1() {
InitializeComponent();
this.Controls.Add(new ImageScroller {
Dock = DockStyle.Fill
});
}
You can see it in action here: https://www.youtube.com/watch?v=ftr3v6pLnqA (excuse the mouse trails, I captured area outside the window)

Dynamically add Chart to Windows Forms - shows up blank

I'm trying to add a Chart control dynamically to a Form (using C#, this should all be .NET 4.0), but it's always blank (only the background color shows). I tried the same code in a Form that already has a control and it works, so I imagine it's some initialization function I should call (I tried Invalidate() on the control and Refresh() on both control and the panel it's being placed in, made no difference). I went through the few similar posts I found, tried throwing in any other commands they used (BeginInit() is from one such post) but no luck so far. Any ideas?
BTW I want to display 6-9 charts (position, speed and acceleration in 3D space) so I'd rather add them dynamically than have 9 sets of assignments. Here's the code that adds the charts to the panel:
foreach (KeyValuePair<string, List<double>> p in b.storedValues)
{
Control c = getChartForData(p);
panel1.Controls.Add(c);
c.Invalidate();
c.Refresh();
break;
}
And the function that creates each chart:
private Chart getChartForData(KeyValuePair<string, List<double>> data)
{
Chart c = new Chart();
((System.ComponentModel.ISupportInitialize)c).BeginInit();
c.Series.Clear();
c.BackColor = Color.White;
c.Height = 300;
c.Width = 500;
c.Palette = ChartColorPalette.Bright;
Series s = new Series(data.Key);
s.ChartType = SeriesChartType.Spline;
double maxValue = 0;
//NOTE: Going logarithmic on this, too big numbers
for (int i = 0; i < data.Value.Count; i++)
{
maxValue = Math.Max(Math.Log10(data.Value[i]), maxValue);
}
for (int i = 0; i < data.Value.Count; i++)
{
s.Points.AddXY(i,Math.Log10(data.Value[i]) * c.Height / maxValue);
}
c.Series.Add(s);
return c;
}
Many thanks in advance.
When you create a Chart yourself, in code, it does not contain any ChartArea.
Therefore, nothing is displayed.
I'm guessing that the designer generates some code to initialize a default chart area when you drag and drop a chart control onto the form.
Also, you should really let the chart control handle the layout, instead of calculating the desired position of each point based on the height of the chart control.
I would go as simple as possible to get something that's working, and then you can tweak the range of the axis afterwards. You can also set an axis to be logarithmic.
Start with trying out this minimal version, and make sure that displays something, before you complicate things. This works for me.
private Chart getChartForData(string key, List<double> data)
{
Chart c = new Chart();
Series s = new Series(key);
s.ChartType = SeriesChartType.Spline;
for (int i = 0; i < data.Count; i++)
{
s.Points.AddXY(i, data[i]);
}
c.Series.Add(s);
var area = c.ChartAreas.Add(c.ChartAreas.NextUniqueName());
s.ChartArea = area.Name;
// Here you can tweak the axis of the chart area - min and max value,
// where they display "ticks", and so on.
return c;
}

Image doesn't show in picturebox c#

I want copy image from one picturebox to another. The code below:
PictureBox pictureBoxRain1 = new PictureBox();
pictureBoxRain1.Size = size;
//pictureBoxRain1.Image = (Image)Properties.Resources.kaplja;
pictureBoxRain1.Image = Image.FromFile(#"C:\images\kaplja.png");
//pictureBoxRain1.ImageLocation = pictureBoxRain.I;
//pictureBoxRain1.Image = Graphics.FromImage();
//pictureBoxRain1.InitialImage = Properties.Resources.kaplja;
//pictureBoxRain1.BackgroundImage = Properties.Resources.kaplja;
pictureBoxRain1.Location = new Point(pictureBoxRain.Location.X + pictureBoxGrass.Size.Width + 10, pictureBoxRain.Location.Y);
Controls.Add(pictureBoxRain1);
All anothers properties copy perfectly to pictureBoxRain1 from pictureBoxRain, but image doesn't want show. Where is problem? I checked many variants such as copy image from Properties.Resources, and reading direct from file and some others(look comments in code above), but nothing works.
EDIT
Check the pictureBoxRain1.SizeMode.

C# moving a PictureBox over another PictureBox

I’m making a card game in c# where I create a class extended from PictureBox and then I create a instance of the class for every card.
I also create a class extended from PictureBox to hold the images for the foundations. This class holds a .png image with transparency.
So far so good but after setting the game table with the foundations, every time I move a card over the foundations the PictureBox that contains the foundation image captures a trail of the card I mover over it creating a very unpleasant visual effect.
I don’t know why the PictureBox of the Foundation tries to capture the image of the card moving over it.
Is there a way to solve this problem? I've tried some suggestions but with no success. Thank you for your help.
Here is a snap of code I use to create an arraylist of PictureBox. Still the same problem.
PictureBox[] pb = new PictureBox[22];
for (int n = 0; n < 4; n++) // linhas
{
int col = (WindowWidth - 3 * gap - 4 * larguraCarta) / 2;
for (int x = 0; x < 4; x++) // colunas
{
pb[cardIndex] = new PictureBox();
pb[cardIndex].Width = larguraCarta;
pb[cardIndex].Height = alturaCarta;
pb[cardIndex].BorderStyle = BorderStyle.FixedSingle;
pb[cardIndex].Location = new Point(col, linha);
pb[cardIndex].SizeMode = PictureBoxSizeMode.StretchImage;
pb[cardIndex].BackColor = Color.White;
pb[cardIndex].BringToFront();
This is a picture of the screen so you can see what happens when I move a card over the foundation.

Button image sides cropped

I'm trying to fit image to button perfectly.
But the image is cropped on its right and bottom faces, see attached print screen:
I edited the button as follows:
var l_oStopImage = Image.FromFile(#"C:\Users\AmitL\Downloads\Button-2-stop-icon72p.png");
var l_oStopPic = new Bitmap(l_oStopImage , new Size(btnStopOperation.Width, btnStopOperation.Height));
btnStopOperation.Image = l_oStopPic ;
btnStopOperation.ImageAlign = System.Drawing.ContentAlignment.MiddleCenter;
btnStopOperation.TabStop = false;
btnStopOperation.FlatStyle = FlatStyle.Flat;
btnStopOperation.FlatAppearance.BorderSize = 0;
I also tried to edit the BackgroundImageLayout but none of the ImageLayouts fixed the problem..
Any suggestions?
Thanks in advance
1https://msdn.microsoft.com/en-us/library/system.windows.forms.imagelayout(v=vs.110).aspx
You should use stretch, I suggest in designtime (this is not java where you have to add elements by code):
this.buttonOk.BackColor = System.Drawing.SystemColors.MenuHighlight;
this.buttonOk.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("buttonOk.BackgroundImage")));
this.buttonOk.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.buttonOk.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.buttonOk.Location = new System.Drawing.Point(475, 15);
this.buttonOk.Name = "buttonOk";
this.buttonOk.Size = new System.Drawing.Size(50, 50);
this.buttonOk.TabIndex = 11;
this.buttonOk.UseVisualStyleBackColor = false;
this.buttonOk.Click += new System.EventHandler(this.buttonOk_Click);
And it will work, done it many times before
I got this code from my own working Form1.Designer.cs but because of that: please use the Visual Studio designer and don't try to write all this code / logic in your constructor or something.
The problem is because you are showing an image with the same size as your button.
When you want an image fit in your button, the width and height of image should be at least 1 point less than your button size. (or in other word, you can set your button width and height 1 point more than the image size).
So you can change your code to this:
var l_oStopPic = new Bitmap(l_oStopImage ,
new Size(btnStopOperation.Width-1, btnStopOperation.Height-1));

Categories