15

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

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

我正在尝试定义一个类,在这种情况下,Game它将成为我的模型。我想Game拥有整个应用程序的所有数据和业务规则。我不要求它Game是特定于 Qt 的——它很可能是通用 C++。然而,在下面的代码中,它确实有一些特定于 Qt 的代码来实现 aQTimer这对于本示例的目的很有用。

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

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

如果到目前为止我的术语不正确或与 MVC 设计模式的 Qt 术语不一致,请见谅。我欢迎对此作出任何澄清。此外,如果我提供的示例代码过于复杂,无法在 Qt 中举例说明 MVC 设计模式,我非常愿意擦干净石板并从更合适的示例开始。我想做的只是开始使用 Qt 和 MVC,但以一种处理更复杂数据类型的方式。

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

代码:

游戏.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

游戏.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()));
}

主窗口.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

主窗口.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));
}

主文件

#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();
}
4

1 回答 1

10

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

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

您想要做的是制作某种类型的QAbstractItemModelQStandardItemModel代表您的数据并执行您想要更新该数据的操作(如您建议的计时器)。由于标准界面,任何连接到模型的视图都可以看到它。您也可以只制作一个单独的计时器,将数据放入现有的 QStandardItemModel

关于自定义 QAbstractItemModel 类的说明

正如@hyde 所指出的,如果您在充分理解现有的具体模型类之前先尝试并尝试去做,那么跳入自定义模型可能会是一个挑战。这是我建议做的事情:

  1. 熟悉方便的小部件(QListWidget、QTableWidget、QTreeWidget)
  2. 然后尝试将 QStandardItemModel 与 QListView/QTableView 一起使用
  3. 然后使用 QTreeView
  4. 最后,当您确实需要对现有数据结构进行非常自定义的建模时,您可以对 QAbstractItemModel 进行子类化以使其使用您自己的内部结构。
于 2012-11-16T19:38:36.487 回答