I want to position Form on top left corner of the screen.
I have tried this.Location = new Point(0,0) but window is positioned at (7,0) - top of the window is on top of the screen but left side is 7 pixels from the screen edge.
I created new WinForms app for testing and added only this code:
private void Form1_Load(object sender, EventArgs e)
{
Point p = new Point(0, 0);
WindowState = FormWindowState.Maximized;
Debug.WriteLine("\nMaximized");
Debug.WriteLine("Location: " + Location);
Debug.WriteLine("Size: " + Size);
Debug.WriteLine("PointToScreen(0,0): " + PointToScreen(p));
WindowState = FormWindowState.Normal;
Location = p;
Debug.WriteLine("\nNormal");
Debug.WriteLine("Location: " + Location);
Debug.WriteLine("Size: " + Size);
Debug.WriteLine("PointToScreen(0,0): " + PointToScreen(p));
Debug.Write("\nScreen.PrimaryScreen.WorkingArea: ");
Debug.WriteLine(Screen.PrimaryScreen.WorkingArea);
}
The output is:
Maximized
Location: {X=-8,Y=-8}
Size: {Width=1936, Height=1056}
PointToScreen(0,0): {X=0,Y=23}
Normal
Location: {X=0,Y=0}
Size: {Width=300, Height=300}
PointToScreen(0,0): {X=8,Y=31}
Screen.PrimaryScreen.WorkingArea: {X=0,Y=0,Width=1920,Height=1040}
Why Location = new Point(0,0) doesn't position form on (0,0)?
Is this due to something on my system? I have Win10 and VS2015. Taskbar is on the bottom, there is nothing on the left side of my desktop.
In order to position it on (0,0) I actually have to position it on (-7,0). Also, reported width of the maximized form is 16 pixels larger than screen width. I understand that because of window edges, title bar etc there is a difference between client area size and form size, but this is not it. When the form is maximized there are no left and right edges (client area width = desktop width) but form width is +16px. There is +8px on each of the 4 sides of the form but Y position is OK. Why is Y-position OK and X is not?
Thanks to Uwe Keim and his own answer to his question, I've created MoveForm function that calculates offset and sets location of the form correctly, regardless of Windows version (ie border size):
void MoveForm(Point p) // Move form to point 'p'
{
this.WindowState = FormWindowState.Normal;
this.Location = new Point(0, 0);
Rectangle rec = WindowHelper.GetWindowRectangle(this.Handle);
p.Offset(-rec.Location.X, -rec.Location.Y);
this.Location = p;
}
MoveForm function uses WindowHelper class from Uwe Keim's post:
public static class WindowHelper
{
// https://code.google.com/p/zscreen/source/browse/trunk/ZScreenLib/Global/GraphicsCore.cs?r=1349
/// <summary>
/// Get real window size, no matter whether Win XP, Win Vista, 7 or 8.
/// </summary>
public static Rectangle GetWindowRectangle(IntPtr handle)
{
if (Environment.OSVersion.Version.Major < 6)
{
return GetWindowRect(handle);
}
else
{
Rectangle rectangle;
return DWMWA_EXTENDED_FRAME_BOUNDS(handle, out rectangle) ? rectangle : GetWindowRect(handle);
}
}
[DllImport(#"dwmapi.dll")]
private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);
private enum Dwmwindowattribute
{
DwmwaExtendedFrameBounds = 9
}
[Serializable, StructLayout(LayoutKind.Sequential)]
private struct Rect
{
// ReSharper disable MemberCanBePrivate.Local
// ReSharper disable FieldCanBeMadeReadOnly.Local
public int Left;
public int Top;
public int Right;
public int Bottom;
// ReSharper restore FieldCanBeMadeReadOnly.Local
// ReSharper restore MemberCanBePrivate.Local
public Rectangle ToRectangle()
{
return Rectangle.FromLTRB(Left, Top, Right, Bottom);
}
}
private static bool DWMWA_EXTENDED_FRAME_BOUNDS(IntPtr handle, out Rectangle rectangle)
{
Rect rect;
var result = DwmGetWindowAttribute(handle, (int)Dwmwindowattribute.DwmwaExtendedFrameBounds,
out rect, Marshal.SizeOf(typeof(Rect)));
rectangle = rect.ToRectangle();
return result >= 0;
}
[DllImport(#"user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(IntPtr hWnd, out Rect lpRect);
private static Rectangle GetWindowRect(IntPtr handle)
{
Rect rect;
GetWindowRect(handle, out rect);
return rect.ToRectangle();
}
}
I figured out the problem.
Just set
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
and test the result. for me it is this:
Maximized
Location: {X=0,Y=0}
Size: {Width=1280, Height=800}
PointToScreen(0,0): {X=0,Y=0}
Normal
Location: {X=0,Y=0}
Size: {Width=477, Height=321}
PointToScreen(0,0): {X=0,Y=0}
It is all about the border.
Related
I want to save the snapshot of a window with the title ending in - Scrivener in a PNG file. To do this, I wrote following method (based on this answer):
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
private void button1_Click(object sender, EventArgs e)
{
Process[] processes = Process.GetProcesses();
Process scrivenerProcess = null;
foreach (Process curProcess in processes)
{
Console.WriteLine("Name: " + curProcess.ProcessName + ", title: " + curProcess.MainWindowTitle);
if (curProcess.MainWindowTitle.EndsWith("- Scrivener"))
{
scrivenerProcess = curProcess;
break;
}
}
if (scrivenerProcess == null)
{
Console.WriteLine("Scrivener not found");
return;
}
var rect = new RECT();
GetWindowRect(new HandleRef(this, scrivenerProcess.MainWindowHandle), out rect);
int width = rect.Right - rect.Left;
int height = rect.Bottom - rect.Top;
var bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bmp);
graphics.CopyFromScreen(rect.Left, rect.Top, 0, 0, new System.Drawing.Size(width, height), CopyPixelOperation.SourceCopy);
bmp.Save("C:\\usr\\dp\\ref\\marcomm\\2020_04_22_wordCounter\\2020-04-24-TestScreenshot.png", ImageFormat.Png);
Console.WriteLine("Heyo!");
}
There are several problems with this code:
First, if the application I want to capture (Scrivener) is not in the foreground while I'm calling that code, the resulting screenshot is empty.
Second, if the Scrivener window is in the foreground, I get the screenshot of the parent window (see below).
How do I need to change my code in order for it to
a. work even when the window is not in foreground and
b. only capture the word count window (not its parent)?
Here is the code.
Here's your problem:
scrivenerProcess.MainWindowHandle
From the documentation:
The main window is the window opened by the process that currently has the focus
In your screenshot, the window you're after does not have Focus (it has a white background with grey text, indicating it's inactive).
Unfortunately, to enumerate a process' other windows you need to use P/Invoke as they aren't exposed via the Process class. Use EnumWindows or EnumChildWindows.
I have a form with rounded borders by codes below:
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
public Form1()
{
InitializeComponent();
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 30, 30));
}
But the problem is:When I Maximize the form, It doesn't maximize correctly.
It Maximizes like this:Image
Please Help Me...
I Found The Answer ...
I should clear the all borders that I set before like this:
private void btnMaximize_Click(object sender, EventArgs e)
{
if (this.WindowState == FormWindowState.Maximized)
{
this.WindowState = FormWindowState.Normal;
btnMaximize.Image = Properties.Resources.maximize_Black;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 30, 30));
}
else
{
this.WindowState = FormWindowState.Maximized;;
btnMaximize.Image = Properties.Resources.maximize_Black_copy;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, Width, Height, 0, 0));
}
}
Thanks For All Friends Wanted To Help Me.
I am using the following code to get the WindowRect for a process on my machine (been testing with the Windows 8.1 calculator).
RECT rc;
GetWindowRect(hWnd, out rc);
var bmp = new Bitmap(rc.Right - rc.Left, rc.Bottom - rc.Top, PixelFormat.Format32bppArgb);
var gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
PrintWindow(hWnd, hdcBitmap, 0);
gfxBmp.ReleaseHdc(hdcBitmap);
gfxBmp.Dispose();
But on Windows 8.1, the bitmap produced is cropped (in the case of the calculator, by about 100 pixels width and 150 height).
RECT is defined as:
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
I've been pulling my hair out with this, can anyone spot what I'm doing wrong?
Cheers
Rich
Currently, I'm using WinAPI in a c# project that deal with Dual-Screen configurations. My question is really simple: how to get the list of all window handle that are about 75% of their size on a specific monitor?
Best regards,
To get the screen with the largest portion of the window you can use this:
System.Windows.Forms.Screen screen = System.Windows.Forms.Screen.FromHandle(form.Handle);
Then you just have to calculate how many % there is on this screen.
Rectangle screenBounds = screen.Bounds;
Rectangle formBounds = form.Bounds;
Rectangle intersection = formBounds.Intersect(screenBounds);
int formArea = formBounds.Width * formBounds.Height;
int intersectArea = intersection.Width * intersection.Height;
int percent = intersectArea * 100 / formArea;
Ok, I created a more generic version, that is able to use any window handle.
Thank you all for your answers!
//Get the Screen object where the Hwnd handle is
System.Windows.Forms.Screen screen = System.Windows.Forms.Screen.FromHandle(Hwnd);
//Create rectangles object
Rectangle screenBound = screen.Bounds;
RECT handleRect = new RECT();
//Get dimensions of the Hwnd handle /!\ don't pass a Rectangle object
if (!GetWindowRect(Hwnd, ref handleRect))
{
//ERROR
}
//Getting the intersection between the two rectangles
Rectangle handleBound = new Rectangle(handleRect.Left, handleRect.Top, handleRect.Right-handleRect.Left, handleRect.Bottom-handleRect.Top);
Rectangle intersection = Rectangle.Intersect(screenBound, handleBound);
//Get the area of the handle
int formArea = handleBound.Width * handleBound.Height;
//Get the area of the intersection
int intersectArea = intersection.Width * intersection.Height;
//Calculate percentage
int percentage = intersectArea * 100 / formArea;
This is the RECT structure:
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
I need a way to center the current window on the screen.
So for example, if a user pushes a button, I want the window to center itself on the screen.
I know you can use the startposition property, but I cannot figure out a way to use that other than when the application first starts up.
So how do I center the form on the screen?
Use Form.CenterToScreen() method.
Using the Property window
Select form → go to property window → select "start position" → select whatever the place you want.
Programmatically
Form form1 = new Form();
form1.StartPosition = FormStartPosition.CenterScreen;
form1.ShowDialog();
Note: Do not directly call Form.CenterToScreen() from your code. Read here.
A single line:
this.Location = new Point((Screen.PrimaryScreen.WorkingArea.Width - this.Width) / 2,
(Screen.PrimaryScreen.WorkingArea.Height - this.Height) / 2);
In Windows Forms:
this.StartPosition = FormStartPosition.CenterScreen;
In WPF:
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
That's all you have to do...
If you want to center your windows during runtime use the code below, copy it into your application:
protected void ReallyCenterToScreen()
{
Screen screen = Screen.FromControl(this);
Rectangle workingArea = screen.WorkingArea;
this.Location = new Point() {
X = Math.Max(workingArea.X, workingArea.X + (workingArea.Width - this.Width) / 2),
Y = Math.Max(workingArea.Y, workingArea.Y + (workingArea.Height - this.Height) / 2)};
}
And finally call the method above to get it working:
ReallyCenterToScreen();
Centering a form in runtime
1.Set following property of Form:
-> StartPosition : CenterScreen
-> WindowState: Normal
This will center the form at runtime but if form size is bigger then expected, do second step.
2. Add Custom Size after InitializeComponent();
public Form1()
{
InitializeComponent();
this.Size = new Size(800, 600);
}
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace centrewindow
{
public partial class Form1 : Form
{
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
[DllImport("user32.dll")]
public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CentreWindow(Handle, GetMonitorDimensions());
}
private void CentreWindow(IntPtr handle, Size monitorDimensions)
{
RECT rect;
GetWindowRect(new HandleRef(this, handle), out rect);
var x1Pos = monitorDimensions.Width/2 - (rect.Right - rect.Left)/2;
var x2Pos = rect.Right - rect.Left;
var y1Pos = monitorDimensions.Height/2 - (rect.Bottom - rect.Top)/2;
var y2Pos = rect.Bottom - rect.Top;
SetWindowPos(handle, 0, x1Pos, y1Pos, x2Pos, y2Pos, 0);
}
private Size GetMonitorDimensions()
{
return SystemInformation.PrimaryMonitorSize;
}
}
}
Centers any window you can get the handle of
Use this:
this.CenterToScreen(); // This will take care of the current form
Might not be completely relevant to the question. But maybe can help someone.
Center Screen non of the above work for me. Reason was I was adding controls dynamically to the form. Technically when it centered it was correct , based on the form before adding the controls.
So here was my solution. ( Should work with both scenarios )
int x = Screen.PrimaryScreen.Bounds.Width - this.PreferredSize.Width;
int y = Screen.PrimaryScreen.Bounds.Height - this.PreferredSize.Height;
this.Location = new Point(x / 2, y / 2);
So you will notice that I am using "PreferredSize" instead of just using Height / Width.
The preferred size will hold the value of the form after adding the controls. Where Height / Width won't.
Hope this helps someone .
Cheers
Use Location property of the form. Set it to the desired top left point
desired x = (desktop_width - form_witdh)/2
desired y = (desktop_height - from_height)/2
Working sample
private void barButtonItem1_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
AccountAddForm f = new AccountAddForm();
f.StartPosition = FormStartPosition.CenterScreen;
f.Show();
}
You can use the Screen.PrimaryScreen.Bounds to retrieve the size of the primary monitor (or inspect the Screen object to retrieve all monitors). Use those with MyForms.Bounds to figure out where to place your form.
In case of multi monitor and If you prefer to center on correct monitor/screen then you might like to try these lines:
// Save values for future(for example, to center a form on next launch)
int screen_x = Screen.FromControl(Form).WorkingArea.X;
int screen_y = Screen.FromControl(Form).WorkingArea.Y;
// Move it and center using correct screen/monitor
Form.Left = screen_x;
Form.Top = screen_y;
Form.Left += (Screen.FromControl(Form).WorkingArea.Width - Form.Width) / 2;
Form.Top += (Screen.FromControl(Form).WorkingArea.Height - Form.Height) / 2;