I need to change the image by clicking on pictureBox, but when I click it again I can't return former picture
Here is my code:
private void PictureBox_Click(object sender, EventArgs e)
{
if (pictureBox.Image == Properties.Resources.openeye)
pictureBox.Image = Properties.Resources.closeeye;
else
pictureBox.Image = Properties.Resources.openeye;
}
How can I fix it?
Here's an example that demonstrates it with two images. One of an "x" another of an "o".
As you can see, the form has two instance variables x and o to store each of the Image objects. There is another flag field called isX which the ClickHandle event handler uses to check which image is currently displayed and switch to the other image, the event handler then toggles the isX field so the next click responds properly.
public void Main(string[] args)
{
var f1 = new Form1(); // form instance that holds the PictureBox
Task.Run(() => Application.Run(f1)); //I'm running this from LINQPad, but this would also work in a console application.
}
public class Form1 : Form // Derives from the Form class
{
private bool isX; // private instance variable to indicate which image is diplayed
private Image x; // private instance variable storing the x image
private Image o; // private instance variable storing the o image
// the picture box this form uses
private PictureBox p;
public Form1()
{
// load the images from wherever they are stored.
// I do this at construction time to avoid doing disk IO when clicking
x = Image.FromFile(#"C:\image\path\x.png");
o = Image.FromFile(#"C:\image\path\o.png");
// Initialize the picture box
p = new PictureBox {
Name = "p1",
Size = new Size(100,100),
Location = new Point(100,100),
Image = o //Initialize with the o image
};
// register the click event handler
p.Click += this.ClickHandle;
// set the flag to false, since the o image is what we start with
this.isX = false;
// add PictureBox p to the form
this.Controls.Add(p);
}
// handles the click action, registered to the PictureBox.Click event
private void ClickHandle(object sender, EventArgs e)
{
// use the flag to check which image is shown, and display the other image
if(this.isX) // this might work with your image == check, I didn't test it
{
p.Image = this.o;
}
else
{
p.Image = this.x;
}
// set the flag to the opposite of whatever the flag currently is
this.isX = ! isX;
}
}
You can set value of picturebox image, but you cant get it that way.
U can use global variable out of method and go this way.
int i = 0;
private void PictureBox1_Click(object sender, EventArgs e)
{
if (i == 0)
{
pictureBox1.Image = Properties.Resources.close;
i++;
}
else
{
pictureBox1.Image = Properties.Resources.open;
i--;
}
}
You can use this.
private void pictureBox1_Click(object sender, EventArgs e)
{
if (pictureBox1.Image!=null&& getSignatureLen( pictureBox1.Image) == getSignatureLen(Properties.Resources.openeye))
{
pictureBox1.Image = Properties.Resources.closeeye;
}
else
{
pictureBox1.Image = PProperties.Resources.openeye;
}
}
public long getSignatureLen(Image img)
{
using (System.IO.MemoryStream mStream = new System.IO.MemoryStream())
{
img.Save(mStream, img.RawFormat);
return mStream.Length;
}
}
You can save the value in the un-used Tag property, of the PictureBox object.
pictureBox1.Tag = 1; //Set it to whatever
if (pictureBox1.Tag == "1") { } //Do your check
Related
I need to save an image to disk that came from a web-cam between 5 and 10 seconds ago from when the "save" command comes in via serial port.
To get there, I have the webcam going into a pictureBox.Image (using opencv4), and then 2 Bitmap variables. Every 5 seconds a timer ticks, and Stored_bitmap_2 = Stored_bitmap_1, then Stored_bitmap_1 = (bitmap) pictureBox.Image.
When the right serial command comes in, I try to
Stored_image_2.Save("C:\Users\GreenWorld\Desktop\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
and I get a run-time error of invalid parameter.
When I do the same thing in a stand-alone project with some buttons (inside the button-click event handler), it works every time.
When I do this inside the serialPort_DataReceived handler, I get all kinds of cross-thread errors. So, I moved the save attempt to its own subroutine, and that fixed that but now this.
I am by no means a professional programmer, I'm an engineer with a simple problem and I can usually write a little simplistic code to fix my immediate issue. Please go easy on me in the explanation :-)
Sample code:
using OpenCvSharp;
using OpenCvSharp.Extensions;
namespace Weld_picture
{
public partial class Form1 : Form
{
// Create class-level accessible variables
int Welding_camera_ID = 1;
VideoCapture capture;
Mat frame;
Bitmap image;
private Thread camera;
bool isCameraRunning = false;
string Serial_command = "";
Bitmap Stored_image_1;
Bitmap Stored_image_2;
bool Image_saved = false;
string Station_ID = "GWM-PWS-01";
string File_name = "";
private void CaptureCamera() // from someone else's sample code
{
camera = new Thread(new ThreadStart(CaptureCameraCallback));
camera.Start();
}
private void CaptureCameraCallback() // from someone else's sample code
{
frame = new Mat();
capture = new VideoCapture(Welding_camera_ID);
capture.Open(Welding_camera_ID);
if (capture.IsOpened())
{
while (isCameraRunning)
{
capture.Read(frame);
image = BitmapConverter.ToBitmap(frame);
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = image;
}
}
}
public Form1()
{
InitializeComponent();
SerialPort1.Open();
}
private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string dummy;
char CR = (char)0x0D;
while (SerialPort1.BytesToRead > 0)
{
Serial_command += (char)SerialPort1.ReadByte();
}
while (Serial_command.IndexOf(CR) > 0)
{
dummy = Serial_command.Substring(0, Serial_command.IndexOf(CR));
Serial_command = Serial_command.Substring(Serial_command.IndexOf(CR) + 1, (Serial_command.Length - (Serial_command.IndexOf(CR) + 1)));
Serial_command.Trim();
dummy.Trim();
proc_Process_serial_data(dummy);
}
}
//*************************************************************************************************************************************
/* the first timer is a 5-second interval. It's the "memory" function so that if/when the save-to-disk is triggered I can store the last-time-shutter-open image */
//*************************************************************************************************************************************
private void Timer_picture_interval_Tick(object sender, EventArgs e)
{
checkBox1.Checked = !checkBox1.Checked;
Timer_picture_interval.Stop();
Stored_image_2 = Stored_image_1;
Stored_image_1 = (Bitmap) pictureBox1.Image;
Timer_picture_interval.Start();
}
//*************************************************************************************************************************************
// the second timer is a 30-second interval. It's the way to turn capture off if the PLC/camera box somehow goes off-line
//*************************************************************************************************************************************
private void Timer_camera_powerdown_Tick(object sender, EventArgs e)
{
if (isCameraRunning)
capture.Release();
isCameraRunning = false;
Timer_picture_interval.Stop();
}
//*************************************************************************************************************************************
private void proc_Process_serial_data(string Serial_string)
{
if (Serial_string.IndexOf("Still here") > 0)
{
if (!isCameraRunning)
CaptureCamera();
isCameraRunning = true;
}
if (Serial_string.IndexOf("Sun's up") > 0)
{
Timer_picture_interval.Start();
Timer_camera_powerdown.Start();
}
if (Serial_string.IndexOf("It's dark") > 0)
{
if ((Stored_image_2 != null) && (!Image_saved)) // in case there's 2 subsequent requests to save the same thing (weld stutter)
{
File_name = "C:\\Users\\GreenWorld\\Desktop\\" + Station_ID + " D" + DateTime.Now.ToString("yyyy_MM_dd THH_mm_ss") + ".jpg";
Stored_image_2.Image.Save("C:\\Users\\GreenWorld\\Desktop\\test.bmp" , System.Drawing.Imaging.ImageFormat.Bmp );
Image_saved = true;
Timer_picture_interval.Stop();
}
Timer_camera_powerdown.Start();
}
}
}
}
You likely be able to fix the cros-threading error by simply calling your proc_Process_serial_data() method within an Invoke() call.
Change:
proc_Process_serial_data(dummy);
To:
this.Invoke((MethodInvoker)delegate ()
{
proc_Process_serial_data(dummy);
});
Also, these two lines aren't actually doing anything:
Serial_command.Trim();
dummy.Trim();
To Trim() the strings, you have capture the returned strings and re-assign them to the original variables:
Serial_command = Serial_command.Trim();
dummy = dummy.Trim();
I have a C# window form for importing and displaying multiple images.
I am able to import multiple images and display the first image, but got some problems on displaying images one by one.
The program flow: user click the button, then select multiple images. After that, the first image should be displayed on the picture box. When the user click the "next image button", the next image should be shown.
The first image is able to display on the picturebox but no idea on displaying them one by one.
Is there any configuration for achieving this or how to implement it through coding.
Thanks everyone.
My coding:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
InitializeOpenFileDialog();
}
private void InitializeOpenFileDialog()
{
// Set the file dialog to filter for graphics files.
this.openFileDialog1.Filter =
"Images (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|" +
"All files (*.*)|*.*";
// Allow the user to select multiple images.
this.openFileDialog1.Multiselect = true;
this.openFileDialog1.Title = "My Image Browser";
}
private void SelectFileButton_Click(object sender, EventArgs e)
{
DialogResult dr = this.openFileDialog1.ShowDialog();
if (dr == System.Windows.Forms.DialogResult.OK)
{
// Read the files
foreach (String file in openFileDialog1.FileNames)
{
// Create a PictureBox.
PictureBox pb = new PictureBox();
Image loadedImage = Image.FromFile(file);
pb.Height = loadedImage.Height;
pb.Width = loadedImage.Width;
pb.Image = loadedImage;
flowLayoutPanel1.Controls.Add(pb);
}
}
}
}
IMHO, there is a better way for achieving that.
You don't have to add PictureBox control for each image, it will overload your form.
My suggestion is to keep a list of all loaded images, and an indexer of the current shown image.
Code:
Add a PictureBox to your form (let's call it pictureBox1), where you want the images to shown.
In addition, add these properties to your class:
private List<Image> loadedImages = new List<Image>();
private int currentImageIndex;
In your "load images" button click event:
private void SelectFileButton_Click(object sender, EventArgs e)
{
DialogResult dr = this.openFileDialog1.ShowDialog();
if (dr == System.Windows.Forms.DialogResult.OK)
{
loadedImages.Clear();
// Read the files
foreach (String file in openFileDialog1.FileNames)
{
// Create a PictureBox.
loadedImages.Add(Image.FromFile(file));
}
if (loadedImages.Count > 0)
{
currentImageIndex = 0;
pictureBox1.Image= loadedImages[currentImageIndex];
}
}
}
And finally, for Next/Previous buttons click event you can add this code:
// Mod function to support negative values (for the back button).
int mod(int a, int b)
{
return (a % b + b) % b;
}
// Show the next picture in the PictureBox.
private void button_next_Click(object sender, EventArgs e)
{
currentImageIndex = mod(currentImageIndex + 1, loadedImages.Count);
pictureBox1.Image = loadedImages[currentImageIndex];
}
// Show the previous picture in the PictureBox.
private void button_prev_Click(object sender, EventArgs e)
{
currentImageIndex = mod(currentImageIndex - 1, loadedImages.Count);
pictureBox1.Image = loadedImages[currentImageIndex];
}
I have a pictureBox with an image inside.
I want, when i click on a button the image should hide and click again to show the image.
In the pictureBox, using paint event i am drawing some lines.
So if im doing pictureBox1.Refresh(); it will draw the lines. I want that if i click on a button the image will not display on/off.
pictureBox1 = null; or pictureBox1.Image.Dispose(); doesn't work it's showing me big red x with white background.
To hide it:
pictureBox.Visible = false;
To hide/show it in a click event:
void SomeButton_Click(Object sender, EventArgs e)
{
pictureBox.Visible = !pictureBox.Visible;
}
For toggling the image in your PictureBox you can create a 1 pixel bitmap and assign it to the picture box when you want hide your image, then assign your image back again. I am a little unclear of what the second part of your question is asking, any drawing in the picturebox's Paint Event will remain unless you exclude it in the Paint Event based on some Condition. If you want to draw a line in the box an toggle it on/off from a button see my second example.
i.e.
public partial class Form1 : Form
{
Bitmap nullBitmap = new Bitmap(1, 1); // create a 1 pixel bitmap
Bitmap myImage = new Bitmap("Load your Image Here"); // Load your image
bool showImage; // boolean variable so we know what image is assigned
public Form1()
{
InitializeComponent();
pictureBox1.Image = myImage;
showImage = true;
}
private void button1_Click(object sender, EventArgs e)
{
if (showImage)
{
pictureBox1.Image = nullBitmap;
showImage = false;
}
else
{
pictureBox1.Image = myImage;
showImage = true;
}
}
}
Second Example
public partial class Form1 : Form
{
bool showLines;
public Form1()
{
InitializeComponent();
showLines = true;
}
private void button1_Click(object sender, EventArgs e)
{
if (showLines)
{
showLines = false;
pictureBox1.Invalidate();
}
else
{
showLines = true;
pictureBox1.Invalidate();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if(showLines)
e.Graphics.DrawLine(Pens.Purple, 0, 0, 100, 100);
}
}
picturebox1.BackgroundImage = null
I was wondering how could I do this. I know I can use the button component but it has the little gray stuff around it when I give it a image. With image button how could I show another image for the hover effect
You want to create a button with no border but displays different images when the user hovers over it with the mouse? Here's how you can do it:
Add an ImageList control to your form at add two images, one for the button's normal appearance and one for when the mouse is hovering over.
Add your button and set the following properties:
FlatStyle = Flat
FlatAppearance.BorderColor (and maybe MouseOverBackColor & MouseDownBackColor) to your form's background color
ImageList = the ImageList you added to the form
ImageIndex to the index value of your normal image
Code the MouseHover and MouseLeave events for the button like this:
// ImageList index value for the hover image.
private void button1_MouseHover(object sender, EventArgs e) => button1.ImageIndex = 1;
// ImageList index value for the normal image.
private void button1_MouseLeave(object sender, EventArgs e) => button1.ImageIndex = 0;
I believe that will give you the visual effect you're looking for.
Small summary (Border, MouseDownBackColor, MouseOverBackColor)
FlatApperance
BorderColor = Black or what ever you want
BorderSize = can be set to 0
MouseDownBackColor = Transparent
MouseOverBackColor = Transparent
Text = none
For MouseDown:
// ImageList index value for the mouse down image.
private void button1_MouseDown(object sender, MouseEventArgs e) => button1.ImageIndex = 2;
You can assign the BackgroundImage property for the button. You can also use the OnMouseEnter and OnMouseExit events to change the background as per your request.
See BackgroundImage OnMouseEnter OnMouseLeave
I also needed an image button, but I wanted one like the ToolstripMenuButton.
With the correct borders and colors on hover.
So I made a custom control to do just that:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace LastenBoekInfrastructure.Controls.Controls
{
[DefaultEvent("Click")]
public class ImageButton : UserControl
{
public string ToolTipText
{
get { return _bButton.ToolTipText; }
set { _bButton.ToolTipText = value; }
}
public bool CheckOnClick
{
get { return _bButton.CheckOnClick; }
set { _bButton.CheckOnClick = value; }
}
public bool DoubleClickEnabled
{
get { return _bButton.DoubleClickEnabled; }
set { _bButton.DoubleClickEnabled = value; }
}
public System.Drawing.Image Image
{
get { return _bButton.Image; }
set { _bButton.Image = value; }
}
public new event EventHandler Click;
public new event EventHandler DoubleClick;
private ToolStrip _tsMain;
private ToolStripButton _bButton;
public ImageButton()
{
InitializeComponent();
}
private void InitializeComponent()
{
var resources = new ComponentResourceManager(typeof(ImageButton));
_tsMain = new ToolStrip();
_bButton = new ToolStripButton();
_tsMain.SuspendLayout();
SuspendLayout();
//
// tsMain
//
_tsMain.BackColor = System.Drawing.Color.Transparent;
_tsMain.CanOverflow = false;
_tsMain.Dock = DockStyle.Fill;
_tsMain.GripMargin = new Padding(0);
_tsMain.GripStyle = ToolStripGripStyle.Hidden;
_tsMain.Items.AddRange(new ToolStripItem[] {
_bButton});
_tsMain.Location = new System.Drawing.Point(0, 0);
_tsMain.Name = "_tsMain";
_tsMain.Size = new System.Drawing.Size(25, 25);
_tsMain.TabIndex = 0;
_tsMain.Renderer = new ImageButtonToolStripSystemRenderer();
//
// bButton
//
_bButton.DisplayStyle = ToolStripItemDisplayStyle.Image;
_bButton.Image = ((System.Drawing.Image)(resources.GetObject("_bButton.Image")));
_bButton.ImageTransparentColor = System.Drawing.Color.Magenta;
_bButton.Name = "_bButton";
_bButton.Size = new System.Drawing.Size(23, 22);
_bButton.Click += bButton_Click;
_bButton.DoubleClick += bButton_DoubleClick;
//
// ImageButton
//
Controls.Add(_tsMain);
Name = "ImageButton";
Size = new System.Drawing.Size(25, 25);
_tsMain.ResumeLayout(false);
_tsMain.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
void bButton_Click(object sender, EventArgs e)
{
if (Click != null)
{
Click(this, e);
}
}
void bButton_DoubleClick(object sender, EventArgs e)
{
if(DoubleClick != null)
{
DoubleClick(this, e);
}
}
public class ImageButtonToolStripSystemRenderer : ToolStripSystemRenderer
{
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{
//base.OnRenderToolStripBorder(e);
}
}
}
}
I'm trying to make a "checkbox" that has a custom check image. I need it to toggle between checked and unchecked when the user clicks the picturebox. I've tried the following code, and the first click shows the checked image fine, however a second click does nothing. Any ideas?
private void pictureBox7_Click(object sender, EventArgs e)
{
if (pictureBox7.Image == Image.FromFile(checkedImg))
{
pictureBox7.Image = Image.FromFile(uncheckedImg);
}
else
{
pictureBox7.Image = Image.FromFile(checkedImg);
}
}
Your if statement is wrong as it is unlikely to return true because you are comparing instances of the Image class which you recreate every time. You could modify it like this:
private bool _pbChecked = false;
private void pictureBox7_Click(object sender, EventArgs e)
{
var pictureBox = (PictureBox)sender;
string imgPath = _pbChecked ? uncheckedImg : checkedImg;
pictureBox.Image = Image.FromFile(imgPath);
_pbChecked = !_pbChecked;
}