Passing QLabel as parameter Qt C++ - 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);

Related

How to have QLabel update as various numbered pushbuttons are clicked

I have a dialpad with numbers 1-9 and 0, and a QLabel above it to show the numbers when clicked(same as a keypad on any phone). All are push buttons. What is the easiest way to get the QLabel to show the numbers as the push buttons are clicked?
For example, if 2 then 0 then 7 is clicked, the label would update in real time with 207. The format of the Qlabel should follow standard phone numbers, 000-000-0000. I understand how to setText for one number at a time, but they keep overriding each other.
Any help is appreciated.
Thank you in advance
What you are looking for is a QSignalMapper. It maps multiple inputs through a single interface and does the sender dispatching for you.
QSignalMapper *mapper(new QSignalMapper(parent));
for (int i=0; i<10; ++i){
QPushButton *button = some_new_button_function();
connect(button, &QPushButton::clicked, mapper, &QSignalMapper::map);
mapper->setMapping(button, i);
}
connect(mapper, QOverload<int>::of(&QSignalMapper::mapped),
[this](int i){/*here your append code*/});
The easiest is to connect the clicked signal of the buttons to a slot (possibly a lambda) that changes the text of the QLabel (using setText()). If you want to append to the current text, then just do setText(label.text() + "new text");.
You have to connect the signals clicked() emitted by each QPushButton to a slot that update the QLabel text.
A brief example
In the parent constructor:
connect(qpb1, &QPushButton::clicked, this, &MyClass::handleQLabel);
And the possible slot implementation:
void MyClass::handleQLabel()
{
QPushButton * qpb = qobject_cast<QPushButton*>(sender()); // Find the sender of the signal
if(qpb != nullptr)
this->myLabel->setText(qpb->text()); // Write anything you want in the QLabel
else
{
// Do what you want.
}
}
This will do the job.
Of course if you don't want use sender() (for multi-threading concerns for example) you can either create one slot by QPushButton and do the same number of connect (heavy and quite a dirty workaround), or create a subclass of QPushButton to add a custom signal to emit with an identifier of the QPushButton and get it with a slot for example.
I hope it can help :)
QLineEdit might better suit your needs in this case if you also want your data representation to follow phone number standard such as "000-000-0000". You can make it read-only, disable interaction flags if you like (but from UI/UX perspective it is better not to, since mostly there is no reason to disallow copying), and also you can set input mask you like. Given your current situation, you can base your needs on the following example:
// Set your format.
ui->lineEdit->setInputMask("000-000-0000");
// Make sure that your text would be in the format you like initially.
ui->lineEdit->setText("999-999-9999");
// Text will be not editable.
ui->lineEdit->setReadOnly(true);
// And here, you can use QSignalMapper as other members have suggested. Or you can just connect multiple buttons somehow. The choice is yours to make.
connect(ui->pushButton, &QPushButton::clicked, ui->lineEdit, [this]
{
// Just keep in mind taht when returning text, some of the mask elements might be here, too.
ui->lineEdit->setText(ui->lineEdit->text().replace("-", "") + "1");
});

Qt custom QPushButton clicked signal

I want to send two integers, string and fret, to a SLOT that will process the location of the button that was pressed. The SIGNAL and SLOT argument have to match so I am thinking I need to reimplement the QPushButton::clicked event method. Problem is I am new to Qt and could use some direction.
connect(&fretBoardButton[string][fret], SIGNAL(clicked()), this, SLOT (testSlot()));
If you use the C++11 connection syntax you can use a lambda with calls testSlot with your string and fret arguments:
connect(&fretBoard[string][fret], &QPushButton::clicked, [this, string, fret]() {
testSlot(string, fret);
});
This code creates a lambda using the [captures, ...](arguments, ...) { code } syntax. When you make the connection it captures the string and fret variable values, and will then pass them on to testSlot when the button is clicked.
There are Two approaches you could use to add the string and fret information. one is to use the sender() function to get the button which emitted the signal. you can the access fret and string if they are members of your button class so in the SLOT you would have.
MyPushButton *button = (MyPushButton *)sender();
button.getFret();
button.getString();
However since you are already subClassing QPushButton you could use a private SLOT to catch the buttonClicked signal and re-emit a signal with the right values.
In the constructor
connect(this, SIGNAL(clicked()), this, SLOT(reemitClicked()));
and then the reemit SLOT
void MyPushButton::reemitClicked()
{
emit clicked(m_fret, m_string);
}
be sure to add the appropriate private slot and public signal to you class
https://doc.qt.io/archives/qq/qq10-signalmapper.html see this artical for a good discussion on various ways to add an argument to signal.

Adding QListWidgetItem To QListWidget

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.

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.