Track QStandardItem lifetime - qt

I'm writing some wrappers over QStandardItemModel. Is it possible to track lifetime (delete events) of QStandardItems?
I think that the only way is to interhit QObject + QStandardItem. But I don't want to do it for some reasons.
UPDATE:
I need to delete my object, that contains pointer to QStandardItem, when this item removed from model.
Here is solution. But I want to do the same for external (not mine) QStandardItem.
class ItemWrap : public QObject, public QStandardItem
{
// ...
};
class MyObject : public QObject
{
MyObject( ItemWrap *item ) // I need MyObject( QStandardItem *item )
{
connect( item, &QObject::destroyed, this, &MyObject::deletelater );
}
// ...
};

As is often the case in Qt, there are objects that are not QObjects, but that are managed by a QObject (or otherwise accessible via one). You need to make MyObject monitor the model the items are in. The code below could be a starting point.
Another approach, not implemented but certainly feasible, is to dynamically replace all items in a model with copies that are instances that you yourself created. By monitoring the relevant model signals, you can be notified of all item additions and replace items with instances that you are a factory for. It would be a thinly veiled dependency injection into a QStandardItemModel.
The lowest-overhead approach would be to move the signals and slots from individual objects to the model itself, so that you avoid the overhead of having potentially very many QObjects, while still retaining their signal/slot functionality.
class MyObject : public QObject {
Q_OBJECT
QStandardItem * m_item;
Q_SLOT void onRowsAboutToBeRemoved(const QModelIndex & parent, int start, int end) {
if (m_item->parent() == parent &&
m_item->index().row() >= start &&
m_item->index().row() <= end) onItemGone;
}
Q_SLOT void onColumnsAboutToBeRemoved(const QModelIndex & parent, int start, int end) {
if (m_item->parent() == parent &&
m_item->index().column() >= start &&
m_item->index().column() <= end) onItemGone;
}
Q_SLOT void onItemGone() {
m_item = 0;
deleteLater();
}
public:
MyObject(QStandardItem* item, QObject * parent = 0) :
QObject(parent), m_item(item)
{
Q_ASSERT(m_item.model());
connect(m_item.model(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
SLOT(onRowsAboutToBeRemoved(QModelIndex,int,int)));
connect(m_item.model(), SIGNAL(columnsAboutToBeRemoved(QModelIndex,int,int)),
SLOT(onColumnsAboutToBeRemoved(QModelIndex,int,int)));
connect(m_item.model(), SIGNAL(modelAboutToBeReset()), SLOT(onItemGone());
connect(m_item.model(), SIGNAL(destroyed()), SLOT(onItemGone());
}
};

Every data model has signals about changes in the model, see documentation of QAbstractItemModel and this is what you need.
Note that QStandardItem is not a QObject so it doesn't have any signals or slots.

Can you please clarify what you mean by track lifetime.
Why do you want to subclass QObject?
Are you going to use SIGNALS and SLOTs? If no then I don't think it is going to be of much use.
Apart from that you can subclass QStandardItem and track the lifetime using your constructor and destructor or a suitable function?

Related

If I call a setValue() or similar function of a Qt widget, when is its valueChanged() slot guaranteed to be executed?

Let's say I have multiple input widgets to set up the same parameter. For example, there is a QSlider and a QSpinBox which need to show the same value. In the valueChanged() slot of one of them I call the setValue() of the other one.
Obviously, this would result in an endless loop of them calling each other.
A similar problem arises when this input widget controls some external resource or device. If the user changes the value, it will send the new value to the external device. But if the external device changes the value (or it is read from a settings file, etc) then I have to update the widget, which in turn will send the value, which in turn will update the widget, and so on.
A third scenario is when I save the values into a file or database, but I have to initialize the widgets to some value at the beginning, possibly before I got all the values from the database. But by initializing the widgets at the beginning of my program, they will write that dummy value into the database, overwriting the real values.
The obvious solution for these problems is to just have a bool which allows or forbids the side effects of the valueChanged() functions.
For example, if I want to change the value of my slider, I use
editing = true;
slider.setValue(value);
editing = false;
While I have if (editing) return; at the beginning of my valueChanged() function.
Assuming I didn't fiddle with setting up the signals and slots manually, but they were done by QtCreator, is there a danger of the slot being called later, for example after the editing flag is set to false again? I tried it, and it works, but I am unsure how guaranteed it is.
If you use direct connection (the default for objects in the same thread), the slot is called as soon as the signal is emitted, that is before the setValue method returns.
If you use Qt::QueuedConnection, the slot is invoked when control returns to the event loop of the receiver's thread.
See Qt::ConnectionType
The way I would go about solving this problem is by having another QObject that will be your data model. Your data will be centralized in your model, and will gotten/set via the model. This way your widgets wouldn't need to know about one another and can be created in separate places in your code as long as they can access your model.
Your model will have a method setValue and a signal valueChanged, so it will look some thing like this:
class Model : public QObject {
Q_OBJECT
public:
void setValue(const QVariant& value) {
if (_value != value) {
_value = value;
emit valueChanged(_value);
}
}
const QVariant& getValue() const {
return _value;
}
public signals:
void valueChanged(QVariant& value);
private:
QVariant _value;
}
Then your widgets can take the same instance of Model as a dependency and listen to its valueChanged signal and update themselves. The widgets will also listen to user input, and when the user changes the value then they will change the value in the model. That way the other widgets will get notified about the change.
Your widgets will look like this:
class MySlider : public QSlider {
Q_OBJECT
public:
explicit MySlider(QSharedPointer<Model> model, QWidget *parent=nullptr)
: QSlider(parent), _model(model) {
connect(this, &QSlider::valueChanged, this, [this](int value){
_model->setValue(value);
});
connect(_model.data(), &Model::valueChanged, this, &MySlider::onValueChanged);
//this is to update the widget with the latest value upon creation
onValueChanged(_model->getValue());
}
private slots:
void onValueChanged(const QVariant& value) {
if (value.toInt() != value()) {
//this is calling QSlider::setValue
setValue(value.toInt());
}
}
}
Before you create all your widgets you can create your model with the default value, so let's assume it's in main:
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MainWindow w;
w.show();
//note that your model doesn't have a parent, it's a shared pointer
auto model = QSharedPointer<Model>::create();
auto mySlider1 = new MySlider(model, &w);
auto mySlider2 = new MySlider(model, &w);
return a.exec();
}
P.S. You can also look into QDataWidgetMapper and see if it can accomplish what you're looking for.

QMainWindow - wait until 'show' function is done

Is there a signal that tells when 'show' function finishes?
I have a problem in my code: If I write:
QMainWinObj.show();
QMainWinObj.someGuiFunc();
the code doesn't work. But, if I write:
QMainWinObj.show();
sleep(3000);
QMainWinObj.someGuiFunc();
It does.
So I think the problem is that 'show' dosn't finish its jub before I call 'someGuiFunc'. That's why I want to have some kind of a sign that 'show' is finished..
This may be a bit dated but since nobody else answered it except the one:
Since there is no "Show" signal I suggest overriding the show event like this:
In your mainwindow.cpp file:
void MainWindow::show()
{
QMainWindow::show();
QApplication::processEvents();
emit windowShown();
}
In your mainwindow.h file, somewhere in MainWindow's declaration:
...
class MainWindow: public QMainWindow
{
...
signals:
void windowShown();
...
}
...
Then, when you go to the designer, right click on the main window (very top of the object tree), and select "Change signals/slots". In the "Signals" frame, click the "+" button, and you will need to add "windowShown()" and then press enter, and then the OK button (note that the elipses "..." denote other code that is already in your header).
That's it -- you can now use the signals/slots editor to link slots up to the 'windowShown' signal whenever you want. Now if you want something more like Microsoft's "Loaded" event which I think is used in .NET you will need to create some instance variable and flag it so that every time the window is shown, it isnt emitted, for example:
void MainWindow::show()
{
QMainWindow::show();
QApplication::processEvents();
emit windowShown();
if (firstTimeShown == true)
{
emit windowLoaded();
firstTimeShown = false;
}
}
Also, don't forget to initialize the variable to 'true' in your constructor:
MainWindow::MainWindow(QObject* parent)
...
{
firstTimeShown = true; // put this somewhere before ui->setupUi()
}
If you decide to put it in the initializer list however, make sure it is in proper order. The compiler will complain if the variables are not instantiated in a top-to-bottom fashion as declared in the class' header.
Now, make sure when you define firstTimeShown in your header, that you make it private. And lets not forget the added signals:
class MainWindow : public QMainWindow
{
...
signals:
void windowLoaded();
void windowShown();
private:
bool firstTimeShown;
...
That's about it. With the flexibility of signals and slots, its pretty easy to mimic any event that you might find from windows forms or from MFC. It just takes a little effort on the programmer's part. Once you get the hang of it however it it'll be like second nature.
note: there probably are optimizations or better and more precise ways of making the "Loaded" and "Shown" signals perform but I have left things like this out for simplicity's sake. And to come back to the question at hand, calling QApplication::processEvents() is most likely what you want to do instead of waiting a fixed amount of time because who knows how long it will take if the user is running 100 other things on top of it, etc, etc. Hope that helped, the extra explanation was included hoping that it might give you a better way to do the things that you want to do instead of waiting for something to be done, 'knowing' it is done is a much better alternative.
There is no such signal, but having QMainWindow subclassed you can override showEvent event.
void MainWindow::showEvent(QShowEvent *){
//your code
}
More info here: http://qt-project.org/doc/qt-4.8/qwidget.html#showEvent
Be aware it's called every time your window is about to be displayed.
Problem can decide without subclassing, just installing event filter like this:
class CWidgetIsPainting_EF : public QObject
{
bool m_bIsPainted = false;
public:
CWidgetIsPainting_EF( QObject * parent = 0 ) : QObject (parent) { }
inline bool IsPainted() const { return m_bIsPainted; }
inline void setIsPainted( bool bIsPainted ) { m_bIsPainted = bIsPainted; }
protected:
bool eventFilter( QObject * obj, QEvent *event )
{
if (event->type() == QEvent::Paint)
{
m_bIsPainted = true;
return true;
};
return QObject::eventFilter(obj, event);
}
};
...
...
CWidgetIsPainting_EF * pPaintingEF = new CWidgetIsPainting_EF( m_pWidget );
m_pWidget->installEventFilter( pPaintingEF );
...
...
while ( !pPaintingEF->IsPainted() )
QApplication::processEvents();
Override bool event(QEvent *event) and catch the Paint event. Works for me at least on Windows.
// MainWindow.h
class MainWindow : public QMainWindow
{
...
bool event(QEvent *event) override;
void functionAfterShown();
...
bool functionAfterShownCalled = false;
...
}
// MainWindow.cpp
bool MainWindow::event(QEvent *event)
{
const bool ret_val = QMainWindow::event(event);
if(!functionAfterShownCalled && event->type() == QEvent::Paint)
{
functionAfterShown();
functionAfterShownCalled = true;
}
return ret_val;
}

What is the right way to suppress Qt signals when values are explicitely set

I got a from QWidget derived class that holds three QSpinBoxes (e.g. coordinates). The valueChanged() signal is connected and is emitted in at least these three cases:
up/down button
manually entered number
setValue()
However, when using setValue(), I want to suppress the signal(s), since I don't want to have (three) signals. In my understanding, there are two ways to handle this:
QObject::blockSignals()
using a flag that indicates whether the values were explicitely set
Both variants work, but I think they are not straight-forward at all: For the first one, I generally block all signals AND I need to set blockSignals(true) for all underyling widgets (blockSignals doesn't block children QObjects in my application). For the second one, I need to query the flag in every update method AND the signals are raised although I don't need them.
Are there any general designing patterns that prevent such behavior? If not, what variant would you prefer?
The third option would be to subclass QSpinBox, implement desired functionality there, and used derived class instead of QSpinBox - this hides all associated complexity in derived class and allows you use it just like QSpinBox.
For example, following class
myQSpinBox.h
#ifndef MYQSPINBOX_H
#define MYQSPINBOX_H
#include <QSpinBox>
class myQSpinBox : public QSpinBox
{
Q_OBJECT
public:
myQSpinBox(QWidget * parent = 0 );
protected:
bool valueBeingSet;
public slots:
void setValue (int val);
private slots:
void On_valueChanged(int val);
signals:
void valueChangedNotBySet(int val);
};
#endif // MYQSPINBOX_H
myQSpinBox.cpp
#include "myQSpinBox.h"
myQSpinBox::myQSpinBox(QWidget * parent)
: QSpinBox(parent)
, valueBeingSet(false)
{
connect(this,SIGNAL(valueChanged(int)),this,SLOT(On_valueChanged(int)));
}
void myQSpinBox::setValue ( int val )
{
valueBeingSet = true;
QSpinBox::setValue(val);
valueBeingSet = false;
}
void myQSpinBox::On_valueChanged(int val)
{
if(!valueBeingSet)
emit valueChangedNotBySet(val);
}
will emit valueChangedNotBySet(int); in cases 1. and 2., but not in case 3., keeping all QSpinBox functionality intact

Is there a way to generate a signal on QSlider value increased

I'm trying to trigger a distinct signal from a QSlider for when it increases or decreases. Unfortunately due to restrictions in the program i'm creating outside of my control I cannot track the value of the slider and just do a comparison.
Is there a way to do this?
If I understand you correctly, you can't use valueChanged(int) to decide if the value increased or decreased, since you can't track the value. However, you need to do this, since QSlider doesn't have distinct signals for an increased / decreased value.
Use this helper class to keep track of the current value. It remaps the signal valueChanged(int) of the provided target object to the new signals valueIncreased(int) and valueDecreased(int) telling the (absolute) difference.
class ValueChangeTracker : public QObject
{
Q_OBJECT
int v;
public:
ValueChangeTracker(QObject *target) :
QObject(target)
{
connect(target, SIGNAL(valueChanged(int)), SLOT(changed(int)));
v = target->property("value"); // or ->value() if you specifically use QSlider* instead of QObject* as the target type
}
signals:
void valueIncreased(int);
void valueDecreased(int);
private slots:
void changed(int newValue) {
int diff = newValue - v;
v = newValue;
if(diff > 0) emit valueIncreased(diff);
if(diff < 0) emit valueDecreased(-diff);
}
};
To use it, simply create a new instance of this class and connect to its signals. In the QObject tree, it becomes a child of the target object, so you don't have to keep the pointer to an instance.
QSlider *mySlider = ...
ValueChangeTracker *tracker = new ValueChangeTracker(mySlider);
connect(tracker, SIGNAL(valueIncreased(int)), ...);
connect(tracker, SIGNAL(valueDecreased(int)), ...);
QSlider emits the signal valueChanged, just connect it to a slot:
mySlider.valueChanged.connect(self.on_mySlider_valueChanged)
and to your tests there and emit a custom signal if you like.
I don't fully understand the question, maybe an example would help. But if you look at the documentation for QSlider, it emits signal valueChanged(int) when the value of the slider changes.

In Qt how to sort the immediate child indexes of a QModelIndex

I'm writing a C++ application that uses Qt classes to work with certain data models. For that purpose I inherited from QAbstractItemModel:
// the following is a class that represents the actual data used in my application
class EventFragment
{
....
private:
qint32 address;
QString memo;
QDateTime dateCreated;
QVector<EventFragment*> _children;
....
};
// the following is the model representation that used by my application to display the actual details to the user
class EventModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit EventModel (QObject *parent = 0);
....
private:
// the following is the root item within the model - I use a tree-like presentation to show my data
EventFragment* _rootFragment;
};
At some point I needed a sort/filter option in my application so I also created a class that inherits from QSortFilterProxyModel
class EventProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit EventProxyModel (QObject *parent = 0);
...
public:
// I had to add my custom implementation in the 'lessThan' method to achieve a
// more complex sort logic (not just comparing the actual values but using
// additional conditions to compare the two indexes)
virtual bool lessThan ( const QModelIndex & left, const QModelIndex & right ) const;
...
};
To achieve sorting, I used the default QSortFilterProxyModel::sort() method (I haven't reimplemented it in my proxy model class) and for a time it seemed to work.
At some point though, I noticed that the actual QSortFilterProxyModel::sort() method sorts the entire model and what I need is to sort only the immediate children of a certain index.
I tried to reimplement the sort() method of the EventModel class, but after a while I realized that QSortFilterProxyModel::sort() is not referring to it at all. On the other hand, I'm not sure how to rearrange the indexes in a safe way so that the view which displays the model does not crash.
I think there must be a way to sort only the immediate children of a certain QModelIndex, but I haven't found it yet.
Is there any tutorial/example that demonstrates a possible solution to my case, or some guidelines on how to do it?
Regards
If you want an optimized solution that doesn't do comparisons at all for the indexes you don't want to sort, I think you'd have to reimeplement your own QAbstractProxyModel, which is a non-trivial task. However, if you're fine with a non-optimized solution, I'd try this:
bool EventProxyModel::lessThan( const QModelIndex & left, const QModelIndex & right ) const {
if ( left.parent() == isTheOneToSortChildrenFor ) {
...apply custom comparison
} else {
return left.row() < right.row();
}
}
Comparing the rows in the source should leave everything other then indexes with that specific parent as they are.

Resources