PDA

View Full Version : Simple Model-View and application structure?



serio
4th September 2010, 13:17
I've been reading a lot of docs but they don't seem to address some of the questions I have about the basic structure of GUI/Sql Qt apps. So here goes :)

* I have a MainWindow, with menubar with dozens of actions and UI with dozens of actions and widgets, do I have to connect all these signal/slots in MainWindow.cpp?
* Multiple widgets and actions acting on the same backend data have to use the same instance of QSqlTableModel? I.e. I have to maintain a list of all my tables in MainWindow.h, instantiate them during MainWindow constructor so they are ready for all possible actions? Which leads to...
* Do I need to attach all these models to my view widgets in MainWindow?
* Do I need to customize my widgets in MainWindow?

I know I don't have to do these things but I have not found a better way, e.g.

* I need to hide column of my QTableView, but since I used QtDesigner there is no constructor for me to do this in, so I end up doing it in MainWindow, likewise...
* I thought it would make more sense to attach a model to a view in the view's constructor, but a) there is no view constructor to edit using QtDesigner?, and b) this would create separate models instances, so other widgets/views using this model would not be updated? Unless I access it via qApp or something...

Lastly, can anyone recommend a good piece of simple open source Qt software that shows SQL integration, QtDesigner and views together? I have the feeling I should almost abandon QtDesigner and create all my widgets in code as subclasses so I can have a more modular application structure.

Thanks for anyone reading this far!

tbscope
4th September 2010, 15:56
I've been reading a lot of docs but they don't seem to address some of the questions I have about the basic structure of GUI/Sql Qt apps. So here goes :)

* I have a MainWindow, with menubar with dozens of actions and UI with dozens of actions and widgets, do I have to connect all these signal/slots in MainWindow.cpp?

Yes.
But if you use designer, you can let it generate slots and connections too.


* Multiple widgets and actions acting on the same backend data have to use the same instance of QSqlTableModel?
It depends on what you want to do.
If you only need one model, then yes, the actions required to perform an action on the model, work on the one and only model.
If you need to have more models, then you need to implement the slots in such a way that the actions are performed on the correct model.


I.e. I have to maintain a list of all my tables in MainWindow.h, instantiate them during MainWindow constructor so they are ready for all possible actions?
Always, and I want to repeat this: always have an object fully initialized in the constructor. You WILL pull your hear out when you use a function before a variable is initialized.


Which leads to...
* Do I need to attach all these models to my view widgets in MainWindow?
It depends what you want to do.
If you only have one view and two models (for example), set the view to show one model first and then use an action to switch to the next model.

A view without a model is like a car without an engine. It just sits there. It's not mandatory, but it's common sense to let at least every view have a model.


* Do I need to customize my widgets in MainWindow?
If you can't get to the results by using an event filter or signals and slots or other methods (other than subclassing), then yes, you might want to subclass.


* I need to hide column of my QTableView, but since I used QtDesigner there is no constructor for me to do this in, so I end up doing it in MainWindow, likewise...
I don't understand your question here. There are functions and methods in the table view to hide a column (I think). So use these in the constructor of your main window.
At some point you will need to write some code.


* I thought it would make more sense to attach a model to a view in the view's constructor
No, that makes no sense to me. Then you loose part of the flexibility of the design pattern.


, but a) there is no view constructor to edit using QtDesigner?
There's the main window constructor of course.


, and b) this would create separate models instances, so other widgets/views using this model would not be updated?
One model connected to two views: change an item in the model -> both views get updated at the same time.
That's the beauty of the model view design pattern. It was designed to do this.


Lastly, can anyone recommend a good piece of simple open source Qt software that shows SQL integration, QtDesigner and views together? I have the feeling I should almost abandon QtDesigner and create all my widgets in code as subclasses so I can have a more modular application structure.
I suggest using Qt Creator. Maybe there's a plugin that does what you want. Here's a list of plugins: http://developer.qt.nokia.com/wiki/Qt_Creator_Plug-in_Gallery

serio
5th September 2010, 02:31
Thanks, but it's still not clear for me.


But if you use designer, you can let it generate slots and connections too.

I know but many of the slots I have don't show in QtDesigner (i.e. Phonon VideoPlayer::play()) , so I'd rather put them all in one place - is the correct place MainWindow constructor? I thought it might be better to connect a widget's signals, or slots, when that widget is instantiated. I.e. in the widgets constructor tell it which slots to connect to. Which goes back to my question about where or if I can access the constructor of widgets added in QtDesigner.


Always, and I want to repeat this: always have an object fully initialized in the constructor. You WILL pull your hear out when you use a function before a variable is initialized.

My question is whether all models accessed from multiple views should be properties of MainWindow. I.e. MainWindow has 50 model objects associated with my 50 db tables.


A view without a model is like a car without an engine. It just sits there. It's not mandatory, but it's common sense to let at least every view have a model.

My question is whether MainWindow constructor is the correct place to attach views (with MainWindow as parent) and models.


If you can't get to the results by using an event filter or signals and slots or other methods (other than subclassing), then yes, you might want to subclass

My question is whether it's "standard" to subclass a widget (and then promote in in QtDesigner) to set a property in it's constructor, or whether again I set properties of these widgets in MainWindow constructor. I.e. I want to hide the first column in QTableView. This is not available in QtDesigner, so where is "usual" place to set this property? You say to set in MainWindow constrcutor - so my MainWindow constructor calls 100's of lines of code to set 100 different properties for all child widgets of MainWindow - is this standard?


There's the main window constructor of course.

This is my question, the view constructor is not the same as MainWindow constructor - I would think it makes more sense to set properties of widget in widget constructor so it is modular (i.e. hide column of QTableView in QTableView constructor), rather than using parent widgets constructor (MainWindow) to set properties of child widget.


One model connected to two views: change an item in the model -> both views get updated at the same time.
That's the beauty of the model view design pattern. It was designed to do this.

Yes, this is what I want - so that means both views should reference the same model attached to MainWindow as a property?


I suggest using Qt Creator. Maybe there's a plugin that does what you want.

Actually I mean an example project that uses clean, logical design with QtDesigner-created widgets and SQL backend. Maybe I should focus on looking through all the example projects and demos. The thing is they usually are small and don't deal with dozens of views and models.

In a nutshell, I want to know if this is the best practice for Qt GUI application:

mainwindow.h


...

class MainWindow : public QMainWindow
{
Q_OBJECT
...
private:
QSqlTableModel *m_user;
QSqlTableModel *m_group;
QSqlTableModel *m_activity;
QSqlTableModel *m_schedule;
QSqlTableModel *m_location;
QSqlTableModel *m_event;
QSqlTableModel *m_admin;
QSqlTableModel *m_venue;

... (etc, etc)
}


mainwindow.cpp


//MainWindow constructor
MainWindow::MainWindow()
{

//instantiate DB and attach all model properties to DB tables
create DBConnection();
attachModelsToDB();

//set all properties of child widgets
setupChildWidgets();

//connect all QAbstractItemView (sub)classes to models
connectViewsToModels();

//connect all signals and slots for all child widgets
connectSignalsAndSlots();

}

ChrisW67
5th September 2010, 07:35
My question is whether it's "standard" to subclass a widget (and then promote in in QtDesigner) to set a property in it's constructor, or whether again I set properties of these widgets in MainWindow constructor. I.e. I want to hide the first column in QTableView. This is not available in QtDesigner, so where is "usual" place to set this property? You say to set in MainWindow constrcutor - so my MainWindow constructor calls 100's of lines of code to set 100 different properties for all child widgets of MainWindow - is this standard?
Most properties of most widgets can be set at design time in Designer. Designer cannot help you hide a column in a QTableView simply because the number of columns in the table is not known at design time. If you use Designer to do some of the drudge coding for your UI it is not uncommon to provide a few tweaks in the class constructor after the setupUi() call and models are attached to views (i.e. all before the Ui is shown). In the case of views then it doesn't make much sense to hide columns before the view knows they exist.

If you think, as I do, that a single, monolithic UI with fifty underlying models is probably ripe for modularisation then Designer is not standing in your way. For example, break up the widgets in the UI into functional groups and use Designer to build a QWidget derivative for each group. Each smaller group will have a more targetted set of models/tweaks in the construction. Then use Designer to build progressively larger UIs with the components you have made.

You can, of course, code the lot by hand and break it up however.


My question is whether MainWindow constructor is the correct place to attach views (with MainWindow as parent) and models.
Often but not always (for views that are children of the MainWindow). Sometimes you will create a model and connect it to a view as the result of user activity. In this case a slot is usually the place this occurs.

This is my question, the view constructor is not the same as MainWindow constructor - I would think it makes more sense to set properties of widget in widget constructor so it is modular (i.e. hide column of QTableView in QTableView constructor), rather than using parent widgets constructor (MainWindow) to set properties of child widget.
You can do it this way if you like. Create your derived view class with its special-purpose constructor and configure away. Use the Promotion feature in Designer to have the YourView class treated like its parent class. With QTableView and the like bear in mind that you are trying to hide columns in a table view before it knows how many columns there are: that doesn't happen until a model is attached to the view.



One model connected to two views: change an item in the model -> both views get updated at the same time.
That's the beauty of the model view design pattern. It was designed to do this.
Yes, this is what I want - so that means both views should reference the same model attached to MainWindow as a property?
Reference the same model: yes. The model can exist anywhere. It can be a pointer to a model generated elsewhere (e.g. some factory class) and only connected to the view during construction of the UI.

serio
5th September 2010, 10:08
Great info, I think I've got that hang of it now. Thanks so much!!