在程序中,通常一个按键被点击时,都会自动调用其相应的槽函数,这就不可避免地需要为每个按键定义一个槽函数。而当这些按键功能相近时,可以考虑使用一个槽函数来响应所有的按键点击信号,这可以避免定义过多的槽函数带来的累赘。但这产生了一个问题,即当多个信号与同一槽函数相连接,在信号触发时,槽函数并不能识别信号究竟是哪个按键触发的。
以下程序展示一个数字键盘来阐述信号映射的原理:
numerickeypad.h
- #ifndef _NUMERICKEYPAD_H_
- #define _NUMERICKEYPAD_H_
- #include <QWidget>
- class QPushButton;
- class QLineEdit;
- class NumericKeypad : public QWidget
- {
- Q_OBJECT
- public:
- NumericKeypad( QWidget * = 0 );
- private slots:
- void keyClicked( const QString & );
- void setText( const QString & );
- signals:
- void textChanged( const QString & );
- private:
- QList< QPushButton * > keys;
- QList< QString > allKeySymbol;
- QString m_text;
- QLineEdit *lineEdit;
- };
- #endif
为创建数字键盘,通常的做法是将所有的按键放在 QGridLayout中:
- layout->addWidget( key1, 0, 0 );
- layout->addWidget( key2, 0, 1 );
- ...
- layout->addWidget( key0, 3, 1 );
- layout->addWidget( keyClear, 3, 2 );
- ...
- for( int r = 0; r < 4; ++r )
- for( int c = 0; c < 3; ++c )
- {
- QString keySymbol = allKeySymbol.at( r * 3 + c );
- QPushButton *key = new QPushButton( keySymbol );
- layout->addWidget( key, r, c );
- keys.append( key );
- ...
- }
- ...
完整的代码:
numerickeypad.cpp
- #include "numerickeypad.h"
- #include <QtGui>
- NumericKeypad::NumericKeypad( QWidget *parent )
- :QWidget( parent )
- {
- allKeySymbol << "1" << "2" << "3"
- << "4" << "5" << "6"
- << "7" << "8" << "9"
- << "." << "0" << "C";
- QGridLayout *layout = new QGridLayout;
- QSignalMapper *mapper = new QSignalMapper( this );
- for( int r = 0; r < 4; ++r )
- for( int c = 0; c < 3; ++c )
- {
- QString keySymbol = allKeySymbol.at( r * 3 + c );
- QPushButton *key = new QPushButton( keySymbol );
- keys.append( key );
- layout->addWidget( key, r, c );
- mapper->setMapping( key, keySymbol );
- }
- foreach( QPushButton *key, keys )
- connect( key, SIGNAL( clicked() ), mapper, SLOT( map() ) );
- connect( mapper, SIGNAL( mapped( QString ) ),
- this, SLOT( keyClicked( QString ) ) );
- lineEdit = new QLineEdit;
- lineEdit->setAlignment( Qt::AlignRight );
- lineEdit->setReadOnly( true );
- QVBoxLayout *mainLayout = new QVBoxLayout( this );
- mainLayout->addWidget( lineEdit );
- mainLayout->addLayout( layout );
- }
- void NumericKeypad::keyClicked( const QString &newText )
- {
- if( newText == "C" )
- setText( "" );
- else
- setText( m_text + newText );
- }
- void NumericKeypad::setText( const QString &text )
- {
- if( text == m_text )
- return;
- m_text = text;
- lineEdit->setText( text );
- emit textChanged( m_text );
- }
创建按键的信号映射:
- 调用QSignalMapper的setMapping( QObject *, const QString & )函数,将按键与相应的QString映射起来。
- 在所有按键与QString的映射建立起来之后,将按键的clicked()信号与QSignalMapper的map()槽函数连接。
- 将QSignalMapper的mapped( const QString & )信号与this的槽函数keyClicked( const QString & )连接。
当某一按键被点击时,其clicked()信号发送时,导致QSignalMapper的槽函数map()被调用,这将会引起QSignalMapper的信号mapped( const QString &)被发送,这个信号将与按键对应的QString对象作为参数发送给this的keyClicked( const QString & )槽函数。这样,keyClicked就能根据接收到的QString的内容来判断发送信号的是哪一个按键了。
当按下的键是 C 时,将会清空QLineEdit显示的文本。
main.cpp
- #include "numerickeypad.h"
- #include <QApplication>
- int main(int argc, char **argv )
- {
- QApplication app( argc, argv );
- NumericKeypad keypad;
- keypad.show();
- return app.exec();
- }