I'm trying to create pictures boxes dynamically from a folder containing images, but in my code I can only create one picture box. How do I do to create one picture box per image?
Here is my code:
namespace LoadImagesFromFolder
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string[] images = Directory.GetFiles(#"C:\Users\Public\Pictures\Sample Pictures", "*.jpg");
foreach (string image in images)
{
pictureBox1.Image = new Bitmap(image);
}
}
}
}
You're just rewriting the image value for your single PictureBox (pictureBox1), but you need to create a new PictureBox for every picture instead and set its value. Do that and you'll be fine.
Something like this (just an example, modify this to your needs!)
foreach (string image in images)
{
PictureBox picture = new PictureBox();
picture.Image = new Bitmap(image);
someParentControl.Controls.Add(picture);
}
You have to use a dialog to select the files, create the PictureBox controls dynamically in the foreach loop and add them to the form's (or other container control's) Controls collection.
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog d = new OpenFileDialog();
// allow multiple selection
d.Multiselect = true;
// filter the desired file types
d.Filter = "JPG |*.jpg|PNG|*.png|BMP|*.bmp";
// show the dialog and check if the selection was made
if (d.ShowDialog() == DialogResult.OK)
{
foreach (string image in d.FileNames)
{
// create a new control
PictureBox pb = new PictureBox();
// assign the image
pb.Image = new Bitmap(image);
// stretch the image
pb.SizeMode = PictureBoxSizeMode.StretchImage;
// set the size of the picture box
pb.Height = pb.Image.Height/10;
pb.Width = pb.Image.Width/10;
// add the control to the container
flowLayoutPanel1.Controls.Add(pb);
}
}
}
Related
I have some pictures in a database which I retrieve them . To load these pictures, I made a "Tab Control" in Windows Form, which has a "Tab page1". when the program runs, a group box, containing a PictureBox (and some other text boxes), will be created for each picture. my pictures can be load in these picture boxes, and I will have a list of group boxes(gbList). However, I can not select these pictures during the run. Can anybody suggest a solution?
private void Form2_Load(object sender, EventArgs e)
{
tabPage1.Controls.Clear();
int x = 0, y = 0;
int j = 0;
for (int i = 0; i < output.Count - 1; i++)
{
PictureBox pic = new PictureBox();
pic.SizeMode = PictureBoxSizeMode.StretchImage;
SelectablegroupBox gb = new SelectablegroupBox();
gb.Controls.Add(pic);
gbList.Add(gb);
//to retrieve the images from the database in ProductImages class: (output is the result of a query of database)
ProductImages pI = output[i];
imgbyte = pI.Pic;
using (MemoryStream ms = new MemoryStream(imgbyte))
{
Image img = Image.FromStream(ms);
pic.Image = img;
}
//to add the group box list o the tabpage:
tabPage1.Controls.Add(gbList[j]);
gbList[j].Location = new Point(x, y);
y += gbList[i].Height;
j++;
}
here is my problem. I want the user to be able to select the images (Then I want to save these selected Items). But the "result" is always empty:
var result = from s in gbList
where s.Focused ==true
select s;
foreach (var s in result)
{ //save the selected images}
As I learned from another post, I defined SelectablegroupBox" as:
class SelectablegroupBox : GroupBox
{
public SelectablegroupBox()
{
this.SetStyle(ControlStyles.Selectable, true);
this.TabStop = true;
}
protected override void OnEnter(EventArgs e)
{
this.Focus();
this.Invalidate();
base.OnEnter(e);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
if (this.Focused)
{
var rc = this.ClientRectangle;
rc.Inflate(-2, -2);
ControlPaint.DrawFocusRectangle(pe.Graphics, rc);
}
}
}
thanks in advance
Your class SelectableGroupBox is not suitable to let the user select one or more images. There can be at most one focused control in your app - this will be probably a button on your form which the user clicks to save the selected images.
One simple solution would be to use CheckBox controls with the Appearance property set to Button. Also, you don't have to layout the images manually, let a FlowLayoutPanel do the job.
First, add a FlowLayoutPanel named flowLayoutPanel to your tabPage2 and set the following Properties:
flowLayoutPanel.AutoScroll = true;
flowLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill;
Then change the appropriate code in Form2 to:
private const int imageWidth = 128;
private const int imageHeight = 128;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
for (int i = 0; i < output.Count; i++)
{
CheckBox cb = new CheckBox();
cb.Appearance = Appearance.Button;
cb.Size = new Size(imageWidth, imageHeight);
cb.BackgroundImageLayout = ImageLayout.Zoom;
ProductImages pI = output[i];
//Don't dispose the MemoryStream, the Image class will need it!
var ms = new MemoryStream(pI.Pic);
cb.BackgroundImage = Image.FromStream(ms);
flowLayoutPanel.Controls.Add(cb);
}
}
This is how you get your selected pictures:
private void SaveButton_Click(object sender, EventArgs e)
{
var selected = flowLayoutPanel.Controls.OfType<CheckBox>().Where(x => x.Checked);
Debug.Print("Selected images: {0}", selected.Count());
foreach (var item in selected)
{
//Save the picture from item.BackgroundImage.
}
}
I have made a picture box called "pb_test" that contains a picture of a factory, when I click it, it creates a new picture box after each click in a specific location of my windows form.
Each created picture box is draggable, that means that I can move it anywhere on my form.
I've created a label on my form that shows the position (x,y) of my draggable picture box. When I create a picture box and drag it, the label shows its position (x,y) , but if I create another one, the new one when I drag it, the label shows (x,y) , but if I drag the first one created, the label doesn't change, and still showing data (x,y) of the last created one.
This is my code:
List<PictureBox> list_pboxes = new List<PictureBox>();
private void pb_test_Click(object sender, EventArgs e)
{
PictureBox pbox = new PictureBox();
pbox.Name = "factory";
pbox.Location = new Point(600, 600);
pbox.Size = new Size(100, 70);
pbox.SizeMode = PictureBoxSizeMode.CenterImage;
pbox.BackColor = Color.AliceBlue;
pbox.Image = pb_test.Image;
pbox.SizeMode = PictureBoxSizeMode.StretchImage;
pbox.BackColor = Color.Transparent;
this.Controls.Add(pbox);
list_pboxes.Add(pbox);
ControlExtension.Draggable(pbox, true);
}
private void timer_ListpicBoxes_Tick(object sender, EventArgs e)
{
foreach (PictureBox p in list_pboxes)
{
lbl_mouse.Text = p.Location.X.ToString() + " , " + p.Location.Y.ToString();
}
}
I want to create a simple image slideshow, when the timer switch, it will switch to the next index of the picturebox (and will loop) but with a fade effect. How can it be done in C#?
Current Code doesn't switch images? And also - how can I create the fade ffect?
I created a simple timer with 5,000ms interval, enabled it on start.
private void timerImage_Tick(object sender, EventArgs e)
{
if (pictureBox1.Image.Equals(InnovationX.Properties.Resources._1))
{
pictureBox1.Image = InnovationX.Properties.Resources._2;
}
else if (pictureBox1.Image.Equals(InnovationX.Properties.Resources._2))
{
pictureBox1.Image = InnovationX.Properties.Resources._3;
}
else
{
pictureBox1.Image = InnovationX.Properties.Resources._1;
}
}
You can't compare Bitmap loaded from resource in this manner. Every time you get image from resource (in your case using property InnovationX.Properties.Resources._1) you will get new instance of Bitmap class. Comparing two different instances of Bitmap classes will always result in false, even if they contains same image.
Bitmap a = InnovationX.Properties.Resources._1; // create new bitmap with image 1
Bitmap b = InnovationX.Properties.Resources._1; // create another new bitmap with image 1
bool areSameInstance = a == b; // will be false
If you load you images from resources to member variables (e.g. in Load event).
// load images when you create a form
private Bitmap image1 = InnovationX.Properties.Resources._1;
private Bitmap image2 = InnovationX.Properties.Resources._2;
private Bitmap image3 = InnovationX.Properties.Resources._3;
// assing and compare loaded images
private void timerImage_Tick(object sender, EventArgs e)
{
if (pictureBox1.Image == image1)
{
pictureBox1.Image = image2;
}
else if (pictureBox1.Image == image2)
{
pictureBox1.Image = image3;
}
else
{
pictureBox1.Image = image1;
}
}
And after that, rewrite that code using array :)
Image[] images = new {
InnovationX.Properties.Resources._1,
InnovationX.Properties.Resources._2,
InnovationX.Properties.Resources._3
};
I load dinamically multiple images in flowLayoutPanel...and I wanna scroll the panel if necessary.
Here is my code:
private void carregarImagensToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFileDialog d = new OpenFileDialog();
// allow multiple selection
d.Multiselect = true;
// filter the desired file types
d.Filter = "JPG |*.jpg|PNG|*.png|BMP|*.bmp";
// show the dialog and check if the selection was made
if (d.ShowDialog() == DialogResult.OK)
{
foreach (string image in d.FileNames)
{
// create a new control
PictureBox pb = new PictureBox();
pb.Tag = tag;
btn.Tag = tag;
pb.MouseDown += pictureBox_MouseDown;
// assign the image
pb.Image = new Bitmap(image);
listaImagens.Add(new Bitmap(image));
// stretch the image
pb.SizeMode = PictureBoxSizeMode.StretchImage;
// set the size of the picture box
pb.Height = pb.Image.Height / 10;
pb.Width = pb.Image.Width / 10;
// add the control to the container
flowLayoutPanel1.Controls.Add(pb);
listaPicBoxes.Add(pb);
tag++;
}
}
}
You could always use the AutoScroll property:
flowLayoutPanel1.AutoScroll = true;
Set the FlowLayoutPanel's AutoScroll property to true
class OriginalImage: Form
{
private Image image;
private PictureBox pb;
public OriginalImage()
{
pb = new PictureBox {SizeMode = PictureBoxSizeMode.CenterImage};
pb.SizeMode = PictureBoxSizeMode.StretchImage;
Controls.Add(pb);
image = Image.FromFile(#"Image/original.jpg");
this.Width = image.Width;
this.Height = image.Height;
this.Text = "Original image";
this.Paint += new PaintEventHandler(Drawer);
}
public virtual void Drawer(object source, PaintEventArgs e)
{
Graphics g = pb.CreateGraphics();
g.DrawImage(image,0,0);
}
I call this create object OriginalImage in other form on button click, but image is not draw? Where is problem?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var oi = new OriginalImage();
oi.Show();
}
}
You're creating a PictureBox and adding it to your controls, but you never actually use it (you're drawing the image manually in the Paint event). Why? This control is likely obscuring the drawing area of the form, as any controls go on top of whatever you draw in the Paint event.
In addition, you're getting the Graphics object by calling CreateGraphics on the PictureBox rather than the Form itself. This is wrong, as the PictureBox's Paint event will fire after this code, erasing whatever you draw.
I would recommend changing your OriginalForm code to the following:
class OriginalImage: Form
{
private Image image;
private PictureBox pb;
public OriginalImage()
{
pb = new PictureBox();
pb.SizeMode = PictureBoxSizeMode.StretchImage;
pb.Dock = DockStyle.Fill; // this will make the PictureBox occupy the
// whole form
Controls.Add(pb);
image = Image.FromFile(#"Image/original.jpg");
this.ClientSize = new Size(image.Width, image.Height); // this allows you to
// size the form while
// accounting for the
// border
this.Text = "Original image";
pb.Image = image; // use this instead of drawing it yourself.
}
}