Center C# form on secondary screen - c#

Quick question, hopefully an easy fix.
I am kinda new to C# and am trying to center a second form, on the secondary screen when it opens. So far I can get it to open on the second screen no problem but it sits in the top left and I cant get it to center. I am aware of the fact that the Location = Screen.AllScreens[1].WorkingArea.Location; will put it in the top left part of said working area. I was wondering if there is a way to (essentially) change the .Location to something else that will center regardless of actual screen size? This will be going onto multiple different systems with varying screen sizes.
Here is the code that I have so far.
On the first form.
public partial class FrmPrompt : Form
{
public FrmPrompt()
{
InitializeComponent();
}
private void ButNo_Click(object sender, EventArgs e)
{
frmConfirm confirm = new frmConfirm();
Screen[] screens = Screen.AllScreens;
lblConfirmMsg.Text = "Please Wait For Customer To Confirm...";
butContinue.Hide();
confirm.Show();
}
}
On the second form:
public partial class frmConfirm : Form
{
public frmConfirm()
{
InitializeComponent();
Location = Screen.AllScreens[1].WorkingArea.Location;
}
private void pictureBox1_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
Thanks!

CenterScreen will locate Form on current screen, so if your FrmPrompt on second screen, when you clicking ButNo - this will work. But I think this is not you asking for.
More then that, CenterScreen will overwrite any location setting of your from Location that was setted before Show method invocation. So I suggests to override OnShown method of frmConfirm
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
var area = Screen.AllScreens[1].WorkingArea;
var location = area.Location;
location.Offset((area.Width - Width) / 2, (area.Height - Height) / 2);
Location = location;
}

try this on the first form, no need to set anything in the 2nd form.
//put it after this line: frmConfirm confirm = new frmConfirm();
confirm.StartPosition = FormStartPosition.CenterScreen;

Related

Show Form side-by-side owner Form

I have a form. If someone presses a button, I want to show a second form "attached" to the original form, meaning that its left side is at the right side of the original form and they have the same height. In other words: they touch each other.
An answer seems to be Open Form next to Parent Form
However, there is a gap between the images. I want them to be exactly next to each other
main form:
private void ShowOtherForm()
{
using (var form = new OtherForm())
{
var dlgResult = form.ShowDialog(this);
ProcessDlgResult(dlgResult);
}
}
Other form, event handler Load
private void FormLoad(object sender, EventArgs e)
{
// show this form attached to the right side of my owner:
this.Location = new Point(this.Owner.Right, this.Owner.Top);
this.Height = this.Owner.Height;
}
Try to use ClientSize and Location
private void Form2_Load(object sender, EventArgs e)
{
var owner = this.Owner;
Location = new Point(owner.Location.X + owner.ClientSize.Width, owner.Location.Y);
Height = owner.Height;
}

Show panel on click

please for a little help in displaying the panel at the click of a button, namely in my application I have a FormMenu in which the panelCentralForm is displayed when loading.
When I click on btnListOfActiveUser_Click I manage to open FormListStaff over panelCentralForm using this code:
private void btnListOfActiveUser_Click(object sender, EventArgs e)
{
FormListStaff formListStaff = new FormListStaff();
AddFormToPanel(formListStaff);
}
private void AddFormToPanel(object form)
{
if (this.panelCentralForm.Controls.Count > 0)
this.panelCentralForm.Controls.RemoveAt(0);
Form fh = form as Form;
fh.TopLevel = false;
fh.FormBorderStyle = FormBorderStyle.None;
fh.Dock = DockStyle.Fill;
this.panelCentralForm.Controls.Add(fh);
this.panelCentralForm.Tag = fh;
fh.Show();
}
my question is how can I in a similar way that now when I click on buttonDashboard to return to me the first view, ie the view from the Central Form panel (panelCentralForm).
private void buttonDashboard_Click(object sender, EventArgs e)
{
panelCentralForm.Visible = true; //something like this, p.s. this code doesn't just work as an example I wrote
}
the whole view belongs from FormMenu.cs
Thanks a lot to everyone for the help
my question is how can I in a similar way that now when I click on
buttonDashboard to return to me the first view
Just Clear() the panel, then add the label back in?
this.panelCentralForm.Controls.Clear();
this.panelCentralForm.Controls.Add(label1);
The label should still be accessible even though it was previously removed from the panel since it is declared at form level in your designer file.

Non-Clipped Overlapped Image

I would like a transparent overlapped non-clipped image. I have one PictureBox overlapping another, as shown in this SO thread.
The solution, which makes sense, sets the parent of the top image to the bottom image. The top image is then set to have a transparent background. The technique works perfectly, just setting the parent of the top image to that of the bottom clips the top image to the area of the bottom image.
Top Image Parent Property NOT Set to the Bottom Image
Now, here is what happens if the top image parent property gets set to the bottom image.
I do not want the top image clipped.
I would volunteer the entire Visual Studio 2019 (VS2019) project, but not sure how to post it.
Here is the code:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ImageOverlap
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
private void FrmMain_Load(object sender, EventArgs e)
{
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
//this.ImgTop.BringToFront();
this.ChangeX.Value = 430;
this.ChangeY.Value = 15;
}
private void ChangeX_ValueChanged(object sender, EventArgs e)
{
this.ImgTop.Left = (int)this.ChangeX.Value;
}
private void ChangeY_ValueChanged(object sender, EventArgs e)
{
this.ImgTop.Top = (int)this.ChangeY.Value;
}
}
}
I put 2 NumericUpDown controls to better adjust the position of the finger pointer.
The call to method BringToFront() can be deleted, as does nothing, just above as mentioned in a couple of answers and used for testing.
UPDATE
I do NOT want to stretch the bottom image. I want to see the form background.
I also realize that the hand pointer is out of bounds of the bottom (parent) image. As such, the hand pointers gets clipped, cut off.
I want to the entirety of the top image to show, just the part of the top image, which overlaps the bottom image to be transparent.
Using what has got to be the world's best app, Paint.Net, here is what I want, also in a nice reusable code format.
My thought towards a solution is at the moment to make a programmatic copy of the hand pointer and overlay that using onto the form just clipping the left portion, which overlaps the bottom image. I think this idea might work, will post as answer if it works.
This answer can probably be optimized and made more reusable, but it works.
I created a copy of the top control. I then used this updated code, which includes a reusable method.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ImageOverlap
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
private void FrmMain_Load(object sender, EventArgs e)
{
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
this.ImgTop.BringToFront();
this.ChangeX.Value = 430;
this.ChangeY.Value = 15;
}
private void ChangeX_ValueChanged(object sender, EventArgs e)
{
this.SetOverlayImageLocation((int)this.ChangeX.Value, this.ImgTop.Top);
}
private void ChangeY_ValueChanged(object sender, EventArgs e)
{
this.SetOverlayImageLocation(this.ImgTop.Left, (int)this.ChangeY.Value);
}
private void SetOverlayImageLocation(int newX, int newY)
{
this.ImgTop.Left = newX;
this.ImgTop.Top = newY;
Point ptImageAtParent = new Point(this.ImgTop.Left + this.ImgBottom.Left, this.ImgTop.Top + this.ImgBottom.Top);
this.ImgTopCopy.Location = ptImageAtParent;
this.ImgTopCopy.SendToBack();
}
}
}
I am thinking that .Net probably has a nice method/property to get the point relative to the parent. I did that in a brute force method. I then set the copy to the back. The location of the copy is set relative to the parent. The trick is that the copy has the parent property set to the main control.
Here is the runtime visual that I got, no Paint.Net involved; looks identical, which is the objective.
The nice part is that the NumericUpDown controls work flawlessly moving the combined image, which to the user appears as one image.
You want the entire image render on bottom image, if yes it means your problem is calculation of top image position.
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
this.ImgTop.BringToFront();
this.ImgTop.Top = 0;
this.ImgTop.Left = ImgBottom.Width - ImgTop.Width;
I see your replay to Reza, sorry for misunderstood. you set the parent of top image to bottom image. the control can't do any more actions outside of parent area after this. if you want to do that you can dynamically split your image into to separate image controls, one of theme inside the bottom image and another outside and control position of both of theme or implement own control maybe by the help of polygons.

Why doesn't the child form appear on the same screen as the parent form?

Update
I accepted Rufus L's answer with a few mods, Relevant code follows
public partial class ClsOfficeRibbonFooTab
{
private void FooTab_Load(object sender, RibbonUIEventArgs e)
{
.
.
.
}
private void CheckResolution()
{
// set the left position so that the expanded version of the form fits on the screen
Screen screen = Screen.FromHandle(new IntPtr(Globals.ThisAddIn.Application.ActiveWindow.Hwnd));
if (screen.Bounds.Width < 1360 || screen.Bounds.Height < 768)
{
throw new FormatException(String.Format("The {0} is supported on screens with a resolution of 1360 by 768 or greater. Your screen is {1} by {2}", "Some caption text", screen.Bounds.Width, screen.Bounds.Height));
}
}
private void ObjButtonFoo_Click(object sender, RibbonControlEventArgs e)
{
using (ClsFormFoo objFormFoo = new ClsFormFoo(parentWindow: Globals.ThisAddIn.Application.ActiveWindow))
{
CheckResolution();
objFormFoo.ShowDialog();
}
}
}
public partial class ClsFormFoo : Form
{
// This form is a fixed dialog with a flyout on the right side.
// expandedWidth is a const set to the max width of this fixed dialog (i.e., the dialog with the flyout extended)
const int expandedWidth = 1345;
public ClsFormFoo(Microsoft.Office.Interop.Word.Window parentWindow)
{
InitializeComponent();
Top = parentWindow.Top;
}
private void ClsFormFoo_Load(object sender, EventArgs e)
{
Screen screen = Screen.FromHandle(new IntPtr(Globals.ThisAddIn.Application.ActiveWindow.Hwnd));
// set the left position so that the expanded version of the form fits on the screen for all legal resolutions
int halfScreenWidth = (int)(screen.WorkingArea.Width / 2);
// This form is a fixed dialog with a flyout on the right side.
// expandedWidth is a const set to the max width of this fixed dialog (i.e., the dialog with the flyout extended)
int halfFormWidth = (int)(expandedWidth / 2);
this.Left = screen.Bounds.Left + ((int)(halfScreenWidth - halfFormWidth));
}
}
Original Post
My VSTO Add-In provides a ribbon button that when clicked, calls ObjButtonFoo_Click, which in turn, shows a ClsFormFoo form (See Code below). ObjButtonFoo_Click includes code to create an IWin32Window owner value representative of Word to pass to ShowDialog.
On a multiple-monitor setup, I would expect that objFormFoo would appear on the same monitor on which Word itself is displayed. However, when I bring up Word on a secondary monitor and cause ObjButtonFoo_Click to be executed, objFormFoo appears on the Primary monitor
What do I do to make objFormFoo appear on the same monitor that Word itself is displayed on whether its the primary monitor or not?
Note: I verified that winWordMain is populated, i.e., its not null. See winWordMain below
Code
private void ObjButtonFoo_Click(object sender, RibbonControlEventArgs e)
{
NativeWindow winWordMain = new NativeWindow();
winWordMain.AssignHandle(new IntPtr(Globals.ThisAddIn.Application.ActiveWindow.Hwnd));
IntPtr(Globals.ThisAddIn.Application.ActiveWindow.Hwnd);
using (ClsFormFoo objFormFoo = new ClsFormFoo()
{
objFormFoo.ShowDialog(winWordMain);
}
winWordMain.ReleaseHandle();
}
winWordMain
I don't have VSTO to test this, but it seems to me that you could just get the position of the ActiveWindow that you're using as the parent, and then use that as a reference for positioning your child form:
private void allRootsWithChilds_CheckedChanged(object sender, EventArgs e)
{
var winWordMain = new NativeWindow();
var parent = Globals.ThisAddIn.Application.ActiveWindow;
winWordMain.AssignHandle(new IntPtr(parent.Hwnd));
using (var objFormFoo = new ClsFormFoo())
{
// Set the Left and Top properties so this form is centered over the parent
objFormFoo.Left = parent.Left + (parent.Width - objFormFoo.Width) / 2;
objFormFoo.Top = parent.Top + (parent.Height - objFormFoo.Height) / 2;
objFormFoo.ShowDialog(winWordMain);
}
winWordMain.ReleaseHandle();
}
You just need to set the StartPosition property of your form to the FormStartPosition.CenterParent value:
loginForm.StartPosition = FormStartPosition.CenterParent;
loginForm.ShowDialog(parentWindowdle);
I used to make a simple screensaver on C#. I used the following code to open the screensaver on the desired screen or on all of them.
You have to take bounds from the desired screen and pass it to the form.
// Constructor
public NameForm(Rectangle bounds)
{
InitializeComponent();
this.Bounds = bounds;
}
// In my case, this is opening the screensaver on all screens
foreach (Screen screen in Screen.AllScreens)
{
NameForm form = new NameForm (screen.Bounds);
form.Show();
}

Rotate display of text and images in a C# screensaver

I am writing a screensaver program in C#. And I want it to do the following:
Start with a text. After about 3 seconds or more, hide the text and show an image. After the next 3 seconds, hide the image show the text and keep going round the loop until the user does something that exits the screensaver.
What I have done:
I started with a simple textlabel and a timer control. I was able to get the textlabel change positions on screen after every 3 seconds. I updated my code to include a picturebox, and in my timer_tick method, I inserted an if-else statement to check, when the method is called,
if the textlabel is shown, hide it and show the picturebox.
else if the picturebox is shown, hide it and show the textbox. Code is shown below:
private void Form1_Load(object sender, EventArgs e)
{
Cursor.Hide();
TopMost = true;
moveTimer.Interval = 3000;
moveTimer.Tick += new EventHandler(moveTimer_Tick);
moveTimer.Start();
}
private void moveTimer_Tick(object sender, System.EventArgs e)
{
//Move text to new Location
//textLabel.Left = rand.Next(Math.Max(1, Bounds.Width - textLabel.Width));
//textLabel.Top = rand.Next(Math.Max(1, Bounds.Height - textLabel.Height));
if (pictureBox1.Enabled == true)
{
pictureBox1.Hide();
textLabel.Show();
}
if (textLabel.Enabled == true)
{
textLabel.Hide();
pictureBox1.Show();
}
}
Here's the problem:
WHen I run the screensaver program, the screen starts with the text, changes to the picture after 3 seconds and stops there.
What do I do to get it moving in a continous loop, showing/hiding the textlabel or picturebox?
Have I implemented this in the right way?
Please clear and concise explanations/answers will be highly appreciated.
Thanks!
Perhaps you could keep the state in a variable that you can switch
private bool state = false;
private void moveTimer_Tick(object sender, System.EventArgs e)
{
//Move text to new Location
//textLabel.Left = rand.Next(Math.Max(1, Bounds.Width - textLabel.Width));
//textLabel.Top = rand.Next(Math.Max(1, Bounds.Height - textLabel.Height));
if (state)
{
pictureBox1.Hide();
textLabel.Show();
}
else
{
textLabel.Hide();
pictureBox1.Show();
}
state = !state;
}
How about something like this?
Enabled says whether the object can receive input.
Visible is what says if its visible or not.
You see it change once and only once because all the objects are enabled. The first if succeeds, hiding the picture and showing the text. But then the second if also succeeds, showing the picture and hiding the text. Since this is all in one event callback, you never see the first if happen, because the second overrides it.
As you're realizing in the comments, the answer is to not check enabled. Instead, check Visible. Make sure to use an else as well, otherwise you may still get the same issue of both being true.
private void moveTimer_Tick(object sender, System.EventArgs e)
{
//Move text to new Location
//textLabel.Left = rand.Next(Math.Max(1, Bounds.Width - textLabel.Width));
//textLabel.Top = rand.Next(Math.Max(1, Bounds.Height - textLabel.Height));
if (pictureBox1.Visible == true)
{
pictureBox1.Hide();
textLabel.Show();
}
else
{
textLabel.Hide();
pictureBox1.Show();
}
}

Categories

Resources