How to Draw Lines with delay? - c#

How to add a time delay while drawing line in picturebox? I am using C #,visual studio 2010.
Graphics g = picturebox.CreateGraphics();
Pen p = new Pen(Color.Red);
for (int j = 1; j < 10; j++)
{
//Draw Line 1
g.DrawLine(p,j*3,j*3,100,100);
//----->How to put a Delay for 2 seconds So I
// see the first line then see the second after 2 sec
//Draw Line 2
g.DrawLine(p,j*10,j*10,100,100);
}

Use a timer on your drawing form. When you're ready to draw, enable the timer and start keeping track of the various lines that you need to draw (for example, in a list / array). Every time the timer fires draw 1 line in the timer's callback function and increment your "line index" (which line to draw next). When all lines are drawn, disable the timer.
For example:
public partial class DrawingForm : Form
{
Timer m_oTimer = new Timer ();
public DrawingForm ()
{
InitializeComponent ();
m_oTimer.Tick += new EventHandler ( m_oTimer_Tick );
m_oTimer.Interval = 2000;
m_oTimer.Enabled = false;
}
// Enable the timer and call m_oTimer.Start () when
// you're ready to draw your lines.
void m_oTimer_Tick ( object sender, EventArgs e )
{
// Draw the next line here; disable
// the timer when done with drawing.
}
}

You can use a simple Timer (System.Windows.Forms.Timer) and keep track of the current line index.
public partial class Form1 : Form {
private int index;
private void frmBrowser_Load(object sender, EventArgs e) {
index = 0;
timer.Interval = 2000;
timer.Start();
}
private void timer1_Tick(object sender, EventArgs e) {
index++;
pictureBox1.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e) {
Pen p = new Pen(Color.Red);
for (int j = 1; j < index; j++) {
g.DrawLine(p,j*3,j*3,100,100);
g.DrawLine(p,j*10,j*10,100,100);
}
}
}
Wrote this from head, it's not tested.

The suggestions in the other answers that add a pause by using a timer are correct but if you want the drawing of a single line to be shown slowly as well you'll need to do more that that.
You could write your own line drawing method and split the drawing of the line into segments and pause between the segments.
A quick alternative is using WPF instead of WinForms:
Add the line to a Canvas with its start and endpoint at the same position.
Add an animation to the endpoint that will move it to the desired location
Upon completion, do the same thing for the next line.
This way you do not have to write the line drawing code nor the timers.

using System.Threading;
Thread.sleep(2000);

Related

Changing Image in PictureBox using a Timer c#

I am trying to figure out how to change the images from a file folder that contains the images to be displayed on the PictureBox.
What I am trying to do is, after a given time interval in the timer, the image in the PictureBox will change.
I have my code but it doesn't seem to work because after it displays the first image, it does not change after that. Please feel free to correct me on what I'm doing wrong. Thanks for the help and advice.
public void playImage()
{
int counter = i + 1;
string[] images = Directory.GetFiles(#"C:\Users\Documents\Visual Studio 2008\Projects\UI\UI\bin\\debugIMAGES");
if (counter > images.Length - 1);
counter = 0;
pictureBox1.Image = Image.FromFile(images[counter]);
}
You can make your list of images and the counter Global variables, Then on every timer tick get an img from the list using the counter and increment it.
So you declare your list and counter as global
string[] imges = null;
int counter = 0;
Then on the Form_Load event set up the timer and read the imges from the directory
private void Form9_Load(object sender, EventArgs e)
{
imges = Directory.GetFiles(#"G:\Pics");
Timer T = new Timer();
T.Interval = 500;
T.Tick += new EventHandler(PlayTime);
T.Start();
}
Then on the timer Tick event you change the picture like this :
void PlayTime(object sender, EventArgs e)
{
// pictureBox1.Image = Image.FromFile(imges[counter++]);
pictureBox1.ImageLocation = imges[counter++]; // better to use it this way.
if (counter >= imges.Length) counter = 0; // Handling out of Bounds
}

Oxyplot updating data after the end of method

Could you please tell me why the chart is updated after the last iteration (i = 99)?
private void music_play_button_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 100; i++)
{
(hr_plot.Model.Series[0] as LineSeries).Points[0] = new DataPoint(i, HRConstants.HRMin);
(hr_plot.Model.Series[0] as LineSeries).Points[1] = new DataPoint(i, HRConstants.HRMax);
System.Threading.Thread.Sleep(10);
hr_plot.Model.InvalidatePlot(true);
};
}
The chart should change after every iteration, not after the whole loop. What is the proper solution?
The Buttoneventhandler blocks the UI-Thread while computing the new data points. As consequence, the chart only chances once the eventhandler is finished
Solution:
You could create a new dispatchertimer in your eventhandler and caluclate a single iteration on every timerTick

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();
}

Moving picture in C#

I need to write a code which moves a picture1 to the top of the screen after a click of a button. After pictire1 reaches the top 20 pixels of the screen must become invisible and make picture2 visible. This is my wrong code:
private void button1_Click(object sender, EventArgs e)
{
int b = pictureBox1.Top;
for (int i = b; i < 20; i--)
{
pictureBox1.Top = i;
System.Threading.Thread.Sleep(20);
}
if (pictureBox1.Top < 20)
{
pictureBox1.Visible = false;
pictureBox2.Visible = true;
}
}
Any ideas how can it be fixed?
This seems wrong:
for (int i = b; i < 20; i--)
{
pictureBox1.Top = i;
System.Threading.Thread.Sleep(20);
}
This would loop while i < 20. From your code, however, one can see that if Top == 20 is reached, you'd like to show another picture. So I guess that should be i >= 20 and the if should be Top <= 20.
Also, you are not refreshing your display. Due to the loop and the Sleep, there will be no UI updates.
Add this, as Cobra_Fast suggests before the Sleep:
this.Invalidate();
this.Refresh();
To sum it up, the following should work (I've also slightly modified the code to make it clearer):
private void button1_Click(object sender, EventArgs e)
{
while (pictureBox1.Top >= 20)
{
pictureBox1.Top = pictureBox1.Top - 1;
this.Invalidate();
this.Refresh();
System.Threading.Thread.Sleep(20);
}
// Here you KNOW that the picture box is at y-position 20, so there's not need
// for the IF
pictureBox1.Visible = false;
pictureBox2.Visible = true;
}
The problem with the above code is that it blocks the UI. To keep it responsive, I'd use a timer as follows:
private void button1_Click(object sender, EventArgs e)
{
// Create a threaded timer
System.Timers.Timer animationTimer = new System.Timers.Timer();
animationTimer.Interval = 20;
animationTimer.AutoReset = false; // Only one Ping! We'll activate it if necessary
animationTimer.Elapsed += new ElapsedEventHandler(AnimationStep);
animationTimer.Start();
// Disable the button also, because we don't want another timer instance to
// interfere with our running animation
button1.Enabled = false;
}
Then, create the event that's called when the timer fires:
private void AnimationStep(object source, ElapsedEventArgs e)
{
// The following code needs to be executed in the context of the UI thread.
// We need to use this.Invoke in Forms or this.Dispatcher.Invoke in WPF
this.Invoke((Action)delegate()
{
// Move picture. Note that we don't need to update the display here
// because the UI thread gets time to do its work while the timer waits
// to fire below
if (pictureBox1.Top > 20)
pictureBox1.Top--;
// Show other picture maybe. I use <= here because initially, the
// position of the picture box may already smaller than 20.
if (pictureBox1.Top <= 20)
{
pictureBox1.Visible = false;
pictureBox2.Visible = true;
}
// Or let the timer fire again if we still need to animate
else
{
(source as System.Timers.Timer).Start();
}
}
}
This works as follows: A timer is created that fires once after 20ms. It then moves the picture up one pixel and then either shows the other picture if the animation is finished or starts the timer again for moving the picture up another pixel.
This keeps the UI responsive and still allows you to animate your picture. The downside is, the animation may not be as smooth as you might want it to be in case your windows is moved or other "work" needs be done by the UI thread.
What if initially b is greater than 20? The loop won't run because the condition in the loop is that i < 20. Because the loop is not ran, nothing will ever happen.
Consider changing the condition in your loop. You probably want the picture to move up, as you're reducing the Top-property. Let's say that initially the Top of pictureBox1 is 40. Following code will work:
while(pictureBox1.Top >= 20)
{
pictureBox1.Top--;
System.Threading.Thread.Sleep(20);
Invalidate();
Refresh();
}
Since the Top is now less than 20, the if-statement can be omitted and you can just call:
pictureBox1.Visible = false;
pictureBox2.Visible = true;
Complete code:
while(pictureBox1.Top >= 20)
{
pictureBox1.Top--;
System.Threading.Thread.Sleep(20);
Invalidate();
Refresh();
}
pictureBox1.Visible = false;
pictureBox2.Visible = true;
After the pictureBox1.Top assignment, call:
this.Invalidate();
this.Refresh();
Assuming you're working with WinForms.

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