I have a form project in Vs2010.
This is my scenario:
I created a form that I want to use like a splash screen, without borders. Inside I have a picture box big like the form.
I set the image importing it and in designer i can see it.
But when I call the splashscreen form from another form and I show It, I can see only the picture box borders, but doesn't load the image.
Update
I load splashScreen in BmForm_Load (other form):
SplashScreen ss = new SplashScreen();
ss.TopMost = true;
ss.Show();
//Prepare bmForm....
ss.Close();
And this is the designer code snippet for the picture box in splash screen form:
this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
this.pictureBox1.ImageLocation = "";
this.pictureBox1.InitialImage = null;
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(256, 256);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
this.pictureBox1.WaitOnLoad = true;
Update 2
If I doesn't close splashScreen form before other form load end, the image is shown after this!
Question
Somebody knows why isn't the picture showed?
What the problem seems to be is that the preparation of your BmForm is locking down the main UI thread that is trying to load the splash image as well as process the commands to prepare the BmForm.
To counter this, load the splash form in its own thread and close the thread/form when done loading.
Example of the code:
Inside your BmForm_Load
Thread splashThread = new Thread(ShowSplash);
splashThread.Start();
// Initialize bmForm
splashThread.Abort();
// This is just to ensure that the form gets its focus back, can be left out.
bmForm.Focus();
The method to show the splash screen
private void ShowSplash()
{
SplashScreen splashScreen = null;
try
{
splashScreen = new SplashScreen();
splashScreen.TopMost = true;
// Use ShowDialog() here because the form doesn't show when using Show()
splashScreen.ShowDialog();
}
catch (ThreadAbortException)
{
if (splashScreen != null)
{
splashScreen.Close();
}
}
}
You might need to add the using System.Threading; to your class and add some extra error handling to the BmForm_Load event in case errors occur, so that you can clean up the splashThread.
You can read more about threading here
Related
I have a main window form (not MDI form) and when i do some process, until this process finishes, i want to show another form (a waiting form)
If i do that regular way like that
ProgressForm = new FrmProgress();
ProgressForm.StartPosition = FormStartPosition.CenterParent;
ProgressForm.ShowDialog();
it works but it stucks in ShowDialog function until I close the form. I know the logic here.
Thats why I called this code with a thread like
Thread splashThread = new Thread(new ThreadStart(
delegate
{
ProgressForm = new FrmProgress();
ProgressForm.StartPosition = FormStartPosition.CenterParent;
ProgressForm.ShowDialog();
//Application.Run(ProgressForm);
}
));
splashThread.SetApartmentState(ApartmentState.STA);
splashThread.Start();
//this part is my job
PackageExtracter packageExtracter = new PackageExtracter();
packageExtracter.InstallPackage(openDlg.FileName);
ProgressForm.Invoke(new Action(ProgressForm.Close));
MessageboxHelper.ShowInfoMessage(Messages.MsgPackageInstalledSuccessfully, Messages.MsgInstallPackageTitle);
ProgressForm.Dispose();
ProgressForm = null;
but this time it opens top-left corner in the first monitor (evne my main application is on the second monitor)
I want to show the "waiting form" as modal and when my job finished, then hide the form.
IS there any idea?
It works like that
Thread splashThread = new Thread(new ThreadStart(
delegate
{
ProgressForm = new FrmProgress();
Application.Run(ProgressForm);
}
));
splashThread.SetApartmentState(ApartmentState.STA);
splashThread.Start();
Your title mentions you want it to show in the center of another form. It looks like you haven't set the parent form for the ProgressForm. You can set this by passing the parent form into the ShowDialog method.
ProgressForm.ShowDialog(someParentForm);
However, i'm not confident that this will work if a different UI thread owns the someParentForm object.
--
If you only want the progress to be in the center of the screen then you can use CenterScreen instead of CenterParent:
ProgressForm.StartPosition = FormStartPosition.CenterScreen;
ProgressForm.ShowDialog();
I am trying to print automatically a series of Windows-Forms. I don't need to show them. The code examples I found on the internet work only when I display the Form with show()! I need to initialize the form with data and send it to the printer Here is the code I am using:
public partial class Form2_withoutShow : Form{
PrintDocument PrintDoc;
Bitmap memImage;
public Form2_withoutShow (Data data)
{
InitializeComponent();
/*
Initialize Data (texboxes, charts ect.) here
*/
this.PrintDoc = new PrintDocument();
this.PrintDoc.PrintPage += PrintDoc_PrintPage;
this.PrintDoc.DefaultPageSettings.Landscape = true;
}
public void Print()
{
this.PrintDoc.Print();
}
void PrintDoc_PrintPage(object sender, PrintPageEventArgs e)
{
int x = SystemInformation.WorkingArea.X;
int y = SystemInformation.WorkingArea.Y;
int width = this.Width;
int height = this.Height;
Rectangle bounds = new Rectangle(x, y, width, height);
Bitmap img = new Bitmap(width, height);
this.DrawToBitmap(img, bounds);
Point p = new Point(10, 10);
e.Graphics.DrawImage(img, p);
}
private void Form2_withoutShow_Load(object sender, EventArgs e)
{
// remove TITLEBar
this.ControlBox = false;
this.Text = String.Empty;
}
}
I call the Print() method from another class in for-loop and pass the Data to be initialized through the constructor.
The MSDN example captures the part on the screen where the forms should be displayed. This doesn't work for me. The approach I am using now yields only the print of the empty Window if I don't call show(). How do I get the data into the form without having to call the show() method? Approaches like mimize the windows when displaying it, also don't work because that is also the print result: a minimized window.
Before showing the form, the form and its controls are not in Created state. To force the form and its controls to be created it's enough to call internal CreateControl(bool fIgnoreVisible) method of your form:
var f = new Form1();
var createControl = f.GetType().GetMethod("CreateControl",
BindingFlags.Instance | BindingFlags.NonPublic);
createControl.Invoke(f, new object[] { true });
var bm = new Bitmap(f.Width, f.Height);
f.DrawToBitmap(bm, new Rectangle(0, 0, bm.Width, bm.Height));
bm.Save(#"d:\bm.bmp");
Also remove codes which you have in your form Load event handler, and put them in constructor of your form.
Note
There are also other workarounds for the problem:
For example you can show the form in a location outside of boundary of the screen and then hide it again. Set the Location to (-32000, -32000) and set StartPosition to be Manual then Show and Hide the form before drawing to bitmap.
Or as another example, you can show the form with Opacity set to 0 and then Show and Hide the form before drawing to bitmap.
In my application I have two winforms. The first acts as my control panel and the second I use to take screen shots. However, when I go from Winform 2 back to Winform 1 I have a new winform created and a brand new tray icon. This is on top of the initial ones I create when the program first starts.
When I go from winform 1 to winform 2 I do the following:
this.Hide();
Form2 form2 = new Form2();
form2.InstanceRef = this;
form2.Show();
Then when I want to go back from Winform 2 to Winform 1 I do the following:
this.Close();
Winform1 form;
form = new Winform1 (capturedImageObj);
form.Show();
I know straight off the bat the issue falls on the fact I'm creating a new Winform1, but I need to do that so I can pass my capturedImageObj back into Winform 1.
I've tried calling this.close() and this.dispose() in the my first section of code but that only closes the program down. Is there a way I can dispose of Winform 1 but still use Winform 2 and pass the object I need to back into a new copy of Winform 1?
Here is the constructor for my Winform 1:
public ControlPanel(Image imjObj)
{
InitializeComponent();
_screenCap = new ScreenCapture();
_screenCap.OnUpdateStatus += _screen_CapOnUpdateStatus;
capturedImage = imjObj;
imagePreview.Image = capturedImage;
}
Change Winform1 to use properties like this:
public Image CapturedImage {
get { return imagePreview.Image; }
set { imagePreview.Image = value; }
}
Then change your constructor like this:
public ControlPanel(Image imjObj)
{
InitializeComponent();
_screenCap = new ScreenCapture();
_screenCap.OnUpdateStatus += _screen_CapOnUpdateStatus;
CapturedImage = imjObj;
}
And, finally, change your Winform2 to do this:
((Winform1)this.InstanceRef).CapturedImage = capturedImageObj;
this.InstanceRef.Show();
this.Close();
Based on the comment, it sounds like your InstanceRef property is of type Form. Change it to be of type Winform1. Or, I changed the code above to do some casting for you.
I have a windows form (Form1) which when a button is clicked on it I want to open another windows form(form2) in a thread.
I want to open it in a thread because when it starts up I have it read and color syntax of 10k+ line long files which takes about 5 or 6 min.
My problems are I do not know the "proper" way to do it. I have found out how to do it and it works right, but I want to be able to have a progress bar telling me how far along Form2 is with its processing. (probably with a Background worker object)
Here is my layout
Form1 has a RichTextBoxes and one buton, click the button and it opens a form in another thread that colors the text in form1's rtb.
Form2 has a Rtb also, this rtb has a method ProcessAllLines which processes the lines and does the work that I want done in another thread.
This is why I think I am having difficulty. The textbox is doing the work while the form is waiting there to load.
Here is how I open the Form2:
private void button1_Click(object sender, EventArgs e)
{
ColoringThread colorer = new ColoringThread(this.m_bruteView.Text);
Thread theThread = new Thread(new ThreadStart(colorer.OpenColorWindow));
theThread.Start();
}
public class ColoringThread
{
string text;
public ColoringThread(string initText)
{
text = initText;
}
public void OpenColorWindow()
{
Form2 form2 = new Form2(text);
form2.ShowDialog();
}
};
And here is how form2 does work:
string initText;
public Form2(string initTextInput)
{
initText = initTextInput;
InitializeComponent();
}
private void InitializeComponent()
{
this.m_ComplexSyntaxer = new ComplexSyntaxer.ComplexSyntaxer();
this.SuspendLayout();
//
// m_ComplexSyntaxer
//
this.m_ComplexSyntaxer.Dock = System.Windows.Forms.DockStyle.Fill;
this.m_ComplexSyntaxer.Location = new System.Drawing.Point(0, 0);
this.m_ComplexSyntaxer.Name = "m_ComplexSyntaxer";
this.m_ComplexSyntaxer.Size = new System.Drawing.Size(292, 273);
this.m_ComplexSyntaxer.TabIndex = 0;
this.m_ComplexSyntaxer.Text = initText;
this.m_ComplexSyntaxer.WordWrap = false;
// THIS LINE DOES THE WORK
this.m_ComplexSyntaxer.ProcessAllLines();
//
// Form2
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.m_ComplexSyntaxer);
this.Name = "Form2";
this.Text = "Form2";
this.ResumeLayout(false);
}
And here is where the work is done:
public void ProcessAllLines()
{
int nStartPos = 0;
int i = 0;
int nOriginalPos = SelectionStart;
while (i < Lines.Length)
{
m_strLine = Lines[i];
m_nLineStart = nStartPos;
m_nLineEnd = m_nLineStart + m_strLine.Length;
m_nLineLength = m_nLineEnd - m_nLineStart;
ProcessLine(); // This colors the current line!
i++;
nStartPos += m_strLine.Length + 1;
}
SelectionStart = nOriginalPos;
}
Sooo, what is the "proper" way to open this form2 and have it report progress to Form1 to show to the user? (I ask because I was told this is not the right thing to do, I will get a "cross-thread" violation apparently?)
I want to open it in a thread because when it starts up I have it read and color syntax of 10k+ line long files which takes about 5 or 6 min.
Why not read the data in a separate thread but then keep the UI itself on the same thread as the first form?
In my experience if you use just one thread for UI operations, it makes life significantly simpler.
As for how you should start a new thread to read the data, there are various options:
You could use BackgroundWorker; which would probably make the progress reporting simpler. See the MSDN article for more information.
Create a new Thread directly and start it
Use a thread-pool thread with ThreadPool.QueueUserWorkItem
If you're using .NET 4, use Task.Factory.StartNew
The other form doesn't need to run in another explicit thread in my opinion.
Sure you want to have the long work done in another thread (or a background worker), but you just want to call another form, and that other form will perform the task in another thread (or background worker).
I have a program, which creates one pictureBox in Form1, and then creates an instance of a class that I called InitialState. The InitialState puts the source to the Image so that it is displayed, and after some time has passed, for which I used a Timer, it creates the next class, MainMenuState. Now, in that MainMenuState class that I've created, I would like to create another pictureBox and make it display on that Form1. Later on, I would like to make the pictures inside it change a bit, and then (possibly) destroy that pictureBox. After that, the program enters the next state (which is in yet another class), and again I would like that class to add a picture box to the original form, and so on.
Basically, I would like to dynamically add controls to the main Form1, but not in the said form, but from the classes I create later on. I've been searching on the internet for a way to do that, and it seems like I would have to use a delegate in order to invoke the Controls.Add method of the Form1 class. I've tried that, and the code compiles, but the pictureBox still doesn't show up.
Here's my code:
Form1 class:
public const string RESOURCE_PATH = "C:/Users/Noel/Documents/Visual Studio 2010/Projects/A/Resources/Animations/";
public Form1()
{
InitializeComponent(); //here, the first pictureBox shows
iInitializeComponent();
zacetnaAnimacija.Dock = DockStyle.Fill; //zacetnaAnimacija is the first pictureBox that appears
zacetnaAnimacija.Anchor = AnchorStyles.Top | AnchorStyles.Left;
zacetnaAnimacija.SizeMode = PictureBoxSizeMode.StretchImage;
InitialState intialState = new InitialState(this, zacetnaAnimacija); //entering InitialState
}
InitialState class:
class InitialState : State
{
System.Timers.Timer initialTimer;
PictureBox pictureBox1;
Form1 form;
public InitialState (Form1 form, PictureBox pictureBox1) {
this.form = form;
GifImage zacetnaSlika = new GifImage(Form1.RESOURCE_PATH + "Presenting.gif"); //this is just a .gif picture I'm displaying
Image trenutnaSlika = zacetnaSlika.GetFrame(0); //a method that plays the .gif
pictureBox1.Image = trenutnaSlika; //makes the first .gif display
this.pictureBox1 = pictureBox1;
initialTimer = new System.Timers.Timer(2500);
initialTimer.Enabled = true;
initialTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
initialTimer.Enabled = false;
MainMenuState menuState = new MainMenuState(form, pictureBox1); //enters main menu state with the Form1 argument passed on
}
MainMenuState class:
class MainMenuState : State
{
Form1 form;
public MainMenuState (Form1 form, PictureBox pictureBox1) {
this.form = form;
GifImage zacetnaSlika = new GifImage(Form1.RESOURCE_PATH + "animated.gif");
Image trenutnaSlika = zacetnaSlika.GetFrame(0);
pictureBox1.Image = trenutnaSlika; //this simply makes another .gif appear in the picture box instead of the first one
PictureBox a = new PictureBox(); //HERE'S my problem, when I want to add ANOTHER pictureBox to that form.
a.BackgroundImage = trenutnaSlika;
a.Location = new System.Drawing.Point(0, 0);
a.Name = "zacetnaAnimacija";
a.Size = new System.Drawing.Size(150, 150);
a.TabIndex = 1;
a.TabStop = false;
AddControl(a); //calling the delegate
}
public delegate void AddControls(PictureBox a);
public void AddControl(PictureBox a)
{
if (form.InvokeRequired)
{
AddControls del = new AddControls(AddControl);
form.Invoke(del, new object[] { a });
}
else
{
form.Controls.Add(a);
}
}
As I've said, the code compiles, but it doesn't create the PictureBox a on the Form1, when the MainMenuState is created. The thing is, if I don't use the delegate in the MainMenuState and just try to do something like form.Controls.Add(a), then I get a "cross-thread operation not valid" exception, and it doesn't even compile. That's why I used the delegate, but even now, it doesn't work.
Can someone please help me?
initialTimer = new System.Timers.Timer(2500);
That's part of the reason you're having trouble. The Elapsed event runs on a threadpool thread, forcing you to do the BeginInvoke song and dance. Use a System.Windows.Forms.Timer instead, its Tick event runs on the UI thread.
You'll also run into trouble with memory management, these classes need to implement IDisposable.
Oh my God, I just found the reason X_x
It was the fact that since the first pictureBox was covering the entire form, and the second one, which was created by the delegate, showed behind it! I just need to bring it to front!
Thank you guys, nonetheless, I probably wouldn't have come to that without you.
Edit: However, may I ask how to bring that control to the front? The a.BringToFront() function doesn't seem to work.
Instead of
form.Invoke(del, new object[]{a});
try:
form.Invoke(new ThreadStart(delegate
{
form.Controls.Add(a);
}
));