【问题标题】:VB Windows form will not size to applications width/heightVB Windows 窗体不会根据应用程序的宽度/高度调整大小
【发布时间】:2017-02-03 02:53:13
【问题描述】:

我将 Visual Basic Windows 窗体大小设置为应用程序的宽度/高度,但它不起作用。

虽然这在 VBA 中对我来说完全可以正常工作,但对于 AddIn 来说却无法正常工作:

  Dim newForm As New ExportingForm
  newForm.ShowDialog()

Public Class ExportingForm

  Private Sub ExportingForm_Layout(sender As Object, e As EventArgs) Handles MyBase.Layout

    Dim exclApp As Excel.Application = Globals.ThisAddIn.Application

    If exclApp.WindowState = Excel.XlWindowState.xlMaximized Then
      Me.WindowState = System.Windows.Forms.FormWindowState.Maximized
    Else
      Me.Size = New Drawing.Point(exclApp.Width, exclApp.Height)
    End If
  End Sub

End Class

此外,在设计器模式下,这里是我对 Windows 窗体的设置:

IsMdiContainer False
Location       0,0
MaximumSize    0,0
MinimumSize    0,0
Padding        0,0,0,0
Size           250,250
StartPosition  CenterParent 

它居中很好,我也可以通过编程方式更改宽度/高度,但是,当将其设置为应用程序宽度/高度时,它会更改到某个点并停止。我需要做什么来纠正这个问题?

我也试过了:

Me.Size = New Drawing.Point(exclApp.ActiveWindow.Width, exclApp.ActiveWindow.Height)

我还尝试在显示表单之前设置大小:

Dim newForm.....
newForm.Size = New Drawing.Point(exclApp.Width, exclApp.Height)
newForm.ShowDialog()

只要能与 Visual Studio 配合使用,我可以翻译任何语言

【问题讨论】:

标签: vb.net visual-studio windows-forms-designer


【解决方案1】:

更正

理论上我最初提出的方法应该有效,但是 Excel PointsToScreenPixels 方法存在问题。对函数的互联网搜索表明结果充其量是不可靠的。因此,我推荐使用 Win32 API 函数 GetWindowRect 来检索 Excel 应用程序的位置和大小。从http://www.pinvoke.net/index.aspx获取的API函数定义。

Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Runtime.InteropServices

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        test()
    End Sub

    Sub test()
        Dim meDPI As PointF = GetDPI(Me.Handle)

        Dim app As New Excel.Application
        app.Visible = True

        Dim appHwnd As IntPtr = New IntPtr(app.Hwnd)

        ' setting Excel's size and position -- just for test verification purposes
        SetWindowPos(appHwnd, IntPtr.Zero, 10, 10, 500, 300, SetWindowPosFlags.DoNotActivate)

        Dim rc As RECT
        GetWindowRect(appHwnd, rc)  ' retrieve Excel's size and position into rc

        app.UserControl = True ' return control to the user 
        Console.WriteLine("Excel located at X: {0}, Y: {1}, Width: {2}, Height: {3}", rc.Left, rc.Top, rc.Width, rc.Height)
        Me.Location = rc.Location
        Me.Size = rc.Size
        Me.Activate() ' bring this form to the front
        Me.Opacity = 0.5 ' allow to view thru to Excel
    End Sub

    Public Shared Function GetDPI(hwnd As IntPtr) As PointF
        Dim ret As PointF
        Using g As Graphics = Graphics.FromHwnd(hwnd)
            ret.X = g.DpiX
            ret.Y = g.DpiY
        End Using
        Return ret
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
    End Function

    <StructLayout(LayoutKind.Sequential)> _
    Public Structure RECT
         Private _Left As Integer, _Top As Integer, _Right As Integer, _Bottom As Integer

         Public Sub New(ByVal Rectangle As Rectangle)
              Me.New(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
         End Sub
         Public Sub New(ByVal Left As Integer, ByVal Top As Integer, ByVal Right As Integer, ByVal Bottom As Integer)
              _Left = Left
              _Top = Top
              _Right = Right
              _Bottom = Bottom
         End Sub

         Public Property X As Integer
              Get
              Return _Left
              End Get
              Set(ByVal value As Integer)
              _Right = _Right - _Left + value
              _Left = value
              End Set
         End Property
         Public Property Y As Integer
              Get
              Return _Top
              End Get
              Set(ByVal value As Integer)
              _Bottom = _Bottom - _Top + value
              _Top = value
              End Set
         End Property
         Public Property Left As Integer
              Get
              Return _Left
              End Get
              Set(ByVal value As Integer)
              _Left = value
              End Set
         End Property
         Public Property Top As Integer
              Get
              Return _Top
              End Get
              Set(ByVal value As Integer)
              _Top = value
              End Set
         End Property
         Public Property Right As Integer
              Get
              Return _Right
              End Get
              Set(ByVal value As Integer)
              _Right = value
              End Set
         End Property
         Public Property Bottom As Integer
              Get
              Return _Bottom
              End Get
              Set(ByVal value As Integer)
              _Bottom = value
              End Set
         End Property
         Public Property Height() As Integer
              Get
              Return _Bottom - _Top
              End Get
              Set(ByVal value As Integer)
              _Bottom = value + _Top
              End Set
         End Property
         Public Property Width() As Integer
              Get
              Return _Right - _Left
              End Get
              Set(ByVal value As Integer)
              _Right = value + _Left
              End Set
         End Property
         Public Property Location() As Point
              Get
              Return New Point(Left, Top)
              End Get
              Set(ByVal value As Point)
              _Right = _Right - _Left + value.X
              _Bottom = _Bottom - _Top + value.Y
              _Left = value.X
              _Top = value.Y
              End Set
         End Property
         Public Property Size() As Size
              Get
              Return New Size(Width, Height)
              End Get
              Set(ByVal value As Size)
              _Right = value.Width + _Left
              _Bottom = value.Height + _Top
              End Set
         End Property

         Public Shared Widening Operator CType(ByVal Rectangle As RECT) As Rectangle
              Return New Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height)
         End Operator
         Public Shared Widening Operator CType(ByVal Rectangle As Rectangle) As RECT
              Return New RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
         End Operator
         Public Shared Operator =(ByVal Rectangle1 As RECT, ByVal Rectangle2 As RECT) As Boolean
              Return Rectangle1.Equals(Rectangle2)
         End Operator
         Public Shared Operator <>(ByVal Rectangle1 As RECT, ByVal Rectangle2 As RECT) As Boolean
              Return Not Rectangle1.Equals(Rectangle2)
         End Operator

         Public Overrides Function ToString() As String
              Return "{Left: " & _Left & "; " & "Top: " & _Top & "; Right: " & _Right & "; Bottom: " & _Bottom & "}"
         End Function

         Public Overloads Function Equals(ByVal Rectangle As RECT) As Boolean
              Return Rectangle.Left = _Left AndAlso Rectangle.Top = _Top AndAlso Rectangle.Right = _Right AndAlso Rectangle.Bottom = _Bottom
         End Function
         Public Overloads Overrides Function Equals(ByVal [Object] As Object) As Boolean
              If TypeOf [Object] Is RECT Then
              Return Equals(DirectCast([Object], RECT))
              ElseIf TypeOf [Object] Is Rectangle Then
              Return Equals(New RECT(DirectCast([Object], Rectangle)))
              End If

              Return False
         End Function
    End Structure

    <DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As SetWindowPosFlags) As Boolean
    End Function
    <Flags> _
    Private Enum SetWindowPosFlags As UInteger
         ''' <summary>If the calling thread and the thread that owns the window are attached to different input queues,
         ''' the system posts the request to the thread that owns the window. This prevents the calling thread from
         ''' blocking its execution while other threads process the request.</summary>
         ''' <remarks>SWP_ASYNCWINDOWPOS</remarks>
         ASynchronousWindowPosition = &H4000
         ''' <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
         ''' <remarks>SWP_DEFERERASE</remarks>
         DeferErase = &H2000
         ''' <summary>Draws a frame (defined in the window's class description) around the window.</summary>
         ''' <remarks>SWP_DRAWFRAME</remarks>
         DrawFrame = &H20
         ''' <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to
         ''' the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE
         ''' is sent only when the window's size is being changed.</summary>
         ''' <remarks>SWP_FRAMECHANGED</remarks>
         FrameChanged = &H20
         ''' <summary>Hides the window.</summary>
         ''' <remarks>SWP_HIDEWINDOW</remarks>
         HideWindow = &H80
         ''' <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the
         ''' top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
         ''' parameter).</summary>
         ''' <remarks>SWP_NOACTIVATE</remarks>
         DoNotActivate = &H10
         ''' <summary>Discards the entire contents of the client area. If this flag is not specified, the valid
         ''' contents of the client area are saved and copied back into the client area after the window is sized or
         ''' repositioned.</summary>
         ''' <remarks>SWP_NOCOPYBITS</remarks>
         DoNotCopyBits = &H100
         ''' <summary>Retains the current position (ignores X and Y parameters).</summary>
         ''' <remarks>SWP_NOMOVE</remarks>
         IgnoreMove = &H2
         ''' <summary>Does not change the owner window's position in the Z order.</summary>
         ''' <remarks>SWP_NOOWNERZORDER</remarks>
         DoNotChangeOwnerZOrder = &H200
         ''' <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to
         ''' the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent
         ''' window uncovered as a result of the window being moved. When this flag is set, the application must
         ''' explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
         ''' <remarks>SWP_NOREDRAW</remarks>
         DoNotRedraw = &H8
         ''' <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
         ''' <remarks>SWP_NOREPOSITION</remarks>
         DoNotReposition = &H200
         ''' <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
         ''' <remarks>SWP_NOSENDCHANGING</remarks>
         DoNotSendChangingEvent = &H400
         ''' <summary>Retains the current size (ignores the cx and cy parameters).</summary>
         ''' <remarks>SWP_NOSIZE</remarks>
         IgnoreResize = &H1
         ''' <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
         ''' <remarks>SWP_NOZORDER</remarks>
         IgnoreZOrder = &H4
         ''' <summary>Displays the window.</summary>
         ''' <remarks>SWP_SHOWWINDOW</remarks>
         ShowWindow = &H40
    End Enum

End Class

请注意,在测试上述代码时,WinForm 应用程序通过在其 app.Manifest 文件中包含以下内容来声明 DPI 感知。

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>

请勿使用

Application.Height PropertyApplication.Width Property 以点而不是像素为单位。您可以使用Window.PointsToScreenPixelsX MethodWindow.PointsToScreenPixelsY 方法计算宽度和高度(以像素为单位)来设置表单大小。

width = exclApp.ActiveWindow.PointsToScreenPixelsX(exclApp.Width)

height = exclApp.ActiveWindow.PointsToScreenPixelsY(exclApp.Height)

我不知道您是否还必须将您的插件声明为 DPI 感知以避免 Windows 缩放您的表单。

注意:基于 Excel 中的测试,只有 ActiveWindow 会产生值。

【讨论】:

  • 这本身是不对的,如果你验证 Window(1) PointsToPixels,你应该使用它的 Points 而不是 exclApp.Width。否则你会得到错误的deminions。此外,参数之前的句点不应该存在。否则它是正确的答案。谢谢
  • 希望您不介意,我进行了编辑以防止将来的问题寻求者混淆。我认为 DPI 意识可能对双显示器或更大的用户有好处。我得再研究一下,谢谢
  • @soulshined,我刚刚在 Excel 中进行了测试。窗口必须是 ActiveWindow,否则函数返回零。此外,转换的值的来源并不重要,只要它是正确的值即可。 exclApp.Windows(1).WidthexclApp.Width 不同。我会编辑帖子。
  • 是的,我个人使用了ActiveWindow,但你的答案保持不变,所以我没有看到任何不正常的东西。我用exclApp.Width 对其进行了测试,它对我产生了不同的结果。我会继续检查。但是在玩了这个之后,还有一些变数在起作用。根据应用程序参考屏幕的位置,会产生不同的结果。例如,当应用程序靠近左下角时,表单填充的尺寸略有不同,这可能是因为我使用了exclApp.ActiveWindow.Width
  • 是的,这似乎不是一个真正可靠的资源,但它足够接近完成工作。我个人不需要很准确,但对于那些寻求微调可靠方法的人来说,这并不是 100% 可靠的。当我在屏幕上移动应用程序并在填充表单之前更改尺寸时,每次都是不同的结果,但仍然足够接近我的需要。我什至用(exclApp.Width) 进行了测试 - 我会重新检查 DPI 意识
猜你喜欢
  • 2012-06-19
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 2017-12-08
  • 1970-01-01
  • 2011-05-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多