2016-08-06 8 views
7

У меня есть QAction в QMenu. Когда QAction is triggered() Я хотел бы знать, какая кнопка сделала это.Я хочу знать, нажата ли QAction левой или правой кнопкой мыши

connect(YourAction, SIGNAL(triggered()), this, SLOT(actionclicked())); 

void MainWindow::actionclicked(QMouseEvent *e) 
{ 
    if (e->buttons() == Qt::RightButton) 
} 

Я не могу сделать что-то вроде этого, потому что triggered() не имеет такой аргумент.

ответ

4

Как заметил @mvidelgauz, QAction абстрагируется от устройств ввода, которые могут вызвать действие. Тем не менее, если действие используется в вашем графическом интерфейсе, оно имеет один или несколько связанных виджетов: кнопки инструментов на панели инструментов, записи в строке меню и т. Д. Эти виджеты действуют как любые другие виджеты, поэтому они получают события, которые могут быть отфильтрованы с использованием installEventFilter и eventFilter. Эти два метода наследуются от QObject, поэтому они присутствуют почти в любом классе Qt. Например, создадим приложение с QMainWindow и QAction с именем actionTest. Тогда давайте обратимся непосредственно главным окно в действии фильтр для ассоциированных виджетов actionTest «s путем переопределения eventFilter метода главного окна:

bool eventFilter(QObject *obj, QEvent *ev) { 
    //Catch only mouse press events. 
    if(ev->type() == QEvent::MouseButtonPress) { 
     // Cast general event to mouse event. 
     QMouseEvent *mev = static_cast<QMouseEvent*>(ev); 
     // Show which button was clicked. 
     if(mev->button() == Qt::LeftButton) { 
      qDebug() << "Left button!"; 
     } 
     if(mev->button() == Qt::RightButton) { 
      qDebug() << "Right button!"; 
     } 
    } 
    // In this example we just showed the clicked button. Pass the event 
    // for further processing to make QAction slots work. 
    return QMainWindow::eventFilter(obj, ev); 
} 

Затем нам необходимо установить объект фильтра событий для всех отслеживаемых объектов, которые являются виджетами в нашем случае , Давайте сделаем это в главном окне конструктора:

MainWindow::MainWindow(QWidget *parent) : 
QMainWindow(parent), 
ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 
    for(auto wgtPtr : ui->actionTest->associatedWidgets()) { 
     wgtPtr->installEventFilter(this); 
    } 
} 

Наконец, добавьте слот для обработки triggered() сигнала:

void on_actionTest_triggered() { 
    qDebug() << "Action triggered!"; 
} 

Теперь при нажатии на пункт меню действий с левой кнопкой мыши, он будет печатать

Left button! 
Action triggered! 

в то время как для правой кнопкой мыши результат будет

Right button! 
Action triggered! 

Обратите внимание, что фильтрация событий виджетов всегда выполняется до triggered().

Приведенный выше код является лишь примером, а класс MainWindow - не лучшее место для размещения eventFilter.В реальном коде вы можете либо:

  1. Создание посвященный QObject подкласса (ов) для QAction виджетов фильтрации событий.
  2. Подкласс QAction и переопределить его eventFilter метод. В этом случае вы можете просто сохранить результат QMouseEvent::button() в объекте подкласса QAction, а затем использовать его в обработчике сигнала triggered(). Существует незначительное неудобство, что создатель Qt (по крайней мере, до версии 3.2.1) не позволяет вам «продвигать» QAction s в своем конструкторе форм, поэтому вам нужно будет добавлять действия в меню вручную в конструкторе окна.
  3. Подкласс QMenu, QToolBar и т. Д., И сделать их фильтрами действий? Я не знаю, как это может быть лучше, чем два предыдущих варианта.

См. Также documentation о системе событий Qt.

Проясним случай 2. Предположим, что класс, унаследованный от QAction, называется MyAction. Чтобы сделать его работу, вам необходимо установить объекты MyAction в качестве фильтров для себя (их виджеты, если быть более конкретными). Вам нужно сделать это после создания виджетов, поэтому установка фильтра в конструкторе MyAction может быть преждевременной и привести к сбоям. Лучшим местом для установки фильтра является конструктор класса, которому принадлежит объект MyAction. Обычно это класс виджета или окна. Так что просто добавить

for(auto wgtPtr : ui->myActionObject->associatedWidgets()) { 
    wgtPtr->installEventFilter(ui->myActionObject); 
} 

в окно конструктора после ui->setupUi(this) вызова. Этот код похож на приведенный выше пример, но мы используем ui->myActionObject вместо объекта в качестве фильтра.

+0

Могу ли я создать eventFilter в классе, который я использую как QAction? У меня уже есть класс, который наследуется от QAction, и я использую его в своем приложении. Я переопределил метод eventFilter, но ничего не происходит. Должен ли я установить его где-нибудь? –

+0

@ S.llous конечно вы можете. Я добавил разъяснение для случая 2 из моего ответа, который должен заставить ваш код работать. Попробуйте напечатать что-нибудь в 'qDebug()' из вашего метода 'eventFilter', чтобы убедиться, что он работает правильно. – Sergey

+0

Будет ли это работать, когда я хочу использовать его на 'QSystemTrayIcon'? Мое приложение не имеет графического интерфейса, а только 'QActions' в' QSystemTrayIcon'. –

3

triggered() не может иметь этот аргумент по конструкции, поскольку она сама по себе не обязательно приводит события мыши:

Этот сигнал посылается, когда действие активируется пользователем; например, когда пользователь нажимает на пункт меню, кнопки панели инструментов, или нажимает комбинацию действие, в горячих клавиш, или когда был вызван триггер()

Вам нужно подключиться к событиям мыши, если вам нужно QMouseEvent в качестве параметра , Фактически сам Qt испускает triggered(), когда (но не только, как я выделил в цитате документа), среда принимает событие мыши из меню. Таким образом, похоже, что вам нужно будет сделать аналогичную вещь в своем коде и добавить свою собственную логику.

P.S. This discussion может быть вам интересна