2012-11-16 13 views
8

Po prostu zaczynam w Qt i próbuję uzyskać uproszczony, działający przykład wzoru projektu kontrolera widoku.Qt Model/View/Controller Przykład

Do tej pory byłem w stanie używać sygnałów i gniazd do łączenia podstawowych widżetów, takich jak przyciski do QLabel, i mieć widok zmodyfikowany po kliknięciu/zwolnieniu przycisku. Zobacz poniższy kod dla działającego przykładu tego (zaimplementowanego w klasie MainWindow).

Próbuję zdefiniować klasę, w tym przypadku Game, która będzie moim modelem. Chcę, aby Game miał wszystkie dane i reguły biznesowe mojej całej aplikacji. Nie wymagam, aby Game było czymś specyficznym dla Qt - bardzo dobrze mógłby być generyczny C++. Jednakże, w poniższym kodzie, ma on pewien specyficzny dla Qt kod do implementacji QTimer, który jest przydatny do celów tego przykładu.

staram się osiągnąć dwie rzeczy w tym przykładzie:

  1. chcę mieć model, który jest w stanie wygenerować jakieś wydarzenie w sobie, jak zwiększający wartość zmiennej na upływ czasu, i ostatecznie zobaczymy, że ta zmiana w jakiś sposób odzwierciedliła się w widoku. Albo jeszcze lepiej, timeout() z QTimer może być po prostu sygnałem, który jest podłączony do jakiegoś gniazda, który jest jakimś wydarzeniem, które ma miejsce w modelu. Używając kodu pokazanego poniżej, odbicie w widoku byłoby ustawieniem label_1 (część klasy MainWindow) w celu wyświetlenia jednego z obrazów już zapisanych w imageOn lub imageOff (także należących do klasy MainWindow).
  2. Chcę, aby przycisk powiązany z on_pushButton_clicked() i on_pushButton_pressed() był w stanie zmodyfikować niektóre wartości przechowywane w modelu. Następnie, zataczając pełne koło z punktem 1, aktualizację modelu należy odzwierciedlić w widoku.

Jeśli moja dotychczasowa terminologia jest niepoprawna lub niezgodna z terminologią Qt wzoru projektowego MVC, wybacz mi. Z zadowoleniem przyjmuję wszelkie wyjaśnienia w tej sprawie. Ponadto, jeśli podany przeze mnie przykładowy kod jest zbyt zawiły, aby zilustrować wzorzec projektowania MVC w Qt, jestem bardziej niż chętny do wyczyszczenia tablicy i rozpoczęcia z bardziej odpowiednim przykładem. Wszystko, co próbuję zrobić, to zacząć od Qt i MVC, ale w sposób, który zajmuje się bardziej złożonymi typami danych.

Próbuję opracować przykład, w którym mogę obsłużyć model i klasę, taką jak Game, która jest potencjalnie złożona - nie jest to prosta lista QStringów lub coś, co może być bardziej proste. Przeglądając dokumentację związaną z MVC, natknąłem się na wiele przykładów, które wykorzystywały funkcję setModel() do próbowania połączeń, które zasadniczo przedstawiam na liście 1 i 2. Problem polegał na tym, że nie mogłem zobaczyć sposobu użycia tego dokładnego podejścia z bardziej złożonym typem danych, takim jak Game, który może być całym modelem danych dla kompletnej aplikacji (wiem, że Game nie jest skomplikowany w tym przykładzie, ale może w końcu być). Potrzebuję czegoś, co jest skalowalne i rozszerzalne, coś, co zadziałałoby dla całej aplikacji. Jeśli te funkcje typu setModel() nadają się do tego - co najprawdopodobniej mogłyby być, po prostu nie mogłem sam tego sobie wyobrazić - chciałbym wiedzieć, jak wdrożyć te w tym przykładzie dotyczące QLabel i obrazów.

Kod:

gra.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(); 
} 
+0

Qt korzysta z podejścia model-widok, nie ma oddzielnego kontrolera. Czy próbujesz użyć rzeczy z widoku modelu Qt lub przetasować własne rzeczy MVC? Więc jakie jest prawdziwe pytanie? – hyde

+0

Nie znam kosztów i korzyści związanych z modelem Qt w porównaniu z innymi rzeczami w grze MVC, ale nie widzę powodu, by pracować przeciwko ziarnu tylko ze względu na niego. Przypuszczam, że oznaczałoby to, że chcę używać rzeczy typu widoku modelu Qt.Nie próbuję zmusić kontrolera do miksu. Nie wiedziałem, że Qt nie wyróżniało natywnie kontrolerów. – nairware

+0

Ogólny widok (z tego, co przeczytałem) jest taki, że widgety wygody są dobre dla małych rzeczy. Widok/standardowe modele są idealne, gdy potrzebujesz mieć jeden model danych i wiele widoków tych samych danych ... i wreszcie ... jeśli potrzebujesz dużych zbiorów danych, które reprezentują twoje własne struktury danych, niestandardowe modele są tam dla tego rodzaju wykonania. – jdi

Odpowiedz

7

A "Kontroler" Qt może technicznie być reprezentowane przez oddzielny QObject podklasy zawierającym jedynie szczeliny. A ty połączysz to między swoim modelem a widokiem.
Ale normalnie to, co robię (i widzę), to po prostu sprawić, by model zawierał logikę biznesową, a podklasa widoku zawierała metody obsługi interakcji użytkownika. Najbardziej zbliżony do koncepcji kontrolera jest wtedy, gdy mam klasę QMainWindow (lub dialog), która reprezentuje aplikację i ma na sobie kilka slotów. Te gniazda są podłączone do prywatnych sygnałów członków UI, aby połączyć je ze sobą.

Przykład: Twoje główne okno ma model, widok i przycisk. W init dla głównego okna ustawiłem model w widoku i podłącz przycisk "kliknięty" do gniazda w moim oknie refreshData(). Ten slot będzie wówczas wywoływał metodę "aktualizacji" w modelu, która będzie automatycznie propagowana do widoku. Główne okno działa więc jak kontroler.

Co chcesz zrobić, to zrobić jakiś rodzaj QAbstractItemModel lub QStandardItemModel który reprezentuje dane i robi to, co chcesz zaktualizować te dane (timer jak ty sugerowane). Każdy widok podłączony do modelu będzie mógł go zobaczyć ze względu na standardowy interfejs. Można też po prostu zrobić oddzielny zegar, który umieszcza dane w istniejącym QStandardItemModel

notatkę o niestandardowych klas QAbstractItemModel

Jak podkreślił @hyde, skoki w niestandardowym modelu może być wyzwaniem, jeśli spróbujesz i wykonaj to najpierw, zanim uzyskasz dobre zrozumienie istniejących klas konkretnych modeli. Oto co polecam robi:

  1. Zapoznaj się z widżetami ogólnospożywczy (QListWidget, QTableWidget, QTreeWidget)
  2. Następnie spróbuj użyć QStandardItemModel z QListView/QTableView
  3. następnie pracować z QTreeView
  4. Wreszcie , kiedy naprawdę potrzebujesz bardzo niestandardowego modelowania istniejących struktur danych, możesz popracować nad podklasą QAbstractItemModel, aby użyć swojej własnej wewnętrznej struktury.
+2

Jedna uwaga na temat QAbstractItemModel: jest to prawdopodobnie jedna z najbardziej złożonych części Qt, więc lepiej przygotuj się na ciągnięcie za włosy i uważny odczyt dokumentów, kiedy robisz pierwszy model od zera ... – hyde

+0

To może być po prostu subiektywne doświadczenie. To skomplikowane, jeśli zaczniesz od razu, bez wcześniejszego zrozumienia istniejących modeli betonu. Gdy już wiesz, jak to działa, łatwo można uzyskać prosty, dostosowany do odczytu model niestandardowy. Jednak zaktualizuję niektóre informacje. Dzięki! – jdi

+0

Dzięki za listę rzeczy do zrobienia. Zacznę od tego i powrócę z lepszym fundamentem. – nairware