I want to create a timer in a separate thread, but I'm not sure how to do it.
The timer should stop after clicking button a button.
Below I have an example that mostly works but it stops sometimes for 1-2 seconds when the loop is executing. So I guess I have to put it in a separate thread? This is what I've tried:
private void buttonStop_Click(object sender, EventArgs e)
{
timer1.Stop();
}
public void TimeThread()
{
th = new Thread(new ThreadStart(Timer));
th.Start();
}
public void Timer()
{
var delta = DateTime.Now - startTime;
textBoxSeconds.Text = delta.Seconds.ToString("n0");
textBoxMinutes.Text = Math.Floor(delta.TotalMinutes).ToString("n0");
}
EDIT:
So here is all the code that I have, still not exactly sure how to put the timer in separate thread.
namespace Imgur
{
public partial class Form1 : Form
{
bool flag = true;
int downloadedNumber = 0;
private DateTime startTime;
public Form1()
{
InitializeComponent();
}
public void buttonStart_Click(object sender, EventArgs e)
{
buttonStart.Enabled = false;
buttonStop.Enabled = true;
if (!flag)
{
flag = true;
}
startTime = DateTime.Now;
timer1.Start();
for (int i=0;i<100000 && flag;i++)
{
WebClient webClient = new WebClient();
string pic1 = rnd_str(5);
string pic2 = ".jpg";
string picture = pic1 + pic2;
//********** GETTING SIZE OF IMAGE ***********
Size sz = GetSize("http://i.imgur.com/" + picture);
string imageSize = (sz.Width.ToString() + " " + sz.Height.ToString()); ;
//********************************************
if(imageSize != "161 81")
{
webClient.DownloadFile("http://i.imgur.com/" + picture, #"e:\test\" + picture);
richTextBox1.Text += String.Format("Downloaded picture: {0}\r\n", picture);
downloadedNumber++;
textBoxDownloadedNumber.Text = string.Format("{0}", downloadedNumber);
}
webClient.Dispose();
Application.DoEvents();
if (i == 999995)
{
flag = false;
}
}
richTextBox1.Text += "End Dowloaded Session \n";
buttonStart.Enabled = true;
buttonStop.Enabled = false;
timer1.Stop();
}
public static Size GetSize(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Accept = "image/gif";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream s = response.GetResponseStream();
Bitmap bmp = new Bitmap(s);
Size sz = new Size(bmp.Width, bmp.Height);
return sz;
}
public static string rnd_str(int liczba_liter)
{
Random r = new Random();
int char_type;
string return_string = "";
int i =0;
for (i = 0; i < liczba_liter; i++)
{
if (r.Next(1, 3) == 1)
{
char_type = r.Next(1, 4);
switch (char_type)
{
case 1:
return_string += (char)r.Next(48, 58); // convertion int -> ASCII character; 48-57 are ASCII digits
break;
case 2:
return_string += (char)r.Next(97, 123); // convertion int -> ASCII character; as above but small letters
break;
case 3:
return_string += (char)r.Next(65, 91); // as above; large letters
break;
default:
i -= 1;
break;//do not add any letter if no type is allowed
}
}
else
{
i -= 1;
return_string += "";
}
}
return return_string;
}
private void buttonStop_Click(object sender, EventArgs e)
{
flag = false;
buttonStart.Enabled = true;
timer1.Stop();
}
public void timer1_Tick(object sender, EventArgs e)
{
var delta = DateTime.Now - startTime;
textBoxSeconds.Text = delta.Seconds.ToString("n0");
textBoxMinutes.Text = Math.Floor(delta.TotalMinutes).ToString("n0");
}
}
}
In your code it seems there is no connection between the timer and the print of the time passed.
You need to pay attention because it isn't possible to change GUI elements from another thread that isn't the main one.
To do this you need to use Invoke in WinForms
if (control.InvokeRequired)
{
control.Invoke(new SetControlPropertyThreadSafeDelegate(SetControlPropertyThreadSafe), new object[] { control, propertyName, propertyValue });
}
else
{
control.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { propertyValue });
}
or dispatcher in WPF/SL - http://www.switchonthecode.com/tutorials/working-with-the-wpf-dispatcher
In order to use another thread and you have some options:
Threadpool (On .Net 4) - http://msdn.microsoft.com/en-us/library/3dasc8as(v=vs.80).aspx
Thread class - http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx
BackgroundWorker Class - http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
The 3rd option is the easiest if you don't know how to work with theards
There're tree Timers in .Net take a look at the following article and select correct timer looks like you need timer from System.Threading, not from System.Windows.Forms.
Related
I can't make a function so that during the movement of the picturebox which happens with a while loop.
I executed a script on certain coordinates, I tried to do it using the switch statement, but the function simply does not work
When you run it, nothing happens, as if this line of code does not exist.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
namespace shadowfiend_minigame
{
public partial class Form1 : Form
{
private int _first_shadowrazeX = 404, _first_shadowrazeY = 204;
private int _second_shadowrazeX = 724, _second_shadowrazeY = 204;
private int _third_shadowrazeX = 1106, _third_shadowrazeY = 204;
private int zeus_hp = 1000;
private int shadow_fiend_hp = 2800;
Point point = new Point(1106, 204);
Point point2 = new Point(724, 204);
Point point3 = new Point(404, 204);
private int speed_zeus, damage_zeus;
private int shadow_fiend_damage;
Thread thread = new Thread(ShadowRaze_Click);
public Form1()
{
InitializeComponent();
this.KeyDown += new KeyEventHandler(ShadowRaze_Click);
KeyPreview = true;
}
bool CheckedBox()
{
bool checked1 = checkBox1.Checked;
bool checked2 = checkBox2.Checked;
bool checked3 = checkBox3.Checked;
if (checked1 == false && checked2 == false && checked3 == false)
{
return false;
}
else return true;
}
private async void Start_Click(object sender, EventArgs e)
{
Thread thread = new Thread(Zeus);
if (CheckedBox() == false)
{
MessageBox.Show("Выберите сложность игры!");
}
else
{
Start.Visible = false;
checkBox1.Visible = false;
checkBox2.Visible = false;
checkBox3.Visible = false;
thread.Start();
}
}
private async void Zeus()
{
Thread thread = new Thread(Zeus);
while (shadow_fiend_hp != 0)
{
for (int i = 0; i < 50; i++)
{
var x = _zeus.Location.X;
this.Invoke(new Action(() => _zeus.Location = new Point(_zeus.Location.X - 20, _zeus.Location.Y)));
Thread.Sleep(speed_zeus);
switch (_zeus.Location.X)
/*
* Here it is necessary that when the picturebox reaches a certain point while moving, the function is executed
*/
{
case 1106:
zeus_hp = zeus_hp - 200;
this.Invoke(new Action(() => label4.Text = "zeus_hp: " + zeus_hp));
break;
case 724:
zeus_hp = zeus_hp - 200;
this.Invoke(new Action(() => label4.Text = "zeus_hp: " + zeus_hp));
break;
case 404:
zeus_hp = zeus_hp - 200;
this.Invoke(new Action(() => label4.Text = "zeus_hp: " + zeus_hp));
break;
}
}
Zeus_Attack(damage_zeus);
if (shadow_fiend_hp == 0)
{
MessageBox.Show("You lose");
this.Invoke(new Action(() => Start.Visible = true));
this.Invoke(new Action(() => checkBox1.Visible = true));
this.Invoke(new Action(() => checkBox2.Visible = true));
this.Invoke(new Action(() => checkBox3.Visible = true));
}
else if (zeus_hp == 0)
{
MessageBox.Show("You win");
this.Invoke(new Action(() => Start.Visible = true));
this.Invoke(new Action(() => checkBox1.Visible = true));
this.Invoke(new Action(() => checkBox2.Visible = true));
this.Invoke(new Action(() => checkBox3.Visible = true));
}
for (int i = 0; i < 50; i++)
{
this.Invoke(new Action(() => _zeus.Location = new Point(_zeus.Location.X + 20, _zeus.Location.Y)));
Thread.Sleep(speed_zeus);
}
}
thread.Join();
ResetAll();
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
checkBox3.Checked = false;
checkBox1.Checked = false;
speed_zeus = 30;
damage_zeus = 200;
}
private void checkBox3_CheckedChanged(object sender, EventArgs e)
{
checkBox1.Checked = false;
checkBox2.Checked = false;
speed_zeus = 10;
damage_zeus = 400;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
checkBox3.Checked = false;
checkBox2.Checked = false;
speed_zeus = 50;
damage_zeus = 100;
}
private async void Zeus_Attack(int damage)
{
shadow_fiend_hp = shadow_fiend_hp - damage;
this.Invoke(new Action(() => hp.Text = "HP: " + shadow_fiend_hp));
}
private async void ShadowFiend_Attack()
{
zeus_hp = zeus_hp - 200;
this.Invoke(new Action(() => label4.Text = "HP: " + shadow_fiend_hp));
}
private void ResetAll()
=> this.Invoke(new Action(() => hp.Text = "HP: 2800"));
private async void ShadowRaze_Click(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Z:
shock.Location = new Point(_first_shadowrazeX, _first_shadowrazeY);
shock.Visible = true;
this.Update();
Thread.Sleep(100);
shock.Visible = false;
break;
case Keys.X:
shock.Location = new Point(_second_shadowrazeX, _second_shadowrazeY);
shock.Visible = true;
this.Update();
Thread.Sleep(100);
shock.Visible = false;
break;
case Keys.C:
shock.Location = new Point(_third_shadowrazeX, _third_shadowrazeY);
shock.Visible = true;
this.Update();
Thread.Sleep(100);
shock.Visible = false;
break;
}
}
}
}
Here's some pretty simple code to move a picture box around the screen using async and await. It's not based on your code - yours is far from being a Minimal Reproduceable Example. This is.
I dropped a few coptrols my form:
A combo box
Two textboxes (Offset and Period)
Two Buttons (Go and Stop)
A PictureBox (I made this public and gave it an obvious background color
Then I created this enum to state the direction I wanted to move the picture box:
public enum Direction
{
SouthEast,
East,
NorthEast,
North,
NorthWest,
West,
SouthWest,
South,
}
Then I created this worker class:
internal class PictureBoxMover
{
public bool enabled = true;
Direction _direction;
int _offset;
int _period;
Form1 _theForm;
private static Dictionary<Direction, (int deltaX, int deltaY)> _deltaRules = new Dictionary<Direction, (int deltaX, int deltaY)> {
{ Direction.North, (0, -1) },
{ Direction.South, (0, 1) },
{ Direction.East, (1, 0) },
{ Direction.West, (-1, 0) },
{ Direction.NorthEast, (1, -1) },
{ Direction.NorthWest, (-1, -1) },
{ Direction.SouthEast, (1, 1) },
{ Direction.SouthWest, (-1, 1) },
};
public PictureBoxMover (Form1 parentForm, Direction direction, int offset, int period)
{
_theForm = parentForm;
_direction=direction;
_offset=offset;
_period=period;
}
public void Disable()
{
enabled = false;
}
public async Task Run()
{
var directionRule = _deltaRules[_direction];
var offsetXY = (directionRule.deltaX * _offset, directionRule.deltaY * _offset);
while (enabled)
{
_theForm.pictureBox1.Location = new Point(_theForm.pictureBox1.Location.X + offsetXY.Item1, _theForm.pictureBox1.Location.Y + offsetXY.Item2);
await Task.Delay(_period);
}
}
}
The static _deltaRules dictionary makes sense of the Directions. The ( 1, -1 ) denotes a tuple of two integers (i.e., _deltaRules is a dictionary with a Direction as key and a two integer tuple as value
The main reason for instance of this class is to allow them to be easily cancellable (/disablable).
In the form's constructor, I bind the Direction dropdown combobox to the possible values of Direction:
DirectionDropDown.DataSource = Enum.GetNames<Direction>();
The rest of the form's class looks like this:
private PictureBoxMover? _currentPictureBoxMover = null;
private async void GoBtn_Click(object sender, EventArgs e)
{
if (Enum.TryParse<Direction>(DirectionDropDown.SelectedItem.ToString(), out var direction) &&
int.TryParse(OffsetTxt.Text, out var offset) &&
int.TryParse(PeriodTxt.Text, out var period))
{
if (_currentPictureBoxMover != null)
{
_currentPictureBoxMover.Disable();
}
_currentPictureBoxMover = new PictureBoxMover(this, direction, offset, period);
await _currentPictureBoxMover.Run();
}
}
private void StopBtn_Click(object sender, EventArgs e)
{
if (_currentPictureBoxMover != null)
{
_currentPictureBoxMover.Disable();
}
_currentPictureBoxMover = null;
}
I keep track of the _currentPictureBoxMover so that I can disable it when I start moving in a new direction. Otherwise the code is pretty self-explanatory.
Note that because everything is done with async and await, I have no threading issues, and no timers to worry about.
One thing to note: part of the reason for having the period/offset controls is to show (and prove to myself) that the form is fully functional while things are moving around
I have a problem with background worker, it gets called twice thus, increasing the time of execution for my long routine, I created background worker manually so, there is no chance for the DoWork to be initialized within the InitializeComponent() method, any help is appreciated.
Here is my code:
namespace formStudent2
{
public partial class formStudent2 : Form
{
private BackgroundWorker backgroundWorker1 = new BackgroundWorker();
private ProgressBar progressBar1 = new ProgressBar();
private Label label1 = new Label();
public formStudent2()
{
InitializeComponent();
}
...
private void btnExportCsv_Click(object sender, EventArgs e)
{
// Path output file CSV
string pathFile = #"D:\DataTest\ListStudent.csv";
int filesCount = 3;
// Check if the backgroundWorker is already busy running the asynchronous operation
if (!backgroundWorker1.IsBusy)
{
btnExportCsv.Enabled = false;
// This method will start the execution asynchronously in the background
backgroundWorker1.RunWorkerAsync();
}
else
{
label1.Text = "Busy processing, please wait...";
}
/**
* Display dialog Progress Bar : Exporting data...
*/
Form form = new Form();
form.Text = "Exporting data...";
form.ClientSize = new Size(376, 100);
form.FormBorderStyle = FormBorderStyle.FixedSingle;
form.ShowIcon = false;
form.ControlBox = false;
form.MaximizeBox = false;
form.MinimizeBox = false;
form.StartPosition = FormStartPosition.CenterScreen;
label1.AutoSize = true;
label1.Location = new System.Drawing.Point(17, 25);
label1.Name = "lblPercent";
label1.Size = new System.Drawing.Size(102, 15);
label1.TabIndex = 1;
label1.Text = "0% Completed";
form.Controls.Add(label1);
Button btnCancel = new Button();
btnCancel.Location = new System.Drawing.Point(268, 19);
btnCancel.Name = "btnCancel";
btnCancel.Size = new System.Drawing.Size(99, 27);
btnCancel.TabIndex = 3;
btnCancel.Text = "Cancel";
btnCancel.UseVisualStyleBackColor = true;
btnCancel.Click += (senderq, eq) =>
{
if (backgroundWorker1.IsBusy)
{
// Cancel the asynchronous operation id still in progress
backgroundWorker1.CancelAsync();
}
else
{
form.Close();
}
};
form.Controls.Add(btnCancel);
progressBar1.Location = new System.Drawing.Point(17, 61);
progressBar1.Name = "progressBar1";
progressBar1.Size = new System.Drawing.Size(350, 27);
form.Controls.Add(progressBar1);
backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.WorkerSupportsCancellation = true;
backgroundWorker1.DoWork += (senderq, eq) =>
{
for (int i = 0; i < filesCount; i++)
{
/**
* Export to file CSV
*/
ExportFileCsv(pathFile, listStudent);
int percentage = (i + 1) * 100 / filesCount;
backgroundWorker1.ReportProgress(percentage);
// Set cancellation to pending
if (backgroundWorker1.CancellationPending)
{
// Execute cancellation
eq.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
}
};
backgroundWorker1.ProgressChanged += (senderq, eq) =>
{
// This is updated from doWork. Its where GUI components are update,
// receives updates after 100ms
progressBar1.Value = eq.ProgressPercentage;
label1.Text = eq.ProgressPercentage.ToString() + "% Completed";
};
backgroundWorker1.RunWorkerCompleted += (senderq, eq) =>
{
// Called when the heavy operation in background is over.
// Can also accept GUI components
if (eq.Cancelled)
{
label1.Text = "Processing cancelled.";
}
else if (eq.Error != null)
{
label1.Text = eq.Error.Message;
}
else
{
btnExportCsv.Enabled = true;
MessageBox.Show("Export Finished!");
form.Close();
}
};
form.ShowDialog();
}
}
}
The running status of the worker is not static. It is dependent an instance of a new background worker. Try to make it shared.
Below is some sort of a pseudo-code (I am a java guy, never programmed with C# before) to do it:
public partial class formStudent {
boolean workerRunningStatus = false;
private void btnExportCsv_Click(object sender, EventArgs e)
{
// Path output file CSV
string pathFile = #"D:\DataTest\ListStudent.csv";
int filesCount = 3;
// Check if the backgroundWorker is already busy running the asynchronous operation
if (!workerRunning)
{
btnExportCsv.Enabled = false;
// This method will start the execution asynchronously in the background
backgroundWorker1.RunWorkerAsync();
}
else
{
workerRunningStatus = true;
//then exit
return;
}
//Continue with the remaining logic
}
}
It's just all about having a single instance of the worker running. Or see how to use a singleton pattern in C#.
I've trying to communicate with an Arduino Due in C#. The communikation works quite well, but my DataReceived handler needs about 1 second to react. This is my problem because I have to send up to 1 billion (1*10E9) commands.
If I activate a DEBUG Setting in the Arduino, it tells me that it's need 64 Milliseconds for a command. I think the C# the App should get it no later than 80 Milliseconds after sending it.
Here is a Part of the Code:
StopWatch s1 = new StopWatch();
private void Open_Port()
{
string port = null;
int baud = 0;
bool ERR = false;
if ((COM_cb.SelectedItem != null) | (BAUD_cb.SelectedItem != null))
{
port = this.COM_cb.GetItemText(this.COM_cb.SelectedItem);
baud = Convert.ToInt32(this.BAUD_cb.GetItemText(this.BAUD_cb.SelectedItem));
ERR = false;
}
else
{
ERR = true;
System.Windows.Forms.MessageBox.Show("Error Msg");
}
if (ERR == false)
{
serialPort1.PortName = port;
serialPort1.BaudRate = baud;
serialPort1.Open();
}
if (serialPort1.IsOpen)//Kalibrieren der Buttons
{
OPEN_btn.Enabled = false;
CLOSE_btn.Enabled = true;
textBox1.ReadOnly = false;
ERR = true;
}
}
private void Print_Click(object sender, EventArgs e) // start
{
Thread t = new Thread(transmit_pic);
t.Start();
}
private void DataReceivedHandler(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
s1.Stop();
//Till this line it take 1 Second after sending
//string t = "";
int byt = serialPort1.BytesToRead;
byte[] buffer = new byte[1];
for (int i = 0; i < byt; i++)
{
serialPort1.Read(buffer, 0, 1);
if(buffer[0] == '0') {
got_answer = true;
}
//t += (char)buffer[0];
}
//RxString= t;
//this.Invoke(new EventHandler(DisplayText));
}
private void sendAktion(int[,] data)
{
string s = int_to_string(data, false);
Console.Write("Send->");
serialPort1.Write(s);
s1.Start();
got_answer = false;
int i = 0;
while (!got_answer) { i++; } //wait for answer
i = 0;
Console.WriteLine("back again ");
}
private void transmit_pic()
{
stop = false;
Bitmap bm = new Bitmap(img);
if (!serialPort1.IsOpen)
{
MessageBox.Show("Open the Serial Port first!");
}
else
{
int size_X = bm.Width;
int size_Y = bm.Height;
for (int h = 0; h < size_Y; h++)
{
for (int w = 0; w < size_X; w++)
{
if(/*somthing happend*/){
//get data...
sendAktion(data)
}
}
}
Console.WriteLine("DONE");
}
}
Does anyone an Idea why c# needs so long to call the datahandler?
Sincere regards,
Fabian Harmsen
UPDATE
- Added comment to DataHandler (24.02.2016 16:30 Europa/Berlin)
The problem lies in the serialPort1_DataReceived received data handler.
I ran a separate thread with a while(true) loop and serial.ReadLine(), all works perfectly.
Hope someone else doesn't need to spend 3 hours fixing this.
using System.Threading;
public void main()
{
setup();
Thread readThread = new Thread(Read);
readThread.Start();
}
public void Read()
{
while(true)
{
try
{
string message = serialPort1.ReadLine();
}
catch (Exception)
{ }
}
I am designing a program that depends on monitoring the battery level of the computer.
This is the C# code I am using:
PowerStatus pw = SystemInformation.PowerStatus;
if (pw.BatteryLifeRemaining >= 75)
{
//Do stuff here
}
My failed attempt of the while statement, it uses all the CPU which is undesirable.
int i = 1;
while (i == 1)
{
if (pw.BatteryLifeRemaining >= 75)
{
//Do stuff here
}
}
How do I monitor this constantly with an infinite loop so that when it reaches 75% it will execute some code.
Try Timer:
public class Monitoring
{
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
public Monitoring()
{
timer1.Interval = 1000; //Period of Tick
timer1.Tick += timer1_Tick;
}
private void timer1_Tick(object sender, EventArgs e)
{
CheckBatteryStatus();
}
private void CheckBatteryStatus()
{
PowerStatus pw = SystemInformation.PowerStatus;
if (pw.BatteryLifeRemaining >= 75)
{
//Do stuff here
}
}
}
UPDATE:
There is another way to do your task complete. You can use SystemEvents.PowerModeChanged.
Call it and wait for changes, monitor the changes occured then do your stuff.
static void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e)
{
if (e.Mode == Microsoft.Win32.PowerModes.StatusChange)
{
if (pw.BatteryLifeRemaining >= 75)
{
//Do stuff here
}
}
}
While loop will cause your UI to response poor and the application will get crashed. You can solve this by using many ways. Please check out the below code snippet will help your needs.
public delegate void DoAsync();
private void button1_Click(object sender, EventArgs e)
{
DoAsync async = new DoAsync(GetBatteryDetails);
async.BeginInvoke(null, null);
}
public void GetBatteryDetails()
{
int i = 0;
PowerStatus ps = SystemInformation.PowerStatus;
while (true)
{
if (this.InvokeRequired)
this.Invoke(new Action(() => this.Text = ps.BatteryLifePercent.ToString() + i.ToString()));
else
this.Text = ps.BatteryLifePercent.ToString() + i.ToString();
i++;
}
}
BatteryChargeStatus.Text = SystemInformation.PowerStatus.BatteryChargeStatus.ToString();
BatteryFullLifetime.Text = SystemInformation.PowerStatus.BatteryFullLifetime.ToString();
BatteryLifePercent.Text = SystemInformation.PowerStatus.BatteryLifePercent.ToString();
BatteryLifeRemaining.Text = SystemInformation.PowerStatus.BatteryLifeRemaining.ToString();
PowerLineStatus.Text = SystemInformation.PowerStatus.PowerLineStatus.ToString();
If you want to perform some operation just convert these string values into the integer.
I'm a tad new to C# so please bear with me!
I am writing a program to send code via RS232 to a home made telescope mount.
The issues I have at the moment is hopefully very simple (But quite difficult for me!)
As an example say I have a button, I want to execute a loop when the left mouse button is held down, (which will be a continuous stream of 232 data), then when the left mouse button is released I need the loop to stop and to execute another line of code.
I sincerely hope that information I have given is enough and somebody is kind enough to help me along (I have searched the internet for answers believe me!)
Many thanks.
Hook into the MouseDown and MouseUp events on the button. The MouseDown event should spawn a thread, or signal to the thread to begin executing the loop. The MouseUp event should signal to the thread to stop executing the loop.
Something like this:
public class InterruptibleLoop
{
private volatile bool stopLoop;
private Thread loopThread;
public void Start() {
// If the thread is already running, do nothing.
if (loopThread != null) {
return;
}
// Reset the "stop loop" signal.
stopLoop = false;
// Create and start the new thread.
loopThread = new Thread(LoopBody);
loopThread.Start();
}
public void Stop() {
// If the thread is not running, do nothing.
if (loopThread == null) {
return;
}
// Signal to the thread that it should stop looping.
stopLoop = true;
// Wait for the thread to terminate.
loopThread.Join();
loopThread = null;
}
private void LoopBody() {
while (!stopLoop) {
// Do your work here
}
}
}
Method 1:
First create a timer with the interval set to the frequency you want it to send the data. And send the data in the tick event. Create an event for the button's mouse down event and the buttons' mouse up event. In the mouse down event, start the timer. In the mouse up event, stop the timer.
Method 2:
Instead of starting a timer on the mouse down event, start a new thread where you do a continuous loop of data sending. Stop the thread on the mouse up event.
namespace Scope_Project_Ver_2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// *** Output data timer ***
otimer.Interval = 50;
// otimer.Interval = isendFreq;
otimer.Tick += new EventHandler(otimer_Tick);
// *** Input data timer ***
// itimer.Interval = 601; <- to be unchecked
// itimer.Tick += new EventHandler(itimer_Tick); <- to be unchecked
}
public int b1,b2,b3,b4,b5;
public string sb1, sb2, sb3, sb4, sb5;
public int ivorSpeed;
public string svorSpeed;
public int ihorSpeed;
public string shorSpeed;
public int isendFreq;
private void sendDataB_Click(object sender, MouseEventArgs e)
{
if (sendDataCB.Checked)
{
sendDataCB.Checked = false;
if (otimer.Enabled)
otimer.Stop();
}
else
{
sendDataCB.Checked = true;
if (!otimer.Enabled)
otimer.Start();
}
}
void otimer_Tick(object sender, EventArgs e)
{
SerialPort port = new SerialPort(
"COM1", 9600, Parity.None, 8, StopBits.One);
port.Open();
port.Write("Q"); // Q
port.Write(sb1); // 1
port.Write(sb2); // 2
// Binary stuff // Ver Speed Binary 3
byte[] bverbinary = new byte[1];
byte verbinary = 0;
verbinary = Byte.Parse(svorSpeed);
bverbinary[0] = verbinary;
port.Write(bverbinary, 0, bverbinary.Length);
// End of Binary stuff for Ver Speed
// Binary stuff // Hor Speed Binary 4
byte[] bhorbinary = new byte[1];
byte horbinary = 0;
horbinary = Byte.Parse(shorSpeed);
bhorbinary[0] = horbinary;
port.Write(bhorbinary, 0, bhorbinary.Length);
port.Write(sb5); // Movement 5
port.Close();
}
private void vorSpeed_ValueChanged(object sender, EventArgs e)
{
// MessageBox.Show((this.vorSpeed.Value).ToString());
this.Text = "You changed the Vertical Speed to " + vorSpeed.Value;
ivorSpeed = (int)vorSpeed.Value;
svorSpeed = ivorSpeed.ToString();
}
private void horSpeed_ValueChanged(object sender, EventArgs e)
{
// MessageBox.Show((this.horSpeed.Value).ToString());
this.Text = "You changed the Horizontal Speed to " + horSpeed.Value;
ihorSpeed = (int)horSpeed.Value;
shorSpeed = ihorSpeed.ToString();
}
private void scopeUp_MouseDown(object sender, MouseEventArgs e) // Scope Up On
{
b1 = 2;
b2 = 0;
b5 = 1;
sb1 = b1.ToString();
sb2 = b2.ToString();
sb3 = b3.ToString();
sb4 = b4.ToString();
sb5 = b5.ToString();
}
private void scopeUp_MouseUp(object sender, MouseEventArgs e) // Scope Up Off
{
}
private void scopeRight_MouseDown(object sender, MouseEventArgs e)
{
b1 = 1;
b2 = 2;
b5 = 1;
sb1 = b1.ToString();
sb2 = b2.ToString();
sb3 = b3.ToString();
sb4 = b4.ToString();
sb5 = b5.ToString();
}
private void scopeRight_MouseUp(object sender, MouseEventArgs e)
{
}
private void scopeDown_MouseDown(object sender, MouseEventArgs e)
{
b1 = 2;
b2 = 1;
b5 = 1;
sb1 = b1.ToString();
sb2 = b2.ToString();
sb3 = b3.ToString();
sb4 = b4.ToString();
sb5 = b5.ToString();
}
private void scopeDown_MouseUp(object sender, MouseEventArgs e)
{
}
private void scopeLeft_MouseDown(object sender, MouseEventArgs e)
{
b1 = 0;
b2 = 2;
b5 = 1;
sb1 = b1.ToString();
sb2 = b2.ToString();
sb3 = b3.ToString();
sb4 = b4.ToString();
sb5 = b5.ToString();
}
private void scopeLeft_MouseUp(object sender, MouseEventArgs e)
{
}
private void scopeStop_Click(object sender, EventArgs e)
{
b1 = 0;
b2 = 0;
b5 = 0;
sb1 = b1.ToString();
sb2 = b2.ToString();
sb3 = b3.ToString();
sb4 = b4.ToString();
sb5 = b5.ToString();
}
private void sendFreq_ValueChanged(object sender, EventArgs e)
{
this.Text = "You changed the send Freq to " + sendFreq.Value + " m/s";
isendFreq = (int)sendFreq.Value;
}
}
}