通过单击任务栏最小化窗口
看起来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 开发人员这种行为是否合理或者是否是一个错误。我认为这个问题可以通过补丁来解决。
如果您仍然打算使用此代码并且还应该支持其他操作系统,请不要忘记将特定于 Windows 的实现包装在#ifdef Q_OS_WIN
.
仅当单击标题栏且窗口未最大化时才启用窗口拖动
其他问题可以更容易地解决。当您处理鼠标事件以实现窗口拖动时,请检查窗口状态和事件位置,并在不需要时禁用移动。
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();
}
}
Here ui->title
是用于显示假标题栏的标签,并且QPoint window_drag_start_pos
是一个类变量。