I have the following connect line:
connect(my_QStandardItemModel ,SIGNAL(itemChanged(QStandardItem*)),
this,SLOT(cellEditEndedCalled(QStandardItem*)));
For some reason whenever I go into edit mode on a cell inside my table (double click) and click on another cell, cellEditEndedCalled() is being called even though I didn't make any changes to my data.
Any ideas on why this might be happening?
EDIT:
Tried with dataChanged(...) instead of itemChanged(...) but the slot is still being called.
Implementation of my_QStandardItemModel :
class my_QStandardItemModel :public QStandardItemModel
{
typedef QStandardItemModel baseClass;
Q_OBJECT
public:
my_QStandardItemModel ();
virtual ~my_QStandardItemModel ();
...
Not overwriting any signals afterwards.
Because the signal itemChanged is not the correct for your situation. QStandardItemModel inherits another singal form QAbstractItemModel
void QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const
QModelIndex &bottomRight, const QVector<int> &roles = QVector<int> ())
that emits with QModelIndex information on the index where changes occured : your cell.
you need to connect that signal to your slot (to be modified to match new signal signature).
Why the itemChanged signal is emitted even you did not modify the data: because that signal emits when you change your item NOT the data in it.
Related
I am using a qlistwidget as an deligate inside an cell of Qtreeview.
I have written a handler for the double click on item of qtreelist . Double click handler for Qlistview deligate is working fine.
My requirement is that on double click on any item of qlistwidget deligate for qlistwidget closes.
Please suggest what is the exact signal to be used for it.
Slot for double click on qtreewidgetlist item :---
void listWidgetDeligate::onListWidgetItemDoubleClicked(QListWidgetItem * item)
{
// emit signal to close the deligate
}
Double click handler pass an QListWidgetItem argument to the slot.
How can i use this argument to close the delicate means which signal to emit for this ?
If you haven't found any appropriate built-in signals for that widget you can always define your own signal in .h file :
signals:
void closeOnDoubleClick();
If you only need your slot void listWidgetDeligate::onListWidgetItemDoubleClicked(QListWidgetItem * item) to emit another signal and do nothing else, you can just do
connect(<the object of listWidgetDeligate>,
SIGNAL(<signal that was previously connected to slot onListWidgetItemDoubleClicked>()),
SIGNAL(closeOnDoubleClick()));
that means that your listWidgetDeligate will emit signal closeOnDoubleClick() after onListWidgetItemDoubleClicked>() was emitted.
Thus, you do not need a slot.
Remember, that the declared parameters of signal and slot connected to each other must be the same.
I have a QTableView that obtains the data from a custom model and it's edited using a custom delegate.
//...
view->setModel(stockModel);
view->setItemDelegateForColumn(0, nameDelegate);
When the user edits a specific cell it types some text (name for an object) and this text could be accepted by the program or not (the program doesn't want to have repeated names).
My solution for this was to the custom delegate to have a signal: notValidText(QModelIndex) and use the signal/slot mechanism to connect the signal to the tableview edit(QModelIndex) slot. This, from what i know, should reedit the cell in question:
//implementation of the delegate
void NameDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index)
{
QLineEdit *line = static_cast<QLineEdit*>(editor);
if(!model->setData(index, line->text(), Qt::EditRole))
{
emit notValidData(index);
}
}
//connection of the view with the delegate
connect(nameDelegate, SIGNAL(notValidData(QModelIndex)), view, SLOT(edit(QModelIndex)));
Unfortunately this is not what happens, so i'm doing something wrong. If someone could give me a tip i would really appreciate.
I just put here some code to show what i did, ask if you need me to post anymore.
Thanks in advance
I am having some difficulty fully grasping how signals and slots are used in Qt. I am sure it is really basic but I'm just no getting it today.
I have a set of widgets a bit like this:
MainWindow
-->StackedWidget
-->ChildForms
Now the idea is that there are some actions on the Child widgets that will cause the stacked widget to display a different page.
So if I understand it properly I thought the way to connect signals and slots is to use the connect() at the scope that knows about the objects but what I have managed to get working doesn't do it this way. At the moment in my child form I use parentWidget() to access the slot of the StackedWidget but I am not very happy with really because it is giving the child information about the parent which it shouldn't have:
void TaskSelectionForm::setButtonMappings()
{
// Set up a mapping between the buttons and the pages
QSignalMapper *mapper = new QSignalMapper(this);
connect(mapper, SIGNAL(mapped(int)), parentWidget(), SLOT(setCurrentIndex(int)));
mapper->setMapping(ui->utilitiesButton, 2); // Value of the index
connect(ui->utilitiesButton, SIGNAL(clicked()), mapper, SLOT(map()));
}
But I am not really sure how I should do this and connect it up. Do I need to have signals at each level and emit through the tree?
A Bit of Signal-Slot Theory
The signal-slot connections are oblivious to parent-child relationships between QObjects, and any such relationship doesn't matter. You're free to connect objects to their children, to their siblings, to their parents, or even to QObjects that are in a separate hierarchy, or to lone QObjects that have neither parents nor children. It doesn't matter.
A signal-slot connection connects a signal on a particular instance of QObject to slot on another instance of QObject. To use the connect method, you need the pointers to the instance of sender QObject and the instance of receiver QObject. You then use the static QObject::connect(sender, SIGNAL(...), receiver, SLOT(...)). Those connections have nothing to do with any hierarchy there is between the sender and receiver.
You can also connect a signal to a signal, to forward it -- for example from a private UI element to a signal that's part of the API of the class. You cannot connect a slot to a slot, because it'd incur a bit of runtime overhead for a rarely-used case. The overhead would be an extra bool member in QObjectPrivate, plus a failed if (bool) test. If you want to forward slots to slots, there are at least two ways to do it:
Emit a signal in the source slot and connect that signal to the destination slot.
Obtain a list of all signals connected to the source slot, iterate on it and connect them to to the target slot. There's no easy way to maintain such connections when further signals are connected or disconnected from the source slot. Unfortunately, QObject only has a connectNotify(const char*) protected function, but not a signal -- so you can't hook up to it unless you would modify src/corelib/kernel/qobject[.cpp,_p.h,.h] to emit such a signal. If you truly need it, just modify the Qt source, you have access it for a reason, after all. Hacking the vtable without modifying Qt is possible, but discouraged for obvious reasons.
The Answer
Below is a self contained example that shows how to do what you want. Turns out I have answers to quite a few questions from my various experiments I've done in Qt in the past. I'm a packrat when it comes to test code. It's all SSCCE to boot :)
// https://github.com/KubaO/stackoverflown/tree/master/questions/signal-slot-hierarchy-10783656
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class Window : public QWidget
{
QSignalMapper m_mapper;
QStackedLayout m_stack{this};
QWidget m_page1, m_page2;
QHBoxLayout m_layout1{&m_page1}, m_layout2{&m_page2};
QLabel m_label1{"Page 1"}, m_label2{"Page 2"};
QPushButton m_button1{"Show Page 2"}, m_button2{"Show Page 1"};
public:
Window(QWidget * parent = {}) : QWidget(parent) {
// the mapper tells the stack which page to switch to
connect(&m_mapper, SIGNAL(mapped(int)), &m_stack, SLOT(setCurrentIndex(int)));
// Page 1
m_layout1.addWidget(&m_label1);
m_layout1.addWidget(&m_button1);
// tell the mapper to map signals coming from this button to integer 1 (index of page 2)
m_mapper.setMapping(&m_button1, 1);
// when the button is clicked, the mapper will do its mapping and emit the mapped() signal
connect(&m_button1, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page1);
// Page 2
m_layout2.addWidget(&m_label2);
m_layout2.addWidget(&m_button2);
// tell the mapper to map signals coming from this button to integer 0 (index of page 1)
m_mapper.setMapping(&m_button2, 0);
connect(&m_button2, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
Connect(stackedwidget->currentactivewidget,SIGNAL(OnAction()),this,SLOT(PrivateSlot()));
PrivateSlot() is a slot declared privately. So in this function, you can add your code to change the page of stackedwidget corresponding to the action produced by currentactivewidget.
Again if you really want to pass the signal up the heirarchy, emit a publicsignal() at the end of private slot function.
Connect(this,SIGNAL(publicsignal()),Parentwidgetofstackedwidget(here mainwindow),SLOT(mainwindow_slot()));
I have a QTreeView with a QSortFilterProxyModel between the view and a QStandardItemModel to sort the tree. I then want to act on clicks in the view through the clicked() signal.
The models/view are setup similar to this:
mymodel = new QStandardItemModel(5, 5, this);
mysort = new MySortProxy(this);
mysort->setSourceModel(mymodel);
myview = new QTableView(this);
myview->setSourceModel(mysort);
connect(myview, SIGNAL(clicked(QModelIndex)), this, slot(clickAction(QModelIndex)));
This setup all works and sorts my data in the way I want it. When you click on an item, the clickAction() slot gets called with the index of the item clicked. I then try to get the item from the index in the slot:
void myclass::clickAction(const QModelIndex &index)
{
QStandardItem *item = mymodel->itemFromIndex(index);
}
However, itemFromIndex returns NULL.
If I remove the QSortFilterProxyModel and set the model directly as sourcemodel in the view, it all works perfectly. I.e.
myview->setSourceModel(mymodel); // was setSourceModel(mysort);
mymodel->itemFromIndex(index) now returns the item as expected, but obviously now I can't use my own sort proxy.
Can anyone tell me what I'm doing wrong and how I can get the item in the click slot when I have a sortfilter proxy in place?
I'm using Qt-4.3.1.
Thanks for any help, Giles
I believe you want to do something like:
void myclass::clickAction(const QModelIndex &index)
{
QStandardItem *item = mymodel->itemFromIndex(mysort->mapToSource(index));
}
I have a class inherited from QWidget, now in that class I will be creating aQListView object and filling up the items to view.
When the selection of items in the list view gets changed, I want to get the selectionChange event.
How can I achieve this?. Please tell me in brief.
When you have a view, you will have a model that will be used to select item. It's called a QItemSelectionModel.
For example, with your QListView, you can get the selectionModel this way :
QItemSelectionModel* selectionModel() const;
Now, from that model, you'll be able to connect on many signals :
void currentChanged ( const QModelIndex & current, const QModelIndex & previous )
void currentColumnChanged ( const QModelIndex & current, const QModelIndex & previous )
void currentRowChanged ( const QModelIndex & current, const QModelIndex & previous )
void selectionChanged ( const QItemSelection & selected, const QItemSelection & deselected )
I think it will help you a bit!
https://doc.qt.io/archives/qt-4.8/qlistwidget.html You might want to use QListWidget instead of view, I don't remember specifics why, but this class has these signals you want to use.
https://doc.qt.io/archives/qt-4.8/qlistwidget.html#itemSelectionChanged
This is the signal you have to connect to.
Make a slot in your class declaration:
private slots:
void selChanged();
Fill this slot with what you want to do upon selection change.
Connect the signal to this slot somewhere in your class - perhaps in the constructor of your QWidget derivative.
connect(yourListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selChanged()));
that's it