【问题标题】:No Title Bar Issue and Windows 10没有标题栏问题和 Windows 10
【发布时间】:2015-09-15 09:50:36
【问题描述】:

我正在开发一个带有自定义标题栏的应用程序。表单设计要求它可以调整大小。请记住,它有一个自定义标题栏,使用正常路线删除自定义表单中的标题栏是行不通的。似乎 Windows 10 API 强制在标题栏上方的屏幕顶部保留一个小的白色“块”。

我的问题是:有没有人遇到过这个问题,你知道修复或解决方法,以便我们可以让表单在 Windows 10 中看起来正确吗?

这是我当前的代码:

Dim testform As New Form
testform.Width = 350
testform.Height = 100
testform.FormBorderStyle = FormBorderStyle.Sizable
testform.ControlBox = False
testform.Text = String.Empty

testform.Show()

由于另一个支持论坛的建议,我们测试了 API 问题,此后似乎已经用尽了帮助。我编译了我们现有的代码并在 Windows 7 机器上运行了可执行文件。在 Windows 7 机器上,表单可以正确打开,ClientRectangle 顶部和表单之间有 0 个空格。

【问题讨论】:

  • 创建边框设置为无的表单,然后覆盖 WndProc() 并处理 WM_NCHITTEST 消息。根据光标当前相对于表单边缘的位置,将m.Result 设置为适当的边缘常数。这将允许无边界表单像一个相当大的表单一样调整大小......
  • @Idle_Mind - 感谢您的建议!我目前不在机器前,也不熟悉您建议的代码。我将研究这些功能并了解如何应用它们,并在我了解更多信息后尽快回复您。
  • 我正在尝试找出这些 WndProc 覆盖。我发现的每个示例似乎都在全球范围内影响代码。如何确保这仅影响多表单项目中的一个特定表单

标签: vb.net winapi


【解决方案1】:

这是一个如何做(某事)如你所愿的示例。我的 VB真的生锈了,所以一定要仔细测试和调试。

首先将表单添加到您的项目中。对于此示例,我保留了名称 Form1,但您可能希望将其更改为有意义的名称。在该表单上,我将BorderStyle 属性设置为None。 (这是我做的唯一改变)

Form1的代码如下:

Public Class Form1
    Public Const WM_NCHITTEST As Integer = &H84
    Public Const BorderSize As Integer = 10

    Protected Overrides Sub WndProc(ByRef m As Message)
        If m.Msg = WM_NCHITTEST Then
            Dim x As Integer = m.LParam.ToInt32 And &HFFFF
            Dim y As Integer = (m.LParam.ToInt32 >> 16) And &HFFFF
            Dim p As Point = New Point(x, y)
            If Me.Bounds.Contains(p) Then
                Dim top As Boolean = Math.Abs(Me.Bounds.Y - y) < BorderSize
                Dim bottom As Boolean = Math.Abs(Me.Bounds.Bottom - y) < BorderSize
                Dim left As Boolean = Math.Abs(Me.Bounds.X - x) < BorderSize
                Dim right As Boolean = Math.Abs(Me.Bounds.Right - x) < BorderSize
                If top And left Then
                    m.Result = NCHITTEST.HTTOPLEFT
                ElseIf top And right Then
                    m.Result = NCHITTEST.HTTOPRIGHT
                ElseIf bottom And left Then
                    m.Result = NCHITTEST.HTBOTTOMLEFT
                ElseIf bottom And right Then
                    m.Result = NCHITTEST.HTBOTTOMRIGHT
                ElseIf top Then
                    m.Result = NCHITTEST.HTTOP
                ElseIf bottom Then
                    m.Result = NCHITTEST.HTBOTTOM
                ElseIf left Then
                    m.Result = NCHITTEST.HTLEFT
                ElseIf right Then
                    m.Result = NCHITTEST.HTRIGHT
                Else
                    m.Result = NCHITTEST.HTCAPTION
                End If
                Exit Sub
            End If
        End If
        MyBase.WndProc(m)
    End Sub
End Class

此外,在您的项目中有意义的某处包括以下枚举。 (我已经去掉了我不使用的值,但它们都在documentation 中可用)为了演示的目的,我将它直接放在End Class 的下方Form1

Public Enum NCHITTEST
    HTBOTTOM = 15
    HTBOTTOMLEFT = 16
    HTBOTTOMRIGHT = 17
    HTCAPTION = 2
    HTLEFT = 10
    HTRIGHT = 11
    HTTOP = 12
    HTTOPLEFT = 13
    HTTOPRIGHT = 14
End Enum

它的实现方式,有一个不可见的 10 像素边框,鼠标将在此处变为调整大小光标。这由BorderSize 常量控制。您可以通过单击并拖动背景中的任意位置来移动表单。 (这就是HTCAPTION 所做的。)

【讨论】:

  • 它不是一个属性,它只是一个常数。如果你愿意,你当然可以把它变成一个属性,或者完全摆脱它,只需将值放入 4 个计算中。即-Math.Abs(Me.Bounds.Y - y) &lt; BorderSize 可能是Math.Abs(Me.Bounds.Y - y) &lt; 10
  • 我创建了一个新项目并对其进行了测试——效果很好!我将看看我能做些什么来将它合并到我现有的项目中,看看它是否能以某种方式与动态创建的表单一起使用。
  • 代码在测试项目中运行良好。然而,在我的实际项目代码中实现这一点时,它似乎并不理解 NCHITTEST 是什么。我以几乎相同的方式插入它,只是它嵌入在生成表单的代码中,并且本身不是表单。我必须在某处为 NCHITTEST 设置命名空间吗?
  • 你必须在某个时候添加一个表单,否则你不能覆盖WndProc。将Form 添加到您的项目中,给它起一个友好的名称,例如BorderlessForm,将代码放入其中,然后在生成表单的代码中使用它。 (即-Dim testForm as New BorderlessFormNCHITTEST 枚举必须在使用它的代码可见的地方,无论它是在同一个文件中,还是在另一个文件中。 Enum 也是一个类型,所以它不能进入​​方法内部,应该在类外部。
  • 想通了,@theB。我只是在两个不同的地方有 Enum 信息。清除它,它就像一个魅力! :) 非常感谢您的帮助!
【解决方案2】:

TheB 有最好的答案,我不得不稍微修改它以使用我的编码。感谢您的所有帮助,先生!

因此,当更改此代码以使用动态创建的控件时,需要进行一些更改。这是我如何让它工作的:

创建一个专门命名的新类:SubclassHWND.vb
(来自Microsoft

Public Class SubclassHWND
    Inherits NativeWindow

    Public Const WM_NCHITTEST = &H84
    Public Const BorderSize As Integer = 10
    Public frm As Form = Nothing

    Public Sub setFrm(ByVal sender As Form)
        frm = sender
    End Sub

    Protected Overloads Overrides Sub WndProc(ByRef m As Message)
        if m.Msg = WM_NCHITTEST Then
            Dim x As Integer = m.LParam.ToInt32 And &HFFFF
            Dim y As Integer = (m.LParam.ToInt32 >> 16) And &HFFFF
            Dim p As Point = New Point(x, y)
            If frm.Bounds.Contains(p) Then
                Dim top As Boolean = Math.Abs(frm.Bounds.Y - y) < BorderSize
                Dim bottom As Boolean = Math.Abs(frm.Bounds.Bottom - y) < BorderSize
                Dim left As Boolean = Math.Abs(frm.Bounds.X - x) < BorderSize
                Dim right As Boolean = Math.Abs(frm.Bounds.Right - x) < BorderSize
                If top And left Then
                    m.Result = NCHITTEST.HTTOPLEFT
                ElseIf top And right Then
                    m.Result = NCHITTEST.HTTOPRIGHT
                ElseIf bottom And left Then
                    m.Result = NCHITTEST.HTBOTTOMLEFT
                ElseIf bottom And right Then
                    m.Result = NCHITTEST.HTBOTTOMRIGHT
                ElseIf top Then
                    m.Result = NCHITTEST.HTTOP
                ElseIf bottom Then
                    m.Result = NCHITTEST.HTBOTTOM
                ElseIf left Then
                    m.Result = NCHITTEST.HTLEFT
                ElseIf right Then
                    m.Result = NCHITTEST.HTRIGHT
                Else
                    m.Result = NCHITTEST.HTCAPTION
                End If
                Exit Sub
            End If
        End If
        Debug.WriteLine(m.ToString())
        MyBase.WndProc(m)
    End Sub
End Class

Public Enum NCHITTEST
    HTBOTTOM = 15
    HTBOTTOMLEFT = 16
    HTBOTTOMRIGHT = 17
    HTCAPTION = 2
    HTLEFT = 10
    HTRIGHT = 11
    HTTOP = 12
    HTTOPLEFT = 13
    HTTOPRIGHT = 14
End Enum

这基本上与@TheB 为我之前为修复提供的代码完全相同,只是做了一些更改。我们继续创建了一个新的Public frm 变量。我们在下一组代码中设置它,以便我们可以引用 WndProc 评估将覆盖的动态表单。

在表单生成代码中,我们添加了这些行来创建在 Windows 10 中没有标题栏 API 的可调整大小的窗口:

newForm.FormBorderStyle = FormBorderStyle.FixedToolWindow
newForm.ControlBox = False
newForm.Text = String.Empty
Dim s As SubclassHWND = New SubclassHWND()
s.setFrm(newForm)
s.AssignHandle(newForm.Handle)

现在项目中的每个动态创建的表单都使用我们在SubclassHWND.vb 中指定的覆盖!感谢大家以及他们所有的宝贵意见。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-04
    • 2020-04-21
    • 1970-01-01
    • 2015-12-02
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多