maybe i need a timer ?
i want that before the image is saved or after saved but to display the images one by one.
now it's just doing the loop so it's not showing the designer at all until the loop will end.
using Accord.Video.FFMPEG;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Net.Mime.MediaTypeNames;
namespace Extract_Frames
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
backgroundWorker1.RunWorkerAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (var vFReader = new VideoFileReader())
{
vFReader.Open(#"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");
for (int i = 0; i < vFReader.FrameCount; i++)
{
Bitmap bmpBaseOriginal = vFReader.ReadVideoFrame();
//bmpBaseOriginal.Save(#"d:\frames\frame" + i + ".bmp");
pictureBox1.Image = bmpBaseOriginal;
//bmpBaseOriginal.Dispose();
}
vFReader.Close();
}
}
}
}
It's working for while but after some images it's throwing exception on the line :
pictureBox1.Image = bmpBaseOriginal;
the exception say the object is in use.
System.InvalidOperationException: 'Object is currently in use
Your code should probably be something like this:
private readonly Queue<Image> images = new Queue<Image>();
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (var vFReader = new VideoFileReader())
{
vFReader.Open(#"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");
for (var i = 0; i < vFReader.FrameCount; i++)
{
images.Enqueue(vFReader.ReadVideoFrame());
}
// Not sure that this would be required as it might happen implicitly at the end of the 'using' block.
vFReader.Close();
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pictureBox1.Image = images.Dequeue();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
pictureBox1.Image.Dispose();
var image = images.Dequeue();
pictureBox1.Image = image;
if (images.Count == 0)
{
timer1.Stop();
}
}
All the Images are added to a queue and then dequeued one by one. The first one is displayed as soon as the loading has completed and the rest will be displayed at regular intervals. This code displayed each Image once and then destroys and discards it. If you want to display them all again when you reach the last then you can use a different type of collection and wrap back to the beginning when you get to the end.
EDIT:
I may have misunderstood a little what you were asking for. This code should display the Images as they're generated:
private void Form1_Load(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (var vFReader = new VideoFileReader())
{
vFReader.Open(#"C:\Users\Chocolade 1972\Downloads\MyVid.mp4");
for (var i = 0; i < vFReader.FrameCount; i++)
{
backgroundWorker1.ReportProgress(0, vFReader.ReadVideoFrame());
}
// Not sure that this would be required as it might happen implicitly at the end of the 'using' block.
vFReader.Close();
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pictureBox1.Image?.Dispose();
pictureBox1.Image = (Image)e.UserState;
}
You can ditch the Timer and the Queue. My only concern is that this may lead to an OutOfMemoryException. If it does, you can call explicitly call GC.Collect intermittently, e.g. every 100 frames.
Related
We just started using c# and the whole class knows nothing.
Yet, the teacher told us to use WinForms and c# to make a program that used bubblesort.
I looked around the web and only found validation for the text boxes (numbers only).
I'm new here but I would like to ask for help if possible.
We have to deliver this work today and we've got nothing so far.
This is the code I have.
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;
namespace maedofeixeira
{
public partial class Form1 : Form
{
int[] elementos = new int[5];
public Form1()
{
InitializeComponent();
}
private void TextBox1_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
{
MessageBox.Show("SO NUMEROS!!!CRL.");
textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length - 1);
}
}
private void TextBox2_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox2.Text, "[^0-9]"))
{
MessageBox.Show("SO NUMEROS!!!CRL.");
textBox2.Text = textBox2.Text.Remove(textBox2.Text.Length - 1);
}
}
private void TextBox3_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox3.Text, "[^0-9]"))
{
MessageBox.Show("SO NUMEROS!!!CRL.");
textBox3.Text = textBox3.Text.Remove(textBox3.Text.Length - 1);
}
}
private void TextBox4_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox4.Text, "[^0-9]"))
{
MessageBox.Show("SO NUMEROS!!!CRL.");
textBox4.Text = textBox4.Text.Remove(textBox4.Text.Length - 1);
}
}
private void TextBox5_TextChanged(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(textBox5.Text, "[^0-9]"))
{
MessageBox.Show("SO NUMEROS!!!CRL.");
textBox5.Text = textBox5.Text.Remove(textBox5.Text.Length - 1);
}
}
private void Bubblesort()
{
int refos = 0;
for (int i=0;i<elementos.Length-1;i++)
{
for (int j = 0; j < elementos.Length - (i + 1); j++)
{
if (elementos[j] > elementos[j + 1])
{
refos = elementos[j];
elementos[j] = elementos[j + 1];
elementos[j + 1] = refos;
}
}
}
}
private void Button1_Click(object sender, EventArgs e)
{
Bubblesort();
for(int i=0;i<elementos.Length;i++)
{
lbOrdenada.Items.Add(elementos[i]);
}
}
}
}
Screenshot:
Problem so far: When we hit the "Ordenar" button, it shows 5 zeros.
You need to put the values from the text boxes into the elementos array. Because of the general messiness of the code, this can't be done elegantly, but something like this should do it:
private void Button1_Click(object sender, EventArgs e)
{
elementos[0] = Convert.ToInt32(TextBox1.Text);
elementos[1] = Convert.ToInt32(TextBox2.Text);
elementos[2] = Convert.ToInt32(TextBox3.Text);
elementos[3] = Convert.ToInt32(TextBox4.Text);
elementos[4] = Convert.ToInt32(TextBox5.Text);
Bubblesort();
for(int i=0;i<elementos.Length;i++)
{
lbOrdenada.Items.Add(elementos[i]);
}
}
sorry for my bad english. I am new here and to C# also.
I need help with screen capturing a area of the Form that contains image in PictureBox and text in TextBox. Everything is fine except that the saved image of screenshot does not contain the image from PictureBox and the text from TextBox. What am I doing wrong?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class ID_Editor_Form : Form
{
Image File;
int TogMove; int MValX; int MValY;
public ID_Editor_Form()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
TogMove = 1; MValX = e.X; MValY = e.Y;
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
TogMove = 0;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (TogMove == 1)
{
this.SetDesktopLocation(MousePosition.X - MValX, MousePosition.Y - MValY);
}
}
OpenFileDialog BrowseID = new OpenFileDialog();
private void button3_Click(object sender, EventArgs e)
{
BrowseID.Filter = "JPG|*.jpg|JPEG|*.jpeg|PNG|*.png|All Files|*.*";
if (BrowseID.ShowDialog() == DialogResult.OK)
{
File = Image.FromFile(BrowseID.FileName);
pictureBox2.Image = File;
}
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(this.Width, this.Height - 48);
DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
bitmap.Save("C:\\Users\\ROBO\\Desktop\\Screen.png", ImageFormat.Png);
MessageBox.Show("Saved Completed");
}
}
}
My purpose is to change drawlines gradient each second in the form application. However it doesn't work. valueble counter " changing in label but not changing in form paint ..
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private int counter = 1;
private void timer1_Tick(object sender, EventArgs e)
{
counter++;
if (counter >= 10)
timer1.Stop();
lblCountDown.Text = counter.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
counter = 0;
timer1.Tick += new EventHandler(timer1_Tick);
counter = new int();
timer1.Interval = 1000; // 1 second
timer1.Start();
lblCountDown.Text = counter.ToString();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(new Pen(Brushes.Crimson),200,200,counter ,300) ;
}
}
}
I intend to change my drawings gradient with time but variable is not changing when its
come to form paint... but it does change in lbl ...
help me if u can guys . dont know what to do.
Here, this one works. The answer is to call this.Invalidate() on form every timer tick.
public partial class Form1 : Form
{
int counter = 0;
public Form1()
{
InitializeComponent();
timer1.Tick += new EventHandler(timer1_Tick);
}
private void button1_Click(object sender, EventArgs e)
{
counter = 1;
timer1.Interval = 1000; // 1 second
timer1.Start();
lblCountDown.Text = counter.ToString();
}
private void timer1_Tick(object sender, EventArgs e)
{
counter++;
if (counter >= 10)
timer1.Stop();
lblCountDown.Text = counter.ToString();
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(new Pen(Brushes.Crimson), 200, 200, counter*10, 300);
}
}
Also changed several things:
Event handler is set only once – to avoid multiple handlers if user clicks button several times.
Removed counter = new int() – no need, you have already set it to =1.
In Form1_Paint set x2 coordinate to counter*10 so it is easier to see the movement.
I will recommend following:
Use Panel control for Drawing and its paint event e.g. Panel_Paint
In Timer_Tick use Panel.Invalidate();
In the paint event Dispose for graphic object that is Pen.
Add a Panel control named panel1 in the form.
Keep every other control outside the panel.
Example of Panel Paint and Timer event:
private void panel1_Paint(object sender, PaintEventArgs e)
{
using (Pen pen = new Pen(Brushes.Crimson))
{
e.Graphics.DrawLine(pen, 200, 200, counter, 300);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
counter++;
if (counter >= 10)
timer1.Stop();
lblCountDown.Text = counter.ToString();
panel1.Invalidate();
}
I have a metronome project set up. I have a tap button which should check the tempo of your beat and average it out. Every bit of math works properly because I checked it with a calculator. Here is the code:
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.Media;
namespace Metronome
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer3_Tick(object sender, EventArgs e)
{
// Convert tempo to timer1.Tick (miliseconds between each beat)
timer1.Interval = Convert.ToInt32(60000 / numericUpDown1.Value);
}
private void button1_Click(object sender, EventArgs e)
{
// Play / Pause button
if (button1.Text == "Go!") { timer1.Enabled = true; button1.Text = "Stop!"; }
else if (button1.Text == "Stop!") { timer1.Enabled = false; button1.Text = "Go!"; }
}
private void timer1_Tick(object sender, EventArgs e)
{
// The 'ding' sound for the metronome
SystemSounds.Beep.Play();
}
private void button2_Click(object sender, EventArgs e)
{
// Set the tempo to be the average of the convertion from miliseconds between 2 beats and the current tempo
if (timer2.Enabled) { numericUpDown1.Value = ((60000 / Tap) + numericUpDown1.Value) / 2; Tap = 0; }
else timer2.Enabled = true;
}
int Tap = 0;
private void timer2_Tick(object sender, EventArgs e)
{
// Get the amount of miliseconds between each beat
Tap++;
}
private void button3_Click(object sender, EventArgs e)
{
// Reset the tap timer
timer2.Enabled = false;
Tap = 0;
}
}
}
The problem is in timer2_Tick, because it should add 1 to Tap every milisecond, instead, when I tried it it goes to a tiny number like 20 or 30. How can I fix this?
There is a really good article I always rely on when selecting which timer to use:
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx
I would suggest using one of the threaded options. Specifically, the article says of the the windows forms timer (System.Windows.Forms.Timer):
If you're looking for a metronome, you've come to the wrong place.
If you only need to check the amount of time passed between button taps, use a StopWatch. It gives you a high precision timing mechanism. There is no need for you to count milliseconds yourself.
I'm attempting to code an application that reads in the values from an IMU. I'm trying to get the different values of the attitude (i.e. direction) of the IMU for 1 second when using the getAtr_Click method. However, while this is calling the Get_Attitude function, it only changes the textbox values once on my form. How do I make it change each time? (I want to see 10 different values flash by on the textbox).
Here's my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Timers;
using VectorNav.Devices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public static Vn100 vn100 = new Vn100("COM5", 9600);
// New Vn100 on COM5
private void Get_Attitude()
//gets the current yaw, pitch, roll in degrees, and displays
{
var attitude = vn100.CurrentAttitude;
yaw.Text = Convert.ToString(attitude.Ypr.YawInDegs);
pitch.Text = Convert.ToString(attitude.Ypr.PitchInDegs);
roll.Text = Convert.ToString(attitude.Ypr.RollInDegs);
}
public Form1()
//connect to the Vn100, set its output to YPR, output at 10Hz
{
InitializeComponent();
vn100.Connect();
vn100.SetAsyncDataOutputType(Vn100.AsyncOutputType.Ypr, true);
vn100.SetAsyncDataOutputFreq(10, true);
}
private void Form1_Load(object sender, EventArgs e)
{
Get_Attitude();
}
private void tare_Click(object sender, EventArgs e)
{
vn100.Tare(true);
vn100.Tare(true); //for some reason it doesn't display the correct Attitude values w/out a double Tare
Get_Attitude();
}
private void getAtr_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
while (vn100.CurrentAttitude == null)
Thread.Sleep(10);
Get_Attitude();
}
}
protected override void OnFormClosing(FormClosingEventArgs e)
//disconnect from the Vn100 when the box is closed
{
vn100.Disconnect();
base.OnFormClosing(e);
}
}
}
This is because you are haulting the UI thread:
private void getAtr_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
while (vn100.CurrentAttitude == null)
Thread.Sleep(10); // < - UI can't respond in a sleep
Get_Attitude();
}
}
You could do this:
private void getAtr_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
while (vn100.CurrentAttitude == null)
{
Thread.Sleep(10); // < - UI can't respond in a sleep
Application.DoEvents();
}
Get_Attitude();
}
}
Or you could force the update to happen synchronously:
private void tare_Click(object sender, EventArgs e)
{
vn100.Tare(true);
vn100.Tare(true); //for some reason it doesn't display the correct Attitude values w/out a double Tare
Get_Attitude();
this.Update();
}
Or you could use a timeout to update the form instead of a loop.
private void tare_Click(object sender, EventArgs e)
{
System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
myTimer.Tick += new EventHandler(TimerEventProcessor);
myTimer.Interval = 10;
myTimer.Start();
}
void TimerEventProcessor(object sender, EventArgs e)
{
Get_Attitude();
}
Do you want to see 10 (possibly) different values displayed in your textboxes during 1s, at an interval of 10ms, once you call getAttr_Click()?
If yes, then that would be the way to do it:
private void getAtr_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
while (vn100.CurrentAttitude == null)
Thread.Sleep(10);
Get_Attitude();
Thread.Sleep(10);
}
}
In your version, the thread that called the getAttr_Click() method just checks vn100.CurrentAttutude at 10ms intervals. Once that has a non-null value, I suspect it remains non-null, meaning your while() loop will be skipped in every for() iteration so Get_Attitude() will be called 10 times in a row (probably) so fast that you only get to see the last values on the screen.
Thing is, this will keep your UI unresponsive each 10ms during the click, so you might consider calling this getAtr_Click() asynchronously or other trivial solution.
EDIT: Actually, it would help knowing the behaviour of the vn100 component. In the case it is unpredictable, the only thing you can be sure of is displaying 10 different values at no less than 10ms distance in time, regardless if you do everything on the UI thread or on a different thread. It is all related to that vn100.CurrentAttitude behaviour...
change it to:
private void Get_Attitude()
//gets the current yaw, pitch, roll in degrees, and displays
{
var attitude = vn100.CurrentAttitude;
yaw.Text = Convert.ToString(attitude.Ypr.YawInDegs);
pitch.Text = Convert.ToString(attitude.Ypr.PitchInDegs);
roll.Text = Convert.ToString(attitude.Ypr.RollInDegs);
vn100.CurrentAttitude = null;
}
private void getAtr_Click(object sender, EventArgs e)
{
for (int i = 1; i <= 10; i++)
{
while (vn100.CurrentAttitude == null)
Thread.Sleep(10);
Get_Attitude();
Application.DoEvents();
}
}