PDA

View Full Version : Qt 4.2 Shortcut Management



dvmorris
25th February 2007, 18:17
Is there a good tutorial on how to create a simple shortcut manager in Qt 4.2?

I found this one on google, but it's using a lot of deprecated functions, and I don't know enough yet to update all of it: http://doc.trolltech.com/qq/qq14-actioneditor.html

Thanks for the help,
dave

fullmetalcoder
25th February 2007, 19:04
I've written such a component myself for use with my IDE project (http://edyuk.sf.net). As soon as I'll have enough time I'll release a proper package but in the meantime you can get the sources (licensed under GPL) from Edyuk's SVN (http://sourceforge.net/svn/?group_id=168260) trunk or source packages (http://sourceforge.net/project/showfiles.php?group_id=168260&package_id=191461&release_id=483870)

It includes a translation-aware shortcut manager class (QShortcutManager) (http://edyuk.svn.sourceforge.net/viewvc/edyuk/trunk/src/lib/qcumber/qshortcutmanager.h?view=log) which can register one or more actions under a given context and assign them a shorcut (either the default one or another set by the user) and a configuration dialog, QShortcutDialog (http://edyuk.svn.sourceforge.net/viewvc/edyuk/trunk/src/lib/qcumber/qshortcutdialog.h?view=log) which shows a tree of registered shortcuts and allow the user to set shortcuts through a custom input dialog (double click on tree item, type your shortcut, click on the OK button and you're done!).
The shortcuts are stored in XML files in a predefined location (you may need to change the source code to fit your needs in this domain...)

Hope this helps you. :)

dvmorris
25th February 2007, 20:05
wow this sounds like exactly what i've been looking for. I will check it out and let you know how it goes. Thanks so much for the quick reply,

Dave

dvmorris
27th February 2007, 08:09
I downloaded edjuk from sourceforge the other day but I don't see those files anywhere in there. Have they been renamed or moved?

it looks like they are supposed to be in trunk/src/lib/qcumber but I don't see them there in the local copy i have.

fullmetalcoder
27th February 2007, 12:39
I downloaded edyuk from sourceforge the other day but I don't see those files anywhere in there. Have they been renamed or moved?

it looks like they are supposed to be in trunk/src/lib/qcumber but I don't see them there in the local copy i have.
:confused: Are you sure you get the right version??? If you used SVN the files must be here (unless the checkout failed someway), if you downloaded packages they must be these of version 0.8.0-rc1.

the path to these files is : $PATH_TO_EDYUK/src/lib/qcumber where PATH_TO_EDYUK corresponds to the place where you extracted the archive or did your SVN checkout...
the files you're interested in are : qshortcutmanager.h qshortcutmanager.cpp qshortcutdialog.h qshortcutdialog.cpp

Alternatively, you can always use the SVN browse option on Sourceforge, access these files and copy there content by hand.

dvmorris
28th February 2007, 05:39
is there an example in the svn checkout that uses the shortcut manager? like a hello world kind of example or something?

fullmetalcoder
28th February 2007, 17:25
is there an example in the svn checkout that uses the shortcut manager? like a hello world kind of example or something?
Well I'm afraid I did not make any example... However it is really simple to use and here is a sample code :


#include "qshortcutmanager.h"

#include <QMenu>
#include <QAction>
#include <QMenuBar>
#include <QMainWindow>
#include <QMessageBox>
#include <QApplication>

int main(int argc, char **argv)
{
QApplication app(argc, argv);

QMainWindow main;
QShortcutManager sm;

QMessageBox ms(&main);
ms.setText( "This is a stub message box. The\n"
"only nice thing about it is that\n"
"it is triggered via a configurable\n"
"shortcut\n\n"
"So long buddy!");

QMenu help("&Help", &main);

QAction *a = new QAction("Show message box", &main);
ms.connect( a , SIGNAL( triggered() ),
SLOT ( exec() ) );

sm.registerAction(a, "Help", "CTRL+M");
help.addAction(a);

QMenu settings("&Settings", &main);

QAction *b = new QAction("Configure &shortcuts", &main);
sm.connect( b , SIGNAL( triggered() ),
SLOT ( configure() ) );

sm.registerAction(b, "Settings", "CTRL+S");
settings.addAction(b);

main.menuBar()->addMenu(&settings);
main.menuBar()->addMenu(&help);
main.show();

return app.exec();
}

Of course to compile this you need to link against Edyuk core library or to pack the need components in your project (no path relocation in the example below : it is assumed that you copied the files in your project folder...) :



QT *= xml

HEADERS += qshortcutmanager.h qshortcutdialog.h
SOURCES += qshortcutmanager.cpp qshortcutdialog.cpp

FORMS += shortcutdialog.ui


Hope this helps.

P.S : I just checked Edyuk sources and the settings storage path is incorrectly set. If you wish to use QShortcutManager within one of your application you should change some code in qshortcutmanager.cpp Replace the content of the QShortcutManager::file(const QString& lang) function with the code below :


QString QShortcutManager::file(const QString& lang)
{
return QDir::homePath()
+ QDir::separator()
+ "."
+ QApplication::applicationName()
+ QDir::separator()
+ "shortcuts_"
+ lang
+ ".xml";
}

dvmorris
28th February 2007, 18:31
Wow this example is really great. I think I have most of it integrated into my code properly but I am getting an error:


qshortcutmanager.cc: In member function 'void QShortcutManager::destroyed(QObject*)':
qshortcutmanager.cc:396: error: 'quintptr' was not declared in this scope

I have put qcumber.h into my directory, and the four files for the qshortcut stuff, but I don't really see any other files I'm supposed to include.

fullmetalcoder
28th February 2007, 18:33
Wow this example is really great. I think I have most of it integrated into my code properly but I am getting an error:


qshortcutmanager.cc: In member function 'void QShortcutManager::destroyed(QObject*)':
qshortcutmanager.cc:396: error: 'quintptr' was not declared in this scopeI have put qcumber.h into my directory, and the four files for the qshortcut stuff, but I don't really see any other files I'm supposed to include.
This is weird... quintptr is a very convinient typedef defined in qglobal.h
I have no idea why it wouldn't compile properly on your box but you can always replace any occurence with : (void*)

dvmorris
28th February 2007, 18:37
I just tried adding

#include <QtGlobal>

to my qshortcutmanager.cpp file, but it didn't seem to work. It looks like quintptr is declared in QtGlobal, but that change gives the same error.

http://stuff.mit.edu/afs/athena/software/qt-dynamic/www/qtglobal.html

dvmorris
28th February 2007, 18:41
you know what? It may be a problem that I am actually using Qt 4.1 and not Qt 4.2.

Qt 4.2 will not install on my mac for some reason, it gets two errors right at the end:

http://www.qtcentre.org/forum/f-installation-5/t-error-installing-qt-422-opensource-on-mac-os-x-5867.html

fullmetalcoder
28th February 2007, 18:43
I just tried adding

#include <QtGlobal>

to my qshortcutmanager.cpp file, but it didn't seem to work. It looks like quintptr is declared in QtGlobal, but that change gives the same error.

http://stuff.mit.edu/afs/athena/software/qt-dynamic/www/qtglobal.html

it is documented here : http://stuff.mit.edu/afs/athena/software/qt-dynamic/www/qtglobal.html#quintptr-typedef

and should be defined in any context provided that you have ANY Qt header included in the source. This is the case in qshortcutmanager.cpp so my only suggestion is to try #include "qglogal.h" and if it still doesn't work replace the occurence or add the typedef by hand in the source file :

typedef void* quintptr;

fullmetalcoder
28th February 2007, 18:58
you know what? It may be a problem that I am actually using Qt 4.1 and not Qt 4.2.
That's absolutely right and I hadn't spotted it... :o I'll place some macro'ed typedef to avoid troubles.

dvmorris
28th February 2007, 21:19
does it save and load the shortcut config files automatically, or do i need to write that in somewhere as another action?

Also, I just had the strangest problem, and I have no idea what really was happening. When I create the configureShortcuts action, if I use the word "config" or "configure" in the text, it won't load the menu into the menuBar.


manageShortcutsAct = new QAction(tr("confshortcuts"),this);
sm->connect( manageShortcutsAct , SIGNAL( triggered() ), SLOT ( configure() ) );
sm->registerAction(manageShortcutsAct, "Configure Shortcuts", "CTRL+M");
that works.

manageShortcutsAct = new QAction(tr("Config Shortcuts"),this);
sm->connect( manageShortcutsAct , SIGNAL( triggered() ), SLOT ( configure() ) );
sm->registerAction(manageShortcutsAct, "Configure Shortcuts", "CTRL+M");
that does not. I guess it's because I'm using the part of the phrase from the registerAction function. does that make sense?

fullmetalcoder
28th February 2007, 21:45
does it save and load the shortcut config files automatically, or do i need to write that in somewhere as another action?

If you modified qshortcutmanager.cpp, called QApplication::setApplicatioName() and ensured that the settings directory ( QDir::homePath + "/." + QApplication::applicationName() ) exists then saving/reloading should be done flawlessly but as the code you got doesn't do all these steps automatically I guess it does not work properly yet...;)



Also, I just had the strangest problem, and I have no idea what really was happening. When I create the configureShortcuts action, if I use the word "config" or "configure" in the text, it won't load the menu into the menuBar.


manageShortcutsAct = new QAction(tr("confshortcuts"),this);
sm->connect( manageShortcutsAct , SIGNAL( triggered() ), SLOT ( configure() ) );
sm->registerAction(manageShortcutsAct, "Configure Shortcuts", "CTRL+M");that works.

manageShortcutsAct = new QAction(tr("Config Shortcuts"),this);
sm->connect( manageShortcutsAct , SIGNAL( triggered() ), SLOT ( configure() ) );
sm->registerAction(manageShortcutsAct, "Configure Shortcuts", "CTRL+M");that does not. I guess it's because I'm using the part of the phrase from the registerAction function. does that make sense?
You may want to take a look at the doc (only Doxygen style comments in the source ATM) for this... Actually QShortcutManager doesn't interfere with the action names but only modify the assigned shortcuts. the parameters passed to registerAction() are as follow :

a QAction to be managed
a QString indicating the context of the action (this is used when storing settings and populating the tree widget of the shortcut dialog ( a '/' in the name indicate a category separator i.e nested categories visible in the tree)
a QString indicating the default shortcut. When no shortcuts is set in the configuration it is used. Also when conflicts are encountered when setting shortcuts through the dialog, it may be used as a fallback value.The action name is set through the QAction constructor or the setText() method. The menu name is set through the QMenu constructor (and possibly a method but I can't remember which one...:o)

Do you mean that using the same text as action name and context causes a bug? Well, I guess I have to check this. Anyway you should indeed avoid using the same text in action name and context because the shortcut dialog would get ugly... As explained above context is a category (meant to contain several actions)...

Hope this helps you.

dvmorris
1st March 2007, 01:12
I tried setting the applicationName to "topmod" in my main function, and I created the directory

/Users/dave/.topmod/shortcuts/

with no files in it. I have one shortcut set to register into the shortcutmanager class, and it gives me an error when i debug saying:

"Unable to access shortcuts..."

I even tried this line instead of all that Qt::homeDir() stuff...

return "/Users/dvmorris/.topmod/shortcuts/shortcuts_en_us.xml";

none of that seemed to work either.


*sorry. it works fine now. Thanks for your help again...

dvmorris
1st March 2007, 08:46
How do I use the numbers as shortcuts? I can't seem to get them to work by themselves without adding a CTRL or ALT key before them.

For example, I have a QTabWidget with five pages and I setup five modes like this


modeBasicsAct = new QAction(QIcon(":/images/mode_basics.png"), tr("&Basics"), this);
sm->registerAction(modeBasicsAct, "Modes", "1");
modeBasicsAct->setStatusTip(tr("Switch to Basics Mode"));
connect(modeBasicsAct, SIGNAL(triggered()), this, SLOT(switchMode(0)));

and I have a slot function defined like this:


void MainWindow::switchMode(int pageId){
modesTabWidget->setCurrentIndex(pageId);
}

The 1,2,3,4,5 shortcuts I set with registerAction do not switch the TabWidget's currentIndex to 0,1,2,3,or 4, like I write in the slot function.

Do you have any ideas as to why that won't work? I also noticed that it doesn't seem to work with any other shortcuts like CTRL+L. Maybe this has nothing to do with the numbers problem. anyways, sorry to bother you so much. I really appreciate your help. Your shortcut manager is phenomenal.

fullmetalcoder
1st March 2007, 08:58
How do I use the numbers as shortcuts? I can't seem to get them to work by themselves without adding a CTRL or ALT key before them.

For example, I have a QTabWidget with five pages and I setup five modes like this


modeBasicsAct = new QAction(QIcon(":/images/mode_basics.png"), tr("&Basics"), this);
sm->registerAction(modeBasicsAct, "Modes", "1");
modeBasicsAct->setStatusTip(tr("Switch to Basics Mode"));
connect(modeBasicsAct, SIGNAL(triggered()), this, SLOT(switchMode(0)));and I have a slot function defined like this:


void MainWindow::switchMode(int pageId){
modesTabWidget->setCurrentIndex(pageId);
}The 1,2,3,4,5 shortcuts I set with registerAction do not switch the TabWidget's currentIndex to 0,1,2,3,or 4, like I write in the slot function.

Do you have any ideas as to why that won't work? I also noticed that it doesn't seem to work with any other shortcuts like CTRL+L. Maybe this has nothing to do with the numbers problem. anyways, sorry to bother you so much. I really appreciate your help. Your shortcut manager is phenomenal.
The shortcut management provided is just a (very :D) convinient wrapper over Qt shortcut mechanism but it doesn't modify it... AFAIK shortcuts NEED modifiers to work because other keys are generally forwarded to other widgets and this is especially true if you have, say, any kind of input widget in your current tab...

Besides your slots registration is wrong : the SLOT() macro is passed a qualified function name ( name + parameters types) and no arguments... That's probably why your code is failing. If you use a special slot for each mode switching and make sure that the child widgets don't accept number keys input it should work...

dvmorris
1st March 2007, 10:04
ok I understand a little better now. I rewrote the slot functions so there is a unique one for each of the five TabWidget Pages. here is one of them:



//inside MainWindow class in .h file
private slots:
void switchBasicsMode();

//in cpp file
void MainWindow::switchBasicsMode(){
modesTabWidget->setCurrentIndex(0);
}


modeBasicsAct = new QAction(QIcon(":/images/mode_basics.png"), tr("&Basics"), this);
sm->registerAction(modeBasicsAct, "Modes", "CTRL+9");
modeBasicsAct->setStatusTip(tr("Switch to Basics Mode"));
connect(modeBasicsAct, SIGNAL(triggered()), this, SLOT(switchBasicsMode()));

but that doesn't seem to work either. the signals slots demo here: http://doc.trolltech.com/4.2/signalsandslots.html is not very helpful either.

The shortcut doesn't seem to do anything. But all the shortcuts for actions that are attached to menuBar items work fine (except single numbers and CTRL+Q). Do I just need to create a dummy menuBar for the five modes so that the shortcuts will do something?

fullmetalcoder
1st March 2007, 18:48
The shortcut doesn't seem to do anything. But all the shortcuts for actions that are attached to menuBar items work fine (except single numbers and CTRL+Q). Do I just need to create a dummy menuBar for the five modes so that the shortcuts will do something?
I forgot to point this out as well... Qt, as far as I tested, forward shortcuts to VISIBLE actions only... If you don't attach your actions to menubars, toolbars, buttons or anything that can manage them, then the shortcut will never trigger the actions (except maybe if you play with the shortcut context (http://doc.trolltech.com/4.1/qaction.html#shortcutContext-prop) but even that may fail...)
(http://doc.trolltech.com/4.1/qaction.html#shortcutContext-prop)

dvmorris
5th March 2007, 21:48
I'm attempting to compile this program on Windows, and it gives the following error:


debug\moc_qshortcutdialog.cpp:40: error: definition of static data member 'QShortcutDialog::staticMetaObject' of dllimport'd class.
debug\moc_qshortcutdialog.cpp:40: warning: 'QShortcutDialog::staticMetaObject' defined locally after being referenced with dllimport linkage
mingw32-make[1]: *** [debug\moc_qshortcutdialog.o] Error 1
mingw32-make[1]: Leaving directory `C:/Documents and Settings/dave/Desktop/thesis/topmod/trunk'
mingw32-make: *** [debug] Error 2

I found a post that you answered about a similar problem here:

http://www.qtcentre.org/forum/f-qt-software-16/t-announce-ideality-001-library-3286.html

but I'm not sure how to implement your fix in this case. Do you have any suggestions? Thanks for the help,
dave