Qt 4.4: disabled widgets receiving mouse events - qt

As the title suggests, is there a way for a disabled widget to receive mouse events?
I'm using QWidget::setEnabled() for changing the appearance of widgets but I still want to receive their mouse events. Thanks in advance :)

You can do this with an event filter on the widget in question. See QObject::eventFilter(). Your implementation might look something like this:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (ui->pushButton)
{
if (event->type() == QEvent::MouseButtonRelease)
{
qDebug() << "mouse button";
return true;
} else
{
return false;
}
} else
{
// pass the event on to the parent class
return QMainWindow::eventFilter(obj, event);
}
}
This will work even if the button is disabled.

Related

Detect Drag on Drop over all Child QWidgets

I'm trying to implement Drag and Drop behavior, across my whole application, I would like to execute some action when a drop occurs, no mater where in the MainWindow. The Problem that I'm facing is that in my MainWindow, I have a Widget which contains a QGraphicsView, which again contains a QGraphicsScene, I can detect the drop anywhere in the application via EventFilter, except in the in the View and Scene. Is it possible to achieve some kind of global drag and drop behavior which I can detect from the MainWindow? I'm trying to avoid spreading the Logic across all my visible Widgets.
This is the drag and drop logic in my MainWindow, works, as said, for all drag and drops that happen not over the View/Scene:
void MainWindow::dropEvent(QDropEvent *event)
{
auto pixmap = QPixmap(event->mimeData()->urls().first().toString().remove("file://"));
if(!pixmap.isNull()) {
load(pixmap);
}
event->acceptProposedAction();
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
For the drag and drops over the View/Scene I've tried to install following event filter:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
qDebug("Enter");
} else if(event->type() == QEvent::Drop) {
qDebug("Drop");
} else if(event->type() == QEvent::GraphicsSceneDrop) {
qDebug("Scene drop");
} else if (event->type() >= 159 && event->type() <= 168) {
qDebug("Any Scene Event");
}
return QObject::eventFilter(obj, event);
}
And apply it in the MainWindow ctor, the only thing that I detect is an enter when it enters the view.
...
setAcceptDrops(true);
mChildWidget->installEventFilter(this);
mChildWidget->setAcceptDrops(true);
...
It looks like I was facing two issues here. The first one is explained in this question here Accepting drops on a QGraphicsScene. The QGraphicsScene ignores DragAndDrops that are not happening over items. Basically you can enable drag and drop but only for evey item individually, which still leaves the arae that is not covered by an item. The solution to this issue seems to be to overwrite dragMoveEvent
void MyQGprahicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
{
Q_UNUSED(event)
// Overriding default dragMoveEvent in order to accept drops without items under them
}
The second issue was that i was facing is that I was trying to apply the eventFilter to Child widget, but it looks like I had to apply it to qApp, after which everything seemed to work, probably because qApp is the top QObject where all events will land when not handled.
#include "DragAndDropHandler.h"
bool DragAndDropHandler::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::DragEnter) {
handleDragEnter(dynamic_cast<QDragEnterEvent *>(event));
} else if(event->type() == QEvent::Drop) {
handleDrop(dynamic_cast<QDropEvent *>(event));
} else if(event->type() == QEvent::GraphicsSceneDrop) {
handleDrop(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
} else if (event->type() == QEvent::GraphicsSceneDragEnter) {
handleDragEnter(dynamic_cast<QGraphicsSceneDragDropEvent *>(event));
}
return QObject::eventFilter(obj, event);
}
void DragAndDropHandler::handleDragEnter(QDragEnterEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDragEnter(QGraphicsSceneDragDropEvent *event)
{
if (event->mimeData()->hasUrls()) {
event->acceptProposedAction();
}
}
void DragAndDropHandler::handleDrop(QDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
void DragAndDropHandler::handleDrop(QGraphicsSceneDragDropEvent *event)
{
auto path = getUrlFromMimeData(event->mimeData());
event->acceptProposedAction();
emit imageDropped(path);
}
QString DragAndDropHandler::getUrlFromMimeData(const QMimeData *mimeData) const
{
return mimeData->urls().first().toString().remove("file://");
}
And, in the constructor of my MainWindow:
setAcceptDrops(true);
qApp->installEventFilter(mDragAndDropHandler);
connect(mDragAndDropHandler, &DragAndDropHandler::imageDropped, this, &MainWindow::loadImageFromFile);

QT QLineEdit focusout

I have a QLineedit with mask and qvalidator (subclassed)
How can i prevent to move away the focus if the input isn't match the mask or validator ?
Because neither mask nor qvalidator don't prevent to move away focus from QLineEdit.
And editingfinished isn't work because :
void QLineEdit::editingFinished()
This signal is emitted when the Return or Enter key is pressed or the line edit loses focus. Note that if there is a validator() or inputMask() set on the line edit and enter/return is pressed, the editingFinished() signal will only be emitted if the input follows the inputMask() and the validator() returns QValidator::Acceptable."
void MainWindow:n_lineEdit_editingFinished()
{
if (ui->lineEdit->text() != "1111") ui->lineEdit->setFocus();
}
So mask (an validator) doesn't work together with editingFinsihed signal.
plus i have tried this
bool MainWindow::eventFilter(QObject *filterObj, QEvent *event)
{
if (filterObj == ui->lineEdit ) {
if(event->type() == QEvent::FocusOut) {
if (ui->lineEdit->text() != "1111") { ui->lineEdit-`>setFocus();};
return true;
};
};
return false;
}
thank you Attila
From the Qt's doc:
Note that if there is a validator set on the line edit, the
returnPressed()/editingFinished() signals will only be emitted if the
validator returns QValidator::Acceptable.
But you can set a focus on every event, not only for FocusOut:
bool MainWindow::eventFilter(QObject *filterObj, QEvent *event)
{
if (filterObj == ui->lineEdit )
ui->lineEdit->setFocus();
if(event->type() == QEvent::KeyRelease)
{
QKeyEvent* e = (QKeyEvent*)event;
if(e->key() == Qt::Key_Return
|| e->key() == Qt::Key_Enter)
{
/* do what you want here */
}
}
return QObject::eventFilter(filterObj, event); // usual process other events
}

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 mousemoveevent + Qt::LeftButton

Quick question, why does:
void roiwindow::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mouseMoveEvent(event);
qDebug() << event->button();
}
return 0 instead of 1 when I'm holding down the left mouse button while moving the cursor around in a graphicscene. Is there anyway to get this to return 1 so I can tell when a user is dragging the mouse across the graphicscene. Thanks.
Though Spyke's answer is correct, you can just use buttons() (docs). button() returns the mouse button that caused the event, which is why it returns Qt::NoButton; but buttons() returns the buttons held down when the event was fired, which is what you're after.
You can know if the left button was pressed by looking at the buttons property:
if ( e->buttons() & Qt::LeftButton )
{
// left button is held down while moving
}
Hope that helped!
The returned value is always Qt::NoButton for mouse move events. You can use Event filter to solve this.
Try this
bool MainWindow::eventFilter(QObject *object, QEvent *e)
{
if (e->type() == QEvent::MouseButtonPress && QApplication::mouseButtons()==Qt::LeftButton)
{
leftbuttonpressedflag=true;
}
if (e->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(e);
if(leftbuttonpressedflag && mouseEvent->pos()==Inside_Graphics_Scene)
qDebug("MouseDrag On GraphicsScene");
}
return false;
}
And also don't forget to install this event filter in mainwindow.
qApplicationobject->installEventFilter(this);

Resources