General question regarding the idea for JUCE MODEL classes


#1

Looking at the two cases of MODEL objects in Juce that I am using - those for listboxes and menubars, as someone not fully read-up on MVC theory ( even though i have the Design Patterns Book ) I am a little puzzled since my understanding was that the MODEL was meant to seperate out the DATA and
"busiess logic" from the actual GUI elements presenting it.

Yet in both the listbox and menubar model objects the two become mixed. The listbox model ends up optionally doing some drawing directly on the graphics object ! and in menu bars the model is the one which creates and dishes out PopupMenu references/instances.

Could you possibly explain the thinking behind this ?


#2

Well, I’ve always found the full MVC paradigm a bit cumbersome really… My thinking for ListBoxes and Tables was just to make something that allows you to throw together working classes with a minimum of boilerplate, since that’s what seems to be most important in almost all the places where I use these things myself. If you do need to split the drawing code from the data model, that’s trivial to do by just using custom row components or writing your own “controller” class to do the rendering, but I have to admit that I’ve never needed to go that far in any of my own apps.


#3

thanks. that clears things up. But maybe worth replacing the word “model” with something else in a future rejig ? just to clarify this ?

I have to say - i think it might be worthwhile revisiting your listbox classes. it became quite cumbersome for me just to add some relatively trivial functionality - i had to
branch off the main juce base classes just to do this, whereas i think a few more virtual methods etc could have saved me a lot of time, and allowed me to keep on the main branch.

ive mentioned this in previous posts.

othwerise keep up the fine work !


#4

Can you explain what functionality you’re missing? Is it just being able to draw rows beyond the number of rows the model reports? If so, that could be added simply by just adding a bool to ListBoxModel such as enableUnboundedRowDrawing. This would enable calls to paintListBoxItem for rows beyond getNumRows. This would have to be disabled by default however, as lots of existing code may not be robust enough to handle the extra rows. Although I think someone else did mention you could fake this by using ListBox::getRowPosition and filling in the empty space yourself.

I can’t see any reason for needing custom row Components beyond numRows though, surely if you need some interactivity you would just create some rows and not fill them in? There is already a callback to intercept mouse clicks on the background, ListBoxModel::backgroundClicked which you could use to create a pop-up menu etc.

Personally I’ve always seen the ListBoxModel class as the Controller part of the MVC paradigm with whatever your internal data is as the actual Model (e.g. some StringArray as a really simple example). The ListBox component is then obviously the View in that it has no direct connection to the underlying data. I do agree this isn’t a complete MVC structure as you only have one way communication between the Controller and the View. In the past I’ve overcome this by just making my ListBoxModels ChangeBroadcasters which then force the current connected ListBox to call updateContent() and repaint() if the content changes.

I would say that Jules is right in as far as making the classes really lightweight and usable though. If you need to display something in a list all you really need to do is override getNumRows and paintListBoxItem. If you’ve got any patches to extend the classes though please share, I’m sure they would be useful.


#5

The “Model” part of MVC refers to your business model as a whole. i.e. The logical entities that make up what your program represents and the relationships between them. For example, if you had a music library application like iTunes or something, your model objects might be “Library”, “Album”, “Playlist”, “Track”…etc. These classes are very basic in nature and should only contain the fields required to describe the entity that it represents. As with most things sometimes exceptions are made and you provide a helper method or two, but the goal should be to keep model objects isolated from anything outside of that. Even business logic should be kept to a minimum within them. In MVC the classes that make up the model are often referred to as model objects, but they can also be described as data objects or data structures.

That said, the terminology used with a certain design pattern is indeed by nature fairly generic and so it is unlikely to find a term that is exclusive to only one pattern. So Jules’ usage of “model” is appropriate for the intention of the classes but using it doesn’t imply that they are part of an MVC pattern. The only real implication of using the “model” term is that the code is intended to represent something in a common way, whether it be through attributes or behaviour or whatever aspect one is intending to represent. Of course it can always be up for debate as to which term best describes the intended purpose but the idea is to just look at the term by it’s general definition, then look at the context in which it is used. Sometimes the context will be a classic design pattern such as MVC, and sometimes it’s just used to help describe an aspect of a simple design concept.


#6

[quote=“dave96”]Can you explain what functionality you’re missing? Is it just being able to draw rows beyond the number of rows the model reports? If so, that could be added simply by just adding a bool to ListBoxModel such as enableUnboundedRowDrawing. This would enable calls to paintListBoxItem for rows beyond getNumRows. This would have to be disabled by default however, as lots of existing code may not be robust enough to handle the extra rows. Although I think someone else did mention you could fake this by using ListBox::getRowPosition and filling in the empty space yourself.

I would say that Jules is right in as far as making the classes really lightweight and usable though. If you need to display something in a list all you really need to do is override getNumRows and paintListBoxItem. If you’ve got any patches to extend the classes though please share, I’m sure they would be useful.[/quote]

enableUnboundedRowDrawing woud go some way to solving this, from my vague recollections. There was an issue that even with custom derived row classes etc one simply didnt receive callbacks for rows in the “empty space”.


#7

Sorry to bump this old dead thread, but I may have something useful to contribute.

While there is nothing specifically in JUCE to help you implement a model/view/controller paradigm, there is nothing in there that prevents you from doing it either. In particular, I have found it helpful to implement an MVC system with JUCE for the following reasons.

First, on my project, the interactions between each of the controls are subtle. Changing one control somewhere can have an effect on superficially unrelated controls in other windows. Having a central model and one controller simplifies this complexity greatly.

Second, there is a great deal of state in my application. It is difficult to serialize the entire state of a JUCE application to a single file and load it again easily. Ideally, there would be a function that would walk the entire hierarchy and record the state of each control, so that JUCE applications could save their state at exit time and restore it when the application is relaunched. Without an MVC system, this is hard to implement; with an MVC system, it’s trivial.

Now since JUCE itself is pretty much a system of Views, it’s not necessary to create a separate View abstraction. But I created a Model class and a Controller class. The Model is responsible for containing all state for my app. It also contains all necessary mutexes as well as ChangeBroadcasters for each of the fields that might affect a change to any JUCE control, but it doesn’t implement any actions except for simple accessors and locking functions. The Controller class is the only class that is friend (in a C++ sense) to the Model, and has access to its internals. All operations on the Model state must go through the Controller. Thus all commands and other effects must be implemented as Controller methods.

Implementing MVC is much simplified if you introduce a bunch of ChangeBroadcasters into your Model class for every field that any JUCE widget needs to be notified about a change. For each relevant field in the Model, you create a corresponding ChangeBroadcaster. Then, you make each interested display widget a ChangeListener that wants to be notified about updates to the Model. Then all of those widgets know exactly the right time to repaint themselves.

I only permit changes to the Model class to occur through the Controller. This reduces locking contention from my highly multithreaded app.

If I had understood JUCE’s hierarchy a little better, I would have made all the Controller’s effects be UndoableActions, which would have let me create an Undo command for my app. Ah the benefits of hindsight…

Hope these breadcrumbs help other people in similar situations.


#8

Concerning MVC: did you consider using a MVC framework, like PureMVC? A couple of years ago, I had some very good experiences with it, in another language then. I’m new to JUCE, but I also have the impression that using MVC would be nice to work with. On the other hand, JUCE is called an application framework - but I don’t see much of that, yet.