Crash on language change caused by auto generated code when using a QTableWidget



  • Hello everybody
    I faced a crash on my application when the user tries to change the language. After some investigating I found out that the issue is generated by the auto generated code during the ui'incing process. The behaviour is very easy to reproduce:

    • create a QtGuiApplication for desktop and name it QtGuiApplication1

    • On the main form add a QTableWidget and with the designer add some column and some rows with some text inside

    • Add a translation file and translate the text of the rows on the QTableWidget

    • Use the usual code to manage the language change using the QTranlastor class and reimplementing the QtGuiApplication1::changeEvent for the event QEvent::LanguageChange

    • In the method where you call QTranslator::Load and then QApplication::installTranslator bofore doing anything delete the sample rows added in design time

    • In this case inside the auto generated method retranslateUi (inside the file ui_QtGuiApplication1.h) you will will get a crash

    • This is because the code doesn't test if the QTableWidgetItem * is null before trying to translate it

    Below my code for QtGuiApplication1 and the auto generated file. I'm using Qt 5.13.0

    #include "QtGuiApplication1.h"
    
    QTranslator QtGuiApplication1::translator;
    
    QtGuiApplication1::QtGuiApplication1(QWidget *parent)
    	: QMainWindow(parent)
    {
    	ui.setupUi(this);
    
    	connect(ui.pushButtonTranslate, SIGNAL(clicked()), this, SLOT(onTranslate()));
    
    	inited = false;
    }
    
    void QtGuiApplication1::onTranslate()
    {
    
    	if (!inited)
    	{
    		ui.tableWidget->setRowCount(0);
    		inited = true;
    	}
    
    	QApplication::removeTranslator(&translator);
    
    	// load the new translator
    	if (translator.load("qtguiapplication1_it.qm", "E:\\Progetti\\QtGuiApplication1\\x64\\Debug"))
    		QApplication::installTranslator(&translator);
    
    }
    
    void QtGuiApplication1::changeEvent(QEvent* event)
    {
    	if (event && event->type() == QEvent::LanguageChange)
    	{
    		// retranslate designer form (single inheritance approach)
    		ui.retranslateUi(this);
    	}
    	QWidget::changeEvent(event);
    
    }
    
    
    #pragma once
    
    #include <QtWidgets/QMainWindow>
    #include "ui_QtGuiApplication1.h"
    #include <QTranslator>
    
    class QtGuiApplication1 : public QMainWindow
    {
    	Q_OBJECT
    
    public:
    	QtGuiApplication1(QWidget *parent = Q_NULLPTR);
    
    protected slots:
    
    	virtual void changeEvent(QEvent* event);
    
    	void onTranslate();
    
    private:
    	bool inited;
    
    	static QTranslator translator;
    
    	Ui::QtGuiApplication1Class ui;
    };
    
    
    /********************************************************************************
    ** Form generated from reading UI file 'QtGuiApplication1.ui'
    **
    ** Created by: Qt User Interface Compiler version 5.13.0
    **
    ** WARNING! All changes made in this file will be lost when recompiling UI file!
    ********************************************************************************/
    
    #ifndef UI_QTGUIAPPLICATION1_H
    #define UI_QTGUIAPPLICATION1_H
    
    #include <QtCore/QVariant>
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QHeaderView>
    #include <QtWidgets/QMainWindow>
    #include <QtWidgets/QMenuBar>
    #include <QtWidgets/QPushButton>
    #include <QtWidgets/QStatusBar>
    #include <QtWidgets/QTableWidget>
    #include <QtWidgets/QToolBar>
    #include <QtWidgets/QWidget>
    
    QT_BEGIN_NAMESPACE
    
    class Ui_QtGuiApplication1Class
    {
    public:
        QWidget *centralWidget;
        QTableWidget *tableWidget;
        QPushButton *pushButtonTranslate;
        QMenuBar *menuBar;
        QToolBar *mainToolBar;
        QStatusBar *statusBar;
    
        void setupUi(QMainWindow *QtGuiApplication1Class)
        {
            if (QtGuiApplication1Class->objectName().isEmpty())
                QtGuiApplication1Class->setObjectName(QString::fromUtf8("QtGuiApplication1Class"));
            QtGuiApplication1Class->resize(600, 519);
            centralWidget = new QWidget(QtGuiApplication1Class);
            centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
            tableWidget = new QTableWidget(centralWidget);
            if (tableWidget->columnCount() < 6)
                tableWidget->setColumnCount(6);
            QTableWidgetItem *__qtablewidgetitem = new QTableWidgetItem();
            tableWidget->setHorizontalHeaderItem(0, __qtablewidgetitem);
            QTableWidgetItem *__qtablewidgetitem1 = new QTableWidgetItem();
            tableWidget->setHorizontalHeaderItem(1, __qtablewidgetitem1);
            QTableWidgetItem *__qtablewidgetitem2 = new QTableWidgetItem();
            tableWidget->setHorizontalHeaderItem(2, __qtablewidgetitem2);
            if (tableWidget->rowCount() < 8)
                tableWidget->setRowCount(8);
            QTableWidgetItem *__qtablewidgetitem3 = new QTableWidgetItem();
            tableWidget->setVerticalHeaderItem(0, __qtablewidgetitem3);
            QTableWidgetItem *__qtablewidgetitem4 = new QTableWidgetItem();
            tableWidget->setVerticalHeaderItem(1, __qtablewidgetitem4);
            QTableWidgetItem *__qtablewidgetitem5 = new QTableWidgetItem();
            tableWidget->setVerticalHeaderItem(2, __qtablewidgetitem5);
            QTableWidgetItem *__qtablewidgetitem6 = new QTableWidgetItem();
            tableWidget->setItem(0, 0, __qtablewidgetitem6);
            QTableWidgetItem *__qtablewidgetitem7 = new QTableWidgetItem();
            tableWidget->setItem(0, 1, __qtablewidgetitem7);
            QTableWidgetItem *__qtablewidgetitem8 = new QTableWidgetItem();
            tableWidget->setItem(0, 2, __qtablewidgetitem8);
            QTableWidgetItem *__qtablewidgetitem9 = new QTableWidgetItem();
            tableWidget->setItem(1, 0, __qtablewidgetitem9);
            QTableWidgetItem *__qtablewidgetitem10 = new QTableWidgetItem();
            tableWidget->setItem(1, 1, __qtablewidgetitem10);
            QTableWidgetItem *__qtablewidgetitem11 = new QTableWidgetItem();
            tableWidget->setItem(1, 2, __qtablewidgetitem11);
            QTableWidgetItem *__qtablewidgetitem12 = new QTableWidgetItem();
            tableWidget->setItem(2, 0, __qtablewidgetitem12);
            QTableWidgetItem *__qtablewidgetitem13 = new QTableWidgetItem();
            tableWidget->setItem(2, 1, __qtablewidgetitem13);
            QTableWidgetItem *__qtablewidgetitem14 = new QTableWidgetItem();
            tableWidget->setItem(2, 2, __qtablewidgetitem14);
            tableWidget->setObjectName(QString::fromUtf8("tableWidget"));
            tableWidget->setGeometry(QRect(40, 10, 531, 301));
            tableWidget->setRowCount(8);
            tableWidget->setColumnCount(6);
            pushButtonTranslate = new QPushButton(centralWidget);
            pushButtonTranslate->setObjectName(QString::fromUtf8("pushButtonTranslate"));
            pushButtonTranslate->setGeometry(QRect(40, 340, 161, 61));
            QtGuiApplication1Class->setCentralWidget(centralWidget);
            menuBar = new QMenuBar(QtGuiApplication1Class);
            menuBar->setObjectName(QString::fromUtf8("menuBar"));
            menuBar->setGeometry(QRect(0, 0, 600, 21));
            QtGuiApplication1Class->setMenuBar(menuBar);
            mainToolBar = new QToolBar(QtGuiApplication1Class);
            mainToolBar->setObjectName(QString::fromUtf8("mainToolBar"));
            QtGuiApplication1Class->addToolBar(Qt::TopToolBarArea, mainToolBar);
            statusBar = new QStatusBar(QtGuiApplication1Class);
            statusBar->setObjectName(QString::fromUtf8("statusBar"));
            QtGuiApplication1Class->setStatusBar(statusBar);
    
            retranslateUi(QtGuiApplication1Class);
    
            QMetaObject::connectSlotsByName(QtGuiApplication1Class);
        } // setupUi
    
        void retranslateUi(QMainWindow *QtGuiApplication1Class)
        {
            QtGuiApplication1Class->setWindowTitle(QCoreApplication::translate("QtGuiApplication1Class", "QtGuiApplication1", nullptr));
            QTableWidgetItem *___qtablewidgetitem = tableWidget->horizontalHeaderItem(0);
            ___qtablewidgetitem->setText(QCoreApplication::translate("QtGuiApplication1Class", "col 1", nullptr));
            QTableWidgetItem *___qtablewidgetitem1 = tableWidget->horizontalHeaderItem(1);
            ___qtablewidgetitem1->setText(QCoreApplication::translate("QtGuiApplication1Class", "col2", nullptr));
            QTableWidgetItem *___qtablewidgetitem2 = tableWidget->horizontalHeaderItem(2);
            ___qtablewidgetitem2->setText(QCoreApplication::translate("QtGuiApplication1Class", "col3", nullptr));
            QTableWidgetItem *___qtablewidgetitem3 = tableWidget->verticalHeaderItem(0);
            ___qtablewidgetitem3->setText(QCoreApplication::translate("QtGuiApplication1Class", "New Row", nullptr));
            QTableWidgetItem *___qtablewidgetitem4 = tableWidget->verticalHeaderItem(1);
            ___qtablewidgetitem4->setText(QCoreApplication::translate("QtGuiApplication1Class", "New Row", nullptr));
            QTableWidgetItem *___qtablewidgetitem5 = tableWidget->verticalHeaderItem(2);
            ___qtablewidgetitem5->setText(QCoreApplication::translate("QtGuiApplication1Class", "New Row", nullptr));
    
            const bool __sortingEnabled = tableWidget->isSortingEnabled();
            tableWidget->setSortingEnabled(false);
            QTableWidgetItem *___qtablewidgetitem6 = tableWidget->item(0, 0);
            ___qtablewidgetitem6->setText(QCoreApplication::translate("QtGuiApplication1Class", "aaaa", nullptr));
            QTableWidgetItem *___qtablewidgetitem7 = tableWidget->item(0, 1);
            ___qtablewidgetitem7->setText(QCoreApplication::translate("QtGuiApplication1Class", "aaaa", nullptr));
            QTableWidgetItem *___qtablewidgetitem8 = tableWidget->item(0, 2);
            ___qtablewidgetitem8->setText(QCoreApplication::translate("QtGuiApplication1Class", "aaaa", nullptr));
            QTableWidgetItem *___qtablewidgetitem9 = tableWidget->item(1, 0);
            ___qtablewidgetitem9->setText(QCoreApplication::translate("QtGuiApplication1Class", "bbbb", nullptr));
            QTableWidgetItem *___qtablewidgetitem10 = tableWidget->item(1, 1);
            ___qtablewidgetitem10->setText(QCoreApplication::translate("QtGuiApplication1Class", "bbbb", nullptr));
            QTableWidgetItem *___qtablewidgetitem11 = tableWidget->item(1, 2);
            ___qtablewidgetitem11->setText(QCoreApplication::translate("QtGuiApplication1Class", "bbbb", nullptr));
            QTableWidgetItem *___qtablewidgetitem12 = tableWidget->item(2, 0);
            ___qtablewidgetitem12->setText(QCoreApplication::translate("QtGuiApplication1Class", "cccc", nullptr));
            QTableWidgetItem *___qtablewidgetitem13 = tableWidget->item(2, 1);
            ___qtablewidgetitem13->setText(QCoreApplication::translate("QtGuiApplication1Class", "cccc", nullptr));
            QTableWidgetItem *___qtablewidgetitem14 = tableWidget->item(2, 2);
            ___qtablewidgetitem14->setText(QCoreApplication::translate("QtGuiApplication1Class", "cccc", nullptr));
            tableWidget->setSortingEnabled(__sortingEnabled);
    
            pushButtonTranslate->setText(QCoreApplication::translate("QtGuiApplication1Class", "Translate", nullptr));
        } // retranslateUi
    
    };
    
    namespace Ui {
        class QtGuiApplication1Class: public Ui_QtGuiApplication1Class {};
    } // namespace Ui
    
    QT_END_NAMESPACE
    
    #endif // UI_QTGUIAPPLICATION1_H
    
    

  • Lifetime Qt Champion

    Hi
    And if you in the process,
    completely delete ui_QtGuiApplication1.h
    and rebuild build all ?

    It sounds like some code left overs.

    "This is because the code doesn't test if the QTableWidgetItem * "
    Why would it be NULL ?
    If you delete from the UI (visually) that code should no longer be there.


Log in to reply