4
\$\begingroup\$

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);

2) 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... ?

3) 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...

4) 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 ?

\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.