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