#c #windows-10 #qml #qt5 #aero-snap
Вопрос:
Когда вы настроили строку заголовка в Windows 10, кому-нибудь удалось поработать с Aero Snap?
Основная строка заголовка слишком уродлива.
Я не решал эту проблему уже неделю. Пожалуйста, дайте мне знать, если есть решение, будь то виджет или Qt Quick.
Я решил эту проблему. Я прошу прощения, если мой вопрос был грубым. Я плохо говорю по-английски.
Сначала я собирался реализовать бескаркасные окна с QWidget и встроить QQuickWidget поверх него, но я нашел лучший способ.
бескаркасный помощник.h
#ifndef FRAMELESSHELPER_H
#define FRAMELESSHELPER_H
#include <QObject>
#include <QQmlParserStatus>
#include <QQuickItem>
#include <QAbstractNativeEventFilter>
// QML : import FramelessHelper 1.0
class QQuickWindow;
class FramelessHelper : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(QQuickItem* titlebar READ titlebar WRITE setTitlebar NOTIFY titlebarChanged)
Q_PROPERTY(qreal borderWidth READ borderWidth WRITE setBorderWidth NOTIFY borderWidthChanged)
public:
explicit FramelessHelper(QObject *parent = nullptr);
~FramelessHelper();
static void QmlInitialize();
virtual bool nativeEventFilter(const QByteArray amp;eventType, void *message, long *result);
virtual void classBegin();
virtual void componentComplete();
QQuickItem *titlebar() const;
void setTitlebar(QQuickItem *titlebar);
qreal borderWidth() const;
void setBorderWidth(qreal borderWidth);
signals:
void borderWidthChanged();
void titlebarChanged();
private:
bool containAcceptMouseButtons(QQuickItem *, qreal x, qreal y);
QQuickItem *mTitlebar = nullptr;
QQuickWindow *mQuickWindow = nullptr;
qreal mBorderWidth = 7;
class NativeEventFilter : public QAbstractNativeEventFilter
{
public:
virtual bool nativeEventFilter(const QByteArray amp;eventType, void *message, long *result);
static void deliver(QQuickWindow* window, FramelessHelper *helper);
static NativeEventFilter *instance;
static QHash<WId, FramelessHelper*> helpers;
};
};
#endif // FRAMELESSHELPER_H
framelesshelper.cpp
#include "framelesshelper.h"
#include <QQuickWindow>
using namespace std;
FramelessHelper::FramelessHelper(QObject *parent) : QObject(parent)
{
}
FramelessHelper::~FramelessHelper()
{
NativeEventFilter::helpers.remove(mQuickWindow->winId());
}
void FramelessHelper::QmlInitialize()
{
qmlRegisterType<FramelessHelper>("FramelessHelper", 1,0, "FramelessHelper");
}
QQuickItem *FramelessHelper::titlebar() const
{
return mTitlebar;
}
void FramelessHelper::setTitlebar(QQuickItem *titlebar)
{
if (mTitlebar != titlebar) {
mTitlebar = titlebar;
emit titlebarChanged();
}
}
qreal FramelessHelper::borderWidth() const
{
return mBorderWidth;
}
void FramelessHelper::setBorderWidth(qreal borderWidth)
{
if (mBorderWidth != borderWidth) {
mBorderWidth = borderWidth;
emit borderWidthChanged();
}
}
bool FramelessHelper::containAcceptMouseButtons(QQuickItem *item, qreal x, qreal y)
{
if (item->acceptedMouseButtons() != Qt::NoButton)
return true;
QPointF pos = item->mapToGlobal(QPoint(0, 0));
int rx = x - pos.x();
int ry = y - pos.y();
QQuickItem *child = item->childAt(rx, ry);
return child ? containAcceptMouseButtons(child, x, y) : false;
}
#ifdef Q_OS_WIN
#include <QPoint>
#include <QScreen>
#include <QSize>
#include <windowsx.h>
#include <QCoreApplication>
//#include <dwmapi.h>
//#include <objidl.h>
//#include <gdiplus.h>
//#include <GdiPlusColor.h>
//#include <windows.h>
//#include <WinUser.h>
//#pragma comment (lib,"Dwmapi.lib")
//#pragma comment (lib,"user32.lib")
bool FramelessHelper::nativeEventFilter(const QByteArray amp;eventType, void *message, long *result)
{
Q_UNUSED(eventType)
#if (QT_VERSION == QT_VERSION_CHECK(5, 11, 1))
MSG* msg = *reinterpret_cast<MSG**>(message);
#else
MSG* msg = reinterpret_cast<MSG*>(message);
#endif
switch (msg->message) {
case WM_NCHITTEST: {
*result = 0;
const LONG border_width = mBorderWidth;
RECT winrect;
GetWindowRect(HWND(mQuickWindow->winId()), amp;winrect);
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(msg->lParam);
if (mQuickWindow->visibility() == QWindow::Windowed) {
bool resizeWidth = mQuickWindow->minimumWidth() != mQuickWindow->maximumWidth();
bool resizeHeight = mQuickWindow->minimumHeight() != mQuickWindow->maximumHeight();
if(resizeWidth)
{
//left border
if (x >= winrect.left amp;amp; x < winrect.left border_width)
{
*result = HTLEFT;
}
//right border
if (x < winrect.right amp;amp; x >= winrect.right - border_width)
{
*result = HTRIGHT;
}
}
if(resizeHeight)
{
//bottom border
if (y < winrect.bottom amp;amp; y >= winrect.bottom - border_width)
{
*result = HTBOTTOM;
}
//top border
if (y >= winrect.top amp;amp; y < winrect.top border_width)
{
*result = HTTOP;
}
}
if(resizeWidth amp;amp; resizeHeight)
{
//bottom left corner
if (x >= winrect.left amp;amp; x < winrect.left border_width amp;amp;
y < winrect.bottom amp;amp; y >= winrect.bottom - border_width)
{
*result = HTBOTTOMLEFT;
}
//bottom right corner
if (x < winrect.right amp;amp; x >= winrect.right - border_width amp;amp;
y < winrect.bottom amp;amp; y >= winrect.bottom - border_width)
{
*result = HTBOTTOMRIGHT;
}
//top left corner
if (x >= winrect.left amp;amp; x < winrect.left border_width amp;amp;
y >= winrect.top amp;amp; y < winrect.top border_width)
{
*result = HTTOPLEFT;
}
//top right corner
if (x < winrect.right amp;amp; x >= winrect.right - border_width amp;amp;
y >= winrect.top amp;amp; y < winrect.top border_width)
{
*result = HTTOPRIGHT;
}
}
if (0!=*result) return true;
}
if (!mTitlebar) return false;
QPointF tbPos = mTitlebar->mapToGlobal(QPoint(0, 0));
if (mQuickWindow->visibility() != QWindow::FullScreen amp;amp;
tbPos.y() <= y amp;amp; tbPos.y() mTitlebar->height() >= y amp;amp;
tbPos.x() <= x amp;amp; tbPos.x() mTitlebar->width() >= x amp;amp;
!containAcceptMouseButtons(mTitlebar, x, y))
{
*result = HTCAPTION;
return true;
}
break;
}
case WM_NCCALCSIZE:
{
NCCALCSIZE_PARAMSamp; params = *reinterpret_cast<NCCALCSIZE_PARAMS*>(msg->lParam);
if (params.rgrc[0].top != 0)
params.rgrc[0].top -= 1;
*result = WVR_REDRAW;
return true;
}}
return false;
}
void FramelessHelper::classBegin()
{
}
void FramelessHelper::componentComplete()
{
auto obj = parent();
while (obj != nullptr) {
if (obj->inherits("QQuickRootItem")) {
auto rootItem = qobject_cast<QQuickItem *>(obj);
mQuickWindow = qobject_cast<QQuickWindow *>(rootItem->window());
if (mQuickWindow) {
NativeEventFilter::deliver(mQuickWindow, this);
// 이동한 모니터의 DPI가 다를경우 화면을 다시 그린다.
connect(mQuickWindow, amp;QWindow::screenChanged, this, [this](QScreen *){
SetWindowPos((HWND) mQuickWindow->winId(), NULL, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE);
});
break;
}
}
obj = obj->parent();
}
}
void FramelessHelper::NativeEventFilter::deliver(QQuickWindow *window, FramelessHelper *helper)
{
if (instance == nullptr) {
instance = new NativeEventFilter;
if (instance) qApp->installNativeEventFilter(instance);
}
if (window amp;amp; helper) {
auto wid = window->winId();
if (!helpers.contains(wid)) {
auto hwnd = reinterpret_cast<HWND>(wid);
// set new window style
DWORD oldStyle = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, oldStyle | WS_CAPTION
| WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME);
helpers.insert(wid, helper);
}
}
if (window amp;amp; helper == nullptr) {
helpers.remove(window->winId());
}
}
bool FramelessHelper::NativeEventFilter::nativeEventFilter(const QByteArray amp;eventType, void *message, long *result)
{
Q_UNUSED(eventType)
auto lpMsg = (LPMSG)message;
auto wid = reinterpret_cast<WId>(lpMsg->hwnd);
if (auto helper = helpers.value(wid)) {
return helper->nativeEventFilter(eventType, message, result);
}
return false;
}
FramelessHelper::NativeEventFilter *FramelessHelper::NativeEventFilter::instance = nullptr;
QHash<WId, FramelessHelper*> FramelessHelper::NativeEventFilter::helpers;
#else
void FramelessHelper::classBegin()
{
}
void FramelessHelper::componentComplete()
{
}
void FramelessHelper::NativeEventFilter::deliver(QQuickWindow *window, FramelessHelper *helper)
{
Q_UNUSED(window)
Q_UNUSED(helper)
}
bool FramelessHelper::NativeEventFilter::nativeEventFilter(const QByteArray amp;eventType, void *message, long *result)
{
Q_UNUSED(eventType)
Q_UNUSED(message)
Q_UNUSED(result)
return false;
}
bool FramelessHelper::nativeEventFilter(const QByteArray amp;eventType, void *message, long *result)
{
Q_UNUSED(eventType)
Q_UNUSED(message)
Q_UNUSED(result)
return false;
}
#endif
импорт FramelessHelper 1.0
импорт QtQuick 2.15
импортируйте QtQuick.Окно 2.15
импортируйте QtQuick.Элементы управления 2.15
ApplicationWindow {
id: window
readonly property real borderWidth: 7
visible: true
width: 1024
height: 800
minimumWidth: 800
minimumHeight: 600
flags: Qt.Window | Qt.FramelessWindowHint
FramelessHelper {
titlebar: menuBar
borderWidth: window.borderWidth
}
menuBar: Titlebar { }
}
Комментарии:
1. Ты пробовал
QWindow::startSystemMove()
?
Ответ №1:
Используйте QWindow::startSystemMove()
и Window::startSystemResize(Qt::Edges edges)
вместо того, чтобы вручную изменять положение и размер вашего окна.
В строке заголовка вызывайте это при нажатии мыши: onPressed: Window.window.startSystemMove() // or windowId.startSystemMove()
Комментарии:
1. Спасибо. QQuickWindow::startSystemMove подтвердил, что Aero Snap не работает, но забыл просмотреть QWindow. Могу ли я получить тот же результат от QtQuick?