Model, View, Controller is a programming technique that separates the “logic” from the “user-interface”:
The Model encapsulates a logical building block (back-end) of the code and encapsulates the following information:
Properties: The state of the buiding block (object).
Methods: The operations that a building block can perform.
Events: Signals that are emitted to communicate asynchronously with the outside world.
The View is the user-interface (front-end) of the code that provides the user with an interactive application. It performs the following tasks:
Displays the contents of the model.
Responds to the user-input.
The Controller orchestrates the communication between the Model and View and ensures that they remain synchronized. The concept of the Controller satisfies applications that distinguish between a display (the View) and an instrumentation panel (the Controller), however this is overcomplicated for computer applications where the instrumentation panel is built into the user-interface (the View). In these situations the Controller is simply a delagate that is used to communicate information between the Model and the View.
The Observer and Publish/Subscribe design patterns are similar concepts that provide a more explicit definition of how the Model and View update each other even when they are defined in separate threads or processes. Thus, in order to communicate between the Model, View and Controller in a multi-threaded/multi-processing application, the Qt Framework provides a Signal/Slot mechanism to send/receive messages and data.
Qt Signals are interrupts (or events) that encapsulate the information that is transmitted between the Model, View, or Controller.
Qt Slots are callback methods that receive signals and provide an asynchronous response to an event that has occurred somewhere else.
Multi-threading is difficult to achieve using interpreted programming languages because the interpreter locks while executing each instruction. Although Python provides a multi-threading library, the Qt Framework multi-threading is preferable because it is implemented in C++.
There are several design patterns of multi-threading tailored to different problems based on the severity of the following requirements:
Parallel instruction execution.
Parallel data access.
During a long automated measurement process, multi-threading must:
Synchronize data between the model and view.
Enable interactive display of the measurement data.
Provide start/step/pause/stop runtime state.
A custom runtime measurement experience can be implemented by inheriting the following classes:
RuntimeModel
(Model).
RuntimeView
(A Global Enum).
The multi-threaded runtime environment is controlled by the following classes:
RuntimeThread
(Controller).
RuntimeState
(A Global Enum).
Hence, this implementaion is a simplification of the theoretical MVC design pattern and is suited towards measurement applications.
Three incremental solutions are available for measurement automation:
Sequencer.
Scripting.
Application.
The MVC programming design pattern enables code re-use and refinement to move between these three solutions by separating the model (the logic) from the view (the user interface). Each solution has different limitations on customization as summarized below:
Solution Type | View | Controller | Model |
---|---|---|---|
Sequencer | Default RuntimeView | RuntimeThread | RuntimeModel Sequencer Actions |
Sequencer | Jupyter Notebook | None/td> | Custom RuntimeModel |
Application | Custom RuntimeView | RuntimeThread | Custom RuntimeModel |
The Sequencer searches through installed modules and will expose any public method of a class that inherits from
RuntimeModel
as a Sequencer Action.