How to dynamically add events to a large number of controls? - c#

I'm trying to add 1152 small pictureBoxes to a Winform dynamically then I want to add to each of those pictureBoxes a Click event so that when I click on them, the image change. I have no idea how to add event handler!?
private void Form1_Load(object sender, EventArgs e)
{
Image image1= Image.FromFile(#"C:\Users\image1.png");
Image image2= Image.FromFile(#"C:\Users\image2.png");
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
var pictures= new PictureBox
{
Name = "pic" + i + j,
Size = new Size(14, 14),
Location = new Point(j * 14, i * 14),
Image = image1,
};
this.Controls.Add(pictures);
}
}
}

So you have a sequence of PictureBoxes and you want two things:
You want to subscribe to a Click event
If the Click event occurs you want to change the image, probably depending on the picture box that was clicked.
First you need to have a sequence of the PictureBoxes you want to have this behaviour. If you don't have a sequence yet, and you want all PictureBoxes on a certain Control to have this behaviour you could use this:
IEnumerable<PictureBox> GetPictureBoxes(Control control)
{
return control.Controls.OfType<PictureControl>();
}
See Enumerable.OfType
Subscribe to event:
IEnumerable<PictureBox> myPictureBoxes = ...
foreach (PictureBox pictureBox in myPictureBoxes)
{
pictureBox.Click += new System.EventHandler(this.pictureBox_Click);
}
Event handler:
private void pictureBox1_Click(object sender, EventArgs e)
{
PictureBox pictureBox = (PictureBox)sender;
Image imageToShow = DecideWhichImageToShow(pictureBox); // TODO
// change the image:
pictureBox.Image = imageToShow
}

On event handler's method, the sender argument will be your PictureBox object, so you can write something like this:
private void Pb_Click(object sender, EventArgs e)
{
PictureBox pb = sender as PictureBox;
try
{
if (pb != null)
pb.Image = Image.FromFile(#"NewImagePath");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

Related

Zooming in ComboBox not working as expected

I have an application that scans an image to display on the application. After the image is scanned, I have the option to zoom the image. There's a combo box on the application that display the zoom percentage as well.
I can zoom fine using my mouse wheel and the combo box % changes accordingly which is fine. The problem happens if I manually select the combo box and select a zoom percentage, say 50%, then there's no changes at all.
Code:
private void ImageBox_ZoomLevelsChanged(object sender, EventArgs e)
{
this.FillZoomLevels();
}
private void ZoomComboBox_Click(object sender, EventArgs e)
{
}
private void FillZoomLevels()
{
ZoomComboBox.Items.Clear();
foreach (int zoom in ImageBox.ZoomLevels)
ZoomComboBox.Items.Add(string.Format("{0}%", zoom));
}
Am I doing anything wrong? Appreciate any help.
When there is more than one control on the Panel, and the ScrollBars are shown, the MouseWheel event of the Panel would be raised, but if there's only a PictureBox on the Panel whose Image large enough to make the panel's ScrollBars visible, then the MouseWheel event of the Panel won't be raised, instead, the Form's MouseWheel event fires.
In the following sample, I just add a PictureBox onto the Panel without any other controls added, set a large Image to the PictureBox which make the Panel's ScrollBars invisible, since there's only one control on the panel, the MouseWheel event of the Panel won't be raised, but the Form's MouseWheel event be raised, we handle this event instead, handle the Form's KeyDown and KeyUp events as well.
Furthermore, set the SizeMode of the PictureBox to StretchImage instead of AutoSize, thus when we change the size of the PictureBox, the Image in the PictureBox will resize to fit the PictureBox.
The PictureBox.Scale() method won't help you in this screnario, change the size of the PictureBox instead.
public partial class Form4 : Form
{
public Form4()
{
InitializeComponent();
}
bool ctrlKeyDown;
bool shiftKeyDown;
private void Form4_Load(object sender, EventArgs e)
{
this.ctrlKeyDown = false;
this.shiftKeyDown = false;
//If there's only PictureBox control on the panel, the MouseWheel event of the form raised
//instead of the MouseWheel event of the Panel.
this.MouseWheel += new MouseEventHandler(Form4_MouseWheel);
this.KeyDown += new KeyEventHandler(Form4_KeyDown);
this.KeyUp += new KeyEventHandler(Form4_KeyUp);
//this is important for zooming the image
this.pictureBox2.SizeMode = PictureBoxSizeMode.StretchImage;
}
void Form4_KeyUp(object sender, KeyEventArgs e)
{
this.ctrlKeyDown = e.Control;
this.shiftKeyDown = e.Shift;
}
void Form4_KeyDown(object sender, KeyEventArgs e)
{
this.ctrlKeyDown = e.Control;
this.shiftKeyDown = e.Shift;
}
void Form4_MouseWheel(object sender, MouseEventArgs e)
{
bool IsGoUp = e.Delta > 0 ? true : false;
if (this.ctrlKeyDown)
{
if (IsGoUp && this.panel1.HorizontalScroll.Value > 5)
{
this.panel1.HorizontalScroll.Value -= 5;
}
if (!IsGoUp && this.panel1.HorizontalScroll.Value < this.panel1.HorizontalScroll.Maximum - 5)
{
this.panel1.HorizontalScroll.Value += 5;
}
}
else if (this.shiftKeyDown)
{
int hStep = (int)(this.pictureBox2.Image.Width * 0.02);
int vStep = (int)(this.pictureBox2.Image.Height * 0.02);
if (IsGoUp)
{
this.pictureBox2.Width += hStep;
this.pictureBox2.Height += vStep;
}
else
{
this.pictureBox2.Width -= hStep;
this.pictureBox2.Height -= vStep;
}
}
else
{
if (IsGoUp && this.panel1.VerticalScroll.Value > 5)
{
this.panel1.VerticalScroll.Value -= 5;
}
if (!IsGoUp && this.panel1.VerticalScroll.Value < this.panel1.VerticalScroll.Maximum - 5)
{
this.panel1.VerticalScroll.Value += 5;
}
}
}
}

How to use array of images with pictureBox and hscrollbar to scroll between the images?

In Form1 I have in the designer a pictureBox.
Then I added a timer in the tick event i did:
private void timer1_Tick(object sender, EventArgs e) {
if (savedall == true) {
for (int i = 0; i < filePaths.Length; i++) {
}
}
}
And the hscrollbar scroll event:
private void hScrollBar1_Scroll(object sender, ScrollEventArgs e) {
}
When the savedall is true then I want to be able to scroll between all the images in filePaths and display each image in the pictureBox.
You can prepare the list of images and a scrollbar imgScroller like this:
List<string> imageList = new List<string>();
imageList = Directory.GetFiles("d:\\", "*.jpg").ToList();
imgScroller.Minimum = 0;
imgScroller.Value = 0;
imgScroller.Maximum = imageList.Count - 1;
imgScroller.SmallChange = 1;
imgScroller.LargeChange = 1;
And the code the Scroll event like this:
private void imgScroller_Scroll(object sender, ScrollEventArgs e)
{
if (scrolledPB.Image != null) scrolledPB.Image.Dispose();
int index = (int)imgScroller.Value;
scrolledPB.Image = Image.FromFile(imageList[index]);
someLabel.Text = "Displaying image " + index + " of " + imageList.Count - 1;
}
Not sure what the timer is doing or if you already have the file paths..

How to retain existing images in a panel while redrawing in c#?

I have a panel where I am drawing images on button click. But on the second button click, the previously drawn image is being replaced by the new Image.
void panel_Image_Paint(object sender, PaintEventArgs e)
{
if (Clipboard.ContainsImage())
{
Point p1 = new Point(i, 0);
e.Graphics.DrawImage(Clipboard.GetImage(), p1);
i += img.Width;
}
}
I want to retain the previously drawn image in the panel, when the new image is being drawn. The clipboard is being refreshed on each button click with the new image. Any help would be highly appreciated!!!!
Thanks..
I'm not sure how the paint event actually works and what causes your images to disappear , but what you can try is adding your images to a list and then looping through the list to get all of your images displayed on the panel.
Try this code:
int i = 0;
List<Image> Images = new List<Image>();
private void panel1_Paint(object sender, PaintEventArgs e)
{
if (Clipboard.ContainsImage())
{
Images.Add(Clipboard.GetImage());
foreach (Image item in Images)
{
e.Graphics.DrawImage(item, new Point(i,0));
i += Clipboard.GetImage().Width;
}
}
i = 0;
}
Don't forget to call the Invalidate function.
private void button1_Click(object sender, EventArgs e)
{
panel1.Invalidate();
}

Events from controls created at run-time

I am populating a flowLayoutPanel with pictureBoxes at run-time with the following code
for (int i = 0; i < immageArray.Length; i++)
{
Image image = Image.FromFile(immageArray[i]);
pictureBoxArray[i] = new PictureBox();
pictureBoxArray[i].Image = image;
pictureBoxArray[i].Width = 256;
pictureBoxArray[i].Height = 256;
pictureBoxArray[i].SizeMode = PictureBoxSizeMode.Zoom;
flowLayoutPanel1.Controls.Add(pictureBoxArray[i]);
}
How can do I create the event/events for controls that don't exist yet at design time?
Try this:
pictureBoxArray[i].MouseDown += new MouseEventHandler(pictureBox_MouseDown);
...
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
....
}
pictureBox_MouseDown is your mouseDown event handler, of course you can attach any event not only MouseDown and you can do it for any control created at runtime.
here is the list of events for PictureBox

I created an array of pictureBoxes how can i register for an event to all the pictureBoxes?

The code:
pbs = new PictureBox[8];
for (int i = 0; i < pbs.Length; i++)
{
pbs[i] = new PictureBox();
pbs[i].MouseEnter += Form1_MouseEnter;
pbs[i].MouseLeave += Form1_MouseLeave;
pbs[i].Size = new Size(100, 100);
pbs[i].Margin = new Padding(0, 0, 0, 60);
pbs[i].Dock = DockStyle.Top;
pbs[i].SizeMode = PictureBoxSizeMode.StretchImage;
Panel p = i < 4 ? panel1 : panel2;
p.Controls.Add(pbs[i]);
pbs[i].BringToFront();
}
I did:
pbs[i].MouseEnter +=
And when i clicked TAB it did: Form1_MouseEnter
It's not what i wanted.
I want that when i move with the mouse over each of the pictureBoxes area it will do something.
One event for all the pictureBoxes.
If i moved over pictureBox1 do something...pictureBox2 the same...
How can i do it ? I don't want to create 8 events for each pictureBox but one enter event for all.
You need simply write
pbs[i].MouseEnter += globalMouseEnterEvent;
of course you need to have a globalMouseEnterEvent somewhere in your code
public void globalMouseEnterEvent(object sender, System.EventArgs e)
{
....
}
However, another piece of information is needed when your work with event shared between numerous controls. You need to recognize the control that triggers the event. The control instance is passed using the sender parameter that you can cast to your appropriate control type, but what is needed is to give a unique identifier to your control. Like setting the Tag or Name properties when you build the control
for (int i = 0; i < pbs.Length; i++)
{
.....
pbs[i].Tag = "PB" + i.ToString()
...
}
so in the MouseEnter code you could write
public void globalMouseEnterEvent(object sender, System.EventArgs e)
{
PictureBox p = sender as PictureBox;
if(p.Tag.ToString() == "PB1")
.....
else if ......
}
dont use form1_event , copy it's code and rename it
pbs[i].MouseEnter += yourEventName
it's enough
What you're doing is absolute correct, you attach the handler to the event of each control in
turn, so that the same handler works for every PictureBox.
I guess your problem is that the method VS creates is named Form1_MouseEnter. This is completely irrelevant, what determines what a method will handle is the += operator, not its name. Just try to run your original code and it will do what you want.
It seems to be a bug in the C# editor though, as it should have named the automatically generated handler something more appropriate, but anyway, you can rename the method afterwards to reflect its true meaning.
I've tried to apply the tips from the others to your code:
pbs = new PictureBox[8];
for (int i = 0; i < pbs.Length; i++)
{
pbs[i] = new PictureBox();
pbs[i].MouseEnter += Picturebox_MouseEnter;
pbs[i].MouseLeave += PictureBox_MouseLeave;
pbs[i].Name = string.Concat("PB", i); //Added to identify each picturebox
pbs[i].Size = new Size(100, 100);
pbs[i].Margin = new Padding(0, 0, 0, 60);
pbs[i].Dock = DockStyle.Top;
pbs[i].SizeMode = PictureBoxSizeMode.StretchImage;
Panel p = i < 4 ? panel1 : panel2;
p.Controls.Add(pbs[i]);
pbs[i].BringToFront();
}
And the handlers:
private void Picturebox_MouseEnter(object sender, EventArgs e)
{
PictureBox pb = sender as PictureBox;
if (pb != null)
{
if (pb.Name == "PB2")
{
//Do PB2 specific task
}
//Your code when mouse enters one of the pictureboxes
//Use Name property to determine wich one, if needed
}
}
private void PictureBox_MouseLeave(object sender, EventArgs e)
{
//Your code when mouse leaves one of the pictureboxes
//Use Name property to determine wich one, if needed
}

Categories

Resources