Qt Model/View/Controller Example - qt

I am just getting started in Qt, and trying to get a simplified, working example of the model-view-controller design pattern.
So far, I have been able to use signals and slots to connect basic widgets like push buttons to a QLabel, and have the view be modified as the push button is clicked/released. See code below for a working example of that (implemented in the MainWindow class).
I am trying to define a class, in this case, Game, which is going to be my model. I want Game to have all of the data and business rules of my entire application. I do not require that Game be anything Qt specific--it very well could be generic C++. However, in the code below, it does have some Qt-specific code to implement a QTimer which is useful for the purposes of this example.
I am trying to achieve two things in this example:
I want to have a model which is able to generate some sort of event within itself, like incrementing a variable value over the passage of time, and then ultimately see that change somehow reflected in the view. Or better yet, the timeout() of the QTimer could simply be the signal that is connected to some slot, that slot being some event that takes place within the model. Using the code shown below, the reflection in the view would be the setting of label_1 (part of the MainWindow class) to display one of the images already stored in imageOn or imageOff (also part of the MainWindow class).
I want to have the push button associated with the on_pushButton_clicked() and on_pushButton_pressed() slots be able to modify some value stored within the model. Then, coming full circle with item 1, have that update of the model be reflected in the view.
If my terminology thus far is incorrect or inconsistent with Qt terminology of MVC design pattern, forgive me. I would welcome any clarification on that. Also, if the example code I have provided is too convoluted for exemplifying the MVC design pattern in Qt, I am more than willing to wipe the slate clean and start with a more appropriate example. All I am trying to do is get started with Qt and MVC, but in a way that deals with more complex data types.
I am trying to develop an example in which I can handle a model and class such as Game which is potentially complex--not a simple list of QStrings or something guaranteed to be more straight-forward. When I browsed through the Qt documentation related to MVC, I came across a lot of examples that used the setModel() function to try and make the connections I am essentially outlining in list items 1 and 2. The problem was that I could not see a way of using that exact approach with a more complex data-type like Game which might be the entire data model for a complete application (I know Game is not complex in this example, but it could be eventually). I need something that is scalable and extensible, something that would work for an entire application. If those setModel()-type functions are suitable for this--which they very likely could be, I just could not figure it out on my own--I would like to know how to implement those in this example dealing with QLabel and images.
Code:
game.h
#ifndef GAME_H
#define GAME_H
#include <QtCore>
class Game : public QObject {
Q_OBJECT
public:
Game();
void timed_job();
private:
QTimer *timer;
};
#endif // GAME_H
game.cpp
#include "game.h"
#include <QtCore>
Game::Game() {
}
void Game::timed_job() {
timer = new QTimer(this);
timer->start(1000);
//connect(timer, SIGNAL(timeout()), this, SLOT(flip()));
}
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 slots:
void on_pushButton_clicked();
void on_pushButton_pressed();
private:
Ui::MainWindow *ui;
QImage imageOn, imageOff;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include <QImage>
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
imageOn.load(":/Files/On.jpg");
imageOff.load(":/Files/Off.jpg");
ui->setupUi(this);
}
MainWindow::~MainWindow() {
delete ui;
}
void MainWindow::on_pushButton_clicked() {
ui->label_1->setPixmap(QPixmap::fromImage(imageOff));
}
void MainWindow::on_pushButton_pressed() {
ui->label_1->setPixmap(QPixmap::fromImage(imageOn));
}
main.cpp
#include <QtGui/QApplication>
#include <QLabel>
#include "mainwindow.h"
#include "game.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}

A "controller" in Qt could technically be represented by a separate QObject subclass, containing just slots. And you would wire this between your model and view.
But normally what I do (and see) is to just make your model contain business logic, and your view subclass contain methods for handling it's user interactions. The closest I get to the controller concept is when I have my QMainWindow (or dialog) class that represents the application, and has a bunch of SLOTS on it. These slots get wired in to the private UI members signals to connect them together.
Example: Your main window has a model, a view, and a push button. In the init for the main window, I would set the model in the view, and connect the push button "clicked" to a slot on my window refreshData(). This slot would then call the "update" method on the model, which will automatically propagate to the view. The main window thus acts like a controller.
What you would want to do is to make some type of QAbstractItemModel or QStandardItemModel that represents your data and does what you want to update that data (a timer like you suggested). Any view connected to the model will be able to see it because of the standard interface. You can also just make a separate timer that places data into an existing QStandardItemModel
A note about custom QAbstractItemModel classes
As pointed out by #hyde, jumping into a custom model can be a challenge if you try and do it first, before getting a good understanding of the existing concrete model classes. Here is what I recommend doing:
Get familiar with the convenience widgets (QListWidget, QTableWidget, QTreeWidget)
Then try using a QStandardItemModel with a QListView/QTableView
Then work with QTreeView
Finally, when you really need very custom modeling for your existing data structures, you can work on subclassing QAbstractItemModel to make it use your own internal structure.

Related

Replace QCameraViewfinder with QVideoWidget in Qt 6

I am trying to port some code to Qt 6's reworked QtMultimedia framework and running into a lot of issues of disappearing APIs.
One of these is QCameraViewfinder, which as I understand it, is a simple viewer of the current QCamera image feed.
It used to be a subclass of QVideoWidget, which still exists, and its documentation helpfully states the following:
Attaching a QVideoWidget to a QMediaPlayer or QCamera allows it to display the video or image output of that object.
player = new QMediaPlayer;
player->setSource(QUrl("http://example.com/myclip1.mp4"));
videoWidget = new QVideoWidget;
player->setVideoOutput(videoWidget);
videoWidget->show();
player->play();
Note: Only a single display output can be attached to a media object at one time.
Problem is, there is no way to do QCamera::setVideoOutput(QVideoWidget*) as that function does not exist.
Neither can I find an alternative API that connects the two.
Is this something that they forgot to provide or am I missing something?
I looked through the relevant classes' source code and documentation, but can't for the life of me find the magic incantation that's supposed to give me a simple view into a QCamera's current video feed.
You have to use QMediaCaptureSession:
#include <QApplication>
#include <QCamera>
#include <QMediaDevices>
#include <QMediaCaptureSession>
#include <QVideoWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QVideoWidget videoWidget;
videoWidget.resize(640, 480);
videoWidget.show();
QCamera camera(QMediaDevices::defaultVideoInput());
camera.start();
QMediaCaptureSession mediaCaptureSession;
mediaCaptureSession.setCamera(&camera);
mediaCaptureSession.setVideoOutput(&videoWidget);
return a.exec();
}

Using QSettings in a global static class

My task is to create a QSettings wrapper class (wrapping is mostly needed by QML) which I can reach everywhere from the model, too.
The obvious choice is a static global instance of this class. However the problem is with this approach is that it's destroyed after main, after QApplication is destroyed, thus giving me the following warning:
QApplication::qAppName: Please instantiate the QApplication object first
Here is a simplified, sample code showing a really simple wrapper, and the destruction phases:
#include <QCoreApplication>
#include <QDebug>
#include <QGlobalStatic>
#include <QSettings>
#include <QTimer>
class Settings: public QObject
{
public:
~Settings() { qDebug() << "~Settings"; }
QSettings settings;
};
Q_GLOBAL_STATIC(Settings, globalSettings)
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){qDebug() << "~QCoreApplication aboutToQuit";});
QObject::connect(&app, &QCoreApplication::aboutToQuit, [](){globalSettings->settings.setValue("Hi", 2);});
QObject::connect(&app, &QCoreApplication::destroyed, [](){qDebug() << "~QCoreApplication destroyed";});
QTimer::singleShot(0, &app, SLOT(quit()));
return app.exec();
}
It prints out the following:
~QCoreApplication aboutToQuit
~QCoreApplication destroyed
~Settings
QApplication::qAppName: Please instantiate the QApplication object first
My question is: providing, in my program QSettings is used after QCoreApplication::aboutToQuit is emitted but before QCoreApplication::destroyed, how can I avoid this warning?
Using QSettings
I've used QSettings in pretty much every project I've ever made. Here is the pattern that I tend to use it:
in main.cpp
#include <QSettings>
//...
// Then in main(), after QApplication is instantiated, but before any settings are accessed
QSettings::setDefaultFormat(QSettings::IniFormat);
QApplication::setOrganizationName("MyOrg");
QApplication::setApplicationName("MyApp"):
Then anytime you are about to access QSettings, you just do this:
QSettings s;
s.value(// reading a value
s.setValue(// writing a value
Everything gets saved in the User Scope in an INI text file. It will be located in Windows under C:/Users/<username>/AppData/Roaming/MyOrg/MyApp.ini.
This usage of QSettings (IMHO) is very clean, doesn't require global variables or static references and is very fast and efficient. And it is very readable.
Now to be able to have things load settings at the right times, and not get the errors you mentioned in your question, see the initial example in the links below:
http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application
http://doc.qt.io/qt-5/qtwidgets-mainwindows-application-example.html
It works much better in the timeline of a Qt application and works great. I tend to make a readSettings and writeSettings for most of my GUI classes and for a number of my backend classes. readSettings happens when the widget has its showEvent or constructor happen and the writeSettings happens in the closeEvent. Also if I have a dedicated settings dialog, I emit a signal to have any affected classes to readSettings, right after the settings dialog writes those specific settings.
If you use the QML port of QSettings, it also uses the Organization name and Application name and the default format of QSettings to pick its filename and location.
http://doc.qt.io/qt-5/qml-qt-labs-settings-settings.html
I believe the default functionality of that QML component is just to read the setting when the component is created, and to write the setting whenever QML changes it. So to change it from C++ and have it recognized by QML, you should probably use the standard QML/C++ methods out there such as:
http://doc.qt.io/qt-5/qtqml-cppintegration-topic.html
And lastly if I am planning on installing defaults for a program that are decided for a build and I don't want to hardcode them, I hand write an INI file and have the installer place it in the system scope location: C:/ProgramData/MyOrg/MyApp.ini
And in the case that the settings of your program are more complex than what you want to store in an INI file, I would look into using QJson, and the SaveGame example.
Hope that helps.

How to use QGraphicsScene with QtGui/QGuiApplication?

I created a new Qt 5 project with QtCreator, and added the following lines to it.
#include <QGraphicsScene>
// in main():
QGraphicsScene scene;
In the .pro file I added:
Qt += gui
The object creation of QGraphicsScene is resulting in the segmentation fault.
What point am I missing?
EDIT:
I realized now that instead of QApplication my rest of the program is using QtGui/QGuiApplication.
How to use QGraphicsScene with QtGui/QGuiApplication?
You're correct: with QApplication it works for me in both Qt 4.8 and 5.2, but not with QGuiApplication:
#include <QApplication>
#include <QGraphicsScene>
#include <QTimer>
int main(int argc, char ** argv) {
QApplication app(argc, argv);
// With QGuiApplication, QGraphicsScene constructor crashes.
QGraphicsScene scene;
QTimer::singleShot(1000, &app, SLOT(quit()));
return app.exec();
}
You're incorrect in stating that the code will compile with just the gui module added to the project. Without the widgets module, your code won't compile, and this should have been the first hint that you're trying to do something that's not supported.
QGraphicsScene is not part of the gui module, but of the widgets module! All classes in the widgets module are free to assume (and they do!) that you've instantiated QApplication, not QGuiApplication! I've submitted it as QTBUG-36413, but - unsurprisingly - it got closed as invalid. It simply is not supposed to work.
If you want to use the QGuiApplication, there's a workaround:
The QApplication (but not QGuiApplication) is keeping a list of all graphics scenes. QGraphicsScene assumes that the type of qApp is QApplication. The list is accessed in QGraphicsScenePrivate::init(). The fix is to guard the reference to scene_list with a type check on qApp:
if (qobject_cast<QApplication*>(qApp))
You need this in both QGraphicsScenePrivate::init() and QGraphicsScene::~QGraphicsScene(). I've confirmed that after you recompile Qt, it doesn't crash anymore.
If you're serious about it, you'd have to copy relevant files from Qt's sources to your project, remove the widgets module from the project file, and patch things up until they work. Personally I think it's a waste of effort. It's trivial to render a QGraphicsView into an arbitrary paint device, without having to actually display it on the screen.

Qt Determine if application is launched from Qt Creator?

How can I from within my code determine if my application is started from Qt Creator (either by "F5" or "Ctrl + R")?
The reason why I want to know this is because I want to create my own debug message handler ( using qInstallMessageHandler()) only when the application is launched from the executable directly. Since Qt allows only one message handler, I don't want to create my own when launching from Qt Creator, or else I can't see the debug messages in Qt Creators own debug console.
I don't think there is an easy way to detect that.
You could add a command line argument to the run settings in QtCreator though, and check for that at runtime.
I have two possible solutions:
check the names of parent process (or parent of parent)
there are multiple ways to do this: under Posix (mingw, linux etc..) you have getppid(). Under Windows you can check the namehave the Psapi or other process handling functions. I have done this for other purposes in the past and it works reliably as long as the process names do not change. Alternatively you could check for the window names. Unfortunately none of these solutions are "Qt-Native".
supply a commandline argument only when started from Qt creator
If you use a library to scan commanline arguments this is probably the simplest solution. I usually use Boost Program Options (Google there). You could create a commandline argument like "--console-log" which specifies to put the logging output to the console. To set that option from within Qt Creator is documented here. This is probably the most "Qt-Native" solution. If you use Qt functions to parse the commandline, it is 100% Qt.
You can try IsDebuggerPresent or use only QDebug and check debug messages with debugview outside QT Creator.
You should google qInstallMessageHandler for more information.
But here goes the definitions:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
#include <QtWidgets>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
// If you're running lots of threads you'll need to do some research to
// determine if you need to make this synchronized (i.e. locked)
if(staticTextEdit) {
staticTextEdit->appendPlainText(msg + "\n");
}
}
private slots:
void on_pushButton_clicked();
private:
// There's lots of different ways to do this ... this was the quickest way for me.
static QPlainTextEdit* staticTextEdit;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
Here are the declarations:
#include "mainwindow.h"
#include "ui_mainwindow.h"
QPlainTextEdit* MainWindow::staticTextEdit = NULL;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
staticTextEdit = ui->plainTextEdit;
qInstallMessageHandler(MainWindow::myMessageHandler);
}
MainWindow::~MainWindow()
{
delete ui;
}
// I'm using QtCreator to help create my slots. =).
void MainWindow::on_pushButton_clicked()
{
qDebug() << "CLICKED";
}
Here is a manual solution.
Define a macro in your .pro file....
# To turn on remove the comment marker '#'
# isEmpty(LAUNCH_FROM_IDE):LAUNCH_FROM_IDE = 1
!isEmpty(LAUNCH_FROM_IDE) {
DEFINES += APP_LAUNCH_FROM_IDE
}
And use in your header/source as needed...
#ifdef APP_LAUNCH_FROM_IDE
...
#endif
That's all
Not sure if this applies to the PC, but under OSX, when Qt Creator launches the application, it does it from the development build path; you can get the current launch path with:
QString expath = QCoreApplication::applicationDirPath();
Get that, dump it via qDebug(), and see where you're running from when launched from Qt. As long as that's not the location you run the application from when you're not launching it from within Qt, this should work.
I get this from the qDebug() when building and running in release mode from within Qt Creator:
"/Users/fyngyrz/build-iToolBox-Desktop_Qt_5_8_0_clang_64bit-Release/iToolBox.app/Contents/MacOS/iToolBox"
So for me, when building my app iToolBox I do the detection like this:
if (expath.indexOf("build-iToolBox-Desktop") != -1) // if we're running from inside Qt
{
}
else // we're not running from inside qt
{
}
Note1:
The release and build paths for Qt builds are different by default; so if you need this to work in both release and debug circumstances, you might have to do two checks of the path instead of one, depending on just what you're searching for.
Note 2:
If you incorporate this approach into your application, and the code will remain intact in the release build, be sure not to including anything in your search string that would incorporate any information you don't want to share, such as your real name which could be part of the path under some operating systems, depending on how you set up your user account.

Multithreading in Qt - doubts and problems

nearly searching for hours I became more confused about the Multithreading concept and I need help understanding and implementing it. After searching I have come to the following implementation
main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <mythread1.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
mythread abc;
abc.start();
abc.wait();
return a.exec();
}
In above code mythread.h is my header file which I created for multithreading and below is my code of mythread1.h
mythread1.h
#ifndef MYTHREAD1_H
#define MYTHREAD1_H
#include <QtGui>
#include <windows.h>
class mythread : public QThread
{
public:
void run();
};
void mythread::run()
{
}
#endif // MYTHREAD_H
Now my questions are
I have defined only one function run() and when the thread is initialized how compiler determines it has to execute run() function and what it does when it has multiple functions, I got this question because in main.cpp I just typed abc.start(); and didn't specify what to execute?
Inside mythread1.h and in run function I made a infinite loop using while(0<1) and ran the program and to my surprise I was just presented with white screen with 100% CPU usage(not a surprise), but it should run concurrently without interfering with main thread right? then why this is happening?
I then used QFile::copy("pathtomytargetfile","targetpath"); inside the run function inside in mythread1.cpp but that didn't work :O and it didn't copy that file but when i connected it with Push button in main thread then it got successfully copied, why this happened?
Does anyone know a simpler way to implement multithreading?
Thank you
First of all: run method should be protected!
Secondly, what do you mean by "I have defined only one function run()". You defined method, not function. abc.start() means that abc instance of mythread will start and use it's entry point method void run(). You can't declare more than one method with same signature. And if you wonder how it calls your run() instead of QThread::run() then you need to read something about virtual methods in C++
Ad. 3: How can we tell why your file didn't copy? Check what errors QFile provides you. Change your code something like that:
QFile f("pathtomytargetfile");
if( ! f.copy("targetpath") )
{
qDebug() << f.errorString();
}
It will provide you some usefull info
My answer might confuse you even more, but the following links are worth reading in my opinion:
This is an article by the engineer who introduced the QThread class. He apologizes for suggesting that inheriting from QThread is the way to go.
This article shows you, how you should do it (strictly speaking -- inheriting from QThread will work as well, it just is not as nice design-wise).
On this page you can find an overview of multithreading techniques that Qt offers and some help deciding which one you should use for your specific problem.
HTH

Resources