Qt 工作 Windows 8 风格的无框自定义窗口 [英] Qt working Windows 8 style frameless custom window

查看:32
本文介绍了Qt 工作 Windows 8 风格的无框自定义窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I recently installed Github for Windows on my Windows 7 machine and loved the custom frame it had, it fit really well with the overall application theme and had it's own titlebar buttons which were really well layed out, very fluent, and seemed very natural to work with.

我进行了一些挖掘,发现了 2 个可以完全清除边界的标志,经过一些自定义后,我让我的应用程序也有一个很好的自定义外观,它直观但与旧 Windows 的所有应用程序不同边框.

I did a bit of digging and found 2 flags that would clear out the border completely and after a bit of customization I got my app to also have a nicely customized look which was intuitive yet different from all the apps with the old Windows border.

问题是它不像其他窗口那样流畅和自然响应,它有故障,我很容易用鼠标移动窗口,但它经常出现故障并且能够在它应该移动的区域上移动'不喜欢点击并拖动禁用的按钮.

The thing was it wasn't fluent and naturally responsive like the other windows, it was glitchy as heck, I easily got the window to move around with the mouse but it often glitched and was able to be moved on areas it shouldn't like clicking and dragging on a disabled button.

与 showMaximize 方法关联的最大化按钮只是扩大了整个窗口以占据整个桌面,您仍然可以移动它(并没有真正最大化).

The maximize button which was linked to showMaximize method just enlarged the whole window to take up the entire desktop, you could still move it (wasnt really trully maximized).

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

The window responded to none of the system signals like clicking the taskbar to minimize it and such.

经过大量修复后,我终于放弃了,这很丢脸,因为我真的很喜欢它的外观,而且非常直观,就像 Windows 的 github 非常直观.

After a lot of fixing around I just finally gave up which was ashame cause I really liekd how it looked and it was very intuitive, much like github for Windows is very intuitive.

有什么办法可以做到吗,我真的还没准备好放弃.

Is there any way I can accomplish this, I'm really not ready to give up yet.

我知道,在制作原始 Windows API 应用程序时,您必须将其链接到 XP 内置样式,因为它默认继承 Windows 95 样式,也许有一个 Qt 未连接到的 Windows 8 样式,我愿意'不知道在研究方面还没有走那么远.

I know that when making a raw Windows API application you have to link it to the XP built-in style because it inherits the Windows 95 style by default, maybe theres a Windows 8 style that Qt'S not connected to, I do't know didn'T go that far in research yet.

推荐答案

点击任务栏最小化窗口

看来Qt::FramelessWindowHint 的实现是有限的.当这个标志被设置时,Windows 认为这个窗口不能被最小化或最大化.我已尝试在纯 winapi 中实现 此解决方案.通过单击任务栏最小化和恢复无框窗口工作正常.显然,Qt 设置了一些阻止此功能的错误标志.可能有什么好的理由,我不知道.

Minimize window by clicking on task bar

It seems that Qt::FramelessWindowHint's implementation is limited. When this flag is set, Windows thinks that this window cannot be minimized or maximized. I've tried this solution implemented in pure winapi. Minimizing and restoring frameless window by clicking on taskbar works fine. Apparently Qt sets some bad flags that block this functionality. May be there is a good reason for that, I don't know.

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

We can use winapi and Qt together but it is troublesome. Firstly, winapi code should be executed after you set window flags and show the window using Qt. Otherwise Qt will overwrite window flags.

另一个问题是当我们使用 winapi 删除边框时,窗口几何形状突然改变,而 Qt 不知道这一点.渲染和事件映射(包括鼠标点击位置)变得无效.我没有找到任何记录在案的方法来更新映射.我发现我们可以告诉 Qt 屏幕方向已经改变,它会强制它重新计算窗口几何形状.但这看起来像一个肮脏的黑客.此外,Qt 4 中缺少 QWidget::windowHandle 函数,并且在 Qt 5 中可能会发生变化".所以这种方法不可靠.但无论如何,它现在有效.下面是完整的代码(在 Windows 8 中测试),应该放在顶层窗口类构造函数中:

Another problem is when we remove border using winapi, window geometry suddently changes, and Qt doesn't know about that. Rendering and event mapping (including mouse click positions) become invalid. I didn't find any documented way to update mapping. I've found that we can tell Qt that screen orientation has changed, and it forces it to recalculate window geometry. But this looks like a dirty hack. Also the QWidget::windowHandle function is missing in Qt 4 and "is subject to change" in Qt 5. So this method is not reliable. But anyway, it works now. Here is complete code (tested in Windows 8) that should be placed in the top window class constructor:

#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 开发人员这种行为是合理的还是一个错误.我认为这个问题可以通过补丁解决.

The true way to solve this problem is to modify the Window Qt platform plugin (see QWindowsWindow class in Qt sources). May be there is a way to inherit from the default implementation, modify it and use in your app. Also you can ask Qt developers is this behavior reasonable or is it a bug. I think that this issue can be fixed with a patch.

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

If you still intend to use this code and other OSs should be also supported, don't forget to wrap windows-specific implementation in #ifdef Q_OS_WIN.

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

Other problems can be fixed more easily. When you process mouse events to implement window dragging, check window state and event position and disable moving when it is unwanted.

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是类变量.

Here ui->title is a label used for displaying fake title bar, and QPoint window_drag_start_pos is a class variable.

这篇关于Qt 工作 Windows 8 风格的无框自定义窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆