I want to include a "remove" icon on entries in my QComboBox, but I am having trouble catching the mouse press event. I've tried to catch it on the combobox, and I've tried reimplemting the QIcon class to catch the mousepress there. No dice. Does anybody know how to do this?
-D
I've written code a bit like this, where I wanted to put a tree view inside a combo box and I needed to take an action when the check box on the tree was clicked. What I ended up doing was installing an event filter on the combo box to intercept mouse clicks, figure out where the mouse click was happening, and then take an action. Probably you can do the same kind of thing with your icon. Here is the code:
bool TreeComboBox::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* m = static_cast<QMouseEvent*>(event);
QModelIndex index = view()->indexAt(m->pos());
QRect vrect = view()->visualRect(index);
if(event->type() == QEvent::MouseButtonPress &&
(model()->flags(index) & Qt::ItemIsUserCheckable) &&
vrect.contains(m->pos()))
{
// Your action here
ToggleItem(index);
UpdateSelectionString();
}
if (view()->rect().contains(m->pos()))
skipNextHide = true;
}
return QComboBox::eventFilter(object, event);
}
Maybe you can reimplement QComboBox::mousePressEvent(QMouseEvent *e) and use e.x() together with QComboBox::iconSize() to find if the event occurred over the icon.
This will off cause break if a Qt style decides to switch label and icon position in combo boxes. Don't know if that is possible?
Related
I have a QTableView where a small mark appears if the mouse hover on active cell. This mark is a widget and emit a signal if hover, changing the selecion mode of the table when I drag over the table.
The problem is that if I am over the mark, I can't drag over the table.
Things I have tried:
Set the widget mark like setWindowFlags(Qt::WindowTransparentForInput);, but I can't use it because I need hover event.
Ignore the events in the widget mark using event->ignore() or sending the event to parent using and eventFilter:
bool EventFilterMarca::eventFilter(QObject *obj, QEvent *event)
{
if( event->type() == QEvent::HoverMove)
{
....
}
else if (event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease ||
event->type() == QEvent::MouseMove ||
event->type() == QEvent::MouseButtonDblClick)
{
//QApplication::sendEvent(parent(),event);//one try
//event->ignore();//another try
return QObject::eventFilter(obj,event);;
}
}
Subclassing mousePressEvent, mouseReleaseEvent and mouseMoveEvent in the mark widget and call to parent class. Looks like if it works (pass the event to parent) into the current cell of the table (the parent):
void Marca::mousePressEvent(QMouseEvent *event)
{
//event->setAccepted(false);
if(event->buttons() == Qt::LeftButton)
{
MiTabla* tabla = qobject_cast<MiTabla*>(parent());
if (tabla)
{
tabla->mousePressEvent(event);
//QApplication::sendEvent(parent(),event);
}
}
//event->ignore();
}
Well, the question is how could get that the behaviour of the table was the same if I am over the widget of the cell or directly on the cell.
Also I add a link with my first approach to getting it. It works but the code is awful and not easy to follow:
https://github.com/exodehm/tablacalc
I think the event filter is not what you want. This is what makes a widget not receive specific events. What you actually want to do is to mark the event to be unhandled by specific widget, putting it higher in the class for handling. In order to do that you should try and reimplement either the widgets ::event method, or more specific handler.
In qt docs it says that:
bool QWidget::event(QEvent *event)
This function returns true if the event was recognized, otherwise it returns false. If the recognized event was accepted (see QEvent::accepted), any further processing such as event propagation to the parent widget stops.
So what I think you should be doing is basically marking event as not accepted when specific event type you want to propagate to parent widget happens for your widget.
So in your case I would expect something like:
void QWidget::dropEvent(QDropEvent *event) {
event->setAccepted(false);
}
Also in order for this to work your table needs to be parent widget of the mark widget.
Is there a way for a QToolButton to display its associated QMenu on top of it instead of below?
I have seen this answer which pleased me but it's in Python and I don't really know how to port it properly.
I also took a look at the source code for QMenu but it's quite overwhelming so I don't really know how to tackle this issue.
There also is a little arrow on the button showing that it'll pop down.
This is the very bottom of my window so I'd like it to pop up in case it becomes too big to fit.
You could do it using an event filter:
QMenu* yourMenu;
yourButton->setMenu(yourMenu);
yourMenu->installEventFilter(this);
bool yourClass::eventFilter(QObject * obj, QEvent *event)
{
if (event->type() == QEvent::Show && obj == yourButton->menu())
{
QPoint pos = /*the position expected*/;
yourButton->menu()->move(pos);
return true;
}
return false;
}
To remove the little arrow, add this to your stylesheet:
QToolButton::menu-indicator{
image: none;
}
I have a subclass of QGraphicsView that should accept two kinds of mouse events: drag and drop for scrolling and simple clicks for item selection/highlight.
So I use
setDragMode(QGraphicsView::ScrollHandDrag);
to enable scrolling the view with the "Hand". And I have a function like this:
void GraphView::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() == Qt::LeftButton)
emit leftClicked(mapToScene(e->pos()));
else
emit rightClicked(mapToScene(e->pos()));
QGraphicsView::mouseReleaseEvent(e);
}
which creates signal whenever the user clicks on the scene.
However, the problem is: when I stop dragging and release the mouse button, the mouseReleaseEvent function is called, and if the cursor happens to be over some element of the scene, it will get highlighted.
How can I changed the mouseReleaseEvent function so that the signals are created only if there was no previous drag of the mouse?
If you use mousePress and mouseMove in combination with mouseRelease, then you can determine what mouse action the user just performed.
If you have mousePress then mouseRelease, then it must be a simple click.
If you have mousePress, mouseMove, and then mouseRelease, then it must be a drag.
The Qt documentation contains an example of interpreting combinations of mouse events in action in a scribbling program.
http://doc.qt.io/qt-4.8/qt-widgets-scribble-example.html
You can extend the principle to something like this:
private bool MyWidget::dragging = false;
private bool MyWidget::pressed = false;
void MyWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
pressed=true;
}
QGraphicsView::mousePressEvent(event)
}
void MyWidget::mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && pressed)
{
dragging=true;
}
QGraphicsView::mouseMoveEvent(event)
}
void MyWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && pressed) {
pressed = false;
if (dragging)
{
dragging = false;
}
else
{
// plain mouse click
// do something here
}
}
QGraphicsView::mouseReleaseEvent(event)
}
Note that this does not address edge cases where a user's mouse action is performed only partially inside the widget. I must also admit that I am relatively new to Qt and have not yet used ScrollHandDrag, but this is how one would go about identifying a certain combination of mouse events.
I've got this test piece of code in mainwindow.cpp:
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
qDebug() << QString("Mouse move (%1,%2)").arg(mouseEvent->pos().x()).arg(mouseEvent->pos().y());
}
return false;
}
I just want to get mouse position when clicked, and send the coordinates to another thread with an OpenCV loop that'll pull HSV information and do things accordingly. I'm using mouse over just for testing.
The problem is that I have no idea how to attach this (tracking, clicking) to a QLabel labelKalibracja, one I use to display video frames, instead of the whole window.
ui->labelKalibracja->installEventFilter(this);
is supposed to work, but doesn't, but
qApp->->installEventFilter(this);
Will make the whole window a mouse track zone.
You should check the object of the event filter :
if (qobject_cast<QLabel*>(obj)==ui->labelKalibracja && event->type() == QEvent::MouseMove)
{
...
}
Now you can make sure that the event is for the label. Note that the event filter could be installed on multiple objects and it's your duty to identify the combination of objects and events.
Right now I'm able to detect when only one button is clicked. But I want to detect when both are pressed together. The purpose is to select some items from a QTableView. I'm trying to select them in such a way that when left button is clicked on an item while right button is already kept pressed then the item will be among the selected.
The following code only shows the message that the right button is clicked, but it doesn't show that both the buttons are clicked. How can I manage to detect when both of them are clicked?
bool MainWindow::eventFilter(QObject* obj, QEvent *ev)
{
if(obj = ui->listOfImages->viewport())
{
QMouseEvent * mouseEv = static_cast<QMouseEvent*>(ev);
if(mouseEv->buttons() == Qt::RightButton)
{
qDebug()<<"Right Button clicked!";
if(mouseEv->buttons() == Qt::LeftButton)
{
qDebug()<<"Both button clicked!";
return QObject::eventFilter(obj,ev);
}
}
}
return QObject::eventFilter(obj,ev);
}
Thanks.
Try
if( (mouseEv->buttons() & Qt::RightButton) &&
(mouseEv->buttons() & Qt::LeftButton) )
{
...
}
Hint:
When you just checked buttons() is equal to Qt::RightButton, how could it be equal to Qt::LeftButton?
The QMouseEvent::buttons() function returns a combination of OR'd states of the mouse buttons.
Therefore, to test the left button is pressed, you should be doing this: -
if(mouseEv->buttons() & Qt::LeftButton)
and for the right button: -
if(mouseEv->buttons() & Qt::RightButton)
As the Qt docs state: -
For mouse press and double click events this includes the button that caused the event. For mouse release events this excludes the button that caused the event.
So you can keep track of when buttons are held down and released.