Search code examples
c++model-view-controllerstructure

Should all buttons contain a reference to the controller in MVC code (C++)?


I'm trying to figure out the best (cleanest) way to structure some code in C++ for an application I'm building. I think MVC makes sense as the way to go, but after a fair amount of research I'm not totally clear I'm doing things the right way.

Here's an example to illustrate my question:

Model

I have a class which contains drawing data called Canvas. An example function, used to clear the current contents of the canvas, is ClearCanvas().

Ultimately, I want a button in the interface to be able to call this function and clear the canvas.

Controller

I have a controller class for the canvas: CanvasController

The controller creates and then holds a reference to a canvas object: CurrentCanvas

The controller also creates the view: CanvasView and then sets a reference to itself on the view: CurrentCanvasView->SetControllerRef(this);

View

The view is made up of a series of nested classes that define the UI. For example, the hierarchy leading to the button in question might be something like this:

CanvasView
-VerticalBox
--HorizontalBox
---Button

During the view's constructor, a reference to the controller is passed from the view to all interactive elements, eg. NewButton->SetControllerRef(this->GetControllerRef());

Button Pressed

So now when the button is pressed, it can function like this:

void ClearCanvasButton::OnButtonPressed()
{
    Controller->CurrentCanvas->ClearCanvas();
}

So my general question is: (1) does this seem like the right way to be doing things, or badly structured?

Also (2): Should the controller be encapsulating the canvas functions, for example:

void CanvasController::ClearCanvas()
{
    CurrentCanvas->ClearCanvas();
}

Such that the function on the button could simply be:

void ClearCanvasButton::OnButtonPressed()
{
    Controller->ClearCanvas();
}

I'm just not sure whether it's correct to essentially be passing down a reference to the controller to all elements of the view which ultimately want to change the model, or whether there is a cleaner way.

Apologies if the question has been asked a thousand times in a thousand different ways, I have been searching around trying to understand this.


Solution

  • You don't need a class ClearCanvasButton, if your Button class contains a member like

    std::function<void()> onButtonPressed;
    

    or similar, rather than

    virtual void onButtonPressed() {};
    

    You then pass a lambda that references the controller

    CanvasView::CanvasView()
    {
        // make the widgets
        Button.onButtonPressed = [Controller](){ Controller->ClearCanvas(); };
    }