【问题标题】:Paint Application Titlebar?油漆应用程序标题栏?
【发布时间】:2013-12-29 20:10:51
【问题描述】:

如何在标题栏上绘制渐变(仅绘制与视觉 XP 主题颜色不同的颜色)以保留 windows XP 样式?

我试图找到示例,但我什至只是将标题栏渐变替换为纯色,我什么也没找到,我找到了一个简单的代码来绘制纯色,但它在 @987654321 处引发异常@表示值不能为空:

<Runtime.InteropServices.DllImport("user32.dll")>
Private Shared Function GetDCEx(
        ByVal hWnd As IntPtr,
        ByVal hrgnClip As IntPtr,
        ByVal DeviceContextValues As DeviceContextValues
) As IntPtr
End Function

Protected Overrides Sub WndProc(ByRef m As Message)

    MyBase.WndProc(m)

    If (m.Msg = 133) Then
        Dim DCX_CACHE As Integer = 2
        Dim DCX_WINDOW As Integer = 1
        Dim g As Graphics = Graphics.FromHdc(GetDCEx(Me.Handle, m.WParam, (DCX_WINDOW Or DCX_CACHE)))
        g.DrawLine(Pens.Red, New Point(0, 0), New Point(30, 30)) 'Draw Here
    End If

End Sub

【问题讨论】:

  • 我会注意向标题栏添加渐变会改变用户体验。如果您查看所有“现代” UI 设计,就会发现没有使用渐变,因为它们会增加 CPU/GPU 的工作量。它还使色盲者更难使用您的软件。

标签: .net vb.net winforms drawing gdi+


【解决方案1】:

为了避免在 dot net 应用程序中使用 API 调用,您可以做很多事情。

  1. 删除了窗口边框并在表单中创建了一个虚拟标题栏。这是最简单的解决方案,可让您实现各种 UI 外观,而无需处理 Windows API。
  2. 查看System.Drawing.Drawing2D.LinearGradientBrush 命名空间。
  3. 查看您的解决方案如何迁移到 Windows 8 中的 WPF 和 Metro UI。应用程序菜单的整个方法发生了变化,因此您的工作可能会被丢弃。
  4. 询问您的客户,更改标题栏颜色的商业案例是什么。话虽如此,过去我曾让图形艺术家为我指定标题栏的颜色。我使用了上面的选项 1。
  5. 一旦您完成任何解决方案,您将不得不在各种操作系统中对其进行测试以确认 API 仍然相关(因此我建议您不要使用它们,因为 M$ 不再是您使用 API 调用的朋友,因此建议使用 .net 方法)。

【讨论】:

    【解决方案2】:

    过了一会儿,但它就这样了:

    a) 您必须删除表单的主题

    SetWindowTheme(Me.Handle, String.Empty, String.Empty)
    

    b) 对于 m.WParam = 1,GetDCEx 失败。因此,GetWindowDC 就是您所需要的。你的覆盖是这样的

        Protected Overrides Sub WndProc(ByRef m As Message)
    
        MyBase.WndProc(m)
    
        If (m.Msg = 133) Then
            If m.WParam = 1 Then
                Dim g As Graphics = Graphics.FromHdc(GetWindowDC(Me.Handle))
                Using g
                    g.DrawLine(Pens.Red, New PointF(0, 0), New PointF(30, 30)) 'Draw Here
                End Using
                Me.Refresh()
    
            Else
    
                Dim DCX_CACHE As Integer = 2
                Dim DCX_WINDOW As Integer = 1
                Dim g As Graphics = Graphics.FromHdc(GetDCEx(Me.Handle, m.WParam, (DCX_WINDOW Or DCX_CACHE)))
                Using g
                    g.DrawLine(Pens.Red, New PointF(0, 0), New PointF(30, 30)) 'Draw Here
                End Using
                Me.Invalidate()
                Me.Refresh()
            End If
        End If
    
    End Sub
    

    你需要的另外两个声明如下

        <Runtime.InteropServices.DllImport("user32.dll")>
    Private Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr
    End Function
    <Runtime.InteropServices.DllImport("uxtheme.dll")>
    Private Shared Function SetWindowTheme(ByVal hWnd As IntPtr, ByVal appName As String, ByVal partList As String) As Integer
    End Function
    

    我在 form_load 事件中调用了 SetThemeWindow,它运行良好。 Using 语句用于 GC 处理图形(清理),而 Me.Refresh() 用于客户区在调整表单大小(或最大化)时不会受到影响。

    感谢 Mike(来自 How to set the client area (ClientRectangle) in a borderless form?)的 C# 代码,该代码相当完整且方向不同。他的编码针对 NC 区域大小,但也针对它们进行绘制。这里更多的是绘画。

    希望对你有帮助!

    [编辑]

    我进行了第一次编辑,但进一步调查表明它可能在特定情况下有效,而不是实际的“最终解决方案”!

    最近的发现也是如此。 GetDCEx 函数实际上失败了,因为 m.WParam 没有提供所需的信息,并且要让 GetDCEx 函数工作,您不需要“m.WParam = 1” IF 测试。只需使用以下内容:

    Using g As Graphics = Graphics.FromHdc(GetDCEx(Me.Handle, IntPtr.Zero, (DeviceContextValues.Window Or DeviceContextValues.Cache)))
        g.ExcludeClip(New Rectangle((Me.Width - Me.ClientSize.Width) / 2, (Me.Height - Me.ClientSize.Height) - ((Me.Width - Me.ClientSize.Width) / 2), Me.ClientRectangle.Width, Me.ClientRectangle.Height))
        g.FillRectangle(Brushes.DarkRed, New Rectangle(0, 0, Me.Width, Me.Height))
        g.DrawRectangle(Pens.Blue, New Rectangle(0, 0, Me.Width - 1, Me.Height - 1))
        g.DrawString(Me.Text, New Font("Tahoma", 10), Brushes.LightCyan, New PointF(Me.Width / 2 - Len(Me.Text) / 2, 4))
        End Using
    

    而不是您拥有的 IF 块,并将 GetDCEx 的第二个参数作为 Intptr.Zero 传递。你永远不会得到一个空返回值。这也绘制了一个边框(有点像某些 Office 或 MS 软件)和水平居中的表单文本(或标题)标题栏。这幅画有一个不包括客户区的附加物。这样,这个区域(客户端)就没有问题了。希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      考虑到我从来没有做过你想做的事情,我真的无法理解上面的代码。只要您不介意无法更改渐变,您可以制作一个 Visual Studio 主题并将其选为代码中每个表单的主题。我也从来没有这样做过,所以我也不知道会有多难。

      【讨论】:

      • 我怀疑这不是关于 VS 主题颜色的问题,而是应用程序主题问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-06
      • 2020-01-16
      • 1970-01-01
      • 1970-01-01
      • 2015-12-03
      • 2013-02-12
      相关资源
      最近更新 更多