Adding QListWidgetItem To QListWidget - c++

So I have a class SnapshotPanel : public QListWidget that I am trying to add a QListWidgetItem to dynamically, however it when ever I try I get a segfault. I have verified that my code to add the item is correct as I can add to the list when I construct my SnapshotPanel. However I cannot add to the panel when the code is called via signals and slot, insight into what I am missing would be apprecited.
Here is the constructor:
SnapshotPanel::SnapshotPanel(QWidget *parent):QListWidget(parent)
{
this->setViewMode(QListWidget::IconMode);
this->setIconSize(QSize(256,256));
this->setResizeMode(QListWidget::Adjust);
QIcon icon("icon.jpeg");
QListWidgetItem *widget = new QListWidgetItem(icon,"Earth");
this->addItem(widget);
}
So is there any reason I wouldn't be able to use the following code when called via signals and slots:
{
QIcon icon("icon.jpeg");
QListWidgetItem *widget = new QListWidgetItem(icon,"Earth");
this->addItem(widget);
}

I think it should just work. "Slots are normal C++ functions" according the documentation.
If you are using multiple threads you need to look into the connection mechanism. Perhaps you need to use queued connections. You would change your connect statements from:
connect(button, &QPushButton::clicked, this, &MainWidget::on_button_clicked);
to
connect(button, &QPushButton::clicked, this, &MainWidget::on_button_clicked, Qt::QueuedConnection);
But read the official documentation here. A SO question (basically pointing you back to the documentation) is here.

Related

QSignalMapper problems with strings

I have a question about QSignalMapper.
I have simple application, a calculator. And I have something like this, I click button and I want to display it. But I have problem, I don't know how to assign string to a button. It only want to work with integers. But i know it is possible to do it with strings. And I need to do it on strings, because then I want to convert it to double type. I have idea how do rest of things I want to do, but this QSignalMapper is killing me.
QSignalMapper *signalMapper = new QSignalMapper(this);
connect(ui->Button0, SIGNAL(clicked()),
signalMapper, SLOT(map()));
signalMapper->setMapping(ui->Button0, '0');
I tried to do something with QString but it did not help.
I will be grateful for any help.
I don't think you need signalMapper to accomplish what you are looking for. A standard connect() function call will likely work.
Try using Qt5 syntax for creating the connection
Change your connect function call to include units if you are using the old way.
Edited - Example syntax for connect
New way. Note that param datatypes are not included in the connect
call.
connect(
sender, &Sender::valueChanged,
receiver, &Receiver::updateValue
);
Old way
connect(
sender, SIGNAL( valueChanged( QString, QString ) ),
receiver, SLOT( updateValue( QString ) )
);
Edited - Method 1 --> Using two known C++ objs
Create a signal function emitting a QString
Create a slot function recieving a QString
Connect the two QStrings together
Handle as desired
Edited - Method 2 --> Using QML exclusively
Declare signal(string str) in QML
Use existing btn onClicked event and call declared signal
Handle to signal via slot and do as needed with text
Edited - Method 3 --> Use QSignalMapper if dealing with MVC and indexs
1. See Qt documentation
Use lambda method to connect button click and text
connect(button, &QPushButton::clicked, [this, text] { clicked(text);
});
Hopefully one of these methods provides some help to solving your problem!

How to used itemExpanded with a subclass of QTreeWidgetItem

I do have a connection related to SIGNAL/SLOT use in Qt/C++
I have wrote an app using a QTreeWidget + QTreeWidgetItems. For the need of the app, I had to subclass QTreeWidgetItem to MyQTreeWidgetItem in order to add some parameters.
Since I move from QTreeWidgetItem class to MyQTreeWidgetItem class,
connect(this, SIGNAL(itemExpanded(MyQTreeWidgetItem*)),
this, SLOT(onSubTreeDisplay(MyQTreeWidgetItem*)));
is not working anymore.
The issue is
QObject::connect: No such signal PulsTreeWidget::itemExpanded(MyQTreeWidgetItem*) in ../puls_connect/pulstreewidget.cpp:33
I think that the issue is coming from the fact that itemExpanded expect QTreeWidgetItem and not MyQTreeWidgetItem. But if I replace MyQTreeWidgetItem by QTreeWidgetItem such as
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)),
this, SLOT(onSubTreeDisplay(MyQTreeWidgetItem*)));
the run complain that SIGNAL/SLOT do not have the same type and this normal.
My item is defined through MyQTreeWidgetItem and not QTreeWidgetItem as I have subclass it.
The connect is done in the QTreeWidget part
Any idea ?
thanks
You can do the signal slot connection like below
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(onSubTreeDisplay(QTreeWidgetItem*)));
Then inside onSubTreeDisplay(), dynamic cast QTreeWidgetItem argument to MyQTreeWidgetItem like below
void onSubTreeDisplay(QTreeWidgetItem* item)
{
MyTreeWidgetItem* myItem = dynamic_cast<MyTreeWidgetItem*>(item);
if (myItem)
{
//cast is successful. you can use myItem
}
}

Passing QLabel as parameter Qt C++

I have a little GIF which is animated on a QLabel with a QMovie, and I want that when the animation of the GIF is complete, to remove the Qlabel. I tried this, but it doesn't work :
QMovie *movie = new QMovie("countdown.gif");
QLabel *processLabel = new QLabel(this);
processLabel->setMovie(movie);
movie->start();
QTimer::singleShot(1000, this, SLOT(movie_finished(backgroundLabel)));
Here is my function :
void movie_finished(QLabel *processLabel){
processLabel->deleteLater();
}
Basic misunderstanding, this is illegal:
QTimer::singleShot(1000, this, SLOT(movie_finished(backgroundLabel)));
You can't give parameters like that to connections. Just types in SLOT, like this:
QTimer::singleShot(1000, this, SLOT(movie_finished(QLabel*)));
There are (at least) three ways to solve this. First remove the QLabel* parameter from slot. Then:
Use QSignalMapper, which basically encapsulates the two alternatives below.
Create an intermediate slot in some class, which has QLabel* member variable, which it then uses in the slot without parameter, and connect the timer signal to this slot.
Use sender() method in your slot (but this is generally considered ugly, breaking encapsulation, and QSignalMapper is preferred).
Using a QTimer to synchronize the end of your movie is not really needed here.
The really simply way to accomplish this is to just have the movie delete the label when it is finished:
connect(movie, SIGNAL(finished()), processLabel, SLOT(deleteLater()));
The QMovie will emit finished() when it is done. So just wire it to the deleteLater() slot of your QLabel.
Because this might make you leak the QMovie when the QLabel is deleted, you may want to parent it to the QLabel, as setting it as the movie does not mean the QLabel actually cleans it up.
QLabel *processLabel = new QLabel(this);
QMovie *movie = new QMovie("countdown.gif");
movie->setParent(processLabel);

why append Slot doesn't work?

I have got a problem when I try to make following simple connections
QSpinBox *spinBox = new QSpinBox;
QSlider *slider = new QSlider(Qt::Horizontal);
QTextEdit *text = new QTextEdit("Hello QT!");
QObject::connect(spinBox, SIGNAL(valueChanged(int)),slider, SLOT(setValue(int)));
QObject::connect(slider, SIGNAL(valueChanged(int)),spinBox, SLOT(setValue(int)));
QObject::connect(slider,SIGNAL(valueChanged(int)),text, SLOT(append("slider changed!")));
QObject::connect(spinBox,SIGNAL(valueChanged(int)),text, SLOT(append("spinbox changed!")));
QObject::connect(text,SIGNAL(textChanged()),spinBox,SLOT(clear()));
It can be successfully compiled and excuted.But the two append slots seem not work.I've checked the help manual about QTextEdit and there's a public slot append there.Have I missed something?Help would be appreciated!
Unfortunately, you cannot pass custom values to your slots via QObject::connect (only type information for the arguments is allowed/interpreted correctly). Instead, create your own slot, something like
void MyWidget::mySliderChangedSlot(int newValue)
{
text->append("slider changed!");
}
and use
QObject::connect(slider, SIGNAL(valueChanged(int)), pMyWidget, SLOT(mySliderChangedSlot(int)));
to achieve your desired behaviour.
I hope that helps.
What exactly are you trying to do? That has now way of working because you connect a signal which has an int param to a slot with a string parameter for one, the other thing is that the signal slots where not meant for this kind of usage you just say wich function are conected and they pass parameters betwen them you dont pass the values yourself, you are not using them correctly read the documentation at http://doc.trolltech.com/4.6/signalsandslots.html for correct usage examples.

Fewer connections in a Qt calculator

I'm writing a simplified calculator using Qt with C++, for learning purposes. Each number is a QPushButton that uses the same slot to modify the text in a lineEdit widget being used as a display.
The slot uses the sender() method to figure out which button was pressed, so the correct number would be written on the display widget.
In order to have all the buttons working, I'd have to write a connection to each one of them, kinda like this:
connect(ui->button1, SIGNAL(clicked()), this, SLOT(writeNum()));
Since they all use the same slot, the only thing that changes is the button being used, so the next sender would be ui->button2, ui->button3, and so on. My question is, is there a way to reduce the number of defined connections?
Edit: Here's a useful link discussing precisely about this problem, in detail.
If you use QtDesigner or the form editor of QtCreator you can just drag lines between the 2 and it will fill in the code for you.
You could also keep all the buttons in a list structure, but I would use a QVector not a standard array.
You might also want to reconsider using the sender() method, it violates OOP design. Instead connect all the buttons to a QSignalMapper and then connect mapped() to your text box.
You should use an int in this case to identify the button which sent the signal to your slot. Essentially you use QSignalMapper for that task:
QSignalMapper sm;
QPushButton* one = new QPushButton(this);
QPushButton* two = new QPushButton(this);
QPushButton* three = new QPushButton(this);
//and so on...
sm.setMapping(one, 1);
sm.setMapping(two, 2);
sm.setMapping(three, 3);
//and so on...
connect(one, SIGNAL(clicked()), &sm, SLOT(map()));
connect(two, SIGNAL(clicked()), &sm, SLOT(map()));
connect(three, SIGNAL(clicked()), &sm, SLOT(map()));
//and so on...
connect(&sm, SIGNAL(mapped(int)), this, SLOT(yourslothere(int)));
Note: QSignalMapper is VERY useful, keep that in mind ;)
I think you can try allocating the QPushButton in a array, something like this
QPushButton* numbers = new QPushButton[10];
And then, perform the connections using a for loop
for(size_t i = 0; i < 9; ++i)
{
connect(numbers[i],SIGNAL(clicked()),this,SLOT(writeNum()));
}
But I don't think it's worth. Explicit connection, while making the code more verbose, make the connections more clear to the reader.