16

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:

  1. 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).
  2. 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();
}
nairware
  • 3,090
  • 9
  • 37
  • 58
  • Qt uses model-view approach, there is no separate controller. Are you trying to use Qt model-view stuff, or roll your own MVC thing? Then, what is the actual question? – hyde Nov 16 '12 at 19:25
  • I don't know the costs and benefits of Qt model-view stuff vs. roll my own MVC thing, but I cannot see any reason to work against the grain just for the sake of it. I suppose that would mean I want to use Qt model-view stuff. I am not trying to force the controller into the mix. I did not know Qt did not natively distinct controllers. – nairware Nov 16 '12 at 19:57
  • The general view (from what I have read) is that the convenience widgets are good for small stuff. The view / standard models are perfect for when you need to have one data model and many views of that same data...and finally...if you need to do huge datasets that represent your own data structures, the custom models are there for that kind of performance. – jdi Nov 16 '12 at 20:01
  • 1
    A good read on the Qt model-view approach: http://qt-project.org/doc/qt-4.8/model-view-programming.html – joaerl Jul 31 '14 at 15:55

1 Answers1

11

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:

  1. Get familiar with the convenience widgets (QListWidget, QTableWidget, QTreeWidget)
  2. Then try using a QStandardItemModel with a QListView/QTableView
  3. Then work with QTreeView
  4. 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.
jdi
  • 90,542
  • 19
  • 167
  • 203
  • 3
    One comment about QAbstractItemModel: it's arguably one of the most complex parts of Qt, so better be prepared for some hair pulling, and careful doc reading, when doing the first model from scratch... – hyde Nov 16 '12 at 19:54
  • 2
    That might just be a subjective experience. It's only complex if you start on it immediately without first understanding the existing concrete models. Once you know how those work, it's pretty easy to get a simple read-only custom model going. I will update with some info though. Thanks! – jdi Nov 16 '12 at 19:57
  • Thanks for the to-do list. I am going to get started on that and come back with a better foundation. – nairware Nov 17 '12 at 01:07
  • @jdi how complex it is to some programmer, that is subjective, but I think it can be objectively said that it is more complex than almost anything else offered by Qt, especially if you don't count things like OpenGL, where complexity comes from outside Qt. – hyde Nov 17 '12 at 08:43
  • 1
    I think getting into painting, or QGraphics transformations can be equally challenging. Again, it is subjective. Doing a read-only custom model only requires 3-4 methods and it works. – jdi Nov 17 '12 at 15:03