Cross-platform Qt5 project using cmake - qt

I am familiar with Qt4 but we are trying to transition to Qt5 and it's being very difficult. I'm trying to create a very simple application, and I had it working using the Qt PRO file, but we need to base it on cmake to keep the build server happy.
The error I get is "invalid use of incomplete type ‘struct Ui::MainWindow’" in the line in mainwindow.cpp where it constructs "ui(new Ui::MainWindow)".
Here are my files (simplified to shorten this post):
mainwindow.h
#include <QtWidgets/QMainWindow>
namespace Ui { class MainWindow; }
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
mainwindow.cpp
#include "mainwindow.h"
#include "moc_mainwindow.cpp"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{ }
MainWindow::~MainWindow()
{ delete ui; }
cmakelists.txt
CMAKE_MINIMUM_REQUIRED( VERSION 2.8.9 FATAL_ERROR )
PROJECT(Test)
set(CMAKE_AUTOMOC TRUE)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
file (GLOB Sources src/*.cpp )
add_executable(Test ${Sources} src/mainwindow.ui )
qt5_use_modules(Test Widgets)
I'm sure I'm missing something obvious, but I've been looking all day and can't figure this one out ...
Looking at the generated moc_mainwindow.cpp (again, some lines truncated to keep this post short):
#include "../src/mainwindow.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
QT_BEGIN_MOC_NAMESPACE
void MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
Q_UNUSED(_id);
Q_UNUSED(_c);
Q_UNUSED(_a);
}
QT_END_MOC_NAMESPACE
I am guessing that MainWindow::qt_static_metacall() is declared in my mainwindow.h in the Q_OBJECT macro. which means I have no idea where this mystical Ui::MainWindow is coming from. Or not.
UPDATE
The problem seems to be that in my mainwindow.cpp, I should be #including "ui_mainwindow.h" instead of "moc_mainwindow.cpp", but there is no "ui_mainwindow.h" being generated, only moc_mainwindow.cpp.

Turns out my understanding of Qt was completely WRONG. moc doesn't generate those ui files, it's doing other magic to make signals & slots work. The solution is to add this link to CMakeLists.txt:
qt5_wrap_ui(uifiles src/mainwindow.ui)

Related

gcc compiles my Qt class with vtable undefined

I cannot get rid of the error "Undefined reference to vtable" when compiling my Linux desktop application.
I did find the thread
Undefined reference to vtable
I have a
set(CMAKE_AUTOMOC ON)
in my CMakeLists.txt
but I receive
AutoMoc warning
---------------
"SRC:/QtGUI/BASIC/SimulatorWindowBasic.cpp"
includes the moc file "SimulatorWindowBasic.moc", but does not contain a Q_OBJECT, Q_GADGET, Q_GADGET_EXPORT, Q_NAMESPACE or Q_NAMESPACE_EXPORT macro.
despite that my definition contains
a Q_Object.
At the end of build, I receive the feared message
/usr/bin/ld: CMakeFiles/Basic_GUI.dir/Basic_GUI.cpp.o: in function `main':
/Myhome/main/BASIC/Basic_GUI.cpp:6: undefined reference to `SimulatorWindowBasic::SimulatorWindowBasic(int, char**, QWidget*)'
/usr/bin/ld: CMakeFiles/Basic_GUI.dir/Basic_GUI.cpp.o: in function `SimulatorWindowBasic::~SimulatorWindowBasic()':
What do I wrong?
Below I show my relevant sources.
(in my previous install using Qt5 and Ubuntu 20.04
I did not experience this issue. The present install uses Ubuntu 22.04 and Qt 6.4.2)
#ifndef SimulatorWindowBasic_H
#define SimulatorWindowBasic_H
#include <QMainWindow>
namespace Ui {
class SimulatorWindowBasic;
}
class SimulatorWindowBasic : public QMainWindow
{
Q_OBJECT
public:
explicit SimulatorWindowBasic(int argc, char **argv, QWidget *parent = 0);
virtual ~SimulatorWindowBasic();
protected:
Ui::SimulatorWindowBasic *ui;
};
#endif // SimulatorWindowBasic_H
and
#include "SimulatorWindowBasic.moc"
#include "SimulatorWindowBasic.h"
#include "uiSimulatorWindowBasic.h"
SimulatorWindowBasic::SimulatorWindowBasic(int argc, char **argv, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::SimulatorWindowBasic)
{
ui->setupUi(this); // This creates the basic splitters
}
SimulatorWindowBasic::~SimulatorWindowBasic
{
}
You have to include "moc_SimulatorWindowBasic.cpp" because you want to have moc run on a header (and not on your source) as described in the cmake documentation

QWidget-Method hide() destroys surface in IVI-enabled Wayland-Compositor

I have a compositor based on the IVI compositor example in which I can manipulate visibility of surfaces via the "visible" property of the respective surface.
However, when a client tries to hide a QWidget via the hide() method, the compositor will destroy the surface instead of just setting the visible property to false.
Is this the intended behavior, and if so, is there a way to change that?
Steps to reproduce:
Build and run the compositor example
Create a new Qt Widgets Project in QtCreator, leave all settings at default
Change mainwindow.h and mainwindow.cpp to look like this:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QTimer *pTimer;
private slots:
void hideWindow();
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
pTimer = new QTimer();
pTimer->setInterval(1000);
connect(pTimer, SIGNAL(timeout()), this, SLOT(hideWindow()));
pTimer->start();
}
void MainWindow::hideWindow()
{
if (isVisible())
{
qDebug() << "hide!";
hide();
}
else
{
qDebug() << "show!";
show();
}
}
MainWindow::~MainWindow()
{
delete ui;
}
When you build and run this program, it will periodically hide and show its mainwindow, but the way it does this is not by telling the compositor to set the "visible" property of the widget, and instead destroying and re-creating the surface.
Also note that you need to set some environment variables before starting the app:
To start a Qt application using the ivi-application protocol with the right id, you need to set QT_WAYLAND_SHELL_INTEGRATION to ivi-shell and QT_IVI_SURFACE_ID to 1337

Image not shown using Qpixmap with QT5.4 and mvs2013 x64

I am using QT (version 5.4 msvc2013_64) with of-course vs2013. The compilation is successful but when running not every thing functions. Before with vs2010 and QT (i think version 5.1 msvc_2010_opengl do not remember exactly) every thing was working but now things are wried which maybe typical with the start of newer versions but need to be resolved. I also got other issues with this but lets get this resolved first as maybe others will be resolved too else I will post another question for the other problems. Of-course If i do not see a solution to this problem with the current QT and vs I will switch to vs2012 (requires downloading and installing); Maybe then everything will work as before. Thanks in advance.
ui_ta7feezquran.h
/********************************************************************************
** Form generated from reading UI file 'ta7feezquran.ui'
**
** Created by: Qt User Interface Compiler version 5.4.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_TA7FEEZQURAN_H
#define UI_TA7FEEZQURAN_H
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QLabel>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QToolBar>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Ta7feezQuranClass
{
public:
QWidget *centralWidget;
QLabel *a;
QMenuBar *menuBar;
QToolBar *mainToolBar;
void setupUi(QMainWindow *Ta7feezQuranClass)
{
if (Ta7feezQuranClass->objectName().isEmpty())
Ta7feezQuranClass->setObjectName(QStringLiteral("Ta7feezQuranClass"));
Ta7feezQuranClass->resize(572, 485);
centralWidget = new QWidget(Ta7feezQuranClass);
centralWidget->setObjectName(QStringLiteral("centralWidget"));
a = new QLabel(centralWidget);
a->setObjectName(QStringLiteral("a"));
a->setGeometry(QRect(-30, -20, 601, 471));
a->setPixmap(QPixmap(QString::fromUtf8(":/Ta7feezQuran/Resources/Amasjed Alharam.jpg")));
a->setScaledContents(true);
Ta7feezQuranClass->setCentralWidget(centralWidget);
menuBar = new QMenuBar(Ta7feezQuranClass);
menuBar->setObjectName(QStringLiteral("menuBar"));
menuBar->setGeometry(QRect(0, 0, 572, 21));
menuBar->setLayoutDirection(Qt::RightToLeft);
Ta7feezQuranClass->setMenuBar(menuBar);
mainToolBar = new QToolBar(Ta7feezQuranClass);
mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
Ta7feezQuranClass->addToolBar(Qt::TopToolBarArea, mainToolBar);
retranslateUi(Ta7feezQuranClass);
QMetaObject::connectSlotsByName(Ta7feezQuranClass);
} // setupUi
void retranslateUi(QMainWindow *Ta7feezQuranClass)
{
Ta7feezQuranClass->setWindowTitle(QApplication::translate("Ta7feezQuranClass", "Ta7feezQuran", 0));
a->setText(QString());
} // retranslateUi
};
namespace Ui {
class Ta7feezQuranClass: public Ui_Ta7feezQuranClass {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_TA7FEEZQURAN_H
ta7feezquran.h
#ifndef TA7FEEZQURAN_H
#define TA7FEEZQURAN_H
#include <QtWidgets/QMainWindow>
#include "ui_ta7feezquran.h"
class Ta7feezQuran : public QMainWindow
{
Q_OBJECT
public:
Ta7feezQuran(QWidget *parent = 0);
~Ta7feezQuran();
private:
Ui::Ta7feezQuranClass ui;
};
#endif // TA7FEEZQURAN_H
ta7feezquran.cpp
#include "ta7feezquran.h"
Ta7feezQuran::Ta7feezQuran(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
Ta7feezQuran::~Ta7feezQuran()
{
}
main.cpp
#include "ta7feezquran.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Ta7feezQuran w;
w.show();
return a.exec();
}
ta7feezquran.qrc
<RCC>
<qresource prefix="/Ta7feezQuran">
<file>Resources/Amasjed Alharam.jpg</file>
</qresource>
</RCC>
Some Application features used, for example images, multimedia, print support, etc., require the use of qt plugins.
The required plugins should be copied to the executable folder (folder where .exe file is included) by copying the plugin folders (with the dlls included) and pasting them inside the executable folder. Every thing else should work as expected.
In this case imageformats folder (with qjpeg.dll included as the file used is jpg) is needed to copied.

templated class in Qt

Is it possible to use a templated class (not based on QObject and doesn't have Q_OBJECT macro) in Qt? I keep getting a linker error when trying to use a templated class. however, when I remove the template from the class, it compiles and links fine. I'm just trying to declare a local variable of type Filter, which uses a template, and I get this linker error:
error: undefined reference to `NumericFilter<int>::NumericFilter(int, int)'
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "filter.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
NumericFilter<int> filter(0, 1);
}
MainWindow::~MainWindow()
{
delete ui;
}
filter.h
template <class T>
class NumericFilter {
public:
NumericFilter (int itemType, int val);
protected:
T m_val;
};
filter.cpp
#include "filter.h"
template <class T>
NumericFilter<T>::NumericFilter (int, int)
{
}
Note that if you remove the template in the declaration and source files and comment out the 'T' member, then it compiles fine.
http://www.parashift.com/c++-faq-lite/separate-template-fn-defn-from-decl.html
If you compile and (try to) link these two .cpp files, most compilers will generate linker errors. There are two solutions for this. The first solution is to physically move the definition of the template function into the .h file, even if it is not an inline function.
This solution may (or may not!) cause significant code bloat, meaning your executable size may increase dramatically (or, if your compiler is smart enough, may not; try it and see).
The other solution is to leave the definition of the template function in the .cpp file and simply add the line template void foo(); to that file:
// File "foo.cpp"
#include <iostream>
#include "foo.h"
template<typename T> void foo()
{
std::cout << "Here I am!\n";
}
template void foo<int>();
So for your case, you would have in your .cpp file:
#include "filter.h"
template <class T>
NumericFilter<T>::NumericFilter(int, int)
{
}
template NumericFilter<int>::NumericFilter<int>(int, int); // added line!!!
Tada! No compile errors!
BTW, parashift's explanations on templates in C++ are the best IMHO.
Hope that helps.

What is the use of setupUi(this) in Qt

I am new to Qt. I have downloaded a source from net.
The header file contains the following
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
ainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui; // Need for this line. Any one please help
};
#endif // MAINWINDOW_H
in mainwindow.cpp file ui->setupUI(this) has been called in constructor. Please help what is the need for the creation of ui variable
You need a MainWindow.ui file which is then processed by Qt's UIC mechanism, which is triggered if you run qmake.
If you are using an IDE like Visual Studio with the Qt Plugin or Qt Creator, just create a new Qt GUI class through the wizard and you will have everything you need.
This page discusses usage of UI files in depth.

Resources