Remove QTextFrame from QTextDocument
-
Hi and welcome to devnet,
IIRC, calling delete on the QTextFrame object should remove it from the document.
-
@SGaist I think you are correct. I followed your hint and finally found a note in the QTextFrame's destructor documentation: Destroys the frame, and removes it from the document's layout.
Unfortunately this causes the application to crash with a segmentation fault, but I am still looking into this.
Thanks for your help!
-
You're welcome !
What does the debugger say ?
-
I called myframe->deleteLater() within a method overriding virtual void QTextEdit::keyPressEvent(QKeyEvent *e)
Calling delete myframe has the same effect.
Here is the call stack NetBeans provides me with:
QMetaObject::cast(QObject*) const ()
QTextFrame::iterator::operator++() ()
?? ()
?? ()
QTextDocumentLayout::draw(QPainter*, QAbstractTextDocumentLayout::PaintContext const&) ()
QWidgetTextControl::drawContents(QPainter*, QRectF const&, QWidget*) ()
?? ()
QTextEdit::paintEvent(QPaintEvent*) ()
QWidget::event(QEvent*) ()
QFrame::event(QEvent*) ()
QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) ()
QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
QApplication::notify(QObject*, QEvent*) ()
QCoreApplication::notifyInternal2(QObject*, QEvent*) ()
QWidgetPrivate::sendPaintEvent(QRegion const&) ()
QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&, QPoint const&, int, QPainter*, QWidgetBackingStore*) ()
?? ()
?? ()
QWidgetPrivate::syncBackingStore() ()
QWidget::event(QEvent*) ()
QMainWindow::event(QEvent*) ()
QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
QApplication::notify(QObject*, QEvent*) ()
QCoreApplication::notifyInternal2(QObject*, QEvent*) ()
QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ()
?? ()
g_main_context_dispatch ()
?? ()
g_main_context_iteration ()
QEventDispatcherGlib::processEvents(QFlagsQEventLoop::ProcessEventsFlag) ()
QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) ()
QCoreApplication::exec() ()
main (argc=1, argv=0x7fffffffe658) -
nope, was lying. Calling delete myframe changes the callstack slightly. Still causing segmentation fault, though.
QTextFrame::lastPosition() const ()
?? ()
?? ()
?? ()
?? ()
QTextDocumentLayout::draw(QPainter*, QAbstractTextDocumentLayout::PaintContext const&) ()
QWidgetTextControl::drawContents(QPainter*, QRectF const&, QWidget*) ()
?? ()
QTextEdit::paintEvent(QPaintEvent*) ()
QWidget::event(QEvent*) ()
QFrame::event(QEvent*) ()
QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject*, QEvent*) ()
QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
QApplication::notify(QObject*, QEvent*) ()
QCoreApplication::notifyInternal2(QObject*, QEvent*) ()
QWidgetPrivate::sendPaintEvent(QRegion const&) ()
QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&, QPoint const&, int, QPainter*, QWidgetBackingStore*) ()
?? ()
?? ()
QWidgetPrivate::syncBackingStore() ()
QWidget::event(QEvent*) ()
QMainWindow::event(QEvent*) ()
QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
QApplication::notify(QObject*, QEvent*) ()
QCoreApplication::notifyInternal2(QObject*, QEvent*) ()
QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ()
?? ()
g_main_context_dispatch ()
?? ()
g_main_context_iteration ()
QEventDispatcherGlib::processEvents(QFlagsQEventLoop::ProcessEventsFlag) ()
QEventLoop::exec(QFlagsQEventLoop::ProcessEventsFlag) ()
QCoreApplication::exec() ()
main (argc=1, argv=0x7fffffffe658) -
I created a small self contained snippet for anyone to try out. Maybe someone can tell me what I am doing wrong when attempting to remove a QTextFrame. Hit 'x' one or more times to add a frame, hit 'y' to remove one. This is where things crash.
main.cpp
#include <QApplication> #include <QtCore> #include <QtGui> #include <QtWidgets> namespace { class TestEdit : public QTextEdit { protected: virtual void keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_X) { QTextCursor cursor = this->textCursor(); QTextFrameFormat frameFormat; frameFormat.setBackground(QColor(Qt::red)); QTextFrame* frame = cursor.insertFrame(frameFormat); } else if (e->key() == Qt::Key_Y) { QTextCursor cursor = this->textCursor(); QTextFrame* currentFrame = cursor.currentFrame(); if(currentFrame != this->document()->rootFrame()) { //delete currentFrame; currentFrame->deleteLater(); return; } } QTextEdit::keyPressEvent(e); } }; } int main(int argc, char *argv[]) { QApplication app(argc, argv); QMainWindow* w = new QMainWindow(); w->setAttribute(Qt::WA_DeleteOnClose); w->setCentralWidget(new TestEdit()); w->adjustSize(); w->move(QApplication::desktop()->screen()->rect().center() - w->rect().center()); w->show(); return app.exec(); }
-
I haven't tested it yet but one thing I see is that you don't test that currentFrame is not null
-
I created a bugreport for this. Looks to me that at least the documentation could need some work in this area. For the record: I found out that removing all child blocks (and frames?) leads to the automatic removal of the frame itself.
-
The documentation has been fixed :)