Popup and pushButton - how to solve it
-
Hello,
I have a QPushButton. When I click on it I would like to create QDialog, which has set flags:
Qt::Window
Qt::Popup
Qt::FramelessWindowHinI set geometry of this QDialog under QPushButton ( it looks like QComboBox when I click QPushButton ).
And this works perfect.
But...
I can't write good solution to hide this QDialog.
There are possibilities:
- click ESCAPE - this works
- click somewhere outside the QPushButton and QDialog - this works
- click on the QPushButton - this works, but often with errors
My goal:
The first click QPushButton to show QDialog, next click to hide it, next click to show it. It looks very easy - I can have a static variable and do something like:if( variable % 2 == 0 ) { } else { }
But the problem is when I click outside the QPushButton. Then my variable don't change.
I check and I see that when I set focus on QDialog and when I click outside the QPushButton it will be run only QFocusOutEvent. When I click on QPushButton it will be run both QFocusOutEvent and next mousePressEvent.
I try using other variables, using exec and I don't have idea...
-
Hi
You can set an event filter on the dialog and look for the focus out event and then call
reject() to close it. This allows you to capture "clicking outside the dialog"https://doc.qt.io/qt-5/eventsandfilters.html
section Event FiltersMake sure to read
"it can accept or reject the event, and allow or deny further processing of the event. "
and understand this part as else you will eats its event and it will do odd stuff. -
@mrjj Thank you.
I tried get the position of mouse cursor where it is when I clicked and I compare position with button's position. I know where the user clicked. But when I go to focus out event the widget is already hide ( popup -> focus out ), so I don't have to use reject.
Sometimes when I click double times in a row I have situation in the end of queue events ( after the first click )
focus out -> mouse press event
Sometimes I have only:
focus out
So there is no the second click. And this is the problem.
-
@TomNow99
Hi
QComboxBox can do it with a local event filter so i wonder if it does use grabmouse.other also had this idea
https://forum.qt.io/topic/97345/how-to-detect-mouse-click-outside-of-widget/2Here they set the event filter on QApp to allow to get all events.
You could also use GrabMouse but be careful with that.
-
@mrjj I find it here:
https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qpushbutton.cpp.htmlI find that function which I have to replace
void QPushButtonPrivate::_q_popupPressed()
But the problem is that I need class QPushButtonPrivate. Of course I find that too. But when I check QPushButtonPrivate I saw that I need QMenu and QMenuPrivate. I think there is better way to replace that QPushButtonPrivate function.
EDIT:
Of course I can have new class like QPushButton2. I don't need change QPushButton -
@TomNow99
Hi
well in other cases you would apply the patch to Qt source and rebuild
the Widget Module. But for such small thing, im not sure its worth it.Did you try with event filer on Application instead?
That should work.
Or use grabmouse to be sure to get it. -
@TomNow99
Hi
Like
qApp->installEventFilter(filter)
qApp is macro to access the one from main.That should allow you to see the click out side.
BUT
But Before testing that, could you test with grabMouse on dialog ?
it should allow you to get the final click with the code you have.https://doc.qt.io/qt-5/qwidget.html#grabMouse
Make SURE to call releaseMouse()
when you close dialog. always. -
@TomNow99
hi
The "this" is the pointer to the QObject that has the filter func
see here
https://forum.qt.io/topic/83995/eventfilter-anywhere-in-the-program/3
its sets on the QApp. So I guess this for you would be where you have the filterfunction, maybe the dialog or the button.Its grapmouse :) Did you read about it ?
What it does ?
If you tell dialog to grab mouse you cannot click button while dialog is open. but it will work with click outside but that click is used to close dialog and it wont go to button that is outside. -
@mrjj I understand filter. Thank you :)
GrabMouse - I understand fifty - fifty :D
True - I can't click on button. But when I click outside the button ( MainWindow, where I add button ) ) I can't close dialog. When I clicked outside app ( for example click on desktop ) I close dialog.
-
@TomNow99
Ok good :)
well grabmouse simply make all events go to one widget instead of the normal way where they go to widget under mouse
so we say "give me all"Should also work clicking in MainWindow. you should also get that event.
-
@mrjj Now my code looks like:
MainWindow ( where I have button which shows / hides dialog ):
#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); button = new QPushButton(this); button->setGeometry(100,100,100,100); connect(button, SIGNAL(clicked()), this, SLOT(clickedSlot())); widget = new tenWidget; // tenWidget is a dialog widget->setFixedSize(300,300); widget->setFocus(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::clickedSlot() { static int click=1; if(click%2==1) { widget->show(); grabMouse(); } else { //widget->hide(); } click++; }
and the dialog ( tenWidget ):
#include "tenwidget.h" tenWidget::tenWidget(QWidget *parent) { setWindowFlag( Qt::FramelessWindowHint); setStyleSheet("QDialog {background-color:red}"); } void tenWidget::focusOutEvent(QFocusEvent *event) { hide(); releaseMouse(); }
Do you think about something like that? Or somewhere I have error?
-
@TomNow99
Hi
I was thinking tenWidget both had grab and release mouse.
As if you let button grab mouse then im not sure you can click on anything in tenWidget.So i would let it grabmouse so it can get the click out side event.
then it can close it. but you cant click on button while its up but clicking over it will close anyway.
its not just really the button :) -
@mrjj I read your post the fourth time and I don't know what I should do next :D
Should I change the place in the code where I grab or release mouse?
EDIT:
Of course I change:grabWindow();
to
widget->grabMouse();
in mainWindow.
But the effect is the same.