我看过一些应用程序(可能不是.NET应用程序)在表单标题栏上的最小化按钮左侧有一个额外的按钮?我怎样才能在C#中实现这个目标?
答案 0 :(得分:35)
更新:添加了适用于Windows Vista和Windows 7的Aero的解决方案
<小时/> 非航空解决方案
窗口交互的非客户区域由一系列非客户端特定消息管理。例如,WM_NCPAINT消息被发送到窗口过程以绘制非客户区域。
我从未在.NET中做过这个,但我怀疑你可以覆盖WndProc并处理WM_NC *消息来实现你想要的。
更新:因为我从未尝试过.NET,所以我花了几分钟时间,我想我会试一试。
在Windows 7上尝试这个,我发现如果我想要操作系统来执行非客户区的基本渲染,我需要禁用窗口的主题。所以这是一个简短的测试。我使用GetWindowDC获取整个窗口的DC而不是GetDCEx,这只是因为我可以从内存中互操作并且没有查找GetDcEx的所有标志常量。当然,代码可以进行更多的错误检查。
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class CustomBorderForm : Form
{
const int WM_NCPAINT = 0x85;
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("user32.dll", SetLastError = true)]
public static extern void DisableProcessWindowsGhosting();
[DllImport("UxTheme.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList);
public CustomBorderForm()
{
// This could be called from main.
DisableProcessWindowsGhosting();
InitializeComponent();
}
protected override void OnHandleCreated(EventArgs e)
{
SetWindowTheme(this.Handle, "", "");
base.OnHandleCreated(e);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_NCPAINT:
{
IntPtr hdc = GetWindowDC(m.HWnd);
using (Graphics g = Graphics.FromHdc(hdc))
{
g.FillEllipse(Brushes.Red, new Rectangle((Width-20)/2, 8, 20, 20));
}
int r = ReleaseDC(m.HWnd, hdc);
}
break;
}
}
}
}
顺便说一下。我打电话给DisableProcessWindowsGhosting
,如果应用程序花费太长时间来响应Windows消息,这将阻止操作系统绘制非客户区域。如果您不这样做,那么在某些情况下,边框将被渲染,但您的装饰品将不会显示。所以这取决于你的要求它是否适合你。
<小时/> Aero支持的解决方案
@TheCodeKing的评论提示,我想我会再看看这个。事实证明,这可以在完全记录的方式完成,同时支持Aero。但它不适合胆小的人。我不会在这里提供一个完整的解决方案,仍有一些问题可以解决,但它确实是基础。
此代码/解决方案基于Win32示例,该示例可在以下位置找到 http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx
原则上你需要做的是以下几点。
上面的步骤将为您提供一个带有标准玻璃框架的窗口,不包括系统菜单(窗口图标)和标题。最小化,最大化和关闭按钮仍将被绘制并将起作用。你无法做的是拖动或调整窗口大小,这是因为框架实际上并不存在,请记住客户区覆盖整个窗口,我们刚要求操作系统将框架绘制到客户区。< / p>
现在,您可以正常地在窗口上绘图,即使在框架顶部也是如此。您甚至可以将控件放在标题区域中。
最后,允许DWM通过从WndProc
(在您处理之前)调用DwmDefWindowProc来为您处理点击测试。它返回一个布尔值,指示DWM是否为您处理了消息。
答案 1 :(得分:4)
我认为这样做的一种方法是处理WM_NCPAINT消息(非客户端绘制)以绘制按钮,并处理非客户端鼠标点击以了解某人点击了“按钮”。
答案 2 :(得分:3)
简单解决方案:
步骤1:创建Windows表单(这将是您的自定义标题栏)
-Set Form Border Style to None
-Add whatever controls you would like to this
-I will name this custom form "TitleBarButtons"
步骤2.在您想要在添加中使用此自定义控件的那个
titleBarBtn = new TitleBarButtons();
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5);
titleBarBtn.Show();
titleBarBtn.Owner = this;
对于你的构造函数......你可以搞砸这个适合我的应用程序的好位置的偏移
步骤3.将移动事件添加到主表单
private void Form14_Move(object sender, EventArgs e)
{
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5);
}
如果您想要更好地解释上述任何代码,请与我们联系。