简体   繁体   中英

Get more control over text cursor from QML

In the sources, I notice there is quite the comprehensive set of cursor control operations:

enum MoveOperation {
    NoMove,
    Start,
    Up,
    StartOfLine,
    StartOfBlock,
    StartOfWord,
    PreviousBlock,
    PreviousCharacter,
    PreviousWord,
    Left,
    WordLeft,
    End,
    Down,
    EndOfLine,
    EndOfWord,
    EndOfBlock,
    NextBlock,
    NextCharacter,
    NextWord,
    Right,
    WordRight,
    NextCell,
    PreviousCell,
    NextRow,
    PreviousRow
};

In contrast, the latest TextField from QtQuick.Controls 1.4 , the cursor position is exposed as a simple integer, which can be set, but without specifying any of those move operations. And that's about it.

In the older TextEdit there is some extra stuff like selectWord() and moveCursorSelection(int position, SelectionMode mode) , but mode is limited to either selecting characters or words.

What's worse, the sparse existing APIs don't really provide the necessary functionality to manually re-implement most of those modes.

So, thins brings me to the question, which is how to get all that that functionality in QML in the most straightforward and least obtrusive way?

Update:

There is actually a more obvious and less intrusive way to get that functionality, and it is by posting fake events to the desired text edit. This had the advantage of not requiring to use private APIs, thus avoiding all the potential build and compatibility complications:

void postKeyEvent(Qt::Key k, QObject * o, bool sh = false, bool ct = false, bool al = false) {
  uint mod = Qt::NoModifier;
  if (sh) mod |= Qt::ShiftModifier;
  if (ct) mod |= Qt::ControlModifier;
  if (al) mod |= Qt::AltModifier;
  QCoreApplication::postEvent(o, new QKeyEvent(QEvent::KeyPress, k, (Qt::KeyboardModifier)mod));
  QTimer::singleShot(50, [=]() { QCoreApplication::postEvent(o, new QKeyEvent(QEvent::KeyRelease, k, (Qt::KeyboardModifier)mod)); });
}

Now I can finally get all the needed cursor control stuff with my custom virtual keyboard on touch devices.


This is one simple solutions which actually works... if you manage to build it, there are some odd problems with building it :

#include <QtQuick/private/qquicktextedit_p.h>
#include <QtQuick/private/qquicktextedit_p_p.h>
#include <QtQuick/private/qquicktextcontrol_p.h>

class CTextEdit : public QQuickTextEdit {
    Q_OBJECT
  public:
    CTextEdit(QQuickItem * p = 0) : QQuickTextEdit(p) {}
  public slots:
    void cursorOp(int mode) {
      QQuickTextEditPrivate * ep = reinterpret_cast<QQuickTextEditPrivate *>(d_ptr.data());
      QTextCursor c = ep->control->textCursor();
      c.movePosition((QTextCursor::MoveOperation)mode);
      ep->control->setTextCursor(c);
    }
};

Obviously it uses private headers, which has two implications:

  • you will have to add the quick-privte module to the PRO file
  • private stuff is subject to changes, including breaking changes, as this friendly message keeps reminding:

_

Project MESSAGE: This project is using private headers and will therefore be tied to this specific Qt module build version.
Project MESSAGE: Running this project against other versions of the Qt modules may crash at any arbitrary point.
Project MESSAGE: This is not a bug, but a result of using Qt internals. You have been warned!

On the upside, it works like a charm. IMO that functionality should have been available as a part of the public API to begin with, it is quite useful and certainly not something that makes sense to be hidden away.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM