如何创建从特定数字开始的 QTextList Decimal

问题描述 投票:0回答:1

我知道如何在 QTextEdit 中创建列表(请参阅下面的代码,这是最重要的部分)。我想知道是否可以创建一个编号列表,从特定数字开始

例如每次列清单:

  1. 从数字开始
  2. 一个。

但我想知道 qt 是否支持列表

  1. 开始
  2. 任何指定的数字。

在文档中,有 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();
}
list qt formatting richtext qtextedit
1个回答
1
投票

从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 之前,没有测试。可能存在一些错误。,

QmyTextList.h

// ...
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;
};
// ...

QmyTextList.cpp

// ...
    : 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;
    }
    // ...
};
© www.soinside.com 2019 - 2024. All rights reserved.