我知道如何在 QTextEdit 中创建列表(请参阅下面的代码,这是最重要的部分)。我想知道是否可以创建一个编号列表,从特定数字开始。
例如每次列清单:
但我想知道 qt 是否支持列表
在文档中,有 QTextListFormat::setNumberPrefix 但在我看来,这就是出现在数字之前的内容。谢谢。
中央功能:
void CreateQuestionForm::list(bool checked, QTextListFormat::Style style) {
QTextCursor cursor = ui->f_textedit->textCursor();
cursor.beginEditBlock();
if (!checked) {
QTextBlockFormat obfmt = cursor.blockFormat();
QTextBlockFormat bfmt;
bfmt.setIndent(obfmt.indent());
cursor.setBlockFormat(bfmt);
} else {
QTextListFormat listFmt;
if (cursor.currentList()) {
listFmt = cursor.currentList()->format();
}
listFmt.setStyle(style);
cursor.createList(listFmt);
}
cursor.endEditBlock();
}
从Qt 6.6开始,Qt已经实现了上述方法
void QTextListFormat::setStart(int start)
以及相应的查询方法int QTextListFormat::start
(证据:https://github.com/qt/qtbase/blob/dev/src/gui/text/qtextformat .cpp#L2759)
但是,当您想在 Qt 6.6 之前使用此方法时,我建议您对
QTextList
、QTextListFormat
进行子类化,并使用适当的方法处理 QTextCursor::insertList
,例如设置 objectIndex
es、覆盖 QTextBlockFormat
设置、 ...但是大约半年后 Qt 6.6 发布后,如果您的计算机允许兼容最新的 Qt,事情就会变得简单。
编辑:
现在,Qt 还是 6.4。 Qt 6.5将于2023年4月9日发布测试版。根据Qt过去版本的平均发布速度,我可以确定Qt 6.6将在半年后发布其源代码和在线安装程序。
6.6之后的MRE:
// ......
void QmyTextEdit::insertList()
{
QTextListFormat form;
QTextListFormat = QTextListFormat();
QTextListFormat.setStart(3);
QTextListFormat.setStyle(QTextListFormat::ListDecimal);
// m_cursor = textCursor();
m_cursor.createList(form);
}
// ....
但是,在 Qt 6.6 之前,没有测试。可能存在一些错误。,
// ...
class QmyTextList : public QTextList
{
Q_OBJECT
public:
QmyTextList(QTextDocument &doc);
void setStart(int start);
int start();
QString itemText(const QTextBlock &blockIt) const;
private:
int m_start;
};
// ...
// ...
: QTextList(doc)
{
setStart(1)
}
void QmyTextList::setStart(int start)
{
if (start != m_start)
m_start = start;
}
int QmyTextList::start()
{
return m_start;
}
QString QmyTextList::itemText(const QTextBlock &blockIt) const
{
Q_D(const QTextList);
int item = blockIt.blockNumber();
if (item <= 0)
return QString();
QTextBlock block = blockIt.previousBlock();
QTextBlockFormat blockFormat = block.blockFormat();
QString result;
const int style = format().style();
QString numberPrefix;
QString numberSuffix = u"."_s;
// the number of the item might be offset by start, which defaults to 1
const int itemNumber = (item + format().start() - 1) + m_start;
if (format().hasProperty(QTextFormat::ListNumberPrefix))
numberPrefix = format().numberPrefix();
if (format().hasProperty(QTextFormat::ListNumberSuffix))
numberSuffix = format().numberSuffix();
switch (style) {
case QTextListFormat::ListDecimal:
result = QString::number(itemNumber);
break;
// from the old richtext
case QTextListFormat::ListLowerAlpha:
case QTextListFormat::ListUpperAlpha:
{
// match the html default behavior of falling back to decimal numbers
if (itemNumber < 1) {
result = QString::number(itemNumber);
break;
}
const char baseChar = style == QTextListFormat::ListUpperAlpha ? 'A' : 'a';
int c = itemNumber;
while (c > 0) {
c--;
result.prepend(QChar::fromUcs2(baseChar + (c % 26)));
c /= 26;
}
}
break;
case QTextListFormat::ListLowerRoman:
case QTextListFormat::ListUpperRoman:
{
// match the html default behavior of falling back to decimal numbers
if (itemNumber < 1) {
result = QString::number(itemNumber);
} else if (itemNumber < 5000) {
QByteArray romanNumeral;
// works for up to 4999 items
static const char romanSymbolsLower[] = "iiivixxxlxcccdcmmmm";
static const char romanSymbolsUpper[] = "IIIVIXXXLXCCCDCMMMM";
QByteArray romanSymbols; // wrap to have "mid"
if (style == QTextListFormat::ListLowerRoman)
romanSymbols = QByteArray::fromRawData(romanSymbolsLower, sizeof(romanSymbolsLower));
else
romanSymbols = QByteArray::fromRawData(romanSymbolsUpper, sizeof(romanSymbolsUpper));
int c[] = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 };
int n = itemNumber;
for (int i = 12; i >= 0; n %= c[i], i--) {
int q = n / c[i];
if (q > 0) {
int startDigit = i + (i+3)/4;
int numDigits;
if (i % 4) {
// c[i] == 4|5|9|40|50|90|400|500|900
if ((i-2) % 4) {
// c[i] == 4|9|40|90|400|900 => with subtraction (IV, IX, XL, XC, ...)
numDigits = 2;
}
else {
// c[i] == 5|50|500 (V, L, D)
numDigits = 1;
}
}
else {
// c[i] == 1|10|100|1000 (I, II, III, X, XX, ...)
numDigits = q;
}
romanNumeral.append(romanSymbols.mid(startDigit, numDigits));
}
}
result = QString::fromLatin1(romanNumeral);
} else {
result = u"?"_s;
}
}
break;
default:
Q_ASSERT(false);
}
if (blockIt.textDirection() == Qt::RightToLeft)
return numberSuffix + result + numberPrefix;
else
return numberPrefix + result + numberSuffix;
}
插入列表时,
QTextCursor cur_ = textCursor();
QTextListFormat format_ = QTextListFormat()
format_.setStyle(QTextListForamt::ListDisc);
QmyTextList* list = static_cast<QmyTextList *>document()->createObject(format_);
QTextBlockFormat modifier;
modifier = QTextBlockFormat();
modifier.setObjectIndex(list->objectIndex());
cur_.mergeBlockFormat(modifier);
不过,我的建议是等到 Qt 6.6 发布后,使用
setStart
方法。
编辑整整一年后:
Qt 6.6 甚至 Qt 6.7 都已经发布了。现在您可以通过
QTextListFormat::setStart
使用它们。
对于 Qt 6.6 之前的版本,请记住继承
QTextDocument
并重写 protected:
createObject(const QTextFormat &format)
方法。
// ...
class QmyTextDocument : public QTextDocument
{
Q_OBJECT
public:
// ...
protected:
QTextObject *createObject(const QTextFormat &format) override
{
QTextObject *object = new QTextObject(this);
if (f.isListFormat())
object = new QmyTextList(this);
// Assume you've subclassed the QTextList
else if (f.isTableFormat())
object = new QTextTable(this);
// Or QmyTextTable if you also override it
else if
// ...
return object;
}
// ...
};