如何在我的 C++ 应用程序中重用 Qt 的 QTextCursor?
How do I reuse Qt's QTextCursor in my C++ application?
我正在 Windows 上使用 C++ 中的 Qt 实现一个文本编辑器,并使用 QWidget 作为我使用 OpenGL 显示文本的表面。到目前为止,我已经有了自己的布局引擎和文档模型,并且能够让文本显示在小部件上。
现在我正在尝试实现一个文本游标,其使用方式类似于 Qt 提供的游标,但 QTextCursor 与其 QTextDocument 模型紧密相关,我无法将其子类化以重新使用我的模型。有什么方法可以在没有模型的情况下仅重用光标吗?
如果没有,我该如何使用 Qt 实现文本光标?
注意:我确实使用了 Windows 提供的插入符方法 here,但我希望避免直接使用它们。
TL;DR:你不能。这不是插入符号。
QTextCursor
是一个迭代器,它与屏幕上的光标无关。如果它作为迭代器很有用,并且如果你自己的文本表示是建立在 QTextDocument
之上,你当然可以重用它。但它不是插入符号。
可见光标控件由 QTextEdit
实现提供。回想一下,QTextEdit
是 QTextDocument
的视图 - 它完全用于文本的图形渲染、控制可见光标等。
没有可用于插入符号的 public Qt API。当您使用 Qt 进行渲染时,WINAPI 插入符方法完全没有用。您需要自己的插入符实现。假设您已经有一个文本表示和一个渲染器,您大概有一个在文本表示上工作的迭代器,因此实现插入符号应该是一件微不足道的事情。
WINAPI 插入符号非常简单,可以通过 Qt 的强大功能重新实现:
class Caret : public QWidget {
Q_OBJECT
Q_PROPERTY(int period READ period WRITE setPeriod)
QPicture m_shape;
BasicTimer m_timer;
int m_period;
void updateSize() {
auto size = m_shape.boundingRect().size();
setFixedSize(size);
resize(size);
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timer.timerId()) return;
if (isVisible()) hide(); else show();
}
public:
QPicture defaultShape(int w, int h) {
QPicture pic;
QPainter p(&pic);
p.fillRect(0, 0, w, h, Qt::black);
return pic;
}
Caret(QWidget * parent = 0, const QPicture & pic = defaultShape()) :
QWidget(parent), m_shape(pic), m_period(250) {
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_TranslucentBackground);
m_timer.start(m_period);
updateSize();
}
void setShape(const QPicture & pic) {
m_shape = pic;
updateSize();
update();
}
void setPeriod(int period) {
if (period < 1) {
m_timer.stop();
if (m_period > 0) show();
} else
m_timer.start(period);
m_period = period;
}
int period() const { return m_period; }
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE {
auto painter = QPainter(this);
painter.fillRect(rect(), Qt::transparent);
painter.drawPicture(QPoint(), m_shape);
}
};
我正在 Windows 上使用 C++ 中的 Qt 实现一个文本编辑器,并使用 QWidget 作为我使用 OpenGL 显示文本的表面。到目前为止,我已经有了自己的布局引擎和文档模型,并且能够让文本显示在小部件上。
现在我正在尝试实现一个文本游标,其使用方式类似于 Qt 提供的游标,但 QTextCursor 与其 QTextDocument 模型紧密相关,我无法将其子类化以重新使用我的模型。有什么方法可以在没有模型的情况下仅重用光标吗?
如果没有,我该如何使用 Qt 实现文本光标?
注意:我确实使用了 Windows 提供的插入符方法 here,但我希望避免直接使用它们。
TL;DR:你不能。这不是插入符号。
QTextCursor
是一个迭代器,它与屏幕上的光标无关。如果它作为迭代器很有用,并且如果你自己的文本表示是建立在 QTextDocument
之上,你当然可以重用它。但它不是插入符号。
可见光标控件由 QTextEdit
实现提供。回想一下,QTextEdit
是 QTextDocument
的视图 - 它完全用于文本的图形渲染、控制可见光标等。
没有可用于插入符号的 public Qt API。当您使用 Qt 进行渲染时,WINAPI 插入符方法完全没有用。您需要自己的插入符实现。假设您已经有一个文本表示和一个渲染器,您大概有一个在文本表示上工作的迭代器,因此实现插入符号应该是一件微不足道的事情。
WINAPI 插入符号非常简单,可以通过 Qt 的强大功能重新实现:
class Caret : public QWidget {
Q_OBJECT
Q_PROPERTY(int period READ period WRITE setPeriod)
QPicture m_shape;
BasicTimer m_timer;
int m_period;
void updateSize() {
auto size = m_shape.boundingRect().size();
setFixedSize(size);
resize(size);
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timer.timerId()) return;
if (isVisible()) hide(); else show();
}
public:
QPicture defaultShape(int w, int h) {
QPicture pic;
QPainter p(&pic);
p.fillRect(0, 0, w, h, Qt::black);
return pic;
}
Caret(QWidget * parent = 0, const QPicture & pic = defaultShape()) :
QWidget(parent), m_shape(pic), m_period(250) {
setAttribute(Qt::WA_TransparentForMouseEvents);
setAttribute(Qt::WA_TranslucentBackground);
m_timer.start(m_period);
updateSize();
}
void setShape(const QPicture & pic) {
m_shape = pic;
updateSize();
update();
}
void setPeriod(int period) {
if (period < 1) {
m_timer.stop();
if (m_period > 0) show();
} else
m_timer.start(period);
m_period = period;
}
int period() const { return m_period; }
void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE {
auto painter = QPainter(this);
painter.fillRect(rect(), Qt::transparent);
painter.drawPicture(QPoint(), m_shape);
}
};