Qt模型/视图/控制器示例

nai*_*are 10 model-view-controller qt signals-slots

我刚刚开始使用Qt,并尝试获得模型 - 视图 - 控制器设计模式的简化工作示例.

到目前为止,我已经能够使用信号和插槽将基本小部件(如按钮)连接到a QLabel,并在单击/释放按钮时修改视图.请参阅下面的代码以获取该实例(在MainWindow类中实现).

我试图定义一个类,在这种情况下Game,这将是我的模型.我想Game拥有整个应用程序的所有数据和业务规则.我不要求GameQt具体 - 它很可能是通用的C++.但是,在下面的代码中,它确实有一些特定于Qt的代码来实现,QTimer这对于本示例的目的是有用的.

我试图在这个例子中实现两件事:

  1. 我希望有一个能够在其自身内部生成某种事件的模型,比如随着时间的推移递增变量值,然后最终看到该变化以某种方式反映在视图中.或者更好的timeout()是,QTimer可能只是连接到某个插槽的信号,该插槽是在模型中发生的某些事件.使用下面显示的代码,视图中的反射将是label_1(MainWindow类的一部分)的设置,以显示已存储的图像之一imageOnimageOff(也是MainWindow类的一部分).
  2. 我想有相关的按钮on_pushButton_clicked()on_pushButton_pressed()插槽能够修改存储在模型内的一些价值.然后,使用第1项进入整圈,将模型的更新反映在视图中.

如果到目前为止我的术语不正确或与MVC设计模式的Qt术语不一致,请原谅我.我欢迎任何澄清.另外,如果我提供的示例代码对于在Qt中举例说明MVC设计模式而言过于复杂,我非常愿意擦除平板并开始使用更合适的示例.我所要做的就是开始使用Qt和MVC,但是处理更复杂的数据类型.

我正在尝试开发一个示例,其中我可以处理模型和类,例如Game可能很复杂 - 不是简单的QStrings列表或保证更直接的东西.当我浏览与MVC相关的Qt文档时,我遇到了很多使用该setModel()函数尝试创建连接的示例,我基本上在列表项1和2中概述了.问题是我看不到一种方法使用更复杂的数据类型的精确方法Game,可能是整个应用程序的整个数据模型(我知道Game在这个例子中并不复杂,但最终可能是这样).我需要一些可扩展和可扩展的东西,这些东西适用于整个应用程序.如果那些setModel()类型函数适合于此 - 它们很可能是,我只是无法自己弄清楚 - 我想知道如何在这个例子中实现处理QLabel和图像.

码:

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
Run Code Online (Sandbox Code Playgroud)

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()));
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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));
}
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

jdi*_*jdi 9

Qt中的"控制器"在技术上可以由一个单独的QObject子类表示,只包含插槽.你可以在模型和视图之间进行连线.
但通常我所做的(和看到的)只是让你的模型包含业务逻辑,你的视图子类包含处理它的用户交互的方法.我最接近控制器概念的是当我有代表应用程序的QMainWindow(或对话框)类时,它上面有一堆SLOTS.这些插槽连接到私有UI成员信号以将它们连接在一起.

示例:您的主窗口有一个模型,一个视图和一个按钮.在主窗口的init中,我将在视图中设置模型,并将"clicked"按钮连接到窗口上的插槽refreshData().然后,此插槽将调用模型上的"更新"方法,该方法将自动传播到视图.因此,主窗口就像一个控制器.

你想要做的是制作某种类型的QAbstractItemModelQStandardItemModel代表你的数据,并做你想要更新的数据(像你建议的计时器).由于标准接口,连接到模型的任何视图都能够看到它.您还可以创建一个单独的计时器,将数据放入现有计数器 QStandardItemModel

关于自定义QAbstractItemModel类的说明

正如@hyde所指出的那样,在深入了解现有的具体模型类之前,跳入自定义模型可能是一个挑战.这是我建议做的:

  1. 熟悉方便小部件(QListWidget,QTableWidget,QTreeWidget)
  2. 然后尝试将QStandardItemModel与QListView/QTableView一起使用
  3. 然后使用QTreeView
  4. 最后,当您真正需要为现有数据结构进行非常自定义建模时,您可以继续使用QAbstractItemModel来使其使用您自己的内部结构.

  • 关于QAbstractItemModel的一个评论:它可以说是Qt中最复杂的部分之一,所以最好准备一些头发拉动,并仔细阅读文档,从头开始做第一个模型... (3认同)
  • 这可能只是一种主观体验。如果您在没有首先了解现有具体模型的情况下立即开始,那么它只会变得复杂。一旦您知道它们是如何工作的,就可以很容易地建立一个简单的只读自定义模型。不过我会更新一些信息。谢谢! (2认同)