Qt QML Как вручную выбрать слово в TextArea двойным щелчком мыши - PullRequest
0 голосов
/ 19 марта 2019

двойной щелчок выбирает слова, но я бы хотел настроить его, например, для выбора термина $ 1000.

Пример:

import QtQuick 2.7
import QtQuick.Controls 1.4

ApplicationWindow
{
    visible: true
    width: 640
    height: 480

    TextArea
    {
        anchors.fill: parent
        text: "hello, try to select the $1000 prize!"
        font.pointSize: 14
    } 
}

Например, каким-то образом переопределить selectWord, либо переопределив onDoubleClicked, либо добавив свои собственные MouseArea, которые не нарушают существующую функциональность TextArea.

Не уверен, как это сделать.

Спасибо за любую помощь.

обновление

Я попытался добавить MouseArea, но это не сработало.Пример;

ApplicationWindow
{
    visible: true
    width: 640
    height: 480

    TextArea
    {
        anchors.fill: parent
        text: "hello, try to select the $1000 prize!"
        font.pointSize: 14

        MouseArea
        {
            anchors.fill: parent
            propagateComposedEvents: true
            onClicked: 
            {
                // attempt to get an event on click without
                // affecting the TextArea. But it breaks selection.
                console.log("clicked some text")
                mouse.accepted = false
            }
        }
    }
}    

Обновление 2

Я думаю, что эта проблема является версией долговременной проблемы Qt, что у вас не может быть какого-то "наблюдателя событий", чья работа состоит в том, чтобыпроверять события, но не мешать им продолжать нормальную работу.

Если бы у меня был наблюдатель событий, я мог бы заставить его "наблюдать" за TextArea и делать что-то по щелчку или двойному щелчку.

Так, вот идет попытка сделать один ....

toucharea.h

#pragma once

#include <QGuiApplication>
#include <QQuickItem>
#include <QTime>

class TouchArea : public QQuickItem
{
    Q_OBJECT
    Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged)

public:

    QTime _lastMousePress;
    int   _clickThresholdMS = 300;

    bool eventFilter(QObject*, QEvent *event) override
    {
        // if false this will allow the event to continue as normal
        // if true it will stop the event propagating
        bool handled = false;

        // https://doc.qt.io/qt-5/qevent.html#Type-enum
        QEvent::Type t = event->type();
        switch (t)
        {
        case QEvent::TouchUpdate:
            break;
        case QEvent::KeyPress:
        case QEvent::KeyRelease:
            {
                QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
                qDebug("key press %d", keyEvent->key());
            }
            break;
        case QEvent::MouseButtonPress:
            {
                qDebug() << "mouse press";
                _lastMousePress.start();
                break;
            }
        case QEvent::MouseButtonRelease:
            {
                qDebug() << "mouse release";
                int dt = _lastMousePress.elapsed();

                if (dt < _clickThresholdMS)
                {
                    qDebug() << "mouse click";
                    emit clicked();
                }
                break;
            }
        }

        return handled;
    }

    QQuickItem *target() const { return _target; }

    void setTarget(QQuickItem *target) 
    {
        qDebug() << "set target";
        if (_target == target) return;

        if (_target)
            _target->removeEventFilter(this);

        _target = target;

        if (_target)
            _target->installEventFilter(this);

        emit targetChanged();
    }

signals:

    void targetChanged();
    void clicked();

private:

    QQuickItem* _target = 0;
};

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <qqmlcontext.h>

#include "toucharea.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<TouchArea>("App", 1, 0, "TouchArea");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

main.qml

import QtQuick 2.12
import QtQuick.Controls 1.4

import App 1.0

ApplicationWindow
{
    visible: true
    width: 640
    height: 480


    TextArea
    {
        id: tarea
        anchors.fill: parent
        text: "hello, try to select the $1000 prize!"
        font.pointSize: 14

        MouseArea
        {
            enabled: false
            anchors.fill: parent

            TouchArea
            {
                target: parent
                onClicked: console.log("captured a click")
            }
        }
    }
}    

Ну, это почти сработало.Я могу захватить только мой синтетический клик , если мы handled событие в eventFilter.Если нет handled, фильтр не видит MouseButtonRelease.

Почему это так.Я ожидал, что это будет первый обработчик, с которым столкнулся до , другие элементы QtQuick увидят его.

Любая помощь?

Ответы [ 2 ]

0 голосов
/ 20 марта 2019

Разобраться в пути;

Шаг 1, определить класс Observer для событий

наблюдатель.h


#pragma once

#include <QGuiApplication>
#include <QQuickItem>
#include <QTime>
#include <QMouseEvent>

class Observer : public QQuickItem
{
    Q_OBJECT

public:

    QTime _lastMousePress;
    int   _clickThresholdMS = 300;

    Observer()
    {
        setFiltersChildMouseEvents(true);
    }

    bool childMouseEventFilter(QQuickItem*, QEvent *event) override
    {
        // if false this will allow the event to continue as normal
        // if true it will stop the event propagating
        bool handled = false;

        // https://doc.qt.io/qt-5/qevent.html#Type-enum
        QEvent::Type t = event->type();
        switch (t)
        {
        case QEvent::TouchUpdate:
            break;
        case QEvent::KeyPress:
        case QEvent::KeyRelease:
            {
                QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
                qDebug("key press %d", keyEvent->key());
            }
            break;
        case QEvent::MouseButtonPress:
            {
                //qDebug() << "mouse press";
                _lastMousePress.start();
            }
            break;
        case QEvent::MouseButtonRelease:
            {
                //qDebug() << "mouse release";
                int dt = _lastMousePress.elapsed();

                if (dt < _clickThresholdMS)
                {
                    //qDebug() << "mouse click";
                    emit clicked();
                }
            }
            break;
        case QEvent::MouseButtonDblClick:
            {
                //QMouseEvent* mevent = static_cast<QMouseEvent*>(event);
                //qDebug() << "mouse double click";
                emit doubleClicked();
                handled = true;
            }
            break;
        }

        return handled;
    }

signals:

    void clicked();
    void doubleClicked();

};

Шаг 2, поместить его в main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <qqmlcontext.h>

#include "observer.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<Observer>("App", 1, 0, "Observer");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

Шаг 3, используйте Observer для обнаружения события

Определите, какое событие вы хотите, а затем заставьте его делать то, что вам нужно, например, для двойного щелчка, чтобы выбрать более широкий класс символовв TextArea;

import QtQuick 2.12
import QtQuick.Controls 1.4

import App 1.0

ApplicationWindow
{
    visible: true
    width: 640
    height: 480

    Observer
    {
        anchors.fill: parent

        onDoubleClicked:
        {
            tarea.selectWord();

            var s = tarea.selectionStart
            var e = tarea.selectionEnd

            function allowed(c)
            {
                if (c == "$" || c == "#") return true;
                if (c >= "0" && c <= "9") return true;
                if (c.toUpperCase() != c.toLowerCase()) return true;
                return false;
            }

            while (allowed(tarea.getText(s-1, s))) tarea.select(--s, e);
            while (allowed(tarea.getText(e, e+1))) tarea.select(s, ++e);
        }

        TextArea
        {
            id: tarea
            anchors.fill: parent
            text: "hello, try to select the #$$$1000###$foo prize!"
            font.pointSize: 14
        }
    }
}    
0 голосов
/ 19 марта 2019

Я не могу придумать никакого решения, которое сохранило бы поведение TextArea, только на стороне QML.Вместо этого я бы попытался обернуть, унаследовать или переопределить компонент на стороне C ++, чтобы добавить то, что вы хотите.

  • Наследование может быть непростым делом, так как несколько классов Qt предназначены для непосредственного наследования, если смотреть на QQuickTextArea и QQuickTextEdit источник, это может быть сложной задачей
  • Повторное внедрение может быть некоторымработать, но это, вероятно, будет вариант, я бы пошел, сохраняя при этом логику и код там до минимума.QQuickTextArea кажется хорошей базой / справкой, так как она меньше / проще, чем QQuickTextArea (которая в свою очередь использует TextArea для внутреннего использования)

Два ключевых элемента для этого:

  • Событияуправление (мышь, выделение, ...)
  • Визуализация компонента на основе классов-оболочек Qt OpenGL (классы графов сцен QSG *).Это немного неясно, но есть некоторые уроки и презентации там об этом.И вы можете просто скопировать и вставить оригинальный код.

Для обоих я бы порекомендовал покопаться в исходном коде:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...