Solved Signals, slots, a vector of objects and their holy mother
-
Hi there,
This is going to be my first post so I hope I explain myself correctly. I have been using Qt and OOP for a short time so please forgive my inexperience.So, there is something I want to accomplish and for the moment I am not being able. I will write a simple example related to my problem to simplify things:
1 - I have created a class "Dog" which looks like this:
class Dog: public QObject { Q_OBJECT public: Dog(); ~Dog(); int getID(); public slots: void setName(QString name); void setID(int id); void setAlive(bool living); private: // Attributes int ID; QString name; bool isItAlive; };
2 - I have a UI with a ComboBox, a TextEdit and a CheckButton. When I create the UI, there is a list of an unknown number of IDs (idNumber) listed in the ComboBox as a result of this code:
Dog *dogs = new Dog[idNumber](); for (int i = 0; i < idNumber; ++i) { dogs[i].setID(i); ui->idComboBox->addItem(QString::number(dogs[i].getID()); }
The idea is to update the attributes of each dog (name and isItAlive) using the ComboBox to select the specific dog to get its information updated, and the TextEdit and the CheckBox for the contents of said attributes. Every time the EditText is changed or the CheckBox is toggled, a signal should have to be emitted so the specific dog (identified by the ID selected in the ComboBox at the time of the change) gets its corresponding name and status.
3 - I create in the MainWindow.cpp a connection between (for instance) the CheckBox and the Dog class:
connect(ui->aliveCheckBox, SIGNAL(toggled(bool)), dogs, SLOT(setAlive(bool)));
The connection seems to be OK but... How do I say which dog gets updated from the dogs array? How do I pass the content of the TextEdit as a parameter of the signal so the slot can update the corresponding attribute of the specific dog?
Maybe using signals and slots is not the best way to deal with this problem, but I want to avoid declaring dogs as global (which would solve all my problems as I could access it everywhere). Thank you very much in advance for your wisdom and help.
-
@alexRHT
QSignalMapper may help you here.But the simplest solution would be to connect to a onDataChanged() slot and in there you get the currently selected dog and update it with the current data of your checkbox and textedit.
-
@alexRHT In the combobox you select one specific dog, right? This way you know which one to modify. You should not connect the toggled(bool) signal to the vector or a dog, but to a slot in your MainWindow. In that slot you get the currently selected dog and modify it. No need to pass content of the TextEdit - you can get it in the slot I mentioned above.
-
@jsulm Ok, let me see if I have understood. What I would do is to detect that any change has been made on any of my UI elements and have a slot in my MainWindow to deal with changes. Inside this slot I get the ui->Whatever->getText or isChecked and even the ComboBox->currentIndex. But, how do I pass to this slot the dogs pointer so I can access to the 'currentIndex' dog? I'm sorry if this is too obvious...
-
@raven-worx I will investigate the QSignalMapper option too. Thanks!
-
@alexRHT You do not pass the dog pointer to the slots - you find the current dog in the slot. In that slot you do it like this (dog is the currently selected one):
Dog *dog = &Dogs[ui->idComboBox->currentIndex()]; dog->setName(name); dog->setID(id); dog->setAlive(living);
You can use the selected item index from the combobox to access the dog from your vector.
-
@jsulm It looked promising but it did not compile as I implemented it. So, I understand that you are here creating a temporary pointer which is pointing to the currentIndex() index of my previously created *dogs vector? Inside the slot I have no access to *dogs so... I feel dumb
-
@alexRHT Without your code I have no idea what is wrong.
Where did you define your dogs array/vector? You should have it somewhere.Yes the pointer points to the dog which is stored at currentIndex() position in your dogs array/vector.
-
@alexRHT Actually it shouldn't be a pointer. This should work as well:
Dog &dog = Dogs[ui->idComboBox->currentIndex()]; dog.setName(name); dog.setID(id); dog.setAlive(living);
-
@jsulm said:
@alexRHT Without your code I have no idea what is wrong.
Where did you define your dogs array/vector? You should have it somewhere.My dogs array/vector is defined at the constructor of MainWindow.cpp, where I also define the texts and states of the elements of the UI. The line of code that creates this array/vector is the one I posted previously:
Dog *dogs = new Dog[idNumber](); //idNumber is extracted from the number of lines of an external .txt file
Isn't this the way to declare the array? Maybe I failed here...
The thing is that the SLOT is a public method of MainWindow and, unless I declare *dogs as global or pass it as a parameter to the SLOT function, I don't have access to it. Am I mistaken? -
@alexRHT If you define dogs in constructor then it will only exist inside the constructor!
You have to put it in your class as private field.class MyClass: public QMainWindow { public slots: void mySlot(); private: Dogs *dogs; }; MyClass::MyClass() { dogs = new Dog[idNumber]; } void MyClass::mySlot() { Dog &dog = dogs[ui->idComboBox->currentIndex()]; dog.setName(name); dog.setID(id); dog.setAlive(living); }
-
@jsulm Newbie's mistake. Now it compiled!! Thanks for your patience and help.