Qt QML如何通过双击在文本区域中手动选择单词

Qt QML如何通过双击在文本区域中手动选择单词,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

双击选择单词,但我想定制它,例如,选择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问题的一个版本,你不能有某种“事件观察者”,其工作是检查事件,但不阻止它们继续正常运行

如果我有一个事件观察者,我可以让它“观察”文本区域,然后单击或双击做一些事情

所以,现在我们要做一个

接触面积

#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;
};
嗯,这几乎奏效了。只有在
eventFilter
中处理了
eventFilter
事件时,我才能捕获我的合成点击。当未处理
过滤器看不到
鼠标按钮释放

这是为什么。我希望这是在其他QtQuick项目看到它之前遇到的第一个处理程序


有什么帮助吗?

我想不出任何解决方案可以保留
TextArea
行为,就在QML方面。我将尝试在C++端包装、继承或重新实现组件,添加您想要的。
  • 继承可能很棘手,因为很少有Qt类是直接继承的,查看
    QQuickTextArea
    qquicktextededit
    源代码,这可能是一个挑战
  • 重新实现可能是一项工作,但这可能是我的选择,同时将逻辑和代码保持在最低限度
    QQuickTextArea
    似乎是一个很好的基础/参考,因为它比
    QQuickTextArea
    更小/更简单(后者反过来在内部使用TextArea)
这其中有两个关键要素:

  • 事件管理(鼠标、选择等)
  • 基于Qt OpenGL包装类(QSG*场景图类)的组件渲染。这有点晦涩,但是有一些教程和演示。您可以复制粘贴原始代码
对于这两种情况,我建议深入研究源代码:

  • QQuickTextEdit
  • QQuickTextArea
    • 想出了一个办法

      步骤1,定义事件的观察者类 观察员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();
      
      };
      

      看起来您可以使用以下工具执行此操作:

      导入QtQuick 2.15
      导入QtQuick.Controls 2.15
      文本字段{
      宽度:parent.width
      selectByMouse:true
      塔普汉德尔{
      grabPermissions:PointerHandler.TakeOverForbidden
      onDoubleTapped:(事件点)=>{
      打印(“taptap”);
      eventPoint.accepted=true;
      }
      }
      }
      

      请注意,我经历了在
      TextField
      上双击=选择字符串在上述两种情况下都不起作用。单击并拖动以选择“始终有效”。

      您是否尝试先搜索它?@folibis当然,但它没有指示如何覆盖双击或其他操作。如果我添加自己的
      MouseArea
      ,则
      TextArea
      中断。您应该澄清您的问题,因为此评论完全改变了question@folibis你说得对。我补充了我到目前为止所尝试的。谢谢你的回答。不幸的是,我使用的是
      TextArea
      1.4,因为我需要的是controls2中没有的剪切粘贴对话框。我尝试在中复制并更改QML源,但私人部分太多。我有一个不同的C++方法。但是它不起作用。哦,很好,我不认为您能够正确捕获/释放复杂对象(如文本词)上的事件。干得好
      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")
                  }
              }
          }
      }    
      
      
      #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();
      
      };
      
      #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();
      }
      
      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
              }
          }
      }