несколько сигналов для одного слота

Для моего графического интерфейса я хотел бы иметь две пары кнопок, которые прокручивают вверх и вниз область прокрутки. Первый набор кнопок должен работать, скажем, в области прокрутки1, а второй набор кнопок должен работать в области прокрутки2. Виджеты, которые я поместил в область прокрутки, называются viewport1 и viewport2. Поскольку оба набора кнопок должны делать одно и то же (прокручивать вверх и вниз), я подумал, что сделаю два слота с именами scrollUp и scrollDown, которые будут обрабатывать прокрутку для обоих наборов кнопок. К сожалению, я не могу сделать эту работу и нуждаюсь в некоторой помощи. Я пробовал следующее:

QPushButton up;
QPushButton down;
QPushButton up2;
QPushButton down2;

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

void MainWindow::scrollDown()
{
QScrollArea area;
QWidget view;

if((QPushButton) &sender = down)
{
    area=scrollArea;
    view=viewport;
}
if((QPushButton) &sender = down2)
{
    area=scrollArea;
    view=viewport;
}
int curpos = area.verticalScrollBar()->value();
area.verticalScrollBar()->setValue(curpos+15);
int newpos = area.verticalScrollBar()->value();
QPoint topLeft = area.viewport()->rect().topLeft();
view.move(topLeft.x(),topLeft.y()-(newpos));
}

void MainWindow::scrollUp()
{
QScrollArea area;
QWidget view;

if((QPushButton) &sender = up)
{
    area=scrollArea;
    view=viewport;
}
if((QPushButton) &sender = up2)
{
    area=scrollArea2;
    view=viewport2;
}
int curpos = area.verticalScrollBar()->value();
area.verticalScrollBar()->setValue(curpos-15);
int newpos = area.verticalScrollBar()->value();
QPoint topLeft = area.viewport()->rect().topLeft();
view.move(topLeft.x(),topLeft.y()-(newpos));
}

Но это не работает по нескольким причинам. Я также попытался передать слоту некоторые аргументы, например:

connect(&up,SIGNAL(clicked()),&up,SLOT(scrollUp(scrollarea1,viewport1)));
connect(&up2,SIGNAL(clicked()),&up,SLOT(scrollUp(scrollarea2,viewport2)));

Но опять безуспешно. Кто-нибудь может мне помочь?


person Frank    schedule 04.07.2012    source источник
comment
Возможный дубликат Могу ли я иметь один слот для нескольких сигналов?   -  person ymoreau    schedule 08.12.2017


Ответы (4)


Прежде всего, "Это не работает" ничего не значит, и вам трудно помочь, если вы не скажете, какие ошибки вы получаете. Тогда проблем немного.

Все производные классы QObject не копируются, это означает, что вы не можете

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

Вы должны использовать указатели (или, возможно, ссылки).

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

Тогда ваши connect вызовы неверны:

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

Третий аргумент — это объект, у которого есть слот. up - это QPushButton, у него нет слота scrollUp(), это ваш MainWindow, который имеет:

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

(поскольку connect вызывается в конструкторе MainWindow, this указывает на текущий объект MainWindow).

Также в C++ одиночный знак = означает присваивание, для сравнения на равенство используйте =='. Andsender` — это функция.

Ваш подход должен работать, если он реализован правильно:

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.
    }
};

Другим подходом было бы выделение фактических инструкций по прокрутке в отдельную функцию:

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`.
};
person Claudio    schedule 04.07.2012
comment
Нужно изменить qobject_cast‹QPushButton› на qobject_cast‹QPushButton *›. - person Magnetron; 13.06.2018

В вашем коде есть несколько ошибок:

  • Об отправителе сигнала: существует не QObject с именем "sender", а метод QObject * QObject::sender() const;, который возвращает указатель на отправителя сигнала.
  • В условиях if: вы переводите QPushButton** в QPushButton ((QPushButton) &sender) и не сравниваете эту вещь со своими кнопками up(2) и down(2).
  • В ваших связях между слотами и сигналами: слоты scrollUp и scrollDown принадлежат не классу QPushButton, а вашему классу MainWindow.

Наконец, вы должны написать что-то вроде этого:

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) {
        // [...]
    }
    // [...]
}
person air-dex    schedule 04.07.2012

Во-первых, у слота не может быть никаких других аргументов, кроме сигнальных рук. Clicked не имеет аргументов, поэтому у слота не может быть аргументов.

Я думаю, что самый простой способ проверить, имеет ли фокус scrollArea 1 или 2, и решить, какой из них следует перемещать.

Я также думаю, что в вашем коде есть ошибка. Не должно ли это:

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

Будь это:

if((QPushButton) &sender = down2)
{
    area=scrollArea2;
    view=viewport2;
}
person Gisli    schedule 04.07.2012

Во-первых, это псевдокод. Он не будет компилироваться, но должен содержать необходимую информацию.

Я считаю, что эту проблему можно наиболее элегантно решить с помощью класса QSignalMapper. Это позволяет безпараметрическим сигналам от нескольких отправителей подключаться к одному слоту.

В шапке напишите что-то вроде этого:

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;
}

В исходном файле напишите что-то вроде этого

#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
  }
}
person marcbf    schedule 17.06.2016