Search code examples
qtmouseeventqabstractbutton

How to detect Qt mouse events only over QPainted objects


I am attempting to produce a compass widget programatically that looks much like this:

Compass widget target

I want each "slice" of the compass to act as a button for interaction w/ the rest of the app. To that end, I figured making them out of QAbstractButtons made the most logical sense, and started down this path:

class compassWedge(QAbstractButton):
    def __init__(self, start_angle, parent=None):
        super().__init__(parent)
        self.start = start_angle
        self.setFixedSize(550, 550)
        self.setMouseTracking(True)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        brush = QBrush()
        if self.underMouse():
            brush.setColor(Qt.black)
        else:
            brush.setColor(Qt.white)
        pen = QPen(Qt.black)
        pen.setWidth(5)
        painter.setBrush(brush)
        painter.setPen(pen)
        painter.drawPie(25, 25, 500, 500, self.start, 45 * 16)
        painter.end()


class compassApplet(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setFixedSize(550, 550)

        self.wedges = []
        for start in range(0, 360 * 16, 45 * 16):
            self.wedges.append(compassWedge(start, self))

And visually this works perfectly so far:

Work in progress

The problem is, for underMouse(), the entirety of the 550x550 slice widget area is considered. I want instead to detect when the mouse is inside the pixels generated within the paintEvent for each slice, i.e. the pie area created by painter.drawPie(...) in each object.

How can I accomplish this without having to do complicated geometry to check mouse position against pie-shaped areas?


Solution

  • Method 1: perform the geometric calculations yourself:

    How can I accomplish this without having to do complicated geometry to check mouse position against pie-shaped areas?

    Doing the geometry check yourself isn't that difficult:

    1. Check if the mouse is inside the circle, i.e. distance between mouse and center of circle <= radius of circle.
    2. Use atan2 to calculate the angle and use it to determine the correct segment

    Method 2: Use QPieSeries

    If you really do not want to implement the geometric calculations yourself, visualising the compass using a QPieSeries may be a solution as it provides a hovered function. However, it may be (more) difficult to obtain the exact desired visual representation.