简体   繁体   English

Qt用户可自定义的热键

[英]Qt User customizable hotkeys

I'm trying to design a Qt GUI application with user customize-able hotkeys. 我正在尝试使用用户可自定义的热键设计Qt GUI应用程序。 The main issue I'm running into is how to synchronize the hotkeys across the application since a particular hotkey (for example, copy) may be used by multiple widgets/components. 我遇到的主要问题是如何在应用程序中同步热键,因为多个小部件/组件可能使用特定的热键(例如,副本)。

My current strategy is to use a reference class which holds a list of QKeySequence objects for each different hotkey. 我目前的策略是使用一个引用类,它包含每个不同热键的QKeySequence对象列表。 Each widget would have to have a way to reference this master list and have custom implementations of low-level the keyPressEvent which would compare inputted keys vs. the hotkeys. 每个小部件都必须有一种方法来引用这个主列表,并且具有低级别keyPressEvent自定义实现,它将比较输入的密钥和热键。 I don't particularly like this strategy, though, as it requires significant re-implimentation in each widget and feels like I'm trying to re-invent the wheel. 不过,我并不特别喜欢这种策略,因为它需要在每个小部件中进行重大改造,并且感觉我正在尝试重新发明轮子。

I also tried using QAction objects which can hold QKeySequence shortcuts internally, then use these to trigger higher-level events which I can handle using slots & signals. 我还尝试使用QAction对象,它可以在内部保存QKeySequence快捷方式,然后使用它们来触发我可以使用插槽和信号处理的高级事件。 However, the main issue I have here is how to manage which slots signals get routed to. 但是,我在这里遇到的主要问题是如何管理哪些插槽信号被路由到。

For example, say I have 2 open widgets which can both receive a copy action signal. 例如,假设我有两个打开的小部件,它们都可以接收copy动作信号。 I can connect a slot for both of these to the same signal and take advantage of the single update point for shortcuts, but then things get messy since only the active widget should act on the copy signal, not both widgets. 我可以将这两个插槽连接到同一个信号,并利用快捷方式的单个更新点,但事情变得混乱,因为只有活动小部件应该对复制信号起作用,而不是两个小部件。 I can re-implement the focusOutEvent and focusInEvent handlers to connect/disconnect slots manually, but this also seems to run into the same issue above where I'm trying to re-invent the wheel and doing more work than is necessary. 我可以重新实现focusOutEventfocusInEvent处理手动连接/断开插槽,但是这也似乎碰到上述在那里我试图重新发明轮子,做更多的工作比是必要的同样的问题。

Is there an easier way around this problem? 有没有更容易解决这个问题的方法?

I don't think there is a particularly easy/non-tedious solution to this problem, but when I needed to add user-customizable hotkeys to my application, here is how I did it: 我不认为这个问题有一个特别简单/非繁琐的解决方案,但是当我需要在我的应用程序中添加用户可自定义的热键时,我就是这样做的:

1) Start with your application that has hard-coded key shortcuts, eg code like this: 1)从具有硬编码密钥快捷方式的应用程序开始,例如:

QMenu * editMenu = new QMenu;
QAction * copyItem = menu->addAction(tr("Copy"), this, SLOT(CopyData()));
copyItem->setShortcut(tr("Ctrl+C"));

2) Create a GetKeySequence() function that looks something like this: 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) Now the tedious part: grovel over all of your code, and anywhere you've specified a key-sequence explicitly (like in the third line of the code shown for step 1), wrap it with a call to GetKeySequence(), like this: 3)现在这个单调乏味的部分:对所有代码进行深入研究,以及明确指定键序列的任何地方(如步骤1中显示的代码的第三行),通过调用GetKeySequence()包装它,像这样:

copyItem->setShortcut(GetKeySequence(tr("Ctrl+C"), tr("Edit_Menu|Copy")));

4) At this point, your program's key-sequences will be customizable; 4)此时,您的程序的键序列将是可定制的; just make sure that the key-settings-file is present on disk before GUI-creation code runs. 在GUI创建代码运行之前,确保密钥设置文件存在于磁盘上。 Here's an excerpt from my program's key-mappings file (which I store as a simple ASCII text file): 这是我程序的键映射文件(我将其存储为简单的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...]

... of course one downside to this approach is that once the GUI is created, the key-bindings can't be modified "on the fly" (at least, not without a lot of additional coding). ......当然,这种方法的一个缺点是,一旦创建了GUI,就无法“动态”修改密钥绑定(至少,没有大量额外的编码)。 My program gets around this simply by closing and then re-creating all windows after the user clicks "Save and Apply" in the Edit Key Bindings dialog. 我的程序只需通过关闭然后在用户单击“编辑键绑定”对话框中的“保存并应用”后重新创建所有窗口来解决此问题。

5) An optional further step (which is some extra work up front but saves time in the long run) is to write a program (or script) that greps all the .cpp files in your program's codebase looking for calls GetKeySequence() in the code. 5)一个可选的进一步步骤(预先做一些额外的工作,但从长远来看节省时间)是编写一个程序(或脚本),它可以查看程序代码库中的所有.cpp文件,查找调用中的GetKeySequence()码。 When it finds a GetKeySequence() call, it parses out the two arguments to the call and prints them as a line in a key-bindings file with the default settings. 当它找到GetKeySequence()调用时,它会解析出调用的两个参数,并使用默认设置将它们作为一行打印在一个键绑定文件中。 This is useful because you can make this script part of your autobuild, and thereafter you'll never have to remember to manually update the default key-settings-file whenever you add a new menu item (or other key-sequence specifier) to your program. 这很有用,因为您可以将此脚本作为autobuild的一部分,此后,无论何时向您的新菜单项(或其他键序列说明符)添加新菜单项(或其他键序列说明符),您都不必记住手动更新默认键设置文件。程序。

This worked well for me, anyway. 无论如何,这对我来说效果很好。 The advantage is that you don't have to refactor your existing program at all; 优点是您根本不必重构现有程序; you can just go through it inserting GetKeySequence() as necessary while leaving the larger logic/structure of the program intact. 您可以根据需要插入GetKeySequence(),同时保持程序的较大逻辑/结构不变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM