通过单击任务栏将窗口最小化
似乎 Qt::FramelessWindowHint
的实现是有限制的。当设置了此标识时,Windows 认为该窗口不能最小化或最大化。我尝试了在纯 winapi 中实现的这个解决方案。通过单击任务栏最小化和恢复无边框窗口可以正常工作。显然 Qt 设置了一些错误的标识阻止了这个功能。可能有很好的理由,我不知道。
我们可以使用 winapi 和 Qt 一起工作,但是这很麻烦。首先,在您设置窗口标志并使用 Qt 显示窗口后,应该执行 winapi 代码。否则,Qt 将覆盖窗口标志。
另一个问题是,当我们使用 winapi 移除边框时,窗口几何图形会突然改变,而 Qt 不知道这一点。渲染和事件映射(包括鼠标点击位置)变得无效。我没有找到任何文档记录的方法来更新映射关系。我发现我们可以告诉 Qt 屏幕方向已经改变了,它就会强制重新计算窗口几何图形。但是这看起来像一个肮脏的小技巧。此外,QWidget::windowHandle
函数在 Qt 4 中缺失,在 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开发人员此行为是否合理或者是一个bug。我认为这个问题可以通过补丁来解决。
如果您仍打算使用此代码,并且其他操作系统也应该得到支持,请不要忘记在
#ifdef Q_OS_WIN
中包装特定于Windows的实现。
仅当单击标题栏并且窗口未最大化时启用窗口拖动
其他问题可以更轻松地解决。当处理鼠标事件以实现窗口拖动时,请检查窗口状态和事件位置,并在不需要移动时禁用它。
void MainWindow::mousePressEvent(QMouseEvent *e) {
if (!isMaximized() &&
e->button() == Qt::LeftButton &&
ui->title->geometry().contains(e->pos())) {
window_drag_start_pos = e->pos();
}
}
void MainWindow::mouseReleaseEvent(QMouseEvent *e) {
window_drag_start_pos = QPoint(0, 0);
}
void MainWindow::mouseMoveEvent(QMouseEvent *e) {
if (!window_drag_start_pos.isNull()) {
move(pos() + e->pos() - window_drag_start_pos);
}
}
void MainWindow::on_minimize_clicked() {
showMinimized();
}
void MainWindow::on_maximize_clicked() {
if (isMaximized()) {
showNormal();
} else {
showMaximized();
}
}
这里的ui->title
是用于显示虚拟标题栏的标签,而QPoint window_drag_start_pos
是一个类变量。