Skip to content

Instantly share code, notes, and snippets.

@qycyfjy
Created September 1, 2023 11:46
Show Gist options
  • Save qycyfjy/06a3c2c52a86fb72503a71ef6faeb485 to your computer and use it in GitHub Desktop.
Save qycyfjy/06a3c2c52a86fb72503a71ef6faeb485 to your computer and use it in GitHub Desktop.
PySide6 ChipExample Custom
import sys
from typing import Optional, List
from PySide6.QtCore import (
Qt,
Signal,
QPropertyAnimation,
QEasingCurve,
QRectF,
QPointF,
Property,
)
from PySide6.QtGui import (
QMouseEvent,
QWheelEvent,
QPaintEvent,
QPainter,
QColor,
QFont,
QPainterPath,
QImage,
QTransform,
QBrush,
QPen,
)
from PySide6.QtWidgets import (
QWidget,
QPushButton,
QHBoxLayout,
QDoubleSpinBox,
QProgressBar,
QComboBox,
QVBoxLayout,
QApplication,
QGraphicsScene,
QGraphicsItem,
QSplitter,
QLabel,
QStyleOptionGraphicsItem,
QGraphicsSceneMouseEvent,
QGraphicsView,
QStyle,
QFrame,
QGridLayout,
QSizePolicy,
QSlider,
)
class Chip(QGraphicsItem):
def __init__(self, color: QColor, x: int, y: int) -> None:
super().__init__()
self._color = color
self._x = x
self._y = y
self._stuff: List[QPointF] = []
self.setZValue((x + y) % 2)
self.setFlags(
QGraphicsItem.GraphicsItemFlag.ItemIsSelectable
| QGraphicsItem.GraphicsItemFlag.ItemIsMovable
)
self.setAcceptHoverEvents(True)
self._font = QFont("Times", 10)
self._font.setStyleStrategy(QFont.StyleStrategy.ForceOutline)
def boundingRect(self) -> QRectF:
return QRectF(0, 0, 110, 70)
def shape(self) -> QPainterPath:
path = QPainterPath()
path.addRect(14, 14, 82, 42)
return path
def paint(
self,
painter: QPainter,
option: QStyleOptionGraphicsItem,
widget: QWidget | None = None,
) -> None:
fill_color = self._color
if (
option.state & QStyle.StateFlag.State_Selected
== QStyle.StateFlag.State_Selected
):
fill_color = fill_color.darker(150)
if (
option.state & QStyle.StateFlag.State_MouseOver
== QStyle.StateFlag.State_MouseOver
):
fill_color = fill_color.lighter(125)
lod = option.levelOfDetailFromTransform(painter.worldTransform())
if lod < 0.2:
if lod < 0.125:
painter.fillRect(QRectF(0, 0, 110, 70), fill_color)
return
b = painter.brush()
painter.setBrush(fill_color)
painter.drawRect(13, 13, 97, 57)
painter.setBrush(b)
return
old_pen = painter.pen()
pen = old_pen
width = 0
if (
option.state & QStyle.StateFlag.State_Selected
== QStyle.StateFlag.State_Selected
):
width += 2
pen.setWidth(width)
b = painter.brush()
darker = 100
if (
option.state & QStyle.StateFlag.State_Sunken
== QStyle.StateFlag.State_Sunken
):
darker = 120
painter.setBrush(QBrush(fill_color.darker(darker)))
painter.drawRect(QRectF(14, 14, 79, 39))
painter.setBrush(b)
if lod >= 1:
painter.setPen(QPen(QColor("gray"), 1))
painter.drawLine(15, 54, 94, 54)
painter.drawLine(94, 53, 94, 15)
painter.setPen(old_pen)
if lod >= 2:
painter.setFont(self._font)
painter.save()
painter.scale(0.1, 0.1)
painter.drawText(170, 180, f"current lod: {lod}")
painter.restore()
def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
return super().mousePressEvent(event)
def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
return super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None:
return super().mouseReleaseEvent(event)
class View(QFrame):
def __init__(self, name: str, parent: QWidget | None = None) -> None:
super().__init__(parent)
self._view = QGraphicsView()
self._view.setRenderHint(QPainter.RenderHint.Antialiasing, False)
self._view.setDragMode(QGraphicsView.DragMode.RubberBandDrag)
self._view.setOptimizationFlags(
QGraphicsView.OptimizationFlag.DontSavePainterState
)
self._view.setViewportUpdateMode(
QGraphicsView.ViewportUpdateMode.SmartViewportUpdate
)
self._view.setTransformationAnchor(
QGraphicsView.ViewportAnchor.AnchorUnderMouse
)
self.scale_slider = QSlider(Qt.Orientation.Horizontal)
self.scale_slider.setRange(0, 500)
self.scale_slider.setValue(250)
self.scale_slider.valueChanged.connect(self.setup_matrix)
layout = QGridLayout()
layout.addWidget(self.scale_slider, 1, 0)
layout.addWidget(self._view)
self.setLayout(layout)
def view(self) -> QGraphicsView:
return self._view
def setup_matrix(self):
scale = pow(2, (self.scale_slider.value() - 250) / 50)
matrix = QTransform()
matrix.scale(scale, scale)
self._view.setTransform(matrix)
class MainWindow(QWidget):
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent)
self._scene = QGraphicsScene()
self.populateScene()
hsplitter1 = QSplitter(self)
hsplitter2 = QSplitter(self)
vsplitter = QSplitter(Qt.Orientation.Vertical, self)
vsplitter.addWidget(hsplitter1)
vsplitter.addWidget(hsplitter2)
button1 = QPushButton("top left")
button1.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
hsplitter1.addWidget(button1)
button2 = QPushButton("top right")
button2.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
hsplitter1.addWidget(button2)
button3 = QPushButton("bottom left")
button3.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
hsplitter2.addWidget(button3)
view4 = View("bottom right")
view4.view().setScene(self._scene)
hsplitter2.addWidget(view4)
layout = QHBoxLayout()
layout.addWidget(vsplitter)
self.setLayout(layout)
self.setWindowTitle("Chip Example")
def populateScene(self):
image = QImage("preview.png")
xx = 0
for i in range(-11000, 11000, 110):
xx += 1
yy = 0
for j in range(-7000, 7000, 70):
yy += 1
x = (i + 11000) / 22000
y = (j + 7000) / 14000
color = QColor(
image.pixel(int(image.width() * x), int(image.height() * y))
)
item = Chip(color, xx, yy)
item.setPos(QPointF(i, j))
self._scene.addItem(item)
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setAttribute(Qt.ApplicationAttribute.AA_DontCreateNativeWidgetSiblings)
mw = MainWindow()
mw.show()
app.exec()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment