Qt GUIにおけるアンカー操作の決定版ガイド: QAbstractTextDocumentLayout::anchorAt() を超えた高度なテクニック


QAbstractTextDocumentLayout::anchorAt()は、指定された位置にあるアンカーの参照を返します。アンカーが存在しない場合は空文字列を返します。

構文

QString QAbstractTextDocumentLayout::anchorAt(const QPointF &position) const;

パラメータ

  • position: アンカーの位置を指定するQPointFオブジェクト

戻り値

  • 例:
  • アンカーの参照。アンカーが存在しない場合は空文字列
QString anchor = layout.anchorAt(position);
if (!anchor.isEmpty()) {
  // アンカーが見つかりました。処理を行う
} else {
  // アンカーが見つかりませんでした。処理を行う
}

詳細

アンカーは、テキストドキュメント内の特定の位置にマークを付けるために使用されます。たとえば、ハイパーリンクや脚注などの参照先を示すために使用できます。

QAbstractTextDocumentLayout::anchorAt()を使用して、指定された位置にあるアンカーを検索できます。アンカーが見つかった場合、そのアンカーの参照が返されます。アンカーが見つからない場合は空文字列が返されます。

この関数は、アンカーをクリックしたときにアンカーに関連付けられたアクションを実行する必要がある場合などに役立ちます。

次の例では、QAbstractTextDocumentLayout::anchorAt()を使用して、テキストドキュメント内のアンカーをクリックしたときにアクションを実行する方法を示します。

class MyTextDocumentLayout : public QAbstractTextDocumentLayout {
public:
  void draw(QPainter *painter, const QRectF &rect) override {
    // ...
  }

  QString anchorAt(const QPointF &position) const override {
    // ...
  }

protected:
  void documentChanged(int position, int charsRemoved, int charsAdded) override {
    // ...
  }

  void drawInlineObject(QPainter *painter, const QRectF &rect,
                        QTextInlineObject object, int posInDocument,
                        const QTextFormat &format) override {
    // ...
  }

  QTextCharFormat format(int position) override {
    // ...
  }

  void positionInlineObject(QTextInlineObject item, int posInDocument,
                            const QTextFormat &format) override {
    // ...
  }

  void resizeInlineObject(QTextInlineObject item, int posInDocument,
                         const QTextFormat &format) override {
    // ...
  }
};

class MyWidget : public QWidget {
public:
  MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
    textDocument = new QTextDocument;
    textLayout = new MyTextDocumentLayout(textDocument);
    textLayout->setDocumentLayout(textDocument);

    connect(textLayout, &QAbstractTextDocumentLayout::cursorPositionChanged,
            this, &MyWidget::onCursorPositionChanged);
  }

private:
  QTextDocument *textDocument;
  MyTextDocumentLayout *textLayout;

public slots:
  void onCursorPositionChanged(const QTextCursor &cursor) {
    QString anchor = textLayout->anchorAt(cursor.position());
    if (!anchor.isEmpty()) {
      // アンカーが見つかりました。処理を行う
    }
  }
};

この例では、MyTextDocumentLayoutというサブクラスを作成し、anchorAt()関数をオーバーライドしています。この関数は、アンカーの参照を返すように実装されています。

MyWidgetクラスは、QTextDocumentMyTextDocumentLayoutオブジェクトを保持します。また、cursorPositionChangedシグナルに接続し、アンカーをクリックしたときにアクションを実行するように実装されています。



#include <QApplication>
#include <QTextDocument>
#include <QTextLayout>
#include <QMessageBox>

class MyTextDocumentLayout : public QAbstractTextDocumentLayout {
public:
  void draw(QPainter *painter, const QRectF &rect) override {
    // ...
  }

  QString anchorAt(const QPointF &position) const override {
    // ...
  }

protected:
  void documentChanged(int position, int charsRemoved, int charsAdded) override {
    // ...
  }

  void drawInlineObject(QPainter *painter, const QRectF &rect,
                        QTextInlineObject object, int posInDocument,
                        const QTextFormat &format) override {
    // ...
  }

  QTextCharFormat format(int position) override {
    // ...
  }

  void positionInlineObject(QTextInlineObject item, int posInDocument,
                            const QTextFormat &format) override {
    // ...
  }

  void resizeInlineObject(QTextInlineObject item, int posInDocument,
                         const QTextFormat &format) override {
    // ...
  }
};

class MyWidget : public QWidget {
public:
  MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
    textDocument = new QTextDocument;
    textLayout = new MyTextDocumentLayout(textDocument);
    textLayout->setDocumentLayout(textDocument);

    connect(textLayout, &QAbstractTextDocumentLayout::cursorPositionChanged,
            this, &MyWidget::onCursorPositionChanged);
  }

private:
  QTextDocument *textDocument;
  MyTextDocumentLayout *textLayout;

public slots:
  void onCursorPositionChanged(const QTextCursor &cursor) {
    QString anchor = textLayout->anchorAt(cursor.position());
    if (!anchor.isEmpty()) {
      QMessageBox::information(this, "アンカー",
                             "アンカーをクリックしました: " + anchor);
    }
  }
};

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

  MyWidget widget;
  widget.show();

  return app.exec();
}

このコードを実行すると、次のようになります。

  1. テキストドキュメント内にアンカーを作成します。
  2. テキストドキュメントをクリックします。
  3. アンカーをクリックすると、メッセージボックスが表示されます。

例2:アンカーをクリックしたときにURLを開く

この例では、QAbstractTextDocumentLayout::anchorAt()を使用して、テキストドキュメント内のアンカーをクリックしたときにURLを開く方法を示します。

#include <QApplication>
#include <QTextDocument>
#include <QTextLayout>
#include <QUrl>
#include <QDesktopServices>

class MyTextDocumentLayout : public QAbstractTextDocumentLayout {
public:
  void draw(QPainter *painter, const QRectF &rect) override {
    // ...
  }

  QString anchorAt(const QPointF &position) const override {
    // ...
  }

protected:
  void documentChanged(int position, int charsRemoved, int charsAdded) override {
    // ...
  }

  void drawInlineObject(QPainter *painter, const QRectF &rect,
                        QTextInlineObject object, int posInDocument,
                        const QTextFormat &format) override {
    // ...
  }

  QTextCharFormat format(int position) override {
    // ...
  }

  void positionInlineObject(QTextInlineObject item, int posInDocument,
                            const QTextFormat &format) override {
    // ...
  }

  void resizeInlineObject(QTextInlineObject item, int posInDocument,
                         const QTextFormat &format) override {
    // ...
  }
};

class MyWidget : public QWidget {
public:
  MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
    textDocument = new QTextDocument;
    textLayout = new MyTextDocumentLayout(textDocument);
    textLayout->setDocumentLayout(textDocument);

    connect(textLayout, &QAbstractTextDocumentLayout::cursorPositionChanged


  • アンカーが存在しない場合は空文字列を返します。

これらの制限を克服するために、QAbstractTextDocumentLayout::anchorAt()の代替方法をいくつか検討することができます。

QTextCursor::anchorAt()を使用する

QTextCursor cursor(textDocument);
cursor.setPosition(position);

QString anchor = cursor.anchorAt();
if (!anchor.isEmpty()) {
  // アンカーが見つかりました。処理を行う
} else {
  // アンカーが見つかりませんでした。処理を行う
}

QTextDocument::findText()を使用する

QTextDocumentFragment fragment = textDocument->findText(anchorText);
if (!fragment.isEmpty()) {
  // アンカーが見つかりました。処理を行う
} else {
  // アンカーが見つかりませんでした。処理を行う
}

カスタムアンカークラスを作成する

カスタムアンカークラスを作成することで、アンカーに関するすべての情報を格納することができます。また、QAbstractTextDocumentLayout::draw()関数を使用して、アンカーをカスタムの方法で描画することができます。

class MyAnchor {
public:
  QString text;
  QUrl url;
  QString id;

  // ...
};

class MyTextDocumentLayout : public QAbstractTextDocumentLayout {
public:
  void draw(QPainter *painter, const QRectF &rect) override {
    // ...

    // アンカーを描画する
    for (const MyAnchor &anchor : anchors) {
      // ...
    }
  }

  // ...

private:
  QList<MyAnchor> anchors;
};