Loss1
Loss1

Reputation: 35

PyQt click different parts of the image to have their own functions

Im creating a workshop manual for my motorbike and my plan is to make the main window show drawn image of the bike (see example below, picture from google) and i would be able to click certain parts of the bike. Lets say i want to see information about the engine, i could click the engine and it would open up.

Should i create an image with transparent background for each part and put them on right spots in the software? If so, how do i make them clickable by "ignoring" the background so only the visible part would be clickable?

enter image description here

Upvotes: 2

Views: 988

Answers (1)

Mergen Studios
Mergen Studios

Reputation: 80

Here's what I got coding up the approach suggested by @ekhumoro

import sys
from PySide2.QtWidgets import QWidget, QVBoxLayout, QApplication, QLabel
from PySide2.QtGui import QPixmap, QPolygon
from PySide2.QtCore import QPoint
from PySide2.QtCore import Qt as Qt

class TextEditDemo(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle("Motorbike Workshop")
        
        # create the image
        self.bike_img = QPixmap("bike.jpg")
        self.pixmap_label = QLabel()
        self.pixmap_label.setPixmap(self.bike_img)

        # connect the mouse press event on the image to the img_click function
        self.pixmap_label.mousePressEvent = self.img_click

        # create the polygons
        first_polygon = QPolygon() << QPoint(0, 0) << QPoint(10, 0) << QPoint(10, 10) << QPoint(0, 10)
        second_polygon = QPolygon() << QPoint(20, 20) << QPoint(30, 20) << QPoint(30, 30) << QPoint(20, 30)

        # create a dictionary containing the name of the area, the polygon and the function to be called when
        # the polygon is clicked
        self.clickable_areas = {
            "first": {
                "polygon": first_polygon,
                "func": self.func1
            },
            "second": {
                "polygon": second_polygon,
                "func": self.func2
            }
        }

        layout = QVBoxLayout()
        layout.addWidget(self.pixmap_label)
        self.setLayout(layout)


    def img_click(self, event):
        # get the position of the click
        pos = event.pos()

        # iterate over all polygons
        for area in self.clickable_areas:
            # if the point is inside one of the polygons, call the function associated with that polygon
            if self.clickable_areas[area]["polygon"].containsPoint(pos, Qt.FillRule.OddEvenFill):
                self.clickable_areas[area]["func"]()
                return
            self.func3()


    # the functions to be called when specific polygons are clicked
    def func1(self):
        print("first polygon clicked!")

    def func2(self):
        print("second polygon clicked!")

    def func3(self):
        print("no polygon was clicked")



def main():
    app = QApplication(sys.argv)
    win = TextEditDemo()
    win.show()

    sys.exit(app.exec_())

if __name__ == "__main__":
    main()

Explanation:

self.clickable_areas is dictionary holding all the polygons that can be clicked and their respective funtions. Every time the image is clicked the position where the image was clicked is saved. Then we iterate over every polygon and use containsPoint to check if the position is inside the polygon. If that is the case the corresponding function to the polygon is called.

For this to work you must manually define all the polygons that are supposed to trigger a function. For that I would recommend using an image editor of your choice to create the polygons and then copy the points over to your code.

Refferences: QPolygon QPoint

Upvotes: 4

Related Questions