#qt #qml
#qt #qml
Вопрос:
двойной щелчок выбирает слова, но я хотел бы настроить его, например, для выбора термина за 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, заключающейся в том, что у вас не может быть какого-то «наблюдателя событий», чья работа заключается в проверке событий, но не в том, чтобы мешать им продолжать свою обычную работу.
Если бы у меня был наблюдатель событий, я мог бы заставить его «наблюдать» за текстовой областью и делать что-то по щелчку или двойному щелчку.
Итак, здесь мы пытаемся создать один….
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 увидят его.
Любая помощь?
Комментарии:
1. Вы пытались сначала выполнить поиск по этому в документации ?
2. @folibis уверен, но в нем нет указаний, как переопределить doubleclick или иным образом. Если я добавлю свой собственный,
MouseArea
тоTextArea
произойдет сбой.3. Вам следует уточнить свой вопрос, поскольку это замечание полностью меняет вопрос
4. @folibis ты прав. Я добавил то, что пробовал до сих пор.
Ответ №1:
Нашел способ;
Шаг 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" amp;amp; 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
}
}
}
Комментарии:
1. О, здорово, я не думал, что вы сможете правильно перехватывать / выпускать события для сложного объекта, такого как текстовое слово . Хорошая работа!
Ответ №2:
Похоже, вы можете сделать это с помощью TapHandler:
import QtQuick 2.15
import QtQuick.Controls 2.15
TextField {
width: parent.width
selectByMouse: true
TapHandler {
grabPermissions: PointerHandler.TakeOverForbidden
onDoubleTapped: (eventPoint) => {
print("taptap");
eventPoint.accepted = true;
}
}
}
Обратите внимание, что я столкнулся с тем, что двойной щелчок = выбрать строку на TextField
работал и не работал после вышесказанного. Хотя щелчок перетаскивание для выбора всегда срабатывал.
Ответ №3:
Я не могу придумать ни одного решения, которое сохранило бы TextArea
поведение, только на стороне QML. Вместо этого я бы попытался обернуть, наследовать или переопределить компонент на стороне C , чтобы добавить то, что вы хотите.
- Наследование может быть сложным, поскольку немногие классы Qt предназначены для наследования напрямую, глядя на
QQuickTextArea
иQQuickTextEdit
исходный код, это может быть непросто - Переопределение может потребовать некоторой работы, но, вероятно, я бы выбрал именно этот вариант, сведя логику и код к минимуму.
QQuickTextArea
кажется хорошей базой / ссылкой, поскольку она меньше / проще, чемQQuickTextArea
(которая, в свою очередь, использует TextArea внутренне)
Два ключевых элемента для этого:
- Управление событиями (мышь, выделение, …)
- Рендеринг компонента, основанный на классах-оболочках Qt OpenGL (QSG * Классы графов сцен). Это немного непонятно, но есть несколько руководств и презентаций по этому поводу. И вы можете просто скопировать-вставить исходный код.
Для обоих я бы рекомендовал покопаться в исходном коде:
Комментарии:
1. Спасибо за ваш ответ. К сожалению, я использую
TextArea
1.4, потому что мне нужно диалоговое окно «Вырезать и вставить», которого нет в controls2. Я попытался скопировать исходные тексты QML и изменить их, но слишком много закрытых разделов. Я попробовал другой подход C . Но это не работает.