【问题标题】:Qt User customizable hotkeysQt 用户自定义热键
【发布时间】:2012-11-17 22:09:51
【问题描述】:

我正在尝试设计一个带有用户自定义热键的 Qt GUI 应用程序。我遇到的主要问题是如何在应用程序中同步热键,因为多个小部件/组件可能使用特定的热键(例如,副本)。

我目前的策略是使用一个引用类,它为每个不同的热键保存一个QKeySequence 对象列表。每个小部件都必须有一种方法来引用此主列表,并具有低级 keyPressEvent 的自定义实现,它将比较输入的键和热键。不过,我并不特别喜欢这种策略,因为它需要在每个小部件中进行大量的重新实现,感觉就像我正在尝试重新发明轮子。

我还尝试使用可以在内部保存QKeySequence 快​​捷方式的QAction 对象,然后使用它们来触发我可以使用槽和信号处理的更高级别的事件。但是,我在这里遇到的主要问题是如何管理信号路由到哪些插槽。

例如,假设我有 2 个打开的小部件,它们都可以接收 copy 动作信号。我可以将这两个的插槽连接到同一个信号,并利用单个更新点的快捷方式,但是事情变得混乱,因为只有活动的小部件应该作用于复制信号,而不是两个小部件。我可以重新实现focusOutEventfocusInEvent 处理程序以手动连接/断开插槽,但这似乎也遇到了上面我试图重新发明轮子并做更多工作而不是必要的问题.

有没有更简单的方法解决这个问题?

【问题讨论】:

    标签: c++ qt qt4


    【解决方案1】:

    我认为这个问题没有特别简单/不乏味的解决方案,但是当我需要向我的应用程序添加用户可自定义的热键时,我是这样做的:

    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) 现在是乏味的部分:对所有代码以及任何你明确指定键序列的地方(如步骤 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 文件进行 greps 查找调用 GetKeySequence( ) 在代码中。当它找到 GetKeySequence() 调用时,它会解析出调用的两个参数,并将它们打印为具有默认设置的键绑定文件中的一行。这很有用,因为您可以将此脚本作为自动构建的一部分,此后您将永远不必记住在向您添加新菜单项(或其他键序列说明符)时手动更新默认键设置文件程序。

    无论如何,这对我来说效果很好。优点是您根本不必重构现有程序;您可以根据需要插入 GetKeySequence() 来完成它,同时保持程序的更大逻辑/结构完好无损。

    【讨论】:

    • 有什么理由不能让用户自定义一个表单,将所有 QActions 的名称放在一列,键序列在另一列?然后,您可以在第二列中加载 QLineEdit,该列捕获击键,然后在对话框接受时使用 QAction::setShortcut 保存它们。我同意您在 QActions 中封装快捷键的建议。
    猜你喜欢
    • 2013-12-10
    • 2018-12-01
    • 1970-01-01
    • 2020-10-12
    • 2018-06-05
    • 1970-01-01
    • 2013-12-20
    • 1970-01-01
    • 2017-07-28
    相关资源
    最近更新 更多