def animate(animation: QPropertyAnimation, start: Union[QPointF, int, float], end: Union[QPointF, int, float], curve: QEasingCurve=QEasingCurve.Linear, speed: float=1 / 50, delay: int=-1): animation.setStartValue(start) animation.setEndValue(end) animation.setEasingCurve(curve) if type(start) == type(end) == QPointF: distance = (end - start).manhattanLength() else: distance = abs(end - start) animation.setDuration(round(distance / speed)) if delay == 0: animation.start() if delay > 0: QTimer.singleShot(delay, animation.start)
def moved(self, tile: Tetris.Tile): translation = QPropertyAnimation(self, b'pos') start, end = self.pos(), QPointF(tile.row, tile.column) curve, speed, delay = QEasingCurve.OutBack, 1 / 50, -1 self.animate(translation, start, end, curve, speed, delay) rotation = QPropertyAnimation(self, b'rotation') start, end = self.rotation(), tile.rotation curve, speed, delay = QEasingCurve.OutBack, 1, -1 self.animate(rotation, start, end, curve, speed, delay) rotation.setDuration(translation.duration()) self.moveAnimation.clear() self.moveAnimation.addAnimation(translation) self.moveAnimation.addAnimation(rotation) self.moveAnimation.start()
def createScene(self): # Root entity self.rootEntity = Qt3DCore.QEntity() # Material self.material = Qt3DExtras.QPhongMaterial(self.rootEntity) # Torus self.torusEntity = Qt3DCore.QEntity(self.rootEntity) self.torusMesh = Qt3DExtras.QTorusMesh() self.torusMesh.setRadius(5) self.torusMesh.setMinorRadius(1) self.torusMesh.setRings(100) self.torusMesh.setSlices(20) self.torusTransform = Qt3DCore.QTransform() self.torusTransform.setScale3D(QVector3D(1.5, 1, 0.5)) self.torusTransform.setRotation(QQuaternion.fromAxisAndAngle(QVector3D(1, 0, 0), 45)) self.torusEntity.addComponent(self.torusMesh) self.torusEntity.addComponent(self.torusTransform) self.torusEntity.addComponent(self.material) # Sphere self.sphereEntity = Qt3DCore.QEntity(self.rootEntity) self.sphereMesh = Qt3DExtras.QSphereMesh() self.sphereMesh.setRadius(3) self.sphereTransform = Qt3DCore.QTransform() self.controller = OrbitTransformController(self.sphereTransform) self.controller.setTarget(self.sphereTransform) self.controller.setRadius(20) self.sphereRotateTransformAnimation = QPropertyAnimation(self.sphereTransform) self.sphereRotateTransformAnimation.setTargetObject(self.controller) self.sphereRotateTransformAnimation.setPropertyName(b"angle") self.sphereRotateTransformAnimation.setStartValue(0) self.sphereRotateTransformAnimation.setEndValue(360) self.sphereRotateTransformAnimation.setDuration(10000) self.sphereRotateTransformAnimation.setLoopCount(-1) self.sphereRotateTransformAnimation.start() self.sphereEntity.addComponent(self.sphereMesh) self.sphereEntity.addComponent(self.sphereTransform) self.sphereEntity.addComponent(self.material)
def close_slide_menu_if_opened(self): width = self.ui.left_side_menu.width() if width == round(width_display / 10): newWidth = round(width_display / 18.82) self.ui.homeButton.setText(QCoreApplication.translate("Main", u"", None)) self.ui.listButton.setText(QCoreApplication.translate("Main", u"", None)) self.ui.addButton.setText(QCoreApplication.translate("Main", u"", None)) self.ui.removeButton.setText(QCoreApplication.translate("Main", u"", None)) self.ui.chooseTablePushButton.setText(QCoreApplication.translate("Main", u"", None)) # Animate the transition self.animation = QPropertyAnimation(self.ui.left_side_menu, b"minimumWidth") self.animation.setDuration(250) self.animation.setStartValue(width) # Start value is the current menu width self.animation.setEndValue(newWidth) # end value is the new menu width self.animation.setEasingCurve(QtCore.QEasingCurve.InOutQuart) self.animation.start()
def __init__(self): super(HeuristicBar, self).__init__() # centring text works, but still do no rotate it self.setStyleSheet( "QProgressBar { text-align: center; background:#aaa;" + " } QProgressBar::chunk {" + "background: qlineargradient(x0:0, y0:0, x1:1, y1:0, stop:0 #222, stop:1 #333);" + "border-radius: 5px;" + "border-style: solid;" + "border-width: 1px;" + "border-color: #845;}") self.setOrientation(Qt.Vertical) self.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) # self.setMinimumWidth(60) self.setMinimum(-100) self.setMaximum(100) # self.setValue(0) self.setFormat("%p") self.animator = QPropertyAnimation(self, b"value")
def __init__(self, q, parent=None, leftText='ON', rightText='OFF'): QObject.__init__(self, parent=parent) self.leftText = leftText self.rightText = rightText self.mPointer = q self.mPosition = 0.0 self.mGradient = QLinearGradient() self.mGradient.setSpread(QGradient.PadSpread) self.animation = QPropertyAnimation(self) self.animation.setTargetObject(self) self.animation.setPropertyName(b'position') self.animation.setStartValue(0.0) self.animation.setEndValue(1.0) self.animation.setDuration(200) self.animation.setEasingCurve(QEasingCurve.InOutExpo) self.animation.finished.connect(self.mPointer.update)
def animate(animation: QPropertyAnimation, start: Union[QPointF, int, float], end: Union[QPointF, int, float], curve: QEasingCurve = QEasingCurve.Linear, speed: float = 1 / 50, delay: int = -1): animation.setStartValue(start) animation.setEndValue(end) animation.setEasingCurve(curve) if type(start) == type(end) == QPointF: distance = (end - start).manhattanLength() else: distance = abs(end - start) animation.setDuration(round(distance / speed)) if delay == 0: animation.start() if delay > 0: QTimer.singleShot(delay, animation.start)
def mousePressEvent(self, mouseEvent: QMouseEvent): closestNode = self.playerNode.closest(mouseEvent.pos() - self.paintOffset) direction = closestNode.row - self.playerNode.row, closestNode.column - self.playerNode.column crawlNode = self.playerNode.crawl(direction) self.animation = QPropertyAnimation(self, b"player", self) if len(crawlNode.links) > 2: self.animation.setEasingCurve(QEasingCurve.OutBack); else: self.animation.setEasingCurve(QEasingCurve.OutBounce); self.animation.setStartValue(self.player) self.animation.setEndValue(crawlNode.point) self.animation.setDuration(400) self.animation.start() self.playerNode = crawlNode if self.playerNode == self.finishNode: QMessageBox.information(self, self.tr("Victory!"), self.tr("You won :)"), QMessageBox.Ok) self.initMaze()
def opacityAnimation(self, end, duration, callback): anims = [] for fx in self.opacFX: ani = QPropertyAnimation(fx, b"opacity") ani.setStartValue(fx.opacity()) ani.setEndValue(end) a = max(fx.opacity(), end) i = min(fx.opacity(), end) ani.setDuration((a - i) * duration) ani.stateChanged.connect(callback) anims.append(ani) return anims
def animate_hover(self, enter): base_color = QColor(244, 84, 67, 100) hover_color = QColor(244, 84, 67, 255) start_value = base_color if enter else hover_color if self.transition: start_value = self.transition.currentValue() self.transition.stop() self.transition = QPropertyAnimation(self, b"palete") self.transition.setStartValue(start_value) self.transition.setEndValue(hover_color if enter else base_color) self.transition.setDuration(100) self.transition.setDirection(QPropertyAnimation.Forward) self.transition.valueChanged.connect( lambda: self.restyle(self.transition.currentValue())) self.transition.start()
def toggle_menu(self, max_width, enable): if enable: """GET WIDTH""" width = self.ui.frame_left_menu.width() max_extend = max_width standard = 70 """SET MAX WIDTH""" if width == 70: width_extended = max_extend else: width_extended = standard """ANIMATION""" self.animation = QPropertyAnimation(self.ui.frame_left_menu, b"minimumWidth") self.animation.setDuration(300) self.animation.setStartValue(width) self.animation.setEndValue(width_extended) self.animation.setEasingCurve(QtCore.QEasingCurve.InOutQuart) self.animation.start()
def animate_pl_move(self, i, j): if not self.is_position_valid(i, j): return self.raise_() self.animator.stop() self.animator = QPropertyAnimation(self, b"geometry") y = (self.table_width - 20) / 8 * i + 10 x = (self.table_width - 20) / 8 * j + 10 old_rect = QRect(self.pos().x(), self.pos().y(), self.width(), self.height()) rect = QRect(x, y, self.height(), self.width()) self.animator.setDuration(500) self.animator.setStartValue(old_rect) self.animator.setEndValue(rect) self.animator.finished.connect(self.calc_position) self.movable = False self.set_cursor_pointing(False) self.animator.start()
def toggleMenu(self, maxWidth, enable): if enable: # GET WIDTH width = self.ui.frame_left_menu.width() maxExtend = maxWidth standard = 70 # SET MAX WIDTH if width == 70: widthExtended = maxExtend else: widthExtended = standard # ANIMATION self.animation = QPropertyAnimation(self.ui.frame_left_menu, b"minimumWidth") self.animation.setDuration(300) self.animation.setStartValue(width) self.animation.setEndValue(widthExtended) self.animation.setEasingCurve(QtCore.QEasingCurve.InOutQuart) self.animation.start()
def searched(self): """ Provides the color changing animation for recently searched nodes """ self.draw(Cell.SEARCHED) if self.node.isStart: self.setStart() elif self.node.isEnd: self.setEnd() else: self.effect = QGraphicsColorizeEffect(self) self.setGraphicsEffect(self.effect) self.paAnimation = QPropertyAnimation(self.effect, b"color") self.paAnimation.setStartValue(QColor(131, 18, 165)) self.paAnimation.setEndValue(Cell.SEARCHED) self.paAnimation.setDuration(1000) self.paAnimation.start()
def toggle_menu(self, maxWidth, enable): # Toggle Menu Bar if enable: # Get Width width = self.ui.frame_pages.width() maxExtend = maxWidth standard = 0 # Set Max Width if width == 0: widthExtended = maxExtend else: widthExtended = standard # Animation self.animation = QPropertyAnimation(self.ui.frame_pages, b"minimumWidth") self.animation.setDuration(400) self.animation.setStartValue(width) self.animation.setEndValue(widthExtended) self.animation.setEasingCurve(QEasingCurve.InOutQuart) self.animation.start()
def __init__(self, orientation=Orientation.HORIZONTAL, animationDuration=250, parent=None): QWidget.__init__(self, parent) self.opened = False self.orientation = orientation self.animationDuration = animationDuration self.mainLayout = None self.animator = QParallelAnimationGroup() if orientation is self.Orientation.HORIZONTAL: self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.setMaximumWidth(0) self.setMinimumWidth(0) # let the entire widget grow and shrink with its content self.animator.addAnimation(QPropertyAnimation(self)) self.animator.addAnimation( QPropertyAnimation(self, b"minimumWidth")) self.animator.addAnimation( QPropertyAnimation(self, b"maximumWidth")) elif orientation is self.Orientation.VERTICAL: self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.setMaximumHeight(0) self.setMinimumHeight(0) # let the entire widget grow and shrink with its content self.animator.addAnimation(QPropertyAnimation(self)) self.animator.addAnimation( QPropertyAnimation(self, b"minimumHeight")) self.animator.addAnimation( QPropertyAnimation(self, b"maximumHeight"))
def __init__(self, widget: QWidget, bg_color: Tuple[int, int, int, int], additional_stylesheet: str = ''): """ Animate provided Widget background stylesheet color :param widget: :param bg_color: """ super(BgrAnimation, self).__init__(widget) self.widget = widget self.color = QColor() self.bg_color = self.widget.palette().color(QPalette.Background) self.additional_stylesheet = additional_stylesheet if bg_color: self.bg_color = QColor(*bg_color) self.color_anim = QPropertyAnimation(self, b'backColor') self.color_anim.setEasingCurve(QEasingCurve.InOutSine) self._setup_blink() self.pulsate_anim = QPropertyAnimation(self, b'backColor') self.pulsate_anim.setEasingCurve(QEasingCurve.InOutQuint) self._setup_pulsate() self.fade_anim = QPropertyAnimation(self, b'backColor') self.fade_anim.setEasingCurve(QEasingCurve.InCubic)
def __init__(self): QMainWindow.__init__(self) self.setWindowFlags(Qt.FramelessWindowHint) self.setFixedSize(300,300) layout = QVBoxLayout() label = QLabel() label.setFixedSize(280,280) layout.addWidget(label, alignment=Qt.AlignCenter) self.setStyleSheet("QLabel{background-color:white}") self.blink_animation = QPropertyAnimation(self, b"backcolor") self.blink_animation.setStartValue(QColor(255,0,0)) self.blink_animation.setKeyValueAt(0.5, QColor(0,0,255)) self.blink_animation.setEndValue(QColor(255,0,0)) self.blink_animation.setDuration(3000) #self.blink_animation.setLoopCount(-1) self.blink_animation.start() container = QWidget() container.setLayout(layout) self.setCentralWidget(container)
def __init__(self, text, Rect, scale, speed, line, color, bold, parent=None): super(scrollTextLabel, self).__init__(parent) if color == 'red': self.color = QColor(231, 0, 18, 255) # red elif color == 'white': self.color = QColor(255, 255, 246, 255) # white elif color == 'Grass': self.color = QColor(144, 195, 32, 255) # Grass elif color == 'Blue': self.color = QColor(0, 160, 234, 255) # Blue if bold: self.font = QFont("Helvetica", scale, QFont.Bold) # 20 25 30 粗體 else: self.font = QFont("Helvetica", scale) self.txt = text self.speed = speed # between 50 ~ 120 self.setAttribute(Qt.WA_TranslucentBackground) self.setWindowFlags( Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint) # 隱藏 FramelessWindow self.metrics = QFontMetrics(self.font) self.setFixedWidth(self.metrics.width(self.txt) + 10) self.setFixedHeight(self.metrics.height() + 5) # self.move(Rect.x() + Rect.width() * 0.97, Rect.y() + 50 * line) self.setFocusPolicy(Qt.NoFocus) self.hide() self.anim = QPropertyAnimation(self, 'pos') self.anim.setDuration(self.speed * 100) self.anim.setStartValue(QPoint(Rect.x() + Rect.width() * 0.95, Rect.y() + 50 * line)) self.anim.setEndValue(QPoint(-self.width() + Rect.x(), Rect.y() + 50 * line)) self.anim.setEasingCurve(QEasingCurve.Linear) self.show() self.repaint() self.anim.start() self.anim.finished.connect(self.sendslot)
def _get_animation_slot(self, window, animation_property): # clear expired slots self.animations[:] = [x for x in self.animations if x is not None] if len(self.animations) > 100: raise MemoryError("Animation stack overflow?") # finish any move animations that affect the current window: for animation in self.animations: if animation.targetObject() == window: endpoint = animation.endValue() animation.stop() window.move(endpoint) self.animations.append(QPropertyAnimation(window, animation_property)) return self.animations[len(self.animations) - 1]
class TabBgrAnimation(BgrAnimation): def __init__(self, tab_widget): """ Animate the background color of the last tab of a tabwidget :param tab_widget: """ widget = tab_widget if type(tab_widget) is QTabWidget: widget = tab_widget.tabBar() LOGGER.debug('Tab Bar: %s', widget) self.style = ''' QTabBar::tab:last {{ background-color: {}; border: 1px solid rgb(221, 221, 221); padding-left: 15px;}} QTabBar::tab:last:selected {{ background-color: rgb(255, 255, 255);}} QTabBar::tab:last:hover {{ background-color: rgb(216, 234, 249);}} ''' super(TabBgrAnimation, self).__init__(widget, tuple()) # -- Overwrite color_anim -- # makes sure we do not animate backColor wihich would actually change tabWidgets # background. self.color_anim = QPropertyAnimation(self, b'styleAnim') self.color_anim.setEasingCurve(QEasingCurve.InOutSine) self._setup_blink() def _get_back_color(self): return self.color def _set_back_color(self, color): self.color = color qss_color = f'rgba({color.red()}, {color.green()}, {color.blue()}, {color.alpha()})' try: self.widget.setStyleSheet(self.style.format(qss_color)) except AttributeError as e: LOGGER.debug('Error setting widget background color: %s', e) styleAnim = Property(QColor, _get_back_color, _set_back_color)
def __init__(self, qTetris: 'QTetris', tetrimino: Tetris.Tetrimino, tile: Tetris.Tile): super(QTetris.QTile, self).__init__() tile.delegate = self self.color = self.colorMap[type(tetrimino)] self.qTetris = qTetris self.moveAnimation = QParallelAnimationGroup() self.dropAnimation = QPropertyAnimation(self, b'pos') self.collapseAnimation = QPropertyAnimation(self, b'pos') self.shiftAnimation = QPropertyAnimation(self, b'pos') self.collapseAnimation.finished.connect(lambda tl=tile: tile.delegate.disappeared(tl)) self.qTetris.scene.addItem(self) self.setPos(QPointF(0, 4)) self.moved(tile)
def __init__(self, *args, pos=(0, 0), shift=(0, 0), length=30, **kwargs): super(FWidget, self).__init__(*args, **kwargs) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowMinimizeButtonHint) self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.length = length self.lengths = dict((i, length * i / 6) for i in range(1, 13)) self.resize(self.lengths[12], self.lengths[12]) self.center = length * 10, length * 9 self.opacity = QGraphicsOpacityEffect(self) x, y = pos a, b = shift self.move(x + a, y + b) self.setGraphicsEffect(self.opacity) self.opacity.setOpacity(0) self.animation = QPropertyAnimation(self.opacity, b'opacity') self.animation.setDuration(1000) self.animation.setStartValue(0) # self.animation.setKeyValueAt(0.25, 0.67) self.animation.setKeyValueAt(0.5, 1) # self.animation.setKeyValueAt(0.75, 0.67) self.animation.setEndValue(0) self.animation.setLoopCount(-1)
class UIFunctions(MainWindow): def toggle_menu(self, maxWidth, enable): if enable: # GET WIDTH width = self.ui.frame_left_menu.width() max_extend = maxWidth standard = 110 # SET MAX WIDTH if width == 110: width_extended = max_extend else: width_extended = standard # ANIMATION self.animation = QPropertyAnimation(self.ui.frame_left_menu, b"minimumWidth") self.animation.setDuration(400) self.animation.setStartValue(width) self.animation.setEndValue(width_extended) self.animation.setEasingCurve(QtCore.QEasingCurve.InOutQuart) self.animation.start()
def toggle(self, maxWidth=150, check=True): if check: width = self.left_menu.width() print(width) maxExtend = maxWidth standart = 70 if width == 70: widthExtended = maxExtend self.pb_settings.setText("Settings") self.pb_form.setText("Form") self.pb_home.setText("Home") else: widthExtended = standart self.pb_settings.setText("") self.pb_form.setText("") self.pb_home.setText("") #Animation# self.animation = QPropertyAnimation(self.left_menu, b"minimumWidth") self.animation.setDuration(400) self.animation.setStartValue(width) self.animation.setEndValue(widthExtended) self.animation.start()
def __init__(self, parent: QWidget = None): super(ShadowClock, self).__init__(parent) self.__radiusWidth: int = 6 # 半径宽度 self.__shadowWidth: int = 4 # 光晕宽度 self.__textColor: QColor = QColor("#22A3A9") # 文本颜色 self.__shadowColor: QColor = QColor("#22A3A9") # 光晕颜色 self.__hourColor: QColor = QColor("#22A3A9") # 时钟颜色 self.__minuteColor: QColor = QColor("#22A3A9") # 分钟颜色 self.__secondColor: QColor = QColor("#22A3A9") # 秒钟颜色 # 采用动画机制,产生过渡效果 self.animation: QPropertyAnimation = QPropertyAnimation(self, b'') self.animation.valueChanged.connect(self.update) self.animation.setDuration(1000) self.animation.setStartValue(0) self.animation.setEndValue(20) self.animation.setLoopCount(-1) self.animation.start()
class AnimateWindowOpacity: def __init__(self, widget: QWidget, duration: int, start_value: float = 0.8, end_value: float = 1.0): self.widget = widget self.duration = duration self.animation = QPropertyAnimation(self.widget, b"windowOpacity") self.start_value, self.end_value = start_value, end_value self.setup_animation(self.start_value, self.end_value) def setup_animation(self, start_value: float = 0.0, end_value: float = 1.0, duration: int = 0): if not duration: duration = self.duration self.animation.setDuration(duration) self.animation.setKeyValueAt(0.0, start_value) self.animation.setKeyValueAt(1.0, end_value) self.animation.setEasingCurve(QEasingCurve.OutCubic) def fade_in(self, duration: int = 0): if self.widget.windowOpacity() >= self.end_value: return False self.setup_animation(self.start_value, self.end_value, duration) self.play() return True def fade_out(self, duration: int = 0): if self.widget.windowOpacity() <= self.start_value: return False self.setup_animation(self.end_value, self.start_value, duration) self.play() return True def play(self): if self.animation.state() != QAbstractAnimation.Running: self.animation.start()
class AnimatedButton: def __init__(self, btn, duration): self.btn = btn self.duration = duration self.animation = QPropertyAnimation(self.btn, b"iconSize") self.setup_animation() def setup_animation(self): size = self.btn.iconSize() start_value = QSize(round(size.width() * 0.2), round(size.height() * 0.2)) end_value = size self.animation.setDuration(self.duration) self.animation.setKeyValueAt(0.0, end_value) self.animation.setKeyValueAt(0.5, start_value) self.animation.setKeyValueAt(1.0, end_value) self.animation.setEasingCurve(QEasingCurve.OutElastic) def play_highlight(self): self.animation.setDuration(self.duration) self.animation.setEasingCurve(QEasingCurve.OutElastic) self.play() def play_on(self): self.animation.setDuration(round(self.duration * 0.3)) self.animation.setEasingCurve(QEasingCurve.InCirc) self.play() def play_off(self): self.animation.setDuration(round(self.duration * 0.3)) self.animation.setEasingCurve(QEasingCurve.OutCirc) self.play() def play(self, event=None): if self.animation.state() != QAbstractAnimation.Running: self.animation.start()
class KnechtExpandableWidget(QObject): expand_height = 250 def __init__(self, widget: QWidget, expand_btn: QPushButton = None, collapsible_widget: QWidget = None): """ Method to add expandable widget functionality to a widget containing an collapsible widget :param widget: the widget which size will be changed :param expand_btn: the button which will toggle the expanded/collapsed state :param collapsible_widget: the widget contained inside >>widget<< whose minimum size height hint will be set to 0 so it becomes collapsible """ super(KnechtExpandableWidget, self).__init__() self.widget = widget self.size_animation = QPropertyAnimation(self.widget, b'size') self.size_animation.setDuration(150) self.size_animation.setEasingCurve(QEasingCurve.OutCurve) self.size_animation.finished.connect(self.widget.updateGeometry) self.expand_toggle_btn = expand_btn or QPushButton(self) self.expand_toggle_btn.setCheckable(True) self.expand_toggle_btn.released.connect(self.expand_widget) self.collapsible_widget = collapsible_widget or QWidget(self) self.collapsible_widget.minimumSizeHint = self._custom_minimum_size_hint self.org_resize = self.widget.resizeEvent self.widget.resizeEvent = self._custom_resize LOGGER.debug('Initialized Expandable Widget with parent: %s', self.parent()) def _custom_minimum_size_hint(self): return QSize(self.collapsible_widget.sizeHint().width(), 0) def _custom_resize(self, event): self.org_resize(event) collapsed_height = self.widget.minimumSizeHint().height() if self.size_animation.state() != QAbstractAnimation.Running: if event.size().height() > collapsed_height: self.expand_toggle_btn.setChecked(True) else: self.expand_toggle_btn.setChecked(False) event.accept() def toggle_expand(self, immediate: bool = False): if self.expand_toggle_btn.isChecked(): self.expand_toggle_btn.setChecked(False) self.expand_widget(immediate=immediate) else: self.expand_toggle_btn.setChecked(True) self.expand_widget(immediate=immediate) def expand_widget(self, immediate: bool = False): if self.expand_toggle_btn.isChecked(): expand_height = self.widget.size().height() else: expand_height = 0 expanded_size = QSize( self.widget.size().width(), self.widget.minimumSizeHint().height() + expand_height) self.size_animation.setStartValue(self.widget.size()) self.size_animation.setEndValue(expanded_size) if immediate: self.widget.resize(expanded_size) self.widget.updateGeometry() else: self.size_animation.start()
class QMaze(QWidget): class QNode: def __init__(self, maze: 'QMaze', row: int, column: int): self.row, self.column = row, column self.maze = maze self.neighbors = [] self.links = [] @property def point(self) -> QPoint: return QPoint(self.column * self.maze.paintStep, self.row * self.maze.paintStep) def closest(self, point: QPoint) -> 'QMaze.QNode': closestNode, closestDistance = None, float("inf") for node in self.links: delta = point - node.point distance = delta.manhattanLength() if distance < closestDistance: closestNode, closestDistance = node, distance return closestNode def crawl(self, direction: tuple, distance: int=1) -> 'QMaze.QNode': if len(self.links) > 2 and distance > 1: return self for link in self.links: if direction == (link.row - self.row, link.column - self.column): return link.crawl(direction, distance + 1) else: return self def __init__(self, size: int): super(QMaze, self).__init__() self.size = size self.nodes = None self.animation = None self.startNode = None self.finishNode = None self.playerNode = None self.paintStep = 0 self.paintOffset = 0 self.initMaze() self.initUI() self.show() def getPlayer(self) -> QPoint: return self._player def setPlayer(self, point: QPoint): self._player = point self.update() player = Property(QPoint, getPlayer, setPlayer) def initMaze(self): self.nodes = {} for row in range(self.size): for column in range(self.size): self.nodes[row, column] = QMaze.QNode(self, row, column) for (row, column), node in self.nodes.items(): if 0 < row: node.neighbors.append(self.nodes[row - 1, column]) if row < self.size - 1: node.neighbors.append(self.nodes[row + 1, column]) if 0 < column: node.neighbors.append(self.nodes[row, column - 1]) if column < self.size - 1: node.neighbors.append(self.nodes[row, column + 1]) self.startNode = self.nodes[0, 0] self.finishNode = self.generateMaze(self.startNode) self.playerNode = self.startNode self.player = self.playerNode.point def generateMaze(self, start: 'QMaze.QNode') -> 'QMaze.QNode': generated = set() deepestNode, deepestRecursion = start, -1 def generateNode(node, recursion=0): nonlocal generated, deepestNode, deepestRecursion if node in generated: return generated.add(node) for neighbor in random.sample(node.neighbors, len(node.neighbors)): if neighbor not in generated: node.links.append(neighbor) neighbor.links.append(node) generateNode(neighbor, recursion + 1) if recursion > deepestRecursion: deepestNode, deepestRecursion = node, recursion generateNode(start) return deepestNode def initUI(self): self.setWindowTitle(self.tr("Maze")) def mousePressEvent(self, mouseEvent: QMouseEvent): closestNode = self.playerNode.closest(mouseEvent.pos() - self.paintOffset) direction = closestNode.row - self.playerNode.row, closestNode.column - self.playerNode.column crawlNode = self.playerNode.crawl(direction) self.animation = QPropertyAnimation(self, b"player", self) if len(crawlNode.links) > 2: self.animation.setEasingCurve(QEasingCurve.OutBack); else: self.animation.setEasingCurve(QEasingCurve.OutBounce); self.animation.setStartValue(self.player) self.animation.setEndValue(crawlNode.point) self.animation.setDuration(400) self.animation.start() self.playerNode = crawlNode if self.playerNode == self.finishNode: QMessageBox.information(self, self.tr("Victory!"), self.tr("You won :)"), QMessageBox.Ok) self.initMaze() def paintEvent(self, paintEvent: QPaintEvent): pen = QPen() pen.setJoinStyle(Qt.RoundJoin) pen.setCapStyle(Qt.RoundCap) painter = QPainter(self) painter.translate(self.paintOffset) painter.setBackgroundMode(Qt.TransparentMode) painter.setRenderHint(QPainter.Antialiasing) if self.nodes is not None: painted = set() def paintNode(node): nonlocal painter, painted if node in painted: return painted.add(node) for link in node.links: if link not in painted: painter.drawLine(node.point, link.point) paintNode(link) color = self.palette().color(QPalette.Dark) pen.setColor(color) pen.setWidth(0.50 * self.paintStep) painter.setPen(pen) for node in self.nodes.values(): if paintEvent.region().contains(node.point): paintNode(node) if self.startNode is not None: color = self.palette().color(QPalette.Dark) pen.setColor(color) pen.setWidth(0.75 * self.paintStep) painter.setPen(pen) if paintEvent.region().contains(self.startNode.point): painter.drawPoint(self.startNode.point) if self.finishNode is not None and paintEvent.region().contains(self.finishNode.point): color = self.palette().color(QPalette.Dark).darker(120) pen.setColor(color) pen.setWidth(0.75 * self.paintStep) painter.setPen(pen) painter.drawPoint(self.finishNode.point) if self.player is not None: color = self.palette().color(QPalette.Highlight) color.setAlpha(196) pen.setColor(color) pen.setWidth(0.90 * self.paintStep) painter.setPen(pen) painter.drawPoint(self.player) del painter, pen def resizeEvent(self, resizeEvent: QResizeEvent): self.paintStep = min(self.width() / self.size, self.height() / self.size) self.paintOffset = QPoint((self.paintStep + (self.width() - self.paintStep * self.size)) / 2, (self.paintStep + (self.height() - self.paintStep * self.size)) / 2) self.player = self.playerNode.point def sizeHint(self) -> QSize: paintStepHint = 40 return QSize(self.size * paintStepHint, self.size * paintStepHint)
class Window(Qt3DExtras.Qt3DWindow): def __init__(self): super(Window, self).__init__() # Camera self.camera().lens().setPerspectiveProjection(45, 16 / 9, 0.1, 1000) self.camera().setPosition(QVector3D(0, 0, 40)) self.camera().setViewCenter(QVector3D(0, 0, 0)) # For camera controls self.createScene() self.camController = Qt3DExtras.QOrbitCameraController(self.rootEntity) self.camController.setLinearSpeed(50) self.camController.setLookSpeed(180) self.camController.setCamera(self.camera()) self.setRootEntity(self.rootEntity) def createScene(self): # Root entity self.rootEntity = Qt3DCore.QEntity() # Material self.material = Qt3DExtras.QPhongMaterial(self.rootEntity) # Torus self.torusEntity = Qt3DCore.QEntity(self.rootEntity) self.torusMesh = Qt3DExtras.QTorusMesh() self.torusMesh.setRadius(5) self.torusMesh.setMinorRadius(1) self.torusMesh.setRings(100) self.torusMesh.setSlices(20) self.torusTransform = Qt3DCore.QTransform() self.torusTransform.setScale3D(QVector3D(1.5, 1, 0.5)) self.torusTransform.setRotation(QQuaternion.fromAxisAndAngle(QVector3D(1, 0, 0), 45)) self.torusEntity.addComponent(self.torusMesh) self.torusEntity.addComponent(self.torusTransform) self.torusEntity.addComponent(self.material) # Sphere self.sphereEntity = Qt3DCore.QEntity(self.rootEntity) self.sphereMesh = Qt3DExtras.QSphereMesh() self.sphereMesh.setRadius(3) self.sphereTransform = Qt3DCore.QTransform() self.controller = OrbitTransformController(self.sphereTransform) self.controller.setTarget(self.sphereTransform) self.controller.setRadius(20) self.sphereRotateTransformAnimation = QPropertyAnimation(self.sphereTransform) self.sphereRotateTransformAnimation.setTargetObject(self.controller) self.sphereRotateTransformAnimation.setPropertyName(b"angle") self.sphereRotateTransformAnimation.setStartValue(0) self.sphereRotateTransformAnimation.setEndValue(360) self.sphereRotateTransformAnimation.setDuration(10000) self.sphereRotateTransformAnimation.setLoopCount(-1) self.sphereRotateTransformAnimation.start() self.sphereEntity.addComponent(self.sphereMesh) self.sphereEntity.addComponent(self.sphereTransform) self.sphereEntity.addComponent(self.material)
class Cell(QLabel): """ The visual representation of a Node """ EMPTY = QColor(0, 0, 0, 120) SEARCHED = QColor(0, 55, 165) IN_LIST = SEARCHED.lighter(f=150) PATH = QColor(255, 255, 0) WALL = QColor(255, 255, 255, 150) def __init__(self, node, mainWindow): # Init superclass QLabel.__init__(self) self.mainWindow = mainWindow self.node = node node.setCell(self) # -- Getting expected GUI behavior -- self.setAutoFillBackground(True) # Allows for automatic color updating self.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Ignored) # Allows cells to adapt to window size self.setScaledContents(True) # Makes images scale to cell size self.setAttribute(Qt.WA_Hover, True) # Allows the enterEvent definition to work # Animation variables self.effect = None self.paAnimation = None # Initialize as empty cell self.draw(Cell.EMPTY) def draw(self, color: QColor): """ Draws this cell with the specified color. The class variables will be passed in, but any color can be used """ self.clear() self.setGraphicsEffect(None) pal = QPalette() pal.setColor(QPalette.Background, color) self.setPalette(pal) def setStart(self): """ Draws this cell as the start node """ self.setPixmap(QPixmap(":/icon/icons/start.png")) def setEnd(self): """ Draws this cell as the end node """ self.setPixmap(QPixmap(":/icon/icons/end.png")) def setWall(self, wall: bool): """ Draws this cell as a wall and updates the node to reflect it """ if wall: self.draw(Cell.WALL) self.setPixmap(QPixmap(":/icon/icons/wall.png")) self.node.wall = True else: self.draw(Cell.EMPTY) self.node.wall = False def inPath(self): self.draw(Cell.PATH) if self.node.isStart: self.setStart() elif self.node.isEnd: self.setEnd() def searched(self): """ Provides the color changing animation for recently searched nodes """ self.draw(Cell.SEARCHED) if self.node.isStart: self.setStart() elif self.node.isEnd: self.setEnd() else: self.effect = QGraphicsColorizeEffect(self) self.setGraphicsEffect(self.effect) self.paAnimation = QPropertyAnimation(self.effect, b"color") self.paAnimation.setStartValue(QColor(131, 18, 165)) self.paAnimation.setEndValue(Cell.SEARCHED) self.paAnimation.setDuration(1000) self.paAnimation.start() def mousePressEvent(self, event): """ Determines if self is the start or end node or neither, and updates things accordingly NOTE: The mouse release event is handled by the window """ if self.node.isStart: QApplication.setOverrideCursor( QCursor( QPixmap(":/icon/icons/start.png").scaledToHeight( self.height()))) self.clear() self.draw(Cell.EMPTY) self.mainWindow.changingStart = True elif self.node.isEnd: QApplication.setOverrideCursor( QPixmap(":/icon/icons/end.png").scaledToHeight(self.height())) self.clear() self.draw(Cell.EMPTY) self.mainWindow.changingEnd = True elif self.node.wall: self.mainWindow.erasingWall = True self.setWall(False) else: self.mainWindow.drawingWall = True self.setWall(True)
class BgrAnimation(QObject): def __init__(self, widget: QWidget, bg_color: Tuple[int, int, int, int], additional_stylesheet: str = ''): """ Animate provided Widget background stylesheet color :param widget: :param bg_color: """ super(BgrAnimation, self).__init__(widget) self.widget = widget self.color = QColor() self.bg_color = self.widget.palette().color(QPalette.Background) self.additional_stylesheet = additional_stylesheet if bg_color: self.bg_color = QColor(*bg_color) self.color_anim = QPropertyAnimation(self, b'backColor') self.color_anim.setEasingCurve(QEasingCurve.InOutSine) self._setup_blink() self.pulsate_anim = QPropertyAnimation(self, b'backColor') self.pulsate_anim.setEasingCurve(QEasingCurve.InOutQuint) self._setup_pulsate() self.fade_anim = QPropertyAnimation(self, b'backColor') self.fade_anim.setEasingCurve(QEasingCurve.InCubic) def fade(self, start_color: tuple, end_color: tuple, duration: int): self.fade_anim.setStartValue(QColor(*start_color)) self.fade_anim.setEndValue(QColor(*end_color)) self.fade_anim.setDuration(duration) self.fade_anim.start(QAbstractAnimation.KeepWhenStopped) def _setup_blink(self, anim_color: tuple = (26, 118, 255, 255)): start_color = self.bg_color anim_color = QColor(*anim_color) self.color_anim.setStartValue(start_color) self.color_anim.setKeyValueAt(0.5, anim_color) self.color_anim.setEndValue(start_color) self.color_anim.setDuration(600) def blink(self, num: int = 1): self.pulsate_anim.stop() self.color_anim.setLoopCount(num) self.color_anim.start() def _setup_pulsate(self, anim_color: tuple = (255, 80, 50, 255)): start_color = self.bg_color anim_color = QColor(*anim_color) self.pulsate_anim.setStartValue(start_color) self.pulsate_anim.setKeyValueAt(0.5, anim_color) self.pulsate_anim.setEndValue(start_color) self.pulsate_anim.setDuration(4000) def active_pulsate(self, num: int = -1): self.pulsate_anim.setLoopCount(num) self.pulsate_anim.start() def _get_back_color(self): return self.color def _set_back_color(self, color): self.color = color qss_color = f'rgba({color.red()}, {color.green()}, {color.blue()}, {color.alpha()})' try: self.widget.setStyleSheet( f'background-color: {qss_color};{self.additional_stylesheet}') except AttributeError as e: LOGGER.debug('Error setting widget background color: %s', e) backColor = Property(QColor, _get_back_color, _set_back_color)
class informationWidget(QWidget): def __init__(self, parent): super(informationWidget, self).__init__(parent) Pwidth = parent.width() self.resize(Pwidth, 28) _color = QColor(151, 238, 238) _color.setAlphaF(0.6) _palette = QPalette() _palette.setBrush(self.backgroundRole(), _color) self.setPalette(_palette) self.setAutoFillBackground(True) self.setGeometry(QRect(0, -28, Pwidth, 28)) self.MainHLayout = QHBoxLayout(self) self.MainHLayout.setSpacing(3) self.MainHLayout.setContentsMargins(0, 0, 0, 0) #self.MainHLayout.setStretch(1, 1) self.msg_label = QLabel(self) self.msg_label.setStyleSheet("background-color: transparent;") self.msg_label.setScaledContents(True) self.msg_label.setMaximumSize(QSize(30, 28)) self.MainHLayout.addWidget(self.msg_label) Pheight = self.height() self.ask_label = QLabel(self) self.ask_label.setStyleSheet("background-color: transparent; color: black;") self.ask_label.setAlignment(Qt.AlignCenter) self.MainHLayout.addWidget(self.ask_label) close_button = QToolButton(self) close_pix = self.style().standardPixmap(QStyle.SP_TitleBarCloseButton) close_button.setIcon(close_pix) close_button.setStyleSheet("QToolButton{background-color: transparent;}") close_button.setCursor(Qt.PointingHandCursor) close_button.setMaximumSize(QSize(30, 28)) self.MainHLayout.addWidget(close_button) close_button.clicked.connect(lambda *args: self.hideMine()) self.setWindowFlags(Qt.FramelessWindowHint) self.show() self.QanimationVis = QPropertyAnimation(self, b"geometry") self.QanimationVis.setDuration(300) #设置动画时间为1秒 self.QanimationVis.setStartValue(QRect(0, -28, self.width(), self.height())) self.QanimationVis.setEndValue(QRect(0, 0, self.width(), self.height())) self.QanimationHid = QPropertyAnimation(self, b"geometry") self.QanimationHid.setDuration(300) self.QanimationHid.setStartValue(QRect(0, 0, self.width(), self.height())) self.QanimationHid.setEndValue(QRect(0, -28, self.width(), self.height())) def setTextPixmap(self, text, mapfile): self.ask_label.setText(text) self.msg_label.setPixmap(QPixmap(mapfile)) self.QanimationVis.start() def hideMine(self): self.QanimationHid.start()
class QTile(QGraphicsObject): colorMap = {Tetris.I: QColor("#53bbf4"), Tetris.J: QColor("#e25fb8"), Tetris.L: QColor("#ffac00"), Tetris.O: QColor("#ecff2e"), Tetris.S: QColor("#97eb00"), Tetris.T: QColor("#ff85cb"), Tetris.Z: QColor("#ff5a48")} def __init__(self, qTetris: 'QTetris', tetrimino: Tetris.Tetrimino, tile: Tetris.Tile): super(QTetris.QTile, self).__init__() tile.delegate = self self.color = self.colorMap[type(tetrimino)] self.qTetris = qTetris self.moveAnimation = QParallelAnimationGroup() self.dropAnimation = QPropertyAnimation(self, b'pos') self.collapseAnimation = QPropertyAnimation(self, b'pos') self.shiftAnimation = QPropertyAnimation(self, b'pos') self.collapseAnimation.finished.connect(lambda tl=tile: tile.delegate.disappeared(tl)) self.qTetris.scene.addItem(self) self.setPos(QPointF(0, 4)) self.moved(tile) def moved(self, tile: Tetris.Tile): translation = QPropertyAnimation(self, b'pos') start, end = self.pos(), QPointF(tile.row, tile.column) curve, speed, delay = QEasingCurve.OutBack, 1 / 50, -1 self.animate(translation, start, end, curve, speed, delay) rotation = QPropertyAnimation(self, b'rotation') start, end = self.rotation(), tile.rotation curve, speed, delay = QEasingCurve.OutBack, 1, -1 self.animate(rotation, start, end, curve, speed, delay) rotation.setDuration(translation.duration()) self.moveAnimation.clear() self.moveAnimation.addAnimation(translation) self.moveAnimation.addAnimation(rotation) self.moveAnimation.start() def dropped(self, tile: Tetris.Tile): start, end = self.pos(), QPointF(tile.row, tile.column) curve, speed, delay = QEasingCurve.OutBounce, 1 / 50, 0 self.animate(self.dropAnimation, start, end, curve, speed, delay) def collapsed(self, tile: Tetris.Tile): start, end = self.pos(), QPointF(tile.row, tile.column + 2 * tile.tetris.num_columns) curve, speed, delay = QEasingCurve.InOutExpo, 1 / 50, 800 if self.dropAnimation.state() == QAbstractAnimation.Running: start = self.dropAnimation.endValue() self.animate(self.collapseAnimation, start, end, curve, speed, delay) def shifted(self, tile: Tetris.Tile): start, end = self.pos(), QPointF(tile.row, tile.column) curve, speed, delay = QEasingCurve.OutBounce, 1 / 100, 1200 if self.dropAnimation.state() == QAbstractAnimation.Running: start = self.dropAnimation.endValue() self.animate(self.shiftAnimation, start, end, curve, speed, delay) def disappeared(self, tile: Tetris.Tile): self.qTetris.scene.removeItem(self) def paint(self, painter: QPainter, styleOption: QStyleOptionGraphicsItem, widget: QWidget=None): pen = QPen() pen.setWidthF(0.05) pen.setColor(Qt.darkGray) painter.setPen(pen) brush = QBrush() brush.setColor(self.color) brush.setStyle(Qt.SolidPattern) painter.setBrush(brush) topLeft = QPointF(0, 0) bottomRight = QPointF(1, 1) rectangle = QRectF(topLeft, bottomRight) rectangle.translate(-0.5, -0.5) painter.drawRect(rectangle) @staticmethod def animate(animation: QPropertyAnimation, start: Union[QPointF, int, float], end: Union[QPointF, int, float], curve: QEasingCurve=QEasingCurve.Linear, speed: float=1 / 50, delay: int=-1): animation.setStartValue(start) animation.setEndValue(end) animation.setEasingCurve(curve) if type(start) == type(end) == QPointF: distance = (end - start).manhattanLength() else: distance = abs(end - start) animation.setDuration(round(distance / speed)) if delay == 0: animation.start() if delay > 0: QTimer.singleShot(delay, animation.start) def boundingRect(self): topLeft = QPointF(0, 0) bottomRight = QPointF(1, 1) rectangle = QRectF(topLeft, bottomRight) rectangle.translate(-0.5, -0.5) return rectangle