Hi I have a QListView widget displayed correctly on my user interface.
I am registering a callback to a completely separate 3rd party library. This callback will be called on a completely separate thread to my user interface. I need this callback to interact with the QListView widget and set a new data model, so I believe I have to use
MyDataModel * model = new MyDataModel( ui->listViewWidget );
QMetaObject::invokeMethod( ui->listViewWidget, "setModel", Q_ARG( MyDataModel *, model ) );
However, It doesn't seem to work. i.e. no data is presented in the QListView widget. I've debugged the return value from QMetaObject::invokeMethod and it's returning false which suggests there's no method called "setModel" on the QListView. However, when I arrange for the callback to be called via the user interface thread, i.e. through a pushbutton on_clicked() event and make a call to
MyDataModel * model = new MyDataModel( ui->listViewWidget );
ui->listViewWidget->setModel( model );
This works perfectly, so there is a "setModel" method on the QListView..
Can someone please help me understand why QMetaObject::invokeMethod isn't working and maybe clear up wether I need to call invokeMethod in this way. i.e. are my thread assumptions correct about it needing to be ran on the event loop thread.
Yours, dazed and confused..
Mark.
The method QMetaObject::invokeMethod invokes only slot or signal on the object. Therefore your setModel must declared as slot. Also Q_ARG() takes a type name and a const reference of that type.
Related
A QWidget Class is a parent of multiple QWidget siblings which overlap. When implementing the mousePressEvent just the most recent constructed child is recieving the event.
Is there a way that all siblings get the event?
Or even better a way to set which child is expected to be recieving it?
p.s. I'm assuming this is clear enough without providing sourcecode, especially since the minimal example would be quiet big anyway. If some one expects the code to be required anyway, leave a comment and I'll add it.
You might want to use QEvent::ignore() function to mark an event as ignored in the widget. Doing so you will propagate it to the parent widget. According to Qt docs on QEvent::ignore() function:
Clears the accept flag parameter of the event object, the equivalent
of calling setAccepted(false). Clearing the accept parameter indicates
that the event receiver does not want the event. Unwanted events might
be propagated to the parent widget.
You should generate new event in callback method of each sibling class.
void QWidgetChild::mousePressEvent(QMouseEvent *event)
{
// Act
// Pass to parent
QWidget::mousePressEvent(event);
// Generate new event for objects of sibling classes
// How?
}
See postEvent documentation.
I'm stuck at a learning project.
I've subclassed QObject, and set up a signal to work with a QAbstractItemModel derived object.
I see like I "received" the object passed in the signal from the GUI thread, and qDebug-ing it shows it holds the same address, however, when I try to modify the data in it through setData in the separated thread, the program crashes.
What can I do to "modify" this QTableView model from another thread?
Or should I create a new model in the thread and pass it back to GUI thread? (is this possible, if yes, how so?)
I've problem with qt signal-slot system.
First I've created a class which is called System in Singleton pattern, so I can access it's instance where I want. System has a signal SelectionChanged.
I've a list widget and I am connecting it's itemSelectionChanged signal to my custom slot which is called onSelectionChanged. In onSelectionChanged slot, I am emitting System's SelectionChanged signal. There is no problem yet.
In my software design, a selection of object(s) can be used by many GUI widgets or custom classes and System's SelectionChanged signal can be emited by widgets other then the list widget.
So I am creating a slot called OnSystemSelectionChanged in the list widget then connect it to the System's SelectionChanged signal. The OnSystemSelectionChangedSlot is like this.
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this) return;
// Then I want to get a list of selected objects and set them as selection of this widget like this:
this->SetSelection(System::Instance()->GetSelectedObjects());
}
But the problem is when I start to set the list widget's selected items, it is going to emit itemSelectionChanged signal and my onSelectionChanged slot will be called. Then the slot will emit System's SelectionChanged signal and then OnSystemSelectionChanged will be called too. It will stop through sender parameter but there is no method for setting list widget's selected items at once.
How can I figure this problem out.
I hope I did explain my problem well. Thanks in advance.
Edit: Spelling and grammer errors are corrected.
There are a few ways of dealing with this in Qt.
Idioms
Use multiple views with one underlying model. This handles propagation of changes to multiple view controls automatically and you don't need to do anything extra. You can use QDataWidgetMapper to link "plain old" widgets to the data elements in a model. I'd say that this should be the preferred way of doing things. Having an underlying model for all of your UI is a step in the direction of good software design anyway.
When propagating changes between data models, implement both a DisplayRole and an EditRole. The views will nominally modify the models using one of the roles (say, the EditRole), while you can, programmatically, modify the models using the other role (say, the DisplayRole). You handle the dataChanged signals from the model in your own slot, properly dealing with the roles, and call setData on the other models with the other role. This prevents the loops.
For controls that are not QAbstractItemViews, implement two signals: one emitted on any change, another one emitted only on changes based on keyboard/mouse input. This is the interface exposed by QAbstractButton, for example: the toggled(bool) signal is the former, the clicked() is the latter. You then only connect to the input-based signals.
Your own code must propagate programmatic changes to all the interlinked controls, since changing one control from your code won't modify the others. This should not be a problem, since well designed code should encapsulate the implementation details of UI controls from rest of the code. Your dialog/window class will thus expose its properties in a way that's not coupled to the number of controls showing a particular property.
Hackish Let's-Hope-They-Won't-Become Idioms
Use a flag inhibiting signal emission (Bartosz's answer).
Break the signal/slot connections for the duration of the change (Bartosz's answer).
Use QObject::blockSignals().
There are two possible solutions I can think of:
add a flag which makes possible to ignore particular signals:
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this || inhibitSelectionChanged)
return;
this->inhibitSelectionChanged = true;
this->SetSelection(System::Instance()->GetSelectedObjects());
this->inhibitSelectionChanged = false;
}
disconnect the slot from the signal, and reconnect it after changing the selection:
void MyListWidget::OnSystemSelectionChanged(QObject *sender)
{
if (sender == this)
return;
this->disconnect(SIGNAL(SelectionChanged()));
this->SetSelection(System::Instance()->GetSelectedObjects());
this->connect(
this, SIGNAL(SelectionChanged()),
this, SLOT(OnSystemSelectionChanged(QObject*)));
}
I found my solution in QObject::blockSignals() method. It will prevent emitting signals from the list widget while I am setting selected items.
Thanks for all the answers and solutions especialy for BartoszKP's. This solution is looks like the official way of his first solution.
The problem: you've tried to cut corners and created a singleton. Not a classic case for singleton.
Signals and slots are used for notifications, each object notifies interested objects about what it did or to reflect its new state.
I'm suggesting changing the design as follows:
No singleton signal.
Each Object has its own signal and slot for a relevant event (e.g. selection change).
The application or a higher level object (that created the widgets/objects) performs the signal to slot connection. If those widgets are placed in a list, this is very simple.
I would like to create a widget in asynchronously and then assign it to a dialog in the main thread. I have a functions to create the widget:
shared_ptr<QTableWidget> createTable() {
auto table = make_shared<QTableWidget>()
// ... add some items to the table
return table;
}
When I call this function synchronously everything works as expected. Problem is when I call this function asynchronously:
auto futureWidget = QtConcurrent::run(createWidget);
I use QFutureWatcher::finished() signal and when the widget creation is done, I try to add that widget to the dialog in the main/GUI thread.
The problem is that sometimes it just crashes with SIGSEG when I add an item to the table. Sometimes when it completes the created widget is not shown. Also there is a lot of warnings on the standard output about using pixmap outside GUI thread.
Is that not possible to create widgets in different thread in Qt? If it is possible, how to do it?
No, it is only possible to create GUI widgets within the main thread.
Usually, it does not take much time to create GUI part of widget. If you have some operation, that takes a lot of time, you probably should extract it from process of widget creation, process it in separate thread and then pass result of this operation to the newly created widget.
EDIT
If you have some complex tables in the widget, you should use Qt MVC system, i.e. QTableView and model based on QAbstractTableModel. You can then fill model in another thread and only then assign it to view, created in main thread.
If I want to make a connection in Qt as follows:
QObject::connect(quitButton, SIGNAL(clicked()), &myapp, SLOT(quit());
What does &myapp refer to here? Why should it be used?
Thanks.
In this case what you get is that whenever the quitButton sends the signal clicked it will be sent to the slot quit in myapp. If the names mean what I think this is probably a button to, well..., quit your app.
Notice there are different versions of connect. It's hard to get the context from a single line of code, but anyway you might wanna check qApp which already represents your application.
EDIT: From another post from you I noticed you asked a trivial question about pointers. So if this is more about what the &character means, it takes the address of your object. This is pure C++ (nothing specific to Qt).
What does &myapp refer to here? Why should it be used?
This is the object that will handle the signal (The & takes the objects address (ie. the underlying code uses pointers).
QObject::connect(quitButton, SIGNAL(clicked()), &myapp, SLOT(quit());
Translation:
When the signal clicked is activated on the object quitButton
Call the slot quit on the object myapp.
What this means:
A signal is just a method that is called by the object when certain internal state changes. In this case the object will call signal when the user interfaced element is clicked on by the mouse.
The signal method will then call all (slot) methods that have been registered. So in this case when you click on the button signal() is called this in turn will call the quit() method on the object 'myapp`.
Given the way QT examples are normally done. myapp is an application object and the quit() method will cause the main thread to exit from the call to exec().