class ShareMenu(QMenu): def __init__(self, *args, **kwargs): super(ShareMenu, self).__init__(*args, **kwargs) self.addAction(self.tr('分享到微博'), self.shareToWb) self.addAction(self.tr('分享到微信'), self.shareToWx) # 动画效果 self.fadeAnimation = QPropertyAnimation(self, b'pos') # 持续时间 self.fadeAnimation.setDuration(200) def shareToWb(self): pass def shareToWx(self): pass def fadeIn(self, sPos, ePos): # 进入动画 self.fadeAnimation.stop() self.fadeAnimation.setStartValue(sPos) self.fadeAnimation.setEndValue(ePos) self.fadeAnimation.start() def exec_(self): size = self.sizeHint() sPos = QCursor.pos() # 鼠标位置 sPos.setX(int(sPos.x() - size.width() / 2)) sPos.setY(sPos.y() - size.height() - 25) # 25 是状态栏高度 ePos = QPoint(sPos.x(), sPos.y() - 25) self.fadeIn(sPos, ePos) super(ShareMenu, self).exec_(ePos)
class Tab(QObject): def __init__(self, parent): QObject.__init__(self, parent) self._toolbar = parent self.icon = None self.text = "" self.has_menu = False self.enabled = True self._fader = 0 self._animator = QPropertyAnimation(self) self._animator.setPropertyName(b"fader") self._animator.setTargetObject(self) def fade_in(self): self._animator.stop() self._animator.setDuration(80) self._animator.setEndValue(1) self._animator.start() def fade_out(self): self._animator.stop() self._animator.setDuration(160) self._animator.setEndValue(0) self._animator.start() def _set_fader(self, value): self._fader = value self._toolbar.update() def _get_fader(self): return self._fader fader = pyqtProperty(float, fget=_get_fader, fset=_set_fader)
class Point(QObject): valueChanged = pyqtSignal(int) def __init__(self, x, ox, y, oy, *args, **kwargs): super(Point, self).__init__(*args, **kwargs) self.__x = x self._x = x self.originX = ox self._y = y self.__y = y self.originY = oy # 5个闭合点 self.closest = [0, 0, 0, 0, 0] # 圆半径 self.radius = 2 + random() * 2 # 连线颜色 self.lineColor = QColor(156, 217, 249) # 圆颜色 self.circleColor = QColor(156, 217, 249) def initAnimation(self): # 属性动画 if not hasattr(self, 'xanimation'): self.xanimation = QPropertyAnimation( self, b'x', self, easingCurve=QEasingCurve.InOutSine) self.xanimation.valueChanged.connect(self.valueChanged.emit) self.yanimation = QPropertyAnimation( self, b'y', self, easingCurve=QEasingCurve.InOutSine) self.yanimation.valueChanged.connect(self.valueChanged.emit) self.yanimation.finished.connect(self.updateAnimation) self.updateAnimation() def updateAnimation(self): self.xanimation.stop() self.yanimation.stop() duration = (1 + random()) * 1000 self.xanimation.setDuration(duration) self.yanimation.setDuration(duration) self.xanimation.setStartValue(self.__x) self.xanimation.setEndValue(self.originX - 50 + random() * 100) self.yanimation.setStartValue(self.__y) self.yanimation.setEndValue(self.originY - 50 + random() * 100) self.xanimation.start() self.yanimation.start() @pyqtProperty(float) def x(self): return self._x @x.setter def x(self, x): self._x = x @pyqtProperty(float) def y(self): return self._y @y.setter def y(self, y): self._y = y
class UQline(UQtxt): def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) kwargs = self._args(*args,**kwargs) redim = kwargs.get("redim",None) posi = kwargs.get("posi",None) size = kwargs.get("size",None) anim = kwargs.get("anim",True) w = 5 if redim == "w": self.resize(size,self.height()) if redim == "h": self.resize(self.width(),size) self.move(posi[0],posi[1]) ef = QGraphicsColorizeEffect(self) self.setGraphicsEffect(ef) self.__animation = QPropertyAnimation(ef,b"color") self.__animation.setDuration(2000) self.__animation.setKeyValueAt(0,QColor(0, 255, 0)) self.__animation.setKeyValueAt(0.5,QColor(255, 0, 0)) self.__animation.setKeyValueAt(1,QColor(0, 255, 0)) self.__animation.setLoopCount(-1) if anim: self.__animation.start() self.show() def load_anim(self): self.__animation.start() def stop_anim(self): self.__animation.stop()
class Window(QWidget): def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.resize(400, 400) layout = QVBoxLayout(self) layout.addWidget(QPushButton('退出', self, clicked=self.doClose)) # 窗口透明度动画类 self.animation = QPropertyAnimation(self, b'windowOpacity') self.animation.setDuration(1000) # 持续时间1秒 # 执行淡入 self.doShow() def doShow(self): try: self.animation.finished.disconnect(self.close) except: pass self.animation.stop() # 透明度范围从0逐渐增加到1 self.animation.setStartValue(0) self.animation.setEndValue(1) self.animation.start() def doClose(self): self.animation.stop() self.animation.finished.connect(self.close) # 动画完成则关闭窗口 # 透明度范围从1逐渐减少到0 self.animation.setStartValue(1) self.animation.setEndValue(0) self.animation.start()
class Tab(QObject): def __init__(self, parent): QObject.__init__(self, parent) self._toolbar = parent self.icon = None self.text = "" self.has_menu = False self.enabled = True self._fader = 0 self._animator = QPropertyAnimation(self) self._animator.setPropertyName(b"fader") self._animator.setTargetObject(self) def fade_in(self): self._animator.stop() self._animator.setDuration(80) self._animator.setEndValue(1) self._animator.start() def fade_out(self): self._animator.stop() self._animator.setDuration(160) self._animator.setEndValue(0) self._animator.start() def _set_fader(self, value): self._fader = value self._toolbar.update() def _get_fader(self): return self._fader fader = pyqtProperty(float, fget=_get_fader, fset=_set_fader)
class AnimationShadowEffect(QGraphicsDropShadowEffect): def __init__(self, color, *args, **kwargs): super(AnimationShadowEffect, self).__init__(*args, **kwargs) self.setColor(color) self.setOffset(0, 0) self.setBlurRadius(0) self._radius = 0 self.animation = QPropertyAnimation(self) self.animation.setTargetObject(self) self.animation.setDuration(2000) # 一次循环时间 self.animation.setLoopCount(-1) # 永久循环 self.animation.setPropertyName(b'radius') # 插入值 self.animation.setKeyValueAt(0, 1) self.animation.setKeyValueAt(0.5, 30) self.animation.setKeyValueAt(1, 1) def start(self): self.animation.start() def stop(self, r=0): # 停止动画并修改半径值 self.animation.stop() self.radius = r @pyqtProperty(int) def radius(self): return self._radius @radius.setter def radius(self, r): self._radius = r self.setBlurRadius(r)
class FileManager(QDialog): def __init__(self): super().__init__() self.ui = Ui_AI() self.ui.setupUi(self) self.show() self.Loop() def Loop(self): self.light = QPropertyAnimation(self.ui.HologramLight, b"geometry") self.light.setDirection(1) self.light.setLoopCount(2) self.light.setStartValue(QRect(0, 781, 481, 20)) self.light.setEndValue(QRect(0, 340, 481, 461)) self.light.start() self.light.stop() self.anim = QPropertyAnimation(self.ui.Blur2, b"geometry") self.anim.setDirection(1) self.anim.setLoopCount(100) self.anim.setStartValue(QRect(110, 240, 231, 231)) self.anim.setEndValue(QRect(130, 240, 231, 231)) self.anim.start() mixer.init() mixer.music.load('/root/PycharmProjects/AI/good.mp3') mixer.music.play()
class OpenAnimation(): def __init__(self): pass def setDuration(self,duration): # 窗口透明度动画类 self.animation = QPropertyAnimation(self, b'windowOpacity') self.animation.setDuration(duration) # 持续时间1秒 # 执行淡入 self.doShow() def doShow(self): try: # 尝试先取消动画完成后关闭窗口的信号 self.animation.finished.disconnect(self.close) except: pass self.animation.stop() # 透明度范围从0逐渐增加到1 self.animation.setStartValue(0) self.animation.setEndValue(1) self.animation.start() def doClose(self): self.animation.stop() self.animation.finished.connect(self.close) # 动画完成则关闭窗口 # 透明度范围从1逐渐减少到0 self.animation.setStartValue(1) self.animation.setEndValue(0) self.animation.start()
class AnimatedButton(QToolButton): def __init__(self, on_tick_func, anim_start=0, anim_end=255, anim_duration=300, parent=None): super().__init__(parent=parent) self._opacity = 0 self.anim_start = anim_start self.anim_end = anim_end self.anim_duration = anim_duration self.anim = QPropertyAnimation(self, b'opacity') self.anim.setDuration(anim_duration) self.anim.setStartValue(anim_start) self.anim.setEndValue(anim_end) self.on_tick = on_tick_func def set_anim_start(self, val): self.anim_start = val self.anim.setStartValue(val) def set_anim_end(self, val): self.anim_end = val self.anim.setEndValue(val) def set_anim_duration(self, val): self.anim_duration = val self.anim.setDuration(val) def get_opacity(self): return self._opacity def set_opacity(self, value): self._opacity = value if value != 1: self.on_tick(self, value) opacity = pyqtProperty('int', get_opacity, set_opacity) def enterEvent(self, event): self.anim.stop() self.anim.setStartValue(self.anim.currentValue()) self.anim.setEndValue(self.anim_end) self.anim.start() super().enterEvent(event) def leaveEvent(self, event): self.anim.stop() self.anim.setStartValue(self.anim.currentValue()) self.anim.setEndValue(self.anim_start) self.anim.start() super().leaveEvent(event)
class StdInfo(QLabel): def __init__(self, text_func, align=Qt.AlignRight | Qt.AlignBottom, parent=None, font=None, **kwds): QLabel.__init__(self, parent, **kwds) if font == None: font = QFont() font.setPointSize(36) self.setStyleSheet("QLabel {color: gray;}") self.setFont(font) self.text_func = text_func self.align = align if callable(text_func): self.display = self.display_func else: self.setText(self.text_func) self.display = self.display_str effect = QGraphicsOpacityEffect(self) self.setGraphicsEffect(effect) self.anim = QPropertyAnimation(effect, b"opacity") self.anim.setDuration(2000) self.anim.setStartValue(1.) self.anim.setEndValue(0.) # self.anim.setEasingCurve(QEasingCurve.OutQuad) self.anim.finished.connect(self.hide) self.parent().resized.connect(self.set_position) def set_position(self, pos=None): if pos == None: coords = self.parent().geometry().getCoords() if self.align & Qt.AlignLeft: x = coords[0] else: x = coords[2] - self.width() if self.align & Qt.AlignTop: y = coords[1] else: y = coords[3] - self.height() pos = (x, y) self.move(*pos) def display_func(self): self.setText(self.text_func()) self.show() self.anim.stop() self.anim.start() def display_str(self): self.show() # self.anim.updateCurrentValue(1.) self.anim.stop() self.anim.start()
class PushButtonFont(QPushButton): LoadingText = "\uf110" def __init__(self, *args, **kwargs): super(PushButtonFont, self).__init__(*args, **kwargs) self.fontSize = self.font().pointSize() * 2 self._rotateAnimationStarted = False self._rotateAnimation = QPropertyAnimation(self) self._rotateAnimation.setTargetObject(self) self._rotateAnimation.setStartValue(1) self._rotateAnimation.setEndValue(12) self._rotateAnimation.setDuration(1000) self._rotateAnimation.setLoopCount(-1) # 无限循环 self._rotateAnimation.valueChanged.connect(self.update) self.clicked.connect(self._onClick) def paintEvent(self, _): option = QStyleOptionButton() self.initStyleOption(option) painter = QStylePainter(self) if self._rotateAnimationStarted: option.text = "" painter.drawControl(QStyle.CE_PushButton, option) if not self._rotateAnimationStarted: return painter.save() font = self.font() font.setPointSize(self.fontSize) font.setFamily("FontAwesome") painter.setFont(font) # 变换坐标为正中间 painter.translate(self.rect().center()) # 旋转90度 painter.rotate(self._rotateAnimation.currentValue() * 30) fm = self.fontMetrics() # 在变换坐标后的正中间画文字 w = fm.width(self.LoadingText) h = fm.height() painter.drawText( QRectF(0 - w * 2, 0 - h, w * 2 * 2, h * 2), Qt.AlignCenter, self.LoadingText) painter.restore() def _onClick(self): if self._rotateAnimationStarted: self._rotateAnimationStarted = False self._rotateAnimation.stop() return self._rotateAnimationStarted = True self._rotateAnimation.start() def update(self, _=None): super(PushButtonFont, self).update()
class Window(QMainWindow, Ui_MainWindow): def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) self.setupUi(self) self.outani = QPropertyAnimation(self.widget, b"geometry") # 背后隐藏的控件 self.outani.setDuration(1000) # 1s self.outani.setEndValue(QRect(0, 30, 178, 681)) # 只是x坐标变化 # 移进去动画 self.inani = QPropertyAnimation(self.widget, b"geometry") # 背后隐藏的控件 self.inani.setDuration(1000) # 1s self.inani.setEndValue(QRect(0, -580, 178, 681)) self.inani.finished.connect(self.onFinish) # 绑定打开关闭事件 self.openButton.clicked.connect(self.onOpen) self.closeButton.clicked.connect(self.onClose) #打开文件 self.action.triggered.connect(self.openFile) self.action.setStatusTip('导入矩阵') self.action.setShortcut('Ctrl+Q') #退出系统 self.action_2.triggered.connect(self.close) self.action_2.setStatusTip('退出系统') self.action_2.setShortcut('Ctrl+E') #开发者信息 self.action_3.setStatusTip('唐伟泽 谢家柯 2016.12.3') def onOpen(self): # 设置按钮不可见 self.openButton.setVisible(False) self.widget.setVisible(True) # 背后的待拉出来的控件可见 self.graphicsView.setGeometry(QtCore.QRect(195, 1, 611, 641)) self.outani.start() # 开启动画效果 def onClose(self): self.outani.stop() # 如果移动到一半则停止 self.inani.start() # 退回去 def onFinish(self): # 关闭动画结束 self.widget.setVisible(False) self.openButton.setVisible(True) self.graphicsView.setGeometry(QtCore.QRect(0, 0, 801, 641)) def openFile(self): fileName1, filetype = QFileDialog.getOpenFileName( self, "选取文件", "/Users/Kelisiya/Desktop", "All Files (*);;Text Files (*.txt)") print(fileName1, filetype)
class NotifyWidget(QWidget): def __init__(self): super().__init__() self.layout = QVBoxLayout(self) self.sub_widget = _NotifySubWidget(self) self.layout.addWidget(self.sub_widget) self.layout.setContentsMargins(0, 0, 0, 0) self._exit_shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self) self._exit_shortcut.activated.connect(self.close) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool) self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_MacAlwaysShowToolWindow) self.resize(width, height) self.move( QApplication.primaryScreen().geometry().right() - self.width() - 20, 40) self.setLayout(self.layout) self._animation = QPropertyAnimation(self, b'windowOpacity') self._animation.setStartValue(0.8) self._animation.setKeyValueAt(0.4, 1) self._animation.setEndValue(0) self._animation.setDuration(5000) self._animation.finished.connect(self.close) def show(self): super().show() self._animation.start() def show_message(self, title, content, pixmap=None): if not self.isVisible(): self.show() self._animation.stop() self._animation.setCurrentTime(0) self._animation.start() self.sub_widget.set_title(title) self.sub_widget.set_content(content) pixmap = pixmap if pixmap else QPixmap(WINDOW_ICON) self.sub_widget.set_pixmap(pixmap) def enterEvent(self, event): self._animation.setCurrentTime(0)
class NotifyWidget(QWidget): def __init__(self): super().__init__() self.layout = QVBoxLayout(self) self.sub_widget = _NotifySubWidget(self) self.layout.addWidget(self.sub_widget) self.layout.setContentsMargins(0, 0, 0, 0) self._exit_shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self) self._exit_shortcut.activated.connect(self.close) self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool) self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_MacAlwaysShowToolWindow) self.resize(width, height) self.move(QApplication.desktop().width() - self.width() - 20, 40) self.setLayout(self.layout) self._animation = QPropertyAnimation(self, b'windowOpacity') self._animation.setStartValue(0.8) self._animation.setKeyValueAt(0.4, 1) self._animation.setEndValue(0) self._animation.setDuration(5000) self._animation.finished.connect(self.close) def show(self): super().show() self._animation.start() def show_message(self, title, content, pixmap=None): if not self.isVisible(): self.show() self._animation.stop() self._animation.setCurrentTime(0) self._animation.start() self.sub_widget.set_title(title) self.sub_widget.set_content(content) pixmap = pixmap if pixmap else QPixmap(WINDOW_ICON) self.sub_widget.set_pixmap(pixmap) def enterEvent(self, event): self._animation.setCurrentTime(0)
class ApplWindow(QDialog): def __init__(self): super(ApplWindow, self).__init__() self.ui = uic.loadUi('testmoveLabel.ui', self) self.ui.pushButton.clicked.connect(self.runne) self.ui.pushButton_2.clicked.connect(self.checkne) self.show() def runne(self,x): self.CN = QPropertyAnimation(self.ui.label, b"geometry") self.CN.setDuration(4000) self.CN.setLoopCount(1) print('a') self.CN.setKeyValueAt(0,QRect(600, 0, 80, 120)) self.CN.setKeyValueAt(0.5,QRect(0, 0, 80, 120)) self.CN.setKeyValueAt(1,QRect(70, 200, 80, 120)) self.CN.start() def checkne(self): x=self.ui.label.x() x2=self.ui.label_2.x() print(x) print(x2) def stopx(self): self.CN.stop()
class ApplWindow(QDialog): def __init__(self): super(ApplWindow, self).__init__() self.ui = uic.loadUi('testmoveLabel.ui', self) self.ui.pushButton.clicked.connect(self.runne) self.ui.pushButton_2.clicked.connect(self.runne) self.count = True # self.left = [300,350,400,450] # self.top = 0 # self.width = 20 # self.height = [170,160,180,190] # for i in range(-1,3): # label_8 = QLabel(str("label_"+str(i+1)), self) # label_8.setStyleSheet("background:red") # label_8.setGeometry(self.left[i+1], self.top, self.width, self.height[i+1]) self.show() def runne(self, x): # self.lstR = [30, 190, 360] # a = random.choice(self.lstR) # self.CN = QPropertyAnimation(self.ui.label, b"geometry") # self.CN.setDuration(2000) # self.CN.setLoopCount(-1) # self.CN.setStartValue(QRect(0, 100, 130, 170)) # self.CN.setEndValue(QRect(400, 100, 130, 170)) # self.CN.start() # print(self.count) self.CN = QPropertyAnimation(self.ui.label, b"geometry") self.lstR = [-100] self.CN.setDuration(4000) self.CN.setLoopCount(-1) print('a') self.CN.setStartValue(QRect(600, 0, 80, 120)) self.CN.setEndValue(QRect(-100, 0, 80, 120)) self.CN.start() self.CN1 = QPropertyAnimation(self.ui.label_2, b"geometry") self.CN1.setDuration(4300) self.CN1.setLoopCount(-1) self.CN1.setStartValue(QRect(800, 100, 80, 140)) self.CN1.setEndValue(QRect(-50, 0, 80, 140)) self.CN1.start() print('b') self.CN2 = QPropertyAnimation(self.ui.label_3, b"geometry") self.CN2.setDuration(4600) self.CN2.setLoopCount(-1) self.CN2.setStartValue(QRect(1000, 0, 80, 135)) self.CN2.setEndValue(QRect(0, 0, 80, 135)) self.CN2.start() print('c') def stopx(self): self.CN.stop() self.CN1.stop() self.CN2.stop()
class VCBlinkText(QWidget): def __init__(self, text: str, parent=None): super(VCBlinkText, self).__init__(parent) self.label = QLabel(text) self.label.setMinimumHeight(self.label.sizeHint().height() + 20) layout = QHBoxLayout(self) layout.addWidget(self.label) self.effect = QGraphicsOpacityEffect(self.label) self.label.setGraphicsEffect(self.effect) self.anim = QPropertyAnimation(self.effect, b'opacity') self.anim.setDuration(3500) self.anim.setLoopCount(-1) self.anim.setStartValue(1.0) self.anim.setKeyValueAt(0.5, 0.0) self.anim.setEndValue(1.0) self.anim.setEasingCurve(QEasingCurve.OutQuad) self.anim.start(QPropertyAnimation.DeleteWhenStopped) def setAlignment(self, alignment: Qt.AlignmentFlag) -> None: self.label.setAlignment(alignment) def stop(self) -> None: self.anim.stop()
class Window(QWidget): def __init__(self, *args, **kwargs): super(Window, self).__init__(*args, **kwargs) layout = QVBoxLayout(self) layout.addWidget(QPushButton('start', self, clicked=self.onStart)) layout.addWidget(QPushButton('pause', self, clicked=self.onPause)) layout.addWidget(QPushButton('resume', self, clicked=self.onResume)) self._offset = 0 self.pani = QPropertyAnimation(self, b'offset', self) self.pani.setDuration(540) self.pani.setLoopCount(1) self.pani.setStartValue(0) self.pani.setEndValue(360) def onPause(self): self.pani.stop() v = self.pani.currentValue() print('current value:', v, 'duration:', int(v / 360 * 540)) self.pani.setDuration(int(v / 360 * 540)) self.pani.setStartValue(v) self.pani.setEndValue(0) def onResume(self): self.pani.start() def onStart(self): self.pani.start() @pyqtProperty(int) def offset(self): return self._offset @offset.setter def offset(self, o): print(o) self._offset = o
class ZoomButton(QPushButton): def __init__(self, *args, **kwargs): super(ZoomButton, self).__init__(*args, **kwargs) self._animation = QPropertyAnimation( self, b'geometry', self, duration=200) def updatePos(self): # 记录自己的固定的geometry值 self._geometry = self.geometry() self._rect = QRect( self._geometry.x() - 6, self._geometry.y() - 2, self._geometry.width() + 12, self._geometry.height() + 4 ) def showEvent(self, event): super(ZoomButton, self).showEvent(event) self.updatePos() def enterEvent(self, event): super(ZoomButton, self).enterEvent(event) self._animation.stop() # 停止动画 # 修改动画的开始值 self._animation.setStartValue(self._geometry) # 修改动画的终止值 self._animation.setEndValue(self._rect) self._animation.start() def leaveEvent(self, event): super(ZoomButton, self).leaveEvent(event) self._animation.stop() # 停止动画 # 修改动画的开始值 self._animation.setStartValue(self._rect) # 修改动画的终止值 self._animation.setEndValue(self._geometry) self._animation.start() def mousePressEvent(self, event): self._animation.stop() # 停止动画 # 修改动画的开始值 self._animation.setStartValue(self._rect) # 修改动画的终止值 self._animation.setEndValue(self._geometry) self._animation.start() super(ZoomButton, self).mousePressEvent(event)
class RotateButton(QPushButton): STARTVALUE = 0 # 起始旋转角度 ENDVALUE = 360 # 结束旋转角度 DURATION = 540 # 动画完成总时间 def __init__(self, *args, image='', **kwargs): super(RotateButton, self).__init__(*args, **kwargs) self.setCursor(Qt.PointingHandCursor) self._angle = 0 # 角度 self._padding = 10 # 阴影边距 self._image = '' # 图片路径 self._shadowColor = QColor(33, 33, 33) # 阴影颜色 self._pixmap = None # 图片对象 # 属性动画 self._animation = QPropertyAnimation(self, b'angle', self) self._animation.setLoopCount(1) # 只循环一次 self.setPixmap(image) # 绑定提示框 #ToolTip.bind(self) def paintEvent(self, event): """绘制事件""" text = self.text() option = QStyleOptionButton() self.initStyleOption(option) option.text = '' # 不绘制文字 painter = QStylePainter(self) painter.setRenderHint(QStylePainter.Antialiasing) painter.setRenderHint(QStylePainter.HighQualityAntialiasing) painter.setRenderHint(QStylePainter.SmoothPixmapTransform) painter.drawControl(QStyle.CE_PushButton, option) # 变换坐标为正中间 painter.translate(self.rect().center()) painter.rotate(self._angle) # 旋转 # 绘制图片 if self._pixmap and not self._pixmap.isNull(): w = self.width() h = self.height() pos = QPointF(-self._pixmap.width() / 2, -self._pixmap.height() / 2) painter.drawPixmap(pos, self._pixmap) elif text: # 在变换坐标后的正中间画文字 fm = self.fontMetrics() w = fm.width(text) h = fm.height() rect = QRectF(0 - w * 2, 0 - h, w * 2 * 2, h * 2) painter.drawText(rect, Qt.AlignCenter, text) else: super(RotateButton, self).paintEvent(event) def enterEvent(self, _): """鼠标进入事件""" # 设置阴影 # 边框阴影效果 ''' effect = QGraphicsDropShadowEffect(self) effect.setBlurRadius(self._padding * 2) effect.setOffset(0, 0) effect.setColor(self._shadowColor) self.setGraphicsEffect(effect) ''' # 开启旋转动画 self._animation.stop() cv = self._animation.currentValue() or self.STARTVALUE self._animation.setDuration(self.DURATION if cv == 0 else int(cv / self.ENDVALUE * self.DURATION)) self._animation.setStartValue(cv) self._animation.setEndValue(self.ENDVALUE) self._animation.start() def leaveEvent(self, _): """鼠标离开事件""" # 取消阴影 self.setGraphicsEffect(None) # 旋转动画 self._animation.stop() cv = self._animation.currentValue() or self.ENDVALUE self._animation.setDuration(int(cv / self.ENDVALUE * self.DURATION)) self._animation.setStartValue(cv) self._animation.setEndValue(self.STARTVALUE) self._animation.start() def setPixmap(self, path): if not os.path.exists(path): self._image = '' self._pixmap = None return self._image = path size = min(self.width(), self.height()) - self.padding # 需要边距的边框 radius = int(size / 2) image = QImage(size, size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) # 填充背景为透明 pixmap = QPixmap(path).scaled(size, size, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation) # QPainter painter = QPainter() painter.begin(image) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) # QPainterPath path = QPainterPath() path.addRoundedRect(0, 0, size, size, radius, radius) # 切割圆 painter.setClipPath(path) painter.drawPixmap(0, 0, pixmap) painter.end() self._pixmap = QPixmap.fromImage(image) self.update() def pixmap(self): return self._pixmap @pyqtProperty(str) def image(self): return self._image @image.setter def image(self, path): self.setPixmap(path) @pyqtProperty(int) def angle(self): return self._angle @angle.setter def angle(self, value): self._angle = value self.update() @pyqtProperty(int) def padding(self): return self._padding @padding.setter def padding(self, value): self._padding = value @pyqtProperty(QColor) def shadowColor(self): return self._shadowColor @shadowColor.setter def shadowColor(self, color): self._shadowColor = QColor(color)
class Window(QMainWindow): def mousePressEvent(self, event): # 重写一堆方法使其支持拖动 if event.button()==Qt.LeftButton: self.m_drag=True self.m_DragPosition=event.globalPos()-self.pos() event.accept() #self.setCursor(QCursor(Qt.OpenHandCursor)) def mouseMoveEvent(self, QMouseEvent): try: if Qt.LeftButton and self.m_drag: self.move(QMouseEvent.globalPos()-self.m_DragPosition) QMouseEvent.accept() except: pass def mouseReleaseEvent(self, QMouseEvent): self.m_drag=False #self.setCursor(QCursor(Qt.ArrowCursor)) def eventFilter(self, object, event): if event.type() == QEvent.MouseButtonPress: if object == self.lab_close: self.doFadeOut() return True elif object == self.lab_clean: try: self.justdoit() except: self.setWarninfo("没有找到配置文件或配置文件错误,请打开设置") return True elif object == self.lab_config: win = gui_config.Window() return True return False def _frame(self): # 边框 self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground, True) # 阴影 effect = QGraphicsDropShadowEffect(blurRadius=12, xOffset=0, yOffset=0) effect.setColor(QColor(25, 25, 25, 170)) self.mainFrame.setGraphicsEffect(effect) def _connect(self): # 信号 #self.btn_close.clicked.connect(self.doFadeOut) return def _eventfilter(self): # 事件过滤 self.lab_close.installEventFilter(self) self.lab_clean.installEventFilter(self) self.lab_config.installEventFilter(self) def doFadeIn(self): # 动画 self.animation = QPropertyAnimation(self, b'windowOpacity') # 持续时间250ms self.animation.setDuration(250) try: # 尝试先取消动画完成后关闭窗口的信号 self.animation.finished.disconnect(self.close) except: pass self.animation.stop() # 透明度范围从0逐渐增加到1 self.animation.setEasingCurve(QEasingCurve.InOutCubic) self.animation.setStartValue(0) self.animation.setEndValue(1) self.animation.start() def doFadeOut(self): self.animation.stop() # 动画完成则关闭窗口 self.animation.finished.connect(self.close) # 透明度范围从1逐渐减少到0s self.animation.setEasingCurve(QEasingCurve.InOutCubic) self.animation.setStartValue(1) self.animation.setEndValue(0) self.animation.start() def get_fileNum(self, path, day, picCacheCheck, fileCheck, picCheck, videoCheck): dir_name = PureWindowsPath(path) # Convert path to the right format for the current operating system correct_path = Path(dir_name) now = datetime.datetime.now() if picCacheCheck: path_one = correct_path / 'Attachment' path_two = correct_path / 'FileStorage/Cache' self.getPathFileNum(now, day, path_one, path_two) if fileCheck: path_one = correct_path / 'Files' path_two = correct_path / 'FileStorage/File' self.getPathFileNum(now, day, path_one, path_two) if picCheck: path_one = correct_path / 'Image/Image' path_two = correct_path / 'FileStorage/Image' self.getPathFileNum(now, day, path_one, path_two) if videoCheck: path_one = correct_path / 'Video' path_two = correct_path / 'FileStorage/Video' self.getPathFileNum(now, day, path_one, path_two) def pathFileDeal(self, now, day, path): if os.path.exists(path): list = os.listdir(path) filelist = [] for i in range(0, len(list)): file_path = os.path.join(path, list[i]) if os.path.isfile(file_path): filelist.append(list[i]) for i in range(0, len(filelist)): file_path = os.path.join(path, filelist[i]) if os.path.isdir(file_path): continue timestamp = datetime.datetime.fromtimestamp( os.path.getmtime(file_path)) #r = relativedelta.relativedelta(now, timestamp) #if r.years * 12 + r.months > month: diff = (now - timestamp).days if diff > day: self.file_list.append(file_path) def getPathFileNum(self, now, day, path_one, path_two): # caculate path_one self.pathFileDeal(now, day, path_one) # caculate path_two if os.path.exists(path_two): osdir = os.listdir(path_two) dirlist = [] month = math.ceil(day / 29) for i in range(0, len(osdir)): file_path = os.path.join(path_two, osdir[i]) if os.path.isdir(file_path): dirlist.append(osdir[i]) for i in range(0, len(dirlist)): file_path = os.path.join(path_two, dirlist[i]) if os.path.isfile(file_path): continue if re.match('\d{4}(\-)\d{2}', dirlist[i]) != None: cyear = int(dirlist[i].split('-', 1)[0]) cmonth = int(dirlist[i].split('-', 1)[1]) diff = (now.year - cyear) * 12 + now.month - cmonth if diff > month: self.dir_list.append(file_path) elif diff == month: self.pathFileDeal(now, day, file_path) #print("delete:", file_path) def callin(self): #另起一个线程来实现删除文件和更新进度条 self.calc = deleteThread(self.file_list, self.dir_list) self.calc.delete_proess_signal.connect(self.callback) self.calc.start() #self.calc.exec() def callback(self, value): self.bar_progress.setValue(value) if value == 100: out = "本次共清理文件" + str(len(self.file_list)) + "个,文件夹" + str( len(self.dir_list)) + "个。请前往回收站检查并清空。" self.setOKinfo(out) return def setWarninfo(self, text): self.lab_info.setStyleSheet( """ .QLabel { border:1px solid #ffccc7; border-radius:3px; line-height: 140px; padding: 5px; color: #434343; background: #fff2f0; } """ ) self.lab_info.setText(text) def setOKinfo(self, text): self.lab_info.setStyleSheet( """ .QLabel { border:1px solid #b7eb8f; border-radius:3px; line-height: 140px; padding: 5px; color: #434343; background: #f6ffed; } """ ) self.lab_info.setText(text) def justdoit(self): # 这个Api设计的太脑残了,其实dir可以直接放在user里的... 有时间改吧 self.file_list = [] self.dir_list = [] self.config = open(working_dir+"/config.json", encoding="utf-8") self.config = json.load(self.config) i = 0 for value in self.config["users"]: if value["is_clean"]: self.get_fileNum(self.config["data_dir"][i], int(value["clean_days"]), value["clean_pic_cache"],value["clean_file"], value["clean_pic"], value["clean_video"]) i = i + 1 if len(self.file_list) + len(self.dir_list) == 0: self.setWarninfo("没有需要清理的文件(可能是您没打勾哦)") self.callin() def __init__(self): super().__init__() loadUi(working_dir+"/ui/main.ui", self) self._frame() #self._connect() self._eventfilter() self.doFadeIn() self.show()
class dicomImage2DdisplayWidget(QWidget): addSeedsSignal = pyqtSignal(bool) def __init__(self, **kwargs): super(dicomImage2DdisplayWidget, self).__init__() self._face = kwargs.get('face', 0) self._datas = kwargs.get('datas', 0) self._Spacing = kwargs.get('spacing', None) self._low_hu = kwargs.get("low_hu", -1150) self._high_hu = kwargs.get("high_hu", 3250) self._axis = 0 #===============Seeds information============================ self.seedsColors = [] self.baseImageSize = 512 self.regionDrawMod = 0 self.drawLayer = [] #===============Regioin draw tool parmeter=================== self.drawPanterbegin = QPoint() self.drawPanterEnd = QPoint() self.posX = 0 self.posY = 0 #===============Init UI====================================== self.initUI() def initUI(self): self.setGeometry(0, 0, self.baseImageSize, self.baseImageSize) self.viewLayout = None self.imLable = QLabel(self) self.imLable.setScaledContents(True) self.imData = None self.topLable = QLabel(self) self.downLable = QLabel(self) self.imLable.resize(self.width(), self.height()) self.initDicomParameter() pass def initDicomParameter(self): #============================SetDataParameter=========================== self._color_table = [qRgb(i, i, i) for i in range(64)] self.datas = self._datas.copy() self.faceWindowV = self.faceWindowH = max(self.datas.shape) #============================ChangeFaceSize============================= self.xSpacing, self.ySpacing, self.zSpacing = self._Spacing #============================OperationMod=============================== self.OperationMod = 0 self.facePlane = ['mainFaceplane', 'leftFaceplane', 'frontFaceplane'] self.idxSlice = 100 self.currentFace = self.facePlane[self._face] #============================RegionGrowingParameter===================== self.PosXY = [150, 75] # self.seedList = [(self.PosXY[0], self.PosXY[1])] self.seedList = [] self.seedSelectNum = 0 self.LowAndUpper = [10, 3000] self.regionArea = [] self.regionDrawSize = 5 self.idxSlicelimt = self.datas.shape[0] # print(self.datas.shape[0]) #======================================================================= self.initOperationButton() self.initDisplayfacePlane() self.choiceOpreationMod() pass def initOperationButton(self): self.facePlanes = QComboBox(self) self.facePlanes.addItem(self.facePlane[0]) self.facePlanes.addItem(self.facePlane[1]) self.facePlanes.addItem(self.facePlane[2]) self.facePlanes.setCurrentIndex(self._face) # self.facePlanes.activated[str].connect(self.faceItem_Choice) self.facePlanes.currentTextChanged.connect(self.faceItem_Choice) self.facePlanes.keyPressEvent = self.customComboxKeyEvent self.facePlanes.move((self.width() - self.facePlanes.width()), 0) #==================================Active keyBoard event without combobox======================= # shorcut = QShortcut(QKeySequence(Qt.Key_F), self.facePlanes, activated=self.useforTestKeyEvent) #=============================================================================================== #================================== Contrul region seed up and low range ======================= regionWide = QRangeSlider(self) regionWide.setMax(255) regionWide.setMin(0) regionWide.setStart(150) regionWide.setEnd(255) regionWide.setRange(0, 255) regionWide.setDrawValues(True) regionWide.setBackgroundStyle('background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #222, stop:1 #333);') regionWide.handle.setStyleSheet('background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #8EE5EE, stop:1 #393);') regionWide.startValueChanged.connect(self.rangeSliderStartVolue) regionWide.endValueChanged.connect(self.rangeSliderEndVolue) #=============================================================================================== self.modCombox = QComboBox(self) self.modCombox.addItem('Normal') self.modCombox.addItem('Region') self.modCombox.setCurrentIndex(self.OperationMod) # self.modCombox.activated[str].connect(self.mod_Choice) self.modCombox.currentTextChanged.connect(self.mod_Choice) self.modCombox.keyPressEvent = self.customComboxKeyEvent self.modCombox.move((self.width() - self.facePlanes.width() - self.modCombox.width()), 0) self.layerScrollBar = QScrollBar(Qt.Horizontal, self) self.layerScrollBar.setGeometry(0, 0, 128, 5) self.layerScrollBar.setMinimum(0) self.layerScrollBar.setMaximum(min(self.datas.shape)) self.layerScrollBar.setValue(0) self.layerScrollBar.sliderMoved.connect(self.selectLayer) self.BaseBoxLayout = QBoxLayout(QBoxLayout.TopToBottom) self.BaseBoxLayout.addWidget(self.layerScrollBar, 0) self.BaseBoxLayout.addWidget(regionWide, 1) self.BaseBoxLayout.setAlignment(Qt.AlignTop) self.secondBoxLayout = QBoxLayout(QBoxLayout.LeftToRight) self.secondBoxLayout.addLayout(self.BaseBoxLayout) self.secondBoxLayout.addWidget(self.modCombox) self.secondBoxLayout.addWidget(self.facePlanes) self.secondBoxLayout.setAlignment(Qt.AlignTop) self.groupbox = QGroupBox(self) self.groupbox.setGeometry(28, -64, 512, 64) self.groupbox.setLayout(self.secondBoxLayout) self.showButton = QPushButton(self) self.showButton.setGeometry(0, 0, 16, 16) self.showButton.clicked.connect(self.playAnimation) self.initAnimation() pass def setGroup_pos(self, apos): self.groupbox.move(apos.x(), apos.y()) pass def setSeedsColor(self, lists): # self.seedList.clear() # self.seedsColors.clear() # for i in range(0, len(colorList)): # self.seedsColors.append(colorList[i][0]) # self.seedList.append(colorList[i][1]) self.seedsColors.append(lists[0]) self.seedList.append(lists[1]) print('seedList:', self.seedList) pass def selectSeedinList(self, num): # tmpS = self.seedList[num] # tmpC = self.seedsColors[num] self.seedSelectNum = num # print(self.seedsColors) # print(self.seedList) # print('number is :', num) # print(tmpC, tmpS) pass def removeSeedinList(self, num): self.seedList.remove(self.seedList[num]) self.choiceDisplayMod() pass def rangeSliderStartVolue(self, event): self.LowAndUpper[0] = event self.choiceDisplayMod() pass def rangeSliderEndVolue(self, event): self.LowAndUpper[1] = event self.choiceDisplayMod() pass def viewSeedinList(self, event): if event[0] == True: print('Open eye is:', event[1]) elif event[0] == False: print('Close eye is:', event[1]) else: print('viewSeedinList error.....') pass def initAnimation(self): self.isBoardshow = False xAxis = self.groupbox.pos().x() yAxis = self.groupbox.height() self.groupBoxAnim = QPropertyAnimation(self, b'pos') self.groupBoxAnim.setDuration(200) self.groupBoxAnim.setStartValue(QPointF(xAxis, -yAxis)) # self.anim.setKeyValueAt(0.5, QPointF(0, 10)) # self.anim.setKeyValueAt(0.8, QPointF(0, 80)) self.groupBoxAnim.setEndValue(QPointF(xAxis, 0)) self.reverGroupBoxAnim = QPropertyAnimation(self, b'pos') self.reverGroupBoxAnim.setDuration(200) self.reverGroupBoxAnim.setStartValue(QPointF(xAxis, 0)) self.reverGroupBoxAnim.setEndValue(QPointF(xAxis, -yAxis)) pass def playAnimation(self): print('-----PlayAnimation-----') if self.isBoardshow == False: self.reverGroupBoxAnim.stop() self.groupBoxAnim.start() self.isBoardshow = True elif self.isBoardshow == True: self.groupBoxAnim.stop() self.reverGroupBoxAnim.start() self.isBoardshow = False pass pos = pyqtProperty(QPointF, fset=setGroup_pos) def selectLayer(self, event): self.idxSlice = self.layerScrollBar.value() self.choiceDisplayMod() pass def sliderval(self): self._low_hu = self.lowHusBar.value() self._high_hu = self.heighHusBar.value() self.choiceDisplayMod() pass def mod_Choice(self, event): if event == 'Normal': self.OperationMod = 0 elif event == 'Region': self.OperationMod = 1 self.choiceOpreationMod() pass def initDisplayfacePlane(self): if self._face == 0: self.topfaceView() elif self._face == 1: self.leftfaceView() elif self._face == 2: self.frontfaceView() pass def faceItem_Choice(self, faceEvent): if faceEvent == self.facePlane[0]: self.topfaceView() self.currentFace = self.facePlane[0] print('main view') elif faceEvent == self.facePlane[1]: self.leftfaceView() self.currentFace = self.facePlane[1] print('left view') elif faceEvent == self.facePlane[2]: self.frontfaceView() self.currentFace = self.facePlane[2] print('front view') self.choiceOpreationMod() self.getResizeEvent(self.width(), self.height()) pass #==========================MakeSureDisplayMod============================= def choiceDisplayMod(self): if self.OperationMod == 0: self.drawNomralArea() elif self.OperationMod == 1: self.drawGrowingArea() pass #========================================================================= def choiceOpreationMod(self): if self.OperationMod == 0: self.imLable.mouseMoveEvent = self.normalModMouseMoveEvent elif self.OperationMod == 1: self.imLable.mouseMoveEvent = self.regionModMouseMoveEvent self.imLable.mousePressEvent = self.regionModMousePressEvent self.imLable.mouseReleaseEvent = self.regionModMouseReleasedEvent self.imLable.wheelEvent = self.regionGrowingWheelEvent self.choiceDisplayMod() pass def topfaceView(self): self.datas = self._datas.copy() self.idxSlicelimt = self.datas.shape[0] self.faceWindowH = self.faceWindowV = self.width() tmpPalete = QPalette() tmpPalete.setColor(QPalette.Background, QColor(0, 0, 0)) self.setPalette(tmpPalete) #=======================Init drawLayer=================== self.drawLayer = np.full(self.datas.shape, 0) print('topfaceView:', self.drawLayer.shape) pass def leftfaceView(self): self.datas = self._datas.copy() self.datas = np.rot90(self.datas, -1) self.datas = np.rot90(self.datas, axes=(0, 2)) self.idxSlicelimt = self.datas.shape[0] self.setScaleSize(max(self.datas.shape), min(self.datas.shape)) tmpPalete = QPalette() tmpPalete.setColor(QPalette.Background, QColor(0, 0, 0)) self.setPalette(tmpPalete) #=======================Init drawLayer=================== self.drawLayer = np.full(self.datas.shape, 0) print('leftfaceView:', self.drawLayer.shape) pass def frontfaceView(self): self.datas = self._datas.copy() self.datas = np.rot90(self.datas, -1) self.idxSlicelimt = self.datas.shape[0] width = self.datas.shape[0] height = self.datas.shape[1] depth = self.datas.shape[2] self.setScaleSize(max(width, height, depth), min(width, height, depth)) tmpPalete = QPalette() tmpPalete.setColor(QPalette.Background, QColor(0, 0, 0)) self.setPalette(tmpPalete) #=======================Init drawLayer=================== self.drawLayer = np.full(self.datas.shape, 0) print('frontfaceView:', self.drawLayer.shape) pass def drawNomralArea(self): self.idxSlice = np.clip(self.idxSlice, 0, self.idxSlicelimt -1) self.imData = self.datas[self.idxSlice] self.displayDicomImage() pass def drawGrowingArea(self): self.imgOriginal = SimpleITK.GetImageFromArray(self.datas[self.idxSlice]) self.imgWhiteMatter = SimpleITK.ConnectedThreshold(image1=self.imgOriginal, seedList=self.seedList, lower=self.LowAndUpper[0], upper=self.LowAndUpper[1], replaceValue=1, ) self.regionArea = SimpleITK.GetArrayFromImage(self.imgWhiteMatter) #================if use draw or eraser==================== if np.sum(self.drawLayer[self.idxSlice] != 0) != 0: self.regionDrawLayerCombinEvent() self.drawGrowingAreaContour() pass def drawGrowingAreaContour(self): foreColorvalue = 1 self.imgWhiteMatter = SimpleITK.GetImageFromArray(self.regionArea) self.imgWhiteMatterNoHoles = SimpleITK.VotingBinaryHoleFilling(image1=self.imgWhiteMatter, radius=[2] * 3, majorityThreshold=50, backgroundValue=0, foregroundValue=foreColorvalue) regionContour = SimpleITK.LabelContour(self.imgWhiteMatterNoHoles) # tmpWmatter = self.imgWhiteMatter # regionContour = tmpWmatter | regionContour tmpImage = SimpleITK.LabelOverlay(self.imgOriginal, regionContour) regionContourArray = SimpleITK.GetArrayFromImage(tmpImage) self.imData = regionContourArray self.displayDicomImage() pass #==============================Key board event ============================================ def customComboxKeyEvent(self, event): print('ComboxKeyEvent') pass def useforTestKeyEvent(self): print('just test combobox key event') # self.displayDicomImage() pass #==============================Use for display dicom image================================= def displayDicomImage(self): if self.imData is not None: raw_data = self.imData shape = self.imData.shape # maxNum = max(shape) # minNum = min(shape) raw_data[raw_data < 0] = 0 raw_data[raw_data > 255] = 255 if len(shape) >= 3: data = raw_data #=================用于调节对比度的方法======================= # data = (raw_data - self._low_hu) / self.window_width * 256 # print('---------Update3d--------') #=========================================================== data = data.astype(np.int8) tmpImage = QImage(data, shape[1], shape[0], shape[1] * shape[2], QImage.Format_RGB888) pixmap = QPixmap.fromImage(tmpImage) # pixmap = pixmap.scaled(self.faceWindowH , self.faceWindowV ) # pixmap = pixmap.scaled(self.xSpacing, self.zSpacing) # pixmap = pixmap.scaled(1024, 128) self.imLable.setPixmap(pixmap) elif len(shape) < 3: data = raw_data # data = (raw_data - self._low_hu) / self.window_width * 256 # print('---------Update2d---------') data = data.astype(np.int8) tmpImage = QImage(data, shape[1], shape[0], QImage.Format_Grayscale8) tmpImage.setColorTable(self._color_table) pixmap = QPixmap.fromImage(tmpImage) # pixmap = pixmap.scaled(self.faceWindowH, self.faceWindowV) # pixmap = pixmap.scaled(self.xSpacing, self.zSpacing) # pixmap = pixmap.scaled(1024, 128) self.imLable.setPixmap(pixmap) pass def normalModMouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton: xAxis = event.pos().x() yAxis = event.pos().y() self.choiceDisplayMod() pass #=============================Region draw layer operation========================================== def regionDrawLayerEvent(self, x, y, value): self.regionArea[y - self.regionDrawSize:y + self.regionDrawSize, x - self.regionDrawSize:x + self.regionDrawSize] = value self.drawLayer[self.idxSlice] = self.regionArea pass def regionDrawLayerCombinEvent(self): self.regionArea = self.drawLayer[self.idxSlice].astype(np.uint8) pass #=============================Region mod mouse Press and released event============================ def regionModMousePressEvent(self, event): if event.buttons() == Qt.LeftButton and self.regionDrawMod != 0: xAxis = event.pos().x() yAxis = event.pos().y() if xAxis >= 0 and yAxis >= 0: tmpX = math.floor(xAxis * (self.baseImageSize / self.imLable.width())) tmpY = math.floor(yAxis * (self.baseImageSize / self.imLable.height())) if self.regionDrawMod == 1: self.regionDrawLayerEvent(tmpX, tmpY, 1) elif self.regionDrawMod == 2: self.regionDrawLayerEvent(tmpX, tmpY, 0) self.drawGrowingAreaContour() pass def regionModMouseReleasedEvent(self, Event): if Event.buttons() == Qt.RightButton: print('Right button released') pass #================================================================================================== #=====================================Region mod mouse move event================================== def regionModMouseMoveEvent(self, event): self.posX = event.pos().x() self.posY = event.pos().y() if event.buttons() == Qt.LeftButton and self.regionDrawMod == 0: if self.regionDrawMod == 0: xAxis = event.pos().x() yAxis = event.pos().y() if xAxis >= 0 and yAxis >= 0: self.PosXY[0] = math.floor(xAxis * (self.baseImageSize / self.imLable.width())) self.PosXY[1] = math.floor(yAxis * (self.baseImageSize / self.imLable.height())) self.seedList[self.seedSelectNum] = (self.PosXY[0], self.PosXY[1]) else: print('Region Mod has Nagtive number') elif event.buttons() == Qt.LeftButton and self.regionDrawMod != 0: xAxis = event.pos().x() yAxis = event.pos().y() if xAxis >= 0 and yAxis >= 0: tmpX = math.floor(xAxis * (self.baseImageSize / self.imLable.width())) tmpY = math.floor(yAxis * (self.baseImageSize / self.imLable.height())) if self.regionDrawMod == 1: self.regionDrawLayerEvent(tmpX, tmpY, 1) elif self.regionDrawMod == 2: self.regionDrawLayerEvent(tmpX, tmpY, 0) else: print('regionModMouseMoveEvent regionDrawMod error......') return self.drawGrowingAreaContour() return else: print('regionModMouseMoveEvent error......') self.choiceDisplayMod() pass #=================================SetWindowSizeEvent========================================== def setScaleSize(self, maxnum, minnum): self.faceWindowH = maxnum self.faceWindowV = minnum * (max(self.xSpacing, self.ySpacing, self.zSpacing) / min(self.xSpacing, self.ySpacing, self.zSpacing)) pass def getResizeEvent(self, sizeX, sizeY): if self.currentFace == self.facePlane[0]: tmpSize = min(sizeX, sizeY) self.imLable.resize(tmpSize, tmpSize) elif self.currentFace == self.facePlane[1]: #==================Resize Lable=================== self.setScaleSize(min(sizeX, sizeY), min(sizeX, sizeY) * (min(self.datas.shape)/max(self.datas.shape))) self.imLable.resize(self.faceWindowH, self.faceWindowV) elif self.currentFace == self.facePlane[2]: self.setScaleSize(min(sizeX, sizeY), min(sizeX, sizeY) * (min(self.datas.shape) / max(self.datas.shape))) self.imLable.resize(self.faceWindowH, self.faceWindowV) #==================Move Lable===================== maxPosY = max(sizeY, self.imLable.height()) minPoxY = min(sizeY, self.imLable.height()) tmpPosX = np.clip((sizeX - sizeY), 0, max(sizeX, sizeY)) / 2 tmpPosY = (maxPosY - minPoxY) / 2 self.imLable.move(tmpPosX, tmpPosY) pass #===========================mousewheelEvent================================== def regionGrowingWheelEvent(self, event): angle = event.angleDelta() / 8 angleX = angle.x() angleY = angle.y() if angleY > 0: self.regionDrawSize -= 1 elif angleY < 0: self.regionDrawSize += 1 pass #==========================RegionDrawMod===================== def setRegionDrawMod(self, event): if event == 0: self.regionDrawMod = 0 elif event == 1: self.regionDrawMod = 1 elif event == 2: self.regionDrawMod = 2 else: print('setRegionDrawMod error....') pass #====================Use for paint or eraser==================== def paintEvent(self, QPaintEvent): pen1 = QPen(Qt.blue, 1) q = QPainter(self) q.setPen(pen1) q.drawRect(self.posX - 25, self.posY - 25, 50, 50) # print('paintEvent') pass @property def window_width(self): return self._high_hu - self._low_hu #======================================================================================================================= # pathDicom = "D:/Dicomfile/MT_07/" # idxSlice = 50 # reader = SimpleITK.ImageSeriesReader() # filenamesDICOM = reader.GetGDCMSeriesFileNames(pathDicom) # # reader.SetFileNames(filenamesDICOM) # imgOriginals = reader.Execute() # datas = SimpleITK.GetArrayFromImage(imgOriginals) # Spacing = imgOriginals.GetSpacing() # # if __name__ == '__main__': # app = QApplication(sys.argv) # win = dicomImage2DdisplayWidget(face=0, datas= datas, spacing=Spacing) # win.show() # sys.exit(app.exec_())
class CDrawer(QWidget): LEFT, TOP, RIGHT, BOTTOM = range(4) def __init__(self, *args, stretch=1 / 4, widget=None, **kwargs): super(CDrawer, self).__init__(*args, **kwargs) self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint | Qt.Drawer | Qt.NoDropShadowWindowHint) self.setAttribute(Qt.WA_StyledBackground, True) self.setAttribute(Qt.WA_TranslucentBackground, True) self.setStretch(stretch) ## Animation self.animIn = QPropertyAnimation(self, duration=500, easingCurve=QEasingCurve.OutCubic) self.animIn.setPropertyName(b'pos') self.animOut = QPropertyAnimation(self, duration=500, finished=self.onAnimOutEnd, easingCurve=QEasingCurve.OutCubic) self.animOut.setPropertyName(b'pos') self.animFadeIn = QPropertyAnimation(self, duration=400, easingCurve=QEasingCurve.Linear) self.animFadeIn.setPropertyName(b'opacityBG') self.animFadeOut = QPropertyAnimation(self, duration=400, easingCurve=QEasingCurve.Linear) self.animFadeOut.setPropertyName(b'opacityBG') ## Background opacity self.opacityBg = 0 self.stylesheetOpacity = '#CDrawer_alphaWidget{background:rgba(55,55,55,%i);}' self.alphaWidget = QWidget(self, objectName='CDrawer_alphaWidget') self.alphaWidget.setAttribute(Qt.WA_TransparentForMouseEvents, True) self.setWidget(widget) # 子控件 def resizeEvent(self, event): self.alphaWidget.resize(self.size()) super(CDrawer, self).resizeEvent(event) def mousePressEvent(self, event): pos = event.pos() if pos.x() >= 0 and pos.y() >= 0 and self.childAt( pos) == None and self.widget: if not self.widget.geometry().contains(pos): self.animationOut() return super(CDrawer, self).mousePressEvent(event) def show(self): super(CDrawer, self).show() parent = self.parent().window() if self.parent() else self.window() if not parent or not self.widget: return # 设置Drawer大小和主窗口一致 self.setGeometry(parent.geometry()) geometry = self.geometry() self.animationIn(geometry) def animationIn(self, geometry): """进入动画 :param geometry: """ self.widget.setGeometry(0, 0, int(geometry.width() * self.stretch), geometry.height()) self.widget.hide() self.animIn.setStartValue(QPoint(-self.widget.width(), 0)) self.animIn.setEndValue(QPoint(0, 0)) self.opacityBg = 0 self.animFadeIn.setStartValue(0) self.animFadeIn.setEndValue(100) self.animFadeIn.start() self.animIn.start() self.widget.show() def animationOut(self): """离开动画 """ self.animIn.stop() self.animFadeIn.stop() self.opacityBg = 100 self.animFadeOut.setStartValue(100) self.animFadeOut.setEndValue(0) self.animFadeOut.start() geometry = self.widget.geometry() self.animOut.setStartValue(geometry.topLeft()) self.animOut.setEndValue(QPoint(-self.widget.width(), 0)) self.animOut.start() def onAnimOutEnd(self): """离开动画结束 """ # 模拟点击外侧关闭 QApplication.sendEvent( self, QMouseEvent(QMouseEvent.MouseButtonPress, QPointF(-1, -1), Qt.LeftButton, Qt.NoButton, Qt.NoModifier)) self.close() def setWidget(self, widget): """设置子控件 :param widget: """ self.widget = widget if widget: widget.setParent(self) self.animIn.setTargetObject(widget) self.animOut.setTargetObject(widget) self.animFadeIn.setTargetObject(self) self.animFadeOut.setTargetObject(self) def setEasingCurve(self, easingCurve): """设置动画曲线 :param easingCurve: """ self.animIn.setEasingCurve(easingCurve) def getStretch(self): """获取占比 """ return self.stretch def setStretch(self, stretch): """设置占比 :param stretch: """ self.stretch = max(0.1, min(stretch, 0.9)) def getOpacityBG(self): return self.opacityBg def setOpacityBG(self, value): self.opacityBg = value self.alphaWidget.setStyleSheet(self.stylesheetOpacity % (self.opacityBg)) opacityBG = pyqtProperty(int, getOpacityBG, setOpacityBG)
class MainWindow(QWidget): def __init__(self): super().__init__() self.save_location = None self.layout = QVBoxLayout() self.create_credential_boxes() self.create_subsession_box() self.create_plot_type_selection() self.create_mode_selection() self.create_spinbox_settings() self.create_title_box() self.create_run_button() self.create_progress_bar() # Window settings self.setLayout(self.layout) self.setFixedSize(800, 600) def create_credential_boxes(self): self.email = QLineEdit() self.password = QLineEdit() self.password.setEchoMode(QLineEdit.Password) user_pass = credentials.retrieve('iracing') self.email.setPlaceholderText("Email") self.password.setPlaceholderText("Password") if user_pass is not None: username, password = user_pass self.email.setText(username) self.password.setText(password) self.layout.addWidget(self.email) self.layout.addWidget(self.password) def create_subsession_box(self): self.subsession = QLineEdit() self.subsession.setPlaceholderText("Subsession ID (ie. 27983466)") self.subsession.setToolTip("Same as the split number when hovering on results icon. Also found in URL of results page.") self.layout.addWidget(self.subsession) def create_title_box(self): self.title = QLineEdit() self.title.setPlaceholderText("Enter plot title") self.layout.addWidget(self.title) def create_plot_type_selection(self): radio_buttons = [QRadioButton("Swarm Plot"), QRadioButton("Violin Plot")] radio_buttons[0].setChecked(True) button_layout = QHBoxLayout() self.plot_type_group = QButtonGroup() for index, button in enumerate(radio_buttons): button_layout.addWidget(button) self.plot_type_group.addButton(button, index) self.layout.addLayout(button_layout) def create_mode_selection(self): radio_buttons = [QRadioButton("Save to file"), QRadioButton("Interactive")] button_layout = QHBoxLayout() self.mode_group = QButtonGroup() radio_buttons[0].setChecked(True) for index, button in enumerate(radio_buttons): button_layout.addWidget(button) self.mode_group.addButton(button, index) self.layout.addLayout(button_layout) def create_spinbox_settings(self): self.max_drivers = QSpinBox() self.max_drivers.setValue(10) self.outlier_delta = QSpinBox() self.outlier_delta.setValue(3) self.yaxis_delta = QSpinBox() self.yaxis_delta.setValue(0) info = ["Max Drivers", "Outlier Delta", "Y-Axis Delta"] options = [self.max_drivers, self.outlier_delta, self.yaxis_delta] los = [QHBoxLayout(), QHBoxLayout(), QHBoxLayout()] for i, opt, lo in zip(info, options, los): lo.addWidget(QLabel(i)) lo.addWidget(opt) self.layout.addLayout(lo) def create_run_button(self): self.run_button = QPushButton('Run!') self.run_button.clicked.connect(self.run) self.layout.addWidget(self.run_button) self.layout.setAlignment(self.run_button, Qt.AlignHCenter) def create_progress_bar(self): self.progress_bar = QProgressBar() self.progress_bar.setRange(0, 100) self.progress_bar.setValue(0) self.layout.addWidget(self.progress_bar) def query_save_location(self): chosen_filename = QFileDialog.getSaveFileName(self, 'Choose file location for pace graph', os.getcwd(), 'PNG (*.png)')[0] self.save_location = Path(chosen_filename) def warn(self, message): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(message) msg.setWindowTitle("Error!") msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def run(self): if self.mode_group.checkedId() == 0: self.query_save_location() if str(self.save_location) == '.': self.warn("You must select save location if using 'Save to file' mode") return config = WorkerConfig( self.subsession.text(), self.email.text(), self.password.text(), self.max_drivers.value(), self.outlier_delta.value(), self.yaxis_delta.value() if self.yaxis_delta.value() != 0 else None, self.mode_group.checkedId() == 1, self.plot_type_group.checkedId() == 1, self.title.text(), self.save_location ) self.worker = Worker(config) self.worker.finished.connect(self.worker_finished) self.worker.my_signal.connect(self.warn) self.worker.plot_ready.connect(self.show_plot) self.run_button.setEnabled(False) self.animation = QPropertyAnimation(self.progress_bar, b"value") self.animation.setDuration(4000) self.animation.setStartValue(0) self.animation.setEndValue(98) self.animation.setEasingCurve(QEasingCurve.OutExpo) self.animation.start() self.worker.start() def worker_finished(self): self.progress_bar.setValue(100) self.animation.stop() self.run_button.setEnabled(True) def show_plot(self, config, results): # matplotlib prefers to be on main thread, which is why we don't plot in the worker self.run_button.setEnabled(False) try: swarm = LapSwarm(results, config.max_drivers, config.outlier_delta) except EmptyResults: self.warn("No subsession results, please check subsession ID.") return ax = swarm.create_plot(config.title, config.violin, config.yaxis_delta) if config.interactive: interactive_plot(ax) else: file_path = str(config.save_location) export_plot(ax, file_path) self.run_button.setEnabled(True)
class MainWindow(QtWidgets.QMainWindow, gui_main.Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) # Animation self.animation = QPropertyAnimation(self, b'windowOpacity') self.animation.setDuration(800) self.doShow() # ProgressBar self.progressBar.setValue(0) self.progressBar.setTextVisible(False) # Buttons self.to_page_action.clicked.connect(self.action) self.to_page_setting.clicked.connect(self.setting) self.to_page_home.clicked.connect(self.home) self.to_page_graph.clicked.connect(self.Graph) self.setTable.clicked.connect(self.set_to_table) self.setGraph.clicked.connect(self.set_to_graph) self.export_to_xls_.clicked.connect(self.resetBar) # SET self.from_data.setDateTime(one_day) self.to_date.setDateTime(now) self.MCCMNC.setText("*") self.ANI.setText("*") self.Client.addItem(None) self.Vendor.addItem(None) # Combo_box for i in client: self.Client.addItem(i[1]) for s in vendor: self.Vendor.addItem(s[1]) self.threadpool = QThreadPool() def set_to_table(self): worker = Worker(self.UserData) worker.signals.result.connect(self.run_to_table) #worker.signals.finished.connect(self.thread_complete) #worker.signals.progress.connect(self.progress_fn) self.threadpool.start(worker) def set_to_graph(self): worker = Worker(self.UserData) self.doAction() worker.signals.result.connect(self.WebGraph) worker.signals.finished.connect(self.resetBar) self.threadpool.start(worker) def flow(self): print('Start') worker = Worker(self.UserData) self.threadpool.start(worker) def doAction(self): self.progressBar.setValue(0) self.progressBar.setMaximum(0) self.progressBar.setMinimum(0) if self.progressBar.minimum() != self.progressBar.maximum(): self.timer = QTimer(self, timeout=self.onTimeout) self.timer.start(randint(1, 3) * 1000) def resetBar(self): self.step = 0 self.progressBar.setValue(0) self.timer.stop() def onTimeout(self): if self.progressBar.value() >= 100: self.timer.stop() self.timer.deleteLater() del self.timer return self.progressBar.setValue(self.progressBar.value() + 1) def UserData(self): fr = self.from_data.dateTime() star = fr.toPyDateTime() to = self.to_date.dateTime() en = to.toPyDateTime() mnc = self.MCCMNC.text() ani = self.ANI.text() cli = self.Client.currentText() vnd = self.Vendor.currentText() conn = cx_Oracle.connect(setting.connet) cursor = conn.cursor() cursor.execute(setting.url, src=cli, dst=vnd, st=star, en=en, mnc=mnc, ani=ani) result = cursor.fetchall() attempts = [] for row in result: attempts.append(row) cursor.close() conn.close() print('OK') # print(attempts) return attempts def WebGraph(self, s): self.stackedWidget.setCurrentWidget(self.page_chart) attempts = s labels = ['Date', 'attempts', 'ok'] df = pd.DataFrame.from_records(attempts, columns=labels) fig = go.Figure() fig.add_trace(go.Scatter(x=df['Date'], y=df['attempts'], name='Attempts')) fig.add_trace(go.Scatter(x=df['Date'], y=df['ok'], name='Delivrd OK')) fig.update_layout(legend_orientation="h", template="plotly_dark", legend=dict(x=.5, xanchor="center"), hovermode="x", margin=dict(l=0, r=0, t=0, b=0)) fig.update_traces(hoverinfo="all", hovertemplate=" %{x}<br>%{y}") raw_html = '<html><head><meta charset="utf-8" />' raw_html += '<script src="https://cdn.plot.ly/plotly-latest.min.js"></script></head>' raw_html += '<body>' raw_html += plotly.offline.plot(fig, include_plotlyjs=False, output_type='div', config=dict(displayModeBar=False)) raw_html += '</body></html>' self.webGraph.setHtml(raw_html) def run_to_table(self, s): attempts = s self.TABLE.setRowCount(len(attempts)) self.TABLE.setColumnCount(len(attempts[0])) for row_num, row in enumerate(attempts): for cell_num, cell_attem in enumerate(row): self.TABLE.setItem(row_num, cell_num, QTableWidgetItem(str(cell_attem))) def Graph(self): self.stackedWidget.setCurrentWidget(self.page_chart) def setting(self): self.stackedWidget.setCurrentWidget(self.page_setting) def action(self): self.stackedWidget.setCurrentWidget(self.page_action) def home(self): self.stackedWidget.setCurrentWidget(self.page_home) def doShow(self): try: self.animation.finished.disconnect(self.close) except: pass self.animation.stop() self.animation.setStartValue(0) self.animation.setEndValue(1) self.animation.start() self.show()
class WindowNotify(QWidget, Ui_NotifyForm): SignalClosed = pyqtSignal() # 弹窗关闭信号 def __init__(self, title="", content="", timeout=5000, *args, **kwargs): super(WindowNotify, self).__init__(*args, **kwargs) self.setupUi(self) self.setTitle(title).setContent(content) self._timeout = timeout self._init() def setTitle(self, title): if title: self.labelTitle.setText(title) return self def title(self): return self.labelTitle.text() def setContent(self, content): if content: self.labelContent.setText(content) return self def content(self): return self.labelContent.text() def setTimeout(self, timeout): if isinstance(timeout, int): self._timeout = timeout return self def timeout(self): return self._timeout def onView(self): print("onView") webbrowser.open_new_tab("http://alyl.vip") def onClose(self): # 点击关闭按钮时 print("onClose") self.isShow = False QTimer.singleShot(100, self.closeAnimation) # 启动弹回动画 def _init(self): # 隐藏任务栏|去掉边框|顶层显示 self.setWindowFlags(Qt.Tool | Qt.X11BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) # 关闭按钮事件 self.buttonClose.clicked.connect(self.onClose) # 点击查看按钮 self.buttonView.clicked.connect(self.onView) # 是否在显示标志 self.isShow = True # 超时 self._timeouted = False # 桌面 self._desktop = QApplication.instance().desktop() # 窗口初始开始位置 self._startPos = QPoint( self._desktop.screenGeometry().width() - self.width() - 5, self._desktop.screenGeometry().height()) # 窗口弹出结束位置 self._endPos = QPoint( self._desktop.screenGeometry().width() - self.width() - 5, self._desktop.availableGeometry().height() - self.height() - 5) # 初始化位置到右下角 self.move(self._startPos) # 动画 self.animation = QPropertyAnimation(self, b"pos") self.animation.finished.connect(self.onAnimationEnd) self.animation.setDuration(1000) # 1s # 弹回定时器 self._timer = QTimer(self, timeout=self.closeAnimation) def show(self, title="", content="", timeout=5000): self._timer.stop() # 停止定时器,防止第二个弹出窗弹出时之前的定时器出问题 self.hide() # 先隐藏 self.move(self._startPos) # 初始化位置到右下角 super(WindowNotify, self).show() self.setTitle(title).setContent(content).setTimeout(timeout) return self def showAnimation(self): print("showAnimation isShow = True") # 显示动画 self.isShow = True self.animation.stop() # 先停止之前的动画,重新开始 self.animation.setStartValue(self.pos()) self.animation.setEndValue(self._endPos) self.animation.start() # 弹出5秒后,如果没有焦点则弹回去 self._timer.start(self._timeout) # QTimer.singleShot(self._timeout, self.closeAnimation) def closeAnimation(self): print("closeAnimation hasFocus", self.hasFocus()) # 关闭动画 if self.hasFocus(): # 如果弹出后倒计时5秒后还有焦点存在则失去焦点后需要主动触发关闭 self._timeouted = True return # 如果有焦点则不关闭 self.isShow = False self.animation.stop() self.animation.setStartValue(self.pos()) self.animation.setEndValue(self._startPos) self.animation.start() def onAnimationEnd(self): # 动画结束 print("onAnimationEnd isShow", self.isShow) if not self.isShow: print("onAnimationEnd close()") self.close() print("onAnimationEnd stop timer") self._timer.stop() print("onAnimationEnd close and emit signal") self.SignalClosed.emit() def enterEvent(self, event): super(WindowNotify, self).enterEvent(event) # 设置焦点(好像没啥用,不过鼠标点击一下后,该方法就有用了) print("enterEvent setFocus Qt.MouseFocusReason") self.setFocus(Qt.MouseFocusReason) def leaveEvent(self, event): super(WindowNotify, self).leaveEvent(event) # 取消焦点 print("leaveEvent clearFocus") self.clearFocus() if self._timeouted: QTimer.singleShot(1000, self.closeAnimation)
class Window(QMainWindow): def mousePressEvent(self, event): # 重写一堆方法使其支持拖动 if event.button() == Qt.LeftButton: self.m_drag = True self.m_DragPosition = event.globalPos() - self.pos() event.accept() # self.setCursor(QCursor(Qt.OpenHandCursor)) def mouseMoveEvent(self, QMouseEvent): try: if Qt.LeftButton and self.m_drag: self.move(QMouseEvent.globalPos() - self.m_DragPosition) QMouseEvent.accept() except: pass def mouseReleaseEvent(self, QMouseEvent): self.m_drag = False # self.setCursor(QCursor(Qt.ArrowCursor)) def _frame(self): # 边框 self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground, True) # 阴影 effect = QGraphicsDropShadowEffect(blurRadius=12, xOffset=0, yOffset=0) effect.setColor(QColor(25, 25, 25, 170)) self.mainFrame.setGraphicsEffect(effect) def doFadeIn(self): # 动画 self.animation = QPropertyAnimation(self, b'windowOpacity') # 持续时间250ms self.animation.setDuration(250) try: # 尝试先取消动画完成后关闭窗口的信号 self.animation.finished.disconnect(self.close) except: pass self.animation.stop() # 透明度范围从0逐渐增加到1 self.animation.setEasingCurve(QEasingCurve.InOutCubic) self.animation.setStartValue(0) self.animation.setEndValue(1) self.animation.start() def doFadeOut(self): self.animation.stop() # 动画完成则关闭窗口 self.animation.finished.connect(self.close) # 透明度范围从1逐渐减少到0s self.animation.setEasingCurve(QEasingCurve.InOutCubic) self.animation.setStartValue(1) self.animation.setEndValue(0) self.animation.start() def setWarninginfo(self, text): self.lab_info.setStyleSheet(""" .QLabel { border:1px solid #ffccc7; border-radius:3px; line-height: 140px; padding: 5px; color: #434343; background: #fff2f0; } """) self.lab_info.setText(text) def setSuccessinfo(self, text): self.lab_info.setStyleSheet(""" .QLabel { border:1px solid #b7eb8f; border-radius:3px; line-height: 140px; padding: 5px; color: #434343; background: #f6ffed; } """) self.lab_info.setText(text)
class PopupWin(QtWidgets.QWidget): def __init__(self): super().__init__() self._init() def _init(self): # 设置widget大小 self.resize(450, 200) # 隐藏任务栏,去掉边框,顶层显示 self.setWindowFlags(Qt.Tool | Qt.X11BypassWindowManagerHint | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) # 设置样式表 self.setStyleSheet("QWidget#widgetTitle {\n" " background-color: rgb(76, 169, 106);\n" "}\n" "QWidget#widgetBottom {\n" " border-top-style: solid;\n" " border-top-width: 2px;\n" " border-top-color: rgb(185, 218, 201);\n" "}\n" "QLabel#labelTitle {\n" " color: rgb(255, 255, 255);\n" "}\n" "QLabel#labelContent {\n" " padding: 5px;\n" "}\n" "QPushButton {\n" " border: none;\n" " background: transparent;\n" "}\n" "QPushButton#buttonClose {\n" " font-family: \"webdings\";\n" " color: rgb(255, 255, 255);\n" "}\n" "QPushButton#buttonClose:hover {\n" " background-color: rgb(212, 64, 39);\n" "}\n" "QPushButton#buttonView {\n" " color: rgb(255, 255, 255);\n" " border-radius: 5px;\n" " border: solid 1px rgb(76, 169, 106);\n" " background-color: rgb(76, 169, 106);\n" "}\n" "QPushButton#buttonView:hover {\n" " color: rgb(0, 0, 0);\n" "}") # 设置横着的布局,总体布局 self.verticalLayout = QtWidgets.QVBoxLayout(self) # 设置布局内预留的空白边框宽度 self.verticalLayout.setContentsMargins(0, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距6px self.verticalLayout.setSpacing(6) self.verticalLayout.setObjectName("verticalLayout") # 标题栏 self.widgetTitle = QtWidgets.QWidget(self) self.widgetTitle.setMinimumSize(QtCore.QSize(0, 26)) self.widgetTitle.setObjectName("widgetTitle") # 竖着的布局 self.horizontalLayout_1 = QtWidgets.QHBoxLayout(self.widgetTitle) # 设置布局内预留的空白边框宽度 self.horizontalLayout_1.setContentsMargins(10, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距0px self.horizontalLayout_1.setSpacing(0) self.horizontalLayout_1.setObjectName("horizontalLayout_1") # 标题栏标签 self.labelTitle = QtWidgets.QLabel(self.widgetTitle) self.labelTitle.setText("新邮件") self.labelTitle.setObjectName("labelTitle") # 竖着的布局增加标题栏标签 self.horizontalLayout_1.addWidget(self.labelTitle) # 添加空白区宽40px、高20px,宽度尽可能扩大,高度尽可能缩小 spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout_1.addItem(spacerItem) # 关闭按钮 self.buttonClose = QtWidgets.QPushButton(self.widgetTitle) self.buttonClose.setText("r") self.buttonClose.setMinimumSize(QtCore.QSize(30, 30)) self.buttonClose.setMaximumSize(QtCore.QSize(30, 30)) self.buttonClose.setObjectName("buttonClose") # 竖着的布局增加关闭按钮 self.horizontalLayout_1.addWidget(self.buttonClose) # 横着的布局添加竖着的布局的标题栏在上面 self.verticalLayout.addWidget(self.widgetTitle) # 增加放新邮件内容的窗口 self.mailInfo = QtWidgets.QWidget(self) # 430 140 self.mailInfo.resize(420, 130) self.mailInfo.setObjectName("mailInfo") # 在邮件内容窗体中添加竖着的布局 self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.mailInfo) # 设置布局内预留的空白边框宽度 self.horizontalLayout_2.setContentsMargins(10, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距0px self.horizontalLayout_2.setSpacing(10) self.horizontalLayout_2.setObjectName("horizontalLayout_2") # 邮件图标(正常邮件,垃圾邮件,星标邮件) self.mailPicLabel = QtWidgets.QLabel(self) self.mailPicLabel.setMinimumSize(100, 100) self.mailPicLabel.setMaximumSize(100, 100) # 普通邮件图标 self.normalPic = QtGui.QPixmap("./pic/normalMail.png") # 垃圾邮件图标 self.junkPic = QtGui.QPixmap("./pic/junkMail.png") # 星标邮件图标 self.starPic = QtGui.QPixmap("./pic/starMail.png") # 默认邮件图标 self.defaultPic = QtGui.QPixmap("./pic/defaultMail.png") # 设置邮件图标 # self.mailPicLabel.setPixmap(self.normalPic) # 让图片自适应label大小 self.mailPicLabel.setScaledContents(True) self.mailPicLabel.setObjectName("mailPicLabel") self.horizontalLayout_2.addWidget(self.mailPicLabel) self.mailInfoWidget = QtWidgets.QWidget(self) # 添加装载邮件信息的布局 self.mailInfoLayout = QtWidgets.QVBoxLayout(self.mailInfoWidget) # 设置布局内预留的空白边框宽度 self.mailInfoLayout.setContentsMargins(0, 0, 0, 0) # 设置布局内各个空间横向和纵向的间距6px self.mailInfoLayout.setSpacing(6) self.mailInfoLayout.setObjectName("mailInfoLayout") # 主题标签 self.subject = QtWidgets.QLabel(self) self.subject.setText("") self.subject.setWordWrap(True) # 自动换行 self.subject.setObjectName("subject") self.mailInfoLayout.addWidget(self.subject) # 发件人标签 self.sender = QtWidgets.QLabel(self) self.sender.setText("") self.sender.setWordWrap(True) # 自动换行 self.sender.setObjectName("sender") self.mailInfoLayout.addWidget(self.sender) # 邮件内容标签 self.body = QtWidgets.QLabel(self) self.body.setText("") # self.body.setWordWrap(True) # 自动换行 self.body.setObjectName("body") self.mailInfoLayout.addWidget(self.body) self.horizontalLayout_2.addWidget(self.mailInfoWidget) self.verticalLayout.addWidget(self.mailInfo) self.verticalLayout.setObjectName("verticalLayout") # 底部的widget self.widgetBottom = QtWidgets.QWidget(self) self.widgetBottom.setObjectName("widgetBottom") # 底部竖着的布局 self.horizontalLayout = QtWidgets.QHBoxLayout(self.widgetBottom) # 设置布局内预留的空白边框宽度 self.horizontalLayout.setContentsMargins(0, 5, 5, 5) # 设置布局内各个空间横向和纵向的间距0px self.horizontalLayout.setSpacing(0) self.horizontalLayout.setObjectName("horizontalLayout") # 添加空白区宽170px、高20px,宽度尽可能扩大,高度尽可能缩小 spacerItem1 = QtWidgets.QSpacerItem(170, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) # 查看按钮 self.buttonView = QtWidgets.QPushButton(self.widgetBottom) self.buttonView.setText("查看") self.buttonView.setObjectName("buttonView") self.buttonView.setMinimumSize(QtCore.QSize(80, 30)) # 设置光标(手指) self.buttonView.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) self.buttonView.setObjectName("buttonView") self.horizontalLayout.addWidget(self.buttonView) self.verticalLayout.addWidget(self.widgetBottom) # 两个空间1:1 self.verticalLayout.setStretch(1, 1) # 信号:点击关闭按钮 槽函数:以动画形式关闭窗口 self.buttonClose.clicked.connect(self.onclose) # 点击查看按钮 self.buttonView.clicked.connect(self.onView) # 鼠标是否在窗口的标志 self.mouseIsInWidget = False # 是否在显示标志 self.isShow = True # 超时标志 self.isTimeOut = False # 页面停留时间是5s(ok) self.timeout = 5000 # 计时器, 计时开始后每1秒进入一次关闭动画的函数 # self.timer = QTimer(self, timeout = self.closeAnimation) self.timer = QTimer(self) self.timer.setInterval(1000) self.timer.timeout.connect(self.closeAnimation) # 信号关闭信号 # self.SignalClosed = pyqtSignal() # 获取桌面 self.deskTop = QtWidgets.QDesktopWidget() # 获取窗口开始位置 self.startPos = QPoint( self.deskTop.screenGeometry().width() - self.width() - 5, self.deskTop.screenGeometry().height()) # 获取窗口弹出结束位置 self.endPos = QPoint( self.deskTop.screenGeometry().width() - self.width() - 5, self.deskTop.availableGeometry().height() - self.height() - 5) # 添加动画(b'pos'是弹出, b'windowOpacity'是渐隐) self.animation = QPropertyAnimation(self, b'pos') # 设置动画持续时间1s self.animation.setDuration(1000) def onclose(self): # 点击关闭按钮时 self.isShow = False # 按下关闭按钮后0.1s启动弹回动画 QTimer.singleShot(100, self.closeAnimation) print("点击关闭按钮与开启关闭动画相连") def onView(self): # 显示主页面 print("点击查看按钮与显示主页面相连") def show(self, type, subject, sender, body): """type: normal,junk,star""" # 停止计时器,防止第二个弹窗弹出时之前的定时器出现问题 self.timer.stop() # 先隐藏 self.hide() # 初始化位置到右下角 self.move(self.startPos) # 调用父类方法 super(PopupWin, self).show() # 根据邮件种类切换图标 if type == "正常邮件": self.mailPicLabel.setPixmap(self.normalPic) elif type == "垃圾邮件": self.mailPicLabel.setPixmap(self.junkPic) elif type == "星标邮件": self.mailPicLabel.setPixmap(self.starPic) else: self.mailPicLabel.setPixmap(self.defaultPic) self.subject.setText(subject) self.sender.setText(sender) # body长度 try: bodyLen = len(body) if (bodyLen > 40): # 只读取前50个字符, 每20个字符添加一个\n bodyStr = body[0:20] + '\n' + body[20:40] + '...' elif (bodyLen > 20 and bodyLen <= 40): bodyStr = body[0:20] + '\n' + body[20:bodyLen] + '...' else: bodyStr = body self.body.setText(bodyStr) except Exception as e: print(e) print("show调用") return self def showAnimation(self): # 显示动画 self.isShow = True # 先停止之前的动画,重新开始 self.animation.stop() # self.timer.stop() # 设置动画起始和停止的位置 self.animation.setStartValue(self.startPos) self.animation.setEndValue(self.endPos) # 开始动画 self.animation.start() # 弹出5秒后,如果没有焦点则弹回去 # self.timer.start(self.timeout) # 5秒后启动关闭动画 print(self.timeout) QTimer.singleShot(self.timeout, self.closeAnimation) print("showAnimation开始") def closeAnimation(self): # 点击与停留冲突 self.timer.start() # 关闭动画 # 如果鼠标点击了closeButton并停留其上,则执行下面的操作 if self.isShow: print("没有点击关闭按钮") if self.mouseIsInWidget: # 如果弹出后倒计时5秒后鼠标还在窗体里,则鼠标移开后后需要主动触发关闭 self.isTimeOut = True return # 计时器停止 self.timer.stop() # 不再show self.isShow = False self.animation.stop() # 设置动画起始和停止的位置 self.animation.setStartValue(self.endPos) self.animation.setEndValue(self.startPos) self.animation.start() # 动画结束, 关闭当前窗口并清理 self.animation.finished.connect(self.animationEnd) print("showAnimation5秒后与closeAnimation相连") def animationEnd(self): # 动画结束,关闭窗口并清理 print("企图开始清理,但没有") if not self.isShow: # 关闭窗口 self.close() print("关闭了窗口") # 停止计时器 self.timer.stop() print("停止了计时器") # 不清楚是否需要下面这句话 # self.animation.finished.disconnect(self.clearAll) print("animation.finished与self.animationEnd相连") def enterEvent(self, event): super().enterEvent(event) print("in") self.mouseIsInWidget = True def leaveEvent(self, event): super().leaveEvent(event) print("out") self.mouseIsInWidget = False
class StickWidget(QGraphicsObject): font: QFont = QFont("monospace", 32) delete_clicked = pyqtSignal(Stick) link_initiated = pyqtSignal('PyQt_PyObject') # Actually StickWidget link_accepted = pyqtSignal('PyQt_PyObject') hovered = pyqtSignal(['PyQt_PyObject', 'PyQt_PyObject']) stick_changed = pyqtSignal('PyQt_PyObject') sibling_changed = pyqtSignal(bool) right_clicked = pyqtSignal('PyQt_PyObject') handle_idle_brush = QBrush(QColor(0, 125, 125, 50)) handle_hover_brush = QBrush(QColor(125, 125, 0, 50)) handle_press_brush = QBrush(QColor(200, 200, 0, 0)) handle_idle_pen = QPen(QColor(0, 0, 0, 255)) handle_press_pen = QPen(QColor(200, 200, 0, 255)) handle_size = 20 normal_color = QColor(0, 200, 120) negative_color = QColor(200, 0, 0) positive_color = QColor(0, 200, 0) mismatched = pyqtSignal('PyQt_PyObject') misplaced = pyqtSignal('PyQt_PyObject') measurement_corrected = pyqtSignal('PyQt_PyObject') clearly_visible = pyqtSignal('PyQt_PyObject') zero_clicked = pyqtSignal('PyQt_PyObject') def __init__(self, stick: Stick, camera: Camera, parent: Optional[QGraphicsItem] = None): QGraphicsObject.__init__(self, parent) self.camera = camera self.stick = stick self.line = QLineF() self.gline = QGraphicsLineItem(self.line) self.stick_label_text = QGraphicsSimpleTextItem("0", self) self.stick_label_text.setFont(StickWidget.font) self.stick_label_text.setPos(self.line.p1() - QPoint(0, 24)) self.stick_label_text.setBrush(QBrush(QColor(0, 255, 0))) self.stick_label_text.hide() self.setZValue(10) self.mode = StickMode.Display self.btn_delete = Button("delete", "x", parent=self) self.btn_delete.setFlag(QGraphicsItem.ItemIgnoresTransformations, True) self.btn_delete.set_base_color([ButtonColor.RED]) self.btn_delete.setVisible(False) btn_size = max(int(np.linalg.norm(self.stick.top - self.stick.bottom) / 5.0), 15) self.btn_delete.set_height(12) self.btn_delete.clicked.connect(self.handle_btn_delete_clicked) self.btn_delete.setPos(self.line.p1() - QPointF(0.5 * self.btn_delete.boundingRect().width(), 1.1 * self.btn_delete.boundingRect().height())) self.btn_delete.set_opacity(0.7) self.top_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self) self.mid_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self) self.bottom_handle = QGraphicsEllipseItem(0, 0, self.handle_size, self.handle_size, self) self.top_handle.setAcceptedMouseButtons(Qt.NoButton) self.mid_handle.setAcceptedMouseButtons(Qt.NoButton) self.bottom_handle.setAcceptedMouseButtons(Qt.NoButton) self.top_handle.setBrush(self.handle_idle_brush) self.top_handle.setPen(self.handle_idle_pen) self.mid_handle.setBrush(self.handle_idle_brush) self.mid_handle.setPen(self.handle_idle_pen) self.bottom_handle.setBrush(self.handle_idle_brush) self.bottom_handle.setPen(self.handle_idle_pen) self.hovered_handle: Optional[QGraphicsRectItem] = None self.handles = [self.top_handle, self.mid_handle, self.bottom_handle] self.link_button = Button("link", "Link to...", parent=self) self.link_button.set_base_color([ButtonColor.GREEN]) self.link_button.set_height(12) self.link_button.set_label("Link", direction="vertical") self.link_button.fit_to_contents() self.link_button.clicked.connect(lambda: self.link_initiated.emit(self)) self.link_button.setVisible(False) self.link_button.setFlag(QGraphicsObject.ItemIgnoresTransformations, False) self.adjust_line() self.setAcceptHoverEvents(True) self.top_handle.setZValue(4) self.bottom_handle.setZValue(4) self.mid_handle.setZValue(4) self.top_handle.hide() self.mid_handle.hide() self.bottom_handle.hide() self.handle_mouse_offset = QPointF(0, 0) self.available_for_linking = False self.link_source = False self.current_highlight_color: QColor = StickWidget.normal_color self.highlighted = False self.frame_color: Optional[None] = self.normal_color self.is_linked = False self.is_master = True self.selected = False self.measured_height: int = -1 self.current_color = self.normal_color self.show_label = False self.highlight_animation = QPropertyAnimation(self, b"highlight_color") self.highlight_animation.valueChanged.connect(self.handle_highlight_animation_value_changed) self.deleting = False self.update_tooltip() self.show_measurements: bool = False self.proposed_snow_height: int = -1 self.zero_btn = Button("zero_btn", "0", parent=self) self.zero_btn.setFlag(QGraphicsItem.ItemIgnoresTransformations, True) self.zero_btn.setVisible(False) self.zero_btn.setPos(self.boundingRect().center() + QPointF(self.zero_btn.boundingRect().width() * -0.5, self.boundingRect().height() * 0.5)) self.zero_btn.clicked.connect(self.handle_zero) @pyqtSlot() def handle_btn_delete_clicked(self): self.delete_clicked.emit(self.stick) def prepare_for_deleting(self): self.deleting = True self.highlight_animation.stop() self.btn_delete.setParentItem(None) self.scene().removeItem(self.btn_delete) self.btn_delete.deleteLater() def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: Optional[PyQt5.QtWidgets.QWidget] = ...): painter.setPen(QPen(self.current_color, 1.0)) brush = QBrush(self.current_highlight_color) pen = QPen(brush, 4) painter.setPen(pen) if self.highlighted: painter.fillRect(self.boundingRect(), QBrush(self.current_highlight_color)) if self.frame_color is not None and self.mode != StickMode.Edit and self.mode != StickMode.EditDelete: painter.setPen(QPen(self.frame_color, 4)) painter.drawRect(self.boundingRect()) pen = QPen(QColor(0, 255, 0, 255)) pen.setWidth(1.0) pen.setColor(QColor(255, 0, 255, 255)) pen.setStyle(Qt.DotLine) painter.setPen(pen) off = 10 painter.drawLine(self.line.p1() - QPointF(0, off), self.line.p1() + QPointF(0, off)) painter.drawLine(self.line.p1() - QPointF(off, 0), self.line.p1() + QPointF(off, 0)) painter.drawLine(self.line.p2() - QPointF(0, off), self.line.p2() + QPointF(0, off)) painter.drawLine(self.line.p2() - QPointF(off, 0), self.line.p2() + QPointF(off, 0)) pen.setStyle(Qt.SolidLine) pen.setColor(QColor(0, 255, 0, 255)) painter.setPen(pen) if self.mode != StickMode.EditDelete: pen.setWidth(2.0) br = painter.brush() painter.setPen(pen) painter.drawEllipse(self.line.p1(), 10, 10) painter.drawEllipse(self.line.p2(), 10, 10) painter.setBrush(br) if self.mode == StickMode.Measurement and self.proposed_snow_height >= 0: point = QPointF(self.boundingRect().x(), -self.proposed_snow_height + self.line.p2().y()) pen = QPen(QColor(200, 100, 0, 255), 3.0) painter.setPen(pen) painter.drawLine(point, point + QPointF(self.boundingRect().width(), 0.0)) if self.measured_height >= 0: vec = (self.stick.top - self.stick.bottom) / np.linalg.norm(self.stick.top - self.stick.bottom) dist_along_stick = self.measured_height / np.dot(np.array([0.0, -1.0]), vec) point = self.line.p2() + dist_along_stick * QPointF(vec[0], vec[1]) point = QPointF(self.boundingRect().x(), point.y()) pen = QPen(QColor(0, 100, 200, 255), 3.0) painter.setPen(pen) painter.drawLine(point, point + QPointF(self.boundingRect().width(), 0.0)) else: painter.drawLine(self.line.p1(), self.line.p2()) if self.selected: pen.setColor(QColor(255, 125, 0, 255)) pen.setStyle(Qt.DashLine) painter.setPen(pen) painter.drawRect(self.boundingRect().marginsAdded(QMarginsF(5, 5, 5, 5))) if self.show_measurements: painter.fillRect(self.stick_label_text.boundingRect().translated(self.stick_label_text.pos()), QBrush(QColor(0, 0, 0, 120))) def boundingRect(self) -> PyQt5.QtCore.QRectF: return self.gline.boundingRect().united(self.top_handle.boundingRect()).\ united(self.mid_handle.boundingRect()).united(self.bottom_handle.boundingRect()) def set_edit_mode(self, value: bool): if value: self.set_mode(StickMode.EditDelete) else: self.set_mode(StickMode.Display) def set_mode(self, mode: StickMode): if mode == StickMode.Display: self.btn_delete.setVisible(False) self.top_handle.setVisible(False) self.mid_handle.setVisible(False) self.bottom_handle.setVisible(False) self.link_button.setVisible(False) self.available_for_linking = False self.link_source = False self.zero_btn.setVisible(False) self.setVisible(self.stick.is_visible) elif mode == StickMode.EditDelete: self.set_mode(StickMode.Display) self.top_handle.setVisible(True) self.mid_handle.setVisible(True) self.bottom_handle.setVisible(True) self.available_for_linking = False self.link_source = False self.btn_delete.setVisible(True) elif mode == StickMode.LinkSource: self.set_mode(StickMode.Display) self.link_source = True self.available_for_linking = False self.link_button.setPos(self.boundingRect().topLeft()) self.link_button.set_width(int(self.boundingRect().width())) self.link_button.set_button_height(int(self.boundingRect().height())) self.link_button.adjust_text_to_button() elif mode == StickMode.LinkTarget: self.set_mode(StickMode.Display) self.link_source = False self.available_for_linking = True elif mode == StickMode.Edit: self.set_mode(StickMode.EditDelete) self.btn_delete.setVisible(False) elif mode == StickMode.Measurement: self.zero_btn.setVisible(True) self.setVisible(True) self.mode = mode self.update_tooltip() self.update() def mousePressEvent(self, event: QGraphicsSceneMouseEvent): if self.mode != StickMode.EditDelete: return if self.hovered_handle is None: return self.hovered_handle.setBrush(self.handle_press_brush) if self.hovered_handle == self.mid_handle: self.bottom_handle.setBrush(self.handle_press_brush) self.bottom_handle.setPen(self.handle_press_pen) self.bottom_handle.setOpacity(0.5) self.top_handle.setBrush(self.handle_press_brush) self.top_handle.setPen(self.handle_press_pen) self.top_handle.setOpacity(0.5) self.hovered_handle.setPen(self.handle_press_pen) self.hovered_handle.setOpacity(0.5) self.handle_mouse_offset = self.hovered_handle.rect().center() - event.pos() self.btn_delete.setVisible(False) def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent): if self.available_for_linking: self.link_accepted.emit(self) return if self.mode == StickMode.Measurement: old_snow = self.stick.snow_height_px self.measured_height = self.proposed_snow_height self.stick.set_snow_height_px(self.proposed_snow_height) if abs(old_snow - self.proposed_snow_height) > 0: self.measurement_corrected.emit(self) self.proposed_snow_height = -1 if self.mode != StickMode.EditDelete and self.mode != StickMode.Edit: return if self.hovered_handle is not None: self.hovered_handle.setBrush(self.handle_hover_brush) self.hovered_handle.setPen(self.handle_idle_pen) self.hovered_handle.setOpacity(1.0) if self.hovered_handle == self.mid_handle: self.bottom_handle.setBrush(self.handle_idle_brush) self.bottom_handle.setPen(self.handle_idle_pen) self.bottom_handle.setOpacity(1.0) self.top_handle.setBrush(self.handle_idle_brush) self.top_handle.setPen(self.handle_idle_pen) self.top_handle.setOpacity(1.0) self.stick_changed.emit(self) self.hovered_handle = None if self.mode == StickMode.EditDelete: self.btn_delete.setVisible(True) def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent): if self.hovered_handle is None: return if self.hovered_handle == self.top_handle: self.line.setP1((event.pos() + self.handle_mouse_offset).toPoint()) elif self.hovered_handle == self.bottom_handle: self.line.setP2((event.pos() + self.handle_mouse_offset).toPoint()) else: displacement = event.pos() - event.lastPos() self.setPos(self.pos() + displacement) self.adjust_handles() self.adjust_stick() self.scene().update() def set_top(self, pos: QPoint): self.line.setP1(pos) self.adjust_handles() self.adjust_stick() self.scene().update() def set_bottom(self, pos: QPoint): self.line.setP2(pos) self.adjust_handles() self.adjust_stick() self.scene().update() def hoverEnterEvent(self, event: QGraphicsSceneHoverEvent): if self.available_for_linking: self.hovered.emit(True, self) elif self.link_source: self.link_button.setVisible(True) self.scene().update() def hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent): for h in self.handles: h.setBrush(self.handle_idle_brush) self.hovered_handle = None if self.available_for_linking: self.hovered.emit(False, self) self.link_button.setVisible(False) self.proposed_snow_height = -1 self.scene().update() def hoverMoveEvent(self, event: QGraphicsSceneHoverEvent): if self.mode != StickMode.EditDelete and self.mode != StickMode.Edit and self.mode != StickMode.Measurement: return if self.mode == StickMode.Measurement: self.proposed_snow_height = max(self.line.p2().y() - event.pos().y(), 0) self.update() return hovered_handle = list(filter(lambda h: h.rect().contains(event.pos()), self.handles)) if len(hovered_handle) == 0: if self.hovered_handle is not None: self.hovered_handle.setBrush(self.handle_idle_brush) self.hovered_handle = None return if self.hovered_handle is not None and self.hovered_handle != hovered_handle[0]: self.hovered_handle.setBrush(self.handle_idle_brush) self.hovered_handle = hovered_handle[0] if self.hovered_handle == self.top_handle: self.top_handle.setBrush(self.handle_hover_brush) elif self.hovered_handle == self.bottom_handle: self.bottom_handle.setBrush(self.handle_hover_brush) else: self.mid_handle.setBrush(self.handle_hover_brush) self.scene().update() def adjust_stick(self): self.stick.top[0] = self.pos().x() + self.line.p1().x() self.stick.top[1] = self.pos().y() + self.line.p1().y() self.stick.bottom[0] = self.pos().x() + self.line.p2().x() self.stick.bottom[1] = self.pos().y() + self.line.p2().y() def adjust_handles(self): if self.line.p1().y() > self.line.p2().y(): p1, p2 = self.line.p1(), self.line.p2() self.line.setP1(p2) self.line.setP2(p1) if self.hovered_handle is not None: self.hovered_handle.setBrush(self.handle_idle_brush) self.hovered_handle.setPen(self.handle_idle_pen) self.hovered_handle = self.top_handle if self.hovered_handle == self.bottom_handle else self.bottom_handle self.hovered_handle.setBrush(self.handle_press_brush) self.hovered_handle.setPen(self.handle_press_pen) rect = self.top_handle.rect() rect.moveCenter(self.line.p1()) self.top_handle.setRect(rect) rect = self.bottom_handle.rect() rect.moveCenter(self.line.p2()) self.bottom_handle.setRect(rect) rect = self.mid_handle.rect() rect.moveCenter(self.line.center()) self.mid_handle.setRect(rect) self.btn_delete.setPos(self.top_handle.rect().center() - QPointF(self.btn_delete.boundingRect().width() / 2, self.btn_delete.boundingRect().height() + self.top_handle.boundingRect().height() / 2)) def set_available_for_linking(self, available: bool): self.available_for_linking = available def set_is_link_source(self, is_source: bool): self.link_source = is_source self.link_button.setPos(self.boundingRect().topLeft()) self.link_button.set_width(int(self.boundingRect().width())) self.link_button.set_button_height(int(self.boundingRect().height())) self.link_button.adjust_text_to_button() def set_frame_color(self, color: Optional[QColor]): self.frame_color = color if color is not None else self.normal_color self.update() def set_is_linked(self, value: bool): self.is_linked = value if not self.is_linked: self.set_frame_color(None) if self.available_for_linking: self.highlight(QColor(0, 255, 0, 100)) else: self.highlight(None) self.update_tooltip() def adjust_line(self): self.setPos(QPointF(0.5 * (self.stick.top[0] + self.stick.bottom[0]), 0.5 * (self.stick.top[1] + self.stick.bottom[1]))) vec = 0.5 * (self.stick.top - self.stick.bottom) self.line.setP1(QPointF(vec[0], vec[1])) self.line.setP2(-self.line.p1()) self.gline.setLine(self.line) self.adjust_handles() self.stick_label_text.setPos(self.line.p1() - QPointF(0.5 * self.stick_label_text.boundingRect().width(), 1.3 * self.stick_label_text.boundingRect().height())) self.update() def set_selected(self, selected: bool): self.selected = selected self.update() def is_selected(self) -> bool: return self.selected def set_snow_height(self, height: int): self.measured_height = height self.update() def border_normal(self): self.current_color = self.normal_color self.update() def border_positive(self): self.current_color = self.positive_color self.update() def border_negative(self): self.current_color = self.negative_color self.update() @pyqtProperty(QColor) def highlight_color(self) -> QColor: return self.current_highlight_color @highlight_color.setter def highlight_color(self, color: QColor): self.current_highlight_color = color def highlight(self, color: Optional[QColor], animated: bool = False): self.highlighted = color is not None if not animated or color is None: self.highlight_animation.stop() self.current_highlight_color = self.normal_color if color is None else color self.update() return self.highlight_animation.setStartValue(color) self.highlight_animation.setEndValue(color) self.highlight_animation.setKeyValueAt(0.5, color.darker()) self.highlight_animation.setDuration(2000) self.highlight_animation.setLoopCount(-1) self.highlight_animation.start() def handle_link_button_hovered(self, btn: Dict[str, Any]): self.link_button.setVisible(btn['hovered']) def handle_highlight_animation_value_changed(self, new: QColor): if not self.deleting: self.update(self.boundingRect().marginsAdded(QMarginsF(10, 10, 10, 10))) def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None: self.right_clicked.emit({'stick_widget': self}) def set_stick_label(self, label: str): self.stick.label = label self.stick_label_text.setText(label) self.update_tooltip() self.update() def get_stick_label(self) -> str: return self.stick.label def get_stick_length_cm(self) -> int: return self.stick.length_cm def set_stick_length_cm(self, length: int): self.stick.length_cm = length self.update_tooltip() self.update() def update_tooltip(self): if self.mode != StickMode.Display or self.mode == StickMode.Measurement: self.setToolTip("") return snow_txt = "Snow height: " if self.stick.snow_height_px >= 0: snow_txt += str(self.stick.snow_height_cm) + " cm" self.stick_label_text.setText(str(self.stick.snow_height_cm)) else: snow_txt = "not measured" self.stick_label_text.setVisible(False) self.stick_label_text.setText(self.stick.label) self.stick_label_text.setVisible(True) stick_view_text = '' role = '' if self.stick.alternative_view is not None: alt_view = self.stick.alternative_view role = " - primary" alt = "Secondary" if not self.stick.primary: role = " - secondary" alt = "Primary" stick_view_text = f'\n{alt} view: {alt_view.label} in {alt_view.camera_folder.name}\n' mark = '*' if self.stick.determines_quality else '' self.setToolTip(f'{mark}{self.stick.label}{role}{stick_view_text}\nLength: {self.stick.length_cm} cm\n{snow_txt}') def set_stick(self, stick: Stick): self.reset_d_btns() self.stick = stick self.adjust_line() self.adjust_handles() self.set_snow_height(stick.snow_height_px) self.update_tooltip() self.set_show_measurements(self.show_measurements) if self.mode == StickMode.Measurement: self.set_frame_color(QColor(200, 100, 0, 100) if not self.stick.is_visible else None) self.setVisible(True) self.clearly_visible_btn.setVisible(not self.stick.is_visible) else: self.setVisible(self.stick.is_visible) def set_show_measurements(self, show: bool): self.show_measurements = show if self.show_measurements: self.stick_label_text.setText(str(self.stick.snow_height_cm) if self.stick.snow_height_cm >= 0 else "n/a") else: self.stick_label_text.setText(self.stick.label) self.update() def handle_zero(self): self.measured_height = 0 self.stick.set_snow_height_px(0) self.measurement_corrected.emit(self) def reset_d_btns(self): self.zero_btn.set_default_state()
class MyForm(QDialog): def __init__(self): super(MyForm, self).__init__() self.ui = uic.loadUi('Game.ui', self) self.ui.frame.setStyleSheet('background-image:url("Lane.png")') self.image = [ "Car-Blue.png", "Car-Green.png", "Car-Oranges.png", "Car-Pink.png" ] self.setWindowTitle('Car Rush') self.setWindowIcon(QIcon('Supercar.png')) self.ui.pushButton_2.setEnabled(False) self.ui.pushButton_4.setEnabled(True) self.ui.pushButton_3.setEnabled(False) self.ui.pushButton_5.setEnabled(False) self.ui.pushButton_2.clicked.connect(self.Go) self.ui.pushButton_3.clicked.connect(self.stop) self.ui.pushButton_4.clicked.connect(self.Go) self.ui.pushButton_5.clicked.connect(self.resume) self.point = 0 self.x = 190 self.y = 400 self.settime2 = 6000 self.speed2 = 6000 self.settime = 5000 self.speed = 5000 def Go(self): print("Go") MF3 = MyForm3() MF3.show() self.resetpoint() self.setPos() # self.Disable() # Xe1 self.timexe1 = QtCore.QTimer() self.timexe1.start(self.settime) self.timexe1.timeout.connect(self.create) # Xe2 self.timexe2 = QtCore.QTimer() self.timexe2.start(self.settime2) self.timexe2.timeout.connect(self.create2) # point self.time_point = QtCore.QTimer() self.time_point.start(self.speed) self.time_point.timeout.connect(self.calculatePoint) #point 2 self.time_point2 = QtCore.QTimer() self.time_point2.start(self.speed2) self.time_point2.timeout.connect(self.calculatePoint2) # checkx self.timeCheck = QtCore.QTimer() self.timeCheck.start(100) self.timeCheck.timeout.connect(self.check) # time Disable self.timeDisable = QtCore.QTimer() self.timeDisable.start(4000) self.timeDisable.timeout.connect(self.Enabled) def create(self): image = random.choice(self.image) self.labelXe1.setPixmap(QPixmap(image)) self.lstR = [30, 190, 360] self.a = random.choice(self.lstR) self.CN = QPropertyAnimation(self.ui.labelXe1, b"geometry") self.CN.setDuration(self.speed) self.CN.setStartValue(QRect(self.a, -50, 100, 150)) self.CN.setEndValue(QRect(self.a, 800, 100, 150)) self.CN.start() def create2(self): self.lstR2 = [30, 190, 360] r2 = random.choice(self.lstR2) if r2 != self.a: self.labelXe2.setPixmap(QPixmap(random.choice(self.image))) self.CN2 = QPropertyAnimation(self.ui.labelXe2, b"geometry") self.CN2.setDuration(self.speed) self.CN2.setStartValue(QRect(r2, -50, 100, 150)) self.CN2.setEndValue(QRect(r2, 800, 100, 150)) self.CN2.start() else: self.lstR2.remove(self.a) r2 = random.choice(self.lstR2) self.labelXe2.setPixmap(QPixmap(random.choice(self.image))) self.CN2 = QPropertyAnimation(self.ui.labelXe2, b"geometry") self.CN2.setDuration(self.speed) self.CN2.setStartValue(QRect(r2, -50, 100, 150)) self.CN2.setEndValue(QRect(r2, 800, 100, 150)) self.CN2.start() def Enabled(self): print("Enabled") self.ui.pushButton_2.setEnabled(False) self.ui.pushButton_3.setEnabled(True) self.ui.pushButton_4.setEnabled(False) self.ui.pushButton_5.setEnabled(True) self.timeDisable.stop() def Disable(self): print("Disable") self.ui.pushButton_2.setEnabled(False) self.ui.pushButton_3.setEnabled(False) self.ui.pushButton_4.setEnabled(False) self.ui.pushButton_5.setEnabled(False) def setPos(self): self.ui.labelXe1.setGeometry(180, -200, 100, 150) self.ui.label_10.setGeometry(190, 400, 100, 150) self.x = 190 self.y = 400 def check(self): # tọa độ xe 1 w_car = self.ui.labelXe1.width() h_car = self.ui.labelXe1.height() X_car = self.ui.labelXe1.x() Y_car = self.ui.labelXe1.y() # tọa độ xe 2 w_car2 = self.ui.labelXe2.width() h_car2 = self.ui.labelXe2.height() X_car2 = self.ui.labelXe2.x() Y_car2 = self.ui.labelXe2.y() # chiều cao, rộng xe đỏ w_card = self.ui.label_10.width() h_card = self.ui.label_10.height() # print("Xe 1 ", X_car, Y_car, "|","Xe 2 ", X_car2, Y_car2,"|", self.x, self.y) if ((self.x <= (X_car + w_car) and self.x >= X_car) or (self.x + w_card >= X_car and self.x + w_card <= X_car + w_car)) \ and ((h_car + Y_car >= self.y) and (h_card + Y_car <= self.y + h_card) or ((Y_car >= self.y) and (Y_car <= self.y + w_card))): self.time_point.stop() self.time_point2.stop() self.timeCheck.stop() self.timexe1.stop() self.timexe2.stop() self.CN.stop() self.CN2.stop() self.ui.labelXe1.move(-200, -200) self.ui.labelXe2.move(-200, -200) self.Disable() self.a = None print("Game Over") self.MF2 = MyForm2() self.MF2.ui.pushButton.clicked.connect(self.PlayAgain) self.MF2.ui.label.setText('SCORE: ' + str(self.point)) self.MF2.show() if ((self.x <= (X_car2 + w_car2) and self.x >= X_car2) or (self.x + w_card >= X_car2 and self.x + w_card <= X_car2 + w_car2)) \ and ((h_car2 + Y_car2 >= self.y) and (h_card + Y_car2 <= self.y + h_card) or ((Y_car2 >= self.y) and (Y_car2 <= self.y + w_card))): self.time_point.stop() self.time_point2.stop() self.timexe1.stop() self.timexe2.stop() self.timeCheck.stop() self.CN.stop() self.CN2.stop() self.ui.labelXe1.move(-200, -200) self.ui.labelXe2.move(-200, -200) self.Disable() self.a = None print("Game Over") self.MF2 = MyForm2() self.MF2.ui.pushButton.clicked.connect(self.PlayAgain) self.MF2.ui.label.setText('SCORE: ' + str(self.point)) self.MF2.show() def PlayAgain(self): self.Go() self.MF2.close() def move(self): self.anim = QPropertyAnimation(self.ui.label_10, b"geometry") self.anim.setDuration(-10) self.anim.setStartValue(QRect(self.x, self.y, 100, 150)) self.anim.setEndValue(QRect(self.x, self.y, 100, 150)) self.anim.start() def stop(self): self.timexe1.stop() self.timexe2.stop() self.time_point.stop() self.time_point2.stop() self.timeCheck.stop() self.CN.pause() self.CN2.pause() print("End") def resume(self): self.timexe1.start() self.timexe2.start() self.time_point.start() self.time_point2.start() self.timeCheck.start() self.CN.resume() self.CN2.resume() def calculatePoint(self): if self.ui.labelXe1.y() > 700: self.point += 10 self.ui.label.setText(str(self.point)) print("Calculate Point 1") if self.point == 20: self.settime = self.settime - 500 self.speed = self.speed - 500 print(self.settime, self.speed) print(self.point) if self.point == 50: self.settime = self.settime - 500 self.speed = self.speed - 500 print(self.settime, self.speed) if self.point == 70: self.settime = self.settime - 500 self.speed = self.speed - 500 print(self.settime, self.speed) if self.point == 100: self.settime = self.settime - 500 self.speed = self.speed - 500 print(self.settime, self.speed) if self.point == 150: self.settime = self.settime - 500 self.speed = self.speed - 500 print(self.settime, self.speed) if self.point == 200: self.settime = self.settime - 500 self.speed = self.speed - 500 print(self.settime, self.speed) def calculatePoint2(self): if self.ui.labelXe2.y() > 700: self.point += 10 print(self.point) self.ui.label.setText(str(self.point)) print("Calculate Point 2") def resetpoint(self): self.point = 0 self.ui.label.setText(str(0)) def keyPressEvent(self, e): if e.key() == QtCore.Qt.Key_W or e.key() == QtCore.Qt.Key_Up: if self.y > 250: self.y -= 30 self.x += 0 elif e.key() == QtCore.Qt.Key_S or e.key() == QtCore.Qt.Key_Down: if self.y < 420: self.y += 30 # self.x += 0 elif e.key() == QtCore.Qt.Key_A or e.key() == QtCore.Qt.Key_Right: if self.x > 10: self.y += 0 self.x -= 30 elif e.key() == QtCore.Qt.Key_D or e.key() == QtCore.Qt.Key_Left: if self.x < 350: self.y += 0 self.x += 30 self.move()
class PopupWidget(QtWidgets.QWidget): # enum PointerPosition LeftSide = 0 RightSide = 1 TopSide = 2 BottomSide = 3 NoPointer = 4 LR_MARGIN = 10.0 #8.0 #/* left / right margin */ TB_MARGIN = 8.0 #5.5 #/* top / bottom margin */ didHide = pyqtSignal() didShow = pyqtSignal() onClick = pyqtSignal() onRightClick = pyqtSignal() def __init__(self, parent=None, timeout=None, delete_on_hide=True, activation_hides=True, dark_mode=False): ''' parent should be a window or None timeout is the amount of time, in milliseconds, to show the widget before it is auto-hidden. None is no timeout. delete_on_hide, if True, will auto-delete this widget after it is hidden due to the timeout or due to calling hide(). ''' super().__init__(parent) self.layout = QtWidgets.QGridLayout(self) if sys.platform != 'darwin': self.layout.setContentsMargins(20, 20, 20, 20) self.animation = QPropertyAnimation(self) self.final_opacity = 1.0 self.popup_opacity = 1.0 self.pointerPos = self.LeftSide self._timer = None self.activation_hides = activation_hides self.dark_mode = dark_mode and sys.platform.lower() != "darwin" #self.resize(200, 50) self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool) self.setAttribute(Qt.WA_TranslucentBackground) self.setAttribute(Qt.WA_ShowWithoutActivating) self.animation.setTargetObject(self) self.animation.setPropertyName(b'popupOpacity') self.animation.setDuration(200) self.setLayout(self.layout) if parent: parent.installEventFilter(self) self.timeout = timeout self.delete_on_hide = delete_on_hide def getPointerPosition(self): return self.pointerPos def setPointerPosition(self, r): self.pointerPos = r self.update() @pyqtProperty( float ) # Property so that Qt animations work. You may set the actual attrbute directly and ingore this in client code def popupOpacity(self): return self.popup_opacity @popupOpacity.setter def popupOpacity(self, value): self.popup_opacity = value self.setWindowOpacity(value) @pyqtProperty( float ) # Property so that Qt animations work. You may set the actual attrbute directly and ingore this in client code def finalOpacity(self): return self.final_opacity @finalOpacity.setter def finalOpacity(self, value): self.final_opacity = value def paintEvent(self, e): #// Draw the popup here #// You can always pick an image and use drawPixmap to #// draw it in order to make things simpler painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.setClipRegion(e.region()) painter.fillRect(e.rect(), QColor(0, 0, 0, 0)) #// Prepare the popup dimensions roundedRectDimensions = QRectF() roundedRectDimensions.setX(self.rect().x() + self.LR_MARGIN) roundedRectDimensions.setY(self.rect().y() + self.TB_MARGIN) roundedRectDimensions.setWidth(self.rect().width() - self.LR_MARGIN * 2.0) roundedRectDimensions.setHeight(self.rect().height() - self.TB_MARGIN * 2.0) pal = QPalette(self.palette()) painter.setBrush( QBrush( pal.color( QPalette.Window if self.dark_mode else QPalette.Mid))) pen = QPen() pen.setColor( pal.color(QPalette.Light if self.dark_mode else QPalette.Button)) pen.setWidth(3) painter.setPen(pen) #// Draw the popup body painter.drawRoundedRect(roundedRectDimensions, self.LR_MARGIN * 2.0, self.TB_MARGIN * 2.0) painter.setPen(Qt.NoPen) painter.setBrush( QBrush( pal.color( QPalette.BrightText if self.dark_mode else QPalette.Dark))) #// Draw the popup pointer based on relPos self.drawPopupPointer(painter) e.accept() def drawPopupPointer(self, p): r = QRectF(self.rect()) if self.pointerPos == self.LeftSide: PPIX_X = self.LR_MARGIN PPIX_Y = PPIX_X * 2.0 points = [ QPointF(r.x() + PPIX_X, r.height() / 2.0 - PPIX_Y / 2.0), QPointF(r.x() + PPIX_X, r.height() / 2.0 + PPIX_Y / 2.0), QPointF(r.x(), r.height() / 2.0), ] p.drawPolygon(*points) if self.pointerPos == self.RightSide: PPIX_X = self.LR_MARGIN PPIX_Y = PPIX_X * 2.0 points = [ QPointF(r.right() - PPIX_X, r.height() / 2.0 - PPIX_Y / 2.0), QPointF(r.right() - PPIX_X, r.height() / 2.0 + PPIX_Y / 2.0), QPointF(r.right(), r.height() / 2.0), ] p.drawPolygon(*points) if self.pointerPos == self.TopSide: PPIX_Y = self.TB_MARGIN PPIX_X = PPIX_Y * 2.0 points = [ QPointF(r.x() + r.width() / 2.0 - PPIX_X / 2.0, r.top() + PPIX_Y), QPointF(r.x() + r.width() / 2.0 + PPIX_X / 2.0, r.top() + PPIX_Y), QPointF(r.x() + r.width() / 2.0, r.top()), ] p.drawPolygon(*points) if self.pointerPos == self.BottomSide: PPIX_Y = self.TB_MARGIN PPIX_X = PPIX_Y * 2.0 points = [ QPointF(r.x() + r.width() / 2.0 - PPIX_X / 2.0, r.bottom() - PPIX_Y), QPointF(r.x() + r.width() / 2.0 + PPIX_X / 2.0, r.bottom() - PPIX_Y), QPointF(r.x() + r.width() / 2.0, r.bottom()), ] p.drawPolygon(*points) def showRelativeTo(self, w): s = self.size() self.moveRelativeTo(w) self.hide() self.show() if self.pointerPos == self.NoPointer: self.raise_() if s != self.size(): # show caused widget resize.. recenter self.moveRelativeTo(w) def moveRelativeTo(self, w): if not w: print( "INTERNAL ERROR: PopupWidget::showRelativeTo got passed a NULL widget pointer! Ignoring.. FIXME!" ) return p = w.mapToGlobal(QPoint(0, 0)) if self.pointerPos == self.LeftSide: p.setX(p.x() + w.width()) p.setY(p.y() - self.height() // 2 + w.height() // 2) elif self.pointerPos == self.RightSide: p.setX(p.x() - self.width()) p.setY(p.y() - self.height() // 2 + w.height() // 2) elif self.pointerPos == self.BottomSide: p.setX(p.x() + w.width() // 2 - self.width() // 2) p.setY(p.y() - self.height()) elif self.pointerPos == self.TopSide: p.setX(p.x() + w.width() // 2 - self.width() // 2) p.setY(p.y() + w.height()) else: #// just center it on the widget p.setX(p.x() + w.width() // 2 - self.width() // 2) p.setY(p.y() + w.height() // 2 - self.height() // 2) if self.isVisible(): self.raise_() self.move(p) def _killTimer(self): if self._timer: self._timer.stop() self._timer.deleteLater() self._timer = None def _startTimer(self, target): self._killTimer() self._timer = QTimer(self) self._timer.setSingleShot(True) def timeout(): self._killTimer() target() self._timer.timeout.connect(timeout) self._timer.start(int(self.timeout)) def showEvent(self, e): super().showEvent(e) if not e.isAccepted(): return if self.animation.state() == QAbstractAnimation.Running: return self.setWindowOpacity(0.0) self.animation.setStartValue(0.0) self.animation.setEndValue(self.final_opacity) self.didShow.emit() self._cleanUp() self.animation.setDirection(QAbstractAnimation.Forward) self.animation.start() if isinstance(self.timeout, (float, int)) and self.timeout > 0: def autoHide(): self._cleanUp() self._startTimer(self.hideAnimated) self.animation.finished.connect(autoHide) def hideEvent(self, e): super().hideEvent(e) if e.isAccepted(): self._cleanUp() if self.delete_on_hide: self.setParent(None) self.deleteLater() def _disconnectFinished(self): try: self.animation.finished.disconnect() except: pass def hideAnimated(self): if self.animation.state() == QAbstractAnimation.Running: return self._cleanUp() self.animation.setDirection(QAbstractAnimation.Backward) self.animation.start() def doHide(): self._cleanUp() self.hide() self.didHide.emit() self.animation.finished.connect(doHide) def eventFilter(self, obj, e): evts = (QEvent.Move, QEvent.Resize, QEvent.Close, QEvent.Hide, QEvent.Show) if self.activation_hides: evts = (*evts, QEvent.WindowStateChange, QEvent.WindowDeactivate) if e.type() in evts: # if the parent window is moved or otherwise touched, make this popup go away self.hideAnimated() return False def mousePressEvent(self, e): if e.button() == Qt.LeftButton: self.onClick.emit() e.accept() elif e.button() == Qt.RightButton: self.onRightClick.emit() e.accept() def _cleanUp(self): ''' Forces animation and timer to stop. This is essential to force the object into a known consistent state ready for deletion, restart of animations, etc. ''' self._disconnectFinished() self._killTimer() self.animation.stop()