Detect if the mouse is clicked outside GroupBox - qt

I am looking for an event if the mouse is clicked outside of the groupBox in Qt. I tried FocusOutEvent but was not able to get the event:
ui.groupBox->installEventFilter(this);
void myClass::focusOutEvent(QFocusEvent *event) { ui.groupBox->hide(); }
Any kind of help would be greatly appreciated!

You have the following options:
Subclass QGroupBox and override mousePressEvent()
Install an event filter on that group box and catch QMouseEvents
If you want to catch only right mouse clicks (context menu), implement a custom context menu handler.

The problem is that the events of the monitored object are not forwarded to the native event handlers of the filter object such as focusOutEvent, but to a special virtual event function, i.e. eventFilter(QObject *obj, QEvent *event) as documented in installEventFilter. So, your event handler should look like this:
bool myClass::eventFilter(QObject *obj, QEvent *event)
{
if (obj == ui.groupBox && event->type () == QEvent::FocusOut)
ui.groupBox->hide();
return false;
}

Related

Qt: Issuing a message before emitting a signal

Brief description of my application and my question:
In a QTabWidget I have several groupBoxes containing each 2 QRadioButtons.
E.g.
Select Menu (groupBox): (RadioButton:) A (RadioButton:) B
At one point of time, only one Menu can be active.
Both radioButtons are connected to each othe ->
When I click radioButton A and set it true, radioButton B is automatically set false - and the other way round.
When trying to change the menu setting, before a click signal is emitted, I would like to issue a QMessageBox Warning "Are you sure you want to change the menu? This can cause severe damage to your device." -Yes/No.
When clicking Yes, I would like to change the menue setting. When clicking No, I would like everything to remain as before.
The only problem I have is: When issuing the QMessageBox in the on_radio_button_toggled slot, the radioButton state has already changed to true.
Even if I change the state in the slot again and correct them, it looks like the state has already changed when the pop up message shows up. I don't want that because that implies that the state of the menue has already changed.
Where or How can I let a QMessageBox pop up before emitting the actual signal slot - when clicking the radio Button?
Thank you very much for your help.
Update:
I have now implemented an eventFilter as recommended. Here is my source code:
ui->radioButtonMenu1->installEventFilter(this);
ui->radioButtonMenu2->installEventFilter(this);
SubmenuOne is a QWidget. It is integrated into the MainWindow by a QTabWidget (via placeholder).
bool SubmenuOne::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
QMessageBox::StandardButton reply;
reply= QMessageBox::question(this,tr("WARNING"),tr("Changing the settings may cause severe damage to your device! Please confirm your decision."),QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes)
{
//QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
//keyEvent->accept();
//event->accept();
qDebug("Yes.");
return false;
}
else
{
qDebug("No.");
return true;
}
}
}
You have to use bool eventFilter(QObject *obj, QEvent *event); Declare event filter in your window, then instal event filter to every radiobutton like this: radioButton1->installEventFilter(this);. Then at eventFilter check event type: if (event->type() == QEvent::MouseButtonPress) and show your QMessageBox. Then you can accept event and return true or false depending on user choise.
bool SubmenuOne::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
QMessageBox::StandardButton reply;
reply= QMessageBox::question(this,tr("WARNING"),tr("Changing the settings may cause severe damage to your device! Please confirm your decision."),QMessageBox::Yes|QMessageBox::No);
if (reply == QMessageBox::Yes)
{
static_cast<QRadioButton*>(obj)->setChecked(True);
}
event->accepted();
return true;
}
return QMainWindow::eventFilter(obj, event); //you forget this. QMainWindow is just base class of your SubmenuOne.
}

Handle mouse events in QListView

I've Dialog that shows folders (in treeView) and files (in listView) respectively. In listView doubleClick signal is handled by a slot that Qt created while I used Designer with aproppriate slot to be implemented. The problem is that I'm not able to handle RIGHT MOUSE click. Is there a solution?
P.S.
I've googled for a while to solve this problem, it seems that inheriting QListView and overriding solve the problem. But in my case I've already populated Qt's standart QListView using Designer.
In this case you can use event filter:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == ui->listView->viewport() && event->type() == QEvent::MouseButtonDblClick)
{
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev->buttons() & Qt::RightButton)
{
qDebug()<< "double clicked" << ev->pos();
qDebug()<< ui->listView->indexAt(ev->pos()).data();
}
}
return QObject::eventFilter(obj, event);
}
To use eventFilter you should also:
protected:
bool eventFilter(QObject *obj, QEvent *event);//in header
and
qApp->installEventFilter(this);//in constructor
Possible addition to your problem. If you want do different things when user clicks left or right mouse buttons you should handle lest and right clicks in filter, without doubleClick signal (because it emits signal in both cases) and your code can be something like:
QMouseEvent *ev = static_cast<QMouseEvent *>(event);
if (ev->buttons() & Qt::RightButton)
{
qDebug()<< "RightButton double clicked";
//do something
}
if (ev->buttons() & Qt::LeftButton)
{
qDebug()<< "LeftButton double clicked";
//do something
}
In my case, I started trying to catch mouse events when a user right-clicked on a line in the QListView, but they never came through. However, all I really wanted to do was popup a context menu, and it turns out the contextMenuEvent did get through! So I didn't have to subclass QListView, just added a contextMenuEvent() to my widget that contained the QListView.
This was Qt3, so your mileage will most definitely differ.

Qt : QWheelEvent does not refer to a value

I'm trying to create a Ctrl + Mousewheel macro to zoom in and out of an image view in my application.
Currently I am trying to use the current code:
new QShortcut(QKeySequence(Qt::CTRL + QWidget::wheelEvent(QWheelEvent *event)), this, SLOT(zoom()));
However I get the error QWheelEvent does not refer to a value. I have all the necessary includes in my header file so I do not understand why I'm getting the error.
Is it illegal to bind the widget event in conjunction within a QKeySequence? If so, how should I handle the event?
You can't use QKeySequence in this way. You should reimplement wheelEvent or use next event filter (it is example how to zoom in/out in textEdit, you can use this code for your special case):
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->plainTextEdit && event->type() == QEvent::Wheel )
{
QWheelEvent *wheel = static_cast<QWheelEvent*>(event);
if( wheel->modifiers() == Qt::ControlModifier )
if(wheel->delta() > 0)
ui->plainTextEdit->zoomIn(2);
else
ui->plainTextEdit->zoomOut(2);
}
return QObject::eventFilter(obj, event);
}
Main idea: catch wheel event and check is Ctrl modifier is pressed.
To use eventFilter you should also:
protected:
bool eventFilter(QObject *obj, QEvent *event);//in header
and
qApp->installEventFilter(this);//in constructor
Note: I showed example with event filter because it is not require subclassing, it is not better or something else, reimplement wheelEvent with similar code and you will get absolutely same result.

Passing parameters to eventFilter for QLineEdit Qt

I have a QLineEdit which I set an eventFilter using installEventFilter(this). Is it possible to pass in parameters to this eventFilter? For example, I want multiple QLineEdits to all call the same eventFilter, but I need to pass in a parameter in order to be able to tell which QLineEdit box caused the event to occur.
Thanks in advance!
The sender object is already passed to eventFilter as first parameter. So you are able to determine which QLineEdit is dispatched like this:
bool eventFilter(QObject *obj, QEvent *ev) {
if (obj == lineEdit1) {
// event from lineEdit1
} else if (obj == lineEdit2) {
// event from lineEdit2
}
}

Signal click on QSpinBox Qt

I would like to open a window when I click on a QSpinBox. The problem is that there is no such signal "clicked" for this widget.
Does someone has an idea how to do that?
A QSpinBox is just a QLineEdit with two buttons, input validation and event handling. It doesn't have clicked signal because it's supposed to handle the mouse even itself.
The problem is that even making a custom widget derived from QSpinBox won't be enough since it doesn't receive the mouse events itself, they are handled by its children widgets. You could install an event filter on the QSpinBox children in order to catch the click event, but that's not the neatest way.
If you just want to display a numpad when the user select the box, you can use directly a QLineEdit. You will lose the QSpinBox buttons (but you can add your own ones if you need them) and the validation (but you can add you own using QValidator).
Then you just have to derive it in order to catch the focus event, trigger a custom signal which would show your keyboard :
class MySpinBox: public QLineEdit
{
Q_OBJECT
public:
MySpinBox(QWidget *parent = 0);
~MySpinBox();
signals:
needNumpad(bool hasFocus);
protected:
virtual void focusInEvent(QFocusEvent *e) {
QLineEdit::focusInEvent(e);
emit(needNumpad(true));
}
virtual void focusOutEvent(QFocusEvent *e) {
QLineEdit::focusInEvent(e);
emit(needNumpad(false));
}
}
You can use an event filter and do something like this:
ui->spinBox->installEventFilter(this);
QObjectList o_list = ui->spinBox->children();
for(int i = 0; i < o_list.length(); i++)
{
QLineEdit *cast = qobject_cast<QLineEdit*>(o_list[i]);
if(cast)
cast->installEventFilter(this);
}
And in the event filter you check for a mouse click (in this example its triggered by all mouse buttons, left click, right click, scroll wheel click etc.).
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
showNumpadDialog();
}
return false;
}
You do not need to create your own QSpinBox with QLineEdit and two buttons.
Since QLineEdit is the child of QSpinBox. You can create an event filter for QLineEdit and check whether its parent is a spinbox. Then so, you would get a click event for spin box.
if(event->type() == QEvent::MouseButtonPress && dynamic_cast<QSpinBox *>(dynamic_cast<QLineEdit *>(obj)->parent()) )

Resources