multiple signals for one slot

雨燕双飞 提交于 2019-12-06 05:26:27

First of all, "It doesn't work" does not mean anything, and it is hard to help you if you do not say what errors you get. Then, there are few problems.

All QObject's derived classes are not copiable, it means you can not do

QWidget a;
QWidget b;
b = a; // Wrong

You should use pointers (or perhaps references).

QWidget a;
QWidget * b = new QWidget(...);
QWidget * c;
c = & a; // Ok
c = b; // Ok

Then your connect calls are wrong:

connect(&up, SIGNAL(clicked()), &up, SLOT(scrollUp()));

The third argument is the object who has the slot. up is a QPushButton, it does not have a scrollUp() slot, it is your MainWindow who does:

connect(&up, SIGNAL(clicked()), this, SLOT(scrollUp()));

(since connect is called in MainWindow's constructor this points to the current MainWindow object).

Also in C++ the single = sign means assignment, for equality comparison use =='. Andsender` is a function.

Your approach should work if implemented in the right way:

class MainWindow: public QWidget
{
    QScrollArea * scroll1;
    QScrollArea * scroll2;
    QWidget * view1;
    QWidget * view2;
    QPushButton * up1;
    QPushButton * up2;
    QPushButton * down1;
    QPushButton * down2;

public:
    MainWindow()
    {
        // Here initialize member variables.
        ...

        connect(up1, SIGNAL(clicked()), this, SLOT(scrollUp()));
        connect(up2, SIGNAL(clicked()), this, SLOT(scrollUp()));
        connect(down1, SIGNAL(clicked()), this, SLOT(scrollDown()));
        connect(down2, SIGNAL(clicked()), this, SLOT(scrollDown()));
    }

public slots:
    void scrollDown()
    {
        QScrollArea * area;
        QWidget * view;

        if(qobject_cast<QPushButton>(sender()) == down1) {
            area = & scroll1;
            view = & view1;
        } else if(qobject_cast<QPushButton>(sender()) == down2) {
            area = & scroll2;
            view = & view2;
        } else {
            // Error.
        }

        // Now `area` and `view` point to the right widgets.
        ...
    }

    void scrollUp()
    {
        // The same as before.
    }
};

Another approach would be to extract the actual scrolling instructions to a separate function:

class MainWindow: public QWidget
{
    // Same variables as before
    ...

public:
    MainWindow()
    {
        // Here initialize member variables.
        ...

        connect(up1, SIGNAL(clicked()), this, SLOT(scrollUp1()));
        connect(up2, SIGNAL(clicked()), this, SLOT(scrollUp2()));
        connect(down1, SIGNAL(clicked()), this, SLOT(scrollDown1()));
        connect(down2, SIGNAL(clicked()), this, SLOT(scrollDown2()));
    }

public slots:
    void scrollDown(QScrollArea * area, QWidget * view)
    {
        // Here you scroll over `area` and `view`.
    }

    void scrollDown1()
    {
        scrollDown(scroll1, area1);
    }

    void scrollDown2()
    {
        scrollDown(scroll2, area2);
    }

    // Again, the same for `scrollUp`.
};

There are several mistakes in your code :

  • About the sender of the signal : There is not a QObject called "sender" but a method QObject * QObject::sender() const; which returns a pointer on the sender of the signal.
  • In the if conditions : you are casting a QPushButton** into a QPushButton ((QPushButton) &sender) and you dont compare that thing with your buttons up(2) and down(2).
  • In your connections between slots and signals : the scrollUp and scrollDown slots do not belong to the QPushButton class but to your MainWindow class.

Finally, you should write something like this :

connect(&up,    SIGNAL(clicked()), this, SLOT(scrollUp()));
connect(&up2,   SIGNAL(clicked()), this, SLOT(scrollUp()));
connect(&down,  SIGNAL(clicked()), this, SLOT(scrollDown()));
connect(&down2, SIGNAL(clicked()), this, SLOT(scrollDown()));

void MainVindow::scrollDown() {
    // [...]

    QPushButton * senderButton = qobject_cast<QPushButton *>(this->sender()); 
    // QPushButton * senderButton = (QPushButton *) this->sender(); works too

    if (senderButton == &down) {
        // [...]
    }

    if (senderButton == &down2) {
        // [...]
    }

    // [...]
}

void MainVindow::scrollUp() {
    // [...]

    QPushButton * senderButton = qobject_cast<QPushButton *>(this->sender());
    // QPushButton * senderButton = (QPushButton *) this->sender(); works too

    if (senderButton == &up) {
        // [...]
    }

    if (senderButton == &up2) {
        // [...]
    }
    // [...]
}

First of all the slot can have no other arguments than the signal hands to it. Clicked has no arguments and there fore the slot can have no arguments.

I would think that the easiest way to check whether scrollArea 1 or 2 has focus and decide from that which one should move.

I also think that there is an error in your code. Shouldn't this:

if((QPushButton) &sender = down2)
{
    area=scrollArea;
    view=viewport;
}

Be this:

if((QPushButton) &sender = down2)
{
    area=scrollArea2;
    view=viewport2;
}

First of all, this is pseudo code. It won't compile, but it should contain the necessary information.

I believe this problem can be most elegantly solved using the QSignalMapper class. It allows parameterless signals from multiple senders to connect to one slot.

In the header, write something like this:

class QSignalMapper;

class MainWindow : public QMainWindow
{

public:
  void init();

public slots:
  void handleScrollButtons(int id);

private:
enum { ScrollUp1, ScrollDown1, ScrollUp2, ScrollDown2 } // just makes it more convenient to use

QSignalMapper *m_scrollbuttonhandler;
}

In the source file, write something like this

#include <QSignalMapper>

void MainWindow::init()
{
  m_scrollbuttonhandler = new QSignalMapper(this);
  m_scrollbuttonhandler->setMapping(scrollup1button, ScrollUp1);
  m_scrollbuttonhandler->setMapping(scrolldown1button, ScrollDown1);
  m_scrollbuttonhandler->setMapping(scrollup2button, ScrollUp2);
  m_scrollbuttonhandler->setMapping(scrolldown2button, ScrollDown2);
  connect(scrollup1button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));
  connect(scrolldown1button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));
  connect(scrollup2button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));
  connect(scrolldown2button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));

  connect(m_scrollbuttonhandler, SIGNAL(mapped(int)), this, SLOT(handleScrollButtons(int)));
}

void MainWindow::handleScrollButtons(int id)
{
  switch (id)
  {
    case ScrollUp1:
    // stuff to do for scrollup1button
    case ScrollDown1:
    // stuff to do for scrolldown1button
    case ScrollUp2:
    // stuff to do for scrollup2button
    case ScrollDown2:
    // stuff to do for scrolldown2button
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!