Skip to main content
Code Review

Return to Question

replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link
Notice removed Draw attention by Community Bot
Bounty Ended with no winning answer by Community Bot
Tweeted twitter.com/StackCodeReview/status/717042272961953792
Notice added Draw attention by Smash
Bounty Started worth 50 reputation by Smash
Source Link
Smash
  • 91
  • 2

MVC and Subject-Observer pattern in C++ & QT

I am trying to implement the MVC pattern in C++ & QT, similar to the question here:

Other MVC Questions

The program has 2 line edits:

  • mHexLineEdit
  • mDecLineEdit

3 buttons

  • mConvertToHexButton
  • mConvertoDecButton
  • mClearButton

and just modifies strings.

enter image description here

The difference with the other question is that I am trying to implement the Subject/Observer pattern to update the View once the Model is changed.

Model.h

#ifndef MODEL_H
#define MODEL_H
#include <QString>
#include <Subject>
class Model : virtual public Subject
{
public:
 Model();
 ~Model();
 void convertDecToHex(QString iDec);
 void convertHexToDec(QString iHex);
 void clear();
 QString getDecValue() {return mDecValue;}
 QString getHexValue() {return mHexValue;}
private:
 QString mDecValue;
 QString mHexValue;
};
#endif // MODEL_H

Model.cpp

#include "Model.h"
Model::Model():mDecValue(""),mHexValue(""){}
Model::~Model(){}
void Model::convertDecToHex(QString iDec)
{
 mHexValue = iDec + "Hex";
 notify("HexValue");
}
void Model::convertHexToDec(QString iHex)
{
 mDecValue = iHex + "Dec";
 notify("DecValue");
}
void Model::clear()
{
 mHexValue = "";
 mDecValue = "";
 notify("AllValues");
}

View.h

#ifndef VIEW_H
#define VIEW_H
#include <QtGui/QMainWindow>
#include "ui_View.h"
#include <Observer>
class Controller;
class Model;
class View : public QMainWindow, public Observer
{
 Q_OBJECT
public:
 View(QWidget *parent = 0, Qt::WFlags flags = 0);
 ~View();
 void setController(VController* iController);
 void setModel(VModel* iModel);
 QString getDecValue();
 QString getHexValue();
public slots:
 void ConvertToDecButtonClicked();
 void ConvertToHexButtonClicked();
 void ClearButtonClicked();
private:
 virtual void update(Subject* iChangedSubject, std::string iNotification);
 Ui::ViewClass ui;
 Controller* mController;
 Model* mModel;
};
#endif // VIEW_H

View.cpp

#include "View.h"
#include "Model.h"
#include "Controller.h"
#include <QSignalMapper>
VWorld::VWorld(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
 ui.setupUi(this);
 connect(ui.mConvertToHexButton,SIGNAL(clicked(bool)),this,SLOT(ConvertToHexButtonClicked()));
 connect(ui.mConvertToDecButton,SIGNAL(clicked(bool)),this,SLOT(ConvertToDecButtonClicked()));
 connect(ui.mClearButton,SIGNAL(clicked(bool)),this,SLOT(ClearButtonClicked()));
}
View::~View(){}
void View::setController(Controller* iController)
{
 mController = iController;
 //connect(ui.mConvertToHexButton,SIGNAL(clicked(bool)),this,SLOT(mController->OnConvertToHexButtonClicked(this)));
 //connect(ui.mConvertToDecButton,SIGNAL(clicked(bool)),this,SLOT(mController->OnConvertToDecButtonClicked(this)));
 //connect(ui.mClearButton,SIGNAL(clicked(bool)),this,SLOT(mController->OnClearButtonClicked(this)));
}
void View::setModel(Model* iModel)
{
 mModel = iModel;
 mModel->attach(this);
}
QString View::getDecValue()
{
 return ui.mDecLineEdit->text();
}
QString View::getHexValue()
{
 return ui.mHexLineEdit->text();
}
void View::ConvertToHexButtonClicked()
{
 mController->OnConvertToHexButtonClicked(this);
}
void View::ConvertToDecButtonClicked()
{
 mController->OnConvertToDecButtonClicked(this);
}
void VWorld::ClearButtonClicked() 
{
 mController->OnClearButtonClicked(this);
}
void View::update(Subject* iChangedSubject, std::string iNotification)
{
 if(iNotification.compare("DecValue") == 0)
 {
 ui.mDecLineEdit->setText(mModel->getDecValue());
 }
 else if(iNotification.compare("HexValue") == 0)
 {
 ui.mHexLineEdit->setText(mModel->getHexValue());
 }
 else if(iNotification.compare("AllValues") == 0)
 {
 ui.mDecLineEdit->setText(mModel->getDecValue());
 ui.mHexLineEdit->setText(mModel->getHexValue());
 }
 else
 {
 //Unknown notification;
 }
}

Controller.h

#ifndef CONTROLLER_H
#define CONTROLLER_H
//Forward Declaration
class Model;
class View;
class Controller 
{
public:
 Controller(Model* iModel);
 virtual ~Controller();
 void OnConvertToDecButtonClicked(View* iView);
 void OnConvertToHexButtonClicked(View* iView);
 void OnClearButtonClicked(View* iView);
private:
 Model* mModel;
};
#endif // CONTROLLER_H

Controller.cpp

#include "Controller.h"
#include "Model.h"
#include "View.h"
Controller::Controller(Model* iModel):mModel(iModel){}
Controller::~Controller(){}
void Controller::OnConvertToDecButtonClicked(View* iView) 
{
 QString wHexValue = iView->getHexValue();
 mModel->convertHexToDec(wHexValue);
}
void Controller::OnConvertToHexButtonClicked(View* iView) 
{
 QString wDecValue = iView->getDecValue();
 mModel->convertDecToHex(wDecValue);
}
void Controller::OnClearButtonClicked(View* iView) 
{
 mModel->clear();
}

main.cpp

#include "View.h"
#include "Model.h"
#include "Controller.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
 QApplication a(argc, argv);
 Model wModel;
 View wView;
 Controller wCtrl(&wModel);
 wView.setController(&wCtrl);
 wView.setModel(&wModel);
 wView.show();
 return a.exec();
}

I can post the Subject/Observer files later if they become relevant.

Asides from general comments, can someone please answer these questions:

  1. Would it be better to connect the buttons signals to the Controller slots directly (like in the portion commented out in View::setController)? The Controller needs to know which View called so it can use the proper information from the View doesn't it? This would mean either:

a) Reimplement a QSignalMapper or

b) Upgrade to Qt5 and VS2012 in order to connect directly with lambdas (C++11);

  1. What is optimal way to know what has changed when update is called by the Model ? Is it a switch/looping through all possibilities, a predefined map... ?

  2. Also, should I pass the necessary info through the update function, or let View check the required values the of Model once it gets notified ?

In the second case the View needs access the Model data...

  1. Should the View need to have a reference to the Model ? since it only acts with on controller? (View::setModel())

If not, how does it register itself as an observer to the Model ?

lang-cpp

AltStyle によって変換されたページ (->オリジナル) /