Qt is a great development framework. I’ve been using it for years and I’m still discovering new & improved ways to do things. For example, I had a rather clunky bit of code to put menu items in the help menu which would open up various pages on my website.
myMainWindow.h
1 2 3 4 5 6 7 |
private slots: void slotWebsite( void ); void slotForums( void ); private: void helpMenuOpenURL( const QString &inURL ); void setupMenus( void ); |
myMainWindow.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// Set up actions and menus void myMainWindow::setupMenus( void ) { QMenuBar *theMenuBar = menuBar(); QMenu *helpMenu = theMenuBar->addMenu( tr( "Help" ) ); QAction *website = new QAction( tr( "Website" ), this ); connect( website, SIGNAL(triggered()), this, SLOT(slotWebsite()) ); helpMenu->addAction( website ); QAction *forums = new QAction( tr( "Support Forums Online" ), this ); connect( forums, SIGNAL(triggered()), this, SLOT(slotForums()) ); helpMenu->addAction( forums ); } // slotWebsite void myMainWindow::slotWebsite( void ) { helpMenuOpenURL( "http://example.com" ); } // slotForums void myMainWindow::slotForums( void ) { helpMenuOpenURL( "http://example.com/forum/" ); } // Open a given URL in the default browser // NOTE: Do not pass inURL from user input unless you've validated it... void myMainWindow::helpMenuOpenURL( const QString &inURL ) { QApplication::setOverrideCursor( Qt::BusyCursor ); #ifdef Q_WS_X11 // NOTE: I don't compile for Linux, so this is untested QProcess::startDetached( "kfmclient exec \"" + inURL + '"' ); #elif defined( Q_WS_MAC ) QProcess::startDetached( "open \"" + inURL + '"' ); #elif defined( Q_WS_WIN ) QProcess::startDetached( "rundll32.exe url.dll,FileProtocolHandler " + inURL ); #endif QApplication::restoreOverrideCursor(); } |
Wow. That’s chunky code. Any additional menu items required a declaration of another one line function which of course meant modifying the header and the cpp file. Messy.
Then I discovered QSignalMapper which let me tie a QString to a given QAction so I would only need one slot to handle any URL opening.
This allowed me to simplify:
myMainWindow.h
1 2 3 4 5 |
private slots: void slotHelpMenuOpenURL( const QString &inURL ); private: void setupMenus( void ); |
myMainWindow.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// Set up actions and menus void myMainWindow::setupMenus( void ) { QSignalMapper *signalMapper = new QSignalMapper( this ); QMenuBar *theMenuBar = menuBar(); QMenu *helpMenu = theMenuBar->addMenu( tr( "Help" ) ); QAction *website = new QAction( tr( "Website" ), this ); signalMapper->setMapping( website, "http://example.com" ); connect( website, SIGNAL(triggered()), signalMapper, SLOT(map()) ); helpMenu->addAction( website ); QAction *forums = new QAction( tr( "Support Forums Online" ), this ); signalMapper->setMapping( forums, "http://example.com/forum/" ); connect( forums, SIGNAL(triggered()), signalMapper, SLOT(map()) ); helpMenu->addAction( forums ); connect( signalMapper, SIGNAL(mapped(const QString &)), SLOT(slotHelpMenuOpenURL(const QString &)) ); } // Open a given URL in the default browser // NOTE: Do not pass inURL from user input unless you've validated it... void myMainWindow::slotHelpMenuOpenURL( const QString &inURL ) { QApplication::setOverrideCursor( Qt::BusyCursor ); #ifdef Q_WS_X11 // NOTE: I don't compile for Linux, so this is untested QProcess::startDetached( "kfmclient exec \"" + inURL + '"' ); #elif defined( Q_WS_MAC ) QProcess::startDetached( "open \"" + inURL + '"' ); #elif defined( Q_WS_WIN ) QProcess::startDetached( "rundll32.exe url.dll,FileProtocolHandler " + inURL ); #endif QApplication::restoreOverrideCursor(); } |
Much cleaner code and it’s easier to maintain and modify. I’ve since found another couple of places in my code that benefit from QSignalMapper since it handles more than QString. It also lets you associate ints, QWidgets, and QObjects to a QAction.
Hope you found it useful. Please let me know!