Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

ISOPimp

C# "Loading" Form

This topic is 5572 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

No, Im not asking how to load a form. What I have currently is a form with a label and a progress bar. I made a public function for the form that updates the progress bar. When I did a few tests the progress bar updated like it was supposed too. So now I want to implement it as a loading dialog when I am executing large functions. For instance, I have this function that does a lot of calculations and takes about 30 seconds to finish. I want to be able to display the loading dialog, start the function, and periodically update the dialog throughout the execution of the function. When this function completes, I want to destroy the loading dialog, and load the form that uses the calculated values. I have tried many different variations to what I want but the closest I have come is by using multithreading. Here is my current code:
		private void cmnuReports_LabSumByProcChildren_Click(object sender, System.EventArgs e)
		{
			loading = new frmLoading("Loading a test report!!!!!");
			loading.Show();
			System.Threading.Thread LoadingThread = new Thread(new ThreadStart(DoStuff));
			LoadingThread.Start();
		}
		private void DoStuff()
		{
			for(int i = 0; i <= 100; i += 20)
			{
				int oldticks = System.Environment.TickCount + 1000;
				for(int ticks = System.Environment.TickCount; ticks < oldticks; ticks = System.Environment.TickCount)
				{
					loading.UpdateProgress((i/100));
					Thread.Sleep(1000);
				}
			}
			loading.Close();
			loading.Dispose();
			loading = null;
			Thread.CurrentThread.Abort();
		}
and this is my loading form''s code:
	public class frmLoading : System.Windows.Forms.Form
	{
		private System.Windows.Forms.Label lblText;
		private System.Windows.Forms.ProgressBar progBar;
		private System.ComponentModel.Container components = null;

		public frmLoading()
		{
			InitializeComponent();
		}

		public frmLoading(string Text): this()
		{
			this.lblText.Text = Text;
		}

		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		public void UpdateProgress(float percent)
		{
			this.progBar.Value = (int)(percent * 100);
			this.progBar.Update();
			this.Refresh();
		}
	}
If anyone can supply me with information on trying to acheive this feat, please share. Thank you.

Share this post


Link to post
Share on other sites
Advertisement
It is generally a bad idea to base your progress bar off of an amount of time instead of amount of work done.

In general, I''d make a work estimate (say, 5,000 records) and call a friend method on the progress bar form with updates every 100 or so. Have the friend method use the Synchronized attribute so that only one call can be occuring at a time.

Then, have your progress bar update itself based off of timer events.

That way, you won''t encounter problems when faster computers come along and blow your original time estimate out of the water.

Share this post


Link to post
Share on other sites
ummm, yeah, the function I posted was just a test to see if my updating actually worked. I will be basing my timing method off of work done.

Anyway, Im such a newb, I finally found out what was wrong:
loading.UpdateProgress((i/100)); 

The input to that function accepts a float telling it the percent that the progress bar should be (0 being no bar, 1.0 being full) but that calculation kept returning the integer 0 so the bar wasnt moving.

Thanks for your time though.

Share this post


Link to post
Share on other sites
You''re calling the method of a control (loading.UpdateProgress()) from a thread other than the thread that created the control which is not good. You need to use Control.Invoke() to marshal the call to the control''s thread.

// delegate declaration
delegate void UpdateLoadFormDelegate(float i);

...

private void DoStuff()
{
UpdateLoadFormDelegate updateProgress = new UpdateLoadFormDelegate(loading.UpdateProgress);

...
}

Then, in the DoStuff() method, replace the call to loading.UpdateProgress() with the Control.Invoke() method:

loading.Invoke(updateProgress, new object[] { i/100f });

Is there any special reason you''re calling Thread.CurrentThread.Abort() at the end of this function?

Share this post


Link to post
Share on other sites
quote:
Original post by noparity
You''re calling the method of a control (loading.UpdateProgress()) from a thread other than the thread that created the control which is not good. You need to use Control.Invoke() to marshal the call to the control''s thread.

// delegate declaration
delegate void UpdateLoadFormDelegate(float i);

...

private void DoStuff()
{
UpdateLoadFormDelegate updateProgress = new UpdateLoadFormDelegate(loading.UpdateProgress);

...
}

Then, in the DoStuff() method, replace the call to loading.UpdateProgress() with the Control.Invoke() method:

loading.Invoke(updateProgress, new object[] { i/100f });


I dont understand why it is bad to do what I am doing? Using your method I have to create another global varaible, the loading Form''s UI isnt updated properly, and I cannot position the window while the "working" thread is doing the calculations.
quote:
Is there any special reason you''re calling Thread.CurrentThread.Abort() at the end of this function?

No. I just wasnt sure if I had to or not so I chose to do it to be safe. (I''m guessing I dont need to, do I?)

Share this post


Link to post
Share on other sites
quote:

I dont understand why it is bad to do what I am doing? Using your method I have to create another global varaible, the loading Form''s UI isnt updated properly, and I cannot position the window while the "working" thread is doing the calculations.


Windows Forms applications use the single-threaded apartment (STA) model (in fact, native Win32 windows are apartment-threaded as well). In short, the STA model implies that a window can be created on any thread, but all function calls to that window must occur on the thread that created the window.

The problems that you''re mentioning make me think that you have not implemented your delegate properly. My example is also part to blame as it wasn''t very explict.

The delegate declaration is placed in the class that will be creating the Loading Form (this was not clear in my last example):

public class MainForm : System.Windows.Forms.Form
{
// here''s our Load Form
LoadForm theForm = null;

// delegates to call to the Load Form from another thread
private delegate void UpdateLoadFormDelegate(float i);
private delegate void UpdateFinishedDelegate();
...
private void button1_Click(object sender, System.EventArgs e)
{
this.theForm = new LoadForm();
System.Threading.Thread loadThread = new Thread(new ThreadStart(this.DoStuff);
this.theForm.Show();
loadThread.Start();
}

private void DoStuff()
{
UpdateLoadFormDelegate updateProgress = new UpdateLoadFormDelegate(theForm.UpdateProgress);
for (...)
{
this.theForm.Invoke(updateProgress, new object[] { i/100f});
}

UpdateFinishedDelegate finished = new UpdateFinishedDeleate(this.theForm.Close);
this.theForm.Invoke(finished);
}
....
}

This is how I''ve implemented it and it works great. You''ll also notice that I''ve added a new delegate to close the Load Form (don''t know how I missed it the first time around ).
quote:

No. I just wasnt sure if I had to or not so I chose to do it to be safe. (I''m guessing I dont need to, do I?)


Calling CurrentThread.Abort() will raise a ThreadAbortException() which will incur some overhead. Just let the function exit normally and the worker thread will terminate.

Share this post


Link to post
Share on other sites
Thanks noparity. Im new to multi threading and havnt used delagates before so I just figured if my way worked, then it was ok.

I am currently implementing the loading form the right way (your way) and will see how it goes.

Thanks again.

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!