I cannot change image in picturebox c# - c#

I have made a yatzy game in a console application, and I am currently trying to make one in a forms application.
This is what I have so far:
namespace Yatzy
{
public partial class Form1 : Form
{
public static Random kast = new Random();
public static int kast1 = kast.Next(1, 7);
public static int kast2 = kast.Next(1, 7);
public static int kast3 = kast.Next(1, 7);
public static int kast4 = kast.Next(1, 7);
public static int kast5 = kast.Next(1, 7);
public static int kast6 = kast.Next(1, 7);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if (kast1 == 1)
{
this.pictureBox_terning1.Image = new Bitmap(#"\Pics\terning1.png");
}
else if (kast1 == 2)
{
this.pictureBox_terning1.Image = new Bitmap(#"\Pics\terning2.png");
}
else if (kast1 == 3)
{
this.pictureBox_terning1.Image = new Bitmap(#"\Pics\terning3.png");
}
else if (kast1 == 4)
{
this.pictureBox_terning1.Image = new Bitmap(#"\Pics\terning4.png");
}
else if (kast1 == 5)
{
this.pictureBox_terning1.Image = new Bitmap(#"\Pics\terning5.png");
}
else if (kast1 == 6)
{
this.pictureBox_terning1.Image = new Bitmap(#"\Pics\terning6.png");
}
else
{
this.pictureBox_terning1.Image = new Bitmap(#"\Pics\terning0.png");
}
}
}
}
As you can see, I define the "kast1" and such in the form, and depending on the outcome, it should display different images in the picturebox. I have looked at every post I could find, and all of the solutions were fuss.
I have tried without "this." and I've tried with "= image.FromFile("Pics\terning#.png");"
Nothing works.

There is no need to use Bitmap object just to load images in the PictureBox.Perhaps the more cleaner way of loading images is by using the Load Method of PictureBox.
If I assume the images are in same directory as your application,enclosed in another folder,this would have done the job easily;
this.pictureBox_terning1.Load(#"\Pics\terning1.png");
The Load method requires a valid path that points to an image as argument,and with this there is no need to call Refresh after loading each image.It doesn't matter if the path is absolute or relative,but the thing that matters is that the path should point to an image.
But I would suggest you to create an absolute path to your executable like this;
string apppath=Application.StartupPath;
string imagepath=#"\Pics\terning1.png";
this.pictureBox_terning1.Load(apppath+imagepath);
As you mentioned that even if no errors are encountered,the images are not being loaded,for such a case debugging would be an ideal technique to find where the program runs out of order.

You probably need to call Refresh() on the picturebox control after you change picture source.

It is most likely that the images you want to load are not at the path you are looking at.
image.FromFile("Pics\terning#.png");
Expects that your images reside in {youprojectfolder}\bin\DebugORRelease\Pics.
new Bitmap(#"\Pics\terning1.png");
Expects that you images reside in {most likely c:}\Pics.
So i would suggest to check this first and if this does not work add a Breakpoint (F9) and start debugging (F5) see MSDN for an introduction in debugging
I would also suggest you to replace your if, else if construct with a switch.

Try this code, which I have tried and works(it will get the bin directory of your app then you can replace folders with image directory):
private void pictureBox1_Click(object sender, EventArgs e)
{
string path = AppDomain.CurrentDomain.BaseDirectory;
string path1 = path.Replace(#"\bin\Debug\", #"\Pics\");
if (kast1 == 1)
{
this.pictureBox_terning1.Image = new Bitmap(path1 + "terning1.png");
}
//rest of the code
}
And if you dont like replacing then set your pictures to be copied to bin directory by
right clicking on image -> properties -> Copy to output directory -> copy
always
.

Related

Getting resources Image path from Picturebox [duplicate]

I have a program which has 16 grid tiles using picturebox but only uses 5 images, the rest of the tiles are just a black image.
I would like to be able to tell which image the 'user' clicks on.
I have a method called image_Click(object sender, EventArgs e)
I have an if statement inside this method that states:
if (peckedSquare.BackColor == Color.Black)
{
System.Diagnostics.Debug.WriteLine("Pecked a black square");
return;
}
This sends a String that lets me know when a black square has been clicked.
Is there an easy way to perhaps say:
//pseudo code:
if (peckedSquare.ImageName == pigeon1.png)
{
System.Diagnostics.Debug.WriteLine("Pecked Pigeon number 1");
}
I have googled my query but I have not found any suitable answers.
//EDIT
I have just re-read my code.
I was assigning each picture to a picturebox square using a randomnumber.
I had this random number as a variable, so I can just use that variable to determine which image was clicked.
ie.
if (randomNumber == 1)
{
System.Diagnostics.Debug.WriteLine("Pecked Pigeon number 1");
}
or better than that
pigeonSelected = randomNumber + 1 //as I am using an array to store the images
System.Diagnostics.Debug.WriteLine("Pecked Pigeon Number {0}", pigeonSelected);
As quick & dirty solution I would use Tag property for that, null for black tiles and file path for the others (and it's always available, even if your image comes from resources), something like this:
if (peckedSquare.Tag == null)
{
Debug.WriteLine("Pecked a black square");
}
else
{
switch (Path.GetFileName(peckedSquare.Tag.ToString()))
{
case "pigeon1.png":
break;
}
}
Of course when you create tiles you have to store file path in Tag:
PictureBox tile = new PictureBox();
tile.Image = Image.FromFile(path); // Or another source, of course
tile.Tag = path;
As alternative you may even use Name property for this, each control is named (primary for designer-code integration) but if you create controls at run-time you can set that value to anything you want (not only valid identifiers). Same usage as above just no need to call ToString().
How to Improve?
Please let me say this solution is not very OOP. Even without a big refactoring we can do little bit better. Note that you can store whatever you want in Tag property. A number, a simple string unrelated to file name or even (maybe better) a class or an enum that represents that image (to delegate action to that object). This is a very raw example:
abstract class Tile {
public abstract void Activate();
}
sealed class EmptyTile : Tile {
public virtual void Activate() {
Debug.WriteLine("Pecked a black square");
}
}
sealed class ImageTile : Tile {
public ImageTile(string content) {
_content = content;
}
public virtual void Activate() {
Debug.WriteLine(_content);
}
private string _content;
}
In this way in your click event handler you can do this:
((Tile)peckedTile.Tag).Activate();
No need to check what's inside or to compare with null. No if and no switch, just don't forget to put proper object (ImageTile or BlackTile) when you create tiles.
Use PictureBox.Load(string) method to load images from file. Then the file path will be stored in the
PictureBox.ImageLocation property:
A call to the Load method will overwrite the ImageLocation property, setting ImageLocation to the URL value specified in the method call.
So you can write for example:
if (peckedSquare.ImageLocation.EndsWith("pigeon1.png"))
{
System.Diagnostics.Debug.WriteLine("Pecked Pigeon number 1");
}
I think you could do something like the following:
private List<PictureBox> pictures = null;
string[] ImageNames = new string[]
{
"images\\test_1.jpg",
"images\\test_2.jpg"
};
private void Form1_Load(object sender, EventArgs e)
{
pictures = new List<PictureBox>();
for (var idx = 0; idx < ImageNames.Length; idx++)
{
pictures.Add(new PictureBox());
pictures[idx].Image = new Bitmap(ImageNames[idx]);
pictures[idx].Click += OnClick;
// you'll want to set the offset and everything so it shows at the right place
Controls.Add(pictures[idx]);
}
}
private void OnClick(object sender, EventArgs eventArgs)
{
// you'll definitely want error handling here
var ImageName = ImageNames[pictures.IndexOf((PictureBox) sender)];
}
You can see that in the click method you will be able to get the image name, which is what you are looking for I believe.
As others have said, you can also use the "Tag" property assuming you weren't already using this for some other purpose. The nice thing about tag is you can probably also edit it through the form designer which allows you to lay things out a little more nicely than the automatic layout I used above. Good luck!
You can do something like this using the Tag property like #Adriano suggested:
public Form1()
{
InitializeComponent();
pictureBox1.Click += pictureBox_Click;
pictureBox2.Click += pictureBox_Click;
pictureBox3.Click += pictureBox_Click;
// ...
pictureBox1.Tag = "picture1.png";
pictureBox2.Tag = "picture2.png";
pictureBox3.Tag = "picture3.png";
}
void pictureBox_Click(object sender, EventArgs e)
{
PictureBox pb = sender as PictureBox;
if (pb.BackColor != Color.Black)
Debug.WriteLine(pb.Tag.ToString());
else
Debug.WriteLine("Black image");
}

c# select Folders or Files in the same method

Okay, so please don't flame me too much, this is my 1st question here, and maybe what I am trying to do is not even possible. Obviously I am not an expert; that's why I am coming to you. :)
I have searched all over here, MSDN, and the rest of the internet (most of which points back here) without any luck. I did see one question asking about using the OpenFileDialog to select a folder instead of a file. I am almost certain that I have seen this in mainstream applications, but the question was marked as being too vague, and that particular caveat was unaddressed in the responses.
I have some text boxes that need file/folder paths. I want to simplify the two methods that handle this, into one. The only difference, is that once selects a file, and the other selects a folder. For simplicity and readability, I'd like to consolidate them.
Is this possible, without literally putting the contents of each code method into a big IF ?
Here are the two methods:
private void FolderBrowser(object sender, EventArgs e)
{
TextBox SenderBox = sender as TextBox;
if (SenderBox.Text != "")//if the text box is not empty
{
//set the selected path to the text box's current contents (incase of accidental entry)
FileBrowserDialog.FileName = SenderBox.Text;
}
if (FileBrowserDialog.ShowDialog() == DialogResult.OK)
{
SenderBox.Text = FileBrowserDialog.FileName;
}
}
private void FileBrowser(object sender, EventArgs e)
{ //basically the same as the folder browser above, but for selecting specific files
TextBox SenderBox = sender as TextBox;
if (SenderBox.Text != "")//if the text box is not empty
{
//set the selected path to the text box's current contents (incase of accidental entry)
FileBrowserDialog.FileName = SenderBox.Text;
}
if (FileBrowserDialog.ShowDialog() == DialogResult.OK)
{
SenderBox.Text = FileBrowserDialog.FileName;
}
}
I have added a Tag to each TextBox, indicating if it needs a file or a folder. I'd like to use the Tag as the condition by which I determine if I should be using a file or folder browser. This is where my ignorance shows; I had envisioned something like this NONWORKING code:
private void browser(object sender, EventArgs e)
{
//cast sender as a textbox
TextBox tBox = (TextBox)sender;
object browser = null;
if (tBox.Tag.ToString().Equals("Folder"))
{
browser = new FolderBrowserDialog();
}
else
{
browser = new OpenFileDialog();
}
if (tBox.Text != "")//if the text box is not empty
{
//set the selected path to the text box's current contents (incase of accidental entry)
browser.FileName = tBox.Text;
}
if (browser.ShowDialog() == DialogResult.OK)
{
tBox.Text = browser.FileName;
}
}
Am I crazy, or is there a way to accomplish what I have in mind? To be clear, I want to know if there is:
An existing Object/Method that would allow for the selection of a file or a folder, or
A way to dynamically re-define an object as a different type of object
Any other way to use 1 Method to dynamically allow for the use of OpenFileDialog or FileBrowserDialog based on some Tag defined on the calling object.
This is the easiest way I've found of solving this problem without relying on third party code, but you'll need to add some sanity checks, in case the user goofs around with the input:
OpenFileDialog ofd = new OpenFileDialog();
ofd.CheckFileExists = false;
string defaultFilename = "Select this folder";
ofd.FileName = defaultFilename;
if (ofd.ShowDialog().Value)
{
// Check if the user picked a file or a directory, for example:
if (!ofd.FileName.Contains(defaultFilename))
{
// File code
}
else // You should probably turn this into an else if instead
{
// Directory code
}
// Alternatively, but still as unsafe
if (File.Exists(ofd.FileName))
{
// File code
}
else
{
// Directory code
}
}
Basically, the "trick" here is to set OpenFileDialog's CheckFileExists to false.
Try using FolderBrowserDialogEx.
See detailed answers here:
How do you configure an OpenFileDialog to select folders?
Both dialogs (FileOpenDialog and FolderBrowserDialog) inherit from CommonDialog; however, this base class has no property to retrieve the result. Moreover, the property is named differently in both dialogs.
You can solve the problem by creating a wrapper. Inheritance is the proper way of re-defining an object as different type.
public abstract class FileFolderDialogBase
{
public abstract bool ShowDialog();
public string Result { get; protected set; }
}
public class FileDialog : FileFolderDialogBase
{
public override bool ShowDialog()
{
var ofd = new OpenFileDialog();
if ofd.ShowDialog() == DialogResult.OK) {
Result = ofd.FileName;
return true;
}
return false;
}
}
public class FolderDialog : FileFolderDialogBase
{
public override bool ShowDialog()
{
var fbd = new FolderBrowserDialog();
if (fbd.ShowDialog() == DialogResult.OK)
Result = fbd.SelectedPath;
return true;
}
return false;
}
}
Usage:
var dialog = textBox.Tag == "Folder" ? new FolderDialog() : new FileDialog;
if (dialog.ShowDialog()) {
textBox.Text = dialog.Result;
}
You can push it further by creating a factory class
public static class FileFolderDialog
{
public static FileFolderDialogBase Create(string type)
{
swich (type.ToLowerInvariant()) {
case "folder":
case "dir":
case "directory":
return new FolderDialog();
default:
return new FileDialog();
}
}
}
Usage
var dialog = FileFolderDialog.Create(textBox.Tag);
if (dialog.ShowDialog()) {
textBox.Text = dialog.Result;
}
why you not try extending the TextBox Class?
It's easy and reusable and you only need to drag and drop your custom control to the WinForm
class FileTextBox : System.Windows.Form.TextBox{
//===>This enumeration is more readable insted of a string XD
public enum DialogType{
File,Folder
}
//===>This property we will handle what kind of Dialog to show
public DialogType OpenDialogType{
get;
set;
}
//===>This is where Object Oriented Programming a& Design do his magic
public System.Windows.Forms.DialogResult ShowDialog(string Title =""){
//===>This function is where we define what kind of dialog to show
System.Windows.Forms.DialogResult Result = System.Windows.Forms.DialogResult.None ;
object Browser=null;
switch(this.OpenDialogType){
case DialogType.File:
Browser = new OpenFileDialog();
((Browser)OpenFileDialog).Title= Title;
if(this.Text.Trim() !="" && this.Text != null ){
((Browser)OpenFileDialog).FileName = this.Tex;
}
Result = ((Browser)OpenFileDialog).ShowDialog();
break;
case DialogType.Folder:
Browser = new FolderBrowserDialog ();
((Browser)FolderBrowserDialog).Description = Title;
if(this.Text.Trim() !="" && this.Text != null ){
((Browser)FolderBrowserDialog).RootFolder = this.Text;
}
Result = ((Browser)FolderBrowserDialog).ShowDialog();
break;
}
return Result;//===>We return thi dialog result just if we want to do something else
}
}
/*
Create a class and copy/paste this code, I think is going to work because
I didn't compiled then go to ToolBox window find this control and Drag & Drop
to your WinForm and in the property window find OpenDialogType property
and this is where you kind define the behavior of OpenDialog();
I'm currently working in a little project in Vs where I create a custom
UI Control downloaded from my git repository
https://github.com/MrAlex6204/GYMSystem
*/

How do you access the name of the image in a picturebox in Visual Studio using C#

I have a program which has 16 grid tiles using picturebox but only uses 5 images, the rest of the tiles are just a black image.
I would like to be able to tell which image the 'user' clicks on.
I have a method called image_Click(object sender, EventArgs e)
I have an if statement inside this method that states:
if (peckedSquare.BackColor == Color.Black)
{
System.Diagnostics.Debug.WriteLine("Pecked a black square");
return;
}
This sends a String that lets me know when a black square has been clicked.
Is there an easy way to perhaps say:
//pseudo code:
if (peckedSquare.ImageName == pigeon1.png)
{
System.Diagnostics.Debug.WriteLine("Pecked Pigeon number 1");
}
I have googled my query but I have not found any suitable answers.
//EDIT
I have just re-read my code.
I was assigning each picture to a picturebox square using a randomnumber.
I had this random number as a variable, so I can just use that variable to determine which image was clicked.
ie.
if (randomNumber == 1)
{
System.Diagnostics.Debug.WriteLine("Pecked Pigeon number 1");
}
or better than that
pigeonSelected = randomNumber + 1 //as I am using an array to store the images
System.Diagnostics.Debug.WriteLine("Pecked Pigeon Number {0}", pigeonSelected);
As quick & dirty solution I would use Tag property for that, null for black tiles and file path for the others (and it's always available, even if your image comes from resources), something like this:
if (peckedSquare.Tag == null)
{
Debug.WriteLine("Pecked a black square");
}
else
{
switch (Path.GetFileName(peckedSquare.Tag.ToString()))
{
case "pigeon1.png":
break;
}
}
Of course when you create tiles you have to store file path in Tag:
PictureBox tile = new PictureBox();
tile.Image = Image.FromFile(path); // Or another source, of course
tile.Tag = path;
As alternative you may even use Name property for this, each control is named (primary for designer-code integration) but if you create controls at run-time you can set that value to anything you want (not only valid identifiers). Same usage as above just no need to call ToString().
How to Improve?
Please let me say this solution is not very OOP. Even without a big refactoring we can do little bit better. Note that you can store whatever you want in Tag property. A number, a simple string unrelated to file name or even (maybe better) a class or an enum that represents that image (to delegate action to that object). This is a very raw example:
abstract class Tile {
public abstract void Activate();
}
sealed class EmptyTile : Tile {
public virtual void Activate() {
Debug.WriteLine("Pecked a black square");
}
}
sealed class ImageTile : Tile {
public ImageTile(string content) {
_content = content;
}
public virtual void Activate() {
Debug.WriteLine(_content);
}
private string _content;
}
In this way in your click event handler you can do this:
((Tile)peckedTile.Tag).Activate();
No need to check what's inside or to compare with null. No if and no switch, just don't forget to put proper object (ImageTile or BlackTile) when you create tiles.
Use PictureBox.Load(string) method to load images from file. Then the file path will be stored in the
PictureBox.ImageLocation property:
A call to the Load method will overwrite the ImageLocation property, setting ImageLocation to the URL value specified in the method call.
So you can write for example:
if (peckedSquare.ImageLocation.EndsWith("pigeon1.png"))
{
System.Diagnostics.Debug.WriteLine("Pecked Pigeon number 1");
}
I think you could do something like the following:
private List<PictureBox> pictures = null;
string[] ImageNames = new string[]
{
"images\\test_1.jpg",
"images\\test_2.jpg"
};
private void Form1_Load(object sender, EventArgs e)
{
pictures = new List<PictureBox>();
for (var idx = 0; idx < ImageNames.Length; idx++)
{
pictures.Add(new PictureBox());
pictures[idx].Image = new Bitmap(ImageNames[idx]);
pictures[idx].Click += OnClick;
// you'll want to set the offset and everything so it shows at the right place
Controls.Add(pictures[idx]);
}
}
private void OnClick(object sender, EventArgs eventArgs)
{
// you'll definitely want error handling here
var ImageName = ImageNames[pictures.IndexOf((PictureBox) sender)];
}
You can see that in the click method you will be able to get the image name, which is what you are looking for I believe.
As others have said, you can also use the "Tag" property assuming you weren't already using this for some other purpose. The nice thing about tag is you can probably also edit it through the form designer which allows you to lay things out a little more nicely than the automatic layout I used above. Good luck!
You can do something like this using the Tag property like #Adriano suggested:
public Form1()
{
InitializeComponent();
pictureBox1.Click += pictureBox_Click;
pictureBox2.Click += pictureBox_Click;
pictureBox3.Click += pictureBox_Click;
// ...
pictureBox1.Tag = "picture1.png";
pictureBox2.Tag = "picture2.png";
pictureBox3.Tag = "picture3.png";
}
void pictureBox_Click(object sender, EventArgs e)
{
PictureBox pb = sender as PictureBox;
if (pb.BackColor != Color.Black)
Debug.WriteLine(pb.Tag.ToString());
else
Debug.WriteLine("Black image");
}

redraw image during excecution WPF

I have a smal application that should set a image to red or green depending on some tests that are made. The test can take a few second, and each one has a custom control with an image connected to it. When I click start I would like for the first test to be done, show the result by changing the image on that one, and then move on. But as it is now, all tests are made (maybe 10 seconds), then ALL the lights are changing at the same time. How can I force the custom control to update the image during the excecution?
private void start_Click(object sender, RoutedEventArgs e)
{
foreach (TestObject tObj in tObjList)
{
bool testResult = tObj.makeTest();
foreach (TestShower ts in m_TSList)
{
if (tObj == ts.gettObj())
{
if (testResult == true)
ts.setLightOn();
else
ts.setLightOff();
ts.UpdateLayout();
break;
}
}
}
}
public void setLightOn()
{
string strUri2 = String.Format(#"pack://application:,,,/;component/Images/Signal_On.png");
BitmapImage img = new BitmapImage(new Uri(strUri2));
iStatus.Source = null;
iStatus.Source = img;
}
public void setLightOff()
{
string strUri2 = String.Format(#"pack://application:,,,/;component/Images/Signal_Off.png");
BitmapImage img = new BitmapImage(new Uri(strUri2));
iStatus.Source = null;
iStatus.Source = img;
}
you should read into Async and await and perform each test at the same time and await the results (obviously this assumes your tests are not interdependant)
and some form of implementation of
Task.Factory.StartNew(() => {
var result = ts.makeTest();
setLight1(result);
})
Although without knowing more it would seem as though you could perform this using databinding to a ViewModel that implements INotifyPropertyChanged on a List of Test Objects.
but not performing the tests asynchronously is the main cause of your issue
i know external links are not really preferred in SO but here is a tutorial
http://www.youtube.com/watch?v=ZyFL3hjHADs
Run the tests in the background and then use Dispatcher to update UI thread:
For WPF & Net 4.5. you can use TPL
private void start_Click(object sender, RoutedEventArgs e)
{
Task.Run(()=>{
foreach (TestObject tObj in tObjList)
{
bool testResult = tObj.makeTest();
Dispatcher.Invoke(()=>{
foreach (TestShower ts in m_TSList)
{
if (tObj == ts.gettObj())
{
if (testResult == true)
ts.setLightOn();
else
ts.setLightOff();
ts.UpdateLayout();
break;
}
}});
}
}
});
}

C# : getting folder name when right click on it

I am developing a windows application, I need to get the Folder name while right clicking on the Folder to do some operations on it .
So far I did the following :
Made a registry subkey in HKKEY_CLASS_ROOT\Folder\shell\(my program name)
Made a registry subkey of my program name\command [the path of my program]
now I made the registry key to be displayed in folder context menu. And in my application I did the following :
1- in program.cs
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 p = new Form1();
if (args.Length > 0)
{
p.pathkey = args[0];
}
Application.Run(p);
}
2- in my form1 :
private string _pathkey;
public string pathkey
{
get { return _pathkey; }
set { _pathkey = value; }
}
private void Form1_Load(object sender, EventArgs e)
{
if (this.pathkey != null)
{
textBox1.Text=pathkey;
}
}
finally :
now when I right click on a folder lets say for example called NEW. then textbox3.text = C:\NEW , so far it works fine but if the folder name is New Folder then textbox3.text = C:\New only not C:\New Folder and that is my problem if args.length > 0 it does only display the the lenght 0 not the full path.
You need to put the %0 in the registry in quotes to force the entire path to be treated as a single argument.
Otherwise, the spaces are treated as argument separators.
You could also call String.Join(" ", args) to manually recombine all of the arguments, but the first way is better.

Categories