我最近在Windows 7机器上安装了适用于Windows的Github,并喜欢它的自定义框架,它非常适合整个应用程序主题,并且具有自己的标题栏按钮,它们的布局非常合理,非常流畅,而且看起来很自然

我做了一些挖掘,发现了2个可以完全清除边框的标志,并且在进行了一些自定义之后,我的应用也拥有了很好的自定义外观,虽然直观但与所有具有旧Windows边框的应用。但是它经常会出现故障,并且能够在不希望单击和拖动禁用按钮的区域上移动。

与showMaximize方法链接的最大化按钮只是扩大了整个窗口的容纳范围整个桌面,您仍然可以移动它(不是真正的最大

该窗口没有响应任何系统信号,例如单击任务栏以将其最小化。

经过大量修复后,我终于放弃了很as愧,因为我真的很喜欢它的外观,而且非常直观,就像适用于Windows的github一样非常直观。

有什么办法可以做到这一点,我真的不准备放弃还没有。

我知道制作原始Windows API应用程序时,必须将其链接到XP内置样式,因为它默认继承Windows 95样式,也许还有Qt的Windows 8样式。没有联系,我不知道在研究中还没有走那么远。

评论

我知道这已经很老了,但是最近我开发了带有自定义边框(甚至可调整大小)的基本程序。因此,如果其他人需要这里的链接:github.com/Nintersoft/CustomTitlebar

#1 楼

通过单击任务栏来最小化窗口

Qt::FramelessWindowHint的实现似乎受到限制。设置此标志时,Windows认为无法最小化或最大化此窗口。我已经尝试过在纯winapi中实现的此解决方案。通过单击任务栏最小化和还原无框架窗口,效果很好。显然,Qt设置了一些阻止该功能的错误标志。我不知道可能有一个很好的理由。

我们可以同时使用winapi和Qt,但这很麻烦。首先,应在设置窗口标志并使用Qt显示窗口之后执行winapi代码。否则,Qt将覆盖窗口标志。

另一个问题是,当我们使用winapi删除边框时,窗口几何形状突然改变,而Qt对此一无所知。渲染和事件映射(包括鼠标单击位置)无效。我没有发现任何记录的方式来更新映射。我发现我们可以告诉Qt屏幕方向发生了变化,并迫使它重新计算窗口几何形状。但这看起来像是肮脏的骇客。同样在Qt 4中缺少QWidget::windowHandle函数,而在Qt 5中“可能会更改”。因此,该方法不可靠。但是无论如何,它现在可以工作了。这是完整的代码(在Windows 8中经过测试),应该放在顶层窗口类构造函数中:

#include "windows.h"
#include <QWindow>
//...
show();
HWND hwnd = reinterpret_cast<HWND>(effectiveWinId());
LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLong(hwnd, GWL_STYLE, lStyle);
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
windowHandle()->reportContentOrientationChange(Qt::PrimaryOrientation);


解决此问题的真正方法是修改Window Qt平台插件(请参阅Qt源代码中的QWindowsWindow类)。可能有一种方法可以继承默认实现,对其进行修改并在您的应用中使用。您也可以问Qt开发人员这种行为是合理的还是错误。我认为可以通过修补此问题。

如果您仍然打算使用此代码,并且还应该支持其他操作系统,请不要忘记将特定于Windows的实现包装在#ifdef Q_OS_WIN中。

仅在以下情况下启用窗口拖动单击标题栏,窗口未最大化

其他问题可以更轻松地解决。当您处理鼠标事件以实现窗口拖动时,请检查窗口状态和事件位置,并在不需要的时候禁用移动。

标题栏,而ui->title是一个类变量。

评论


isMaximized方法显然也不怎么有用,我尝试了on_maximize_clicked()的确切代码,显然它检查窗口是否位于0,0位置以及屏幕的宽度和高度。窗口仍然可以移动,一旦移动它不再位于0,0,则isMaximized返回false以便尝试最大化,但是大小仍然是监视器的宽度和高度,因此什么也没有发生。再次单击显然会将其击退到还原模式。我也尝试了标题栏,如果标题栏按钮在标题栏中,则单击并拖动按钮可移动窗口

–黒い雪
13年10月31日在22:26

我通过在按钮旁边的标题栏中添加了一个不可见的手柄来克服了这一问题,并且使其正常工作,但我从未完全正确,尽管我已经移除了所有页边距并扩大了尺寸,但您还是必须在手柄中间单击垂直握住,等等。。。最后,我想它不可能没有太乱,我更喜欢一个流畅的应用程序,而不是看起来不错,优雅但有点毛病的应用程序

–黒い雪
13年10月31日在22:29

我没有描述过的问题。 on_maximize_clicked代码和isMaimized非常适合我。 ui-> title-> geometry()不包含最大化/最小化按钮的位置,因此单击这些按钮来移动窗口是不可能的。这些问题可能是由您的代码中的某些问题引起的。尝试运行我的完整代码。

–帕维尔·斯特拉霍夫(Pavel Strakhov)
13-10-31在23:27

关于最小化:如果您将Qt :: WindowMinimizeButtonHint和Qt :: FramelessWindowHint一起设置(即setWindowFlags(windowFlags()| Qt :: FramelessWindowHint | Qt :: WindowMinimizeButtonHint);),则该窗口将没有最小化按钮,但仍然可以通过单击任务栏图标最小化。

–点火器
2014年2月1日在20:04

Qt :: FramelessWindowHint不是最佳解决方案。这样,您将丢失所有Windows Aero特定功能,并且无法最大化窗口(而是进入全屏状态,隐藏任务栏)。

–我什么都不知道
17年1月1日在8:26

#2 楼

如果您使用Qt :: FramelessWindowHint,则会丢失所有与Windows框架相关的功能,例如停靠,快捷方式,最大化等。在某些情况下,您可以自己实现一些功能,但是在某些情况下仍然无法使用,包括处理多个监视器和Windows Key的所有功能。如果您需要让应用程序像常规Windows应用程序一样运行,则Qt :: FramelessWindowHint几乎是死胡同。

唯一真正的解决方案是使用Windows为此目的提供的DWM API使用DWM的窗框。它们提供了如何在框架区域中执行任何操作的示例,同时保留了所有标准的Windows管理员行为。

Chrome之类的应用程序确实为此使用了DWM(请参见铬源)。当然,Chrome浏览器未使用Qt,因此它不必执行QMainWindow来处理Windows特定消息的工作,并且其代码中包含大量注释,表明该代码有多混乱,例如:

 // Hack necessary to stop black background flicker, we cut out
 // resizeborder here to save us from having to do too much
 // addition and subtraction in Layout() ...


类似地,您提到的Windows的Github应用程序是在名为Electron的平台上构建的,您猜想它反过来又使用DWM。

我尚未在Qt应用程序周围找到DWM框架的任何可行示例,但希望这可以提供一个起点。