2012-07-04 3 views
1

Для моего GUI я хотел бы иметь две пары кнопок, которые прокручиваются вверх и вниз по прокрутке. Первый набор кнопок должен работать на say scrollarea1, а второй набор кнопок должен работать на scrollarea2. Виджеты, которые я помещал в scrollarea, называются 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))); 

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

+0

Возможный дубликат [Могу ли я иметь один слот для нескольких сигналов?] (https://stackoverflow.com/questions/24313530/can-i-have-one-slot-for-several-signals) – ymoreau

ответ

5

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

производные классы Все 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++ одиночный знак = означает назначение, для сравнения использования равенства =='. And отправитель является функцией.

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

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

Есть несколько ошибок в коде:

  • О отправителе сигнала: Существует не QObject называется «sender», а метод QObject * QObject::sender() const; который возвращает указатель на отправителе сигнала.
  • В случае условия: вы Кастинг 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) { 
     // [...] 
    } 
    // [...] 
} 
0

Прежде всего слот не может иметь никаких других аргументов, чем сигнал руки к нему. Нажатие не имеет аргументов, и поэтому в слоте нет аргументов.

Я бы подумал, что самый простой способ проверить, имеет ли scrollArea 1 или 2 фокус и решить, с чего двигаться.

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

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

Будь это:

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

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

Я считаю, что эта проблема может быть изящно решена с использованием класса 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 
    } 
}