class ColorPicker(QDialog): def __init__(self, lightTheme=False, useAlpha=False): super(ColorPicker, self).__init__() self.usingAlpha = useAlpha # Call UI Builder function if useAlpha: if lightTheme: self.ui = Ui_Light_Alpha() else: self.ui = Ui_Dark_Alpha() self.ui.setupUi(self) else: if lightTheme: self.ui = Ui_Light() else: self.ui = Ui_Dark() self.ui.setupUi(self) # Make Frameless self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.setWindowTitle("Color Picker") # Add DropShadow self.shadow = QGraphicsDropShadowEffect(self) self.shadow.setBlurRadius(17) self.shadow.setXOffset(0) self.shadow.setYOffset(0) self.shadow.setColor(QColor(0, 0, 0, 150)) self.ui.drop_shadow_frame.setGraphicsEffect(self.shadow) # Connect update functions self.ui.hue.mouseMoveEvent = self.moveHueSelector self.ui.red.textEdited.connect(self.rgbChanged) self.ui.green.textEdited.connect(self.rgbChanged) self.ui.blue.textEdited.connect(self.rgbChanged) self.ui.hex.textEdited.connect(self.hexChanged) if self.usingAlpha: self.ui.alpha.textEdited.connect(self.alphaChanged) # Connect window dragging functions self.ui.title_bar.mouseMoveEvent = self.moveWindow self.ui.title_bar.mousePressEvent = self.setDragPos self.ui.window_title.mouseMoveEvent = self.moveWindow self.ui.window_title.mousePressEvent = self.setDragPos # Connect selector moving function self.ui.black_overlay.mouseMoveEvent = self.moveSVSelector self.ui.black_overlay.mousePressEvent = self.moveSVSelector # Connect Ok|Cancel Button Box and X Button self.ui.buttonBox.accepted.connect(self.accept) self.ui.buttonBox.rejected.connect(self.reject) self.ui.exit_btn.clicked.connect(self.reject) self.lastcolor = (0, 0, 0) self.color = (0, 0, 0) self.alpha = 100 ## Main Function def getColor(self, lc=None): if lc != None and self.usingAlpha: alpha = lc[3] lc = lc[:3] self.setAlpha(alpha) self.alpha = alpha if lc == None: lc = self.lastcolor else: self.lastcolor = lc self.setRGB(lc) self.rgbChanged() r, g, b = lc self.ui.lastcolor_vis.setStyleSheet( f"background-color: rgb({r},{g},{b})") if self.exec_(): r, g, b = self.hsv2rgb(self.color) self.lastcolor = (r, g, b) if self.usingAlpha: return (r, g, b, self.alpha) return (r, g, b) else: return self.lastcolor ## Update Functions def hsvChanged(self): h, s, v = (100 - self.ui.hue_selector.y() / 1.85, (self.ui.selector.x() + 6) / 2.0, (194 - self.ui.selector.y()) / 2.0) r, g, b = self.hsv2rgb(h, s, v) self.color = (h, s, v) self.setRGB((r, g, b)) self.setHex(self.hsv2hex(self.color)) self.ui.color_vis.setStyleSheet(f"background-color: rgb({r},{g},{b})") self.ui.color_view.setStyleSheet( f"border-radius: 5px;background-color: qlineargradient(x1:1, x2:0, stop:0 hsl({h}%,100%,50%), stop:1 #fff);" ) def rgbChanged(self): r, g, b = self.i(self.ui.red.text()), self.i( self.ui.green.text()), self.i(self.ui.blue.text()) cr, cg, cb = self.clampRGB((r, g, b)) if r != cr or (r == 0 and self.ui.red.hasFocus()): self.setRGB((cr, cg, cb)) self.ui.red.selectAll() if g != cg or (g == 0 and self.ui.green.hasFocus()): self.setRGB((cr, cg, cb)) self.ui.green.selectAll() if b != cb or (b == 0 and self.ui.blue.hasFocus()): self.setRGB((cr, cg, cb)) self.ui.blue.selectAll() self.color = self.rgb2hsv(r, g, b) self.setHSV(self.color) self.setHex(self.rgb2hex((r, g, b))) self.ui.color_vis.setStyleSheet(f"background-color: rgb({r},{g},{b})") def hexChanged(self): hex = self.ui.hex.text() r, g, b = self.hex2rgb(hex) self.color = self.hex2hsv(hex) self.setHSV(self.color) self.setRGB((r, g, b)) self.ui.color_vis.setStyleSheet(f"background-color: rgb({r},{g},{b})") def alphaChanged(self): alpha = self.i(self.ui.alpha.text()) oldalpha = alpha if alpha < 0: alpha = 0 if alpha > 100: alpha = 100 if alpha != oldalpha or alpha == 0: self.ui.alpha.setText(str(alpha)) self.ui.alpha.selectAll() self.alpha = alpha ## Internal setting functions def setRGB(self, c): r, g, b = c self.ui.red.setText(str(self.i(r))) self.ui.green.setText(str(self.i(g))) self.ui.blue.setText(str(self.i(b))) def setHSV(self, c): self.ui.hue_selector.move(7, (100 - c[0]) * 1.85) self.ui.color_view.setStyleSheet( f"border-radius: 5px;background-color: qlineargradient(x1:1, x2:0, stop:0 hsl({c[0]}%,100%,50%), stop:1 #fff);" ) self.ui.selector.move(c[1] * 2 - 6, (200 - c[2] * 2) - 6) def setHex(self, c): self.ui.hex.setText(c) def setAlpha(self, a): self.ui.alpha.setText(str(a)) ## Color Utility def hsv2rgb(self, h_or_color, s=0, v=0, a=None): if type(h_or_color).__name__ == "tuple": if len(h_or_color) == 4: h, s, v, a = h_or_color else: h, s, v = h_or_color else: h = h_or_color r, g, b = colorsys.hsv_to_rgb(h / 100.0, s / 100.0, v / 100.0) if a != None: return (r * 255, g * 255, b * 255, a) return (r * 255, g * 255, b * 255) def rgb2hsv(self, r_or_color, g=0, b=0, a=None): if type(r_or_color).__name__ == "tuple": if len(r_or_color) == 4: r, g, b, a = r_or_color else: r, g, b = r_or_color else: r = r_or_color h, s, v = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0) if a != None: return (h * 100, s * 100, v * 100, a) return (h * 100, s * 100, v * 100) def hex2rgb(self, hex): if len(hex) < 6: hex += "0" * (6 - len(hex)) elif len(hex) > 6: hex = hex[0:6] rgb = tuple(int(hex[i:i + 2], 16) for i in (0, 2, 4)) return rgb def rgb2hex(self, r_or_color, g=0, b=0, a=0): if type(r_or_color).__name__ == "tuple": r, g, b = r_or_color[:3] else: r = r_or_color hex = '%02x%02x%02x' % (int(r), int(g), int(b)) return hex def hex2hsv(self, hex): return self.rgb2hsv(self.hex2rgb(hex)) def hsv2hex(self, h_or_color, s=0, v=0, a=0): if type(h_or_color).__name__ == "tuple": h, s, v = h_or_color[:3] else: h = h_or_color return self.rgb2hex(self.hsv2rgb(h, s, v)) ## Dragging Functions def setDragPos(self, event): self.dragPos = event.globalPos() def moveWindow(self, event): # MOVE WINDOW if event.buttons() == Qt.LeftButton: self.move(self.pos() + event.globalPos() - self.dragPos) self.dragPos = event.globalPos() event.accept() def moveSVSelector(self, event): if event.buttons() == Qt.LeftButton: pos = event.pos() if pos.x() < 0: pos.setX(0) if pos.y() < 0: pos.setY(0) if pos.x() > 200: pos.setX(200) if pos.y() > 200: pos.setY(200) self.ui.selector.move(pos - QPoint(6, 6)) self.hsvChanged() def moveHueSelector(self, event): if event.buttons() == Qt.LeftButton: pos = event.pos().y() - 7 if pos < 0: pos = 0 if pos > 185: pos = 185 self.ui.hue_selector.move(QPoint(7, pos)) self.hsvChanged() ## Utility ## Custom int() function, that converts uncastable strings to 0 def i(self, text): try: return int(text) except: return 0 ## clamp function to remove near-zero values def clampRGB(self, rgb): r, g, b = rgb if r < 0.0001: r = 0 if g < 0.0001: g = 0 if b < 0.0001: b = 0 if r > 255: r = 255 if g > 255: g = 255 if b > 255: b = 255 return (r, g, b)
class MainWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) # Install the converted ui file as interface self.ui = Ui_MainWindow() self.ui.setupUi(self) # Enables the custom title bar self._configure_title_bar(True) # Set title and description self.setWindowTitle("PyDracula - Modern GUI") self.ui.titleRightInfo.setText( "PyDracula APP - Theme with colors based on Dracula for Python.") # Install event filter to handle own QResizeEvents self.installEventFilter(self) # Holds the position to drag to: self.drag_pos: Optional[QPoint] = None # SET UI DEFINITIONS # /////////////////////////////////////////////////////////////// self.uiDefinitions() # QTableWidget PARAMETERS # /////////////////////////////////////////////////////////////// self.ui.tableWidget.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) # connect button to toggle menu self.ui.toggleButton.clicked.connect(self.toggleMenu) # LEFT MENUS self.ui.btn_home.clicked.connect(self.on_home_btn_clicked) self.ui.btn_widgets.clicked.connect(self.on_widgets_btn_clicked) self.ui.btn_new.clicked.connect(self.on_new_btn_clicked) # EXTRA LEFT BOX self.ui.toggleLeftBox.clicked.connect(self.toggleLeftBox) self.ui.extraCloseColumnBtn.clicked.connect(self.toggleLeftBox) # EXTRA RIGHT BOX self.ui.settingsTopBtn.clicked.connect(self.toggleRightBox) # LOAD AND APPLY STYLE with open(r"themes\py_dracula_dark.qss", "r") as fhandle: self.ui.styleSheet.setStyleSheet(fhandle.read()) # SET MANUAL STYLES self.ui.lineEdit.setStyleSheet("background-color: rgb(98, 114, 164);") self.ui.pushButton.setStyleSheet( "background-color: rgb(98, 114, 164);") self.ui.plainTextEdit.setStyleSheet( "background-color: rgb(98, 114, 164);") self.ui.tableWidget.setStyleSheet( "QScrollBar:vertical { background: rgb(98, 114, 164); } QScrollBar:horizontal { background: rgb(98, 114, 164); }" ) self.ui.scrollArea.setStyleSheet( "QScrollBar:vertical { background: rgb(98, 114, 164); } QScrollBar:horizontal { background: rgb(98, 114, 164); }" ) self.ui.comboBox.setStyleSheet("background-color: rgb(98, 114, 164);") self.ui.horizontalScrollBar.setStyleSheet( "background-color: rgb(98, 114, 164);") self.ui.verticalScrollBar.setStyleSheet( "background-color: rgb(98, 114, 164);") self.ui.commandLinkButton.setStyleSheet("color: rgb(255, 121, 198);") # SET HOME PAGE AND SELECT MENU # /////////////////////////////////////////////////////////////// self.ui.stackedWidget.setCurrentWidget(self.ui.home) self.ui.btn_home.setStyleSheet( self.selectMenu(self.ui.btn_home.styleSheet())) def eventFilter(self, obj: QObject, event: QEvent) -> bool: """Filter events for custom title bar.""" if obj is self.ui.titleRightInfo and event.type( ) == QEvent.MouseButtonDblClick: # This was originally done with a delay of 250 but I didn't like it. # QTimer.singleShot(250, lambda: self.maximize_restore()) self.maximize_restore() if obj is self.ui.titleRightInfo and event.type( ) == QEvent.MouseButtonPress: self.drag_pos = event.globalPos() if obj is self.ui.titleRightInfo and event.type() == QEvent.MouseMove: # Restore the window when it is moved in maximized state. if self.isMaximized(): # TODO: When doing this, we also need to move the window so it's under the mouse cursor! self.maximize_restore() # Move the window to the new position. if event.buttons() == Qt.LeftButton: self.move(self.pos() + event.globalPos() - self.drag_pos) self.drag_pos = event.globalPos() return True if obj is self.ui.titleRightInfo and event.type( ) == QEvent.MouseButtonRelease: # Todo: Check if we should move it to the last received position. self.drag_pos = None if obj is self and event.type() == QEvent.Resize: self.resize_grips() return False def _configure_title_bar(self, custom) -> None: """Configures the app to use a standard or custom title bar.""" self._enable_custom_title_bar = custom if self._enable_custom_title_bar: # Handle double click events to maximize/restore the MainWindow self.ui.titleRightInfo.installEventFilter(self) # Remove standard title bar. self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) # CUSTOM GRIPS self.left_grip = CustomGrip(self, Qt.LeftEdge, True) self.right_grip = CustomGrip(self, Qt.RightEdge, True) self.top_grip = CustomGrip(self, Qt.TopEdge, True) self.bottom_grip = CustomGrip(self, Qt.BottomEdge, True) else: self.ui.appMargins.setContentsMargins(0, 0, 0, 0) self.ui.minimizeAppBtn.hide() self.ui.maximizeRestoreAppBtn.hide() self.ui.closeAppBtn.hide() self.ui.frame_size_grip.hide() @Slot(name="on_home_btn_clicked") def on_home_btn_clicked(self): """Handle a click on the home_btn.""" self.ui.stackedWidget.setCurrentWidget(self.ui.home) self.resetStyle("btn_home") self.ui.btn_home.setStyleSheet( self.selectMenu(self.ui.btn_home.styleSheet())) @Slot(name="on_widgets_btn_clicked") def on_widgets_btn_clicked(self): """Handle a click on the widgets_btn.""" self.ui.stackedWidget.setCurrentWidget(self.ui.widgets) self.resetStyle("btn_widgets") self.ui.btn_widgets.setStyleSheet( self.selectMenu(self.ui.btn_widgets.styleSheet())) @Slot(name="on_new_btn_clicked") def on_new_btn_clicked(self): """Handle a click on the new_btn.""" self.ui.stackedWidget.setCurrentWidget(self.ui.new_page) self.resetStyle("btn_new") self.ui.btn_new.setStyleSheet( self.selectMenu(self.ui.btn_new.styleSheet())) def maximize_restore(self): if not self.isMaximized(): self.showMaximized() self.ui.appMargins.setContentsMargins(0, 0, 0, 0) self.ui.maximizeRestoreAppBtn.setToolTip("Restore") self.ui.maximizeRestoreAppBtn.setIcon( QIcon(":/icons/images/icons/icon_restore.png")) self.ui.frame_size_grip.hide() self.left_grip.hide() self.right_grip.hide() self.top_grip.hide() self.bottom_grip.hide() else: self.showNormal() self.resize(self.width() + 1, self.height() + 1) self.ui.appMargins.setContentsMargins(10, 10, 10, 10) self.ui.maximizeRestoreAppBtn.setToolTip("Maximize") self.ui.maximizeRestoreAppBtn.setIcon( QIcon(":/icons/images/icons/icon_maximize.png")) self.ui.frame_size_grip.show() self.left_grip.show() self.right_grip.show() self.top_grip.show() self.bottom_grip.show() # TOGGLE MENU # /////////////////////////////////////////////////////////////// def toggleMenu(self): # GET WIDTH width = self.ui.leftMenuBg.width() maxExtend = Settings.MENU_WIDTH standard = 60 # SET MAX WIDTH if width == 60: widthExtended = maxExtend else: widthExtended = standard # ANIMATION self.animation = QPropertyAnimation(self.ui.leftMenuBg, b"minimumWidth") self.animation.setDuration(Settings.TIME_ANIMATION) self.animation.setStartValue(width) self.animation.setEndValue(widthExtended) self.animation.setEasingCurve(QEasingCurve.InOutQuart) self.animation.start() # TOGGLE LEFT BOX # /////////////////////////////////////////////////////////////// def toggleLeftBox(self): # GET WIDTH width = self.ui.extraLeftBox.width() widthRightBox = self.ui.extraRightBox.width() color = Settings.BTN_LEFT_BOX_COLOR # GET BTN STYLE style = self.ui.toggleLeftBox.styleSheet() # SET MAX WIDTH if width == 0: # SELECT BTN self.ui.toggleLeftBox.setStyleSheet(style + color) if widthRightBox != 0: style = self.ui.settingsTopBtn.styleSheet() self.ui.settingsTopBtn.setStyleSheet( style.replace(Settings.BTN_RIGHT_BOX_COLOR, "")) else: # RESET BTN self.ui.toggleLeftBox.setStyleSheet(style.replace(color, "")) self.start_box_animation(width, widthRightBox, "left") # TOGGLE RIGHT BOX # /////////////////////////////////////////////////////////////// def toggleRightBox(self): # GET WIDTH width = self.ui.extraRightBox.width() widthLeftBox = self.ui.extraLeftBox.width() color = Settings.BTN_RIGHT_BOX_COLOR # GET BTN STYLE style = self.ui.settingsTopBtn.styleSheet() # SET MAX WIDTH if width == 0: # SELECT BTN self.ui.settingsTopBtn.setStyleSheet(style + color) if widthLeftBox != 0: style = self.ui.toggleLeftBox.styleSheet() self.ui.toggleLeftBox.setStyleSheet( style.replace(Settings.BTN_LEFT_BOX_COLOR, "")) else: # RESET BTN self.ui.settingsTopBtn.setStyleSheet(style.replace(color, "")) self.start_box_animation(widthLeftBox, width, "right") def start_box_animation(self, left_box_width, right_box_width, direction): # Check values if left_box_width == 0 and direction == "left": left_width = 240 else: left_width = 0 # Check values if right_box_width == 0 and direction == "right": right_width = 240 else: right_width = 0 # ANIMATION LEFT BOX self.left_box = QPropertyAnimation(self.ui.extraLeftBox, b"minimumWidth") self.left_box.setDuration(Settings.TIME_ANIMATION) self.left_box.setStartValue(left_box_width) self.left_box.setEndValue(left_width) self.left_box.setEasingCurve(QEasingCurve.InOutQuart) # ANIMATION RIGHT BOX self.right_box = QPropertyAnimation(self.ui.extraRightBox, b"minimumWidth") self.right_box.setDuration(Settings.TIME_ANIMATION) self.right_box.setStartValue(right_box_width) self.right_box.setEndValue(right_width) self.right_box.setEasingCurve(QEasingCurve.InOutQuart) # GROUP ANIMATION self.group = QParallelAnimationGroup() self.group.addAnimation(self.left_box) self.group.addAnimation(self.right_box) self.group.start() # SELECT/DESELECT MENU # /////////////////////////////////////////////////////////////// # SELECT @staticmethod def selectMenu(getStyle): select = getStyle + Settings.MENU_SELECTED_STYLESHEET return select # DESELECT @staticmethod def deselectMenu(getStyle): deselect = getStyle.replace(Settings.MENU_SELECTED_STYLESHEET, "") return deselect # START SELECTION def selectStandardMenu(self, widget): for w in self.ui.topMenu.findChildren(QPushButton): if w.objectName() == widget: w.setStyleSheet(self.selectMenu(w.styleSheet())) # RESET SELECTION def resetStyle(self, widget): for w in self.ui.topMenu.findChildren(QPushButton): if w.objectName() != widget: w.setStyleSheet(self.deselectMenu(w.styleSheet())) # START - GUI DEFINITIONS # /////////////////////////////////////////////////////////////// def uiDefinitions(self): # DROP SHADOW self.shadow = QGraphicsDropShadowEffect(self) self.shadow.setBlurRadius(17) self.shadow.setXOffset(0) self.shadow.setYOffset(0) self.shadow.setColor(QColor(0, 0, 0, 150)) self.ui.bgApp.setGraphicsEffect(self.shadow) # RESIZE WINDOW self.sizegrip = QSizeGrip(self.ui.frame_size_grip) self.sizegrip.setStyleSheet( "width: 20px; height: 20px; margin 0px; padding: 0px;") # MINIMIZE self.ui.minimizeAppBtn.clicked.connect(self.showMinimized) # MAXIMIZE/RESTORE self.ui.maximizeRestoreAppBtn.clicked.connect(self.maximize_restore) # CLOSE APPLICATION self.ui.closeAppBtn.clicked.connect(self.close) def resize_grips(self): if self._enable_custom_title_bar: self.left_grip.setGeometry(0, 10, 10, self.height()) self.right_grip.setGeometry(self.width() - 10, 10, 10, self.height()) self.top_grip.setGeometry(0, 0, self.width(), 10) self.bottom_grip.setGeometry(0, self.height() - 10, self.width(), 10)
class MainWindow(QMainWindow): """Voice Changer main window.""" def __init__(self, parent=None): super(MainWindow, self).__init__() self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.") self.setWindowTitle(__doc__) self.setMinimumSize(240, 240) self.setMaximumSize(480, 480) self.resize(self.minimumSize()) self.setWindowIcon(QIcon.fromTheme("audio-input-microphone")) self.tray = QSystemTrayIcon(self) self.center() QShortcut("Ctrl+q", self, activated=lambda: self.close()) self.menuBar().addMenu("&File").addAction("Quit", lambda: exit()) self.menuBar().addMenu("Sound").addAction( "STOP !", lambda: call('killall rec', shell=True)) windowMenu = self.menuBar().addMenu("&Window") windowMenu.addAction("Hide", lambda: self.hide()) windowMenu.addAction("Minimize", lambda: self.showMinimized()) windowMenu.addAction("Maximize", lambda: self.showMaximized()) windowMenu.addAction("Restore", lambda: self.showNormal()) windowMenu.addAction("FullScreen", lambda: self.showFullScreen()) windowMenu.addAction("Center", lambda: self.center()) windowMenu.addAction("Top-Left", lambda: self.move(0, 0)) windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position()) # widgets group0 = QGroupBox("Voice Deformation") self.setCentralWidget(group0) self.process = QProcess(self) self.process.error.connect( lambda: self.statusBar().showMessage("Info: Process Killed", 5000)) self.control = QDial() self.control.setRange(-10, 20) self.control.setSingleStep(5) self.control.setValue(0) self.control.setCursor(QCursor(Qt.OpenHandCursor)) self.control.sliderPressed.connect( lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor))) self.control.sliderReleased.connect( lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor))) self.control.valueChanged.connect( lambda: self.control.setToolTip(f"<b>{self.control.value()}")) self.control.valueChanged.connect(lambda: self.statusBar().showMessage( f"Voice deformation: {self.control.value()}", 5000)) self.control.valueChanged.connect(self.run) self.control.valueChanged.connect(lambda: self.process.kill()) # Graphic effect self.glow = QGraphicsDropShadowEffect(self) self.glow.setOffset(0) self.glow.setBlurRadius(99) self.glow.setColor(QColor(99, 255, 255)) self.control.setGraphicsEffect(self.glow) self.glow.setEnabled(False) # Timer to start self.slider_timer = QTimer(self) self.slider_timer.setSingleShot(True) self.slider_timer.timeout.connect(self.on_slider_timer_timeout) # an icon and set focus QLabel(self.control).setPixmap( QIcon.fromTheme("audio-input-microphone").pixmap(32)) self.control.setFocus() QVBoxLayout(group0).addWidget(self.control) self.menu = QMenu(__doc__) self.menu.addAction(__doc__).setDisabled(True) self.menu.setIcon(self.windowIcon()) self.menu.addSeparator() self.menu.addAction( "Show / Hide", lambda: self.hide() if self.isVisible() else self.showNormal()) self.menu.addAction("STOP !", lambda: call('killall rec', shell=True)) self.menu.addSeparator() self.menu.addAction("Quit", lambda: exit()) self.tray.setContextMenu(self.menu) self.make_trayicon() def run(self): """Run/Stop the QTimer.""" if self.slider_timer.isActive(): self.slider_timer.stop() self.glow.setEnabled(True) call('killall rec ; killall play', shell=True) self.slider_timer.start(3000) def on_slider_timer_timeout(self): """Run subprocess to deform voice.""" self.glow.setEnabled(False) value = int(self.control.value()) * 100 command = f'play -q -V0 "|rec -q -V0 -n -d -R riaa bend pitch {value} "' print(f"Voice Deformation Value: {value}") print(f"Voice Deformation Command: {command}") self.process.start(command) if self.isVisible(): self.statusBar().showMessage("Minimizing to System TrayIcon", 3000) print("Minimizing Main Window to System TrayIcon now...") sleep(3) self.hide() def center(self): """Center Window on the Current Screen,with Multi-Monitor support.""" window_geometry = self.frameGeometry() mousepointer_position = QApplication.desktop().cursor().pos() screen = QApplication.desktop().screenNumber(mousepointer_position) centerPoint = QApplication.desktop().screenGeometry(screen).center() window_geometry.moveCenter(centerPoint) self.move(window_geometry.topLeft()) def move_to_mouse_position(self): """Center the Window on the Current Mouse position.""" window_geometry = self.frameGeometry() window_geometry.moveCenter(QApplication.desktop().cursor().pos()) self.move(window_geometry.topLeft()) def make_trayicon(self): """Make a Tray Icon.""" if self.windowIcon() and __doc__: self.tray.setIcon(self.windowIcon()) self.tray.setToolTip(__doc__) self.tray.activated.connect( lambda: self.hide() if self.isVisible() else self.showNormal()) return self.tray.show()
class CircularProgress(QWidget): def __init__(self): QWidget.__init__(self) self.shadow = QGraphicsDropShadowEffect(self) self.value = 0 self.width = 200 self.height = 200 self.progress_width = 10 self.progress_rounded_cap = True self.progress_color = 0x4988D1 self.max_value = 100 self.font_family = "Segoe UI" self.font_size = 12 self.suffix = "%" self.text_color = 0x498BD1 self.enable_shadow = True self.resize(self.width, self.height) def paintEvent(self, event: QtGui.QPaintEvent) -> None: width = self.width - self.progress_width height = self.height - self.progress_width margin = int(self.progress_width / 2) value = (self.value * 360) / self.max_value paint = QtGui.QPainter() paint.begin(self) paint.setRenderHint(QtGui.QPainter.Antialiasing) paint.setFont(QtGui.QFont(self.font_family, self.font_size)) rect = QtCore.QRect(0, 0, self.width, self.height) paint.setPen(Qt.NoPen) paint.drawRect(rect) pen = QtGui.QPen() pen.setColor(QtGui.QColor(self.progress_color)) pen.setWidth(self.progress_width) if self.progress_rounded_cap: pen.setCapStyle(Qt.RoundCap) paint.setPen(pen) paint.drawArc(margin, margin, width, height, -90 * 16, int(-value * 16)) pen.setColor(QtGui.QColor(self.text_color)) paint.setPen(pen) paint.drawText(rect, Qt.AlignCenter, f"{self.value}{self.suffix}") paint.end() def set_value(self, value: int): self.value = value def add_shadow(self, enable): if enable: self.shadow.setBlurRadius(5) self.shadow.setXOffset(0) self.shadow.setYOffset(0) self.shadow.setColor(QtGui.QColor(0, 0, 0, 120)) self.setGraphicsEffect(self.shadow)