I'm trying to do waste collection program and these are part of codes. My problem is if the picturebox shows image that on second if statements (magazine), there is no problem. But if shows first image that on first if statements (newspaper) and if NewWaste(); gives magazine then there is a problem. Because it adds both of them to listbox but I don't see the second image on picturebox. How can I solve that?
private void NewWaste()
{
Image[] images = new Image[] { newspaper.Image, magazine.Image, glass.Image };
int wastes = rnd.Next(images.Length);
wastePictureBox.Image = images[wastes];
}
//(part of class)
public bool Add(Waste waste)
{
if (FilledVolume + waste.Volume <= Capacity)
return true;
else
return false;
}
private void addPaperWasteBtn_Click(object sender, EventArgs e)
{
if (paperWasteBox.Add(newspaper) == true && wastePictureBox.Image == newspaper.Image)
{
paperWasteListBox.Items.Add("Newspaper");
NewWasteImage();
}
if (paperWasteBox.Add(magazine) == true && wastePictureBox.Image == magazine.Image)
{
paperAtikListBox.Items.Add("Magazine");
NewWasteImage();
}
}
If you only want the second if statement to run if the first one didn't, then you want an else if statement before the second conditional check.
Change:
if (paperWasteBox.Add(newspaper) == true && wastePictureBox.Image == newspaper.Image)
{
paperWasteListBox.Items.Add("Newspaper");
NewWasteImage();
}
if (paperWasteBox.Add(magazine) == true && wastePictureBox.Image == magazine.Image)
{
paperAtikListBox.Items.Add("Magazine");
NewWasteImage();
}
To:
if (paperWasteBox.Add(newspaper) == true && wastePictureBox.Image == newspaper.Image)
{
paperWasteListBox.Items.Add("Newspaper");
NewWasteImage();
}
else if (paperWasteBox.Add(magazine) == true && wastePictureBox.Image == magazine.Image)
{
paperAtikListBox.Items.Add("Magazine");
NewWasteImage();
}
Notice the difference in the SIXTH line!
Related
I ran into little problem today as I was working on my game...
The problem is I have this condition running on 1 milisecond timer :
if (jump == true &&
jumped == 0 &&
(Player.Location == new Point(Player.Location.X, Block1.Location.Y - Player.Height) ||
Player.Top == this.Height - Player.Height))
{
do something...
}
The "Block1" is one object in the game (Picturebox) and I need like 10 or 20 or even 100 more of these blocks with the same condition, so how could I simplify it? It would be 50 or even more lines of one condition. Basically I would like to know if there is a way of mixing all "Blocks" (pictureboxes) into a group (named Blocks) or something I could still access with Blocks.Location.Y etc
There are too many conditions in this single check, IMO. I'd break them down and then work on each condition in a stand-alone manner which will make things easier to debug as well as to read/comprehend in the future.
// Too much going on here; let's refactor.
if (jump == true
&& jumped == 0
&& (Player.Location == new Point(Player.Location.X, Block1.Location.Y - Player.Height)
|| Player.Top == this.Height - Player.Height))
{
//do something...
}
Instead of creating a large if statement, pull the conditions into a single method:
// first refactor
private bool IsValidForSomeAction()
{
if(!jump)
{
return false;
}
if(jumped != 0)
{
return false;
}
if(Player.Top == this.Height - Player.Height)
{
return true;
}
if (Player.Location == new Point(Player.Location.X, Block1.Location.Y - Player.Height))
{
return true;
}
return false;
}
After the first refator, it becomes clear that there is no need to create a new Point for the final comparison:
// second refactor
private bool IsValidForSomeAction()
{
if(!jump)
{
return false;
}
if(jumped != 0)
{
return false;
}
if(Player.Top == this.Height - Player.Height)
{
return true;
}
// only the Y location matters, no need to create a new Point for the comparison.
if (Player.Location.Y == Block1.Location.Y - Player.Height)
{
return true;
}
return false;
}
Now, let's focus on what really matters: if (Player.Location.Y == Block1.Location.Y - Player.Height). The condition boils down to the difference between the Block's Y location and the Player's Height.
Given that there may be 10, 20, 50, or 100+ Blocks to compare, then create a private field containing a collection of all the Blocks.
// override the onload event and find all the picture boxes:
private readonly List<PictureBox> _boxes = new List<PictureBox>();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_boxes.AddRange(this.Controls.OfType<PictureBox>()
}
The _boxes field can then be used for the final validation:
// third refactor
private bool IsValidForSomeAction()
{
if(!jump)
{
return false;
}
if(jumped != 0)
{
return false;
}
if(Player.Top == this.Height - Player.Height)
{
return true;
}
// only the Y location matters, no need to create a new Point for the comparison.
if(_boxes.Any(x => x.Location.Y - Player.Height == Player.Location.Y)
{
return true;
}
return false;
}
After reading this question, it has become apparent to me that I am writing my event incorrectly. However, I have no idea how I am going to be able to re-write what I have written using Object sender. My event adds the text from selected checkboxes to a two-dimensional list (report), and the order in report must be the same as the order of the selected checkboxes. Also, no more than two checkboxes can be selected at a time. Here is the event:
void checkedListBox_ItemCheck(CheckedListBox chkdlstbx, ItemCheckEventArgs e)
{
int index = Convert.ToInt32(chkdlstbx.Tag);
if ((chkdlstbx.CheckedItems.Count == 0) && (e.CurrentValue == CheckState.Unchecked))
{
Var.report[index].Add(chkdlstbx.Text);
}
if ((chkdlstbx.CheckedItems.Count == 1) && (e.CurrentValue == CheckState.Checked))
{
Var.report[index].RemoveAt(0);
}
if ((chkdlstbx.CheckedItems.Count == 1) && (e.CurrentValue == CheckState.Unchecked))
{
if (chkdlstbx.SelectedIndex < chkdlstbx.CheckedIndices[0])
{
Var.report[index].Insert(0, chkdlstbx.Text);
}
else
{
Var.report[index].Add(chkdlstbx.Text);
}
}
if ((chkdlstbx.CheckedItems.Count == 2) && (e.CurrentValue == CheckState.Checked))
{
if (chkdlstbx.SelectedIndex == chkdlstbx.CheckedIndices[0])
{
Var.report[index].RemoveAt(0);
}
else
{
Var.report[index].RemoveAt(1);
}
}
if ((chkdlstbx.CheckedItems.Count == 2) && (e.CurrentValue == CheckState.Unchecked))
{
e.NewValue = CheckState.Unchecked;
}
updateReport();
}
It is being called by this line:
chkdlstbx.ItemCheck += new ItemCheckEventHandler(checkedListBox_ItemCheck);
If anyone could help me re-write my event using object, that'd be awesome. I'm not really sure how else I would go about solving this problem!
This should suffice:
void checkedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
{
CheckedListBox chkdlstbx = sender as CheckedListBox;
if (chkdlstbx == null)
{
throw new InvalidArgumentException();
}
....
}
In my game I'm going to have a lot of interactions in which I'll need to see if a player has an item, and if he does and something else is true, then do an action. Described in the following code.
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit == true)
{
foreach (Item item in player.PlayerInventory.Items)
{
if (item.ItemName == "tinder")
{
foreach (Item pit in allItemsOnGround)
{
if (pit.ItemName == "firepit" &&
pit.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
item.ItemName = "empty";
pit.ItemName = "firepitwithtinder";
pit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
}
oldMouseState = currentMouseState;
}
}
As you can see, this is ugly to look at and I think that there would be a better way to do this, but I'm not sure how. Since there will be a lot of these types of methods, I'm wondering what would be the best way to accomplish this?
Seems like you could get rid of (actually hide) the loops altogether by using some LINQ:
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit)
{
Item tinder = player.PlayerInventory.Items.FirstOrDefault(i => i.ItemName == "tinder");
if (tinder != null)
{
Item firepit = allItemsOnGround.FirstOrDefault(i => i.ItemName == "firepit" && i.ItemRectangle.Contains(MouseWorldPosition));
if (firepit != null &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
tinder.ItemName = "empty";
firepit.ItemName = "firepitwithtinder";
firepit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
oldMouseState = currentMouseState;
}
}
This has the added advantage of short-circuiting the loop when the item is found. It also makes it easy to check against things other than the name (like an "IsFlammable" or "CanContainFire" property) so you could use multiple items instead of just "tinder" and "firepit".
If you actually intended to remove all firepits and tinder, use:
private void SetTinderInPit()
{
MouseState currentMouseState = Mouse.GetState();
if (player.NextToFirePit)
{
foreach (Item tinder in player.PlayerInventory.Items.Where(i => i.ItemName == "tinder")
{
foreach (Item firepit in allItemsOnGround.Where(i => i.ItemName == "firepit"))
{
if (firepit.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
tinder.ItemName = "empty";
firepit.ItemName = "firepitwithtinder";
firepit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
oldMouseState = currentMouseState;
}
}
Quick caveat; this code will remove all firepits with the first tinder, leaving the other tinders unscathed. I could unravel the loops to remove everything, but this function matches the provided one; and besides, I'm assuming thats not the intended behavior.
Note you do not need ToList anywhere because you are not modifying the collection during enumeration. You can always modify the items in the collection, proved with the following test:
class IntWrapper
{
public int value;
public IntWrapper(int value)
{
this.value = value;
}
}
class Program
{
static void Main(string[] args)
{
List<IntWrapper> test = new List<IntWrapper>() { new IntWrapper(1), new IntWrapper(2), new IntWrapper(3), new IntWrapper(4), new IntWrapper(5) };
foreach (IntWrapper i in test.Where(i => i.value == 1))
{
i.value = 0;
}
foreach (IntWrapper i in test)
{
Console.WriteLine(i.value);
}
Console.ReadLine();
}
}
The only real change I would make to your existing code would be to move the check for mouse state early on, to avoid checking this multiple times in your loops. In addition I would use Linq to shorten the conditions (by removing the 'if' statements):
MouseState currentMouseState = Mouse.GetState();
// I would get all the conditional checks out of the way up front first
if (player.NextToFirePit &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
{
foreach (var tinderItem in player.PlayerInventory.Items
.Where(item => item.ItemName == "tinder"))
{
foreach (var firePit in allItemsOnGround
.Where(item => item.ItemName == "firepit" &&
item.ItemRectangle.Contains(MouseWorldPosition)))
{
tinderItem.ItemName = "empty";
firePit.ItemName = "firepitwithtinder";
firePit.Texture = Content.Load<Texture2D>("firepitwithtinder");
}
}
}
oldMouseState = currentMouseState;
An alternate idea, since you were looking for a way to get rid of the 'ugly' code, would be to move some of this functionality to the player object.
I would probably use LINQ more.
Note that this is written in Notepad, not visual studio so is more of a pseudo-code.
private void SetTinderInPit()
{
var currentMouseState = Mouse.GetState();
if (!player.NextToFirePit) return;
player.PlayerInventory.Items.Where(item => item.ItemName == "tinder").ToList().ForEach(item =>
{
allItemsOnGround.Where(x => x.ItemName == "firepit" &&
x.ItemRectangle.Contains(MouseWorldPosition) &&
currentMouseState.LeftButton == ButtonState.Pressed &&
oldMouseState.LeftButton == ButtonState.Released)
.ToList().ForEach(pit =>
{
item.ItemName = "empty";
pit.ItemName = "firepitwithtinder";
pit.Texture = Content.Load<Texture2D>("firepitwithtinder");
});
});
oldMouseState = currentMouseState;
}
Is this wrong?
I always get "cb1 and firmware" even if my checkBox2 is checked. I also tried with just & instead of &&.
It was working fine before I had to add it into thread to get UI to update correctly.
private void MyWorkerThread2()
{
if (this.IsChecked(checkBox1) && (this.IsChecked(checkBox2) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware and cb2");
Prep.clean();
startedimage();
fscreate();
wipefiles();
}
else if ((this.IsChecked(checkBox1) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware");
Prep.clean();
startedimage();
wipefiles();
}
else if (myString == "86.09.0000")
{
MessageBox.Show("firmware");
if (myThread == null)
{
Prep.clean();
startedimage();
myThread = new Thread(MyWorkerThread);
myThread.IsBackground = true;
myThread.Start();
}
}
else
{
FactoryReset();
}
}
public delegate bool IsCheckedDelegate(CheckBox cb);
public bool IsChecked(CheckBox cb)
{
if (cb.InvokeRequired)
{
return (bool)cb.Invoke(new IsCheckedDelegate(IsChecked), new Object[] { cb });
}
else
{
return cb.Checked;
}
}
I always get "cb1 and firmware" even if my checkBox2 is checked.
The fact that checkBox2 is checked isn't going to change the fact that checkBox1 is also checked and so the first if statement succeeds. If checkBox1 wasn't checked, it would fall to the other sets.
It's not clear what you're trying to do here, but I would say the first two if statements need reversed.
It seems like you only want the first to be executed when checkBox2 is NOT checked.
Change:
if ((this.IsChecked(checkBox1) && (myString == "86.09.0000")))
To:
if ((this.IsChecked(checkBox1) && (!this.IsChecked(checkBox2) && (myString == "86.09.0000")))
There are four possibilities here:
none
cb1
cb2
cb1, cb2
Try reordering the code
if (this.IsChecked(checkBox1) && (this.IsChecked(checkBox2) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware and cb2");
Prep.clean();
startedimage();
fscreate();
wipefiles();
}
else if ((this.IsChecked(checkBox1) && (myString == "86.09.0000")))
{
MessageBox.Show("cb1 and firmware");
Prep.clean();
startedimage();
wipefiles();
}
How can I make some cells in DataGridView unselectable?
By 'unselectable' I mean: It cannot be selected in any way and trying to select it won't unselect any other cell.
I don't mean ReadOnly. My cells already have this property as true.
DataGridView.MultiSelect needs to be false.
Thanks to JYL's answer I wrote a code:
private int selectedCellRow = 0;
private int selectedCellColumn = 0;
private void grid_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
if (e.Cell == null || e.StateChanged != DataGridViewElementStates.Selected)
return;
if (e.Cell.RowIndex == 0 || e.Cell.ColumnIndex == 0 || e.Cell.RowIndex == 1 && e.Cell.ColumnIndex == 1)
{
e.Cell.Selected = false;
grid.Rows[selectedCellRow].Cells[selectedCellColumn].Selected = true;
}
else
{
selectedCellRow = e.Cell.RowIndex;
selectedCellColumn = e.Cell.ColumnIndex;
}
//this was only for seeing what is happening
//this.Text = selectedCellRow + " " + selectedCellColumn;
}
But this leads to StackOverflow. What condition and where I need to put to prevent that?
Added and commented the condition you were asking about.
private int selectedCellRow = 0;
private int selectedCellColumn = 0;
private void grid_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
if (e.Cell == null || e.StateChanged != DataGridViewElementStates.Selected)
return;
//if Cell that changed state is to be selected you don't need to process
//as event caused by 'unselectable' will select it again
if (e.Cell.RowIndex == selectedCellRow && e.Cell.ColumnIndex == selectedCellColumn)
return;
//this condition is necessary if you want to reset your DataGridView
if (!e.Cell.Selected)
return;
if (e.Cell.RowIndex == 0 || e.Cell.ColumnIndex == 0 || e.Cell.RowIndex == 1 && e.Cell.ColumnIndex == 1)
{
e.Cell.Selected = false;
grid.Rows[selectedCellRow].Cells[selectedCellColumn].Selected = true;
}
else
{
selectedCellRow = e.Cell.RowIndex;
selectedCellColumn = e.Cell.ColumnIndex;
}
}
You can use the event "CellStateChanged".
private void DataGridViewXYZ_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
if (e.Cell == null
|| e.StateChanged != DataGridViewElementStates.Selected)
return;
if (! [condition here : can this cell be selectable ?])
e.Cell.Selected = false;
}
EDIT : if you leave the MultiSelect property of gridView to True, you can manage yourself a "single select" gridview with unselectable cells : il the cell is selectable, clear the other selection...
I believe this article may prove useful to you:
http://blog.spencen.com/2009/04/25/readonly-rows-and-cells-in-a-datagrid.aspx
The ReadOnly property can be applied to the entire grid, a column, a row, or an individual cell.