Получаване на форматиране на празни редове

Малко съм объркан как работи QTextBlock::iterator:

Документацията показва ясни примери как да го използвате в нормален текст:

QTextBlock::iterator it;
for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
    QTextFragment currentFragment = it.fragment();
    if (currentFragment.isValid())
        processFragment(currentFragment);
}

Срещам проблеми с празни редове от текст. На тези линии,

it = currentBlock.begin();
if(it.atEnd())
    // returns true !

Все още трябва да мога да чета форматиране (char и block)

Трябва ли да проверя блока в края? Има ли някакъв друг начин за тестване на блокове без нищо освен новия ред?

Текущото ми решение: проверете и последния итератор, отделно от цикъла "for" и също така тествайте дали това е последният блок в документа (ако се опитам да получа фрагмента от последния блок в документа, програмата се срива ).

Изглежда, че работя срещу документацията... Как да получа форматирането на празни редове?

Редактиране:

Моето старо решение:

QTextBlock currentBlock = document()->findBlock(selStart);
QTextBlock lastBlock = document()->lastBlock();
while (currentBlock.isValid())
{
    QTextBlock::iterator it = currentBlock.begin();
    if(currentBlock != lastBlock && it.atEnd())
    {
        QTextFragment currentFragment = it.fragment();
        if (currentFragment.isValid())
        {
            QTextCharFormat f = currentFragment.charFormat();
            // do something
        }
    } 
    else
    {
        for (; !(it.atEnd()); ++it)
        {
            QTextFragment currentFragment = it.fragment();
            if (currentFragment.isValid())
            {
                // do stuff
                QTextCharFormat f = currentFragment.charFormat();
                // do stuff
            }
        }
    }
}

Ново решение, базирано на отговор от Tarod, елиминира един тест (но изглежда има по-малко последователно поведение)

QTextBlock currentBlock = document()->findBlock(selStart);
QTextBlock lastBlock = document()->lastBlock();
while (currentBlock.isValid())
{
    QTextBlock::iterator it = currentBlock.begin();
    if(currentBlock != lastBlock && it.atEnd())
    {
        QTextCharFormat f = currentBlock.charFormat();
        // do something
    } 
    else
    {
        for (; !(it.atEnd()); ++it)
        {
            QTextFragment currentFragment = it.fragment();
            if (currentFragment.isValid())
            {
                // do stuff
                QTextCharFormat f = currentFragment.charFormat();
                // do stuff
            }
        }
    }
}

Все още трябва да проверя спрямо последния блок и да избягвам да го използвам, ако е празен, понякога се срива.


person Thalia    schedule 01.10.2015    source източник


Отговори (2)


Мисля, че проблемът е, че просто итерирате върху QTextBlock и четете съдържанието на неговите текстови фрагменти. В този случай, за празно QTextBlock, както доказахте, currentBlock.begin() == it.atEnd(), защото QTextBlock няма текстови фрагменти.

Трябва да преминете през всички текстови блокове на документа, да получите необходимата информация и, ако е необходимо, да преминете през всеки един, за да прочетете последователността от текстови фрагменти.

В следващия пример блок #3 е празен ред (\n\n). Няма да видите реда qDebug() << "I am a QTextBlock with text!" отпечатан, въпреки че все още имаме информация за този текстов блок благодарение на QTextBlockFormat и QTextCharFormat.

main.cpp

#include <QApplication>
#include "graphicstextitem_3.h"

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

    GraphicsTextItem_3 g3;
    g3.show();

    return a.exec();
}

graphicstextitem_3.h

#ifndef GRAPHICSTEXTITEM_3_H
#define GRAPHICSTEXTITEM_3_H

#include <QMainWindow>

class QGraphicsScene;
class QGraphicsView;
class QGraphicsTextItem;

class GraphicsTextItem_3 : public QMainWindow
{
    Q_OBJECT
public:
    explicit GraphicsTextItem_3(QMainWindow *parent = 0);

private:
     QGraphicsScene *scene;
     QGraphicsView *view;
     QGraphicsTextItem *item;

signals:

public slots:
};

#endif // GRAPHICSTEXTITEM_3_H

graphicstextitem_3.cpp

#include "graphicstextitem_3.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsTextItem>
#include <QTextCursor>
#include <QTextDocument>
#include <QTextBlock>
#include <QDebug>

GraphicsTextItem_3::GraphicsTextItem_3(QMainWindow *parent) : QMainWindow(parent)
{
    scene = new QGraphicsScene(this);
    view = new QGraphicsView(scene);

    item = new QGraphicsTextItem("Block 0\n Block 1\n Block 2\n\n Block 4");
    item->setTextInteractionFlags(Qt::TextEditorInteraction);
    QFont f = item->font();
    f.setPointSize(30);
    item->setFont(f);

    QTextDocument* doc = item->document();

    for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
    {
        QTextBlockFormat block_format = it.blockFormat();
        QTextCharFormat char_format = it.charFormat();

        qDebug() << "*** Block number: " << it.blockNumber()
                 << " with text: " << it.text();

        qDebug() << "* Block format info: "
                 << " leftMargin: " << block_format.leftMargin()
                 << " rightMargin: " << block_format.rightMargin()
                 << " topMargin: " << block_format.topMargin()
                 << " bottomMargin: " << block_format.bottomMargin()
                 << " lineHeight: " << block_format.lineHeight();

        qDebug() << "* Char format info: "
                 << " pointSize: " << char_format.font().pointSize()
                 << " fontFamily: " << char_format.font().family();

        QTextBlock::iterator tb_it = it.begin();

        if (tb_it.atEnd())
        {
            qDebug() << "it.begin() == tb_it.atEnd()";
            /* The application crashes if we get the fragment */
            // tb_it.fragment();
        }

        for (tb_it = it.begin(); !(tb_it.atEnd()); ++tb_it) {
            QTextFragment currentFragment = tb_it.fragment();

            if (currentFragment.isValid())
            {
                qDebug() << "I am a QTextBlock with text!"
                         << " Out of here empty QTextBlock!"
                         << " You - shall not - pass!";
            }
        }
    }

    scene->addItem(item);
    view->setFixedSize(640, 480);

    this->setCentralWidget(view);
}
person Tarod    schedule 02.10.2015
comment
Благодаря ви за примера. Вашият подход - отне ми минута да го видя - е подобен - извличате информацията от всички блокове на begin() - което се грижи за празните блокове, както и за други непразни. Това премахва необходимостта от отделно тестване за край. Единственият проблем - трябва да мога да направя това върху селекция, а не върху целия документ. В случай, че блокът не е празен, но изборът не започва в началото на блока, аз винаги чета информация, която е от грешни фрагменти, което винаги ще доведе до лош резултат. - person Thalia; 02.10.2015
comment
Може да съм заседнал с подхода си... Фактът, че кодът ми работи - че мога да извлека валиден фрагмент от празен блок - когато it.begin() == it.end() - е озадачаващ - но МОГА да извлека валиден фрагмент от празен блок и да проверя неговия форматирайте с charFormat(), точно както в нормалния цикъл, дори не с blockCharFormat(). Но гледайки вашия пример, не разбрах, че в този случай мога да извлека формата от самия it и нямам нужда от фрагмент. - person Thalia; 02.10.2015
comment
Кодът ти е доста добър. С моя код приложението се срива, ако се опитаме да извлечем фрагмент, когато сме в празен блок и iterator::atEnd() е вярно. Актуализирах кода, за да илюстрирам това. Ако имате текст в празен блок (това е възможно!), може би QTextFragment::isValid() работи различно. - person Tarod; 05.10.2015

Ето псевдо кода (който работи за мен). Накратко, когато методът atEnd() върне TRUE, вие добавяте нов line.

QTextEdit * pwTextEdit = whatever your source;
QTextDocument * poDocument = pwTextEdit->document();

QTextBlock oTextBlock = poDocument->begin();
while (oTextBlock.isValid())
{
    QTextBlock::iterator oTextBlockIterator(oTextBlock.begin());
    while (TRUE)
    {
        if (oTextBlockIterator.atEnd())
        {
            // Append your '\n' here
            break;
        }
        QTextFragment oTextFragment = oTextBlockIterator.fragment();
        QString sText = oTextFragment.text();
        // Process the text from sText
        oTextBlockIterator++;
    }
    oTextBlock = oTextBlock.next();
}
person Daniel    schedule 07.07.2017