Search code examples
qtqmltouchscreen

Qml QTouchDevice


I am new in Qt. I am working on windows desktop application and using Qt with qml. On PC that hasn't QTouchDevices, splitter between component (element that allow you resize component on window) works good with mouse (screenshot "Good distance"), but if screen is touchscreen I have next problem, please look on screenshot "Wrong distance".

My application shouldn't support any touch device. So how to disable this Qt feature? I need the same behavior like on device without touch screen.

Wrong distance

Wrong distance

Good distance

Good distance

I have tried disable touch device using privet methods using next sample:

QWindowSystemInterface::unregisterTouchDevice(QTouchDevice::devices().first());

This works, but QWindowSystemInterface is private class and it disable touchscreen. And one more in QTCreator splitters work fine, exactly as I need.


Solution

  • If you can't patch Qt, the only way that I can think of would be to iterate through the children, searching for the MouseArea. For example, suppose you had this QML:

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    import QtQuick.Layouts 1.1
    
    ApplicationWindow {
        width: 600
        height: 400
        visible: true
    
        property alias splitView: splitView
    
        SplitView {
            id: splitView
            anchors.fill: parent
    
            Rectangle {
                width: 200
                Layout.maximumWidth: 400
                color: "lightblue"
                Text {
                    text: "View 1"
                    anchors.centerIn: parent
                }
            }
    
            Rectangle {
                id: centerItem
                Layout.minimumWidth: 50
                Layout.fillWidth: true
                color: "lightgray"
                Text {
                    text: "View 2"
                    anchors.centerIn: parent
                }
            }
        }
    }
    

    You could then print out the object tree of the SplitView like so:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQuickItem>
    #include <QDebug>
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        QObject *window = engine.rootObjects().first();
        QQuickItem *splitView = window->property("splitView").value<QQuickItem*>();
        splitView->dumpObjectTree();
    
        return app.exec();
    }
    

    That gives you:

    SplitView_QMLTYPE_1:: 
        QQmlComponent:: 
        QQuickSystemPalette:: 
        QObject_QML_2:: 
        QQmlComponent:: 
        QQuickItem:: 
        QQuickItem:: 
        QQuickItem:: 
            QQuickLoader_QML_3:: 
                QObject_QML_4:: 
                QQuickMouseArea_QML_5:: 
                QQuickRectangle:: 
                    QQmlContext:: 
        QQuickItem:: 
        QQmlComponentAttached:: 
        QQuickRectangle:: 
            QQuickText:: 
            QQuickLayoutAttached:: 
        QQuickRectangle:: 
            QQuickText:: 
            QQuickLayoutAttached:: 
        QQuickLayoutAttached:: 
    

    QObject::dumpObjectTree() prints out metaObject->className(), so we know to look for an object whose metaObject has a className matching that:

    Then:

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQuickItem>
    #include <QScreen>
    #include <QWindow>
    #include <QDebug>
    
    QQuickItem *findMouseArea(QQuickItem *item)
    {
        foreach (QQuickItem *childItem, item->childItems()) {
            if (QString(childItem->metaObject()->className()).startsWith(QStringLiteral("QQuickMouseArea_QML"))) {
                return childItem;
            } else {
                QQuickItem *mouseArea = findMouseArea(childItem);
                if (mouseArea) {
                    return mouseArea;
                }
            }
        }
    
        return 0;
    }
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        QWindow *window = qobject_cast<QWindow*>(engine.rootObjects().first());
        QQuickItem *splitView = window->property("splitView").value<QQuickItem*>();
        QQuickItem *mouseArea = findMouseArea(splitView);
        mouseArea->setProperty("defaultMargin", QVariant(window->screen()->physicalDotsPerInch() / 25.4));
    
        return app.exec();
    }
    

    Apparently, Screen::pixelDensity is calculated using the physical dots per inch of the screen, divided by 25.4, so we copy that as well. You could use any other value there.

    You will need to adapt the code should a second MouseArea ever be introduced, for example.

    It's still largely dependent on private API, but it doesn't touch Qt code, at least.