0

I'm pretty new to QT and try to add a button (which emits a signal on click) during runtime. I added a slot for the adding itself but it didn't work. For testing-purposes I've put a printf("Hello World"); in my code to see when the method is called.

Strangely I get my "Hello World" only when I close the program... For testing purposes I've called the add-Method in my main. If I click on the button nothing happens. As I remove it from the main I don't even get that any more...

Maybe someone can tell me what I did wrong?

ButtonCreator.h

QT_BEGIN_NAMESPACE
class QAction;
class QGroupBox;
class QPushButton;
class QVBoxLayout;
class QGridLayout;

QT_END_NAMESPACE

class ButtonCreator : public QWidget {
    Q_OBJECT

public:
    ButtonCreator();

private:
    void createGridGroupBox();
    unsigned int buttoncount; //Number of current buttons


    QVBoxLayout *mainLayout; //Main Window
    QGroupBox *gridGroupBox; //Window with Buttons
    QGridLayout *layout; //Button-Layout

    QPushButton* getAddButton();
public slots:
    int addButton(QIcon *icon = 0); //Add Button
};

ButtonCreator.cpp

#include <QtGui>
#include "ButtonCreator.h"


ButtonCreator::ButtonCreator() {
    createGridGroupBox(); //Create Window

    mainLayout = new QVBoxLayout;
    mainLayout->addWidget(gridGroupBox);
    mainLayout->addWidget(getAddButton());
    setLayout(mainLayout);

}

void ButtonCreator::createGridGroupBox() {
    gridGroupBox = new QGroupBox();
    layout = new QGridLayout;    
    gridGroupBox->setLayout(layout);
}

int ButtonCreator::addButton(QIcon *icon) {
    printf("Hello World");
    QPushButton *button = new QPushButton();    

if (icon != 0) {
    button->setIcon(*icon);
}
    layout->addWidget(button, 0, buttoncount);    
    buttoncount++;

    button->show();            //Adding that didn't change anything
    gridGroupBox->update();    //Adding that didn't change anything
    layout->update();          //Adding that didn't change anything


    return buttoncount;
}


QPushButton* ButtonCreator::getAddButton() {
    QPushButton *addbutton = new QPushButton();

    QPixmap pixmap(100, 100);
    pixmap.fill(QColor("blue"));
    QIcon icon = QIcon(pixmap);

    connect(addbutton, SIGNAL(clicked()), this, SLOT(addButton(&icon)));
    return addbutton;
}

Related to the Signal I want to add I am a bit confused. It's easy to find how slots are defined but related to Signals I'm even unsure if I understood the difference.

For example if I press a button it sends the absolute number of buttons as Signal. Is it correct to do it like:

ButtonCreator.h

class ButtonCreator : public QWidget {
..
signals:
void getAbsButtons(int anyPara); 
..
}

And to add it with:

connect(newButton, SIGNAL(clicked()), this, SLOT(getAbsButtons(para)));

At http://www.qtcentre.org/threads/19493-creating-custom-signal they have a similar discussion. It puzzles me I am treading the Signal like a slot...

Qohelet
  • 1,459
  • 4
  • 24
  • 41

1 Answers1

2

Because your SLOTaddButton(&icon) is never excuted at runtime.

While a SLOT can be taken as a regular C++ function, the return value of it can only be retrieved when it is called as a function. In addition, there is no magic in SIGNAL & SLOT mechanism, eventually the moc will replace the connections with C++ codes according to their function signature. It's better to keep in mind that the argument number of SLOT shouldn be less than that of SIGNAL.

For example, these connections will work:

connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));

But this one won't:

connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));

Because this SLOT SLOT(objectDestroyed(QObject*) will be expecting a QObject that the signal will not send. If you use Qt creator, a runtime error of this connection will be reported.


As for your second question, if you'd like to send a clicking SIGNAL accompanied with some arguments, there are at least 3 ways to achieve what you want, and what you mentioned in OP connect(newButton, SIGNAL(clicked()), this, SLOT(getAbsButtons(para))); won't work because: First, it's a failed connection. Second, the clicked() SIGNAL doesn't send any information, it just serve as a trigger. If you want some SIGNAL like clicked(int) to be sent from QPushButton as you click it, you may:

  1. Subclass the QPushButton and reimplement the mouse click event to make it EMIT clicked(int), or

  2. connect SIGNAL clicked() to SLOT onClicked(). Inside onCLicked(), EMIT another SIGNAL toFinalDestination(int) to SLOT FinalDestination(int), or

  3. Use QSignalMapper: enter image description here

For more information about QSignalMapper, check this link and the document.


[Edit]:

A SLOT function can be called as a regular C++ function (compilation time) or as a SLOT (runtime). The function connect() is to make SLOT fucntion accessible through SIGNAL at run time, hence you only need to pass the type of arguments to connect(), and the varaibles sent will be decided at runtime (signal emitted). From your original post, I think you mistreated your slots as normal function in connect(), it might be your blind spot.

Tay2510
  • 5,748
  • 7
  • 39
  • 58
  • The icon is used, unfortunately I haven't copied the line. I've read the documentation where you got the examples from: http://qt-project.org/doc/qt-4.8/signalsandslots.html - after removing the parameter from `addButton()` it worked. But I still don't get it... Do I need to modify the `clicked()`-Signal in some ways to be able to create an add-Slot with a parameter? And how? Related to Subclassing: I haven't tried to subclass a qt-object yet. Is there something I consider? – Qohelet May 30 '14 at 02:43
  • The original `QPushButton` class emits only `clicked()` as it is clicked, so you have to do something to work around. If you go subclassing way, you need declare a new signal clicked(int) and emit it, which means you need reimplement mouse click event. Personally I prefer use `QSignalMapper` or something trivial like option 2. – Tay2510 May 30 '14 at 02:51
  • 1
    @Qohelet I've edited my post, appending something which might help you clarify the concept. – Tay2510 May 30 '14 at 03:27
  • Ok, I got that with the slot, it was really helpful, thank you! But related to the signal. Is it possible to define a SIGNAL in a class and connect it to a button? Like when I click on a button it emits this specified signal? – Qohelet Jun 01 '14 at 16:20
  • @Qohelet Yes, you can connect a SIGNAL to another SIGNAL, it's legitimate in Qt. But just like the example, the argument number of second SIGNAL cannot exceed the argument number of the first SIGNAL. – Tay2510 Jun 01 '14 at 16:48
  • The issue is more about the implementation of a Signal. I just find the prototypes online and in documentations. But till now I haven't seen any actual fully implemented signal-method? – Qohelet Jun 01 '14 at 18:26
  • 1
    @Qohelet SIGNAL is not for implementation, we only implement SLOTs. For SIGNAL, you just need to give it a function signature and `emit` it when the time is right. SLOT is the one who really does jobs, and Qt use SIGNAL to decide **Which** SLOT (by valid connection, we have been discussing this over and over again) and **When** (when you `emit` the signal) it should be executed. [Check this link](http://stackoverflow.com/questions/2008033/how-does-qt-implement-signals-and-slots), it might be helpful for you. – Tay2510 Jun 01 '14 at 19:25