2012-04-27 40 views
6

搜索这里和其他放置像qtcentre我见过这个问题已经出现,但似乎无法得到它的工作。我有一个主窗口小部件了QSplitter其中包含两个窗格小部件(从子类QFrame)。每个窗格都有一个菜单栏,具有相同的关联质量控制/快捷方式QT - QAction :: eventFilter:模糊的快捷方式超负荷

我试过的ShortcutContexts所有组合与setShortcutContext()

WindowShortcutApplicationShortcut环境得到所需要的 “暧昧快捷超载”。

虽然WidgetShortcutWidgetWithChildrenShortcut都无能为力。

如果我手动激活菜单,他们当然工作得很好。 我也尝试着重于重载enterEvent()的父窗口小部件。

任何想法?

谢谢。

main.h
#include <QMainWindow> 
#include <QFrame> 

QT_BEGIN_NAMESPACE 
class QAction; 
class QMenu; 
class QHBoxLayout; 
class QSplitter; 
class QWidget; 
QT_END_NAMESPACE 

class Pane: public QFrame 
{ 
    Q_OBJECT 

    public: 
    Pane(QWidget* parent = 0); 

    protected: 
    void   enterEvent(QEvent *event); 
    void   leaveEvent(QEvent *event); 

    private: 
    void   createMenus(); 

    QMenuBar *  m_menuBar; 

    private Q_SLOTS: 
    void   split(); 
}; 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    MainWindow(); 

private: 
    void createActions(); 
    void createMenus(); 
    void setupUi(QMainWindow *MainWindow); 

    QMenu *fileMenu; 
    QAction *exitAct; 

    QWidget *centralwidget; 
    QHBoxLayout *horizontalLayout; 
    QSplitter *splitter; 
    QFrame *frame; 
    QFrame *frame_2; 
}; 

main.cpp中
#include <iostream> 
#include <QApplication> 
#include <QMainWindow> 
#include <QSplitter> 
#include <QFrame> 
#include <QMenuBar> 
#include <QBoxLayout> 
#include "main.h" 

Pane::Pane(QWidget* parent) : 
    QFrame(parent) 
{ 
    setFrameShape(QFrame::StyledPanel); 
    setFrameShadow(QFrame::Raised); 

    QVBoxLayout *layout = new QVBoxLayout; 
    QFrame::setLayout(layout); 

    m_menuBar = new QMenuBar; 
    QWidget *m_widget = new QWidget; 

    layout->addWidget(m_menuBar); 
    layout->addWidget(m_widget); 
    layout->setContentsMargins(2, 2, 2, 2); 

    show(); 

    createMenus(); 
} 

void 
Pane::enterEvent(QEvent *event) 
{ 
    std::cout << "enter" << std::endl; 
    setFocus(); 
    setStyleSheet("QFrame { border: 1px solid rgb(127, 127, 0); }"); 
    if (focusWidget()) 
     std::cout << "focuswidget = " << focusWidget()->objectName().toUtf8().constData() << std::endl; 
} 

void 
Pane::leaveEvent(QEvent *event) 
{ 
    std::cout << "leave" << std::endl; 
    clearFocus(); 
    setStyleSheet("QFrame { border: 1px solid rgb(64, 64, 64); }"); 
} 

void 
Pane::split() 
{ 
    std::cout << "split pane" << std::endl; 
} 

void 
Pane::createMenus() 
{ 
    QMenu *paneMenu = m_menuBar->addMenu(tr("&Pane")); 

    QAction *paneSplitAct = new QAction(tr("Split"), this); 
    paneSplitAct->setShortcut(Qt::Key_S); 
    paneSplitAct->setShortcutContext(Qt::WidgetWithChildrenShortcut); 
    paneSplitAct->setStatusTip(tr("Split Pane")); 
    connect(paneSplitAct, SIGNAL(triggered()), this, SLOT(split())); 
    paneMenu->addAction(paneSplitAct); 
} 

MainWindow::MainWindow() 
{ 
    setupUi(this); 

    createActions(); 
    createMenus(); 
} 

void MainWindow::createActions() 
{ 
    exitAct = new QAction(tr("E&xit"), this); 
    exitAct->setShortcuts(QKeySequence::Quit); 
    exitAct->setStatusTip(tr("Exit the application")); 
    connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); 
} 

void MainWindow::createMenus() 
{ 
    fileMenu = menuBar()->addMenu(tr("&File")); 
    fileMenu->addAction(exitAct); 
} 


void MainWindow::setupUi(QMainWindow *MainWindow) 
{ 
    if (MainWindow->objectName().isEmpty()) 
     MainWindow->setObjectName(QString::fromUtf8("MainWindow")); 

    MainWindow->resize(800, 600); 
    centralwidget = new QWidget(MainWindow); 
    centralwidget->setObjectName(QString::fromUtf8("centralwidget")); 
    horizontalLayout = new QHBoxLayout(centralwidget); 
    horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); 
    splitter = new QSplitter(centralwidget); 
    splitter->setObjectName(QString::fromUtf8("splitter")); 
    splitter->setOrientation(Qt::Horizontal); 

    frame = new Pane(splitter); 
    frame->setObjectName(QString::fromUtf8("frame")); 
    splitter->addWidget(frame); 

    frame_2 = new Pane(splitter); 
    frame_2->setObjectName(QString::fromUtf8("frame_2")); 
    splitter->addWidget(frame_2); 

    horizontalLayout->addWidget(splitter); 

    MainWindow->setCentralWidget(centralwidget); 

    QMetaObject::connectSlotsByName(MainWindow); 
} 

int main(int argc, char *argv[]) 
{ 
    QApplication app(argc, argv); 
    app.setOrganizationName("Trolltech"); 
    app.setApplicationName("Application Example"); 
    MainWindow mainWin; 
    mainWin.show(); 
    return app.exec(); 
} 

main.pro中
HEADERS  = main.h 
SOURCES  = main.cpp 
CONFIG  += no_keywords 

UPDATE:Pane::createMenus()结合到底添加一个addAction(paneSplitAct)呼叫与usin g Qt::WidgetShortcut上下文似乎给了我想要的。

从我所了解的文档中,这应该是在小部件中创建一个上下文菜单。我似乎没有得到一个(我承担的鼠标右键单击),但没关系,因为我不想要一个。仍然需要eventEvent()leaveEvent()覆盖来正确设置焦点。

回答

1

AFAIK对于像这样的大多数场景,设置WidgetShortcut的快捷方式是正确的。但问题在于你的重复动作是在菜单栏中,它不能有焦点(在传统的小部件意义上),这就是为什么它没有做任何事情。

将共享操作放入主窗口并使其成为应用程序快捷方式可能更有意义。然后在动作触发的主窗口插槽中找出哪个对象具有焦点并将命令推送到其上。

+0

因为我在其构造函数中将'QAction'的父项设置为'this',并且'WidgetShortcut'的文档声明“当它的父窗口小部件具有焦点时该快捷方式处于活动状态”应该不行?事件如果'QAction'是'QMenubar'的一个孩子,那么'WidgetWithChildrenShortcut'似乎可以工作。你的其他想法似乎可行,除了我会有多个窗格子类型,我宁愿不必将所有可能的快捷方式添加到'MainWindow'类。谢谢! – user1360310 2012-04-28 00:19:48

4

我遇到了类似的问题:2个不同的小部件具有相同的操作快捷方式(小部件之间的不同操作)。只要其中一个小部件在应用程序中可见,一切都有效。只要两者都可见,我就得到了这个“模糊快捷超载”的消息。

的解决方案是:这两个动作的背景下,必须正确设置的Qt :: WidgetWithChildrenShortcut,然后它好工作 - 只是根据目前的工作重点。

如果只有一个动作有正确的情况下,一个与默认情况下得到触发,并显示该消息。

如果这两个动作没有上下文中设置(默认值),最后产生的行动被触发和显示的消息。

所以,如果你有一个快捷方式的任意位置添加一个动作,记得去思考正确的上下文并设置它,是限制性的!

0

该解决方案的工作很适合我,当菜单栏被禁用或不用于触发行动的快捷方式。

程序添加快捷方式:

bool StingrayEditor::eventFilter(QObject* obj, QEvent* e) 
{ 
    switch (e->type()) { 
    case QEvent::Shortcut: { 
     QShortcutEvent* sev = static_cast<QShortcutEvent*>(e); 
     if (sev->isAmbiguous()) { 
      foreach(const auto& action, actions()) { 
       if (action->shortcut() == sev->key()) { 
        action->trigger(); // Trigger the action that matches the ambigous shortcut event. 
        return true; 
       } 
      } 
     } 
    } 
    // ... 
    default: break; 
    } 

    return false; 
} 

void StingrayEditor::add_shortcut(const QJsonObject& item_json) 
{ 
    QString item_path = item_json["path"].toString(); 
    QString shortcut = item_json["shortcut"].toString(); 
    if (!shortcut.isEmpty()) { 
     QKeySequence key_sequence = QKeySequence::fromString(shortcut); 
     QAction* shortcut_action = new QAction(item_path, this); 
     if (!key_sequence.isEmpty()) { 
      shortcut_action->setShortcut(key_sequence); 
      shortcut_action->setShortcutContext(Qt::ApplicationShortcut); 
     } 
     connect(shortcut_action, &QAction::triggered, this, [item_path]() 
     { 
      // Action to be executed 
     }); 

     // Add the action to the main window. 
     addAction(shortcut_action); 
    } 
} 

则需要使用shortcut_action->setShortcutContext(Qt::ApplicationShortcut);

然后你需要过滤器/监听事件赶上QEvent::Shortcut是非常重要的

不要忘记事件,像这样注册:

qApp->installEventFilter(this);