Sorry, but I have another problem. In my code I can now get it to randomly assign pictures to pictureboxes but unfortunately I cannot get any of the pictureboxes to become visible, upon clicking them, this event should happen:
private void pictureBox1_Click(object sender, EventArgs e)
{
// The timer is only on after two non-matching
// icons have been shown to the player,
// so ignore any clicks if the timer is running
if (timer1.Enabled == true)
{
return;
}
PictureBox clickedpicturebox = sender as PictureBox;
if (clickedpicturebox == null)
{
// If the clicked picture is visible, the player clicked
// an icon that's already been revealed --
// ignore the click
if (clickedpicturebox.Visible == true)
return;
// If firstClicked is null, this is the first icon
// in the pair that the player clicked,
// so set firstClicked to the picturebox that the player
// clicked, make it visible, and return
if (firstClicked.Tag == null)
{
clickedpicturebox = firstClicked;
firstClicked.Tag = clickedpicturebox.Tag;
firstClicked.Visible = true;
}
// If the player gets this far, the timer isn't
// running and firstClicked isn't null,
// so this must be the second icon the player clicked
// Set its property to visible
clickedpicturebox = secondClicked;
secondClicked.Tag = clickedpicturebox.Tag;
secondClicked.Visible = true;
// If the player gets this far, the player
// clicked two different icons, so start the
// timer (which will wait three quarters of
// a second, and then hide the icons)
timer1.Start();
}
}
But for some reason, even if I strip it down to just a line that says:
PictureBox clickedpicturebox = sender as PictureBox;
clickedpicturebox.Visible = true;
It still doesn't work, could it be because I selected multiple pictures to apply the event to at the same time?
Also, incase you need it, I have the properties of the first picturebox here, all other pictureboxes are essentially the same.
//
// pictureBox1
//
this.pictureBox1.BackColor = System.Drawing.Color.Transparent;
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pictureBox1.Location = new System.Drawing.Point(5, 5);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(125, 119);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
this.pictureBox1.Visible = false;
this.pictureBox1.Click += new System.EventHandler(this.pictureBox1_Click);
EDIT: I would like to thank everyone, the problem is now resolved, I have used the labels allow me to easily interact between the foreground and background colours, allowing for easy transition between a label and a picturebox.
H W and ASh are both correct, the problem is resolved.
Related
I have an app with 2 forms. Form1 have the pictureBox and buttons, Form2 has a code that, when i call the form:
private void button1_Click(object sender, EventArgs e)
{
new Form2().Show();
}
it turns is a Zoom Lens, that i can use in Form1 pictureBox.
Problem is, when Form2(lens) is runing and i click ESC to close the form2, it closes but keep increasing consuming memory. Even the errors that form2(lens) has is triggering, like move mouse too far at the border, even after call close to form2.
Here is the code to the Lens form2:
PictureBox pictureBox1 = new PictureBox(); // Have a picture box
int zoom = 1; // Variable for zoom value
public Form1()
{
pictureBox1.Dock = DockStyle.Fill; // Occupy the full area of the form
pictureBox1.BorderStyle = BorderStyle.FixedSingle; // Have a single border of clear representation
Controls.Add(pictureBox1); // Add the control to the form
FormBorderStyle = FormBorderStyle.None; // Make the form borderless to make it as lens look
Timer timer = new Timer(); // Have a timer for frequent update
timer.Interval = 100; // Set the interval for the timer
timer.Tick += timer_Tick; // Hool the event to perform desire action
timer.Start(); //Start the timer
printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); // Have a bitmap to store the image of the screen
}
void timer_Tick(object sender, EventArgs e)
{
var graphics = Graphics.FromImage(printscreen as Image); // Get the image of the captured screen
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size); // Get the copy of screen
var position = Cursor.Position; // Get the position of cursor
var lensbmp = new Bitmap(50, 50); // Have a bitmap for lens
var i = 0; // Variable for row count
var j = 0; // Variable for column count
for (int row = position.X - 25; row < position.X + 25; row++) // Indicates row number
{
j = 0; // Set column value '0' for new column
for (int column = position.Y - 25; column < position.Y + 25; column++) // Indicate column number
{
lensbmp.SetPixel(i, j, printscreen.GetPixel(row, column)); // Place current region pixel to lens bitmap
j++; // Increase row count
}
i++; // Increase column count
}
this.pictureBox1.Image = new Bitmap(lensbmp, lensbmp.Width * zoom, lensbmp.Height * zoom); // Assign lens bitmap with zoom level to the picture box
Size = pictureBox1.Image.Size; // Assign optimal value to the form
Left = position.X + 20; // Place form nearer to cursor X value
Top = position.Y + 20; // Place form nearer to cursor Y value
TopMost = true; // Keep the form top level
}
// Override OnKeyDown for zoom in and zoom out actions
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyValue == 73) // Set "i" as the key for Zoom In.
zoom++; // Increase zoom by 1 item greater
else if (e.KeyValue == 79) // Set "o" as the key for Zoom Out
zoom--; // Decrease zoom by 1 item smaller
else if (e.KeyValue == 27) // Set "Esc" to close the magnifier
{
Close(); // Close the form
Dispose(); // Dispose the form
}
base.OnKeyDown(e);
}
Is that a way to close this form2 and stop all methods while form1 keep runing? It keep increasing memory consume like 1mb for sec.
You have a dangerous timer because it isn't declared at the form scope, so it can still keep running.
Declare it at the form level instead:
PictureBox pictureBox1 = new PictureBox();
int zoom = 1;
Timer timer = new Timer();
public Form1()
{
pictureBox1.Dock = DockStyle.Fill; // Occupy the full area of the form
pictureBox1.BorderStyle = BorderStyle.FixedSingle; // Have a single border of clear representation
Controls.Add(pictureBox1); // Add the control to the form
FormBorderStyle = FormBorderStyle.None; // Make the form borderless to make it as lens look
timer.Interval = 100; // Set the interval for the timer
timer.Tick += timer_Tick; // Hool the event to perform desire action
timer.Start(); //Start the timer
printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); // Have a bitmap to store the image of the screen
}
Also, make sure you dispose of your image and graphic objects, too, when they aren't being used anymore.
All I have created a custom hex viewer tool for viewing a particular file type.
As part of the requirements I need to highlight certain bit values once I hover over a hex range (which is implemented via C# Run class).
The problem is about 50% of the time I get multiple popups drawn on top of each other rather than one.
See below:
Here my relevant code snippet in C#:
private Popup popup = new Popup();
void ToolTip_MouseEnter(object sender, EventArgs e)
{
//TODO: base popup action on data value
if (popup.IsOpen!=true)
{
if (sender is Run && HexDocumentUIHelperUtility.zftSequenceBitsMouseUp)
{
Run runControl = sender as Run;
if (runControl != null)
{
//popup.HorizontalAlignment = HorizontalAlignment.Center;
//popup.VerticalAlignment = VerticalAlignment.Center;
TextBox textBox = new TextBox();
textBox.Text = this.getZftBitsVisualization().getBinaryString();
int startHighlight = this.getZftBitsVisualization().getHighlightIndex();
int length = this.getZftBitsVisualization().getHighlightLength();
//textBox.SelectionStart = startHighlight;
//textBox.SelectionLength = length;
textBox.SelectionBrush = Brushes.Gold;
textBox.Select(startHighlight, length);
textBox.FontSize = 15;
popup.Child = textBox;
//get the current mouse position
//I adjusted the mouse Y coordinate by minus 20 pixels in order to avoid the popup vbeing displayed on top of the hex range
int mouseYCoordinate = System.Windows.Forms.Control.MousePosition.Y + 20;
popup.HorizontalOffset = System.Windows.Forms.Control.MousePosition.X;
popup.VerticalOffset = mouseYCoordinate;
popup.IsOpen = true;
textBox.Focus();
}
}
}//if the pop is not already opened
}
void ToolTip_MouseLeave(object sender, EventArgs e)
{
if (sender is Run)
{
Run runControl = sender as Run;
if (runControl != null)
{
if (popup != null)
{
popup.IsOpen = false;
popup.Child = null;
}
if (highlightedRunList != null)
{
highlightedRunList.Clear();
}
}
}
}
You are testing if the popup is already open at the top of the method but not actually setting that it is until much further down.
This gives the mouse enter event chance to fire several times before finally setting IsOpen to true preventing further popups opening.
Move the setting of IsOpen to immediately after the test for the popup not being open. You can always set it back to false if the popup fails.
I have a TableLayoutPanel inside a Form and that TableLayoutPanel has five Picturebox controls inside some of its cells. What I would like to do is, move those Pictureboxes to different cells based on a list of coordinates passed as an argument. From user perspective, those Pictureboxes will disappear from one cell and reappear in another cell.(Just like a main character in tile base game where the character disappear in one cell and reappear in an adjacent cell). The update method is inside Form class and it is called by a method from another class. The problem is, it does not display each movement. It just shows initial positions of all Pictureboxes followed by some refreshing and then the final position. It should display PictureBoxes in each coordinates before it gets to the final coordinate. I tried Thread.Sleep() but it doesn't work. How do I resolve this issue?
public partial class CheckerBoard : Form
{
....
....
public void update(Position k, List<Position> p)
{
p1_picturebox.Visible = false;
p2_picturebox.Visible = false;
p3_picturebox.Visible = false;
p4_picturebox.Visible = false;
p5_picturebox.Visible = false;
// Load images in new positions
this.board.Controls.Add(k_picturebox, k.col, knight.row);
this.board.Controls.Add(p1_picturebox, p[0].col, p[0].row);
this.board.Controls.Add(p2_picturebox, p[1].col, p[1].row);
this.board.Controls.Add(p3_picturebox, p[2].col, p[2].row);
this.board.Controls.Add(p4_picturebox, p[3].col, p[3].row);
this.board.Controls.Add(p5_picturebox, p[4].col, p[4].row);
------UPDATED---------
this.Invalidate();
Thread.Sleep(3000);
}
}
UPDATE
I fixed my code as per suggestions. However, the problem still persists. Seems that it is redrawing the whole tablelayoutpanel instead of moving picture box from one cell to the other. I can see the refreshing of the tablelayoutpanel.
private void replay(State currentState)
{
DispatcherTimer timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(0.5)
};
timer.Tick += (o, e) =>
{
List<Position> pos = new List<Position>();
foreach(Position p in currentState.pawns)
{
pos.Add(p);
}
this.update(currentState.knight, pos);
currentState = currentState.next;
if (currentState == null)
{
timer.IsEnabled = false;
//this.prepareDisplay();
}
};
timer.IsEnabled = true;
}
public void update(Position knight, List<Position> pawns)
{
// Load images in new positions
this.board.Controls.Remove(knight_picturebox);
this.board.Controls.Add(knight_picturebox, knight.col, knight.row);
for(int i=0; i < pawns.Count; i++)
{
//this.board.Controls.Add(this.picBoxList[i], pawns[i].col, pawns[i].row);
this.picBoxList[i].WaitOnLoad = true;
this.board.Controls.Remove(this.picBoxList[i]);
this.board.Controls.Add(this.picBoxList[i], pawns[i].col, pawns[i].row);
}
}
UPDATE
With suspendLayout and improveLayout, redrawing is improved. But I'm wondering if it is possible not to redraw the tablelayout but just the pictureboxes so that it appears only the pictureboxes are moving.
I hope this works. Assuming that you have made the temporary list of the names of the pictureboxes into List from where you can retrieve the names and find them to move to another position. So, basically in my method you are simply shifting their positions to another cells in your tablelayout panel.
You can optimize it by using "foreach" loop to retrieve pictureboxes instead of iterating the same Controls.Find() function for each control.name of picturebox.
public void update(Position k, List<Position> p)
{
PictureBox p1 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
PictureBox p2 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
PictureBox p3 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
PictureBox p4 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
PictureBox p5 = this.Controls.Find("/* the picturebox name*/", true).FirstOrDefault() as PictureBox;
this.board.Controls.Remove(p1);
this.board.Controls.Remove(p2);
this.board.Controls.Remove(p3);
this.board.Controls.Remove(p4);
this.board.Controls.Remove(p5);
//p1_picturebox.Visible = false;
//p2_picturebox.Visible = false;
//p3_picturebox.Visible = false;
//p4_picturebox.Visible = false;
//p5_picturebox.Visible = false;
// Load images in new positions
//this.board.Controls.Add(k_picturebox, k.col, knight.row);
this.board.Controls.Add(p1, p[0].col, p[0].row);
this.board.Controls.Add(p2, p[1].col, p[1].row);
this.board.Controls.Add(p3, p[2].col, p[2].row);
this.board.Controls.Add(p4, p[3].col, p[3].row);
this.board.Controls.Add(p5, p[4].col, p[4].row);
//alternatively for the whole above code you may optimize like below.
int i = 0;
foreach(Control c in PictureBoxList) //PictureBoxList is retrieved as List<Control>
{
PictureBox p1 = this.Controls.Find(c.Name, true).FirstOrDefault() as PictureBox;
p1.Name = c.Name; //assign new name from the same list which contains pictureboxes and can get name by using c.Name
this.board.Controls.Remove(p1);
this.board.Controls.Add(p1, p[i].col, p[i].row);
i++;
}
------UPDATED-------- -
this.Invalidate();
Thread.Sleep(3000);
}
Update:
Have you tried setting the WaitOnLoad property of Picturebox to true?
Update2:
Try invalidating the board and then the new pictureBoxes particularly.
I have this code where i click control + m :
void gkh_KeyDown(object sender, KeyEventArgs e)
{
if ((e.KeyCode == System.Windows.Forms.Keys.LControlKey) || (e.KeyCode == System.Windows.Forms.Keys.RControlKey))
{
controlDown = true;
}
if (e.KeyCode == System.Windows.Forms.Keys.M && controlDown)
{
backgroundWorker1.RunWorkerAsync();
Then the backgroundworker do work event:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (mf1 == null)
{
mf1 = new MagnifierForm(mConfiguration, System.Windows.Forms.Cursor.Position);
mf1.Show();
}
}
I used a breakpoint and its getting to the MagnifierForm constructor and do everything there but when i click continue i never see this MagnifierForm form . Why ?
EDIT**
The reason i wanted to use backgroundworker to show the new form is that in the main form where i show the new form i have a timer tick event and for some reason this timer when its running only when its running making the new form to be show on a different location from the mouse cursor and the the form is moving/sliding to where the mouse cursor is.
When the timer is not working there is no problems i show the new form and its showing it exactly where the mouse cursor is.
I dont know why this timer event make the problem and the timer is not connected by anything to the new form i want to show.
This is the timer event i have in the main form:
private void timer2_Tick(object sender, EventArgs e)
{
label1.Visible = true;
if (counter == 200)
{
timer2.Enabled = false;//counter = 0;
return;
}
counter += 1;
distance = (float)counter;
CloudEnteringAlert.cloudalert(bitmapwithclouds, distance);
pictureBox1.Invalidate();
Now i found that if i remove for the test the line:
CloudEnteringAlert.cloudalert(bitmapwithclouds, distance);
And the timer is working there is no problem. The new form is show exactly where the mouse cursor is.
This is the cloudalert method that making the problem and i dont know why:
public static List<PointF> cloudalert(Bitmap bmp, float kilometers)
{
AddDistanceToPoints = new List<PointF>();
Color c1 = Color.White;
Color c2 = Color.FromArgb(c1.A,
(int)(c1.R * 1), (int)(c1.G * 1), (int)(c1.B * 1));
Load();
float distance = kilometers / (float)1.09;
clouds = new List<PointF>();
clouds1 = new List<PointF>();
file = Path.GetDirectoryName(Application.LocalUserAppDataPath) + "\\Data" + "\\Data.txt";
OptionsFile setting_file = new OptionsFile(file);
LoadPoints_X = setting_file.GetListFloatKey("Points Coordinates X");
LoadPoints_Y = setting_file.GetListFloatKey("Points Coordinates Y");
for (int i = 0; i < PointsFloat.Count; i++)
{
//clouds1.Add(new PointF(LoadPoints_X[i] - distance, LoadPoints_Y[i]));
AddDistanceToPoints.Add(new PointF(PointsFloat[i].X - distance, PointsFloat[i].Y));
}
bmp = FastComparison(bmp, Properties.Resources.clean_radar_image);
newbitmap = bmp;
for (int x = 0; x < AddDistanceToPoints.Count; x++)//clouds1.Count; x++)
{
if (AddDistanceToPoints[x].X > 0)//clouds1[x].X > 0)
{
//Color color = bmp.GetPixel((int)clouds1[x].X, (int)clouds1[x].Y);
Color color = bmp.GetPixel((int)AddDistanceToPoints[x].X, (int)AddDistanceToPoints[x].Y);
int dR = (int)color.R;
int dG = (int)color.G;
int dB = (int)color.B;
if (dR == 0 && dG == 0 && dB == 0)
{
}
else
{
//clouds.Add(new PointF(clouds1[x].X, clouds1[x].Y));
clouds.Add(new PointF(AddDistanceToPoints[x].X, AddDistanceToPoints[x].Y));
//newbitmap.SetPixel((int)clouds1[x].X, (int)clouds1[x].Y, Color.White);
newbitmap.SetPixel((int)AddDistanceToPoints[x].X, (int)AddDistanceToPoints[x].Y, Color.White);
}
}
}
//newbitmap.Save(#"d:\test\newbitmap.jpg");
if (clouds.Count == 0)
{
cloudsfound = false;
cloudsdistance.Text = distance.ToString();
//clouds = null;
return clouds
;
}
else
{
cloudsfound = true;
for (int i = 0; i < clouds.Count; i++)
{
pointtocolor.Add(clouds[i]);
cloudsdistance.Text = distance.ToString();
}
}
return clouds;
}
And in the main form im showing the new form by button click for example:
private void button1_Click(object sender, EventArgs e)
{
if (mf1 == null)
{
mf1 = new MagnifierForm(mConfiguration, System.Windows.Forms.Cursor.Position);
mf1.Show();
}
}
Then why this timer tick event or more why this method cloudalert making the form mf1 to be show on a different location for a second and then the form slide/moving to where the mouse cursor is. But when this method i remove it or stop the timer and show the new form so there is no problems the form is show right where the mouse cursor is.
And the new form i show it at any place on the screen i dont show it only over the main form i show it where ever the mosue cursor is. The mouse can be on the taskbar or at 0,0 of the screen or anyplace and then i click button1 or i have global keys hook so i make Ctrl + M
And when the timer is running with this method cloudalert the form is show at some different location then move slide to the place of where the mouse cursor is.
You can get the new form im trying to show that is a magnifying glass here:
http://www.codeproject.com/Articles/18235/Simple-Magnifier
What im trying to do is not using this magnifier menu it have but using my button click event or the ctrl + m keys to show the magnifier glass form. But i have this problem.
If im using this magnifier menu and timer is working with the method there is no problems.
Strange cant figure out where is the problem with my timer2/method cloudalert.
First - do not work with UI from multiple threads. If you want to display something when worker completes execution, then handle RunWorkerCompleted event (this handler runs on main thread):
void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
if (mf1 == null)
{
mf1 = new MagnifierForm(mConfiguration, Cursor.Position);
mf1.Show();
}
}
Second - your code is not working, because background thread exits. If you would change mf1.Show() to mf1.ShowDialog() then you'll see your form.
DoWork is run in a worker thread. You shouldn't try to change your UI from there, but only from your main UI thread.
Here is my dilemma. I have a set of 10 buttons that I use to rate something. They have a star image that when pressed gets changed from a grey one to a red one. If I press the star number 5 all the previous ones also get changed to red.
My problem is that the star that is clicked does not change its image so I found a workaround to introduce a pause inside a dispatcher block. I don't see this very elegant but it works and I was wondering if someone has a better approach.
Even if nobody finds a better way at least this code will help other people to do stuff with multiple buttons that do almost the same thing or browsing through controls in a panel.
Here is the code of the click event:
private void btnStar_Click(object sender, RoutedEventArgs e)
{
//First we get the number of the star from the control name
String strNum = (sender as Button).Name;
strNum = strNum.Replace("btnStar", "");
int idxSelected = int.Parse(strNum);
Debug.WriteLine("Selected star #" + strNum);
//We store the image ON an OFF to be used later
ImageBrush imgbrON = new ImageBrush();
imgbrON.ImageSource = new BitmapImage(new Uri("images/estrella_on.png", UriKind.Relative));
imgbrON.Stretch = Stretch.None;
ImageBrush imgbrOFF = new ImageBrush();
imgbrOFF.ImageSource = new BitmapImage(new Uri("images/estrella_off.png", UriKind.Relative));
imgbrOFF.Stretch = Stretch.None;
//If we pressed the first star when only the first was selected we reset all
if (idxSelected == 1 && iCurrentNumberOfStars == 1)
{
idxSelected = 0; //In order to deselect all stars
Debug.WriteLine("Deselect all");
}
else
{
//Here is the code to do the WORKAROUND to select the clicked star
Dispatcher.BeginInvoke(() =>
{
Thread.Sleep(500);
(sender as Button).Background = imgbrON;
});
}
iCurrentNumberOfStars = idxSelected;
foreach (UIElement child in ContentPanel.Children)
{
Thread.Sleep(10);
if (child.GetType().Name == "Button")
{
Button tmpButton = (child as Button);
Image content = tmpButton.Content as Image;
strNum = tmpButton.Name;
if (strNum.StartsWith("btnStar") == true)
{
strNum = strNum.Replace("btnStar", "");
int idxtmp = int.Parse(strNum);
if (idxtmp > idxSelected )
{
Debug.WriteLine(tmpButton.Name + ":OFF");
tmpButton.Background = imgbrOFF;
}
else
{
Debug.WriteLine(tmpButton.Name +":ON");
tmpButton.Background = imgbrON;
}
}
}
}
}
}
The reason why it's happens - Button has a visual states which manipulate the background property. When you try to set the background to your own - animation overrides your changes. If you remove background animation from visual states - it will work without a Delay.