Aug 15 2007
From the wikipedia:
Model-view-controller (MVC) is an architectural pattern used in software engineering. In complex computer applications that present a large amount of data to the user, a developer often wishes to separate data (model) and user interface (view) concerns, so that changes to the user interface will not affect data handling, and that the data can be reorganized without changing the user interface.
MVC is not only useful for web frameworks and applications, here is a simple example of the implementation of the MVC pattern for a Qt GUI application.
For this example the business data (Model) will consist of just a counter. The GUI (View) will have elements to increase and decrease this counter. Since this is a very small proof-of-concept application there is no need for a Controller component. You can have a look at the code before we start.
First the Model class:-
<br /> class Model < Qt::Object<br /> slots 'increase()', 'decrease()'<br /> signals 'modified()'</p> <p> attr :counter</p> <p> def initialize<br /> super<br /> @counter = 0<br /> end</p> <p> def increase<br /> @counter += 1<br /> emit modified()<br /> end</p> <p> def decrease<br /> @counter -= 1<br /> emit modified()<br /> end<br /> end<br />
The Model extends
Qt::Object so we can inherit the signals / slots functionality. Signals and slots will be the mechanisms used by our components to talk to each other. The class defines two slots:
decrease(). If an external component wants to modify the data kept by the Model, the component will send a signal to one of these slots. In the same way, one the value of the counter is modified, the Model will emit the
The View class contains only two methods: the constructor and one slot. In the constructor we create the widgets of the interface and then connect the different signals and slots (more on this later). A single slot is defined in the class:
counter_modified(). This slot will receive the signal sent by the Model each time the underlaying data is modified. Here is the code:-
<br /> class View < Qt::Widget<br /> slots 'counter_modified()'</p> <p> def initialize(model)<br /> super(nil)</p> <p> # keep a reference to the model<br /> @model = model</p> <p> # define widgets and layout<br /> grid = Qt::GridLayout.new<br /> @btn1 = Qt::PushButton.new('+1')<br /> @btn2 = Qt::PushButton.new('-1')<br /> @lcd = Qt::LCDNumber.new<br /> grid.addWidget(@btn1)<br /> grid.addWidget(@btn2)<br /> grid.addWidget(@lcd)<br /> self.setLayout(grid)</p> <p> # connect signals and slots between the Model and the View<br /> connect @btn1, SIGNAL('clicked()'), @model, SLOT('increase()')<br /> connect @btn2, SIGNAL('clicked()'), @model, SLOT('decrease()')<br /> connect @model, SIGNAL('modified()'), self, SLOT('counter_modified()')<br /> end</p> <p> def counter_modified<br /> @lcd.display(@model.counter)<br /> end<br /> end<br />
As mentioned earlier we are not using a Controller component for this example. However, the controller behaviour still exist but is included in the View class.
The Model has two slots and is able to emit a signal. We only need to bind this messages with the corresponding widgets in the user interface. The lines below connect the
clicked() of the buttons with the different slots of the Model. Likewise, the
modified() signal of the Model is connected to the
counter_modified() slot of the View.
<br /> connect @btn1, SIGNAL('clicked()'), @model, SLOT('increase()')<br /> connect @btn2, SIGNAL('clicked()'), @model, SLOT('decrease()')<br /> connect @model, SIGNAL('modified()'), self, SLOT('counter_modified()')<br />
When the Model emits the
modified() signal, the View will update the value displayed in the Qt::LCDNumber widget.
More complex data models may require more complex patterns, but that is another story and shall be told another time.
Popularity: 13% [?]