QHeaderView mouse tracking fails - qt

I need to connect some simple filter functionality, to a mouse click on a QTreeView header item. Simple enough, I implemented a slot function that connects to:
QTreeView::header()->sectionClicked(int)
After setting
QTreeView::header()->setSectionsClickable(true)
,sectionClicked is emitted any time I click on a header that is highlighted by the default hover effect that any clickable header will produce.
The issue is, hovering over some areas in clickable headers will not be recognized. Hence, in these parts there is no highlight and I will not get any sectionClicked triggers. I traced it back further and derived my own class from QHeaderView and put some output into mouseMoveEvent.
class MyHeaderView : public QHeaderView
{
Q_OBJECT
public:
MyHeaderView(QWidget* parent = 0)
: QHeaderView(Qt::Horizontal, parent)
{
setMouseTracking(true);
}
protected:
virtual void mouseMoveEvent(QMouseEvent* event)
{
qDebug() << event->pos();
}
};
While leaving all QTreeView settings as they were, I set an instance of this class to be the header via
QTreeView::setHeader(QHeaderView*)
I could see, that in all areas were the hover effect failed, I did not get the debug output you can see in the overridden mouseMoveEvent.
As a result I am assuming, that the mouse tracking is not working correctly.
The overall application I am working on is quiet big, so I set up a stand alone example, for all of this. To my surprise, everything works as expected. I am clueless, how I should proceed with this. Can anyone think of reasons for the mouse tracking to fail in some parts of a widget? Could it be a frame rate issue tied to lack of performance? Are there settings on widgets that affect the overall mouse tracked area? Can parent widgets affect mouse tracking?

In my application I have a controller class that handles a lot of application logic connected to various signals the tree view emits. This class is not suppost to render any visualization. Hence, it would be the most reasonable choice to derive from QObject. After a while I noticed, that it was in fact derived from QWidget. Being a QWidget I am guessing it tries to render some sort of visual representation, which the overlays the tree view. That's why I don't get any mouse events in some parts of the header.
After changing the base class of my controller to QObject, everything works fine again.

Related

Docking with QWinWidget: Adding DockWidgetAreas to QWidgets

I have an application utilizing QWinWidget in a Win32 window. I'd like to add DockWidgets and the associated behaviour to it. There don't seem to be any exposed APIs for adding custom DockAreas, and the latest docs are sparse beyond adding DockWidgets to a QMainWindow. Older docs imply there once was a public QDockArea class.
So far, my best option appears to be adding a neutered QMainWindow (no top-level status, no frame, etc.) to the QWinWidget and going from there (second source).
I was hoping there was a way to add DockAreas to any container, but it doesn't appear that way. As a side note, QWinWidget is used to have window manager control with our custom frame requirement, but if there's a pure QMainWindow/QWidget way to have the same result (with Qt::FramelessWindowHint), I'd be happy to switch over.
As I said in the comments, I've added within my QWinWidget in my Win32 window a QMainWindow field. That is:
class QWinWidget : public QWidget
{
...
QMainWidget* mainWidget;
}
QWinWidget::QWinWidget()
{
mainWidget = new QMainWindow(this);
mainWidget->setWindowFlags(Qt::Widget); //1
}
Note that while the docs and some forum posts (from this post) indicate you need to set window flags explicitly due to the QMainWindow constructor setting Qt::Window, I tested it without the setWindowFlags() line (marked with //1 above) without noticing anything wrong.
So, this gives me the nice QWinWidget window I spent so much time making, inside a frameless Win32 window, with a QMainWindow child and all the features that brings along with it. Docking, menu bar, status bar, etc.

Qt Main window loosing focus and going to background unexpectedly

Going up the learning curve and everything has been making sense so far except for this one:
I have a main window from where I call one or more dialog like this:
d->setWindowFlags(Qt::CustomizeWindowHint | Qt::Window | Qt::FramelessWindowHint);
d->setGeometry(etc...
d->show();
The dialogs are not bound to the main window, and they are actually set to be displayed right beside the main window looking like an extension.
To close the dialogs I use a mouse 'enterEvent' on the mainwindow to send a close signal to the dialog(s) which will use hide().
void MainWidget::enterEvent(QEvent *event)
{
emit signal_related_close();
}
This works but randomly this causes a very annoying issue. When the signal is sent to close the dialogs, the main window would loose focus and go in the background (behind whatever application that is on the screen). Note that it does not minimize but only goes in the background and like I said it is random (about one out of 3 times I do it). I can't seem to get a pattern.
I initially thought the signal was messed up and instead used a dialog::leaveEvent() but that didn't help. I also tried using dialog::mouseMoveEvent and using that to hide the dialog but that would still randomly loose focus on the application.
The only method that doesn't loose focus is using a push button on each dialog that will initiate the same hide commands but that's not great for my UI. So it would seem that using the mouse enterEvent/leaveEvent,mouseMoveEvent will cause that random issue.
Anyone experienced this issue before? Any idea what could be wrong? Thx.
I can't explain why but this problem occurred when using QEvent or any mouse related event together with recursive children widgets. For example take this code in the parent widget constructor:
ChildWidget c1 = new ChildWidget (this);
ChildWidget c2 = new ChildWidget (c1);
Childwidget c3 = new ChildWidget (c2);
Using QEvent in the parent widget will randomly make the window go to the background and loose focus.
Setting all the ChildWidget to the same parent stopped the problem.

How to scroll QLabel?

I am trying to implement Picture Zoom In/Out and Picture Scroll on Meego/Qt/QML.
I have written a class A which is inherited from QLabel.
A::A( "parent" )
{
setAlignment();
setGeometry();
setScaledContents();
}
Now I have a Controller class B. This class is responsible to handle the events from QML to the my Class A. In my controller class I have instantiate in the following way.
B :: B()
{
a = new A();
proxyWidget = new QGraphicsProxyWidget();
proxyWidget->setWidget(a);
}
Since this is a QML based application I am handling events from QML.
For Zoom I have used PinchArea. Whenever I am getting PinchUpdated event I am setting the setGeometryof the QLabel accordingly. I am zooming in and zooming out.
For scroll I have used MouseArea with onPositionChanged event. However I am unable to scroll the label event after calling the scroll API of the QLabel.
Can someone please tell me where am I doing wrong?
I assume you want to zoom using mouse scroll for instance.
I am not good at QML but you certainly should be handling wheel events in your class A. It is not clear for me if every Qt event has a QML equivalent, but you can always put C++ code. The function to implement is :
virtual void wheelEvent ( QWheelEvent * event );
You have the delta variable which can be useful to determine the speed of zoom (using delta absolute value) and whether it should grow or shrink (using sign of delta)

How to show pixel position and color from a QGraphicsPixmapItem

I'm developing a custom widget with QGraphicsScene/View and I have no prior experience with it.
The custom widget is an image viewer that needs to track mouse movement and send signal(s) to it's parent dialog / window. The signal(s) will be the position of the pixel under the mouse cursor and it's color (in RGB). A status bar will use that information.
I use a QGraphicsPixmapItem to display the image I load from a file in the scene.
Thanks.
First of all you have to implement the mouseMoveEvent in your custom item. In this function you can easily get the mouse position calling the pos function. You can get the rgb value if you transform the item's pixmap into image and call the pixel function. You should consider storing the QImage as member variable in order to avoid multiple transformations. Finally you have to emit a custom signal. Sample code follows:
void MyPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event)
{
QPointF mousePosition = event->pos();
QRgb rgbValue = pixmap().toImage().pixel(mousePosition.x(), mousePostion.y());
emit currentPositionRgbChanged(mousePosition, rgbValue);
}
Notice that QGraphicsItems do not inherit from QObject so by default signals/slots are not supported. You should inherit from QObject as well. This is what QGraphicsObject does. Last but not least I would advise you to enable mouse tracking on your QGraphicsView
I found the mouseMoveEvent approach to not work at all, at least not with Qt5.5. However, enabling hover events with setAcceptHoverEvents(true) on the item and reimplementing hoverMoveEvent(QGraphicsSceneHoverEvent * event) worked like a charm.
The Qt docs on mouseMoveEvent() provide the clue:
"If you do receive this event, you can be certain that this item also received a mouse press event"
http://doc.qt.io/qt-5.5/qgraphicsitem.html#mouseMoveEvent

Qt - top level widget with keyboard and mouse event transparency?

I want an app's main window to ignore mouse and keyboard events, passing them to applications underneath it in the window manager Z-order.
I see how to make child widgets ignore keyboard or mouse events, but how about the main window?
I'm trying to make a desktop widget that always sits just over the background and is totally invisible to keyboard and mouse events. (Pass through)
Qt::X11BypassWindowManagerHint gets me keyboard pass through (although sadly X11 specific, but fine for now), so how about mouse events?
Is there a OS-agnostic way to be transparent to keyboard events?
EDIT:
The key word here is transparency.
I don't want to EAT mouse and keyboard events, I want the window manager to know I don't want them at all. Those events should be directed to whatever application is under me in the zorder.
For example, I want to be able to click on desktop icons that are covered by my widget and interact with them as if the widget was not there.
I found the following solution (tested on Linux, also works on Windows according to #TheSHEEEP):
setWindowFlags(windowFlags() | Qt::WindowTransparentForInput);
It has been added in more recent qt release (i did not find when)
see http://doc.qt.io/qt-5/qt.html
On Windows you can set WS_EX_TRANSPARENT
To do this in Qt use the following code:
Include the header,
#if _WIN32
#include <windows.h>
#endif
and put the following code into the constructor.
#if _WIN32
HWND hwnd = (HWND) winId();
LONG styles = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, styles | WS_EX_TRANSPARENT);
#endif
Maybe what you want is
widget->setAttribute(Qt::WA_TransparentForMouseEvents)
? That's what QRubberBand uses to let it's parent handle the mouse events. As for keyboard events, a QWidget doesn't get any keyboard events unless it has set itself a focusPolicy().
setFocusPolicy( Qt::NoFocus );
should therefore take care of the keyboard events.
Use Qt's event filters: they will allow your application to eat whichever events you specify (i.e. keyboard and mouse events) but still process other events such as paint events.
bool FilterObject::eventFilter(QObject* object, QEvent* event)
{
QKeyEvent* pKeyEvent = qobject_cast<QKeyEvent*>(event);
QMouseEvent* pMouseEvent = qobject_cast<QMouseEvent*>(event);
if (pKeyEvent || pMouseEvent)
{
// eat all keyboard and mouse events
return true;
}
return FilterObjectParent::eventFilter(object, event);
}
Maybe I'm missing something here, but have you tried subclassing the QMainWindow class and overriding the QWidget::event() method to always return false? If you need to handle some events, you could add that intelligence here as well.
This technique should allow you to inspect the events coming in to the application and ignore them if desired without having to eat them using an event filter.
If this doesn't work you could attempt to redirect the events to the desktop by calling QCoreApplication::notify() and passing the event to the desktop widget obtained by calling QApplication::desktop(). I have no idea if this would work, but it seemed like it might be worth giving a try.
I think that overriding is supposed to work:
bool YourMainWindow::event( QEvent *event )
{
event ->accept();
return true;
}
that's some of what the QWidget class documentation says about event() member function:
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.

Resources