2016-09-20 39 views
3

我想將窗體放置在屏幕的左上角。表單位置和大小行爲

我試過this.Location = new Point(0,0),但窗口位於(7,0) - 窗口頂部位於屏幕頂部,但左側距離屏幕邊緣7個像素。 我創造了新的WinForms應用程序進行測試和只添加以下代碼:

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); 
} 

輸出是:

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} 

爲什麼Location = new Point(0,0)不會在(0,0)位置的形式? 這是由於我的系統上的東西?我有Win10和VS2015。任務欄在底部,我的桌面左側沒有任何東西。 爲了將它定位在(0,0)上,我實際上必須將它定位在(-7,0)上。此外,最大化形式的報告寬度比屏幕寬度大16個像素。我明白,由於窗口邊緣,標題欄等,客戶區域大小和窗體大小之間存在差異,但事實並非如此。當表格最大化時,沒有左右邊緣(客戶區寬度=桌面寬度),但表格寬度爲+ 16px。窗體四邊各有8px,但Y位置正確。爲什麼Y位置正確而X不是?

+0

您將位置設置爲「0,0」,「Debug.WriteLine」顯示「位置:{X = 0,Y = 0}」。所以有什麼問題?同樣'PointToScreen(0,0):{X = 8,Y = 31}'是可以的,它是窗體客戶區的'0,0'點的屏幕座標。 –

+0

我在Win10或8.1之前沒有注意到這個定位問題。如果我不得不猜測,我會說觀察到的問題是不能再禁用的桌面窗口管理器組合的結果。一些新的調查。謝謝。 :) – TnTinMn

+0

問題是,就像我寫的那樣,窗口的位置(實際上,我能看到的)是右邊7個像素。注意客戶端座標(8,31) - X是8,因爲窗口位置是7,加上窗口邊緣的1個像素,並且由於標題欄Y是31。這就是爲什麼當我將位置設置爲(-7,0)時,窗戶位於角落。所以,客戶端座標是好的 - 客戶端矩形_really_從(8,31)開始。表單座標不正確 - 表單位置是_really_(7,0),而不是(0,0),如其所述。 – c4551u5

回答

0

我想出了這個問題。

只需設置

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;

和測試結果。對我來說是這樣的:

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} 

這一切都是關於邊界。

Look at this

+0

如果您想要無邊框窗口,那就行,但我需要一個常規窗口。 – c4551u5

+0

然後,你應該做一些計算,以獲得正確的位置和大小。一個窗口的邊界總是8和31像素。 – MSL

+0

它們並不總是那麼大,這就是(問題的一部分)。除了不同的Windows版本及其默認設置,用戶還可以自定義這些設置......幸運的是,'DWMWA_EXTENDED_FRAME_BOUNDS'可用於獲取實際值 – c4551u5

2

由於Uwe Keim和自己answerquestion,我創建MoveForm函數計算偏移並正確設置格式的位置,無論Windows版本(即邊框大小):

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函數使用WindowHelper類從Uwe Keimpost

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(); 
    } 
} 
+1

我很高興您找到了解決方法。我發現了一個類似的解決方案[這裏](http://www.vbforums.com/showthread.php?824699-RESOLVED-Form-Placement-Considering-Aero-Borders&p=5019707&viewfull=1#post5019707),這也表明設置'SubsystemVersion'爲6.0可以解決這個問題,但是它只能在Win 8上運行。大部分的偏移量是由於HKEY_CURRENT_USER \ Control Panel \ Desktop \ WindowMetrics下的'BorderWidth'和'PaddedBorderWidth'設置的綜合效果'在註冊表中。雖然將這兩個設置爲零,但仍然會留下1 px偏移量。 – TnTinMn

+0

我見過類似的設置SubsystemVersion的解決方案,但這個更優雅(如果這個問題/解決方案中的任何東西都可以被調用)。這裏SubsystemVersion沒有改變,但取決於版本,選擇了測量實際窗口矩形的兩種不同方法之一。感謝WindowMetric註冊表信息。 – c4551u5

+1

更多信息。如果您重寫'Form.OnHandleCreated'並調用[SetWindowTheme(this.Handle,「」,「」)](http://pinvoke.net/default.aspx/uxtheme/SetWindowTheme.html),則會禁用主題on形式本身。您現在將看到圍繞表單繪製的完整邊框。看起來好像在左邊界上出現的偏移量實際上是一個透明的邊界區域。 – TnTinMn