我正在尝试使用用户可自定义的热键设计Qt GUI应用程序。我遇到的主要问题是如何在应用程序中同步热键,因为多个小部件/组件可能会使用特定的热键(例如,副本)。
我目前的策略是使用一个引用类,它包含每个不同热键的QKeySequence
个对象列表。每个小部件都必须有一种方法来引用这个主列表,并且具有低级keyPressEvent
的自定义实现,它将比较输入的密钥和热键。不过,我并不特别喜欢这种策略,因为它需要在每个小部件中进行重大改造,感觉我正在尝试重新发明轮子。
我还尝试使用QAction
对象,这些对象可以在内部保存QKeySequence
个快捷方式,然后使用这些对象触发更高级别的事件,我可以使用插槽&信号。但是,我在这里遇到的主要问题是如何管理哪些插槽信号被路由到。
例如,假设我有两个打开的小部件,它们都可以接收copy
动作信号。我可以将这两个插槽连接到同一个信号,并利用快捷方式的单个更新点,但事情变得混乱,因为只有活动小部件应该作用于复制信号,而不是两个小部件。我可以重新实现focusOutEvent
和focusInEvent
处理程序来手动连接/断开插槽,但这也似乎遇到了上面我正在尝试重新发明轮子并做更多事情的相同问题工作比必要的。
有解决这个问题的方法吗?
答案 0 :(得分:5)
我不认为这个问题有一个特别简单/非繁琐的解决方案,但是当我需要在我的应用程序中添加用户可自定义的热键时,我就是这样做的:
1)从具有硬编码密钥快捷方式的应用程序开始,例如:像这样的代码:
QMenu * editMenu = new QMenu;
QAction * copyItem = menu->addAction(tr("Copy"), this, SLOT(CopyData()));
copyItem->setShortcut(tr("Ctrl+C"));
2)创建一个看起来像这样的GetKeySequence()函数:
static QHash<QString, QKeySequence> _usersKeyPreferences;
static bool _usersKeyPreferencesLoaded = false;
QKeySequence GetKeySequence(const QString & keySequence, const QString & contextStr)
{
if (_usersKeyPreferencesLoaded == false)
{
// Oops, time to load in the user's saved custom-key settings from a file somewhere
_usersKeyPreferences = LoadUsersKeyPreferencesFromFile();
_usersKeyPreferencesLoaded = true; // so we'll only try to load the file once
}
if (_usersKeyPreferences.contains(contextStr))
{
return _usersKeyPreferences[contextStr];
}
else
{
// No user preference specified? Okay, fall back to using the
// hard-coded default key sequence instead.
return QKeySequence(qApp->translate(contextStr, keySequence));
}
}
3)现在,这是一个单调乏味的部分:对所有代码进行grovel,并在显式指定键序列的任何地方(如步骤1中显示的代码的第三行),通过调用GetKeySequence来包装它(),像这样:
copyItem->setShortcut(GetKeySequence(tr("Ctrl+C"), tr("Edit_Menu|Copy")));
4)此时,您的程序的键序列将是可自定义的;在GUI创建代码运行之前,确保密钥设置文件存在于磁盘上。这是我程序的键映射文件(我将其存储为简单的ASCII文本文件)的摘录:
Edit_Menu|Copy = Ctrl+C
Edit_Menu|Cut = Ctrl+X
Edit_Menu|Paste = Ctrl+V
[... and so on for all other menu items, etc...]
......当然,这种方法的一个缺点是,一旦创建了GUI,就无法“动态”修改密钥绑定(至少,没有大量额外的编码)。我的程序只需通过关闭然后在用户单击“编辑键绑定”对话框中的“保存并应用”后重新创建所有窗口来解决此问题。
5)可选的进一步步骤(预先进行一些额外的工作,但从长远来看节省时间)是编写一个程序(或脚本),用于查找程序代码库中的所有.cpp文件,以查找调用GetKeySequence( )在代码中。当它找到GetKeySequence()调用时,它会解析出调用的两个参数,并使用默认设置将它们作为一行打印在一个键绑定文件中。这很有用,因为您可以将此脚本作为autobuild的一部分,此后,无论何时向您的新菜单项(或其他键序列说明符)添加新菜单项(或其他键序列说明符),您都不必记住手动更新默认键设置文件。程序
无论如何,这对我来说效果很好。优点是您根本不必重构现有程序;您可以根据需要插入GetKeySequence(),同时保留程序的较大逻辑/结构。