コード例 #1
0
 def UiComponents(self):
     button = QPushButton("Close Window", self)
     button.setGeometry(QRect(100, 100, 111, 50))
     button.setIcon(QtGui.QIcon("home.png"))
     button.setIconSize(QSize(40, 40))
     button.setToolTip("This Is Click Me Button")
     button.clicked.connect(ClickMe)
コード例 #2
0
    def initUI(self):

        QToolTip.setFont(QFont('SansSerif', 10))

        self.setToolTip('This is a <b>QWidget</b> widget')

        btn = QPushButton('Button', self)
        btn.setToolTip('This is a <b>QPushButton</b> widget')
        btn.resize(btn.sizeHint())
        btn.move(50, 50)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Tooltips')
        self.show()
コード例 #3
0
ファイル: message-box-example.py プロジェクト: wbeebe/pyqt
    def __init__(self):
        app = QApplication(sys.argv)
        super().__init__()
        self.setWindowTitle('PyQt6 Message Box')
        self.setGeometry(100, 100, 320, 200)

        #
        # Create a button that when clicked will pop up our dialog.
        # Connect our function on_click so that it is called when
        # the button is clicked.
        #
        button = QPushButton('Click to Open Message Box', self)
        button.setToolTip('This opens an example message box')
        button.clicked.connect(self.on_click)
        #
        # Add the button to the center of our simple window.
        #
        widget = QWidget()
        layout = QHBoxLayout(widget)
        layout.addWidget(button)
        self.setCentralWidget(widget)

        self.show()
        sys.exit(app.exec())
コード例 #4
0
ファイル: button-example.py プロジェクト: wbeebe/pyqt
    def __init__(self):
        app = QApplication(sys.argv)
        super().__init__()

        self.setWindowTitle('PyQt6 simple button example')
        self.setGeometry(100, 100, 360, 140)

        button = QPushButton('PyQt6 Push Button', self)
        button.setToolTip('Click button to change window status message.')
        #
        # Not too sure about setting the fixed size of the button.
        # But I did that to keep the button from stretching across the width of
        # the window. Must be a way to have the button fit the size of it's text.
        #
        button.clicked.connect(self.on_click)
        button.setFixedSize(150, 30)

        widget = QWidget()
        layout = QHBoxLayout(widget)
        layout.addWidget(button)
        self.setCentralWidget(widget)
        self.statusBar().showMessage('Operational')
        self.show()
        sys.exit(app.exec())
コード例 #5
0
class Window(QDialog):
    def __init__(self):
        super().__init__()

        self.title = "PyQt6 Window"
        self.top = 100
        self.left = 100
        self.width = 400
        self.height = 300

        self.InitWindow()

    def InitWindow(self):
        self.setWindowIcon(QtGui.QIcon("home.png"))
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        self.createLayout()
        vbox = QVBoxLayout()
        vbox.addWidget(self.groupBox)
        self.setLayout(vbox)

        self.show()

    def createLayout(self):
        self.groupBox = QGroupBox("What Is Your Favorite Sport?")

        hboxlayout = QHBoxLayout()

        self.button = QPushButton("Football", self)
        self.button.setIcon(QtGui.QIcon("home.png"))
        self.button.setIconSize(QSize(40, 40))
        self.button.setToolTip("This Is Click Me Button")
        self.button.setMinimumHeight(40)
        hboxlayout.addWidget(self.button)

        self.button1 = QPushButton("Cricket", self)
        self.button1.setIcon(QtGui.QIcon("home.png"))
        self.button1.setIconSize(QSize(40, 40))
        self.button1.setMinimumHeight(40)
        self.button1.setToolTip("This Is Click Me Button")
        hboxlayout.addWidget(self.button1)

        self.button2 = QPushButton("Tennis", self)
        self.button2.setIcon(QtGui.QIcon("home.png"))
        self.button2.setIconSize(QSize(40, 40))
        self.button2.setMinimumHeight(40)
        self.button2.setToolTip("This Is Click Me Button")
        hboxlayout.addWidget(self.button2)

        self.groupBox.setLayout(hboxlayout)
コード例 #6
0
 def __init__(self):
     super().__init__()
     self.logger = logging.getLogger(__name__)
     formatter = logging.Formatter(
         fmt="%(asctime)s-%(levelname)s-%(message)s",
         datefmt="%Y-%m-%d %H:%M:%S")
     filehandler = logging.FileHandler(filename="logs.log",
                                       mode="w",
                                       encoding="utf-8")
     handler = QLogger(update_signal=self.update_signal)
     handler.setLevel(logging.INFO)
     filehandler.setLevel(logging.INFO)
     self.logger.setLevel(logging.INFO)
     if os.path.exists("config.json") == False:
         self.gen_conf()
     with open(file="config.json", mode="r",
               encoding="utf-8") as conf_reader:
         conf = json.loads(conf_reader.read())
     debug = bool(conf["debug"])
     if debug == True:
         handler.setLevel(logging.DEBUG)
         filehandler.setLevel(logging.DEBUG)
         self.logger.setLevel(logging.DEBUG)
     handler.setFormatter(formatter)
     filehandler.setFormatter(formatter)
     self.logger.addHandler(handler)
     self.logger.addHandler(filehandler)
     self.logger.debug("当前调试状态:%s" % debug)
     self.resize(1024, 768)
     self.setWindowOpacity(0.9)
     self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
     self.setWindowFlag(Qt.WindowFlags.FramelessWindowHint)
     self.setAutoFillBackground(True)
     self.work = Work(show_qr_signal=self.show_qr_signal,
                      finish_signal=self.finish_signal,
                      close_qr_signal=self.close_qr_signal)
     self.work_thread = QThread()
     self.work.moveToThread(self.work_thread)
     self.main_layout = QGridLayout()
     self.setLayout(self.main_layout)
     self.title = QLabel("ChinaUniOnlineGUI")
     self.title.setStyleSheet(
         "QLabel{border:none;border-radius:5px;background:transparent;color:#9AD3BC;font-size:60px;}"
     )
     self.title.setAlignment(Qt.Alignment.AlignCenter)
     handler.widget.setStyleSheet(
         "QPlainTextEdit{font-family:Microsoft YaHei;background:#F3EAC2;border:none;border-radius:5px;}QScrollBar:vertical,QScrollBar::handle:vertical{background:#F3EAC2;border:none;border-radius:8px;width:16px;}QScrollBar::handle:vertical:hover{background:#F5B461;}QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical{background:#FFFDF9;border:none;border-radius:8px;width:16px;}QScrollBar::down-arrow:vertical,QScrollBar::up-arrow:vertical{background:#F5B461;border:none;border-radius:8px;width:16px;height:16px;}QScrollBar::sub-line:vertical,QScrollBar::add-line:vertical{background:transparent;border:none;}"
     )
     self.control = QVBoxLayout()
     self.control_close = QPushButton()
     self.control_close.setToolTip("关闭")
     self.control_close.setStyleSheet(
         "QPushButton{background:#FFE3ED;border-radius:5px;border:none;}QPushButton:hover{background:#EC524B;}"
     )
     self.contron_max = QPushButton()
     if self.isMaximized() == False:
         self.contron_max.setToolTip("最大化")
     else:
         self.contron_max.setToolTip("还原")
     self.contron_max.setStyleSheet(
         "QPushButton{background:#FFFDF9;border-radius:5px;border:none;}QPushButton:hover{background:#F5B461;}"
     )
     self.control_min = QPushButton()
     self.control_min.setToolTip("最小化")
     self.control_min.setStyleSheet(
         "QPushButton{background:#BEEBE9;border-radius:5px;border:none;}QPushButton:hover{background:#F3EAC2;}"
     )
     self.start_button = QPushButton("开始(&S)")
     self.start_button.setStyleSheet(
         "QPushButton{background:#9BE3DE;border:none;border-radius:5px;font-size:20px;font-family:DengXian;}QPushButton:hover{background:#9AD3BC;}"
     )
     self.start_button.setToolTip("开始")
     self.start_button.setFixedSize(120, 60)
     self.start_button.setDefault(True)
     setting_button = QPushButton("设置")
     setting_button.setToolTip("设置")
     setting_button.setFixedSize(60, 60)
     setting_button.setStyleSheet(
         "QPushButton{background:#9BE3DE;border:none;border-radius:5px;font-size:20px;font-family:DengXian;}QPushButton:hover{background:#9AD3BC;}"
     )
     setting_button.clicked.connect(self.setting_callback)
     start = QHBoxLayout()
     start.addWidget(self.start_button, 2)
     start.addWidget(setting_button, 1)
     self.control_close.clicked.connect(self.close)
     self.control_min.clicked.connect(self.min_callback)
     self.contron_max.clicked.connect(self.max_callback)
     self.start_button.clicked.connect(self.start_callback)
     self.work_thread.started.connect(self.work.start)
     self.finish_signal.connect(self.finish_callback)
     self.close_qr_signal.connect(self.close_qr)
     self.control.addWidget(self.control_min)
     self.control.addWidget(self.contron_max)
     self.control.addWidget(self.control_close)
     self.main_layout.addLayout(self.control, 0, 0)
     self.main_layout.addWidget(self.title, 0, 1)
     self.main_layout.addLayout(start, 0, 2)
     self.main_layout.addWidget(handler.widget, 1, 1)
     self.update_signal.connect(handler.widget.appendPlainText)
     handler.widget.textChanged.connect(handler.scroll_widget_to_bottom)
     self.show_qr_signal.connect(self.show_qr)
     self.logger.debug("已初始化UI")
コード例 #7
0
class UI(QWidget):
    update_signal = pyqtSignal(str)
    show_qr_signal = pyqtSignal(bytes)
    finish_signal = pyqtSignal()
    close_qr_signal = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.logger = logging.getLogger(__name__)
        formatter = logging.Formatter(
            fmt="%(asctime)s-%(levelname)s-%(message)s",
            datefmt="%Y-%m-%d %H:%M:%S")
        filehandler = logging.FileHandler(filename="logs.log",
                                          mode="w",
                                          encoding="utf-8")
        handler = QLogger(update_signal=self.update_signal)
        handler.setLevel(logging.INFO)
        filehandler.setLevel(logging.INFO)
        self.logger.setLevel(logging.INFO)
        if os.path.exists("config.json") == False:
            self.gen_conf()
        with open(file="config.json", mode="r",
                  encoding="utf-8") as conf_reader:
            conf = json.loads(conf_reader.read())
        debug = bool(conf["debug"])
        if debug == True:
            handler.setLevel(logging.DEBUG)
            filehandler.setLevel(logging.DEBUG)
            self.logger.setLevel(logging.DEBUG)
        handler.setFormatter(formatter)
        filehandler.setFormatter(formatter)
        self.logger.addHandler(handler)
        self.logger.addHandler(filehandler)
        self.logger.debug("当前调试状态:%s" % debug)
        self.resize(1024, 768)
        self.setWindowOpacity(0.9)
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.setWindowFlag(Qt.WindowFlags.FramelessWindowHint)
        self.setAutoFillBackground(True)
        self.work = Work(show_qr_signal=self.show_qr_signal,
                         finish_signal=self.finish_signal,
                         close_qr_signal=self.close_qr_signal)
        self.work_thread = QThread()
        self.work.moveToThread(self.work_thread)
        self.main_layout = QGridLayout()
        self.setLayout(self.main_layout)
        self.title = QLabel("ChinaUniOnlineGUI")
        self.title.setStyleSheet(
            "QLabel{border:none;border-radius:5px;background:transparent;color:#9AD3BC;font-size:60px;}"
        )
        self.title.setAlignment(Qt.Alignment.AlignCenter)
        handler.widget.setStyleSheet(
            "QPlainTextEdit{font-family:Microsoft YaHei;background:#F3EAC2;border:none;border-radius:5px;}QScrollBar:vertical,QScrollBar::handle:vertical{background:#F3EAC2;border:none;border-radius:8px;width:16px;}QScrollBar::handle:vertical:hover{background:#F5B461;}QScrollBar::add-page:vertical,QScrollBar::sub-page:vertical{background:#FFFDF9;border:none;border-radius:8px;width:16px;}QScrollBar::down-arrow:vertical,QScrollBar::up-arrow:vertical{background:#F5B461;border:none;border-radius:8px;width:16px;height:16px;}QScrollBar::sub-line:vertical,QScrollBar::add-line:vertical{background:transparent;border:none;}"
        )
        self.control = QVBoxLayout()
        self.control_close = QPushButton()
        self.control_close.setToolTip("关闭")
        self.control_close.setStyleSheet(
            "QPushButton{background:#FFE3ED;border-radius:5px;border:none;}QPushButton:hover{background:#EC524B;}"
        )
        self.contron_max = QPushButton()
        if self.isMaximized() == False:
            self.contron_max.setToolTip("最大化")
        else:
            self.contron_max.setToolTip("还原")
        self.contron_max.setStyleSheet(
            "QPushButton{background:#FFFDF9;border-radius:5px;border:none;}QPushButton:hover{background:#F5B461;}"
        )
        self.control_min = QPushButton()
        self.control_min.setToolTip("最小化")
        self.control_min.setStyleSheet(
            "QPushButton{background:#BEEBE9;border-radius:5px;border:none;}QPushButton:hover{background:#F3EAC2;}"
        )
        self.start_button = QPushButton("开始(&S)")
        self.start_button.setStyleSheet(
            "QPushButton{background:#9BE3DE;border:none;border-radius:5px;font-size:20px;font-family:DengXian;}QPushButton:hover{background:#9AD3BC;}"
        )
        self.start_button.setToolTip("开始")
        self.start_button.setFixedSize(120, 60)
        self.start_button.setDefault(True)
        setting_button = QPushButton("设置")
        setting_button.setToolTip("设置")
        setting_button.setFixedSize(60, 60)
        setting_button.setStyleSheet(
            "QPushButton{background:#9BE3DE;border:none;border-radius:5px;font-size:20px;font-family:DengXian;}QPushButton:hover{background:#9AD3BC;}"
        )
        setting_button.clicked.connect(self.setting_callback)
        start = QHBoxLayout()
        start.addWidget(self.start_button, 2)
        start.addWidget(setting_button, 1)
        self.control_close.clicked.connect(self.close)
        self.control_min.clicked.connect(self.min_callback)
        self.contron_max.clicked.connect(self.max_callback)
        self.start_button.clicked.connect(self.start_callback)
        self.work_thread.started.connect(self.work.start)
        self.finish_signal.connect(self.finish_callback)
        self.close_qr_signal.connect(self.close_qr)
        self.control.addWidget(self.control_min)
        self.control.addWidget(self.contron_max)
        self.control.addWidget(self.control_close)
        self.main_layout.addLayout(self.control, 0, 0)
        self.main_layout.addWidget(self.title, 0, 1)
        self.main_layout.addLayout(start, 0, 2)
        self.main_layout.addWidget(handler.widget, 1, 1)
        self.update_signal.connect(handler.widget.appendPlainText)
        handler.widget.textChanged.connect(handler.scroll_widget_to_bottom)
        self.show_qr_signal.connect(self.show_qr)
        self.logger.debug("已初始化UI")

    def min_callback(self):
        if self.isMinimized() == False:
            self.showMinimized()

    def max_callback(self):
        if self.isMaximized() == False:
            self.showMaximized()
            self.contron_max.setToolTip("还原")
        else:
            self.showNormal()
            self.contron_max.setToolTip("最大化")

    def start_callback(self):
        self.start_time = time.time()
        self.work_thread.start()
        self.start_button.setEnabled(False)
        self.start_button.setText("执行中...")

    def finish_callback(self):
        self.start_button.setEnabled(True)
        self.start_button.setText("开始")
        passed_time = time.time() - self.start_time
        mins, secs = divmod(passed_time, 60)
        hours, mins = divmod(mins, 60)
        self.logger.info("执行完成,共计用时 {:0>2d}:{:0>2d}:{:0>2d}".format(
            int(hours), int(mins), int(secs)))

    def show_qr(self, qr: bytes):
        title_label = QLabel("请使用微信扫描小程序码完成登陆")
        title_label.setStyleSheet(
            "QLabel{color:#ffe3ed;border:none;background-color:transparent;border-radius:5px;}"
        )
        title_label.setAlignment(Qt.Alignment.AlignCenter)
        title_label.setFixedHeight(20)
        qr_label = QLabel()
        pixmap = QPixmap()
        pixmap.loadFromData(qr)
        qr_label.setPixmap(pixmap)
        qr_label.setStyleSheet(
            "QLabel{color:#ffe3ed;border:none;background-color:transparent;border-radius:5px;}"
        )
        layout_ = QVBoxLayout()
        layout_.addWidget(title_label, 1)
        layout_.addWidget(qr_label, 9)
        self.qr_dialog = QWidget(self)
        self.qr_dialog.setLayout(layout_)
        self.main_layout.addWidget(self.qr_dialog, 1, 1,
                                   Qt.Alignment.AlignCenter)
        self.qr_dialog.show()

    def close_qr(self):
        self.qr_dialog.close()

    def setting_callback(self):
        setting = SettingWindow(parent=self)
        setting.setStyleSheet(
            "QDialog{border:none;border-radius:5px;background:#F3EAC2;}")
        setting.show()

    def gen_conf(self):
        default_conf = {
            "debug": False,
            "hero": {
                "title": "英雄篇",
                "enabled": True,
                "times": 1
            },
            "revival": {
                "title": "复兴篇",
                "enabled": True,
                "times": 1
            },
            "creation": {
                "title": "创新篇",
                "enabled": True,
                "times": 1
            },
            "belief": {
                "title": "信念篇",
                "enabled": True,
                "times": 1
            },
            "limit_time": {
                "title": "限时赛",
                "enabled": True,
                "times": 1
            },
            "rob": {
                "title": "抢十赛",
                "enabled": True,
                "times": 1
            }
        }
        with open(file="config.json", mode="w",
                  encoding="utf-8") as conf_writer:
            conf_writer.write(
                json.dumps(default_conf,
                           indent=4,
                           sort_keys=True,
                           ensure_ascii=False))
        self.logger.info("已生成默认配置文件")

    def mousePressEvent(self, event: QMouseEvent):
        self.logger.debug("触发鼠标按压事件")
        super().mousePressEvent(event)
        self.setFocus()
        self.m_flag = True
        if event.button() == Qt.MouseButtons.LeftButton and self.isMaximized(
        ) == False and self.hasFocus() == True:
            self.old_pos = event.globalPosition()  #获取鼠标相对窗口的位置
            self.logger.debug("已获取鼠标位置")
            self.setCursor(QtGui.QCursor(
                Qt.CursorShape.SizeAllCursor))  #更改鼠标图标

    def mouseMoveEvent(self, event: QMouseEvent):
        self.logger.debug("触发鼠标移动事件")
        super().mouseMoveEvent(event)
        if self.m_flag == True:
            delta_x = int(event.globalPosition().x() - self.old_pos.x())
            delta_y = int(event.globalPosition().y() - self.old_pos.y())
            self.move(self.x() + delta_x, self.y() + delta_y)  #更改窗口位置
            self.logger.debug("已更改窗口位置")
            self.old_pos = event.globalPosition()

    def mouseReleaseEvent(self, event: QMouseEvent):
        self.logger.debug("触发鼠标释放事件")
        super().mouseReleaseEvent(event)
        self.m_flag = False
        self.setCursor(QtGui.QCursor(Qt.CursorShape.ArrowCursor))
コード例 #8
0
 def __init__(self, parent: QWidget):
     super().__init__()
     self.logger = logging.getLogger(__name__)
     with open(file="config.json", mode="r",
               encoding="utf-8") as conf_reader:
         self.conf = json.loads(conf_reader.read())
     self.logger.debug("初始化设置界面。设置内容:%s" % self.conf)
     layout = QGridLayout()
     self.setLayout(layout)
     self.setModal(True)
     self.setParent(parent)
     self.resize(400, 300)
     title = QLabel("设置")
     title.setStyleSheet(
         "QLabel{border:none;border-radius:5px;background:transparent;color:#9AD3BC;font-size:20px;}"
     )
     title.setAlignment(Qt.Alignment.AlignCenter)
     layout.addWidget(title, 0, 1, Qt.Alignment.AlignCenter)
     control_close = QPushButton()
     control_close.setStyleSheet(
         "QPushButton{background:#FFE3ED;border-radius:5px;border:none;}QPushButton:hover{background:#EC524B;}"
     )
     control_close.setToolTip("关闭")
     control_close.setFixedHeight(20)
     control_close.clicked.connect(self.close_callback)
     layout.addWidget(control_close, 0, 0)
     debug_check = QCheckBox("调试模式")
     debug_check.setChecked(self.conf["debug"])
     debug_check.setToolTip("单击切换开关状态")
     debug_check.setStyleSheet(
         "QCheckBox::indicator{width:10px;height:10px;border:none;border-radius:5px;background:#9BE3DE;}QCheckBox::indicator:unchecked{background:#BEEBE9;}QCheckBox::indicator:unchecked:hover{background:#9AD3BC;}QCheckBox::indicator:checked{background:#95E1D3;}QCheckBox::indicator:checked:hover{background:#98DED9;}"
     )
     self.content = QGridLayout()
     (x, y) = self.show_setting(conf=self.conf,
                                layout=self.content)  # 返回content的最后一个元素的x,y
     proxy = QGroupBox()
     proxy.setObjectName("proxy")
     proxy_layout = QVBoxLayout()
     proxy_label = QLabel("代理地址:")
     proxy_label.setStyleSheet(
         "QLabel{background:transparent;border:none;}")
     proxy_input = EnhancedEdit()
     proxy_input.setText(self.conf["proxy"])
     proxy_input.setToolTip("格式为协议://IP:端口,留空保持直连")
     proxy_input.setStyleSheet(
         "QLineEdit{border:1px solid #F3EAC2;border-radius:5px;background:transparent;}QLineEdit:hover{border:1px solid #F5B461;}"
     )
     proxy_layout.addWidget(proxy_label)
     proxy_layout.addWidget(proxy_input)
     proxy.setLayout(proxy_layout)
     proxy.setStyleSheet("QGroupBox{border-radius:5px;}")
     proxy.setToolTip("代理设置")
     if y + 1 >= 3:
         y_ = 0
         x_ = x + 1
     else:
         y_ = y + 1
         x_ = x
     self.content.addWidget(proxy, x_, y_)
     self.content.addWidget(debug_check)
     layout.addLayout(self.content, 1, 1)
コード例 #9
0
ファイル: app.py プロジェクト: Z-zxQ/yt-downloader
class YTdownloader(QWidget):
    def __init__(self):
        super().__init__()
        # setup some flags
        self.isFetching = False
        self.isDownloading = False

        # default output path
        self.outputPath = f'{QDir.homePath()}/videos'

        # setup some window specific things
        self.setWindowTitle('YouTube Downloader')
        self.setWindowIcon(QIcon('assets/yt-icon.ico'))
        self.setFixedSize(705, 343)

        # parent layout
        layout = QVBoxLayout()
        layout.setContentsMargins(15, 15, 15, 10)
        self.setLayout(layout)

        # top bar layout
        topBar = QHBoxLayout()

        # detail section
        detailSec = QHBoxLayout()
        metaSec = QVBoxLayout()

        # download section
        downloadSec = QHBoxLayout()
        downloadBtn = QVBoxLayout()

        # output path link button
        self.outputBtn = QPushButton('📂  Output Path')
        self.outputBtn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.outputBtn.setToolTip(self.outputPath)
        self.outputBtn.clicked.connect(self.setOutputPath)

        # status bar
        self.statusBar = QStatusBar()

        # message box
        self.message = QMessageBox()

        # setting up widgets
        self.urlBox = QLineEdit()
        self.urlBox.setFocusPolicy(Qt.FocusPolicy.ClickFocus or Qt.FocusPolicy.NoFocus)
        self.urlBox.setPlaceholderText('🔍 Enter or paste video URL...')
        self.button = QPushButton('Get')
        self.button.setDefault(True)
        self.button.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.button.clicked.connect(self.getDetails)

        # thumbnail
        pixmap = QPixmap('assets\placeholder.jpg')
        self.thumb = QLabel()
        self.thumb.setFixedSize(250, 141)
        self.thumb.setScaledContents(True)
        self.thumb.setPixmap(pixmap)

        # detail widgets
        self.title = QLabel('Title: ')
        self.author = QLabel('Author: ')
        self.length = QLabel('Duration: ')
        self.publish_date = QLabel('Published: ')

        # progress bar
        self.progress_bar = QProgressBar()
        
        # download options
        self.download = QComboBox()
        self.download.setPlaceholderText('Download Video')
        self.download.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.download.activated.connect(lambda: self.getContent(0))
        self.download.setEnabled(False)

        # download audio button
        self.download_audio = QPushButton('Download Audio')
        self.download_audio.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.download_audio.clicked.connect(lambda: self.getContent(1))
        self.download_audio.setEnabled(False)

        # add widgets and layouts
        topBar.addWidget(self.urlBox)
        topBar.addWidget(self.button)

        # detail section
        metaSec.addWidget(self.title)
        metaSec.addWidget(self.author)
        metaSec.addWidget(self.length)
        metaSec.addWidget(self.publish_date)
        detailSec.addWidget(self.thumb)
        detailSec.addSpacing(20)
        detailSec.addLayout(metaSec)

        # download section
        downloadBtn.addWidget(self.download)
        downloadBtn.addWidget(self.download_audio)
        downloadSec.addWidget(self.progress_bar)
        downloadSec.addSpacing(10)
        downloadSec.addLayout(downloadBtn)

        # status bar
        self.statusBar.setSizeGripEnabled(False)
        self.statusBar.addPermanentWidget(self.outputBtn)

        # add content to parent layout
        layout.addLayout(topBar)
        layout.addSpacing(20)
        layout.addLayout(detailSec)
        layout.addSpacing(5)
        layout.addLayout(downloadSec)
        layout.addWidget(self.statusBar)

        # setup a connection thread to keep checking internet connectivity
        self.connection = ConnectionThread()
        self.connection.start()

        # catch the connection response signal
        self.connection.con_response.connect(self.connection_slot)

    # connection slot
    def connection_slot(self, status):
        curMsg = self.statusBar.currentMessage()
        # connection succeeded
        if status:
            if curMsg == '🔴  Disconnected':
                self.statusBar.showMessage('🟢  Connection restored!', 3000)
            elif curMsg != '🟢  Connected':
                self.statusBar.showMessage('🟢  Connected')
        # connection failed
        elif curMsg == '🟢  Connected':
            self.statusBar.showMessage('🔴  Connection interrupted!', 3000)
        elif curMsg != '🔴  Disconnected': 
            self.statusBar.showMessage('🔴  Disconnected')

    # set output path slot
    def setOutputPath(self):
        # update the output path
        path = str(QFileDialog.getExistingDirectory(self, "Select Output Directory"))
        if path:
            self.outputPath = path
            # update tooltip
            self.outputBtn.setToolTip(path)

    # get button slot
    def getDetails(self):
        curMsg = self.statusBar.currentMessage()
        if curMsg == '🔴  Disconnected' or curMsg == '🔴  Connection interrupted!':
            self.message.critical(
                self,
                'Error',
                'Connection failed!\nAre you sure you\'re connected to the internet ? '
            )
        elif self.button.text() == 'Get':
            self.button.setText('Stop')
            # indicate progress bar as busy
            self.progress_bar.setRange(0, 0)
            # set fetching flag
            self.isFetching = True
            # setup a worker thread to keep UI responsive
            self.worker = WorkerThread(self.urlBox.text())
            self.worker.start()
            # catch the finished signal
            self.worker.finished.connect(self.finished_slot)
            # catch the response signal
            self.worker.worker_response.connect(self.response_slot)
            # catch the error signal
            self.worker.worker_err_response.connect(self.err_slot)
        elif self.button.text() == 'Stop':
            if self.isFetching:
                # stop worker thread
                self.worker.terminate()
                # set back the button text
                self.button.setText('Get')
            elif self.isDownloading:
                # stop download thread
                self.download_thread.terminate()
                # show the warning message
                self.message.information(
                    self,
                    'Interrupted',
                    'Download interrupted!\nThe process was aborted while the file was being downloaded... '
                )
                # reset pogress bar
                self.progress_bar.reset()

    # download options slot
    def getContent(self, id):
        if self.isFetching:
            # show the warning message
            self.message.warning(
                self,
                'Warning',
                'Please wait!\nWait while the details are being fetched... '
            )
        else:
            # disable the download options
            self.download.setDisabled(True)
            self.download_audio.setDisabled(True)
            # set downloading flag
            self.isDownloading = True
            # set button to stop 
            self.button.setText('Stop')
            # setup download thread
            if id == 0:
                self.download_thread = DownloadThread(self.yt, self.download.currentText()[:4], self.outputPath)
            else:
                self.download_thread = DownloadThread(self.yt, 'audio', self.outputPath)
            # start the thread
            self.download_thread.start()
            # catch the finished signal
            self.download_thread.finished.connect(self.download_finished_slot)
            # catch the response signal
            self.download_thread.download_response.connect(self.download_response_slot)
            # catch the complete signal
            self.download_thread.download_complete.connect(self.download_complete_slot)
            # catch the error signal
            self.download_thread.download_err.connect(self.download_err_slot)

    # finished slot
    def finished_slot(self):
        # remove progress bar busy indication
        self.progress_bar.setRange(0, 100)
        # unset fetching flag
        self.isFetching = False

    # response slot
    def response_slot(self, res):
        # set back the button text
        self.button.setText('Get')
        # save the yt object for speeding up download
        self.yt = res[0]
        # set the actual thumbnail of requested video
        self.thumb.setPixmap(res[1])
        # slice the title if it is more than the limit
        if len(res[2]) > 50:
            self.title.setText(f'Title:  {res[2][:50]}...')
        else:
            self.title.setText(f'Title:  {res[2]}')
        # set leftover details
        self.author.setText(f'Author:  {res[3]}')
        self.length.setText(f'Duration:  {timedelta(seconds=res[4])}')
        self.publish_date.setText(f'Published:  {res[5].strftime("%d/%m/%Y")}')
        # clear any previous items if any
        self.download.clear()
        # add resolutions as items to the download button and enable them
        self.download.addItems([item for item in res[6]])
        self.download.setDisabled(False)
        self.download_audio.setDisabled(False)

    # error slot
    def err_slot(self):
        # show the warning message
        self.message.warning(
            self,
            'Warning',
            'Something went wrong!\nProbably a broken link or some restricted content... '
        )
        # set back the button text
        self.button.setText('Get')

    # download finished slot
    def download_finished_slot(self):
        # set back the button text
        self.button.setText('Get')
        # now enable the download options
        self.download.setDisabled(False)
        self.download_audio.setDisabled(False)
        # unset downloading flag
        self.isDownloading = False
        # reset pogress bar
        self.progress_bar.reset()

    # download response slot
    def download_response_slot(self, per):
        # update progress bar
        self.progress_bar.setValue(per)
        # adjust the font color to maintain the contrast
        if per > 52:
            self.progress_bar.setStyleSheet('QProgressBar { color: #fff }')
        else:
            self.progress_bar.setStyleSheet('QProgressBar { color: #000 }')
    
    # download complete slot
    def download_complete_slot(self, location):
        # use native separators
        location = QDir.toNativeSeparators(location)
        # show the success message
        if self.message.information(
            self,
            'Downloaded',
            f'Download complete!\nFile was successfully downloaded to :\n{location}\n\nOpen the downloaded file now ?',
            QMessageBox.StandardButtons.Open,
            QMessageBox.StandardButtons.Cancel
        ) is QMessageBox.StandardButtons.Open: subprocess.Popen(f'explorer /select,{location}')

    # download error slot
    def download_err_slot(self):
        # show the error message
        self.message.critical(
            self,
            'Error',
            'Error!\nSomething unusual happened and was unable to download...'
        )
コード例 #10
0
class AttributeWidget(CustomScrollableListItem):
    def __init__(self, document_base_viewer):
        super(AttributeWidget, self).__init__(document_base_viewer)
        self.document_base_viewer = document_base_viewer
        self.attribute = None

        self.setFixedHeight(40)
        self.setStyleSheet("background-color: white")

        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(20, 0, 20, 0)
        self.layout.setSpacing(40)

        self.attribute_name = QLabel()
        self.attribute_name.setFont(CODE_FONT_BOLD)
        self.layout.addWidget(self.attribute_name,
                              alignment=Qt.AlignmentFlag.AlignLeft)

        self.num_matched = QLabel("matches: -")
        self.num_matched.setFont(CODE_FONT)
        self.layout.addWidget(self.num_matched,
                              alignment=Qt.AlignmentFlag.AlignLeft)

        self.buttons_widget = QWidget()
        self.buttons_layout = QHBoxLayout(self.buttons_widget)
        self.buttons_layout.setContentsMargins(0, 0, 0, 0)
        self.buttons_layout.setSpacing(10)
        self.layout.addWidget(self.buttons_widget,
                              alignment=Qt.AlignmentFlag.AlignRight)

        self.forget_matches_button = QPushButton()
        self.forget_matches_button.setIcon(QIcon("aset_ui/resources/redo.svg"))
        self.forget_matches_button.setToolTip(
            "Forget matches for this attribute.")
        self.forget_matches_button.setFlat(True)
        self.forget_matches_button.clicked.connect(
            self._forget_matches_button_clicked)
        self.buttons_layout.addWidget(self.forget_matches_button)

        self.remove_button = QPushButton()
        self.remove_button.setIcon(QIcon("aset_ui/resources/trash.svg"))
        self.remove_button.setToolTip("Remove this attribute.")
        self.remove_button.setFlat(True)
        self.remove_button.clicked.connect(self._remove_button_clicked)
        self.buttons_layout.addWidget(self.remove_button)

    def update_item(self, item, params=None):
        self.attribute = item

        if len(params.attributes) == 0:
            max_attribute_name_len = 10
        else:
            max_attribute_name_len = max(
                len(attribute.name) for attribute in params.attributes)
        self.attribute_name.setText(self.attribute.name + (
            " " * (max_attribute_name_len - len(self.attribute.name))))

        mappings_in_some_documents = False
        no_mappings_in_some_documents = False
        num_matches = 0
        for document in params.documents:
            if self.attribute.name in document.attribute_mappings.keys():
                mappings_in_some_documents = True
                if document.attribute_mappings[self.attribute.name] != []:
                    num_matches += 1
            else:
                no_mappings_in_some_documents = True

        if not mappings_in_some_documents and no_mappings_in_some_documents:
            self.num_matched.setText("not matched yet")
        elif mappings_in_some_documents and no_mappings_in_some_documents:
            self.num_matched.setText("only partly matched")
        else:
            self.num_matched.setText(f"matches: {num_matches}")

    def enable_input(self):
        self.forget_matches_button.setEnabled(True)
        self.remove_button.setEnabled(True)

    def disable_input(self):
        self.forget_matches_button.setDisabled(True)
        self.remove_button.setDisabled(True)

    def _forget_matches_button_clicked(self):
        self.document_base_viewer.main_window.forget_matches_for_attribute_with_given_name_task(
            self.attribute.name)

    def _remove_button_clicked(self):
        self.document_base_viewer.main_window.remove_attribute_with_given_name_task(
            self.attribute.name)
コード例 #11
0
class B23Download(QWidget):
    def __init__(self):
        super(B23Download, self).__init__()
        # setup some flags
        self.is_fetching = False
        self.is_downloading = False

        # default output path
        basepath = os.path.dirname(os.path.abspath(__file__))
        path = os.path.join(basepath, "videos")
        self.output_path = path

        # setup some window specific things
        self.setWindowTitle("Bilibili Favorite Downloader")
        self.setWindowIcon(QIcon("images/icon_bilibili.ico"))
        self.setFixedSize(705, 343)

        # parent layout
        main_layout = QVBoxLayout()
        main_layout.setContentsMargins(15, 15, 15, 10)
        self.setLayout(main_layout)

        # top bar layout
        top_layout = QHBoxLayout()

        # detail section
        mid_main_layout = QHBoxLayout()
        mid_right_layout = QVBoxLayout()

        # download section
        bottom_main_layout = QHBoxLayout()
        bottom_right_layout = QVBoxLayout()

        # output path link button
        self.output_btn = QPushButton("📂  Output Path")
        self.output_btn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.output_btn.setToolTip(self.output_path)
        self.output_btn.clicked.connect(self.set_output_path)

        # status bar
        self.status_bar = QStatusBar()

        # message box
        self.message_box = QMessageBox()

        # setting up widgets
        self.url_edit = QLineEdit()
        self.url_edit.setPlaceholderText("🔍 Enter or paste favorite URL...")
        self.get_btn = QPushButton("Get")
        self.get_btn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.get_btn.clicked.connect(self.get_details)

        # thumbnail
        pixmap = QPixmap("images/placeholder.png")
        self.thumb = QLabel()
        self.thumb.setFixedSize(250, 141)
        self.thumb.setScaledContents(True)
        self.thumb.setPixmap(pixmap)

        # detail widgets
        self.title = QLabel("Title: ")
        self.author = QLabel("Author: ")
        self.length = QLabel("Videos: ")
        self.publish_date = QLabel("Published: ")

        # progress bar
        self.progress_bar = QProgressBar()

        # download options
        self.download_btn = QPushButton(" Download Videos ")
        self.download_btn.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.download_btn.clicked.connect(self.get_content)
        self.download_btn.setEnabled(False)
        self.download_btn.setShortcut("Ctrl+Return")
        self.download_btn.setMinimumWidth(200)

        # add widgets and layouts
        top_layout.addWidget(self.url_edit)
        top_layout.addWidget(self.get_btn)

        # detail section
        mid_right_layout.addWidget(self.title)
        mid_right_layout.addWidget(self.author)
        mid_right_layout.addWidget(self.length)
        mid_right_layout.addWidget(self.publish_date)
        mid_main_layout.addWidget(self.thumb)
        mid_main_layout.addSpacing(20)
        mid_main_layout.addLayout(mid_right_layout)

        # download section
        bottom_right_layout.addWidget(self.download_btn)
        bottom_main_layout.addWidget(self.progress_bar)
        bottom_main_layout.addSpacing(10)
        bottom_main_layout.addLayout(bottom_right_layout)

        # status bar
        self.status_bar.setSizeGripEnabled(False)
        self.status_bar.addPermanentWidget(self.output_btn)

        # add content to parent layout
        main_layout.addLayout(top_layout)
        main_layout.addSpacing(20)
        main_layout.addLayout(mid_main_layout)
        main_layout.addSpacing(5)
        main_layout.addLayout(bottom_main_layout)
        main_layout.addWidget(self.status_bar)

    # set output path slot
    def set_output_path(self):
        # update the output path
        path = str(
            QFileDialog.getExistingDirectory(self, "Select Output Directory"))
        if path:
            self.output_path = path
            # update tooltip
            self.output_btn.setToolTip(path)

    # get button slot
    def get_details(self):
        text = self.url_edit.text().strip()

        if not text:
            return

        if text.find("fid") < 0:
            self.message_box.warning(
                self,
                "Error",
                ("Input a correct favorite URL!\n"
                 "For example: https://space.bilibili.com/xxx/favlist?fid=xxx..."
                 ),
            )
            return

        if self.get_btn.text() == "Get":
            self.get_btn.setText("Stop")
            # indicate progress bar as busy
            self.progress_bar.setRange(0, 0)
            # set fetching flag
            self.is_fetching = True
            # setup a worker thread to keep UI responsive
            self.media_id = text.split("fid=")[-1].split("&")[0]
            self.worker = WorkerThread(self.media_id)
            self.worker.start()
            # catch the finished signal
            self.worker.finished.connect(self.finished_slot)
            # catch the response signal
            self.worker.worker_response.connect(self.response_slot)
            # catch the error signal
            self.worker.worker_err_response.connect(self.err_slot)
        elif self.get_btn.text() == "Stop":
            if self.is_fetching:
                # stop worker thread
                self.worker.terminate()
                # set back the get_btn text
                self.get_btn.setText("Get")
            elif self.is_downloading:
                # stop download thread
                self.download_thread.terminate()
                # show the warning message_box
                self.message_box.information(
                    self,
                    "Interrupted",
                    "Download interrupted!\nThe process was aborted while the file was being downloaded... ",
                )
                # reset progress bar
                self.progress_bar.reset()

    # download options slot
    def get_content(self):
        if self.is_fetching:
            # show the warning message
            self.message_box.critical(
                self,
                "Error",
                "Please wait!\nWait while the details are being fetched... ",
            )
        else:
            # disable the download options
            self.download_btn.setDisabled(True)
            # set downloading flag
            self.is_downloading = True
            # set button to stop
            self.get_btn.setText("Stop")
            self.download_thread = DownloadThread(
                self.media_id,
                self.media_counts,
                self.first_page_medias,
                self.output_path,
            )
            # start the thread
            self.download_thread.start()
            # catch the finished signal
            self.download_thread.finished.connect(self.download_finished_slot)
            # catch the response signal
            self.download_thread.download_response.connect(
                self.download_response_slot)
            # catch the complete signal
            self.download_thread.download_complete.connect(
                self.download_complete_slot)
            # catch the error signal
            self.download_thread.download_err.connect(self.download_err_slot)

    # handling enter key for get/stop button
    def keyPressEvent(self, event):
        self.url_edit.setFocus()
        if (event.key() == Qt.Key.Key_Enter.value
                or event.key() == Qt.Key.Key_Return.value):
            self.get_details()

    # finished slot
    def finished_slot(self):
        # remove progress bar busy indication
        self.progress_bar.setRange(0, 100)
        # unset fetching flag
        self.is_fetching = False

    # response slot
    def response_slot(self, res):
        # set back the button text
        self.get_btn.setText("Get")
        # set the actual thumbnail of requested video
        self.thumb.setPixmap(res.thumb_img)
        # slice the title if it is more than the limit
        if len(res.title) > 50:
            self.title.setText(f"Title: {res.title[:50]}...")
        else:
            self.title.setText(f"Title: {res.title}")
        # cache first page medias
        self.first_page_medias = res.medias
        self.media_counts = res.media_counts
        # set leftover details
        self.author.setText(f"Author: {res.author}")
        self.length.setText(f"Videos: {res.media_counts}")
        self.publish_date.setText(
            f'Published: {time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(res.publish_date))}'
        )
        self.download_btn.setDisabled(False)

    # error slot
    def err_slot(self):
        # show the warning message
        self.message_box.warning(
            self,
            "Warning",
            "Something went wrong!\nProbably a broken link or some restricted content... ",
        )
        # set back the button text
        self.get_btn.setText("Get")

    # download finished slot
    def download_finished_slot(self):
        # set back the button text
        self.get_btn.setText("Get")
        # now enable the download options
        self.download_btn.setDisabled(False)
        # unset downloading flag
        self.is_downloading = False
        # reset pogress bar
        self.progress_bar.reset()

    # download response slot
    def download_response_slot(self, per):
        # update progress bar
        self.progress_bar.setValue(per)
        # adjust the font color to maintain the contrast
        if per > 52:
            self.progress_bar.setStyleSheet("QProgressBar { color: #fff }")
        else:
            self.progress_bar.setStyleSheet("QProgressBar { color: #000 }")

    # download complete slot
    def download_complete_slot(self, location):
        # use native separators
        location = QDir.toNativeSeparators(location)
        # show the success message
        if (self.message_box.information(
                self,
                "Downloaded",
                f"Download complete!\nFile was successfully downloaded to :\n{location}\n\nOpen the downloaded file now ?",
                QMessageBox.StandardButtons.Open,
                QMessageBox.StandardButtons.Cancel,
        ) is QMessageBox.StandardButtons.Open):
            subprocess.Popen(f"explorer /select,{location}")

    # download error slot
    def download_err_slot(self):
        # show the error message
        self.message_box.critical(
            self,
            "Error",
            "Error!\nSomething unusual happened and was unable to download...",
        )
コード例 #12
0
class AboutDialog(QDialog):
    check_update = pyqtSignal(str, bool)

    def __init__(self, parent=None):
        super(AboutDialog, self).__init__(parent)
        self._ver = ''
        self._github = 'https://github.com/rachpt/lanzou-gui'
        self._api_url = 'https://github.com/zaxtyson/LanZouCloud-API'
        self._gitee = 'https://gitee.com/rachpt/lanzou-gui'
        self._home_page = 'https://rachpt.cn/lanzou-gui/'
        self.initUI()
        self.setStyleSheet(others_style)

    def set_values(self, version):
        self._ver = version
        self.lb_name_text.setText(f"v{version}  (点击检查更新)")  # 更新版本

    def show_update(self, ver, msg):
        self.lb_new_ver = QLabel("新版")  # 检测新版
        self.lb_new_ver_msg = QLabel()
        self.lb_new_ver_msg.setOpenExternalLinks(True)
        self.lb_new_ver_msg.setWordWrap(True)
        if ver != '0':
            self.lb_name_text.setText(f"{self._ver}  ➡  {ver}")
        self.lb_new_ver_msg.setText(msg)
        self.lb_new_ver_msg.setMinimumWidth(700)
        if self.form.rowCount() < 5:
            self.form.insertRow(1, self.lb_new_ver, self.lb_new_ver_msg)

    def initUI(self):
        self.setWindowTitle("关于 lanzou-gui")
        about = f'本项目使用PyQt6实现图形界面,可以完成蓝奏云的大部分功能<br/> \
    得益于 <a href="{self._api_url}">API</a> 的功能,可以间接突破单文件最大 100MB 的限制,同时增加了批量上传/下载的功能<br/> \
Python 依赖见<a href="{self._github }/blob/master/requirements.txt">requirements.txt</a>,\
<a href="{self._github}/releases">releases</a> 有打包好了的 Windows 可执行程序,但可能不是最新的'

        project_url = f'<a href="{self._home_page}">主页</a> | <a href="{self._github}">repo</a> | \
                        <a href="{self._gitee}">mirror repo</a>'

        self.logo = QLabel()  # logo
        self.logo.setPixmap(QPixmap(SRC_DIR + "logo2.gif"))
        self.logo.setStyleSheet("background-color:rgb(255,255,255);")
        self.logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.lb_qt_ver = QLabel("依赖")  # QT 版本
        self.lb_qt_text = QLabel(
            f"QT: {QT_VERSION_STR}, PyQt: {PYQT_VERSION_STR}")  # QT 版本
        self.lb_name = QLabel("版本")  # 版本
        self.lb_name_text = QPushButton("")  # 版本
        self.lb_name_text.setToolTip("点击检查更新")
        ver_style = "QPushButton {border:none; background:transparent;font-weight:bold;color:blue;}"
        self.lb_name_text.setStyleSheet(ver_style)
        self.lb_name_text.clicked.connect(
            lambda: self.check_update.emit(self._ver, True))
        self.lb_about = QLabel("关于")  # about
        self.lb_about_text = QLabel()
        self.lb_about_text.setText(about)
        self.lb_about_text.setOpenExternalLinks(True)
        self.lb_author = QLabel("作者")  # author
        self.lb_author_mail = QLabel(
            "<a href='mailto:[email protected]'>rachpt</a>")
        self.lb_author_mail.setOpenExternalLinks(True)
        self.lb_update = QLabel("项目")  # 更新
        self.lb_update_url = QLabel(project_url)
        self.lb_update_url.setOpenExternalLinks(True)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
        self.buttonBox.setStandardButtons(
            QDialogButtonBox.StandardButton.Close)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Close).setText("关闭")
        self.buttonBox.rejected.connect(self.reject)
        self.buttonBox.setStyleSheet(btn_style)

        self.recommend = QLabel(
            "<br />大文件推荐使用 <a href='https://github.com/Aruelius/cloud189'>cloud189-cli</a>"
        )
        self.recommend.setOpenExternalLinks(True)

        self.line = QLine(QPoint(), QPoint(550, 0))
        self.lb_line = QLabel('<html><hr /></html>')

        vbox = QVBoxLayout()
        vbox.addWidget(self.logo)
        vbox.addStretch(1)
        self.form = QFormLayout()
        self.form.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
        self.form.setFormAlignment(Qt.AlignmentFlag.AlignLeft)
        self.form.setHorizontalSpacing(40)
        self.form.setVerticalSpacing(15)
        self.form.addRow(self.lb_qt_ver, self.lb_qt_text)
        self.form.addRow(self.lb_name, self.lb_name_text)
        self.form.addRow(self.lb_update, self.lb_update_url)
        self.form.addRow(self.lb_author, self.lb_author_mail)
        self.form.addRow(self.lb_about, self.lb_about_text)
        self.form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.
                                       AllNonFixedFieldsGrow)  # 覆盖MacOS的默认样式
        vbox.addLayout(self.form)
        vbox.addStretch(1)
        vbox.addWidget(self.recommend)
        vbox.addWidget(self.lb_line)
        donate = QLabel()
        donate.setText("<b>捐助我</b>&nbsp;如果你愿意")
        donate.setAlignment(Qt.AlignmentFlag.AlignCenter)
        hbox = QHBoxLayout()
        hbox.addStretch(2)
        for it in ["wechat", "alipay", "qqpay"]:
            lb = QLabel()
            lb.setPixmap(QPixmap(SRC_DIR + f"{it}.jpg"))
            hbox.addWidget(lb)
        hbox.addStretch(1)
        hbox.addWidget(self.buttonBox)
        vbox.addWidget(donate)
        vbox.addLayout(hbox)
        self.setLayout(vbox)
        self.setMinimumWidth(720)

    def paintEvent(self, event):
        QDialog.paintEvent(self, event)
        if not self.line.isNull():
            painter = QPainter(self)
            pen = QPen(Qt.GlobalColor.red, 3)
            painter.setPen(pen)
            painter.drawLine(self.line)
コード例 #13
0
ファイル: login.py プロジェクト: fakegit/lanzou-gui
class LoginDialog(QDialog):
    """登录对话框"""

    clicked_ok = pyqtSignal()

    def __init__(self, config):
        super().__init__()
        self._cwd = os.getcwd()
        self._config = config
        self._cookie_assister = 'login_assister.exe'
        self._user = ""
        self._pwd = ""
        self._cookie = {}
        self._del_user = ""
        self.initUI()
        self.setStyleSheet(dialog_qss_style)
        self.setMinimumWidth(560)
        self.name_ed.setFocus()
        # 信号
        self.name_ed.textChanged.connect(self.set_user)
        self.pwd_ed.textChanged.connect(self.set_pwd)
        self.cookie_ed.textChanged.connect(self.set_cookie)

    def update_selection(self, user):
        """显示已经保存的登录用户信息"""
        user_info = self._config.get_user_info(user)
        if user_info:
            self._user = user_info[0]
            self._pwd = user_info[1]
            self._cookie = user_info[2]
        # 更新控件显示内容
        self.name_ed.setText(self._user)
        self.pwd_ed.setText(self._pwd)
        try: text = ";".join([f'{k}={v}' for k, v in self._cookie.items()])
        except: text = ''
        self.cookie_ed.setPlainText(text)

    def initUI(self):
        self.setWindowTitle("登录蓝奏云")
        self.setWindowIcon(QIcon(SRC_DIR + "login.ico"))
        logo = QLabel()
        logo.setPixmap(QPixmap(SRC_DIR + "logo3.gif"))
        logo.setStyleSheet("background-color:rgb(0,153,255);")
        logo.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.tabs = QTabWidget()
        self.auto_tab = QWidget()
        self.hand_tab = QWidget()

        # Add tabs
        self.tabs.addTab(self.auto_tab,"自动获取Cookie")
        self.tabs.addTab(self.hand_tab,"手动输入Cookie")
        self.auto_get_cookie_ok = AutoResizingTextEdit("🔶点击👇自动获取浏览器登录信息👇")
        self.auto_get_cookie_ok.setReadOnly(True)
        self.auto_get_cookie_btn = QPushButton("自动读取浏览器登录信息")
        auto_cookie_notice = '支持浏览器:Chrome, Chromium, Opera, Edge, Firefox'
        self.auto_get_cookie_btn.setToolTip(auto_cookie_notice)
        self.auto_get_cookie_btn.clicked.connect(self.call_auto_get_cookie)
        self.auto_get_cookie_btn.setStyleSheet("QPushButton {min-width: 210px;max-width: 210px;}")

        self.name_lb = QLabel("&U 用户")
        self.name_lb.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.name_ed = QLineEdit()
        self.name_lb.setBuddy(self.name_ed)

        self.pwd_lb = QLabel("&P 密码")
        self.pwd_lb.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.pwd_ed = QLineEdit()
        self.pwd_ed.setEchoMode(QLineEdit.EchoMode.Password)
        self.pwd_lb.setBuddy(self.pwd_ed)

        self.cookie_lb = QLabel("&Cookie")
        self.cookie_ed = QTextEdit()
        notice = "由于滑动验证的存在,需要输入cookie,cookie请使用浏览器获取\n" + \
            "cookie会保存在本地,下次使用。其格式如下:\n ylogin=value1; phpdisk_info=value2"
        self.cookie_ed.setPlaceholderText(notice)
        self.cookie_lb.setBuddy(self.cookie_ed)

        self.show_input_cookie_btn = QPushButton("显示Cookie输入框")
        self.show_input_cookie_btn.setToolTip(notice)
        self.show_input_cookie_btn.setStyleSheet("QPushButton {min-width: 110px;max-width: 110px;}")
        self.show_input_cookie_btn.clicked.connect(self.change_show_input_cookie)
        self.ok_btn = QPushButton("登录")
        self.ok_btn.clicked.connect(self.change_ok_btn)
        self.cancel_btn = QPushButton("取消")
        self.cancel_btn.clicked.connect(self.change_cancel_btn)
        lb_line_1 = QLabel()
        lb_line_1.setText('<html><hr />切换用户</html>')
        lb_line_2 = QLabel()
        lb_line_2.setText('<html><hr /></html>')

        self.form = QFormLayout()
        self.form.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
        self.form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)  # 覆盖MacOS的默认样式
        self.form.addRow(self.name_lb, self.name_ed)
        self.form.addRow(self.pwd_lb, self.pwd_ed)
        if is_windows:
            def set_assister_path():
                """设置辅助登录程序路径"""
                assister_path = QFileDialog.getOpenFileName(self, "选择辅助登录程序路径",
                                                            self._cwd, "EXE Files (*.exe)")
                if not assister_path[0]:
                    return None
                assister_path = os.path.normpath(assister_path[0])  # windows backslash
                if assister_path == self._cookie_assister:
                    return None
                self.assister_ed.setText(assister_path)
                self._cookie_assister = assister_path

            self.assister_lb = QLabel("登录辅助程序")
            self.assister_lb.setAlignment(Qt.AlignmentFlag.AlignCenter)
            self.assister_ed = MyLineEdit(self)
            self.assister_ed.setText(self._cookie_assister)
            self.assister_ed.clicked.connect(set_assister_path)
            self.assister_lb.setBuddy(self.assister_ed)
            self.form.addRow(self.assister_lb, self.assister_ed)

        hbox = QHBoxLayout()
        hbox.addWidget(self.show_input_cookie_btn)
        hbox.addStretch(1)
        hbox.addWidget(self.ok_btn)
        hbox.addWidget(self.cancel_btn)

        user_box = QHBoxLayout()
        self.user_num = 0
        self.user_btns = {}
        for user in self._config.users_name:
            user = str(user)  # TODO: 可能需要删掉
            self.user_btns[user] = QDoublePushButton(user)
            self.user_btns[user].setStyleSheet("QPushButton {border:none;}")
            if user == self._config.name:
                self.user_btns[user].setStyleSheet("QPushButton {background-color:rgb(0,153,2);}")
                self.tabs.setCurrentIndex(1)
            self.user_btns[user].setToolTip(f"点击选中,双击切换至用户:{user}")
            self.user_btns[user].doubleClicked.connect(self.choose_user)
            self.user_btns[user].clicked.connect(self.delete_chose_user)
            user_box.addWidget(self.user_btns[user])
            self.user_num += 1
            user_box.addStretch(1)

        self.layout = QVBoxLayout(self)
        self.layout.addWidget(logo)
        vbox = QVBoxLayout()
        if self._config.name:
            vbox.addWidget(lb_line_1)
            user_box.setAlignment(Qt.AlignmentFlag.AlignCenter)
            vbox.addLayout(user_box)
            vbox.addWidget(lb_line_2)
            if self.user_num > 1:
                self.del_user_btn = QPushButton("删除账户")
                self.del_user_btn.setIcon(QIcon(SRC_DIR + "delete.ico"))
                self.del_user_btn.setStyleSheet("QPushButton {min-width: 180px;max-width: 180px;}")
                self.del_user_btn.clicked.connect(self.call_del_chose_user)
                vbox.addWidget(self.del_user_btn)
            else:
                self.del_user_btn = None
            vbox.addStretch(1)

        vbox.addLayout(self.form)
        vbox.addStretch(1)
        vbox.addLayout(hbox)
        vbox.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.hand_tab.setLayout(vbox)
        auto_cookie_vbox = QVBoxLayout()
        auto_cookie_vbox.addWidget(self.auto_get_cookie_ok)
        auto_cookie_vbox.addWidget(self.auto_get_cookie_btn)
        auto_cookie_vbox.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.auto_tab.setLayout(auto_cookie_vbox)
        self.layout.addWidget(self.tabs)
        self.setLayout(self.layout)
        self.update_selection(self._config.name)

    def call_del_chose_user(self):
        if self._del_user:
            if self._del_user != self._config.name:
                self.user_num -= 1
                self._config.del_user(self._del_user)
                self.user_btns[self._del_user].close()
                self._del_user = ""
                if self.user_num <= 1:
                    self.del_user_btn.close()
                    self.del_user_btn = None
                return
            else:
                title = '不能删除'
                msg = '不能删除当前登录账户,请先切换用户!'
        else:
            title = '请选择账户'
            msg = '请单击选择需要删除的账户\n\n注意不能删除当前账户(绿色)'
        message_box = QMessageBox(self)
        message_box.setIcon(QMessageBox.Icon.Critical)
        message_box.setStyleSheet(btn_style)
        message_box.setWindowTitle(title)
        message_box.setText(msg)
        message_box.setStandardButtons(QMessageBox.StandardButton.Close)
        buttonC = message_box.button(QMessageBox.StandardButton.Close)
        buttonC.setText('关闭')
        message_box.exec()

    def delete_chose_user(self):
        """更改单击选中需要删除的用户"""
        user = str(self.sender().text())
        self._del_user = user
        if self.del_user_btn:
            self.del_user_btn.setText(f"删除 <{user}>")

    def choose_user(self):
        """切换用户"""
        user = self.sender().text()
        if user != self._config.name:
            self.ok_btn.setText("切换用户")
        else:
            self.ok_btn.setText("登录")
        self.update_selection(user)

    def change_show_input_cookie(self):
        row_c = 4 if is_windows else 3
        if self.form.rowCount() < row_c:
            self.org_height = self.height()
            self.form.addRow(self.cookie_lb, self.cookie_ed)
            self.show_input_cookie_btn.setText("隐藏Cookie输入框")
            self.change_height = None
            self.adjustSize()
        else:
            if not self.change_height:
                self.change_height = self.height()
            if self.cookie_ed.isVisible():
                self.cookie_lb.setVisible(False)
                self.cookie_ed.setVisible(False)
                self.show_input_cookie_btn.setText("显示Cookie输入框")
                start_height, end_height = self.change_height, self.org_height
            else:
                self.cookie_lb.setVisible(True)
                self.cookie_ed.setVisible(True)
                self.show_input_cookie_btn.setText("隐藏Cookie输入框")
                start_height, end_height = self.org_height, self.change_height
            gm = self.geometry()
            x, y = gm.x(), gm.y()
            wd = self.width()
            self.animation = QPropertyAnimation(self, b'geometry')
            self.animation.setDuration(400)
            self.animation.setStartValue(QRect(x, y, wd, start_height))
            self.animation.setEndValue(QRect(x, y, wd, end_height))
            self.animation.start()

    def set_user(self, user):
        self._user = user
        if not user:
            return None
        if user not in self._config.users_name:
            self.ok_btn.setText("添加用户")
            self.cookie_ed.setPlainText("")
        elif user != self._config.name:
            self.update_selection(user)
            self.ok_btn.setText("切换用户")
        else:
            self.update_selection(user)
            self.ok_btn.setText("登录")

    def set_pwd(self, pwd):
        if self._user in self._config.users_name:
            user_info = self._config.get_user_info(self._user)
            if pwd and pwd != user_info[1]:  # 改变密码,cookie作废
                self.cookie_ed.setPlainText("")
                self._cookie = None
            if not pwd:  # 输入空密码,表示删除对pwd的存储,并使用以前的cookie
                self._cookie = user_info[2]
                try: text = ";".join([f'{k}={v}' for k, v in self._cookie.items()])
                except: text = ''
                self.cookie_ed.setPlainText(text)
        self._pwd = pwd

    def set_cookie(self):
        cookies = self.cookie_ed.toPlainText()
        if cookies:
            try:
                self._cookie = {kv.split("=")[0].strip(" "): kv.split("=")[1].strip(" ") for kv in cookies.split(";") if kv.strip(" ") }
            except: self._cookie = None

    def change_cancel_btn(self):
        self.update_selection(self._config.name)
        self.close()

    def change_ok_btn(self):
        if self._user and self._pwd:
            if self._user not in self._config.users_name:
                self._cookie = None
        if self._cookie:
            up_info = {"name": self._user, "pwd": self._pwd, "cookie": self._cookie, "work_id": -1}
            if self.ok_btn.text() == "切换用户":
                self._config.change_user(self._user)
            else:
                self._config.set_infos(up_info)
            self.clicked_ok.emit()
            self.close()
        elif USE_WEB_ENG:
            self.web = LoginWindow(self._user, self._pwd)
            self.web.cookie.connect(self.get_cookie_by_web)
            self.web.setWindowModality(Qt.WindowModality.ApplicationModal)
            self.web.exec()
        elif os.path.isfile(self._cookie_assister):
            try:
                result = os.popen(f'{self._cookie_assister} {self._user} {self._pwd}')
                cookie = result.read()
                try:
                    self._cookie = {kv.split("=")[0].strip(" "): kv.split("=")[1].strip(" ") for kv in cookie.split(";")}
                except: self._cookie = None
                if not self._cookie:
                    return None
                up_info = {"name": self._user, "pwd": self._pwd, "cookie": self._cookie, "work_id": -1}
                self._config.set_infos(up_info)
                self.clicked_ok.emit()
                self.close()
            except: pass
        else:
            title = '请使用 Cookie 登录或是选择 登录辅助程序'
            msg = '没有输入 Cookie,或者没有找到登录辅助程序!\n\n' + \
                  '推荐使用浏览器获取 cookie 填入 cookie 输入框\n\n' + \
                  '如果不嫌文件体积大,请下载登录辅助程序:\n' + \
                  'https://github.com/rachpt/lanzou-gui/releases'
            message_box = QMessageBox(self)
            message_box.setIcon(QMessageBox.Icon.Critical)
            message_box.setStyleSheet(btn_style)
            message_box.setWindowTitle(title)
            message_box.setText(msg)
            message_box.setStandardButtons(QMessageBox.StandardButton.Close)
            buttonC = message_box.button(QMessageBox.StandardButton.Close)
            buttonC.setText('关闭')
            message_box.exec()

    def get_cookie_by_web(self, cookie):
        """使用辅助登录程序槽函数"""
        self._cookie = cookie
        self._close_dialog()

    def call_auto_get_cookie(self):
        """自动读取浏览器cookie槽函数"""
        try:
            self._cookie = get_cookie_from_browser()
        except Exception as e:
            logger.error(f"Browser_cookie3 Error: {e}")
            self.auto_get_cookie_ok.setPlainText(f"❌获取失败,错误信息\n{e}")
        else:
            if self._cookie:
                self._user = self._pwd = ''
                self.auto_get_cookie_ok.setPlainText("✅获取成功即将登录……")
                QTimer.singleShot(2000, self._close_dialog)
            else:
                self.auto_get_cookie_ok.setPlainText("❌获取失败\n请提前使用支持的浏览器登录蓝奏云,读取前完全退出浏览器!\n支持的浏览器与顺序:\nchrome, chromium, opera, edge, firefox")

    def _close_dialog(self):
        """关闭对话框"""
        up_info = {"name": self._user, "pwd": self._pwd, "cookie": self._cookie}
        self._config.set_infos(up_info)
        self.clicked_ok.emit()
        self.close()
コード例 #14
0
class UploadDialog(QDialog):
    """文件上传对话框"""
    new_infos = pyqtSignal(object)

    def __init__(self, user_home):
        super().__init__()
        self.cwd = user_home
        self._folder_id = -1
        self._folder_name = "LanZouCloud"
        self.set_pwd = False
        self.set_desc = False
        self.pwd = ''
        self.desc = ''
        self.allow_big_file = False
        self.max_size = 100
        self.selected = []
        self.initUI()
        self.set_size()
        self.setStyleSheet(dialog_qss_style)

    def set_pwd_desc_bigfile(self, settings):
        self.set_pwd = settings["set_pwd"]
        self.set_desc = settings["set_desc"]
        self.pwd = settings["pwd"]
        self.desc = settings["desc"]
        self.allow_big_file = settings["allow_big_file"]
        self.max_size = settings["max_size"]
        if self.allow_big_file:
            self.btn_chooseMultiFile.setToolTip("")
        else:
            self.btn_chooseMultiFile.setToolTip(f"文件大小上限 {self.max_size}MB")

    def set_values(self, folder_name, folder_id, files):
        self.setWindowTitle("上传文件至 ➩ " + str(folder_name))
        self._folder_id = folder_id
        self._folder_name = folder_name
        if files:
            self.selected = files
            self.show_selected()
        self.exec()

    def initUI(self):
        self.setWindowTitle("上传文件")
        self.setWindowIcon(QIcon(SRC_DIR + "upload.ico"))
        self.logo = QLabel()
        self.logo.setPixmap(QPixmap(SRC_DIR + "logo3.gif"))
        self.logo.setStyleSheet("background-color:rgb(0,153,255);")
        self.logo.setAlignment(Qt.AlignmentFlag.AlignCenter)

        # btn 1
        self.btn_chooseDir = QPushButton("选择文件夹", self)
        self.btn_chooseDir.setObjectName("btn_chooseDir")
        self.btn_chooseDir.setObjectName("btn_chooseDir")
        self.btn_chooseDir.setIcon(QIcon(SRC_DIR + "folder.gif"))

        # btn 2
        self.btn_chooseMultiFile = QPushButton("选择多文件", self)
        self.btn_chooseDir.setObjectName("btn_chooseMultiFile")
        self.btn_chooseMultiFile.setObjectName("btn_chooseMultiFile")
        self.btn_chooseMultiFile.setIcon(QIcon(SRC_DIR + "file.ico"))

        # btn 3
        self.btn_deleteSelect = QPushButton("移除", self)
        self.btn_deleteSelect.setObjectName("btn_deleteSelect")
        self.btn_deleteSelect.setIcon(QIcon(SRC_DIR + "delete.ico"))
        self.btn_deleteSelect.setToolTip("按 Delete 移除选中文件")

        # 列表
        self.list_view = MyListView()
        self.list_view.drop_files.connect(self.add_drop_files)
        self.list_view.setViewMode(QListView.ViewMode.ListMode)
        self.slm = QStandardItem()
        self.model = QStandardItemModel()
        self.list_view.setModel(self.model)
        self.model.removeRows(0, self.model.rowCount())  # 清除旧的选择
        self.list_view.setEditTriggers(
            QAbstractItemView.EditTrigger.NoEditTriggers)
        self.list_view.setSelectionBehavior(
            QAbstractItemView.SelectionBehavior.SelectRows)
        self.list_view.setSelectionMode(
            QAbstractItemView.SelectionMode.ExtendedSelection)

        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
        self.buttonBox.setStandardButtons(
            QDialogButtonBox.StandardButton.Ok
            | QDialogButtonBox.StandardButton.Cancel)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText("确定")
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Cancel).setText("取消")

        vbox = QVBoxLayout()
        hbox_head = QHBoxLayout()
        hbox_button = QHBoxLayout()
        hbox_head.addWidget(self.btn_chooseDir)
        hbox_head.addStretch(1)
        hbox_head.addWidget(self.btn_chooseMultiFile)
        hbox_button.addWidget(self.btn_deleteSelect)
        hbox_button.addStretch(1)
        hbox_button.addWidget(self.buttonBox)
        vbox.addWidget(self.logo)
        vbox.addLayout(hbox_head)
        vbox.addWidget(self.list_view)
        vbox.addLayout(hbox_button)
        self.setLayout(vbox)
        self.setMinimumWidth(350)

        # 设置信号
        self.btn_chooseDir.clicked.connect(self.slot_btn_chooseDir)
        self.btn_chooseMultiFile.clicked.connect(self.slot_btn_chooseMultiFile)
        self.btn_deleteSelect.clicked.connect(self.slot_btn_deleteSelect)

        self.buttonBox.accepted.connect(self.slot_btn_ok)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.clear_old)
        self.buttonBox.rejected.connect(self.reject)

    def set_size(self):
        if self.selected:
            h = 18 if len(self.selected) > 18 else 10
            w = 40
            for i in self.selected:
                i_len = len(i)
                if i_len > 100:
                    w = 100
                    break
                if i_len > w:
                    w = i_len
            self.resize(120 + w * 7, h * 30)
        else:
            self.resize(400, 300)

    def clear_old(self):
        self.selected = []
        self.model.removeRows(0, self.model.rowCount())
        self.set_size()

    def show_selected(self):
        self.model.removeRows(0, self.model.rowCount())
        for item in self.selected:
            if os.path.isfile(item):
                self.model.appendRow(
                    QStandardItem(QIcon(SRC_DIR + "file.ico"), item))
            else:
                self.model.appendRow(
                    QStandardItem(QIcon(SRC_DIR + "folder.gif"), item))
            self.set_size()

    def backslash(self):
        """Windows backslash"""
        tasks = {}
        for item in self.selected:
            url = os.path.normpath(item)
            total_size = 0
            total_file = 0
            if os.path.isfile(url):
                total_size = os.path.getsize(url)
                if not total_size:
                    continue  # 空文件无法上传
                total_file += 1
            else:
                for filename in os.listdir(url):
                    file_path = os.path.join(url, filename)
                    if not os.path.isfile(file_path):
                        continue  # 跳过子文件夹
                    total_size += os.path.getsize(file_path)
                    total_file += 1
            tasks[url] = UpJob(url=url,
                               fid=self._folder_id,
                               folder=self._folder_name,
                               pwd=self.pwd if self.set_pwd else None,
                               desc=self.desc if self.set_desc else None,
                               total_size=total_size,
                               total_file=total_file)
        return tasks

    def slot_btn_ok(self):
        tasks = self.backslash()
        if self.selected:
            self.new_infos.emit(tasks)
            self.clear_old()

    def slot_btn_deleteSelect(self):
        _indexes = self.list_view.selectionModel().selection().indexes()
        if not _indexes:
            return
        indexes = []
        for i in _indexes:  # 获取所选行号
            indexes.append(i.row())
        indexes = set(indexes)
        for i in sorted(indexes, reverse=True):
            self.selected.remove(self.model.item(i, 0).text())
            self.model.removeRow(i)
        self.set_size()

    def add_drop_files(self, files):
        for item in files:
            if item not in self.selected:
                self.selected.append(item)
            self.show_selected()

    def slot_btn_chooseDir(self):
        dir_choose = QFileDialog.getExistingDirectory(self, "选择文件夹",
                                                      self.cwd)  # 起始路径
        if dir_choose == "":
            return
        if dir_choose not in self.selected:
            self.selected.append(dir_choose)
            self.cwd = os.path.dirname(dir_choose)
        self.show_selected()

    def slot_btn_chooseMultiFile(self):
        files, _ = QFileDialog.getOpenFileNames(self, "选择多文件", self.cwd,
                                                "All Files (*)")
        if len(files) == 0:
            return
        for _file in files:
            if _file not in self.selected:
                if os.path.getsize(_file) <= self.max_size * 1048576:
                    self.selected.append(_file)
                elif self.allow_big_file:
                    self.selected.append(_file)
        self.show_selected()

    def keyPressEvent(self, e):
        if e.key() == Qt.Key.Key_Delete:  # delete
            self.slot_btn_deleteSelect()