How to handle right button clicks in QTreeWidgetItem? - c++

I'm implementing something similar to Eclipse's Package Explorer, using QTreeWidget, but I don't know how to handle right mouse button clicks.
How do I use Qt creator so I can handle right clicks on a QTreeWidgetItem?

You can set the context menu policy on the tree view item and then create a signal/slot event handlers as per usual.
For an example you can refer to this:
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->treeView, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(onCustomContextMenu(const QPoint &)));
Then just implement the onContextMenu function above

Related

I want to know if QAction is clicked by left or right mouse button

I have a QAction in QMenu. When QAction is triggered() I would like to know which button did it.
connect(YourAction, SIGNAL(triggered()), this, SLOT(actionclicked()));
void MainWindow::actionclicked(QMouseEvent *e)
{
if (e->buttons() == Qt::RightButton)
}
I can't do something like this because triggered() does not have such argument.
As #mvidelgauz noticed, QAction is abstracted from input devices which may triggered the action. Nevertheless, if the action is used in your GUI, it has one or more associated widgets: tool buttons in a toolbar, entries in menu bar and so on. These widgets act like any other widgets, so they receive events which may be filtered with the use of installEventFilter and eventFilter. These two methods are inherited from QObject, so they are present in almost any Qt class. For example, let's create an application with QMainWindow and QAction called actionTest. Then let's turn the main window itself into an action filter for actionTest's associated widgets by overriding main window's eventFilter method:
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);
}
Then we need to install event filter object for all watched objects, which are widgets in our case. Let's do it in main window constructor:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(auto wgtPtr : ui->actionTest->associatedWidgets()) {
wgtPtr->installEventFilter(this);
}
}
Finally, add a slot for triggered() signal handling:
void on_actionTest_triggered() {
qDebug() << "Action triggered!";
}
Now if you click the action menu entry with left mouse button, it will print
Left button!
Action triggered!
while for right mouse button the result will be
Right button!
Action triggered!
Note that widget event filtering is always performed before triggered() signal emission.
The above code is just an example, and MainWindow class is not the best place to host eventFilter method. In real code you may either:
Create dedicated QObject subclass(es) for QAction widgets event filtering.
Subclass QAction and override it's eventFilter method. In this case you may just save the result of QMouseEvent::button() in the QAction subclass object and later use it in triggered() signal handler. There is a minor inconvenience that Qt creator (at least up to v3.2.1) does not allow you to "promote" QActions in it's form designer, so you'll need to add actions to menus manually in window constructor.
Subclass QMenu, QToolBar, etc.., and make them action filters? I don't know how can it be better than two former variants.
See also documentation about Qt event system.
Let's clarify case 2. Assume the class inherited from QAction is called MyAction. In order to make it work you need to install MyAction objects as filters for themselves (their widgets, to be more specific). You need to do it after widgets were created, so installing filter in MyAction constructor may be premature and lead to crashes. Better place for filter installation is a constructor of a class which owns MyAction object. Typically it's a widget or window class. So just add
for(auto wgtPtr : ui->myActionObject->associatedWidgets()) {
wgtPtr->installEventFilter(ui->myActionObject);
}
to your window constructor after ui->setupUi(this) call. This code is like in the above example, but we use ui->myActionObject instead of this object as filter.
triggered() cannot have this argument by design because it by itself is not necessarily result of a mouse event:
This signal is emitted when an action is activated by the user; for example, when the user clicks a menu option, toolbar button, or presses an action's shortcut key combination, or when trigger() was called
You need to connect to mouse events if you need QMouseEvent as parameter. In fact Qt itself emits triggered() when (but not only as I highlighted in doc quote) framework receives mouse event from menu. So it looks like you'll need to do a similar thing in your code and add your own logic.
P.S. This discussion might be interesting for you

intercept and ignore a wheel event in a QTabWidget

I implement a UI with Qt. My UI is a mainwindow containing some widgets, and a supervisor to manage my widget behaviors. In one of my widget, outputDataWidget, I have a QTabWidget, and some other widgets.
In my tabWidget, I have a dataEditor to show points, and I create a "+" tab, to create a new tab. The tab creation is done by a connect function, which is in the mainwindow:
connect(outputWidget.get(), SIGNAL(SIG_createNewOutput(int)), projectSupervisor.get(), SLOT(sCreateNewOutput(int)));
My problem is: when we use the wheel mouse button in the tab header to go rigth, some new page are created. I would like intercept the signal and avoid the creation of a new tab.
I try to add a filter event in the mainwindow and in the outputdatawidget to ignore the wheel event. Then I try to reimplemeted wheelEvent(QWheelEvent* we) and event(QEvent *e) of the QTabWidget. Each time, we enter in thiese modification after call the connect (create the tab).
Have you an idea how to call the event before the connect, or how I can disable the wheelevent of a QTabWidget?
Thanks
You'll have to subclass QTabBar to handle the QWheelEvent, then call QTabWidget::setTabBar during initialization.
This is necessary because QTabWidget internally uses a QTabBar with Qt::WheelFocus, so the wheel event never propagates to the tab widget.

How to override menuitem click event in QtDesigner?

I'm trying to make a C++ Qt Widget Application using QtDesigner,
I have to override some menu items clicked events,
so how to override the QAction clicked event from .ui?
If I understand well you are looking for this:

Add mouse click event to QGraphicsView created with QtCreator

Is there a way to create a event to the QGraphicsView created without creating another class and inheriting the QGraphicsView?
I want to know if there's a way to do something like that:
ui->gView->AddEvent(click, functionName);
Thanks.
If you want to handle mouse click event for the view, install an event filter to the view and watch for MouseButtonPress event.

Qt: open context menu on mouse press

I'm trying to change the default behavior of context menus: Instead of opening on the release event of the right mouse button, I want it to open on the press event, and it's actions to be triggered on the release event). On one widget I could overload the mousePressEvent() and fire a custom contextmenu event, but I want it to be global to all the context menus of my program...
Any ideas?
Thanks.
I was trying to implement a widget base on top of QWidget with a custom way to handle context menu to suit your needs when I realize that using ActionsContextMenu policy with actions directly own by the widget does exactly the behavior you are expecting. (Qt 4.6.2 & 4.7 on linux, didn't try on windows yet but I don't know why the behavior should be different).
Is that a policy you can use ? If you don't really need external menus, I'll suggest to go with this solution.
Otherwise you will have to create your own widget base with a custom QMenu member. You should use the Qt::PreventContextMenu policy to guarantee the right click to end in the void mousePressEvent(QMouseEvent *event) of your widget. In this event handler make sure to show your menu. In your menu re-implement the void mouseReleaseEvent( QMouseEvent *event) if it don't trigger the current action do it your-self with the mouse position (in the event) and the QAction* actionAt( const QPoint & pt) const. But be careful the void mouseReleaseEvent( QMouseEvent *event) of the QMenu is already re-implemented from QWidget and may do some stuff you want to preserve !
EDIT
It's kind of sad but this behavior seems to be different by design on windows the void QMenu::mouseReleaseEvent(QMouseEvent *e) does the following:
Extracted form qmenu.cpp, Qt 4.6.2 sdk
#if defined(Q_WS_WIN)
//On Windows only context menus can be activated with the right button
if (e->button() == Qt::LeftButton || d->topCausedWidget() == 0)
#endif
d->activateAction(action, QAction::Trigger);
I don't know what the topCausedWidget() does in life but it's kind of explicit that only left button release will trigger the current action ...
One simple solution for you will be to re-implement your QMenu with this line commented ...
Sounds like you need to create your own class based on QMenu, and use it for every context menu in your program.
Check here for a reference.