Showing a popup menu on QGraphicsScene click or right click - qt

Is there a way to show a popup when the user right clicks on an empty portion of the scene?
I'm new at Qt and I've tried slots and subclassing, but to no avail.
No such slot and, respectively:
"error: 'QMouseEvent' has not been declared"
when trying to implement the onMouseRelease event.

QGraphicsView is the widget used for displaying the contents of the QGraphicsScene. So the correct place to implement the context menu (popup menu) is the QGraphicsView.
You need to reimplement the contextMenuEvent function is your own class inherited from QGraphicsView:
void YourGraphicsView::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(this);
menu.addAction(...);
menu.addAction(...);
...
menu.exec(event->globalPos());
}
See also the Qt's Menus Example.

You can re-implement the contextMenuEvent method of the QGraphicsScene class, which will give you access to the scene coordinates as well as the screen coordinates (as opposed to QGraphicsView, which also works but doesn't have this information):
void YourGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
// event->scenePos() is available
QMenu menu(this);
menu.addAction(...);
menu.addAction(...);
...
menu.exec(event->screenPos());
}

Related

How to hide a QWidget when mouse clicked on out side that widget

I want hide a QWidget when mouse clicks out of that widget just like it have a popup flag:
auto widget = new QWidget(this);
widget->setWindowFlag(Qt::Popup); // this widget will hide, when mouse click out of that widget.
For some reason, I can't set these flags and must implement some thing myself which behaves like this.
Or can I get a mouse event out of that widget?
Solution:
As I said, I can't use Qt flags and have to implement the similar behavior myself.My solution is installEventFilter to QApplication, in the override method eventFilter,I filter the QMouseEvent and send a signal.
Yes, you can get a mouse event out of the widget.
Make a custom widget and reimplement mousePressEvent, which will catch the last click (the ouside-the-widget click that hides the "popup"). But be careful to add the call to QWidget::mousePressEvent(event) in the end, otherwise the last click will be lost and your widget will remain onscreen.
CustomWidget::CutomWidget(QWidget *parent) : QWidget(parent)
{
setWindowFlags(Qt::Popup);
}
void CustomWidget::mousePressEvent(QMouseEvent *event)
{
if (!this->underMouse()) {
//if the click is not on the widget, i.e. if it's the click that hides it,
// you caught it, do what you want to do here.
}
QWidget::mousePressEvent(event);
}
Hope it helps.

Show a QWidget after pressing a button

I want to change a QWidget in a QMainWindow dynamically. Therefore, the old widget (if it exists) will be deleted, a new one will be constructed and added to the main window.
The widget (_visualization) is a QMainWindow itself that contains a menu bar and a widget that shows an OSG scene graph.
If I donĀ“t call show() on the new widget, I will only see the menu bar, but not the scene graph.
My goal is to call show(), when the user clicks on a button. The button is connected with the outer QMainWindow (MyQMainWindow).
Unfortunately, when I call show() on _visualization in the connected method, the scene graph will not be shown. In contrast to that, the scene graph will be shown, if I call it in the constructor method (loadVisualization(...)).
MyQMainWindow::MyQMainWindow(QWidget *parent ) :
QMainWindow(parent) {
...
loadVisualization(...);
connect(_ui->nextButton, SIGNAL(clicked()), this, SLOT(showNext()));
...
}
void MyQMainWindow::loadVisualization(QString filePath) {
if (_visualization) {
_heightWidgetLayout->removeWidget(_visualization);
delete _visualization;
}
_visualization= new HeightVisualization(0, filePath);
_visualization->setParent(_mainWindowWidget);
_heightWidgetLayout->addWidget(_visualization);
//_visualization->show(); // will work here
}
void MyQMainWindow::showNext() {
_visualization->show(); // does not work here!
}
I know that QT will call setVisible(...) on the widget. This method first tests some states in QT (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden)). If I call show() in showNext(), these tests lead to a return without any change.
Is it a problem with connectors and slots? Is there a possibility to show the widget, when the user clicked on a button?
What I have learned is that it is easy to use stackedWidget.
You can then programmatically change it with this
currentPageIndex = (currentPageIndex + 1) % 3;
ui->stackedWidget->setCurrentIndex(0);
The 3 can be the total pages you have in your stack widget. You can either use currentPageIndex, or you can just create some constants with the page ids like I have done with the 0.

How to use leaveEvent with listView created from QtCreator form?

I am trying to call some function (or slot) when the mouse leaves the space of my QListView (tableView). Normally, you could use the leaveEvent() function. So for example I could write
void MainWindow::leaveEvent(QEvent * event){
qApp->quit();
}
This works as intended. When the mouse leaves the MainWindow widget, the application quits. However, what if I wanted to quit the application when the mouse leaves my QListView object which is INSIDE of my MainWindow widget?
How do I reimplement a function for this QListView when it was created within Qt Creator's form designer?
Here is what I have (unsuccessfully) tried:
void Ui::tableView::leaveEvent(){
qApp->quit();
}
And below, I have tried using leaveEvent() as a signal, and it says leaveEvent is undefined (can you even use events as SIGNALs?)
connect(ui->tableView, SIGNAL(leaveEvent(QEvent *event)), this, SLOT(testSlot()));
Basically, I am trying to call some function when the mouse leaves my tableView which was created with Qt Creator's form designer. The QListView class seems to have a mouseEntered() SIGNAL, but not mouseLeave() SIGNAL.
Subclass QListView and reimplement the leaveEvent (example):
class MyListView : public QListView
{
Q_OBJECT
void MyListView::leaveEvent(QEvent *e){
QListView::leaveEvent(e);
anyOtherAction();
}
}

Qt context menu breaking selection in QTreeView

I have a QTreeView class with a context menu installed as follows:
m_ui.tree->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_ui.tree, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(ShowTreeContextMenu(const QPoint&)));
...
void ShowTreeContextMenu(const QPoint& point)
{
m_treeContextMenu->exec(m_ui.tree->viewport()->mapToGlobal(point));
}
However when the context menu is being displayed the QTreeView will no longer respond to mouse clicks. Clicking on an item in the QTreeView while the context menu is displayed will remove the context menu but does not select the clicked item.
This is especially disorientating when right clicking on a new item, as the context menu pops up over the new item, but as the item was not selected the contents of the context menu are referring to the previously selected item.
A possible solution which I haven't verified would be to capture the click event of the right click, manually make the selection in the tree view and then invoking the parent click event which will in turn activate the context menu.
You don't say which version of Qt you are using, but we found the same problem in Qt4.4.0, it worked in 4.3. We reported this to Trolltech as a bug 225615
This is still marked as pending, so in the meantime I would follow Shy's suggestion of intercepting the right click and making the selection yourself.
Subclass the QTreeView and add the protected method void contextMenuEvent(QContextMenuEvent *event); In this method you execute a QMenu:
class TreeView : public QTreeView{
Q_OBJECT
public:
TreeView(QWidget *parent);
~TreeView();
protected:
void contextMenuEvent(QContextMenuEvent *event);
};
void TreeView::contextMenuEvent(QContextMenuEvent *event){
QMenu menu(this);
menu.addAction(action1);
menu.addAction(action2);
//...
menu.addAction(actionN);
menu.exec(event->globalPos());
}

On Qt widgets like DoubleSpinBox or ComboBox, how do i have custom right click menu

I have a few combo-boxes and double spin boxes on my Qt Dialog. Now I need a "ResetToDefault" item on a menu that comes up when you right click on the widget (spin box or combo box).
How do i get it. Is there some way I can have a custom menu that comes up on right click or Is there a way i can add items to the menu that comes on right click.
First, for Qt4, the simplest way is to create an action to reset the data, and add it the the widget using the addAction method (or use the designer). Then, set the contextMenuPolicy attribute to Qt::ActionsContextMenu. The context menu will appear and the action will be triggered.
Code example:
QAction *reset_act = new QAction("Reset to default");
mywidget->addAction(reset_act);
mywidget->setContextMenuPolicy(Qt::ActionsContextMenu);
// here connect the 'triggered' signal to some slot
For Qt3, you might have to intercept the context menu event, and thus inherit the QSpinBox and others. Or maybe you can intercept the context menu event from the main window, detect if it occurred above the widget supposed to have a context menu (using the QWidget::childAt method) and show it there. But you'll have to test.
For Qt4, you can do this for an editable QComboBox by using your own QLineEdit. Create a derived QLineEdit class which implements the contextMenuEvent
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
MyLineEdit(QWidget* parent = 0) : QLineEdit(parent){}
void contextMenuEvent(QContextMenuEvent *event)
{
QPointer<QMenu> menu = createStandardContextMenu();
//add your actions here
menu->exec(event->globalPos());
delete menu;
}
};
Then, use the setLineEdit function of QComboBox to set the line edit
MyLineEdit* edit = new MyLineEdit();
comboBox->setLineEdit(edit);
The combo box will now use your line edit class. The createStandardContextMenu function creates the normal context menu and you can add any new actions to it that you like in the contextMenuEvent handler before it is shown.
If the QComboBox is not editable then it doesn't have a default context menu so using the Qt::ActionsContextMenu method is much simpler.
QAbstractSpinBox also has a setLineEdit function so you can use a similar technique. Although, for some reason the setLineEdit function is protected on QAbstractSpinBox but public on QLineEdit.

Resources