Beispiel #1
0
class HLabels(QHBoxLayout):
    labelSheet = """QLabel {
                        font-size: 12pt;
                        font-weight: bold;
                        padding-right: 5px;
                        color: #9eeeee;}"""

    valSheet = """QLabel {
                        font-size: 12pt;
                        font-weight: bold;
                        color: #eece9e;}"""

    def __init__(self, label1=None, label2=None):
        super().__init__()
        self.label = QLabel(label1)
        self.label.setStyleSheet(self.labelSheet)
        self.value = QLabel(label2)
        self.value.setStyleSheet(self.valSheet)
        self.addWidget(self.label)
        self.addWidget(self.value)
        self.label.setAlignment(Qt.AlignmentFlag.AlignRight)
        self.value.setAlignment(Qt.AlignmentFlag.AlignLeft)

    def update_value(self, text):
        self.value.setText(str(text))

    def update_percent(self, var):
        text = str(round(var * 100, 4))
        self.value.setText(text + "%")
    def setUpWindow(self):
        """Set up the dialog's widgets and layout."""
        header_label = QLabel("""<p style='color:#65888C'>
            Welcome to Database Manager</p>""")
        header_label.setFont(QFont("Arial", 24))
        header_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.info_label = QLabel("""<p style='color:#65888C'>
            Sign into your account.</p>""")
        self.info_label.setAlignment(Qt.AlignmentFlag.AlignHCenter)

        username_label = QLabel("Username:"******"Password:"******"Log In", QDialogButtonBox.ButtonRole.AcceptRole)
        button_box.accepted.connect(self.clickedLogInButton)

        log_in_grid = QGridLayout()
        log_in_grid.addWidget(header_label, 0, 0, 1, 3,
                              Qt.AlignmentFlag.AlignCenter)
        log_in_grid.addWidget(self.info_label, 1, 0, 1, 3,
                              Qt.AlignmentFlag.AlignCenter)
        log_in_grid.addWidget(username_label, 2, 0)
        log_in_grid.addWidget(self.username_line, 2, 1)
        log_in_grid.addWidget(password_label, 3, 0)
        log_in_grid.addWidget(self.password_line, 3, 1)
        log_in_grid.addWidget(button_box, 4, 1)
        self.setLayout(log_in_grid)
Beispiel #3
0
class MainWindow(QMainWindow):
    def __init__(self):
        """ MainWindow Constructor """
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        """Initialize settings, call functions that define 
        UI elements, and display the main window."""
        self.setMinimumSize(700, 400)
        self.setWindowTitle("GIF and Image Viewer")

        # Set up the main window, menu, and dock widgets
        self.setUpMainWindow()
        self.show()  # Display the main window

    def setUpMainWindow(self):
        """Set up the application's main window and widgets."""
        self.movie = QMovie()  # Create movie object

        self.media_label = QLabel()  # Create label to place images/GIFs on
        self.media_label.setPixmap(QPixmap("icons/image_label.png"))
        self.media_label.setFrameShape(QFrame.Shape.StyledPanel)
        self.media_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.setCentralWidget(self.media_label)
Beispiel #4
0
    def __addLine__(self, label, value):
        lbl = QLabel(label)
        lbl.setAlignment(Qt.Alignment.AlignRight)
        self.layout.addWidget(lbl, self.row, 0)

        lbl = QLabel(value)
        lbl.setAlignment(Qt.Alignment.AlignTop)
        self.layout.addWidget(lbl, self.row, 1)
        self.row += 1
Beispiel #5
0
        def make_slider(MAX_RANGE, INIT_VALUE):
            label = QLabel("")
            label.setAlignment(Qt.AlignmentFlag.AlignCenter)

            slider = QSlider(orientation=Qt.Orientation.Horizontal)
            slider.setRange(0, SLIDER_MAX_RANGE_INT)
            slider.setValue(int(SLIDER_MAX_RANGE_INT*(INIT_VALUE/MAX_RANGE)))
            slider.setTickPosition(QSlider.TickPosition.TicksBelow)
            slider.setTickInterval(int(SLIDER_MAX_RANGE_INT*0.1))
            slider.setSingleStep(1)

            return slider, label
Beispiel #6
0
class StatsFrame(QWidget):
    """Calculate statistics for each turn of the players."""

    label_ssheet = """QLabel {
                    font-size: 15pt;
                    font-weight: bold;
                    padding-right: 5px;
                    color: #fca018;}"""

    def __init__(self, parent=None, window=None):
        super().__init__(parent=parent)
        self.window = window
        self.hlayout = QHBoxLayout()
        self.setLayout(self.hlayout)
        self.vbox1 = QVBoxLayout()
        self.vbox2 = QVBoxLayout()
        self.cardCount = HLabels("Cards in Deck: ", "0")
        self.deckCount = HLabels("Number of Decks: ", "0")
        self.playerCount = HLabels("Number of Players: ", "0")
        self.breaking21 = HLabels("Breaking 21: ", " 0")
        self.exactly = HLabels("Exactly 21: ", " 0")
        self.under21 = HLabels("Under 21: ", " 0")
        self.probabilities = QLabel("Probabilities", parent=self)
        self.quantities = QLabel("Quantities", parent=self)
        self.vbox2.addWidget(self.quantities)
        self.vbox2.addLayout(self.cardCount)
        self.vbox2.addLayout(self.deckCount)
        self.vbox2.addLayout(self.playerCount)
        self.vbox1.addWidget(self.probabilities)
        self.vbox1.addLayout(self.breaking21)
        self.vbox1.addLayout(self.exactly)
        self.vbox1.addLayout(self.under21)
        self.hlayout.addLayout(self.vbox1)
        self.hlayout.addLayout(self.vbox2)
        self.quantities.setStyleSheet(self.label_ssheet)
        self.probabilities.setStyleSheet(self.label_ssheet)
        self.probabilities.setAlignment(Qt.AlignmentFlag(4))
        self.quantities.setAlignment(Qt.AlignmentFlag(4))
        self.labels = {
            "cards": self.cardCount,
            "decks": self.deckCount,
            "players": self.playerCount,
            "breaking": self.breaking21,
            "exactly": self.exactly,
            "under": self.under21,
        }
        self.window.driver.hook(self.labels)
Beispiel #7
0
def App():
    app = QApplication(sys.argv)
    win = QWidget()

    win.setWindowTitle("PyQt6 QLabel Example")
    win.left = 100
    win.top = 100

    l1 = QLabel("Hello World")
    l2 = QLabel("Welcome to Python GUI Programming")
    #
    # Because you can't instantiate a QLable directly with a QPixmap.
    #
    l3 = QLabel()
    l3.setPixmap(QPixmap("python-small.png"))

    l1.setAlignment(Qt.Alignment.AlignCenter)
    l2.setAlignment(Qt.Alignment.AlignCenter)
    l3.setAlignment(Qt.Alignment.AlignCenter)

    vbox = QVBoxLayout()
    vbox.addWidget(l1)
    vbox.addStretch()
    vbox.addWidget(l2)
    vbox.addStretch()
    vbox.addWidget(l3)
    vbox.addStretch()

    win.setLayout(vbox)
    win.show()
    sys.exit(app.exec())
Beispiel #8
0
 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()
Beispiel #9
0
class FixedSlider(QSlider):
    def __init__(self):
        super(FixedSlider,self).__init__()
        self.setTickInterval(1)
        self.value_label=QLabel(self)    
        self.value_label.setFixedSize(40,20) 
        self.value_label.setAutoFillBackground(True)
        self.value_label.setStyleSheet("QLabel{background:transparent;font:8px}")
        self.value_label.setAlignment(Qt.Alignment.AlignCenter)
        self.value_label.setVisible(False)
        self.value_label.move(0,-5)
    def mousePressEvent(self,event:QMouseEvent):
        super(FixedSlider,self).mousePressEvent(event)
        if self.value_label.isVisible()==False:
            self.value_label.setVisible(True)
            self.value_label.setText(str(self.value()/10))
    def mouseMoveEvent(self,event:QMouseEvent):
        super(FixedSlider,self).mouseMoveEvent(event)
        self.value_label.setText(str(self.value()/10))
        self.value_label.move(int((self.width()-self.value_label.width())*self.value()/(self.maximum()-self.minimum())),-5)
    def mouseReleaseEvent(self,event:QMouseEvent):
        super(FixedSlider,self).mouseReleaseEvent(event)
        if self.value_label.isVisible()==True:
            self.value_label.setVisible(False)
Beispiel #10
0
class ConfigDialog(QDialog):
    def __init__(self, parent=None):
        super(ConfigDialog, self).__init__(parent)
        self.classifyExercises = parent.classifyExercises
        self.setFixedSize(500, 400)
        self.setWindowTitle("Model Configurations")

        self.epochValue = QLabel()
        self.vbox = QVBoxLayout()
        self.label_maximum = QLabel()
        self.label_minimum = QLabel()
        self.slider_hbox = QHBoxLayout()
        self.slider_vbox = QVBoxLayout()
        self.batchSizeMenu = QComboBox()
        self.properties = QFormLayout()
        self.epochSlider = Slider(orientation=Qt.Orientations.Horizontal)

        self.trainButton = QPushButton('Train Model')
        self.resultButton = QPushButton('Show result image')
        self.progress = QProgressBar()

        self.batchSizeMenu.addItems(['2', '4', '8', '16', '32', '64', '128'])
        self.batchSizeMenu.setCurrentIndex(3)
        self.batchSizeMenu.setMaximumWidth(100)

        self.initSlider()

        self.properties.addRow('Batch Size', self.batchSizeMenu)

        self.resultButton.setEnabled(False)
        self.actionsLayout = QHBoxLayout()

        self.actionsLayout.addWidget(self.trainButton)
        self.actionsLayout.addWidget(self.resultButton)

        self.optionsLayout = QVBoxLayout()
        self.optionsLayout.addWidget(QLabel('Model properties'))
        self.optionsLayout.addLayout(self.vbox)
        self.optionsLayout.addLayout(self.properties)
        self.optionsLayout.addLayout(self.actionsLayout)
        self.progress.setAlignment(QtCore.Qt.Alignment.AlignCenter)
        self.optionsLayout.addWidget(self.progress)
        # self.options_layout.addWidget(self.label)
        # self.options_layout.addWidget(self.list_widget)

        self.setLayout(self.optionsLayout)

        self.trainThread = TrainThread(self.classifyExercises)
        self.connections()
        print("init config")

    def initSlider(self):
        self.epochValue.setAlignment(QtCore.Qt.Alignment.AlignHCenter)

        self.epochSlider.setMinimum(2)
        self.epochSlider.setMaximum(10)
        self.epochSlider.setTickInterval(1)
        # self.epochSlider.setInterval(1)
        # self.epochSlider.setValue(8)  # no idea why, but 8 is the middle somehow
        self.epochSlider.setSliderPosition(6)
        self.epochSlider.setTickPosition(QSlider.TickPosition.TicksBelow)

        self.label_minimum.setNum(self.epochSlider.minimum().real * 50)
        self.label_minimum.setAlignment(QtCore.Qt.Alignment.AlignLeft)
        self.label_maximum.setNum(self.epochSlider.maximum().real * 50)

        self.label_maximum.setAlignment(QtCore.Qt.Alignment.AlignRight)

        self.epochSlider.minimumChanged.connect(self.label_minimum.setNum)
        self.epochSlider.maximumChanged.connect(self.label_maximum.setNum)

        self.slider_hbox.addWidget(self.label_minimum,
                                   QtCore.Qt.Alignment.AlignLeft)
        self.slider_hbox.addWidget(self.epochValue)
        self.slider_hbox.addWidget(self.label_maximum,
                                   QtCore.Qt.Alignment.AlignRight)

        self.slider_vbox.addWidget(self.epochSlider)
        self.slider_vbox.addLayout(self.slider_hbox)
        # self.slider_vbox.addStretch()

        self.vbox.addLayout(self.slider_vbox)

    def connections(self):
        self.batchSizeMenu.currentIndexChanged.connect(
            self.onBatchSizeSelected)
        self.resultButton.clicked.connect(self.onResultClicked)
        self.trainButton.clicked.connect(self.onTrainClicked)
        self.epochSlider.valueChanged.connect(self.updateEpochValue)
        self.trainThread.taskFinished.connect(self.onFinished)

    def updateEpochValue(self, num):
        print(num)
        epochs = num * 50
        self.epochValue.setNum(epochs)
        self.classifyExercises.epochs = epochs

    def onBatchSizeSelected(self, ind):
        self.classifyExercises.training_batch_size = int(
            self.batchSizeMenu.currentText())

    def onResultClicked(self):
        print("open image")
        self.classifyExercises.DisplayResults()

    def onTrainClicked(self):
        if self.classifyExercises.subject is not None:
            if self.classifyExercises.DataAvailable():
                if self.resultButton.isEnabled:
                    self.resultButton.setEnabled(False)

                self.trainThread.start()
                self.progress.setRange(0, 0)
            else:
                CustomMessage.showDialog(
                    "Message", "Calibrate for patient to obtain data.",
                    QMessageBox.StandardButtons.Ok)

        else:
            CustomMessage.showDialog(
                "Message", "You must either select or enter a subject name.",
                QMessageBox.StandardButtons.Ok)
            print("Subject is none!")

    def onFinished(self):
        # Stop the progress
        self.progress.setRange(0, 1)
        self.progress.setValue(1)
        CustomMessage.showDialog("Message", "Training model finished!",
                                 QMessageBox.StandardButtons.Ok)
        self.resultButton.setEnabled(True)
Beispiel #11
0
class MainWindow(QMainWindow):
    def __init__(self):
        """ MainWindow Constructor """
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        """Initialize settings, call functions that define 
        UI elements, and display the main window."""
        self.setMinimumSize(700, 400)
        self.setWindowTitle("GIF and Image Viewer")

        # Set up the main window and dock widget
        self.setUpMainWindow()
        self.displayFilesDock()
        self.show()  # Display the main window

    def setUpMainWindow(self):
        """Set up the application's main window and widgets."""
        self.movie = QMovie()  # Create movie object

        self.media_label = QLabel()  # Create label to place images/GIFs on
        self.media_label.setPixmap(QPixmap("icons/image_label.png"))
        self.media_label.setFrameShape(QFrame.Shape.StyledPanel)
        self.media_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.setCentralWidget(self.media_label)

    def displayFilesDock(self):
        """Dock widget that displays the movie file location in a QLineEdit 
        widget, provides a button for opening directories with images and GIFs, 
        and shows the media from the selected folder in a QTreeWidget."""
        self.files_dock = QDockWidget()
        self.files_dock.setWindowTitle("Media Folder")
        self.files_dock.setAllowedAreas(Qt.DockWidgetArea.LeftDockWidgetArea)

        folder_label = QLabel("Media Location:")
        # The QLineEdit widget is set to read-only as a quick way to display
        # the folder path
        self.folder_line = QLineEdit()
        self.folder_line.setMinimumWidth(100)
        self.folder_line.setReadOnly(True)

        open_button = QPushButton("Open...")

        folder_h_box = QHBoxLayout()
        folder_h_box.addWidget(folder_label)
        folder_h_box.addWidget(self.folder_line)
        folder_h_box.addWidget(open_button)

        self.files_tree = QTreeWidget()
        self.files_tree.setHeaderLabel("Media Files")
        self.files_tree.setColumnCount(1)

        # Set up the dock's layout
        dock_v_box = QVBoxLayout()
        dock_v_box.addLayout(folder_h_box)
        dock_v_box.addWidget(self.files_tree)

        dock_container = QWidget()
        dock_container.setLayout(dock_v_box)

        self.files_dock.setWidget(dock_container)
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea,
                           self.files_dock)
class LoginWindow(QDialog):
    def __init__(self):
        """ Login Dialog """
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        self.setWindowTitle("Login Window")
        self.setFixedSize(500, 200)

        self.setUpWindow()
        # Connect to database after setting up the login dialog
        self.connectToDatabase()
        self.show()

    def setUpWindow(self):
        """Set up the dialog's widgets and layout."""
        header_label = QLabel("""<p style='color:#65888C'>
            Welcome to Database Manager</p>""")
        header_label.setFont(QFont("Arial", 24))
        header_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.info_label = QLabel("""<p style='color:#65888C'>
            Sign into your account.</p>""")
        self.info_label.setAlignment(Qt.AlignmentFlag.AlignHCenter)

        username_label = QLabel("Username:"******"Password:"******"Log In", QDialogButtonBox.ButtonRole.AcceptRole)
        button_box.accepted.connect(self.clickedLogInButton)

        log_in_grid = QGridLayout()
        log_in_grid.addWidget(header_label, 0, 0, 1, 3,
                              Qt.AlignmentFlag.AlignCenter)
        log_in_grid.addWidget(self.info_label, 1, 0, 1, 3,
                              Qt.AlignmentFlag.AlignCenter)
        log_in_grid.addWidget(username_label, 2, 0)
        log_in_grid.addWidget(self.username_line, 2, 1)
        log_in_grid.addWidget(password_label, 3, 0)
        log_in_grid.addWidget(self.password_line, 3, 1)
        log_in_grid.addWidget(button_box, 4, 1)
        self.setLayout(log_in_grid)

    def connectToDatabase(self):
        """Create a QSqlDatabase object and connect to the database."""
        database = QSqlDatabase.addDatabase("QSQLITE")
        database.setDatabaseName("data/inventory.db")
        database.setConnectOptions("QSQLITE_ENABLE_REGEXP")
        if not database.open():
            error = database.lastError().text()
            QMessageBox.critical(QApplication.activeWindow(),
                                 "Connection Error",
                                 f"Something went wrong: {error}")
            sys.exit(1)

        # Handle if the database is missing and SQLite creates a new,
        # empty database
        tables_needed = {
            "Staff", "Customers", "Orders", "Products", "Categories"
        }
        no_tables = tables_needed - set(database.tables())
        if no_tables:
            QMessageBox.critical(QApplication.activeWindow(), "Error",
                                 f'{no_tables} missing.')
            sys.exit(1)

    def replaceText(self, text):
        """Slot for resetting the information label's text."""
        self.info_label.setText(
            "<p style='color:#65888C'>Sign into your account.</p>")

    def clickedLogInButton(self):
        """Check the user's username and password information from 
        the database to determine if they are able to log in."""
        username = self.username_line.text()
        password = self.password_line.text()

        query = QSqlQuery()
        query.exec("PRAGMA foreign_keys = ON")
        query.prepare("SELECT * FROM Staff WHERE username=:username")
        query.bindValue(":username", username)
        query.exec()

        # Open the main window or provide feedback
        if query.first():  # Retrieve the first matching username
            if query.value("password") == password:
                admin_or_not = query.value(
                    "is_admin"
                )  # Retrieve the value for administrative privileges

                # Open the main window and close the login dialog
                self.main_window = MainWindow(admin_or_not)
                self.main_window.showMaximized()
                self.close()
            else:
                self.info_label.setText(
                    "<p style='color:#F34B2C'>Incorrect password.</p>")
        else:
            self.info_label.setText(
                "<p style='color:#F34B2C'>Incorrect username.</p>")
Beispiel #13
0
class MergeFileDialog(QDialog):
    check_update = pyqtSignal(str, bool)

    def __init__(self, user_home, parent=None):
        super(MergeFileDialog, self).__init__(parent)
        self.cwd = user_home
        self.selected = ""
        self.initUI()
        self.setStyleSheet(others_style)

    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)

        # lable
        self.choose_lb = QLabel("选择文件夹")
        # folder
        self.choose_folder = MyLineEdit(self)
        self.choose_folder.setObjectName("choose_folder")
        self.choose_folder.clicked.connect(self.slot_choose_folder)
        self.status = QLabel(self)

        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("关闭")
        self.buttonBox.setStyleSheet(btn_style)

        vbox = QVBoxLayout()
        hbox_head = QHBoxLayout()
        hbox_button = QHBoxLayout()
        hbox_head.addWidget(self.choose_lb)
        hbox_head.addWidget(self.choose_folder)
        hbox_button.addWidget(self.buttonBox)
        vbox.addWidget(self.logo)
        vbox.addStretch(1)
        vbox.addWidget(self.status)
        vbox.addLayout(hbox_head)
        vbox.addStretch(1)
        vbox.addLayout(hbox_button)
        self.setLayout(vbox)
        self.setMinimumWidth(350)

        # 设置信号
        self.buttonBox.accepted.connect(self.slot_btn_ok)
        self.buttonBox.rejected.connect(self.slot_btn_no)
        self.buttonBox.rejected.connect(self.reject)

    def slot_choose_folder(self):
        dir_choose = QFileDialog.getExistingDirectory(self, "选择文件夹",
                                                      self.cwd)  # 起始路径
        if dir_choose == "":
            return
        self.selected = dir_choose
        self.choose_folder.setText(self.selected)
        self.status.setText("")
        self.cwd = os.path.dirname(dir_choose)

    def slot_btn_no(self):
        self.selected = ""
        self.choose_folder.setText(self.selected)
        self.status.setText("")

    def slot_btn_ok(self):
        if self.selected:
            success, msg = un_serialize(self.selected)
            if success:
                text = "提取成功✅"
            else:
                text = f"提取失败❌, {msg}"
        else:
            text = "未选择文件夹📂"
        self.status.setText(text)
Beispiel #14
0
class MainWindow(QMainWindow):

    def __init__(self):
        """MainWindow Constructor for Image Manager"""
        super().__init__() # Constructor for QMainWindow
        self.initializeUI()
        
    def initializeUI(self):
        """Set up the GUI's main window."""
        self.setWindowTitle("Image Manager")
        self.setObjectName("ImageManager")
  
        # Set up the main window, menu, and dock widgets
        self.setUpMainWindow()
        self.displayImagePreviewDock()
        self.createActions()
        self.createMenus()
        self.show() # Display the main window

    def setUpMainWindow(self):
        """Set up the application's main window containing the QListWidget."""
        self.image_view_lw = ImageViewerListWidget(self)
        self.setCentralWidget(self.image_view_lw)

    def createActions(self):
        """Create the application's menu actions."""
        # Create actions for File menu
        self.import_act = QAction("Import Images...", self, triggered=self.importImages)
        self.import_act.setShortcut("Ctrl+I") 

        self.preferences_act = QAction("Preferences...", self, triggered=self.showPreferencesDialog)
           
        self.quit_act = QAction("Quit Task Manager", self, triggered=self.close)
        self.quit_act.setShortcut(QKeySequence.StandardKey.Quit) # Ctrl+Q

        # Create actions for Edit menu
        self.select_all_act = QAction("Select All", self, triggered=self.image_view_lw.selectAll)
        self.select_all_act.setShortcut(QKeySequence.StandardKey.SelectAll) # Ctrl+A

        self.delete_act = QAction("Delete Images", self, triggered=self.deleteImages)
        self.delete_act.setShortcut(QKeySequence.StandardKey.Delete) # Del
        self.delete_act.setEnabled(False)

        # Create actions for View menu
        # Handle the visibility of the dock widget
        self.show_dock_act = self.image_preview_dock.toggleViewAction()
        self.show_dock_act.setText("Show Image View") 

        self.sort_ascend_act = QAction("Sort Ascending", self, 
            triggered=lambda: self.sortListItems(Qt.SortOrder.AscendingOrder))
        self.sort_ascend_act.setEnabled(False)

        self.sort_descend_act = QAction("Sort Descending", self, 
            triggered=lambda: self.sortListItems(Qt.SortOrder.DescendingOrder))
        self.sort_descend_act.setEnabled(False)

        self.fullscreen_act = QAction("Show Fullscreen", self, 
            triggered=self.displayFullScreen, checkable=True)

        # Create actions for Help menu
        self.about_act = QAction("About Image Manager", 
            self, triggered=self.showAboutDialog)

    def createMenus(self):
        """Create the application's menu."""
        self.file_menu = self.menuBar().addMenu("&File")
        self.file_menu.addAction(self.import_act)
        self.file_menu.addSeparator()
        self.file_menu.addAction(self.preferences_act)
        self.file_menu.addSeparator()
        self.file_menu.addAction(self.quit_act)

        self.edit_menu = self.menuBar().addMenu("&Edit")
        self.edit_menu.addAction(self.select_all_act)
        self.edit_menu.addSeparator()
        self.edit_menu.addAction(self.delete_act)  

        self.view_menu = self.menuBar().addMenu("&View")
        self.view_menu.addAction(self.show_dock_act)  
        self.view_menu.addSeparator()
        self.view_menu.addAction(self.sort_ascend_act)
        self.view_menu.addAction(self.sort_descend_act)
        self.view_menu.addSeparator()
        self.view_menu.addAction(self.fullscreen_act) 

        self.help_menu = self.menuBar().addMenu("&Help")
        self.help_menu.addAction(self.about_act)  

    def displayImagePreviewDock(self):
        """Dock widget that displays a selected image in a scrollable 
        area and uses its file name as the dock's title."""        
        self.image_preview_dock = QDockWidget()
        self.image_preview_dock.setObjectName("PreviewDock")
        self.image_preview_dock.setWindowTitle("Show Image View")
        self.image_preview_dock.setAllowedAreas(Qt.DockWidgetArea.RightDockWidgetArea)

        self.display_image_label = QLabel()
        self.display_image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.view_scroll_area = QScrollArea()
        self.view_scroll_area.setMinimumWidth(300)
        self.view_scroll_area.setWidgetResizable(True)

        self.image_preview_dock.setWidget(self.view_scroll_area)
        # Set initial location of dock widget
        self.addDockWidget(Qt.DockWidgetArea.RightDockWidgetArea, self.image_preview_dock)  

    def displayFullScreen(self, state):
        """Check the state of checkable fullscreen_act. If True, show the 
        main window as fullscreen."""
        if state: self.showFullScreen()
        else: self.showNormal()

    def importImages(self):
        """Placeholder method."""
        pass

    def deleteImages(self):
        """Placeholder method."""
        pass

    def showPreferencesDialog(self):
        """Placeholder method."""
        pass

    def showAboutDialog(self):
        """Placeholder method."""
        pass
Beispiel #15
0
class UIComicInfoWidget(QWidget):
    load_chapter_list_signa = QtCore.pyqtSignal(ChapterInfo)
    load_download_task_signa = QtCore.pyqtSignal(DownloadTask)

    def __init__(self, comic_info: ComicInfo, down_v_box_layout: QVBoxLayout):
        super().__init__()
        self.comic_info = comic_info
        self.down_v_box_layout = down_v_box_layout
        self.img_label = QLabel(self)
        self.img_label.setScaledContents(True)
        img = QImage.fromData(comic_info.cover)
        w, h = image_resize(comic_info.cover, width=200)
        self.img_label.resize(QtCore.QSize(w, h))
        self.img_label.setGeometry(10, 10, w, h)
        self.img_label.setPixmap(QPixmap.fromImage(img))
        # self.img_label.setPixmap(QtGui.QPixmap("/Users/bo/my/tmp/老夫子2/第1卷/1.jpg"))

        self.title = QLabel(self)
        self.title.setGeometry(220, 10, 100, 40)
        title_font = QtGui.QFont()
        title_font.setPointSize(16)
        title_font.setBold(True)
        title_font.setUnderline(True)
        self.title.setFont(title_font)
        self.title.setText(comic_info.title)
        self.title.setWordWrap(True)

        info_font = QtGui.QFont()
        info_font.setPointSize(14)
        # 作者
        self.author = QLabel(self)
        self.author.setText("作者 : " + comic_info.author)
        self.author.setGeometry(220, 50, 150, 40)
        self.author.setWordWrap(True)
        self.author.setFont(info_font)
        # 状态
        self.status = QLabel(self)
        self.status.setText("更新状态 : " + comic_info.status)
        self.status.setGeometry(220, 90, 150, 40)
        self.status.setFont(info_font)

        # 热度
        self.heat = QLabel(self)
        self.heat.setText("热度 : " + str(comic_info.heat))
        self.heat.setGeometry(220, 130, 150, 40)
        self.heat.setFont(info_font)

        # 类型
        self.tip = QLabel(self)
        self.tip.setText("类型 : " + comic_info.tip)
        self.tip.setGeometry(220, 170, 150, 40)
        self.tip.setWordWrap(True)
        self.tip.setFont(info_font)

        # web
        self.domain = QLabel(self)
        self.domain.setText(f"查看原网页 : {comic_info.domain}")
        self.domain.setText(f'查看原网页 : <a href="{comic_info.url}">{comic_info.domain}</a>')
        self.domain.setGeometry(220, 210, 150, 40)
        self.domain.setOpenExternalLinks(True)
        self.domain.setFont(info_font)

        # 描述
        self.describe = QLabel(self)
        self.describe.setText("  " + comic_info.describe)
        self.describe.setGeometry(10, 320, 350, 330)
        self.describe.setWordWrap(True)
        # 对齐方式
        self.describe.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignTop)

        # 章节列表,创建一个区域

        self.searchHBoxLayout = QHBoxLayout()
        # self.searchHBoxLayout.addSpacing()
        self.searchGroupBox = QGroupBox()
        self.searchGroupBox.setLayout(self.searchHBoxLayout)

        self.searchScroll = QScrollArea(self)
        self.searchScroll.setGeometry(370, 10, 574, 590)
        self.searchScroll.setWidget(self.searchGroupBox)
        self.searchScroll.setWidgetResizable(True)

        # 全选
        self.check_all = QCheckBox(self)
        self.check_all.setText("全选")
        self.check_all.setGeometry(700, 610, 100, 20)
        self.check_all.stateChanged.connect(self.check_all_fun)

        # 下载
        self.down_button = QPushButton(self)
        self.down_button.setText("下载")
        self.down_button.setGeometry(780, 605, 50, 30)

        self.down_button.clicked.connect(self.download_button_click)

        self.load_chapter_list_signa.connect(self.load_chapter)
        self.load_download_task_signa.connect(self.download_callback)

        # 调用对应的service的接口,获取章节列表
        constant.SERVICE.chapter(comic_info, self.load_chapter_list_signa.emit)

    i = 0
    searchVBoxLayout: QVBoxLayout
    check_box_list: List[QCheckBox] = []

    def check_all_fun(self):
        for check_box in self.check_box_list:
            check_box.setChecked(self.check_all.isChecked())

    def download_callback(self, task: DownloadTask):
        widget = DownLoadTaskWidget(task)
        self.down_v_box_layout.addWidget(widget)

    def download_button_click(self):
        flag = False
        for check_box in self.check_box_list:
            if check_box.isChecked():
                constant.SERVICE.parse_image(self.comic_info, check_box.property("chapter_info"),
                                             self.load_download_task_signa.emit)
                if not flag:
                    QMessageBox.information(self, "下载通知", "正在解析选中章节", QMessageBox.StandardButton.Yes)
                    flag = True

    def load_chapter(self, chapter_info: ChapterInfo):
        if self.i % 26 == 0:
            self.searchVBoxLayout = QVBoxLayout()
            self.searchVBoxLayout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)  # 对齐方式,研究了3个小时 o(╥﹏╥)o
            self.searchHBoxLayout.addLayout(self.searchVBoxLayout)

        check_box = QCheckBox()
        self.check_box_list.append(check_box)
        check_box.setText(chapter_info.title)
        check_box.setProperty("chapter_info", chapter_info)
        task = constant.downloaded_task_map.get(chapter_info.url)
        if task and task.status == -1:
            check_box.setStyleSheet('color:red')
            check_box.setChecked(True)

        self.searchVBoxLayout.addWidget(check_box)
        self.i += 1
Beispiel #16
0
class MoveFileDialog(QDialog):
    '''移动文件对话框'''
    new_infos = pyqtSignal(object)

    def __init__(self, parent=None):
        super(MoveFileDialog, self).__init__(parent)
        self.infos = None
        self.dirs = {}
        self.initUI()
        self.setStyleSheet(dialog_qss_style)

    def update_ui(self):
        names = "\n".join([i.name for i in self.infos])
        names_tip = "\n".join([i.name for i in self.infos])
        self.tx_name.setText(names)
        self.tx_name.setToolTip(names_tip)

        self.tx_new_path.clear()
        f_icon = QIcon(SRC_DIR + "folder.gif")
        for f_name, fid in self.dirs.items():
            if len(f_name) > 50:  # 防止文件夹名字过长?
                f_name = f_name[:47] + "..."
            self.tx_new_path.addItem(f_icon,
                                     "id:{:>8},name:{}".format(fid, f_name))

    def set_values(self, infos, all_dirs_dict):
        self.infos = infos
        self.dirs = all_dirs_dict
        self.update_ui()
        self.exec()

    def initUI(self):
        self.setWindowTitle("移动文件(夹)")
        self.setWindowIcon(QIcon(SRC_DIR + "move.ico"))
        self.lb_name = QLabel()
        self.lb_name.setText("文件(夹)名:")
        self.lb_name.setAlignment(Qt.AlignmentFlag.AlignRight
                                  | Qt.AlignmentFlag.AlignTrailing
                                  | Qt.AlignmentFlag.AlignVCenter)
        self.tx_name = AutoResizingTextEdit()
        self.tx_name.setFocusPolicy(Qt.FocusPolicy.NoFocus)  # 只读
        self.tx_name.setReadOnly(True)
        self.lb_new_path = QLabel()
        self.lb_new_path.setText("目标文件夹:")
        self.lb_new_path.setAlignment(Qt.AlignmentFlag.AlignRight
                                      | Qt.AlignmentFlag.AlignTrailing
                                      | Qt.AlignmentFlag.AlignVCenter)
        self.tx_new_path = QComboBox()

        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("取消")

        self.grid = QGridLayout()
        self.grid.setSpacing(10)
        self.grid.addWidget(self.lb_name, 1, 0)
        self.grid.addWidget(self.tx_name, 1, 1)
        self.grid.addWidget(self.lb_new_path, 2, 0)
        self.grid.addWidget(self.tx_new_path, 2, 1)
        self.grid.addWidget(self.buttonBox, 3, 0, 1, 2)
        self.setLayout(self.grid)
        self.buttonBox.accepted.connect(self.btn_ok)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        self.setMinimumWidth(280)

    def btn_ok(self):
        new_id = self.tx_new_path.currentText().split(",")[0].split(":")[1]
        for index in range(len(self.infos)):
            self.infos[index].new_id = int(new_id)
        self.new_infos.emit(self.infos)
Beispiel #17
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)
Beispiel #18
0
class MainWindow(QMainWindow):
    def __init__(self):
        """ MainWindow Constructor """
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        """Initialize settings, call functions that define 
        UI elements, and display the main window."""
        self.setMinimumSize(700, 400)
        self.setWindowTitle("GIF and Image Viewer")

        # Set up the main window, menu, and dock widget
        self.setUpMainWindow()
        self.displayFilesDock()
        self.createActions()
        self.createMenus()
        self.createToolbar()
        self.show()  # Display the main window

    def setUpMainWindow(self):
        """Set up the application's main window and widgets."""
        self.movie = QMovie()  # Create movie object
        self.movie.stateChanged.connect(self.changeButtonStates)

        self.media_label = QLabel()  # Create label to place images/GIFs on
        self.media_label.setPixmap(QPixmap("icons/image_label.png"))
        self.media_label.setFrameShape(QFrame.Shape.StyledPanel)
        self.media_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.setCentralWidget(self.media_label)

    def createActions(self):
        """Create the application's menu actions."""
        # Create actions for File menu
        self.open_act = QAction("Open...", self, triggered=self.openDirectory)
        self.open_act.setShortcut(QKeySequence.StandardKey.Open)

        self.quit_act = QAction("Quit Viewer", self, triggered=self.close)
        self.quit_act.setShortcut(QKeySequence.StandardKey.Quit)  # Ctrl+Q

        # Create actions for View menu
        # Handle the visibility of the dock widget
        self.show_dock_act = self.files_dock.toggleViewAction()
        self.show_dock_act.setText("Show Media Folder")

        # Create actions for the toolbar (These actions could also be
        # added to the GUI's menu bar or to a context menu)
        self.play_act = QAction(QIcon("icons/play.png"),
                                "Play",
                                self,
                                triggered=self.startMovie)
        self.pause_act = QAction(QIcon("icons/pause.png"),
                                 "Pause",
                                 self,
                                 triggered=self.pauseMovie)
        self.stop_act = QAction(QIcon("icons/stop.png"),
                                "Stop/Reset",
                                self,
                                triggered=self.stopMovie)
        self.disableMovieButtons()

    def createMenus(self):
        """Create the application's menu."""
        # Make the toolbar appear in the main window for macOS users.
        # More information about this in Chapter 2 - Building the Foundation for GUIs
        if QSysInfo.productType() == "macos" or "osx":
            self.menuBar().setNativeMenuBar(False)

        self.file_menu = self.menuBar().addMenu("&File")
        self.file_menu.addAction(self.open_act)
        self.file_menu.addSeparator()
        self.file_menu.addAction(self.quit_act)

        self.view_menu = self.menuBar().addMenu("&View")
        self.view_menu.addAction(self.show_dock_act)

    def createToolbar(self):
        """Create the application's toolbar for playing GIFs."""
        toolbar = self.addToolBar("GIF Controls Toolbar")
        toolbar.setIconSize(QSize(24, 24))

        # Add actions to the toolbar
        toolbar.addAction(self.play_act)
        toolbar.addAction(self.pause_act)
        toolbar.addAction(self.stop_act)

    def displayFilesDock(self):
        """Dock widget that displays the movie file location in a QLineEdit 
        widget, provides a button for opening directories with images and GIFs, 
        and shows the media from the selected folder in a QTreeWidget."""
        self.files_dock = QDockWidget()
        self.files_dock.setWindowTitle("Media Folder")
        self.files_dock.setAllowedAreas(Qt.DockWidgetArea.LeftDockWidgetArea)

        folder_label = QLabel("Media Location:")
        # The QLineEdit widget is set to read-only as a quick way to display
        # the folder path
        self.folder_line = QLineEdit()
        self.folder_line.setMinimumWidth(100)
        self.folder_line.setReadOnly(True)

        open_button = QPushButton("Open...")
        open_button.clicked.connect(self.openDirectory)

        folder_h_box = QHBoxLayout()
        folder_h_box.addWidget(folder_label)
        folder_h_box.addWidget(self.folder_line)
        folder_h_box.addWidget(open_button)

        self.files_tree = QTreeWidget()
        self.files_tree.setHeaderLabel("Media Files")
        self.files_tree.setColumnCount(1)

        # Set up the dock's layout
        dock_v_box = QVBoxLayout()
        dock_v_box.addLayout(folder_h_box)
        dock_v_box.addWidget(self.files_tree)

        dock_container = QWidget()
        dock_container.setLayout(dock_v_box)

        self.files_dock.setWidget(dock_container)
        self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea,
                           self.files_dock)

    def openDirectory(self):
        """Open a QFileDialog for selecting a local directory. Only display 
        image and GIF files."""
        directory = QFileDialog.getExistingDirectory(
            self, "Choose Directory", "", QFileDialog.Option.ShowDirsOnly
        )  # Specify the file mode to only select directories

        if directory:
            self.movie.setFileName(directory)
            # Check if image data is valid before playing
            if self.movie.isValid():
                # Use setMovie() to set the label's contents as the selected GIF
                self.media_label.setMovie(self.movie)
                self.startMovie()  # Call method to begin playing

    def startMovie(self):
        """Start playing the movie."""
        self.movie.start()

    def pauseMovie(self):
        """Pause the movie."""
        self.movie.setPaused(True)

    def stopMovie(self):
        """Stop playing the movie and reset the movie back to 
        the first frame."""
        self.movie.stop()
        self.movie.jumpToFrame(0)

    def changeButtonStates(self, state):
        """Slot that handles enabling/disabling buttons in the toolbar
        based on the state of QMovie."""
        if state == QMovie.MovieState.Running:
            # The animation begins playing once control returns to the event loop
            self.play_act.setEnabled(False)
            self.pause_act.setEnabled(True)
            self.stop_act.setEnabled(True)
        if state == QMovie.MovieState.Paused:
            self.play_act.setEnabled(True)
            self.pause_act.setEnabled(False)
            self.stop_act.setEnabled(False)
        if state == QMovie.MovieState.NotRunning:
            self.play_act.setEnabled(True)
            self.pause_act.setEnabled(False)
            self.stop_act.setEnabled(False)

    def disableMovieButtons(self):
        """Simple method to disable the movie buttons in the toolbar."""
        self.play_act.setEnabled(False)
        self.pause_act.setEnabled(False)
        self.stop_act.setEnabled(False)
Beispiel #19
0
    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)
Beispiel #20
0
class RenameDialog(QDialog):
    out = pyqtSignal(object)

    def __init__(self, parent=None):
        super(RenameDialog, self).__init__(parent)
        self.infos = []
        self.min_width = 400
        self.initUI()
        self.update_text()
        self.setStyleSheet(dialog_qss_style)

    def set_values(self, infos=None):
        self.infos = infos or []
        self.update_text()  # 更新界面

    def initUI(self):
        self.setWindowIcon(QIcon(SRC_DIR + "desc.ico"))
        self.lb_name = QLabel()
        self.lb_name.setText("文件夹名:")
        self.lb_name.setAlignment(Qt.AlignmentFlag.AlignRight
                                  | Qt.AlignmentFlag.AlignTrailing
                                  | Qt.AlignmentFlag.AlignVCenter)
        self.tx_name = QLineEdit()
        self.lb_desc = QLabel()
        self.tx_desc = QTextEdit()
        self.lb_desc.setText("描  述:")
        self.lb_desc.setAlignment(Qt.AlignmentFlag.AlignRight
                                  | Qt.AlignmentFlag.AlignTrailing
                                  | Qt.AlignmentFlag.AlignVCenter)

        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("取消")

        self.grid = QGridLayout()
        self.grid.setSpacing(10)
        self.grid.addWidget(self.lb_name, 1, 0)
        self.grid.addWidget(self.tx_name, 1, 1)
        self.grid.addWidget(self.lb_desc, 2, 0)
        self.grid.addWidget(self.tx_desc, 2, 1, 5, 1)
        self.grid.addWidget(self.buttonBox, 7, 1, 1, 1)
        self.setLayout(self.grid)
        self.buttonBox.accepted.connect(self.btn_ok)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

    def update_text(self):
        self.tx_desc.setFocus()
        num = len(self.infos)
        if num == 1:
            self.lb_name.setVisible(True)
            self.tx_name.setVisible(True)
            infos = self.infos[0]
            self.buttonBox.button(
                QDialogButtonBox.StandardButton.Ok).setToolTip("")  # 去除新建文件夹影响
            self.buttonBox.button(
                QDialogButtonBox.StandardButton.Ok).setEnabled(
                    True)  # 去除新建文件夹影响
            self.setWindowTitle("修改文件夹名与描述")
            self.tx_name.setText(str(infos.name))
            if infos.desc:
                self.tx_desc.setText(str(infos.desc))
                self.tx_desc.setToolTip('原描述:' + str(infos.desc))
            else:
                self.tx_desc.setText("")
                self.tx_desc.setToolTip('')
            self.tx_desc.setPlaceholderText("无")
            self.min_width = len(str(infos.name)) * 8
            if infos.is_file:
                self.setWindowTitle("修改文件描述")
                self.tx_name.setFocusPolicy(Qt.FocusPolicy.NoFocus)
                self.tx_name.setReadOnly(True)
            else:
                self.tx_name.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
                self.tx_name.setReadOnly(False)
                self.tx_name.setFocus()
        elif num > 1:
            self.lb_name.setVisible(False)
            self.tx_name.setVisible(False)
            self.setWindowTitle(f"批量修改{num}个文件(夹)的描述")
            self.tx_desc.setText('')
            self.tx_desc.setPlaceholderText("建议160字数以内。")

        else:
            self.setWindowTitle("新建文件夹")
            self.tx_name.setText("")
            self.buttonBox.button(
                QDialogButtonBox.StandardButton.Ok).setEnabled(False)
            self.buttonBox.button(
                QDialogButtonBox.StandardButton.Ok).setToolTip("请先输入文件名!")
            self.tx_name.textChanged.connect(self.slot_new_ok_btn)
            self.tx_name.setPlaceholderText("不支持空格,如有会被自动替换成 _")
            self.tx_name.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
            self.tx_name.setReadOnly(False)
            self.tx_desc.setPlaceholderText("可选项,建议160字数以内。")
            self.tx_name.setFocus()
        if self.min_width < 400:
            self.min_width = 400
        self.resize(self.min_width, 200)

    def slot_new_ok_btn(self):
        """新建文件夹槽函数"""
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Ok).setEnabled(True)
        self.buttonBox.button(
            QDialogButtonBox.StandardButton.Ok).setToolTip("")

    def btn_ok(self):
        new_name = self.tx_name.text()
        new_des = self.tx_desc.toPlainText()
        info_len = len(self.infos)
        if info_len == 0:  # 在 work_id 新建文件夹
            if new_name:
                self.out.emit(("new", new_name, new_des))
        elif info_len == 1:
            if new_name != self.infos[0].name or new_des != self.infos[0].desc:
                self.infos[0].new_des = new_des
                self.infos[0].new_name = new_name
                self.out.emit(("change", self.infos))
        else:
            if new_des:
                for infos in self.infos:
                    infos.new_des = new_des
                self.out.emit(("change", self.infos))
class Ui_TrainPanel(object):
    def setupUi(self, TrainPanel):
        self.parent = TrainPanel
        self.mainLayout = QHBoxLayout(TrainPanel)

        self.bigFont = QLabel().font()
        self.bigFont.setPointSize(13)

        self.actionsLayout = QHBoxLayout(TrainPanel)
        # self.checkRecording = QCheckBox(TrainPanel)
        self.calibrateButton = QPushButton("Calibrate", parent=TrainPanel)
        self.calibrateButton.setFont(self.bigFont)
        self.calibrateButton.setStyleSheet(CustomQStyles.buttonStyle)
        self.calibrateButton.setMinimumHeight(50)
        self.calibrateButton.setMaximumWidth(170)
        self.calibrateButton.setMinimumWidth(120)

        self.sessionButton = QPushButton("Session", parent=TrainPanel)
        self.sessionButton.setFont(self.bigFont)
        self.sessionButton.setStyleSheet(CustomQStyles.outlineButtonStyle)
        self.sessionButton.setMinimumHeight(50)
        self.sessionButton.setMaximumWidth(170)
        self.sessionButton.setMinimumWidth(120)

        self.listFiles = QListWidget(TrainPanel)
        self.listFiles.setFont(self.bigFont)
        self.label = QLabel('or select', parent=TrainPanel)
        self.subjectLayout = QVBoxLayout(TrainPanel)
        print("init")

        self.box1 = QGroupBox(parent=TrainPanel)
        self.box2 = QGroupBox(parent=TrainPanel)
        self.wizard = CalibrateWizard(parent=TrainPanel)

        self.setPatientsBox(TrainPanel)  # right panel
        self.setActionsBox(TrainPanel)  # left panel

        self.mainLayout.addWidget(self.box1, stretch=2)
        self.mainLayout.addWidget(self.box2, stretch=3)
        # self.mainLayout.setAlignment(self.box2, Qt.Alignment.AlignCenter)

    # Display progress bar, checkbox - to record new gestures or not, start train
    def setActionsBox(self, TrainPanel):
        hLayout = QVBoxLayout()
        hLayout.addWidget(self.calibrateButton)
        hLayout.addWidget(self.sessionButton)
        hLayout.setAlignment(self.calibrateButton, Qt.Alignment.AlignCenter)
        hLayout.setAlignment(self.sessionButton, Qt.Alignment.AlignCenter)
        self.box2.setLayout(hLayout)

    # Display list of subjects, or new subject
    def setPatientsBox(self, TrainPanel):

        # Button to create new patient
        self.addPatient = QPushButton('Create Patient')
        self.addPatient.setFixedSize(120, 35)
        self.addPatient.setStyleSheet(CustomQStyles.outlineButtonStyle)

        self.label.setSizePolicy(QSizePolicy.Policy.Expanding,
                                 QSizePolicy.Policy.Expanding)
        self.label.setAlignment(QtCore.Qt.Alignment.AlignCenter)

        self.loadPatientList()

        self.listFiles.setStyleSheet(CustomQStyles.listStyle)
        self.listFiles.setFocusPolicy(Qt.FocusPolicy.NoFocus)

        self.subjectLayout.addWidget(self.addPatient)
        self.subjectLayout.setAlignment(self.addPatient,
                                        Qt.Alignment.AlignCenter)
        self.subjectLayout.addWidget(self.label)
        self.subjectLayout.addWidget(self.listFiles)

        self.box1.setLayout(self.subjectLayout)

    def loadPatientList(self):
        self.listFiles.clear()
        self.parent.patients.clear()
        files = [
            f for f in listdir(PATIENTS_PATH) if isfile(join(PATIENTS_PATH, f))
        ]
        for x, ind in zip(files, range(0, len(files))):
            item = QListWidgetItem(x.split('.')[0])
            item.setTextAlignment(Qt.Alignment.AlignHCenter)
            self.listFiles.addItem(item)
            with open(PATIENTS_PATH + x, 'r') as f:
                person_dict = json.load(f)
                patient = Patient(person_dict['Name'], person_dict['Age'],
                                  person_dict['Exercises'])
                self.parent.patients.append(patient)

        print(self.parent.patients)

    def deleteItemsOfLayout(self, layout):
        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.setParent(None)
                else:
                    self.deleteItemsOfLayout(item.layout())
Beispiel #22
0
class UIComicListWidget(QWidget):
    def __init__(self, comic_info: ComicInfo, tab_widget: QTabWidget, down_v_box_layout: QVBoxLayout):
        super().__init__()
        self.tabWidget = tab_widget
        self.comicInfo = comic_info
        self.down_v_box_layout = down_v_box_layout
        self.setMinimumHeight(200)
        # 图片
        img = QImage.fromData(comic_info.cover)
        self.img_label = QLabel(self)
        self.img_label.setScaledContents(True)
        w, h = image_resize(comic_info.cover, height=200)
        self.img_label.resize(QtCore.QSize(w, h))
        self.img_label.setGeometry(5, 5, w, h)
        self.img_label.setPixmap(QPixmap.fromImage(img))
        # self.img_label.setPixmap(QtGui.QPixmap("/Users/bo/my/tmp/老夫子2/第1卷/1.jpg"))
        # 标题
        self.title = ButtonQLabel(self)
        self.title.onclick(self.add_tab)
        self.title.setText(comic_info.title)
        self.title.setGeometry(180, 10, 550, 35)
        title_font = QtGui.QFont()
        title_font.setPointSize(30)
        title_font.setBold(True)
        title_font.setUnderline(True)
        self.title.setFont(title_font)
        self.title.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor))

        # 作者
        self.author = QLabel(self)
        self.author.setText("作者 : " + comic_info.author)
        self.author.setGeometry(180, 50, 250, 20)
        # 状态
        self.status = QLabel(self)
        self.status.setText("更新状态 : " + comic_info.status)
        self.status.setGeometry(500, 50, 150, 20)
        # 热度
        self.status = QLabel(self)
        self.status.setText("热度 : " + str(comic_info.heat))
        self.status.setGeometry(800, 50, 100, 20)

        # 类型
        self.tip = QLabel(self)
        self.tip.setText("类型 : " + comic_info.tip)
        self.tip.setGeometry(180, 70, 250, 20)

        # web
        self.domain = QLabel(self)
        self.domain.setText(f"查看原网页 : {comic_info.domain}")
        self.domain.setText(f'查看原网页 : <a href="{comic_info.url}">{comic_info.domain}</a>')
        self.domain.setGeometry(500, 70, 250, 20)
        self.domain.setOpenExternalLinks(True)

        # 描述
        self.describe = QLabel(self)
        self.describe.setText("  " + comic_info.describe)
        self.describe.setGeometry(180, 90, 664, 110)
        self.describe.setWordWrap(True)
        # 对齐方式
        self.describe.setAlignment(
            QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignTop)

    def add_tab(self):
        if self.comicInfo.url in constant.OPEN_TAB:
            self.tabWidget.setCurrentIndex(constant.OPEN_TAB.index(self.comicInfo.url) + 3)
        else:
            info = UIComicInfoWidget(self.comicInfo, self.down_v_box_layout)
            self.tabWidget.setCurrentIndex(self.tabWidget.addTab(info, self.comicInfo.title))
            constant.OPEN_TAB.append(self.comicInfo.url)
Beispiel #23
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)
Beispiel #24
0
    def initUI(self):
        self.setWindowTitle("设置")
        logo = QLabel()
        logo.setPixmap(QPixmap(SRC_DIR + "logo2.gif"))
        logo.setStyleSheet("background-color:rgb(255,255,255);")
        logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.download_threads_lb = QLabel("同时下载文件数")
        self.download_threads_var = QLineEdit()
        self.download_threads_var.setPlaceholderText("范围:1-9")
        self.download_threads_var.setToolTip("范围:1-9")
        self.download_threads_var.setInputMask("D")
        self.max_size_lb = QLabel("分卷大小(MB)")
        self.max_size_var = QLineEdit()
        self.max_size_var.setPlaceholderText("普通用户最大100,vip用户根据具体情况设置")
        self.max_size_var.setToolTip("普通用户最大100,vip用户根据具体情况设置")
        self.max_size_var.setInputMask("D99")
        self.timeout_lb = QLabel("请求超时(秒)")
        self.timeout_var = QLineEdit()
        self.timeout_var.setPlaceholderText("范围:1-99")
        self.timeout_var.setToolTip("范围:1-99")
        self.timeout_var.setInputMask("D9")
        self.upload_delay_lb = QLabel("上传延时(秒)")
        self.upload_delay_var = QLineEdit()
        self.upload_delay_var.setPlaceholderText("范围:1-99")
        self.upload_delay_var.setToolTip("范围:1-99")
        self.upload_delay_var.setInputMask("D9")
        self.dl_path_lb = QLabel("下载保存路径")
        self.dl_path_var = MyLineEdit(self)
        self.dl_path_var.clicked.connect(self.set_download_path)
        self.time_fmt_box = QCheckBox("使用[年-月-日]时间格式")
        self.time_fmt_box.setToolTip("文件上传日期显示格式")
        self.to_tray_box = QCheckBox("关闭到系统托盘")
        self.to_tray_box.setToolTip("点击关闭软件按钮是最小化软件至系统托盘")
        self.watch_clipboard_box = QCheckBox("监听系统剪切板")
        self.watch_clipboard_box.setToolTip("检测到系统剪切板中有符合规范的蓝奏链接时自动唤起软件,并提取")
        self.debug_box = QCheckBox("开启调试日志")
        self.debug_box.setToolTip("记录软件 debug 信息至 debug-lanzou-gui.log 文件")
        self.set_pwd_box = QCheckBox("上传文件自动设置密码")
        self.set_pwd_var = AutoResizingTextEdit()
        self.set_pwd_var.setPlaceholderText(" 2-8 位数字或字母")
        self.set_pwd_var.setToolTip("2-8 位数字或字母")
        self.set_desc_box = QCheckBox("上传文件自动设置描述")
        self.set_desc_var = AutoResizingTextEdit()
        self.big_file_box = QCheckBox(f"允许上传超过 {self.max_size}MB 的大文件")
        self.big_file_box.setToolTip("开启大文件上传支持 (功能下线)")
        self.upgrade_box = QCheckBox("自动检测新版本")
        self.upgrade_box.setToolTip("在软件打开时自动检测是否有新的版本发布,如有则弹出更新信息")

        self.time_fmt_box.toggle()
        self.time_fmt_box.stateChanged.connect(self.change_time_fmt)
        self.to_tray_box.stateChanged.connect(self.change_to_tray)
        self.watch_clipboard_box.stateChanged.connect(self.change_watch_clipboard)
        self.debug_box.stateChanged.connect(self.change_debug)
        self.set_pwd_box.stateChanged.connect(self.change_set_pwd)
        self.set_pwd_var.editingFinished.connect(self.check_pwd)
        self.set_desc_box.stateChanged.connect(self.change_set_desc)
        self.big_file_box.stateChanged.connect(self.change_big_file)
        self.upgrade_box.stateChanged.connect(self.change_upgrade)

        buttonBox = QDialogButtonBox()
        buttonBox.setOrientation(Qt.Orientation.Horizontal)
        buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Reset | QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel)
        buttonBox.button(QDialogButtonBox.StandardButton.Reset).setText("重置")
        buttonBox.button(QDialogButtonBox.StandardButton.Save).setText("保存")
        buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText("取消")
        buttonBox.button(QDialogButtonBox.StandardButton.Reset).clicked.connect(lambda: self.set_values(reset=True))
        buttonBox.button(QDialogButtonBox.StandardButton.Save).clicked.connect(self.slot_save)
        buttonBox.rejected.connect(self.reject)

        form = QFormLayout()
        form.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
        form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)  # 覆盖MacOS的默认样式
        form.setSpacing(10)
        form.addRow(self.download_threads_lb, self.download_threads_var)
        form.addRow(self.timeout_lb, self.timeout_var)
        form.addRow(self.upload_delay_lb, self.upload_delay_var)
        form.addRow(self.max_size_lb, self.max_size_var)
        form.addRow(self.dl_path_lb, self.dl_path_var)

        vbox = QVBoxLayout()
        vbox.addWidget(logo)
        vbox.addStretch(1)
        vbox.addLayout(form)
        vbox.addStretch(1)
        hbox = QHBoxLayout()
        hbox.addWidget(self.time_fmt_box)
        hbox.addWidget(self.to_tray_box)
        hbox.addWidget(self.watch_clipboard_box)
        hbox.addWidget(self.debug_box)
        vbox.addLayout(hbox)
        vbox.addStretch(1)
        hbox_2 = QHBoxLayout()
        hbox_2.addWidget(self.set_pwd_box)
        hbox_2.addWidget(self.set_pwd_var)
        vbox.addLayout(hbox_2)
        vbox.addStretch(1)
        hbox_3 = QHBoxLayout()
        hbox_3.addWidget(self.set_desc_box)
        hbox_3.addWidget(self.set_desc_var)
        vbox.addLayout(hbox_3)
        hbox_4 = QHBoxLayout()
        hbox_4.addWidget(self.big_file_box)
        hbox_4.addWidget(self.upgrade_box)
        vbox.addStretch(1)
        vbox.addLayout(hbox_4)
        vbox.addStretch(2)
        vbox.addWidget(buttonBox)
        self.setLayout(vbox)
        self.setMinimumWidth(500)
Beispiel #25
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))
Beispiel #26
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setFixedSize(800, 410)
        self.setWindowTitle("PyLX16A Servo Testing Software")

        self.port_selection_box = QComboBox(self)
        self.port_selection_box.setFixedSize(200, 27)
        self.port_selection_box.move(30, 65)
        port_selection_box_label = QLabel("Select Port:", self)
        port_selection_box_label.move(30, 35)

        self.port_selection_box_refresh_button = QPushButton("Refresh", self)
        self.port_selection_box_refresh_button.setFixedSize(60, 23)
        self.port_selection_box_refresh_button.move(170, 38)

        self.id_selection_box = QListWidget(self)
        self.id_selection_box.setFixedSize(200, 200)
        self.id_selection_box.move(30, 135)
        id_selection_box_label = QLabel("Connected Servos:", self)
        id_selection_box_label.setFixedWidth(200)
        id_selection_box_label.move(30, 105)

        self.id_selection_box_refresh_button = QPushButton("Refresh", self)
        self.id_selection_box_refresh_button.setFixedSize(60, 23)
        self.id_selection_box_refresh_button.move(170, 108)

        self.set_id_line_edit = QLineEdit(self)
        self.set_id_line_edit.setFixedSize(50, 27)
        self.set_id_line_edit.move(80, 355)
        set_id_line_edit_label = QLabel("Set ID:", self)
        set_id_line_edit_label.move(30, 355)
        set_id_line_edit_label.setFixedSize(50, 27)

        self.set_id_button = QPushButton("Change ID!", self)
        self.set_id_button.setFixedSize(85, 27)
        self.set_id_button.move(145, 355)

        self.position_slider = QSlider(Qt.Orientation.Horizontal, self)
        self.position_slider.setMinimum(0)
        self.position_slider.setMaximum(240)
        self.position_slider.setFixedWidth(200)
        self.position_slider.move(300, 55)
        self.position_slider_readout = QLabel("0.00°", self)
        self.position_slider_readout.setFixedWidth(50)
        self.position_slider_readout.move(450, 30)
        self.position_slider_readout.setAlignment(
            Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        position_slider_label = QLabel("Angle (degrees):", self)
        position_slider_label.move(300, 30)

        self.position_offset_slider = QSlider(Qt.Orientation.Horizontal, self)
        self.position_offset_slider.setMinimum(-30)
        self.position_offset_slider.setMaximum(30)
        self.position_offset_slider.setFixedWidth(200)
        self.position_offset_slider.move(300, 125)
        self.position_offset_slider_readout = QLabel("0.00°", self)
        self.position_offset_slider_readout.setFixedWidth(50)
        self.position_offset_slider_readout.move(450, 100)
        self.position_offset_slider_readout.setAlignment(
            Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        position_offset_slider_label = QLabel("Angle offset (degrees):", self)
        position_offset_slider_label.setFixedWidth(200)
        position_offset_slider_label.move(300, 100)

        self.angle_lower_limit_textentry = QLineEdit(self)
        self.angle_lower_limit_textentry.setFixedWidth(50)
        self.angle_lower_limit_textentry.move(450, 175)
        self.angle_lower_limit_textentry.setValidator(
            QIntValidator(0, 240, self))
        self.angle_upper_limit_textentry = QLineEdit(self)
        self.angle_upper_limit_textentry.setFixedWidth(50)
        self.angle_upper_limit_textentry.move(450, 210)
        self.angle_upper_limit_textentry.setValidator(
            QIntValidator(0, 240, self))
        self.angle_lower_limit_textentry_label = QLabel(
            "Lower Limit (degrees):", self)
        self.angle_lower_limit_textentry_label.move(300, 175)
        self.angle_lower_limit_textentry_label.setFixedWidth(150)
        self.angle_upper_limit_textentry_label = QLabel(
            "Upper Limit (degrees):", self)
        self.angle_upper_limit_textentry_label.move(300, 210)
        self.angle_upper_limit_textentry_label.setFixedWidth(150)

        self.vin_lower_limit_textentry = QLineEdit(self)
        self.vin_lower_limit_textentry.setFixedWidth(50)
        self.vin_lower_limit_textentry.move(450, 265)
        self.vin_lower_limit_textentry.setValidator(
            QIntValidator(4500, 12000, self))
        self.vin_upper_limit_textentry = QLineEdit(self)
        self.vin_upper_limit_textentry.setFixedWidth(50)
        self.vin_upper_limit_textentry.move(450, 300)
        self.vin_upper_limit_textentry.setValidator(
            QIntValidator(4500, 12000, self))
        self.vin_lower_limit_textentry_label = QLabel(
            "Voltage Lower Limit (mV):", self)
        self.vin_lower_limit_textentry_label.move(300, 265)
        self.vin_lower_limit_textentry_label.setFixedWidth(150)
        self.vin_upper_limit_textentry_label = QLabel(
            "Voltage Upper Limit (mV):", self)
        self.vin_upper_limit_textentry_label.move(300, 300)
        self.vin_upper_limit_textentry_label.setFixedWidth(150)

        self.temp_limit_textentry = QLineEdit(self)
        self.temp_limit_textentry.setFixedWidth(50)
        self.temp_limit_textentry.move(450, 355)
        self.temp_limit_textentry.setValidator(QIntValidator(50, 100, self))
        self.temp_limit_textentry_label = QLabel("Temp Limit (°C):", self)
        self.temp_limit_textentry_label.move(300, 355)
        self.temp_limit_textentry_label.setFixedWidth(150)

        self.servo_mode_radio_button = QRadioButton("Servo Mode", self)
        self.servo_mode_radio_button.move(565, 50)
        self.motor_mode_radio_button = QRadioButton("Motor Mode", self)
        self.motor_mode_radio_button.move(565, 75)

        self.motor_speed_slider = QSlider(Qt.Orientation.Horizontal, self)
        self.motor_speed_slider.setMinimum(-1000)
        self.motor_speed_slider.setMaximum(1000)
        self.motor_speed_slider.setFixedWidth(200)
        self.motor_speed_slider.move(565, 125)
        motor_speed_slider_label = QLabel("Motor Speed:", self)
        motor_speed_slider_label.move(565, 100)

        self.torque_enabled_checkbox = QCheckBox("Torque Enabled", self)
        self.torque_enabled_checkbox.move(565, 175)
        self.torque_enabled_checkbox.setFixedWidth(200)

        self.led_enabled_checkbox = QCheckBox("LED Enabled", self)
        self.led_enabled_checkbox.move(565, 210)
        self.led_enabled_checkbox.setFixedWidth(200)

        self.led_over_temp_checkbox = QCheckBox("LED Over Temperature", self)
        self.led_over_temp_checkbox.move(565, 258)
        self.led_over_temp_checkbox.setFixedWidth(200)
        self.led_over_voltage_checkbox = QCheckBox("LED Over Voltage", self)
        self.led_over_voltage_checkbox.move(565, 283)
        self.led_over_voltage_checkbox.setFixedWidth(200)
        self.led_rotor_locked_checkbox = QCheckBox("LED Rotor Locked", self)
        self.led_rotor_locked_checkbox.move(565, 308)
        self.led_rotor_locked_checkbox.setFixedWidth(200)

        self.physical_position_readout = QLabel("--°", self)
        self.physical_position_readout.move(565, 367)
        self.physical_position_readout.setFixedWidth(200)
        self.physical_position_readout_label = QLabel("Position", self)
        self.physical_position_readout_label.move(565, 347)

        self.temperature_readout = QLabel("-- °C", self)
        self.temperature_readout.move(635, 367)
        self.temperature_readout.setFixedWidth(200)
        self.temperature_readout_label = QLabel("Temperature", self)
        self.temperature_readout_label.move(635, 347)

        self.voltage_readout = QLabel("-- V", self)
        self.voltage_readout.move(730, 367)
        self.voltage_readout.setFixedWidth(200)
        self.voltage_readout_label = QLabel("Voltage", self)
        self.voltage_readout_label.move(730, 347)

        self.readout_update_timer = QTimer(self)
        self.readout_update_timer.timeout.connect(self.update_readouts)
        self.readout_update_timer.start(250)

        self.active_servo: LX16A = None

        self.position_slider.setValue(0)
        self.position_offset_slider.setValue(0)
        self.motor_speed_slider.setValue(0)
        self.id_selection_box_refresh_button.setEnabled(False)
        self.disable_widgets()

        self.port_selection_box.currentTextChanged.connect(
            self.port_selection_box_changed)
        self.port_selection_box_refresh_button.clicked.connect(
            self.port_refresh_button_clicked)
        self.id_selection_box.currentTextChanged.connect(
            self.id_selection_box_changed)
        self.id_selection_box_refresh_button.clicked.connect(
            self.id_refresh_button_clicked)
        self.set_id_button.pressed.connect(self.id_updated)
        self.position_slider.sliderMoved.connect(self.position_slider_updated)
        self.position_offset_slider.sliderMoved.connect(
            self.position_offset_slider_updated)
        self.angle_lower_limit_textentry.textChanged.connect(
            self.angle_lower_limit_updated)
        self.angle_upper_limit_textentry.textChanged.connect(
            self.angle_upper_limit_updated)
        self.vin_lower_limit_textentry.textChanged.connect(
            self.vin_lower_limit_updated)
        self.vin_upper_limit_textentry.textChanged.connect(
            self.vin_upper_limit_updated)
        self.temp_limit_textentry.textChanged.connect(self.temp_limit_updated)
        self.servo_mode_radio_button.toggled.connect(
            self.servo_mode_radio_button_toggled)
        self.motor_mode_radio_button.toggled.connect(
            self.motor_mode_radio_button_toggled)
        self.motor_speed_slider.valueChanged.connect(
            self.motor_speed_slider_updated)
        self.torque_enabled_checkbox.stateChanged.connect(
            self.torque_enabled_checkbox_toggled)
        self.led_enabled_checkbox.stateChanged.connect(
            self.led_enabled_checkbox_toggled)
        self.led_over_temp_checkbox.stateChanged.connect(
            self.led_error_triggers_checkbox_toggled)
        self.led_over_voltage_checkbox.stateChanged.connect(
            self.led_error_triggers_checkbox_toggled)
        self.led_rotor_locked_checkbox.stateChanged.connect(
            self.led_error_triggers_checkbox_toggled)

        self.scan_for_ports()

    def disable_widgets(self):
        self.set_id_line_edit.setEnabled(False)
        self.position_slider.setEnabled(False)
        self.position_offset_slider.setEnabled(False)
        self.angle_lower_limit_textentry.setEnabled(False)
        self.angle_upper_limit_textentry.setEnabled(False)
        self.vin_lower_limit_textentry.setEnabled(False)
        self.vin_upper_limit_textentry.setEnabled(False)
        self.temp_limit_textentry.setEnabled(False)
        self.servo_mode_radio_button.setEnabled(False)
        self.motor_mode_radio_button.setEnabled(False)
        self.motor_speed_slider.setEnabled(False)
        self.torque_enabled_checkbox.setEnabled(False)
        self.led_enabled_checkbox.setEnabled(False)
        self.led_over_temp_checkbox.setEnabled(False)
        self.led_over_voltage_checkbox.setEnabled(False)
        self.led_rotor_locked_checkbox.setEnabled(False)

    def enable_widgets(self):
        self.set_id_line_edit.setEnabled(True)
        self.position_slider.setEnabled(True)
        self.position_offset_slider.setEnabled(True)
        self.angle_lower_limit_textentry.setEnabled(True)
        self.angle_upper_limit_textentry.setEnabled(True)
        self.vin_lower_limit_textentry.setEnabled(True)
        self.vin_upper_limit_textentry.setEnabled(True)
        self.temp_limit_textentry.setEnabled(True)
        self.servo_mode_radio_button.setEnabled(True)
        self.motor_mode_radio_button.setEnabled(True)
        self.motor_speed_slider.setEnabled(True)
        self.torque_enabled_checkbox.setEnabled(True)
        self.led_enabled_checkbox.setEnabled(True)
        self.led_over_temp_checkbox.setEnabled(True)
        self.led_over_voltage_checkbox.setEnabled(True)
        self.led_rotor_locked_checkbox.setEnabled(True)

    def clear_servo(self):
        self.active_servo = None

    @catch_disconnection
    def set_servo_id(self, id_):
        if not id_.isdigit():
            return

        self.active_servo = LX16A(int(id_))
        self.active_servo.enable_torque()

        self.position_slider.setValue(
            int(self.active_servo.get_physical_angle()))
        self.position_slider_readout.setText(
            f"{int(self.active_servo.get_physical_angle() * 25 / 6) * 6 / 25:0.2f}°"
        )
        self.position_offset_slider.setValue(
            int(self.active_servo.get_angle_offset()))
        self.position_offset_slider_readout.setText(
            f"{int(self.active_servo.get_angle_offset() * 25 / 6) * 6 / 25:0.2f}°"
        )
        self.angle_lower_limit_textentry.setText(
            str(int(self.active_servo.get_angle_limits()[0])))
        self.angle_upper_limit_textentry.setText(
            str(int(self.active_servo.get_angle_limits()[1])))
        self.vin_lower_limit_textentry.setText(
            str(self.active_servo.get_vin_limits()[0]))
        self.vin_upper_limit_textentry.setText(
            str(self.active_servo.get_vin_limits()[1]))
        self.temp_limit_textentry.setText(
            str(self.active_servo.get_temp_limit()))
        self.motor_speed_slider.setValue(self.active_servo.get_motor_speed(
        ) if self.active_servo.is_motor_mode() else 0)
        if self.active_servo.is_motor_mode():
            self.motor_mode_radio_button.setChecked(True)
        else:
            self.servo_mode_radio_button.setChecked(True)
        self.motor_speed_slider.setEnabled(self.active_servo.is_motor_mode())
        self.torque_enabled_checkbox.setChecked(
            self.active_servo.is_torque_enabled())
        self.led_enabled_checkbox.setChecked(
            self.active_servo.is_led_power_on())
        self.led_over_temp_checkbox.setChecked(
            self.active_servo.get_led_error_triggers()[0])
        self.led_over_voltage_checkbox.setChecked(
            self.active_servo.get_led_error_triggers()[1])
        self.led_rotor_locked_checkbox.setChecked(
            self.active_servo.get_led_error_triggers()[2])

    @catch_disconnection
    def scan_for_servos(self, port):
        self.setCursor(Qt.CursorShape.WaitCursor)

        LX16A.initialize(port)

        self.id_selection_box.clear()

        for i in range(0, 254):
            try:
                servo = LX16A(i)
                self.id_selection_box.addItem(str(i))
            except:
                pass

        self.setCursor(Qt.CursorShape.ArrowCursor)

    @catch_disconnection
    def scan_for_ports(self):
        ports = serial.tools.list_ports.comports()
        for port in ports:
            self.port_selection_box.addItem(port.device)

    @catch_disconnection
    def update_readouts(self):
        if self.active_servo is None:
            return

        try:
            self.physical_position_readout.setText(
                f"{self.active_servo.get_physical_angle():0.2f}°")
            self.temperature_readout.setText(
                f"{self.active_servo.get_temp()} °C")
            self.voltage_readout.setText(
                f"{self.active_servo.get_vin() / 1000} V")
        except (ServoTimeoutError, ServoChecksumError):
            pass

    @catch_disconnection
    def id_updated(self):
        new_id = self.set_id_line_edit.text()

        try:
            servo = LX16A(int(new_id))
        except ServoTimeoutError:
            # Meaning this ID is not taken
            self.active_servo.set_id(int(new_id))
            self.id_selection_box.item(
                self.id_selection_box.currentRow()).setText(new_id)

            return

        QMessageBox.warning(None, "Error", "ID already taken")

    @catch_disconnection
    def position_slider_updated(self, pos):
        if float(self.voltage_readout.text()[:-2]) < 5:
            QMessageBox.warning(
                None,
                "Error",
                "The voltage going through the servo is too low. Is your battery powered on?",
            )

            return
        self.active_servo.move(pos)
        self.position_slider_readout.setText(
            f"{int(pos * 25 / 6) * 6 / 25:0.2f}°")

    @catch_disconnection
    def position_offset_slider_updated(self, pos):
        self.active_servo.set_angle_offset(pos)
        self.position_offset_slider_readout.setText(
            f"{int(pos * 25 / 6) * 6 / 25:0.2f}°")

    @catch_disconnection
    def angle_lower_limit_updated(self, text):
        if (QIntValidator(0, 240, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) > int(self.angle_upper_limit_textentry.text()):
            return

        self.active_servo.set_angle_limits(
            int(text), int(self.angle_upper_limit_textentry.text()))

    @catch_disconnection
    def angle_upper_limit_updated(self, text):
        if (QIntValidator(0, 240, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) < int(self.angle_lower_limit_textentry.text()):
            return

        self.active_servo.set_angle_limits(
            int(self.angle_lower_limit_textentry.text()), int(text))

    @catch_disconnection
    def vin_lower_limit_updated(self, text):
        if (QIntValidator(4500, 12000, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) > int(self.vin_upper_limit_textentry.text()):
            return

        self.active_servo.set_vin_limits(
            int(text), int(self.vin_upper_limit_textentry.text()))

    @catch_disconnection
    def vin_upper_limit_updated(self, text):
        if (QIntValidator(4500, 12000, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        if int(text) < int(self.vin_lower_limit_textentry.text()):
            return

        self.active_servo.set_vin_limits(
            int(self.vin_lower_limit_textentry.text()), int(text))

    @catch_disconnection
    def temp_limit_updated(self, text):
        if (QIntValidator(50, 100, self).validate(text, 0) !=
                QIntValidator.State.Acceptable):
            return

        self.active_servo.set_temp_limit(int(text))

    @catch_disconnection
    def servo_mode_radio_button_toggled(self, checked):
        if checked:
            self.active_servo.servo_mode()
            self.motor_speed_slider.setEnabled(False)
            self.position_slider.setEnabled(True)
            self.position_offset_slider.setEnabled(True)
        else:
            self.active_servo.motor_mode(int(self.motor_speed_slider.value()))
            self.motor_speed_slider.setEnabled(True)
            self.position_slider.setEnabled(False)
            self.position_offset_slider.setEnabled(False)

    @catch_disconnection
    def motor_mode_radio_button_toggled(self, checked):
        if checked:
            self.active_servo.motor_mode(int(self.motor_speed_slider.value()))
            self.motor_speed_slider.setEnabled(True)
            self.position_slider.setEnabled(False)
            self.position_offset_slider.setEnabled(False)
        else:
            self.active_servo.servo_mode()
            self.motor_speed_slider.setEnabled(False)
            self.position_slider.setEnabled(True)
            self.position_offset_slider.setEnabled(True)

    @catch_disconnection
    def motor_speed_slider_updated(self, pos):
        self.active_servo.motor_mode(pos)

    @catch_disconnection
    def torque_enabled_checkbox_toggled(self, checked):
        if checked:
            self.active_servo.enable_torque()
        else:
            self.active_servo.disable_torque()

        self.position_slider.setEnabled(checked)
        self.position_offset_slider.setEnabled(checked)
        self.servo_mode_radio_button.setEnabled(checked)
        self.motor_mode_radio_button.setEnabled(checked)
        self.motor_speed_slider.setEnabled(checked)

    @catch_disconnection
    def led_enabled_checkbox_toggled(self, checked):
        if checked:
            self.active_servo.led_power_on()
        else:
            self.active_servo.led_power_off()

    @catch_disconnection
    def led_error_triggers_checkbox_toggled(self):
        self.active_servo.set_led_error_triggers(
            self.led_over_voltage_checkbox.isChecked(),
            self.led_over_temp_checkbox.isChecked(),
            self.led_rotor_locked_checkbox.isChecked(),
        )

    @catch_disconnection
    def port_refresh_button_clicked(self, value):
        self.id_selection_box_refresh_button.setEnabled(False)
        self.disable_widgets()
        self.port_selection_box.clear()
        self.id_selection_box.clear()
        self.scan_for_ports()

    @catch_disconnection
    def id_refresh_button_clicked(self, value):
        self.disable_widgets()
        self.id_selection_box.clear()
        self.scan_for_servos(self.port_selection_box.currentText())

    @catch_disconnection
    def port_selection_box_changed(self, text):
        if text == "":
            return

        self.id_selection_box_refresh_button.setEnabled(True)
        self.disable_widgets()
        self.id_selection_box.clear()
        self.clear_servo()
        self.scan_for_servos(text)

    @catch_disconnection
    def id_selection_box_changed(self, text):
        if text == "":
            return

        self.enable_widgets()
        self.set_servo_id(text)
Beispiel #27
0
class MainWindow(QMainWindow):
    def __init__(self, admin_or_not=None):
        """ MainWindow Constructor """
        super().__init__()
        self.admin_or_not = admin_or_not  # Used to grant the user admin privileges
        self.curr_proxy_model = None  # Variable that refers to the current page's proxy mmodel
        self.initializeUI()

    def initializeUI(self):
        """Set up the GUI's main window."""
        self.setWindowTitle("Database Manager")
        self.setMinimumSize(800, 400)
        self.setUpMainWindow()

    def setUpMainWindow(self):
        """Create and arrange widgets in the main window."""
        # Create the container widget for each of the pages
        # in the tab widget
        self.customer_tab = QWidget()
        self.orders_tab = QWidget()
        self.category_tab = QWidget()
        self.products_tab = QWidget()

        # Add or insert the tabs into the tab widget
        self.tabs = QTabWidget()
        self.tabs.setDocumentMode(True)
        self.tabs.addTab(self.customer_tab, "Customers")
        self.tabs.addTab(self.orders_tab, "Orders")
        self.tabs.addTab(self.category_tab, "Categories")
        self.tabs.addTab(self.products_tab, "Products")
        if self.admin_or_not == 1:
            self.staff_tab = QWidget()
            self.tabs.insertTab(0, self.staff_tab, "Staff")
            self.createStaffTab()
            self.tabs.setCurrentIndex(1)  # Set tab to Customers tab
        self.tabs.currentChanged.connect(self.updateWidgetsAndStates)

        # Call the methods to construct each page
        self.createCustomersTab()
        self.createOrdersTab()
        self.createCategoriesTab()
        self.createProductsTab()

        # Create the widgets in the sidebar for filtering table content
        self.table_name_label = QLabel("<b>Customers</b>")
        self.table_name_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.filter_pattern_line = QLineEdit()
        self.filter_pattern_line.setClearButtonEnabled(True)
        self.filter_pattern_line.textChanged.connect(self.filterRegExpChanged)

        self.filter_regex_combo = QComboBox()
        filter_options = ["Default", "Wildcard", "Fixed String"]
        self.filter_regex_combo.addItems(filter_options)
        self.filter_regex_combo.currentIndexChanged.connect(
            self.filterRegExpChanged)

        self.filter_field_combo = QComboBox()
        self.updateWidgetsAndStates(
            1)  # Initialize the values in filter_field_combo
        self.filter_field_combo.currentIndexChanged.connect(
            self.selectTableColumn)

        filter_case_sensitivity_cb = QCheckBox("Filter with Case Sensitivity")
        filter_case_sensitivity_cb.toggled.connect(self.toggleCaseSensitivity)
        filter_case_sensitivity_cb.toggle()

        # Layout for the sidebar
        filter_v_box = QVBoxLayout()
        filter_v_box.addWidget(self.table_name_label)
        filter_v_box.addWidget(QLabel("Filter Pattern"))
        filter_v_box.addWidget(self.filter_pattern_line)
        filter_v_box.addWidget(QLabel("Filter filter"))
        filter_v_box.addWidget(self.filter_regex_combo)
        filter_v_box.addWidget(QLabel("Select Table Column"))
        filter_v_box.addWidget(self.filter_field_combo)
        filter_v_box.addWidget(filter_case_sensitivity_cb)
        filter_v_box.addStretch(2)

        self.filter_group = QGroupBox("Filtering")
        self.filter_group.setMaximumWidth(260)
        self.filter_group.setLayout(filter_v_box)

        # Arrange the containers in the main window
        main_h_box = QHBoxLayout()
        main_h_box.addWidget(self.tabs)
        main_h_box.addWidget(self.filter_group)

        main_container = QWidget()
        main_container.setLayout(main_h_box)
        self.setCentralWidget(main_container)

        # Create status bar
        self.setStatusBar(QStatusBar())

    def createStaffTab(self):
        """Create the page to view the Staff table from the database."""
        staff_sql_model = QSqlRelationalTableModel()
        staff_sql_model.setTable("Staff")
        staff_sql_model.select()  # Populate the model with data

        staff_proxy_model = QSortFilterProxyModel()
        staff_proxy_model.setSourceModel(staff_sql_model)

        staff_table = QTableView()
        staff_table.setSortingEnabled(True)
        staff_table.setModel(staff_proxy_model)
        staff_table.setItemDelegateForColumn(
            staff_sql_model.fieldIndex("staff_id"), ReadOnlyDelegate())
        staff_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeMode.Stretch)

        staff_h_box = QHBoxLayout()
        staff_h_box.addWidget(staff_table)
        self.staff_tab.setLayout(staff_h_box)

    def createCustomersTab(self):
        """Create the page to view the Customers table from the database."""
        cust_sql_model = QSqlRelationalTableModel()
        cust_sql_model.setTable("Customers")
        cust_sql_model.setRelation(
            cust_sql_model.fieldIndex("staff_id"),
            QSqlRelation("Staff", "staff_id", "username"))
        cust_sql_model.setHeaderData(cust_sql_model.fieldIndex("staff_id"),
                                     Qt.Orientation.Horizontal,
                                     "staff_username")
        cust_sql_model.select()  # Populate the model with data

        cust_proxy_model = QSortFilterProxyModel()
        cust_proxy_model.setSourceModel(cust_sql_model)

        cust_table = QTableView()
        cust_table.setSortingEnabled(True)
        cust_table.setModel(cust_proxy_model)
        cust_table.setItemDelegate(SqlProxyDelegate(cust_table))
        cust_table.setItemDelegateForColumn(cust_sql_model.fieldIndex("phone"),
                                            PhoneDelegate())
        cust_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeMode.Stretch)

        cust_h_box = QHBoxLayout()
        cust_h_box.addWidget(cust_table)
        self.customer_tab.setLayout(cust_h_box)

    def createOrdersTab(self):
        """Create the page to view the Orders table from the database."""
        ord_sql_model = QSqlRelationalTableModel()
        ord_sql_model.setTable("Orders")
        ord_sql_model.setRelation(
            ord_sql_model.fieldIndex("product_id"),
            QSqlRelation("Products", "product_id", "product_name"))
        ord_sql_model.setRelation(
            ord_sql_model.fieldIndex("customer_id"),
            QSqlRelation("Customers", "customer_id", "first_name"))
        ord_sql_model.setHeaderData(ord_sql_model.fieldIndex("customer_id"),
                                    Qt.Orientation.Horizontal, "customer_name")
        ord_sql_model.select()  # Populate the model with data

        ord_proxy_model = QSortFilterProxyModel()
        ord_proxy_model.setSourceModel(ord_sql_model)

        ord_table = QTableView()
        ord_table.setSortingEnabled(True)
        ord_table.setModel(ord_proxy_model)
        ord_table.setItemDelegate(SqlProxyDelegate(ord_table))
        ord_table.setItemDelegateForColumn(
            ord_sql_model.fieldIndex("date_of_order"), DateDelegate())
        ord_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeMode.Stretch)

        ord_h_box = QHBoxLayout()
        ord_h_box.addWidget(ord_table)
        self.orders_tab.setLayout(ord_h_box)

    def createCategoriesTab(self):
        """Create the page to view the Categories table from the database."""
        cat_sql_model = QSqlRelationalTableModel()
        cat_sql_model.setTable("Categories")
        cat_sql_model.select()  # Populate the model with data

        cat_proxy_model = QSortFilterProxyModel()
        cat_proxy_model.setSourceModel(cat_sql_model)

        cat_table = QTableView()
        cat_table.setSortingEnabled(True)
        cat_table.setModel(cat_proxy_model)
        cat_table.setItemDelegateForColumn(
            cat_sql_model.fieldIndex("category_id"), ReadOnlyDelegate())
        cat_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeMode.Stretch)

        cat_h_box = QHBoxLayout()
        cat_h_box.addWidget(cat_table)
        self.category_tab.setLayout(cat_h_box)

    def createProductsTab(self):
        """Create the page to view the Products table from the database."""
        prod_sql_model = QSqlRelationalTableModel()
        prod_sql_model.setTable("Products")
        prod_sql_model.setRelation(
            prod_sql_model.fieldIndex("category_id"),
            QSqlRelation("Categories", "category_id", "category_name"))
        prod_sql_model.select()  # Populate the model with data

        prod_proxy_model = QSortFilterProxyModel()
        prod_proxy_model.setSourceModel(prod_sql_model)

        prod_table = QTableView()
        prod_table.setSortingEnabled(True)
        prod_table.setModel(prod_proxy_model)
        prod_table.setItemDelegate(SqlProxyDelegate(prod_table))
        prod_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeMode.Stretch)

        prod_h_box = QHBoxLayout()
        prod_h_box.addWidget(prod_table)
        self.products_tab.setLayout(prod_h_box)

    def filterRegExpChanged(self, value):
        """Slot for collecting the expression (pattern) for filtering
        items in the tables. Expressions are then passed to various
        QSortFilterProxyModel methods depending upon the value in 
        filter_regex_combo."""
        pattern = self.filter_pattern_line.text()
        filter = self.filter_regex_combo.currentText()
        model = self.curr_proxy_model

        if filter == "Wildcard":
            regex = QRegularExpression()
            pattern = regex.wildcardToRegularExpression(
                pattern,
                regex.WildcardConversionOption.UnanchoredWildcardConversion)
        elif filter == "Fixed String":
            pattern = QRegularExpression.escape(pattern)

        option = QRegularExpression.PatternOption.NoPatternOption
        regex = QRegularExpression(pattern, option)
        # Check whether or not the regular expression is valid or not
        if regex.isValid():
            model.setFilterRegularExpression(regex)
        else:
            # Display error message in the statusbar
            self.statusBar().showMessage(regex.errorString(), 4000)
            model.setFilterRegularExpression(QRegularExpression())

    def selectTableColumn(self, index):
        """Select the field (column) in the SQL table to be filtered."""
        self.curr_proxy_model.setFilterKeyColumn(index)

    def toggleCaseSensitivity(self, toggled):
        """Toggle whether items are filtered with or without case sensitivity."""
        if toggled:
            self.curr_proxy_model.setFilterCaseSensitivity(
                Qt.CaseSensitivity.CaseSensitive)
        else:
            self.curr_proxy_model.setFilterCaseSensitivity(
                Qt.CaseSensitivity.CaseInsensitive)

    def updateWidgetsAndStates(self, index):
        """Whenever the user switches a tab, update information regarding
        the tab selected, the current table's QSortFilterProxyModel, and information
        displayed in the sidebar for filtering."""
        self.filter_field_combo.clear()
        curr_table = self.tabs.currentWidget().findChild(QTableView)
        curr_model = curr_table.model().sourceModel()

        # Set text to display current table's name in the sidebar
        self.table_name_label.setText(f"<b>{curr_model.tableName()}</b>")
        self.curr_proxy_model = curr_table.model()

        # Update QComboBox values based on currently selected tab
        field_names = []
        for col in range(0, curr_model.columnCount()):
            field_names.append(curr_model.record().fieldName(col))
            if curr_model.tableName() == "Orders" and \
                "first_name" in field_names:
                field_names = [
                    "customer_name" if n == "first_name" else n
                    for n in field_names
                ]
        self.filter_field_combo.addItems(field_names)

        # NOTE: To the reader, the following code differs slightly from the book.
        # This portion is left here as reference should you need to use both
        # QSqlTableModel and QSqlRelationalTableModel classes. Simply replace the code
        # above with the code below.
        """
        if isinstance(curr_table.model(), QSqlRelationalTableModel):
            self.table_name_label.setText(f"<b>{curr_table.model().tableName()}</b>")

            # Update QComboBox values based on currently selected tab
            for col in range(0, curr_table.model().columnCount()):
                field_names.append(curr_table.model().record().fieldName(col))
            self.filter_field_combo.addItems(field_names)

        elif isinstance(curr_table.model(), QSortFilterProxyModel):
            self.table_name_label.setText(f"<b>{curr_model.tableName()}</b>")
            self.curr_proxy_model = curr_table.model()

            # Update QComboBox values based on currently selected tab
            for col in range(0, curr_model.columnCount()):
                field_names.append(curr_model.record().fieldName(col))
                if "first_name" in field_names:
                    field_names = ["customer_name" if i=="first_name" else i for i in field_names]
            self.filter_field_combo.addItems(field_names)
        """

    def closeEvent(self, event):
        """Close database connection when window is closed."""
        model = self.curr_proxy_model.sourceModel()
        model.database().close()
class MPPIOptionsWindow(QWidget):
    def __init__(self):
        super(MPPIOptionsWindow, self).__init__()

        self.horizon_steps = controller_mppi.mpc_samples
        self.num_rollouts = controller_mppi.num_rollouts
        self.dd_weight = controller_mppi.dd_weight
        self.ep_weight = controller_mppi.ep_weight
        self.ekp_weight = controller_mppi.ekp_weight * 1.0e1
        self.ekc_weight = controller_mppi.ekc_weight * 1.0e-1
        self.cc_weight = controller_mppi.cc_weight * 1.0e-2
        self.ccrc_weight = controller_mppi.ccrc_weight * 1.0e-2
        self.R = controller_mppi.R  # How much to punish Q
        self.LBD = controller_mppi.LBD  # Cost parameter lambda
        self.NU = controller_mppi.NU  # Exploration variance

        layout = QVBoxLayout()

        ### Set Horizon Length
        horizon_options_layout = QVBoxLayout()

        self.horizon_label = QLabel("")
        self.horizon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        horizon_options_layout.addWidget(self.horizon_label)

        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(10, 300)
        slider.setValue(self.horizon_steps)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(10)
        slider.setSingleStep(10)
        horizon_options_layout.addWidget(slider)

        slider.valueChanged.connect(self.horizon_length_changed)

        ### Set Number of Rollouts
        rollouts_options_layout = QVBoxLayout()

        self.rollouts_label = QLabel("")
        self.rollouts_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        rollouts_options_layout.addWidget(self.rollouts_label)

        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(10, 3000)
        slider.setValue(self.num_rollouts)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(10)
        slider.setSingleStep(10)
        rollouts_options_layout.addWidget(slider)

        slider.valueChanged.connect(self.num_rollouts_changed)

        ### Set Cost Weights
        cost_weight_layout = QVBoxLayout()

        # Distance difference cost
        self.dd_weight_label = QLabel("")
        self.dd_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.dd_weight_label)
        self.dd_label = QLabel("")
        self.dd_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.dd_label)
        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(0, 990)
        slider.setValue(self.dd_weight)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(10)
        slider.setSingleStep(10)
        cost_weight_layout.addWidget(slider)
        slider.valueChanged.connect(self.dd_weight_changed)

        # Potential energy cost
        self.ep_weight_label = QLabel("")
        self.ep_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ep_weight_label)
        self.ep_label = QLabel("")
        self.ep_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ep_label)
        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(0, 1e5 - 1e3)
        slider.setValue(self.ep_weight)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(1e3)
        slider.setSingleStep(1e3)
        cost_weight_layout.addWidget(slider)
        slider.valueChanged.connect(self.ep_weight_changed)

        # Pole kinetic energy cost
        self.ekp_weight_label = QLabel("")
        self.ekp_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ekp_weight_label)
        self.ekp_label = QLabel("")
        self.ekp_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ekp_label)
        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(0, 99)
        slider.setValue(self.ekp_weight)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(1)
        slider.setSingleStep(1)
        cost_weight_layout.addWidget(slider)
        slider.valueChanged.connect(self.ekp_weight_changed)

        # Cart kinetic energy cost
        self.ekc_weight_label = QLabel("")
        self.ekc_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ekc_weight_label)
        self.ekc_label = QLabel("")
        self.ekc_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ekc_label)
        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(0, 99)
        slider.setValue(self.ekc_weight)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(1)
        slider.setSingleStep(1)
        cost_weight_layout.addWidget(slider)
        slider.valueChanged.connect(self.ekc_weight_changed)

        # Control cost
        self.cc_weight_label = QLabel("")
        self.cc_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.cc_weight_label)
        self.cc_label = QLabel("")
        self.cc_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.cc_label)
        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(0, 99)
        slider.setValue(self.cc_weight)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(1)
        slider.setSingleStep(1)
        cost_weight_layout.addWidget(slider)
        slider.valueChanged.connect(self.cc_weight_changed)

        # Control change rate cost
        self.ccrc_weight_label = QLabel("")
        self.ccrc_weight_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ccrc_weight_label)
        self.ccrc_label = QLabel("")
        self.ccrc_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        cost_weight_layout.addWidget(self.ccrc_label)
        slider = QSlider(orientation=Qt.Orientation.Horizontal)
        slider.setRange(0, 99)
        slider.setValue(self.ccrc_weight)
        slider.setTickPosition(QSlider.TickPosition.TicksBelow)
        slider.setTickInterval(1)
        slider.setSingleStep(1)
        cost_weight_layout.addWidget(slider)
        slider.valueChanged.connect(self.ccrc_weight_changed)

        ### Set some more MPPI constants
        mppi_constants_layout = QVBoxLayout()

        # Quadratic cost penalty R
        textbox = QLineEdit()
        textbox.setText(str(self.R))
        textbox.textChanged.connect(self.R_changed)
        h_layout = QHBoxLayout()
        h_layout.addWidget(QLabel("Quadratic input cost penalty R ="))
        h_layout.addWidget(textbox)
        mppi_constants_layout.addLayout(h_layout)

        # Quadratic cost penalty LBD
        textbox = QLineEdit()
        textbox.setText(str(self.LBD))
        textbox.textChanged.connect(self.LBD_changed)
        h_layout = QHBoxLayout()
        h_layout.addWidget(QLabel("Importance of higher-cost rollouts LBD ="))
        h_layout.addWidget(textbox)
        mppi_constants_layout.addLayout(h_layout)

        # Quadratic cost penalty NU
        textbox = QLineEdit()
        textbox.setText(str(self.NU))
        textbox.textChanged.connect(self.NU_changed)
        h_layout = QHBoxLayout()
        h_layout.addWidget(QLabel("Exploration variance NU ="))
        h_layout.addWidget(textbox)
        mppi_constants_layout.addLayout(h_layout)

        # Sampling type
        h_layout = QHBoxLayout()
        btn1 = QRadioButton("iid")
        if btn1.text() == controller_mppi.SAMPLING_TYPE: btn1.setChecked(True)
        btn1.toggled.connect(lambda: self.toggle_button(btn1))
        h_layout.addWidget(btn1)
        btn2 = QRadioButton("random_walk")
        if btn2.text() == controller_mppi.SAMPLING_TYPE: btn2.setChecked(True)
        btn2.toggled.connect(lambda: self.toggle_button(btn2))
        h_layout.addWidget(btn2)
        btn3 = QRadioButton("uniform")
        if btn3.text() == controller_mppi.SAMPLING_TYPE: btn3.setChecked(True)
        btn3.toggled.connect(lambda: self.toggle_button(btn3))
        h_layout.addWidget(btn3)
        btn4 = QRadioButton("repeated")
        if btn4.text() == controller_mppi.SAMPLING_TYPE: btn4.setChecked(True)
        btn4.toggled.connect(lambda: self.toggle_button(btn4))
        h_layout.addWidget(btn4)
        btn5 = QRadioButton("interpolated")
        if btn5.text() == controller_mppi.SAMPLING_TYPE: btn5.setChecked(True)
        btn5.toggled.connect(lambda: self.toggle_button(btn5))
        h_layout.addWidget(btn5)
        mppi_constants_layout.addWidget(QLabel("Sampling type:"))
        mppi_constants_layout.addLayout(h_layout)

        ### Put together layout
        self.update_labels()
        self.update_slider_labels()
        layout.addLayout(horizon_options_layout)
        layout.addLayout(rollouts_options_layout)
        layout.addLayout(cost_weight_layout)
        layout.addLayout(mppi_constants_layout)

        self.setLayout(layout)
        self.setWindowFlags(self.windowFlags()
                            | Qt.WindowType.WindowStaysOnTopHint)
        self.setGeometry(0, 0, 400, 50)

        self.show()
        self.setWindowTitle("MPPI Options")

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_labels)
        self.timer.start(100)

    def horizon_length_changed(self, val: int):
        self.horizon_steps = val
        # TODO: Replace by setter method
        controller_mppi.mpc_samples = self.horizon_steps
        self.update_slider_labels()

    def num_rollouts_changed(self, val: int):
        self.num_rollouts = val
        controller_mppi.num_rollouts = self.num_rollouts
        self.update_slider_labels()

    def dd_weight_changed(self, val: int):
        self.dd_weight = val
        # TODO: Replace by setter method
        controller_mppi.dd_weight = self.dd_weight * 1.0
        self.update_slider_labels()

    def ep_weight_changed(self, val: int):
        self.ep_weight = val
        # TODO: Replace by setter method
        controller_mppi.ep_weight = self.ep_weight * 1.0
        self.update_slider_labels()

    def ekp_weight_changed(self, val: int):
        self.ekp_weight = val
        # TODO: Replace by setter method
        controller_mppi.ekp_weight = self.ekp_weight * 1.0e-1
        self.update_slider_labels()

    def ekc_weight_changed(self, val: int):
        self.ekc_weight = val
        # TODO: Replace by setter method
        controller_mppi.ekc_weight = self.ekc_weight * 1.0e1
        self.update_slider_labels()

    def cc_weight_changed(self, val: int):
        self.cc_weight = val
        # TODO: Replace by setter method
        controller_mppi.cc_weight = self.cc_weight * 1.0e2
        self.update_slider_labels()

    def ccrc_weight_changed(self, val: int):
        self.ccrc_weight = val
        # TODO: Replace by setter method
        controller_mppi.ccrc_weight = self.ccrc_weight * 1.0e2
        self.update_slider_labels()

    def R_changed(self, val: str):
        if val == '': val = '0'
        val = float(val)
        self.R = val
        controller_mppi.R = self.R

    def LBD_changed(self, val: str):
        if val == '': val = '0'
        val = float(val)
        if val == 0: val = 1.0
        self.LBD = val
        controller_mppi.LBD = self.LBD

    def NU_changed(self, val: str):
        if val == '': val = '0'
        val = float(val)
        if val == 0: val = 1.0
        self.NU = val
        controller_mppi.NU = self.NU

    def toggle_button(self, b):
        if b.isChecked(): controller_mppi.SAMPLING_TYPE = b.text()

    def update_slider_labels(self):
        self.horizon_label.setText(
            f"Horizon: {self.horizon_steps} steps = {round(self.horizon_steps * controller_mppi.dt, 2)} s"
        )
        self.rollouts_label.setText(f"Rollouts: {self.num_rollouts}")
        self.dd_weight_label.setText(
            f"Distance difference cost weight: {round(self.dd_weight, 2)}")
        self.ep_weight_label.setText(
            f"Pole angle cost weight: {round(self.ep_weight, 2)}")
        self.ekp_weight_label.setText(
            f"Pole kinetic energy cost weight: {round(self.ekp_weight * 1.0e-1, 4)}"
        )
        self.ekc_weight_label.setText(
            f"Cart kinetic energy cost weight: {round(self.ekc_weight * 1.0e1, 3)}"
        )
        self.cc_weight_label.setText(
            f"Control cost weight: {round(self.cc_weight * 1.0e2, 3)}")
        self.ccrc_weight_label.setText(
            f"Control change rate cost weight: {round(self.ccrc_weight * 1.0e2, 3)}"
        )

    def update_labels(self):
        self.dd_label.setText(f"{round(controller_mppi.gui_dd.item(), 2)}")
        self.ep_label.setText(f"{round(controller_mppi.gui_ep.item(), 2)}")
        self.ekp_label.setText(f"{round(controller_mppi.gui_ekp.item(), 2)}")
        self.ekc_label.setText(f"{round(controller_mppi.gui_ekc.item(), 2)}")
        self.cc_label.setText(f"{round(controller_mppi.gui_cc.item(), 2)}")
        self.ccrc_label.setText(f"{round(controller_mppi.gui_ccrc.item(), 2)}")
Beispiel #29
0
class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.width = 500
        self.height = 500
        self.xPos = 600
        self.yPos = 400
        self.initUI()

    def initUI(self):
        self.setGeometry(self.xPos, self.yPos, self.width, self.height)
        self.vBoxLayout = QVBoxLayout()

        self.slider = Slider(
            direction=Qt.Orientation.Horizontal,
            duration=750,
            animationType=QEasingCurve.Type.OutQuad,
            wrap=False,
        )

        self.label1 = QLabel()
        self.label1.setText('First Slide')
        self.label1.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.label1.setStyleSheet(
            'QLabel{background-color: rgb(245, 177, 66); color: rgb(21, 21, 21); font: 25pt;}'
        )
        self.slider.addWidget(self.label1)

        self.label2 = QLabel()
        self.label2.setText('Second Slide')
        self.label2.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.label2.setStyleSheet(
            'QLabel{background-color: rgb(21, 21, 21); color: rgb(245, 177, 66); font: 25pt;}'
        )
        self.slider.addWidget(self.label2)

        self.label3 = QLabel()
        self.label3.setText('Third Slide')
        self.label3.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.label3.setStyleSheet(
            'QLabel{background-color: rgb(93, 132, 48); color: rgb(245, 177, 66); font: 25pt;}'
        )
        self.slider.addWidget(self.label3)

        self.buttonPrevious = QPushButton()
        self.buttonPrevious.setText('Previous Slide')
        self.buttonPrevious.clicked.connect(self.slider.slidePrevious)

        self.buttonNext = QPushButton()
        self.buttonNext.setText('Next Slide')
        self.buttonNext.clicked.connect(self.slider.slideNext)

        self.buttonLayout = QHBoxLayout()
        self.buttonLayout.addWidget(self.buttonPrevious)
        self.buttonLayout.addWidget(self.buttonNext)

        self.vBoxLayout.addWidget(self.slider)
        self.vBoxLayout.addLayout(self.buttonLayout)

        self.centralWidget = QWidget(self)
        self.centralWidget.setLayout(self.vBoxLayout)
        self.setCentralWidget(self.centralWidget)

        self.show()
Beispiel #30
0
class InfoDialog(QDialog):
    """文件信息对话框"""
    get_dl_link = pyqtSignal(str, str)
    closed = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.infos = None
        self._short_link_flag = True  # 防止多次重试
        self.initUI()
        self.setStyleSheet(dialog_qss_style)

    def update_ui(self):
        self.tx_dl_link.setPlaceholderText("单击获取")
        self.tx_name.setText(self.infos.name)
        if self.infos.is_file:
            self.setWindowTitle("文件信息")
            self.lb_name.setText("文件名:")
            self.lb_desc.setText("文件描述:")
            self.tx_dl_link.setText("")  # 清空旧的信息
            self.lb_dl_link.setVisible(True)
            self.tx_dl_link.setVisible(True)
        else:
            self.setWindowTitle("文件夹信息")
            self.lb_name.setText("文件夹名:")
            self.lb_desc.setText("文件夹描述:")
            self.lb_dl_link.setVisible(False)
            self.tx_dl_link.setVisible(False)

        if self.infos.size:
            self.tx_size.setText(self.infos.size)
            self.lb_size.setVisible(True)
            self.tx_size.setVisible(True)
        else:
            self.tx_size.setVisible(False)
            self.lb_size.setVisible(False)

        if self.infos.time:
            self.lb_time.setVisible(True)
            self.tx_time.setVisible(True)
            self.tx_time.setText(self.infos.time)
        else:
            self.lb_time.setVisible(False)
            self.tx_time.setVisible(False)

        if self.infos.downs:
            self.lb_dl_count.setVisible(True)
            self.tx_dl_count.setVisible(True)
            self.tx_dl_count.setText(str(self.infos.downs))
        else:
            self.tx_dl_count.setVisible(False)
            self.lb_dl_count.setVisible(False)

        if self.infos.pwd:
            self.tx_pwd.setText(self.infos.pwd)
            self.tx_pwd.setPlaceholderText("")
        else:
            self.tx_pwd.setText("")
            self.tx_pwd.setPlaceholderText("无")

        if self.infos.desc:
            self.tx_desc.setText(self.infos.desc)
            self.tx_desc.setPlaceholderText("")
        else:
            self.tx_desc.setText("")
            self.tx_desc.setPlaceholderText("无")

        self.tx_share_url.setText(self.infos.url)
        self.adjustSize()

    def set_values(self, infos):
        self.infos = infos
        self.update_ui()

    def set_dl_link_tx(self, text):
        self.tx_dl_link.setText(text)
        self.adjustSize()

    def call_get_dl_link(self):
        url = self.tx_share_url.text()
        pwd = self.tx_pwd.text()
        self.get_dl_link.emit(url, pwd)
        self.tx_dl_link.setPlaceholderText("后台获取中,请稍候!")

    def call_get_short_url(self):
        if self._short_link_flag:
            self._short_link_flag = False
            self.tx_short.setPlaceholderText("后台获取中,请稍候!")
            url = self.tx_share_url.text()
            from lanzou.api.extra import get_short_url

            short_url = get_short_url(url)
            if short_url:
                self.tx_short.setText(short_url)
                self.tx_short.setPlaceholderText("")
                self._short_link_flag = True
            else:
                self.tx_short.setText("")
                self.tx_short.setPlaceholderText("生成失败!api 可能已经失效")

    def clean(self):
        self._short_link_flag = True
        self.tx_short.setText("")
        self.tx_short.setPlaceholderText("单击获取")

    def initUI(self):
        self.setWindowIcon(QIcon(SRC_DIR + "share.ico"))
        self.setWindowTitle("文件信息")
        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.rejected.connect(self.clean)
        self.buttonBox.rejected.connect(self.closed.emit)

        self.logo = QLabel()
        self.logo.setPixmap(QPixmap(SRC_DIR + "q9.gif"))
        self.logo.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.logo.setStyleSheet("background-color:rgb(255,204,51);")

        self.lb_name = QLabel()
        self.lb_name.setText("文件名:")
        self.tx_name = AutoResizingTextEdit()
        self.tx_name.setReadOnly(True)
        self.tx_name.setMinimumLines(1)

        self.lb_size = QLabel()
        self.lb_size.setText("文件大小:")
        self.tx_size = QLabel()

        self.lb_time = QLabel()
        self.lb_time.setText("上传时间:")
        self.tx_time = QLabel()

        self.lb_dl_count = QLabel()
        self.lb_dl_count.setText("下载次数:")
        self.tx_dl_count = QLabel()

        self.lb_share_url = QLabel()
        self.lb_share_url.setText("分享链接:")
        self.tx_share_url = QLineEdit()
        self.tx_share_url.setReadOnly(True)

        self.lb_pwd = QLabel()
        self.lb_pwd.setText("提取码:")
        self.tx_pwd = QLineEdit()
        self.tx_pwd.setReadOnly(True)

        self.lb_short = QLabel()
        self.lb_short.setText("短链接:")
        self.tx_short = AutoResizingTextEdit(self)
        self.tx_short.setPlaceholderText("单击获取")
        self.tx_short.clicked.connect(self.call_get_short_url)
        self.tx_short.setReadOnly(True)
        self.tx_short.setMinimumLines(1)

        self.lb_desc = QLabel()
        self.lb_desc.setText("文件描述:")
        self.tx_desc = AutoResizingTextEdit()
        self.tx_desc.setReadOnly(True)
        self.tx_desc.setMinimumLines(1)

        self.lb_dl_link = QLabel()
        self.lb_dl_link.setText("下载直链:")
        self.tx_dl_link = AutoResizingTextEdit(self)
        self.tx_dl_link.setPlaceholderText("单击获取")
        self.tx_dl_link.clicked.connect(self.call_get_dl_link)
        self.tx_dl_link.setReadOnly(True)
        self.tx_dl_link.setMinimumLines(1)

        vbox = QVBoxLayout()
        vbox.addWidget(self.logo)
        vbox.addStretch(1)
        form = QFormLayout()
        form.setLabelAlignment(Qt.AlignmentFlag.AlignRight)
        form.addRow(self.lb_name, self.tx_name)
        form.addRow(self.lb_size, self.tx_size)
        form.addRow(self.lb_time, self.tx_time)
        form.addRow(self.lb_dl_count, self.tx_dl_count)
        form.addRow(self.lb_share_url, self.tx_share_url)
        form.addRow(self.lb_pwd, self.tx_pwd)
        form.addRow(self.lb_short, self.tx_short)
        form.addRow(self.lb_desc, self.tx_desc)
        form.addRow(self.lb_dl_link, self.tx_dl_link)
        form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)  # 覆盖MacOS的默认样式
        vbox.addLayout(form)
        vbox.addStretch(1)
        vbox.addWidget(self.buttonBox)

        self.setLayout(vbox)
        self.setMinimumWidth(500)