Search code examples
qtqtabwidgetqplaintextedit

Show asterisk on changes of a QTabWidget


I'm creating a multifile texteditor using tabs for the different files to edit. To do this I'm using a QTabWidget which holds the QPlainTextEdit widgets where the user can edit the text. If the user edits the text within the QPlainTextEdit I want to change the tab title by adding a asterisk (*), to show him there are unsaved changes done within this file.

My current solution is the following:

Add a new tab to the QTabWidget:

QPlainTextEdit* temp = new QPlainTextEdit("lots of text", this);
temp->setWindowTitle("the title of the tab");
connect(temp->document(), SIGNAL(contentsChanged()), this, SLOT(onTabContentChanged()));
mTabWidget->setCurrentIndex(mTabWidget->addTab(temp, temp->windowTitle()));

Slot for reaction to the content change:

void MainWindow::onTabContentChanged(void) {
// Content of a tabbed QPlainTextedit has changed; find it and set it to modified
QTextDocument* tempDocument = dynamic_cast<QTextDocument*>(sender());
if(tempDocument) {
    for (int var = 0; var < mTabWidget->count(); ++var) {
        QPlainTextEdit* tempTextedit =  dynamic_cast<QPlainTextEdit*>(mTabWidget->widget(var));
            if(tempTextedit) {
                if(tempDocument == tempTextedit->document()) {
                    tempTextedit->setWindowModified(true);
                    mTabWidget->setTabText(mTabWidget->indexOf(tempTextedit), "add a * here");
                }
            }
    }
}

}

In my opinion using sender() is not good and it's too much effort/code to do this so I got the feeling I did it wrong or there is a better way to do this.

Any ideas?

Using:

Win7 Pro

Qt 5.3.2


Solution

  • There are multiple ways to simplify this code. For example, you can make use of QPlainTextEdit::textChanged signal instead of QTextDocument::contentsChanged. If you do that, you'll get QPlainTextEdit after dynamic cast and you'll be able to use QTabWidget::indexOf right away without iterating.

    Also you can assume that user can't edit something on inactive tab, so you can just use QTabWidget::currentIndex.

    However, sometimes complicated is better than simplified. I assume your editor will have some features and its behavior will not be the same as simple QPlainTextEdit. It may be good to create a class representing a tab content. You can either derive from QPlainTextEdit or create another form class that contains QPlainTextEdit and possibly will contain more widgets in the future. You can then put all logic related to single editor in this class, so it should also decide which title should be displayed for it. The class should have a pointer to main form or tab widget and can easily calculate its own index in tab widget, so it can rename its tab without using sender().