Qt experts, using QPainter, how can I define a fill area between two QPainterPaths that are connected with straight lines?
Unsolved
Qt for Python
-
So I'm trying to create a fake 3D / isometric extrusion effect by creating a QPainterPath, duplicating and offsetting it, converting both to polygons, extracting their points and finally connecting these points with straight lines. This is the result:
I can't figure out a way to fill between the lines with color, any help?
Here's the full code to run the app from the .gif posted above:
from PyQt6.QtGui import QPainter, QPainterPath, QFont, QPen, QBrush, QColor from PyQt6.QtCore import QPointF, Qt from PyQt6.QtWidgets import QApplication, QWidget, QSlider, QVBoxLayout import sys import math class TextPathPoints(QWidget): def __init__(self): super().__init__() self.resize(800, 300) # Create a QPainterPath with text self.font = QFont("Super Dessert", 120) # Use a valid font self.path = QPainterPath() self.path.addText(100, 200, self.font, "HELLO!") # Control variables for extrusion self.extrusion_length = 25 # Length of extrusion self.extrusion_angle = 45 # Angle in degrees (measured counterclockwise from the positive x-axis) layout = QVBoxLayout() # Create slider for extrusion length (range 0-100, step 1) self.length_slider = QSlider() self.length_slider.setRange(0, 100) self.length_slider.setValue(self.extrusion_length) self.length_slider.setTickInterval(1) self.length_slider.valueChanged.connect(self.update_extrusion_length) layout.addWidget(self.length_slider) # Create slider for extrusion angle (range 0-360, step 1) self.angle_slider = QSlider() self.angle_slider.setRange(0, 360) self.angle_slider.setValue(self.extrusion_angle) self.angle_slider.setTickInterval(1) self.angle_slider.valueChanged.connect(self.update_extrusion_angle) layout.addWidget(self.angle_slider) self.setLayout(layout) def update_extrusion_length(self, value): self.extrusion_length = value self.update() # Trigger repaint to update the path def update_extrusion_angle(self, value): self.extrusion_angle = value self.update() # Trigger repaint to update the path def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) painter.setRenderHint(QPainter.RenderHint.Antialiasing) # Convert angle to radians angle_rad = math.radians(self.extrusion_angle) # Calculate x and y offsets based on extrusion length and angle self.offset_x = self.extrusion_length * math.cos(angle_rad) self.offset_y = self.extrusion_length * math.sin(angle_rad) # Duplicate the path self.duplicated_path = QPainterPath(self.path) # Duplicate the original path self.duplicated_path.translate(self.offset_x, self.offset_y) # Offset using calculated values # Convert paths to polygons original_polygon = self.path.toFillPolygon() duplicated_polygon = self.duplicated_path.toFillPolygon() # Extract points from polygons self.original_points = [(p.x(), p.y()) for p in original_polygon] self.duplicated_points = [(p.x(), p.y()) for p in duplicated_polygon] # Set brush for filling the path brush = QBrush(QColor("#ebd086")) # Front and back fill painter.setBrush(brush) # Fill the original path painter.fillPath(self.path, brush) # Set pen for drawing lines between points pen = QPen() pen.setColor(QColor("black")) # Color of the lines pen.setWidthF(1.4) painter.setPen(pen) pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin) pen.setCapStyle(Qt.PenCapStyle.RoundCap) # Draw duplicated path painter.drawPath(self.duplicated_path) # Connect corresponding points between the original and duplicated paths num_points = min(len(self.original_points), len(self.duplicated_points)) for i in range(num_points): original_x, original_y = self.original_points[i] duplicated_x, duplicated_y = self.duplicated_points[i] painter.drawLine(QPointF(original_x, original_y), QPointF(duplicated_x, duplicated_y)) # Draw the original path painter.drawPath(self.path) app = QApplication(sys.argv) window = TextPathPoints() window.show() sys.exit(app.exec())