My task is to create a window for QtQuick with possibility to use it like a common window but with custom frame look (not the default system decoration). I would like to achieve effect similar to Visual Studio window or something like this.
Code that allows me to achieve that goal is shown below:
main.cpp
#include <QtQuick/qquickpainteditem.h>
#include <qapplication.h>
#include <qqmlengine.h>
#include <QtQuick/qquickwindow.h>
class frameLess :
public QQuickWindow
{
public:
frameLess(QWindow *parent = 0) :QQuickWindow(parent) { }
bool nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG *msg = static_cast<MSG *>(message);
switch (msg->message)
{
case WM_SHOWWINDOW:
// after that call Qt considers window as frameless
setFlags(Qt::FramelessWindowHint | Qt::WindowSystemMenuHint | Qt::Window | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);
// that call force the Windows to serve users mouse events like in standard window
SetWindowLongPtr(msg->hwnd, GWL_STYLE, WS_POPUP | WS_CAPTION | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX);
return false;
case WM_NCCALCSIZE:
// prevent the Windows from painting the frame
*result = 0;
return true;
default:
break;
}
return false;
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qmlRegisterType<frameLess>("fb", 1, 0, "FrameLess");
QQmlEngine engine;
QQmlComponent *component = new QQmlComponent(&engine);
QObject::connect(&engine, SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit()));
component->loadUrl(QUrl("qrc:////main.qml"));
if (!component->isReady())
{
qWarning("%s", qPrintable(component->errorString()));
return -1;
}
QObject *topLevel = component->create();
QQuickWindow *window = qobject_cast<QQuickWindow *>(topLevel);
QSurfaceFormat surfaceFormat = window->requestedFormat();
window->setFormat(surfaceFormat);
window->show();
return app.exec();
}
main.qml
import fb 1.0
import QtQuick 2.2
import QtQuick.Controls 1.1
FrameLess {
color:"lightgray"
Rectangle {
width: 45
height: 45
color: "green"
anchors {
top: parent.top
left: parent.left
}
MouseArea {
anchors.fill: parent
hoverEnabled: true;
onEntered: parent.color="red"
onExited: parent.color="green"
}
}
}
As a result, frameless window with green rectangle in the upper left corner should appear. Furthermore, that rectangle should change color to red when hovered by mouse.
When I'm building that with ANGLE-based Qt build, everything works as expected.
However, my team is using OpenGL-based Qt build. The problem is that when my code is linked against such version of Qt, painting area is shifted by the size of window frame:
What is more, only painting area is shifted. For example, mouse hitboxes are in proper place. Because of that hitboxes and scene items coordinates are desynchronized. (the interactive area of MouseArea lies in a different place than the Rectangle it fills)
My expectations was that using a different Qt builds should not affect the resulting application.
My question is why using the OpenGL-based Qt build does affect the window looks and how can I achieve portably (across windows Qt builds) the expected behavior.
The build I was using are:
I am using Windows 8.1 for testing
Update: It seems that this bug is fixed in Qt 5.4.0
This is a Qt bug. Please report as such. You shouldn't need to do anything special in your code for this to behave properly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With