I created one dialog that is used only to bindValues in a SQL database,
and I can save every new record sucessfully. The problem is that I've got another dialog with QSQlTableModel that only shows the information from the database. Every time I make a new record I must close the program and run it again to see the changes in the ShowInformationDialog().
Do you know some way such that I don't need to close the program to update the information in my ShowInformationDialog()?
You can use select() method of QSqlTableModel class to repopulate the model with data from the database. Bound views get updated automatically. I suggest connecting a signal from wherever you update the data in the database (i.e. your dialog updating the SQL database) to custom slot in your ShowInformationDialog() that calls the select() of the QSqlTableModel object. I assume you have a QMainWindow object that is parent of both dialogues which would be most likely the best place to establish the connection.
Also since your ShowInformationDialog()'s model is only used for viewing the data consider using QSqlQueryModel. If that is used then setQuery() method should be used instead of select() but otherwise (the connection of a signal to ShowInformationDialog()'s slot) it would be the same.
Related
I'm trying to implement an application in Qt with a model-view-controller scheme. I have some model classes (databases), one application controller, and a bunch of GUI classes. All GUI classes know the app controller and can call its public slots to send data to it that should be stored in the model. The app controller takes the data and calls the appropriate database to store it. The database classes check the data and return a bool to the app controller to tell if the data was okay or not.
Now, one GUI element has prepared some user data and wants to send it to the app controller. I am trying to figure out how to let the GUI-class know that the app controller validated the incoming data with the model and it accepted the data. My app controller shouldn't care nor know which GUI elements call its public API to commit data to the model. But how does the app controller communicate a response to the GUI element to tell it, that everything was fine, so the GUI element can close itself?
My idea would have been to let the GUI element create a random number token to send it to the app controller together with the data as a kind of "callback address". As soon as my GUI element receives an okay signal with the correct token attached, it can react to that.
I was dunno. All my solutions feel weird and not how it's supposed to be in Qt.
Edit 1: a pseudo-code example for clarification:
void Appcontroller::Slot(userdata)
{
bool okay = database->save(userdata)
};
void Appcontroller::CreateMasterWindow()
{
this->masterwindow_ = new MasterWindow(this);
// I am propagating the knowledge of the app controller to the
// MasterWindow and the latter can propagate that info further
// down, that's fine (everybody can know the responsible
// controller, but I don't think the controller should care about
// all his bastard children)
};
void MasterWindow::CreateSubWindow()
{
this->subwindow_ = new SubWindow(appcontroller_);
// the masterwindow creates a random subwindow that the controller
// should't have to care about
};
void SubWindow::SendUserData(userdata)
{
QObject::connect(this, &SubWindow::SendToControllerSignal,
appcontroller_, &Appcontroller::Slot);
emit SendToControllerSignal(userdata);
// how to get a callback (targeted to me/this) from this,
// if the appcontroller does not know me? what is de way?
};
TL;DR: Connections should be made outside of the components. To compose the parts of your system, you instantiate the objects, and then connect them for desired functionality. The objects should otherwise have no knowledge of each other.
Thus, the only means of communication between the objects are signals and slots.
All GUI classes know the app controller and can call its public slots to send data to it that should be stored in the model
Nope.
The GUI classes should know nothing. When a GUI class needs something, it emits a signal. When a GUI class is supposed act on something (e.g. a change in the model), it exposes that as a slot.
I am propagating the knowledge of the app controller to the MasterWindow
Why? The MasterWindow exposes its functionality via signals and slots. Composing it into a bigger system is accomplished by signal/slot connections. No other knowledge is needed.
The app controller takes the data and calls the appropriate database to store it.
Does there even need to be a controller? All it seems to do is act like a signal-slot connection. You can directly connect the GUI classes to the database, and the controller could be what sets the connections up initially.
Otherwise, the application controller can act as a viewmodel, i.e. a QAbstractItemModel that adapts the model exposed by the database, and tweaks it for display/interaction (e.g. adds color properties, icons, etc.).
The database classes check the data and return a bool to the app controller to tell if the data was okay or not.
The database classes should expose slots that are used to modify the database state. They should also expose signals that indicate any changes. To indicate failure, the database can indicate a "change" with the same value.
how to get a callback (targeted to me/this) from this, if the appcontroller does not know me? what is de way?
The signals from the model/database are connected to the GUI classes. A GUI class can go into a "change pending" state once it emits a "change requested" signal. It will then react accordingly when its "new value" slot is called with the updated value: if the value didn't change, it indicates a failure, otherwise it indicates success. If it didn't request a change, it simply updates the displayed value - something else changed it.
This can be all done using nothing more than the Q_PROPERTY mechanism, and the change notification signals.
If the values aren't simple discretes, but rather have some structure, expose those as indices in a custom QAbstractItemModel. Each GUI item can then act on one or more model indices: requesting the changes, and reacting to value updates.
Multiple GUI elements can be hooked up to the same database variable (or no GUI elements!), and the GUI must support this and update its state to reflect the state of the model.
The "tickets" or "request identifiers" you propose are mostly spurious. The requesting GUI element has enough state to know that it requested a change, and can always act predictably on subsequent feedback from the model/database.
I am building an application using Qt/QML. The QML of my main window is very complex and depends on lots of data which must be loaded via HTTP and then be processed by a C++ backend before it is ready to be displayed.
The C++ backend provides a signal which is fired when the data is ready. Until then, I want the window to be empty except for a simple loading indicator being displayed. Of course, I could use a simple overlay which hides my actual interface until the data is available, but this would mean that the QML code of my actual user interface is already loaded and tries to access the not-yet-available data, which is causing a lot of errors, so I would need to add dozens of dummy values and NOTIFY signals for each single property which might not yet be available.
What is the best way to completely deactivate a portion of QML code and to enable it as soon as a signal is triggered?
My personal experience is to not give data to your view components, don't bind them. For example, set your text value to an empty string or don't set it, set your image component source to an empty string or don't set it at first. When your signal comes in with data ready, you assign the data to the views at that time.
I have some newbie question. I'm not sure if I understand Model-View-Controller design pattern correctly.
Maybe I will start from describing my problem. I'm reading some data from file. This can take let's say 10 seconds and after that I present those data in the table. The question is how should I store those data? Besides QStandardItemModel should I have another container to which I will read data from file and use it in other threads? For example, I have QStandardItemModel in Gui thread and I create another container let's say QVector. I load data from file to QVector and then I move data from QVector to QStandardItemModel?
I can't use QStandardItemModel in other thread and read data directly from file to QStandardItemModel because GUI freeze as I know because QStandardItemModel emits signal to update view after appendRow.
Or maybe I should create custom model and add method to update view only when whole file is loaded into QStandardItemModel? QTableView has own container for data and it's not synchronized with the model? Is it possible/correct way?
What with situation when I read a new file?
Thanks for any help.
I think you can do such steps for resolve your problem:
When you need to load new data from file, set model for your QTableView in nullptr.
Fill QStandardItemModel (this model was the model for your QTableView) in non-main (non-GUI) thread with data from file.
Set model with data for your QTableView in main (GUI) thread.
Of course, the simplest way to solve your problem also may be to show for user something like this: "Data loading, please wait...", while you load data in QStandardItemModel in main (GUI) thread.
I wrote a QAbstractItemModel based class and implemented data(const QModelIndex & ar_index, int a_role) const function. I refresh the model using:
beginInsertRows(QModelIndex(), 0, 0);
// fill model
endInsertRows();
Inside data function I update some information X needed after refreshing.
I checked that data functions are invoked after refreshing the model and debugging I verified that my X variable is properly setted.
After refreshing, I need to fill another widget with this X value. How do I know that all data refresh was finished and correctly show Xvalue? Which signal is emmited after completelly refreshing the model?
There is no standard signal to use here -- the Qt's MVC API is designed to support not only static models, but also the dynamic ones, and for these, there cannot ever be a signal telling "all done". For example, in Trojita, a Qt IMAP e-mail client, rowsInserted is emitted to indicate that a new e-mail has arrived, but this happens even before the library knows anything about the new arrivals -- not even their UIDs. Only after the remote server has responded to the library's commands with data, the dataChanged is emitted to indicate that the "data represented by the model" has changed and that the attached views shall update.
You said you're reimplementing your own QAIM from scratch. This means that you can set any contracts you see fit here. Are some of the data immutable, i.e. guaranteed to never change after they have been loaded? If so, you can use a custom role like RoleIsItemFetched and after each change to the model (that is, after modelReset, rowsInserted, rowsMoved and dataChanged) check whether your data(someIndex, RoleIsItemFetched).toBool() function returns true. If so, you have your data, if not, you have to keep waiting.
An alternative to that might be to introduce your own signal. Don't be afraid of that, the MVC API is great for presenting data to users, but if you think you need more control over what is returned and have full control over the model and the "views", go ahead and make the code do what you need.
Previously, I asked about running model and view in different threads and now, I understand how it poses a problem. To circumvent the problem, I was thinking of duplication of data. When data is modified by the worker thread, it simultaneously sends an update to GUI/Model thread to update the model with the same data (so there exist a exact copy of data with the GUI/model).
Does this sound like a plausible approach? Other method is to use direct widgets with default models like QTableWidget etc. but then I need to do a lot of things that are powered by QTableView by default.
Please suggest!
Link to other question: Design Pattern, Qt Model/View and multiple threads
There are 2 scenarios that are possible but in either case you will need at least 2 objects as follows:
Data Object
Contains all functions required for maintaining and manipulating data. Data is stored in Pointers to objects describing data. Data Structures for this I will leave up to you.
Model
Contains a vector of pointers to data that is currently being displayed
Scenario 1
Data in QTableView is display only in which case on a QTimer signal or a different signal the data storage is locked and vector for display model is cut and put into the model and reset() is called to have QTableView repainted with new data.
Scenario 2
You can manipulate data via custom ItemEditor in QTableView. In this case the top widget that has QTableView should have references to your data object and QTableView and a signal handler for the signal emitted by the ItemEditor when the edit is complete. This signal handler will then lock the data structure inside data object and update it, once done it may cut a new vector to display but more often then not it won't have to.
How you will set up the locking, searching, etc is entirely up to you.