From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Example Code

Model View Controller in LVOOP

Code and Documents

Attachment

Overview
The example builds showing how MVC can be as simple as an Event Based Queued State Machine through to using the Command Pattern to allow for extensibility and then on to using the Factory Pattern to use plug ins to extend it even further. 


Description
The example builds showing how MVC can be as simple as an Event Based Queued State Machine through to using the Command Pattern to allow for extensibility and then on to using the Factory Pattern to use plug ins to extend it even further. The first VI to run and examine is the MVC Starter. This breaks the code into two. The top loop is the View and the bottom one the Controller. The Model is the data in the two shift registers on the bottom loop containing the frequency and waveform data. One point to note is the user event to put data into the View and then onto the Waveform Display where this would normally go in the controller. This split is important in making this MVC. The next VI, MVC OOP, does exactly the same job but now encapsulates the frequency and waveform data into a class, with read and write methods to get data out of and put data into the class. The next VI, MVC OOP Advanced, extends the functionality of this by adding the option to change the type of waveform used. Whilst normally this would change the original class it does not in this project so that both may exist in parallel in the project. All of the examples to this point are using the cluster of enum and variant to pass command and data from the View to the Controller. The next example, MVC OOP Advanced with Commands, changes this to use classes to send the message between the loops. There is a parent class ‘Message.lvclass’ which is used to create the queue and has an execute method that can be overridden to provide functionality. This is uses dynamic dispatch to carry out the actions previously done in the state machine. Each previous action now a method of a class, which is a child of ‘Message.lvclass’, and carries out it's Execute method to run the action.

The final part of the example is MVC OOP Advanced with Commands and Factory which extends the previous example to use the Factory Pattern to allow the user to create plug ins to create their own waveforms, load them in from disk etc. On initialization it scans a directory for .lvclass files in a directory and then loads the class in from disk to carry out the generation task. The Dynamic Dispatch VI shows the concept by pouring beer. Dependent on the type of beer that is requested, the pour method is altered to suit the type of beer. 

 


Requirements

  • LabVIEW 2012 (or compatible)


Steps to Implement or Execute Code

  1. Unzip the attached folder to your computer
  2. Open the project "MVC Example.lvproj"
  3. Open and  Run the different VI as you wish

 

Additional Information or References
VI Block Diagram of "MVC Starter.vi" (Check other VIs in project)

 Block Diagram.png


 **This document has been updated to meet the current required format for the NI Code Exchange.**

 

Example code from the Example Code Exchange in the NI Community is licensed with the MIT license.

Comments
Thoric
Trusted Enthusiast Trusted Enthusiast
Trusted Enthusiast
on

The document, and the attached LV Project, is also an excellent tutorial into the benefits of OOP. It provides a non-OOP solution (MVC Starter), then progressively introduces OOP elements and highlights the benefits achieved.

Thoric (CLA, CLED, CTD and LabVIEW Champion)


cirrusio
Active Participant
Active Participant
on

Great job, Mike!  This gives a good starting point for understanding MVCs.

Patur
Member
Member
on

Really nice to see how you can go from a queue based design to OOP

Although I'm sad to say that I don't have the "NI Vision Development Module" required to see the beer VI

You might want to initialize the Frequency dial to 0 at startup, to avoid flatline on 2nd run when the dial is left at >0.

Thanks for this example

--
Patur Sivertsen Vase
www.hfjensen.dk
Steve_Hudson
Member
Member
on

Suppose I want to add a plugin to generate a different function. What is the best way to either copy a given class, create a child of one the other functions, or create a child of the generate class, without it being part of the project? That is to make it like the square wave generator, which is loaded from the directory.

Sorry for the very basic question about working with classes and project folders.

Thanks for your help.

**  I think that I have it. It was necessary to create an new empty project for the plugins, so that I could then add the first plugin. Then I could create a new class or GOOP clone an existing one.

Mr_Steve
Member
Member
on

Mike,

This is great stuff. I only have a couple improvements that you can make with your event programing.  It's easier and more reliable to use the value change event for your boolean button presses.  This way, if a use clicks somewhere else but release on a button, that buttons event isn't triggered, or if a user clicks down, but wants to cancle, they can click else where and no event will be trigged either.  Only when the user clicks and releases the button triggering a value change will the actual event trigger. You also do not need the method node to reset to defaul either since your boolean buttons are set as a latch type; they'll reset to default once the value has been read from them. Lastly, is to move each of the boolean control terminals to their corresponding value change events. This will allow you to quickly find the corresponding event when double clicking the FP control.

adqwq
Member
Member
on

This is invaluable to understand webcast 2843. It should be included as a link to download for that webcast.

I was trying for a week to understand command pattern, and that presentation along with reviewing this code has helped me to grasp it and use it.

It was a an "AHAAAA" moment.

Thank you

Not applicable
on

Sorry about my OOO msg... deleting it

Oli_Wachno
Active Participant Active Participant
Active Participant
on

Thanks for this excellent example!

LVOOP rules whatever some may say or think in a very rude and inappropriate manner.

Jpina
Member Member
Member
on

Perhaps you could collaborate by posting your example instead of criticizing other people's effort with those manners...

Alessandro__ wrote:


                       

...


                   
Padugur
Member
Member
on

this is very good arcticle and thanks for opening up the thought process .I would like to know when you are nor distroying the event register.is there any reason or you just left like that .

MikeeB
Member
Member
on

As I wrote this four and a half years ago, I can't quite remember why, it was probably just an oversight on my part. I just forgot. There are several things that I would probably do differently now, but this was the piece of code that, at the time, helped me to understand OOP and the Command Pattern. From the feedback and the number of downloads it seems to be helping other people at that stage of their learning process too.

Mohamedbakr2
Member
Member
on

Thanks MikeeB for the tutorial, It would be great to have more documentation about the design.

bharathp10
Member
Member
on

Thank you MikeeB ..very helpful..

bp
ramktamu
Member Member
Member
on

This is very helpful document.

157+ CLDs & 9 CLA Trained
LabVIEW Training resources
jfalesi
Member
Member
on

Great example but I'm confused about one thing - by using a user event to trigger display updates, aren't the view and controller combined? That is, by having the same loop/event handler that handles user input ALSO handle updating the display, it seems to me that view and controller aren't really separated. Am I missing something?

jfalesi
Member
Member
on

Also wondering why the GenTriangle.Execute method is the same as GenTriangle.Generate (similarly for Gen Sine)Screenshot 2021-12-08 123309.jpgScreenshot 2021-12-08 123345.jpg