Update multiple pictureboxes at the same time - c#

I have four PictureBoxes (each PictureBox represents one dice) and a Timer that changes every 100ms source pictures (loaded in memory as List<Bitmap> imagesLoadedFromIncludedResources).
Code:
private List<PictureBox> dices = new List<PictureBox>();
private void timer_diceImageChanger_Tick(object sender, EventArgs e)
{
foreach (PictureBox onePictureBox in dices)
{
oneDice.WaitOnLoad = false;
onePictureBox.Image = //... ;
oneDice.Refresh();
}
}
I need to change all the images at once - at this moment, you can see that the images are changing from left to right with a small delay.
I tried variant with one Thread for each PictureBox (using Control.Invoke method from this answer) - it is visually little better but not perfect.

You can try to suspend form's layout logic:
SuspendLayout();
// set images to pictureboxes
ResumeLayout(false);

Parallel.ForEach
(
dices,
new ParallelOptions { MaxDegreeOfParallelism = 4 },
(dice) =>
{
dice.Image = ...;
dice.WaitOnLoad = false;
dice.Refresh();
}
);
The problem is that UI controls can only be accessed from the UI thread. If you want to use this approach, you must create a copy of your PictureBoxes and then replace the UI ones once the operation is done.
Another approach would be creating two PictureBoxes, with the first one just on the top of the other one (hiding the latter)... you change all the images and then, once the processing is complete, you iterate all the ones in the back putting them on the top which would result in a lesser delay.

I'd approach this differently - it's been a while since I've played with WinForms stuff, but I'd probably take more control over the rendering of the images.
In this example I've got the images all in one source bitmap stacked vertically, stored as a resource in assembly:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Timer timer;
private Bitmap dice;
private int[] currentValues = new int[6];
private Random random = new Random();
public Form1()
{
InitializeComponent();
this.timer = new Timer();
this.timer.Interval = 500;
this.timer.Tick += TimerOnTick;
this.dice = Properties.Resources.Dice;
}
private void TimerOnTick(object sender, EventArgs eventArgs)
{
for (var i = 0; i < currentValues.Length; i++)
{
this.currentValues[i] = this.random.Next(1, 7);
}
this.panel1.Invalidate();
}
private void button1_Click(object sender, EventArgs e)
{
if (this.timer.Enabled)
{
this.timer.Stop();
}
else
{
this.timer.Start();
}
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
if (this.timer.Enabled)
{
for (var i = 0; i < currentValues.Length; i++)
{
e.Graphics.DrawImage(this.dice, new Rectangle(i * 70, 0, 60, 60), 0, (currentValues[i] - 1) * 60, 60, 60, GraphicsUnit.Pixel);
}
}
}
}
}
The source is here if it helps: http://sdrv.ms/Wx2Ets

Related

Make picture box move across screen during runtime

I am using Windows Forms (.NET Framework) and am trying to make a picture box move a cross a screen.
I have tried using timers and this while loop but the image (it's supposed to be a plane) does not appear in the case of the while loop and the use of timers makes it difficult to remove past picture Boxes so they appear to generate a sequence of planes. How can I accomplish this?Does it have something to do with Sleep()?
private void Button1_Click(object sender, EventArgs e)
{
//airplane land
//drawPlane(ref locx, ref locy);
//timer1.Enabled = true;
while (locx > 300)
{
var picture = new PictureBox
{
Name = "pictureBox",
Size = new Size(30, 30),
Location = new System.Drawing.Point(locx, locy),
Image = Properties.Resources.plane2, //does not appear for some reason
};
this.Controls.Add(picture);
Thread.Sleep(500);
this.Controls.Remove(picture);
picture.Dispose();
locx = locx - 50;
}
You can use a "Timer" to change the position of the PictureBox regularly.
Here is a simple demo that using Timer Class you can refer to.
public partial class Form1 : Form
{
private System.Timers.Timer myTimer;
public Form1()
{
InitializeComponent();
myTimer = new System.Timers.Timer(100);
myTimer.Elapsed += new System.Timers.ElapsedEventHandler(myTimer_Elapsed);
myTimer.AutoReset = true;
myTimer.SynchronizingObject = this;
}
private void myTimer_Elapsed(object sender, ElapsedEventArgs e)
{
pictureBox1.Location = new Point(pictureBox1.Location.X + 1, pictureBox1.Location.Y);
}
private void btStart_Click(object sender, EventArgs e)
{
myTimer.Enabled = true;
}
}
The result,

Large string in label causing application to hang (C# Windows)

I am having an windows application where I am fetching data from db and binding that to a label. I am using timer and scrolling the label, this works fine when the string is around 150 characters but when I have string of around 30000 characters it just hangs out the application.
lblMsg1.AutoEllipsis = true;
private void timer1_Tick(object sender, EventArgs e)
{
try
{
if (lblMsg1.Right <= 0)
{
lblMsg1.Left = this.Width;
}
else
lblMsg1.Left = lblMsg1.Left - 5;
this.Refresh();
}
catch (Exception ex)
{
}
}
public void bindData()
{
lblMsg.Text = "Some Large text";
}
public void Start()
{
try
{
timer1.Interval = 150;
timer1.Start();
}
catch (Exception ex)
{
Log.WriteException(ex);
}
}
Why is this related to string length and causing application to hang? Thanks in advance.
I guess you are trying to create a news ticker?
I am not sure that labels are designed to hold such big strings.
Use a picturebox instead and update your code.
Define two variables in your form class. One to hold text offset and the other to hold the graphics object for the picture box. Like this:
private float textoffset = 0;
System.Drawing.Graphics graphics = null;
In the form onload do this:
private void Form1_Load(object sender, EventArgs e)
{
textoffset = (float)pictureBox1.Width; // Text starts off the right edge of the window
pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height);
graphics = Graphics.FromImage(pictureBox1.Image);
}
Your timer should then look like this:
private void timer1_Tick(object sender, EventArgs e)
{
graphics.Clear(BackColor);
graphics.DrawString(newstickertext, new Font(FontFamily.GenericMonospace, 10, FontStyle.Regular), new SolidBrush(Color.Black), new PointF(textoffset, 0));
pictureBox1.Refresh();
textoffset = textoffset-5;
}
Instead of a Label, use a TextBox and set the ScrollBars, MultiLine and WordWrap properties according to your needs. To disable editing of the TextBox (and, thus, make it behave similar to a label), use the ReadOnly property.

how to make checkboxes work in accordance with labels c#(yahtzee)

This is my form running, i want to code the checkboxes so that they can hold the picture of their specific dice
Image[] diceImages;
int[] dice;
Random rand;
#endregion
#region Initialization
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
diceImages=new Image[7];
diceImages[0] = Properties.Resources.dice_face_0;
diceImages[1] = Properties.Resources.dice_face_1;
diceImages[2] = Properties.Resources.dice_face_2;
diceImages[3] = Properties.Resources.dice_face_3;
diceImages[4] = Properties.Resources.dice_face_4;
diceImages[5] = Properties.Resources.dice_face_5;
diceImages[6] = Properties.Resources.dice_face_6;
dice = new int[5] { 0, 0, 0, 0, 0 };
rand = new Random();
}
#endregion
private void btnRoll_Click(object sender, EventArgs e)
{
for (int i = 0; i < dice.Length; i++)
dice[i] = rand.Next(1, 7);
Array.Sort(dice);
lblDie1.Image = diceImages[dice[0]];
lblDie2.Image = diceImages[dice[1]];
lblDie3.Image = diceImages[dice[2]];
lblDie4.Image = diceImages[dice[3]];
lblDie5.Image = diceImages[dice[4]];
}
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
private void chk4_CheckedChanged(object sender, EventArgs e)
{
}
i have created 5 checkboxes with names chk1-5, i have tried fitting the code in but it doesn't work, could someone help me make this code work.
While your question is pretty unclear as to how you actually want your UI to look like, what might help is the use of UserControls:
You could make a new UserControl named DiceControl that combines one dice image and its corresponding CheckBox. You can then put multiple instances of that control on your form in the designer as if it were just one control. That might help you align stuff the way you want.
All you need to do is create methods/properties on the DiceControl that allow you to get/set the current image and the current hold status.

C# - Updating a Chart in Real-Time

Bear with me, I'm new to Stack Overflow, but have used it as a resource for a long time when researching methods of programming that I'm not fond with.
I read up a tutorial on how to create a graph in a C# Windows Forms Application, and was attempting to find out how to make it update itself in real-time if I ever need to use the graph to plot the total amount of data in a sensor. To test it out, I'm using a timer, ticking at every second (1000ms). And before I can use this with a sensor, I'm having two values automatically increment by 1.
The current problem I'm facing is that the chart itself won't update, and only stays the way it was drawn when the form loaded. I thought it was because I have to redraw the chart with chart1.Update();, and I tried using that before/after recreating the chart every second. However, the result is the same regardless. I just wondered if there's something I haven't done or needs to be changed in order to update the chart in real-time.
This is where the code is at currently:
public partial class Form1 : Form
{
int a = 1;
int b = 2;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Data arrays.
string[] seriesArray = { "Cats", "Dogs" };
int[] pointsArray = { a, b };
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series.
for (int i = 0; i < seriesArray.Length; i++)
{
// Add series.
Series series = this.chart1.Series.Add(seriesArray[i]);
// Add point.
series.Points.Add(pointsArray[i]);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
a++;
b++;
// Data arrays.
string[] seriesArray = { "Cats", "Dogs" };
int[] pointsArray = { a, b };
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series.
for (int i = 0; i < seriesArray.Length; i++)
{
// Add series.
Series series = this.chart1.Series.Add(seriesArray[i]);
// Add point.
series.Points.Add(pointsArray[i]);
}
chart1.Update();
}
}
Your code has several problems:
The timer click event is not hooked up. I know that it isn't because otherwise you'd get an exception telling you that..
..you can add a series only once. You were doing it on each timer.Tick. This and all other setup commands should go into an initial method like the form load.
I have corrected the errors in the code below, but, obviously, the data don't make any sense yet.
Also: While I have added code to hook up the timer.Tick, the button.Click is not hooked up. Usually you let the designer do this by double-clicking the control to hook up the standard event of a control or by double-clicking the event in the control's event tab in the property page.
int a = 1;
int b = 2;
string[] seriesArray = { "Cats", "Dogs" };
private void Form1_Load(object sender, EventArgs e)
{
// Set palette.
this.chart1.Palette = ChartColorPalette.SeaGreen;
// Set title.
this.chart1.Titles.Add("Pets");
// Add series
this.chart1.Series.Clear();
for (int i = 0; i < seriesArray.Length; i++)
{
chart1.Series.Add(seriesArray[i]);
}
// hook up timer event
timer1.Tick += timer1_Tick;
}
private void timer1_Tick(object sender, EventArgs e)
{
a++;
b++;
// Data array
int[] pointsArray = { a, b };
for (int i = 0; i < seriesArray.Length; i++)
{
// Add point.
chart1.Series[i].Points.Add(pointsArray[i]);
}
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}

Periodic printing of shapes

I am making an application using WPF and C#. What I'm trying to do is to print a lots of shapes on a canvas with some time in between when I push a button. At the moment when I push the button, everything just pops up at once. I have tried to sleep the thread for some time between every "print" but that doesn't help, it just take longer time before everything splash up at once. What I want to achive is that the shapes pop up one at a time with lets say 0.5 seconds in between. The code is the following:
private void Create_Click(object sender, RoutedEventArgs e)
{
Random random = new Random();
for (int i = 0; i < 50; i++)
{
Thread.Sleep(500);
Path f = FlowerFactory.createFlower(FlowerBP, true);
Canvas.SetLeft(f, random.Next(0, 1650));
Canvas.SetTop(f, random.Next(0,1000));
DrawBoard.Children.Add(f);
}}
You need to, first, run the loop in a background thread so that it doesn't block the UI from updating; and second, send the UI-rendering tasks back to the UI thread. For the first, you can use Task.Factory.StartNew, and for the second, use Dispatcher.Invoke:
Random random = new Random();
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 50; i++)
{
Thread.Sleep(500);
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
Path f = FlowerFactory.createFlower(FlowerBP, true);
Canvas.SetLeft(f, random.Next(0, 1650));
Canvas.SetTop(f, random.Next(0,1000));
DrawBoard.Children.Add(f);
}));
}
});
It was bad decision to sleep your main thread that responsible for GUI.
Try to use DispatchTimer. For example:
DispatcherTimer m_dispatcherTimer = new DispatcherTimer();
int m_count = 50;
private void Init()
{
m_dispatcherTimer.Tick += new EventHandler(OnTick);
m_dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
private void Create_Click(object sender, RoutedEventArgs e)
{
m_count = 50;
m_dispatcherTimer.Start();
}
private void OnTick(object sender, EventArgs e)
{
// Draw your shapes here
if(0>=--m_count)
{
m_dispatcherTimer.Stop();
}
}
using System.Reactive.Concurrency;
using System.Reactive.Linq;
...
var subscription = Observable.Interval(TimeSpan.FromSeconds(0.5)).Take(50).Subscribe(x=>CreateRandomFlower);

Categories

Resources