1

I'm working on a RaspberryPi with a 3.5 inch LCD screen. I have a Qt 5 based application that operates in kiosk mode without a title bar. The app uses the entire 320x480 screen. I am trying to add a second dialog that is displayed when the user clicks a button on the main dialog window.

Each dialog is designed using Qt Designer. Each dialog has a *.ui file that sets the dialog size and adds a button. The *.ui file is uic'd or moc'd into a header and source file:

$g++ -c -pipe -g3 -O1 -O2 -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_UITOOLS_
LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/x86_64
-linux-gnu/qt5 -isystem /usr/include/x86_64-linux-gnu/qt5/QtUiTools -isystem /us
r/include/x86_64-linux-gnu/qt5/QtWidgets -isystem /usr/include/x86_64-linux-gnu/
qt5/QtGui -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -I. -isystem /usr/in
clude/libdrm -I. -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -o dialog1.o 
dialog1.cpp
In file included from dialog2.h:7:0,
                 from dialog1.h:8,
                 from dialog1.cpp:1:
ui_dialog2.h:22:7: error: redefinition of ‘class Ui_Dialog’
 class Ui_Dialog
       ^~~~~~~~~
In file included from dialog1.h:7:0,
                 from dialog1.cpp:1:
ui_dialog1.h:22:7: note: previous definition of ‘class Ui_Dialog’
 class Ui_Dialog
       ^~~~~~~~~
In file included from dialog2.h:7:0,
                 from dialog1.h:8,
                 from dialog1.cpp:1:
ui_dialog2.h:50:11: error: redefinition of ‘class Ui::Dialog’
     class Dialog: public Ui_Dialog {};
           ^~~~~~
In file included from dialog1.h:7:0,
                 from dialog1.cpp:1:
ui_dialog1.h:50:11: note: previous definition of ‘class Ui::Dialog’
     class Dialog: public Ui_Dialog {};
           ^~~~~~
Makefile:445: recipe for target dialog1.o failed
make: *** [dialog1.o] Error 1

The problem seems to be the way the *.ui file is translated:

$ cat ui_dialog1.h | tail -n 7
namespace Ui {
    class Dialog: public Ui_Dialog {};
} // namespace Ui

And:

$ cat ui_dialog2.h | tail -n 7
namespace Ui {
    class Dialog: public Ui_Dialog {};
} // namespace Ui

I know the problem, but I am not sure how to fix it under Qt tools. The tools need to use a unique namespace or unique class name for each *.ui file.

How do I fix the problem?


A MCVE is available at Noloader | qt-ui-dialog GitHub. The MCVE be cloned with:

git clone https://github.com/noloader/qt-ui-dialog

The problem can be reproduced with:

cd qt-ui-dialog
make clean && qmake && make
p-a-o-l-o
  • 9,807
  • 2
  • 22
  • 35
jww
  • 97,681
  • 90
  • 411
  • 885
  • I find it strange that I generated that problem, are you using any IDE? I've done things similar to what you point out but Qt Creator is smart to distinguish and avoid those problems, you could provide a [mre] – eyllanesc Dec 11 '19 at 09:08
  • Thanks @eyllanesc. No, I am not using an IDE. I do use Qt Designer to design the forms, however. Where would you like the source files for the MCVE? Pasted into the question? GitHub? Elsewhere? The XML files are relatively large, so I avoided dumping them into the question. – jww Dec 11 '19 at 09:10
  • On the other hand, seeing your previous questions, I observe that you are a beginner in Qt so I recommend using QtCreator since you will avoid trivial problems like the one you point out and that way your learning curve will be easier. – eyllanesc Dec 11 '19 at 09:14
  • If your code is extensive it is not an MRE, so you could create .ui that do not have any widget and so your .xml would not be extensive since as you point out the problem is not with the content but with the double declaration that is caused by the top item of the XML. – eyllanesc Dec 11 '19 at 09:15
  • In conclusion: If your project is small then it can be an MRE, but if it is extensive then you will have to strive to minimize it or create another project only oriented to implement the functionality that generates problems. I am surprised that I have to explain this to a 70k user. – eyllanesc Dec 11 '19 at 09:17
  • @eyllanesc - You should not be surprised a 70k user does not want to dump a wall of text with the question. I'm a Qt beginner, and I am working from [C++ GUI Programming with Qt](https://www.amazon.com/dp/0132354160). Unfortunately, the book does not cover the errors I am encountering. I'd expect an experience Qt user to know the problem from the tail of the `ui_*` files. – jww Dec 11 '19 at 09:21
  • Recommendation: do not use old books, use the Qt documentation, or if you have time follow the tutorials of https://www.youtube.com/user/VoidRealms , https://www.youtube.com/playlist?list=PL2D1942A4688E9D63 (are those that start me in Qt). Use Qt Creator <3 – eyllanesc Dec 11 '19 at 09:26

1 Answers1

2

An ui_something.h header must be included in something.cpp source file, not in something.h header. Looking at your compiler output, it seems you're including ui_dialog1.h in dialog1.h, which is wrong: include it in dialog1.cpp, instead (same applies to other dialogs).

Be sure to forward declare the Ui namespace and class in the header, though. In both your headers, add this lines before the dialog class declaration:

namespace Ui {
    class Dialog;
}

This means you must use a pointer to this Ui::Dialog class, so it has to be:

class Dialog1 : public QDialog
{
   /* ... */
private:
    Ui::Dialog * ui;
};

and, accordingly:

Dialog1::Dialog1(QDialog *parent)
    : QDialog(parent), 
      ui(new Ui::Dialog)
{
    ui->setupUi(this);
}

cleanup:

Dialog1::~Dialog1()
{
    delete ui;
}
p-a-o-l-o
  • 9,807
  • 2
  • 22
  • 35
  • Thanks again @p-a-o-l-o. Switching to a `Ui::Dialog*` and reworking the includes cleared the issue. I also found another way to clear it using Qt Designer. In Qt Designer we can rename the dialog. The setting is under ***`Qobject`***, and the setting is ***`objectName`***. So changing the object name to `Dialog1` and `Dialog2` results in `UI_Dialog1` and `UI_Dialog2`, and then `Ui::Dialog1` and `Ui::Dialog2`. – jww Dec 12 '19 at 01:23
  • One more related question if you don't mind... Why do folks prefer `Ui::Dialog* ui` rather then `Ui::Dialog ui`. The former requires dynamic memory allocation from the heap. The latter does not require a heap allocation, and is more efficient at runtime. – jww Dec 12 '19 at 01:34
  • In this peculiar case, there's no choice: because of the forward declaration, one could only use a pointer (or a reference, like `Ui::Dialog & ui`). – p-a-o-l-o Dec 12 '19 at 08:51
  • I tried to use an `unique_ptr` to ensure the cleanup and I got another compile failure. The declaration is `std::unique_ptr ui;`, and the error is `error: invalid application of ‘sizeof’ to incomplete type ‘Ui::Dialog’`. I think those objects need a unique name, and the `ui_dialog.h` header needs to be included in the class header. – jww Dec 17 '19 at 00:09
  • @jww a smart pointer is redundant here: you're already implementing RAII by yourself: `ui` object is well encapsulated into dialog class (it's private), instantiated in its constructor and delete'd in its destructor. – p-a-o-l-o Dec 17 '19 at 07:39