コード例 #1
0
ファイル: logger.py プロジェクト: RamyE/SFU_ML
class Logger:
    def __init__(self, textBrowser, textLabel):
        self.logBox = QTextBrowser()
        self.labelBox = QLabel()
        self.logBox = textBrowser
        self.labelBox = textLabel
        self._enabled = True

    def log(self, logLine, type=None, special=None):
        if not self._enabled:
            return
        string = ""
        if logLine is "":
            try:
                logLine = specialLogs[special][0]
                if type is None:
                    type = specialLogs[special][1]
            except:
                print("An invalid special log has been provided: ", special)
        color = "black"
        if type is None:
            type = "INFO"
        string = string + type + ": "
        if type in typeColors.keys():
            color = typeColors[type]
        string = string + logLine
        self.logBox.append(string)
        self.labelBox.setStyleSheet("color: " + color)
        self.labelBox.setAlignment(Qt.AlignHCenter)
        if type in typeColors.keys():
            self.labelBox.setText(logLine)

    def saveLog(self, filePath):
        try:
            if filePath[-4:] != ".txt":
                filePath = filePath + ".txt"
            with open(filePath, mode='a') as outFile:
                outFile.write(
                    "\nThe following log has been saved at {} \n".format(
                        datetime.now()))
                outFile.write(self.logBox.toPlainText())
        except IOError:
            self.log("An error was found. Please check the output file path!",
                     type="ERROR")
            return -1
        return 0

    def clearLog(self):
        self.logBox.clear()
        self.labelBox.clear()

    def enableLogging(self):
        self._enabled = True

    def disableLogging(self):
        self._enabled = False
コード例 #2
0
class mainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.activeImage = ""
        self.previewImage = ""
        self.n = 400  #Set image display max size

        #Top Row Setup
        self.hedder = QLabel("Welcome to the Image Restoration App")

        #Button Row Setup
        self.selectButton = QPushButton("Click to select an image.")
        self.selectButton.clicked.connect(self.imageSelect)
        self.option1 = QPushButton("Black and White to Color")
        self.option1.clicked.connect(self.bandwToColorFilter)
        self.option2 = QPushButton("Denoise Image")
        self.option2.clicked.connect(self.denoiseFilter)
        self.option3 = QPushButton("Sharpen Image")
        self.option3.clicked.connect(self.sharpenFilter)
        self.option4 = QPushButton("Resize Image")
        self.option4.clicked.connect(self.resizeFilter)
        self.resizePercent = QLineEdit(self)
        self.saveImage = QPushButton("Save Image")
        self.saveImage.clicked.connect(self.imageSave)
        self.saveLabel = QLabel("Save name ->")
        self.saveName = QLineEdit(self)

        self.optionsRow = QHBoxLayout()
        self.optionsRow.addWidget(self.selectButton)
        self.optionsRow.addWidget(self.option1)
        self.optionsRow.addWidget(self.option2)
        self.optionsRow.addWidget(self.option3)
        self.optionsRow.addWidget(self.option4)
        self.optionsRow.addWidget(self.resizePercent)
        self.optionsRow.addWidget(self.saveLabel)
        self.optionsRow.addWidget(self.saveName)
        self.optionsRow.addWidget(self.saveImage)

        #Image Display Setup
        self.activeImageDisplay = QLabel()
        self.previewImageDisplay = QLabel()

        self.imageDisplayRow = QHBoxLayout()
        self.imageDisplayRow.addWidget(self.activeImageDisplay)
        self.imageDisplayRow.addWidget(self.previewImageDisplay)

        #Main Layout Setup
        self.mainLayout = QVBoxLayout()
        self.mainLayout.addWidget(self.hedder)
        self.mainLayout.addLayout(self.optionsRow)
        self.mainLayout.addLayout(self.imageDisplayRow)

        self.setLayout(self.mainLayout)

    def imageSelect(self):  #function for selecting image
        self.activeImage = easygui.fileopenbox()
        pixmap = QPixmap(self.activeImage)
        self.previewImage = ""
        self.previewImageDisplay.clear()
        if str(pixmap.size()
               ) == "PySide2.QtCore.QSize(0, 0)":  #checks if image is valid
            self.activeImage = ""
            self.activeImageDisplay.clear()
            self.hedder.setText("Warning: Invalid image.")
            self.repaint()
        else:  #if image is valid, sets and displays image
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.activeImageDisplay.setPixmap(pixmap)
            self.hedder.setText("Image selected. Now, apply a filter.")
            self.previewImageDisplay.clear()
            self.repaint()

    def bandwToColorFilter(self):  #code to run bandwToColor, save and display
        if self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = bandwToColor(self.previewImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = bandwToColor(self.activeImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def denoiseFilter(self):  #code to run denoise, save and display
        if self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = denoise(self.previewImage)
            imPath = self.previewImage
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = denoise(self.activeImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def sharpenFilter(self):  #code to run sharpen, save and display
        if self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = sharpen(self.previewImage)
            imPath = self.previewImage
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = sharpen(self.activeImage)
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Now, apply additional filters or save.")
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def resizeFilter(self):  #code to run resize, save and "display"
        if self.resizePercent.displayText().isnumeric() == False:
            self.hedder.setText(
                "Warning: You must imput an integer for the resize. Greater than 100 increases size, less than 100 decreases size."
            )
            self.repaint()
        elif int(self.resizePercent.displayText()) < 0.0:
            self.hedder.setText(
                "Warning: Resize must be number greater than 0.")
            self.repaint()
        elif self.previewImage != "":  #checks if preview exists. If it does, it will be edited instead of original.
            self.previewImage = resize(self.previewImage,
                                       int(self.resizePercent.displayText()))
            imPath = self.previewImage
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Warning: Resize may not be visible in app. Now, apply additional filters or save."
            )
            self.repaint()
        elif self.activeImage != "":  #checks if image is ready
            self.previewImage = resize(self.activeImage,
                                       int(self.resizePercent.displayText()))
            imPath = self.previewImage
            pixmap = QPixmap(imPath)
            pixmap = pixmap.scaled(self.n, self.n, Qt.KeepAspectRatio)
            self.previewImageDisplay.setPixmap(pixmap)
            self.hedder.setText(
                "Filter applied. Warning: Resize may not be visible in app. Now, apply additional filters or save."
            )
            self.repaint()
        else:  #if image is not ready, displays warning
            self.hedder.setText(
                "Warning: No image selected. Select an image before apllying filters."
            )
            self.repaint()

    def imageSave(self):  #code to save image
        if self.previewImage == "":  #checks if image is ready
            self.hedder.setText(
                "Warning: No image to save. Upload an image to edit or apply a filter."
            )
            self.repaint()
        elif self.saveName.displayText() == "":  #checks if name is valid
            self.hedder.setText(
                "Warning: No name for image. Add a name before hitting save.")
            self.repaint()
        else:
            im = Image.open(self.previewImage)
            if "." in self.saveName.displayText(
            ):  #checks if save name as extension
                fileName = self.saveName.displayText()
            else:  #if not, defaults to extension of original image
                extension = findExtension(self.activeImage)
                fileName = self.saveName.displayText() + extension
            im.save(fileName)
            self.hedder.setText(
                "Image saved! Remember to change the save name before saving more images."
            )
コード例 #3
0
ファイル: search.py プロジェクト: SimoneGasperini/rboost
class SearchWindow(QWidget):
    def __init__(self, rboost):
        super().__init__()
        self.rboost = rboost

        self.layout = QVBoxLayout()
        self._add_input_layout()
        self._add_output_layout()
        self.table_view = None
        self._add_table_view_layout()
        self.setLayout(self.layout)

    def _add_input_layout(self):
        self.input_layout = QHBoxLayout()
        self._add_label()
        self._add_input_line()
        search_button = QPushButton('Search')
        search_button.clicked.connect(self.show_results)
        clear_button = QPushButton('Clear')
        clear_button.clicked.connect(self.clear_results)
        self.input_layout.addWidget(search_button)
        self.input_layout.addWidget(clear_button)
        self.layout.addLayout(self.input_layout)

    def _add_label(self):
        label = QLabel('Label:')
        label.setFont(QFont('Arial', 16))
        label.setAlignment(Qt.AlignVCenter | Qt.AlignRight)
        self.input_layout.addWidget(label)

    def _add_input_line(self):
        self.layout = QVBoxLayout()
        self.input_line = QLineEdit()
        self.input_line.setFont(QFont('Arial', 20))
        self.input_line.setMaximumWidth(800)
        self.input_layout.addWidget(self.input_line)

    def _add_output_layout(self):
        self.output_layout = QVBoxLayout()
        self.label_not_found = QLabel()
        self.label_not_found.setFont(QFont('Times', 12))
        self.label_not_found.setStyleSheet('QLabel {color : red}')
        self.similar_labels = QLabel()
        self.similar_labels.setFont(QFont('Times', 12))
        self.output_layout.addWidget(self.label_not_found)
        self.output_layout.addWidget(self.similar_labels)
        self.layout.addLayout(self.output_layout)

    def _add_table_view_layout(self, df=None):
        self.table_view_layout = QHBoxLayout()
        if self.table_view is not None:
            self.table_view_layout.removeWidget(self.table_view)
            self.table_view.deleteLater()
        self.table_view = self._create_table_view(df=df)
        self.table_view_layout.addWidget(self.table_view)
        self.layout.addLayout(self.table_view_layout)

    def _create_table_view(self, df):
        if df is None:
            df = pd.DataFrame()
        model = PandasModel(df)
        table_view = QTableView()
        table_view.setModel(model)
        table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        return table_view

    def _get_dataframe(self, label):
        dframe = self.rboost.database.dataframe
        colname = self.rboost.documents_df_cols['keywords']
        df = dframe[dframe[colname].apply(lambda keywords: label in keywords)]
        return df

    def _get_messages(self, label, df):
        msg1 = f'Label "{label}" not found in RBoost!' if df.empty else ''
        similar_labels = [
            lab for lab in self.rboost.labnames
            if 0 < lev.distance(label, lab) < 3
        ]
        msg2 = 'Similar labels found: "' + '", "'.join(similar_labels) + '"' \
            if similar_labels else 'Similar labels found: None'
        return msg1, msg2

    def show_results(self):
        label = self.input_line.text()
        df = self._get_dataframe(label=label)
        msg1, msg2 = self._get_messages(label=label, df=df)
        self.label_not_found.setText(msg1)
        self.similar_labels.setText(msg2)
        self._add_table_view_layout(df=df)
        self.setLayout(self.layout)

    def clear_results(self):
        self.input_line.clear()
        self.label_not_found.clear()
        self.similar_labels.clear()
        empty_df = pd.DataFrame()
        self._add_table_view_layout(df=empty_df)
        self.setLayout(self.layout)
コード例 #4
0
class ApplicationWindow(QMainWindow):
    def __init__(self, inputfile, frame):
        super().__init__()

        self.title = "GIXStapose"

        if inputfile is None:
            print("No input provided, showing simple cubic example")
            path = Path(__file__).parent / "data/sc10.pdb"
            inputfile = str(path.resolve())
        self.basename = os.path.basename(inputfile).split(".")[0]
        self.render_counter = 0
        self.diffract_counter = 0

        self.init_diffractometer(inputfile, frame)

        self.initUI()

    def init_diffractometer(self, inputfile, frame):
        compound = compound_load(inputfile, frame)
        self.scene = create_scene(compound)
        mode = self.scene.device.mode
        self.title = f"GIXStapose ({mode} mode)"

        self.d = Diffractometer()
        self.d.load_compound(compound)

    def initUI(self):
        self.setWindowTitle(self.title)

        # Menubar
        menubar = self.menuBar()
        filemenu = menubar.addMenu("File")
        render = QAction("Render Scene", self)
        export = QAction("Export Diffraction Pattern", self)
        print_camera = QAction("Print Camera", self)
        filemenu.addAction(render)
        filemenu.addAction(export)
        filemenu.addAction(print_camera)
        filemenu.triggered[QAction].connect(self.processtrigger)

        self.main = QWidget()
        self.setCentralWidget(self.main)

        # creates 'top' and 'bot' horizontalgroupbox grid layout objects
        self.createGridLayout()

        windowlayout = QVBoxLayout()
        windowlayout.addWidget(self.tophorizontalGroupBox)
        windowlayout.addWidget(self.bothorizontalGroupBox)
        self.main.setLayout(windowlayout)

        self.show()

    def createGridLayout(self):
        from fresnel import interact

        # Top grid with sceneview and diffraction pattern
        self.tophorizontalGroupBox = QGroupBox()
        toplayout = QGridLayout()

        # Add the SceneView widget
        self.view = interact.SceneView(self.scene)
        self.view.rendering.connect(self.update_camera)
        toplayout.addWidget(self.view, 0, 0)

        # Add the diffraction widget
        dynamic_canvas = FigureCanvas(Figure(figsize=(15, 15)))
        toplayout.addWidget(dynamic_canvas, 0, 1)
        self.diffract_ax = dynamic_canvas.figure.add_subplot(111)
        self.diffract_ax.axis("off")
        self.diffract_ax.set_axis_off()
        self.plot_diffract(self.view.scene.camera)

        self.tophorizontalGroupBox.setLayout(toplayout)

        # Bottom grid with camera, buttons, zoom, sigma
        self.bothorizontalGroupBox = QGroupBox()
        botlayout = QGridLayout()

        # Camera printout
        self.label = QLabel()
        self.label.setText(self.camera_text(self.view.scene.camera))
        # widget, row, col, rowspan, colspan
        botlayout.addWidget(self.label, 0, 0, 2, 1)

        # Buttons
        self.button100 = QPushButton("100")
        self.button100.setMaximumSize(QSize(100,40))
        botlayout.addWidget(self.button100, 0, 1, 2, 1)

        self.button110 = QPushButton("110")
        self.button110.setMaximumSize(QSize(100,40))
        botlayout.addWidget(self.button110, 0, 2, 2, 1)

        self.button111 = QPushButton("111")
        self.button111.setMaximumSize(QSize(100,40))
        botlayout.addWidget(self.button111, 0, 3, 2, 1)

        # Connect buttons to moving the camera
        # thanks to this wonderful answer https://stackoverflow.com/a/57167056/11969403
        self.button100.clicked.connect(lambda: self.move_camera((1,0,0)))
        self.button110.clicked.connect(lambda: self.move_camera((1,1,0)))
        self.button111.clicked.connect(lambda: self.move_camera((1,1,1)))

        # Add space between buttons and slider
        botlayout.setColumnMinimumWidth(4,350)

        # Zoom slider
        zlabel = QLabel("Zoom")
        zlabel.setAlignment(Qt.AlignCenter)
        botlayout.addWidget(zlabel, 0, 5)

        self.zooms = [i for i in range(1, self.d.N) if self.d.N % i == 0]
        self.zoomslider = QSlider(Qt.Horizontal)
        self.zoomslider.setMinimum(0)
        self.zoomslider.setMaximum(len(self.zooms)-1)
        self.zoomslider.setValue(self.zooms.index(self.d.zoom))
        self.zoomslider.valueChanged.connect(self.change_zoom)
        self.zoomslider.setMaximumSize(QSize(600,30))
        botlayout.addWidget(self.zoomslider, 1, 5)

        botlayout.setColumnMinimumWidth(6,50)

        self.bothorizontalGroupBox.setLayout(botlayout)

    def processtrigger(self, q):
        if q.text() == "Render Scene":
            print("Rendering...")
            output = fresnel.pathtrace(self.view.scene, light_samples=40, w=600, h=600)
            filename = f"{self.basename}_scene{self.render_counter}.png"

            image = PIL.Image.fromarray(output[:], mode='RGBA')
            image.save(filename, dpi=(300, 300))

            old_camera = self.view.scene.camera
            print(f"Rendered {filename}")
            self.render_counter += 1

        elif q.text() == "Export Diffraction Pattern":
            print("Saving diffraction pattern...")
            filename = f"{self.basename}_dp{self.diffract_counter}.png"

            plt.imsave(filename, self.dp, cmap="jet")
            print(f"Diffraction pattern saved as {filename}")
            self.diffract_counter += 1

        elif q.text() == "Print Camera":
            print("Current camera is:\n")
            print(self.camera_text(self.view.scene.camera))

    def change_zoom(self):
        self.d.zoom = self.zooms[self.zoomslider.value()]
        self.plot_diffract(self.view.scene.camera)

    def camera_text(self, camera):
        """
        Convert a fresnel.Camera object to a readable string
        """
        pos = camera.position
        look = camera.look_at
        up = camera.up
        text = "".join(
            [
                "Camera\n",
                f"   position = [{pos[0]:.3f}, {pos[1]:.3f}, {pos[2]:.3f}],\n",
                f"   look_at =  [{look[0]:.3f}, {look[1]:.3f}, {look[2]:.3f}],\n",
                f"   up =       [{up[0]:.3f}, {up[1]:.3f}, {up[2]:.3f}],\n",
                f"   height =   {camera.height:.3f}",
            ]
        )
        return text

    def update_camera(self, camera):
        self.label.clear()
        # display the camera value
        self.label.setText(self.camera_text(camera))
        self.plot_diffract(camera)

    def plot_diffract(self, camera):
        self.diffract_ax.clear()
        self.diffract_ax.axis("off")

        # diffraction pattern
        self.dp = self.d.diffract_from_camera(camera)
        self.diffract_ax.imshow(self.dp, cmap="jet")
        self.diffract_ax.figure.canvas.draw()
        self.repaint()

    def move_camera(self, pos):
        self.view.scene.camera = camera_from_pos(pos)
        #self.repaint()
        self.view._start_rendering()
        self.view.update()
コード例 #5
0
ファイル: main.py プロジェクト: ysglyl/recognition-client
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.users = None
        self.camera = None
        self.playing = False
        self.frames = None
        self.capturing = False
        self.capture_frame = None
        self.flag_recognize = False
        self.model = None

        # key:user_id, value:((x,y,w,h),name,color,welcome_msg)
        self.recognized_faces = {}

        self.lbl_viewer = None
        self.btn_open_camera = None
        self.btn_close_camera = None
        self.btn_open_video = None
        self.btn_close_video = None
        self.cb_recognize = None
        self.btn_sync_face = None
        self.btn_capture = None
        self.lbl_capture_pic = None
        self.btn_capture_save = None

        self.init_ui()
        self.train_model()
        if os.path.exists('faces{}tmp'.format(os.sep)):
            shutil.rmtree('faces{}tmp'.format(os.sep))

    def init_ui(self):
        self.setFixedSize(Config.width, Config.height)
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        self.setWindowIcon(QIcon('icons/icon.png'))
        self.setWindowTitle('客户端')

        menu_bar = self.menuBar()
        menu_bar.setNativeMenuBar(False)
        manage_menu = menu_bar.addMenu("信息管理")
        client_login_action = manage_menu.addAction("服务器连接")
        client_login_action.triggered.connect(self.manage_client_login)
        user_action = manage_menu.addAction("用户管理")
        user_action.triggered.connect(self.manage_user)

        setting_menu = menu_bar.addMenu("设置")
        server_action = setting_menu.addAction("服务器")
        server_action.triggered.connect(self.setting_server)
        dimension_action = setting_menu.addAction("窗口尺寸")
        dimension_action.triggered.connect(self.setting_dimension)

        help_menu = menu_bar.addMenu("帮助")
        client_register_action = help_menu.addAction("客户端注册")
        client_register_action.triggered.connect(self.help_client_register)

        status_bar = self.statusBar()
        status_bar.showMessage("欢迎使用客户端")

        self.lbl_viewer = QLabel(self)
        self.lbl_viewer.setGeometry(QRect(10, 26, Config.width - 130, Config.height - 60))
        self.lbl_viewer.setText('没有图像')
        font = QFont()
        font.setPointSize(20)
        self.lbl_viewer.setFont(font)
        self.lbl_viewer.setAlignment(Qt.AlignCenter)
        self.lbl_viewer.setFrameShape(QFrame.StyledPanel)

        self.btn_open_camera = QPushButton(self)
        self.btn_open_camera.setGeometry(QRect(Config.width - 110, 10, 100, 26))
        self.btn_open_camera.setText('打开摄像头')
        self.btn_open_camera.clicked.connect(self.btn_click)

        self.btn_close_camera = QPushButton(self)
        self.btn_close_camera.setGeometry(QRect(Config.width - 110, 46, 100, 26))
        self.btn_close_camera.setText('关闭摄像头')
        self.btn_close_camera.setDisabled(True)
        self.btn_close_camera.clicked.connect(self.btn_click)

        self.btn_open_video = QPushButton(self)
        self.btn_open_video.setGeometry(QRect(Config.width - 110, 82, 100, 26))
        self.btn_open_video.setText('播放视频')
        self.btn_open_video.clicked.connect(self.btn_click)

        self.btn_close_video = QPushButton(self)
        self.btn_close_video.setGeometry(QRect(Config.width - 110, 118, 100, 26))
        self.btn_close_video.setText('停止播放')
        self.btn_close_video.setDisabled(True)
        self.btn_close_video.clicked.connect(self.btn_click)

        self.cb_recognize = QCheckBox(self)
        self.cb_recognize.setText('启动识别')
        self.cb_recognize.setDisabled(True)
        self.cb_recognize.setGeometry(QRect(Config.width - 108, 154, 100, 26))
        self.cb_recognize.clicked.connect(self.cb_click)

        self.btn_sync_face = QPushButton(self)
        self.btn_sync_face.setGeometry(QRect(Config.width - 110, 190, 100, 26))
        self.btn_sync_face.setText("同步数据")
        self.btn_sync_face.clicked.connect(self.btn_click)

        self.btn_capture = QPushButton(self)
        self.btn_capture.setGeometry(QRect(Config.width - 110, Config.height - 200, 100, 26))
        self.btn_capture.setText('截屏')
        self.btn_capture.setDisabled(True)
        self.btn_capture.clicked.connect(self.btn_click)

        self.lbl_capture_pic = QLabel(self)
        self.lbl_capture_pic.setGeometry(QRect(Config.width - 110, Config.height - 160, 100, 100))
        self.lbl_capture_pic.setAlignment(Qt.AlignCenter)
        self.lbl_capture_pic.setFrameShape(QFrame.StyledPanel)

        self.btn_capture_save = QPushButton(self)
        self.btn_capture_save.setGeometry(QRect(Config.width - 110, Config.height - 60, 100, 26))
        self.btn_capture_save.setText('保存截图')
        self.btn_capture_save.setDisabled(True)
        self.btn_capture_save.clicked.connect(self.btn_click)

    def btn_click(self):
        btn = self.sender()
        if btn == self.btn_open_camera:
            self.btn_open_camera.setDisabled(True)
            self.btn_close_camera.setDisabled(False)
            self.btn_capture.setDisabled(False)
            self.cb_recognize.setDisabled(False)
            self.camera = cv2.VideoCapture(0)
            self.frames = collections.deque(maxlen=33)
            self.start_play()
        elif btn == self.btn_close_camera:
            self.stop_play()
            self.btn_open_camera.setDisabled(False)
            self.btn_close_camera.setDisabled(True)
            self.btn_capture.setDisabled(True)
            self.cb_recognize.setDisabled(True)
        elif btn == self.btn_sync_face:
            self.btn_sync_face.setDisabled(True)
            self.sync_data()
        elif btn == self.btn_capture:
            self.capturing = True
            self.btn_capture_save.setDisabled(False)
        elif btn == self.btn_capture_save:
            AddUserFace(self.capture_frame).exec_()
            self.train_model()

    def cb_click(self):
        cb = self.sender()
        if cb == self.cb_recognize:
            if cb.isChecked():
                self.flag_recognize = True
            else:
                self.flag_recognize = False

    def start_play(self):
        self.playing = True
        play_thread = Thread(target=self.play)
        play_thread.start()
        recognize_thread = Thread(target=self.recognize)
        recognize_thread.start()

    def stop_play(self):
        self.playing = False

    def play(self):
        while self.camera.isOpened():
            try:
                if not self.playing:
                    break
                ret, frame = self.camera.read()
                if ret:
                    if self.flag_recognize:
                        self.frames.appendleft(frame.copy())
                        faces = self.recognized_faces.copy()
                        for user_id in faces:
                            face = faces[user_id]
                            x, y, w, h = face[0]
                            cv2.rectangle(frame, (x, y), (x + w, y + h), tuple(list(map(int, face[2].split(',')))), 1, cv2.LINE_AA)
                            if Config.show_name:
                                cv2.putText(frame, face[1], (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 2,
                                            tuple(list(map(int, face[2].split(',')))), 2)
                            if Config.show_match_result:
                                cv2.putText(frame, 'Match degree:' + str(face[3]), (10, 40), cv2.FONT_HERSHEY_SIMPLEX, 2, tuple(list(map(int, face[2].split(',')))), 2)
                    img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    image = QImage(img, img.shape[1], img.shape[0], img.shape[1] * 3, QImage.Format_RGB888)
                    pix_map = QPixmap.fromImage(image)
                    pix_map = pix_map.scaled(Config.width - 130, Config.height - 60, Qt.KeepAspectRatio)
                    self.lbl_viewer.setPixmap(pix_map)
                    # 保存截图
                    if self.capturing:
                        self.capture_frame = frame.copy()
                        pix_map = pix_map.scaled(100, 100, Qt.KeepAspectRatio)
                        self.lbl_capture_pic.setPixmap(pix_map)
                        self.capturing = False
            except Exception as e:
                print(e)
        self.lbl_viewer.clear()
        self.camera.release()

    def recognize(self):
        classifier = HaarcascadeDetective().get_face_classifier()
        while self.playing:
            try:
                if len(self.frames) == 0:
                    time.sleep(0.05)
                    continue
                if self.flag_recognize:
                    frame = self.frames.pop()
                    faces = classifier.get_faces_position(frame)
                    self.recognized_faces.clear()
                    for (x, y, w, h) in faces:
                        face = frame[y:y + h, x:x + w]
                        if self.model is not None:
                            gray = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY)
                            params = self.model.predict(gray)
                            user = self.find_user_by_id(params[0])
                            if user is not None:
                                self.recognized_faces[user[1]] = ((x, y, w, h), user[2], user[3], int(params[1]))
                            else:
                                self.recognized_faces['-1'] = ((x, y, w, h), 'No this user', '255,0,0', 0)
                        else:
                            self.recognized_faces['-2'] = ((x, y, w, h), 'No model', '255,0,0', 0)
            except Exception as e:
                print(e)

    def sync_data(self):
        client = DbHelper.query_client()
        if client is None:
            Tool.show_msg_box('客户端尚未认证!')
            self.btn_sync_face.setDisabled(False)
            return
        shutil.rmtree('faces')
        os.mkdir('faces')
        DbHelper.delete_users()
        users = Tool.user_face_list(client[0])
        if users is not None:
            for user in users:
                user_id = DbHelper.insert_user(user['rowId'], user['name'], user['color'], user['clientId'])
                faces = user['faces']
                for face in faces:
                    Tool.download_face(face['rowId'], str(user_id))
        self.btn_sync_face.setDisabled(False)
        # 重新训练模型
        self.train_model()

    def train_model(self):
        self.users = DbHelper.query_users()
        y, x = [], []
        faces_dir = os.listdir('faces')
        for user_dir in faces_dir:
            if user_dir == 'tmp':
                continue
            faces = os.listdir('faces{}{}'.format(os.sep, user_dir))
            for face in faces:
                y.append(int(user_dir))
                im = cv2.imread('faces{}{}{}{}'.format(os.sep, user_dir, os.sep, face), 0)
                x.append(np.asarray(im, dtype=np.uint8))
        if len(x) != 0 and len(y) != 0:
            self.model = cv2.face.LBPHFaceRecognizer_create()
            self.model.train(np.asarray(x), np.asarray(y, dtype=np.int64))

    def find_user_by_id(self, user_id):
        for user in self.users:
            if user[0] == user_id:
                return user

    def closeEvent(self, *args, **kwargs):
        self.playing = False
        if os.path.exists('faces{}tmp'.format(os.sep)):
            shutil.rmtree('faces{}tmp'.format(os.sep))

    @staticmethod
    def manage_client_login():
        ClientLogin().exec_()

    @staticmethod
    def manage_user():
        AddUser().exec_()

    @staticmethod
    def setting_server():
        ServerSetting().exec_()

    @staticmethod
    def setting_dimension():
        DimensionSetting().exec_()

    @staticmethod
    def help_client_register():
        ClientRegister().exec_()
コード例 #6
0
class Artigence(QMainWindow):
    def __init__(self):
        super(Artigence, self).__init__()

        # Basic Settings
        self.setGeometry(300, 200, 682, 422)
        self.setMinimumSize(QSize(682, 422))
        self.setMaximumSize(QSize(682, 422))
        self.setWindowIcon(QIcon("arti.PNG"))
        self.setWindowTitle("Artigence Home")

        # Color Scheme
        self.palette = QPalette()
        self.palette.setColor(self.palette.Window, QColor('#000000'))
        self.palette.setColor(self.palette.WindowText, QColor('#FFFFFF'))
        self.setPalette(self.palette)

        self.light_palette = QPalette()
        self.light_palette.setColor(self.light_palette.Window,
                                    QColor('#FFFFFF'))
        self.light_palette.setColor(self.light_palette.WindowText,
                                    QColor('#000000'))

        # Setting MenuBar
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(0, 0, 682, 21)

        self.date_menu = QMenu(self.menubar)
        self.date_menu.setTitle(str(datetime.now().strftime('%d-%m-%Y')))

        self.theme_menu = QMenu(self.menubar)
        self.theme_menu.setTitle('Theme')

        self.dark_theme = QAction('Dark Theme')
        self.dark_theme.setShortcut(QKeySequence('Ctrl+Shift+D'))
        self.theme_menu.addAction(self.dark_theme)
        self.dark_theme.triggered.connect(lambda: self.dark())

        self.light_theme = QAction('Light Theme')
        self.light_theme.setShortcut(QKeySequence('Ctrl+Shift+L'))
        self.theme_menu.addAction(self.light_theme)
        self.light_theme.triggered.connect(lambda: self.light())

        self.app_menu = QMenu(self.menubar)
        self.app_menu.setTitle('Apps')

        self.calculator_menu = QAction('Calculator')
        self.calculator_menu.setShortcut(QKeySequence('Alt+C'))
        self.app_menu.addAction(self.calculator_menu)
        self.calculator_menu.triggered.connect(lambda: self.calculator_func())

        self.game_menu = QAction('GameHub')
        self.game_menu.setShortcut(QKeySequence('Alt+G'))
        self.app_menu.addAction(self.game_menu)
        self.game_menu.triggered.connect(lambda: self.games_func())

        self.music_menu = QAction('Muse (Music)')
        self.music_menu.setShortcut(QKeySequence('Alt+M'))
        self.app_menu.addAction(self.music_menu)
        self.music_menu.triggered.connect(lambda: self.music_func())

        self.news_menu = QAction('News')
        self.news_menu.setShortcut(QKeySequence('Alt+E'))
        self.app_menu.addAction(self.news_menu)
        self.news_menu.triggered.connect(lambda: self.news_func())

        self.notepad_menu = QAction('Notepad')
        self.notepad_menu.setShortcut(QKeySequence('Alt+N'))
        self.app_menu.addAction(self.notepad_menu)
        self.notepad_menu.triggered.connect(lambda: self.notepad_func())

        self.pronunciator = QAction('Pronunciator')
        self.pronunciator.setShortcut(QKeySequence('Alt+P'))
        self.app_menu.addAction(self.pronunciator)
        self.pronunciator.triggered.connect(lambda: self.pronunciator_func())

        self.translate_menu = QAction('Translate')
        self.translate_menu.setShortcut(QKeySequence('Alt+T'))
        self.app_menu.addAction(self.translate_menu)
        self.translate_menu.triggered.connect(lambda: self.translate_func())

        self.weather_menu = QAction('Weather')
        self.weather_menu.setShortcut(QKeySequence('Alt+W'))
        self.app_menu.addAction(self.weather_menu)
        self.weather_menu.triggered.connect(lambda: self.weather_func())

        self.setMenuBar(self.menubar)
        self.menubar.addAction(self.date_menu.menuAction())
        self.menubar.addAction(self.theme_menu.menuAction())
        self.menubar.addAction(self.app_menu.menuAction())

        # Creating Widgets
        self.query = QLineEdit(self)
        self.query.setGeometry(QRect(20, 30, 451, 41))
        self.query.setMinimumSize(QSize(451, 41))
        self.query.setMaximumSize(QSize(451, 41))
        self.query.setPlaceholderText("Enter your Query Here:")
        self.query.setFont(QFont('Roboto', 16))
        self.query.setClearButtonEnabled(True)

        self.update = QPushButton(self)
        self.update.setGeometry(QRect(491, 30, 171, 41))
        self.update.setMinimumSize(QSize(1, 1))
        self.update.setMaximumSize(QSize(171, 51))
        self.update.setText("What's New in the Updates?")
        self.update.setCursor(QCursor(Qt.PointingHandCursor))

        self.suggestions = QLabel(self)
        self.suggestions.setGeometry(QRect(20, 220, 111, 31))
        self.suggestions.setMinimumSize(QSize(111, 31))
        self.suggestions.setMaximumSize(QSize(111, 31))
        self.suggestions.setText("Suggestions:")
        self.suggestions.setFont(QFont('Roboto', 14))

        self.chrome = QPushButton(self)
        self.chrome.setGeometry(QRect(20, 260, 91, 31))
        self.chrome.setCursor(QCursor(Qt.PointingHandCursor))
        self.chrome.setText('Open Chrome')

        self.games = QPushButton(self)
        self.games.setGeometry(QRect(420, 260, 91, 31))
        self.games.setCursor(QCursor(Qt.PointingHandCursor))
        self.games.setText('Games')

        self.cmd = QPushButton(self)
        self.cmd.setGeometry(QRect(160, 260, 91, 31))
        self.cmd.setCursor(QCursor(Qt.PointingHandCursor))
        self.cmd.setText('Open Cmd')

        self.joke = QPushButton(self)
        self.joke.setGeometry(QRect(160, 310, 91, 31))
        self.joke.setCursor(QCursor(Qt.PointingHandCursor))
        self.joke.setText('Joke Please!!')

        self.music = QPushButton(self)
        self.music.setGeometry(QRect(290, 260, 91, 31))
        self.music.setCursor(QCursor(Qt.PointingHandCursor))
        self.music.setText('Music')

        self.youtube = QPushButton(self)
        self.youtube.setGeometry(QRect(290, 310, 91, 31))
        self.youtube.setCursor(QCursor(Qt.PointingHandCursor))
        self.youtube.setText('Youtube')

        self.time = QPushButton(self)
        self.time.setGeometry(QRect(20, 310, 91, 31))
        self.time.setCursor(QCursor(Qt.PointingHandCursor))
        self.time.setText('Tell Time')

        self.weather = QPushButton(self)
        self.weather.setGeometry(QRect(420, 310, 91, 31))
        self.weather.setCursor(QCursor(Qt.PointingHandCursor))
        self.weather.setText('Weather')

        self.calculator = QPushButton(self)
        self.calculator.setGeometry(QRect(550, 260, 101, 31))
        self.calculator.setCursor(QCursor(Qt.PointingHandCursor))
        self.calculator.setText('Calculator')

        self.wikipedia = QPushButton(self)
        self.wikipedia.setGeometry(QRect(550, 310, 101, 31))
        self.wikipedia.setCursor(QCursor(Qt.PointingHandCursor))
        self.wikipedia.setText('India Wikipedia')

        self.news = QPushButton(self)
        self.news.setGeometry(QRect(20, 360, 91, 31))
        self.news.setCursor(QCursor(Qt.PointingHandCursor))
        self.news.setText('Latest News')

        self.meaning = QPushButton(self)
        self.meaning.setGeometry(QRect(420, 360, 231, 31))
        self.meaning.setCursor(QCursor(Qt.PointingHandCursor))
        self.meaning.setText('Meaning of Obsolete (or any word)')

        self.harry_potter = QPushButton(self)
        self.harry_potter.setGeometry(QRect(290, 360, 91, 31))
        self.harry_potter.setCursor(QCursor(Qt.PointingHandCursor))
        self.harry_potter.setText('Harry Potter')

        self.translate = QPushButton(self)
        self.translate.setGeometry(QRect(160, 360, 91, 31))
        self.translate.setCursor(QCursor(Qt.PointingHandCursor))
        self.translate.setText('Open Translate')

        self.line = QFrame(self)
        self.line.setGeometry(QRect(20, 200, 661, 16))
        self.line.setFrameShape(QFrame.HLine)
        self.line.setFrameShadow(QFrame.Sunken)

        self.label = QLabel(self)
        self.label.setGeometry(QRect(20, 100, 631, 91))
        self.label.setFont(QFont('Roboto', 12))
        self.label.setTextFormat(Qt.AutoText)
        self.label.setWordWrap(True)

        self.wish()

        # Making the Widgets Functional
        self.query.returnPressed.connect(lambda: self.on_enter())
        self.query.returnPressed.connect(lambda: self.clear_text())

        self.update.clicked.connect(lambda: self.update_func())
        self.music.clicked.connect(lambda: self.music_func())
        self.games.clicked.connect(lambda: self.games_func())
        self.calculator.clicked.connect(lambda: self.calculator_func())
        self.weather.clicked.connect(lambda: self.weather_func())
        self.news.clicked.connect(lambda: self.news_func())
        self.translate.clicked.connect(lambda: self.translate_func())
        self.time.clicked.connect(lambda: self.time_func())
        self.joke.clicked.connect(lambda: self.joke_func())
        self.youtube.clicked.connect(lambda: self.youtube_func())
        self.wikipedia.clicked.connect(lambda: self.wikipedia_func())
        self.chrome.clicked.connect(lambda: self.chrome_func())
        self.cmd.clicked.connect(lambda: self.cmd_func())
        self.meaning.clicked.connect(lambda: self.meaning_func())
        self.harry_potter.clicked.connect(lambda: self.potter_func())

    def pronunciator_func(self):
        self.speak('Opening Pronunciator')
        from pronunciator import Pronunciator
        self.pronunciator_win = Pronunciator()
        self.pronunciator_win.show()

    def pong_func(self):
        import pong

    def notepad_func(self):
        self.speak('Opening Notepad')
        from notepad import Notepad
        self.notepad_win = Notepad()
        self.notepad_win.show()

    def update_func(self):
        os.startfile('Each Version Updates.txt')

    def translate_func(self):
        self.speak(
            'Opening Translate\nPlease Wait as opening Translate may take up to 4-5 seconds'
        )
        from translate import Translate
        self.translate_win = Translate()
        self.translate_win.show()

    def games_func(self):
        self.speak('Opening GameHub')
        from games import GameHub
        self.game_win = GameHub()
        self.game_win.show()

    def weather_func(self):
        self.speak('Opening Weather.')
        from weather import Weather
        self.weather_win = Weather()
        self.weather_win.show()

    def music_func(self):
        self.speak('Opening Muse')
        from music import Music
        self.music_win = Music()
        self.music_win.show()

    def calculator_func(self):
        self.speak('Opening Calculator.')
        from calculator import Calculator
        self.calculator_win = Calculator()
        self.calculator_win.show()

    def news_func(self):
        self.speak('Opening News.')
        from news import News
        self.news_win = News()
        self.news_win.show()
        self.speak(
            'Welcome to News.\nThese are the latest international headlines according to BBC News Network.'
        )

    def chrome_func(self):
        try:
            chrome_path = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
            os.startfile(chrome_path)
            self.speak('Opening Chrome.')
        except Exception:
            self.speak(
                'No Google Chrome installation found on the host device.')

    def cmd_func(self):
        cmd_path = 'C:\\Windows\\system32\\cmd.exe'
        os.startfile(cmd_path)
        self.speak('Opening Command Prompt.')

    def time_func(self):
        question = 'time'
        app_id = 'LLQ4QY-A7K3LEL4T8'
        client = wolframalpha.Client(app_id)
        res = client.query(question)
        answer = next(res.results).text
        self.speak(answer)

    def joke_func(self):
        self.speak(pyjokes.get_joke())

    def youtube_func(self):
        webbrowser.open('https://www.youtube.com')
        self.speak('Opening Youtube.')

    def wikipedia_func(self):
        try:
            self.speak('Searching Wikipedia. Please Wait...')
            query = 'India'.replace('wikipedia', '')
            result = wikipedia.summary(query, sentences=1)
            self.speak('According to Wikipedia...')
            self.speak(result)
        except Exception as e:
            self.speak(e)

    def meaning_func(self):
        question = 'obsolete'
        app_id = 'LLQ4QY-A7K3LEL4T8'
        client = wolframalpha.Client(app_id)
        res = client.query(question)
        answer = next(res.results).text
        self.speak(answer)

    def potter_func(self):
        new = 2
        google_url = "http://google.com/?#q="
        webbrowser.open(google_url + 'Harry Potter', new=new)

    def clear_text(self):
        self.query.clear()

    def on_enter(self):
        user_query = self.query.text().lower()

        if 'wikipedia' in user_query:
            try:
                self.speak('Searching Wikipedia. Please Wait...')
                user_query = user_query.replace('wikipedia', '')
                result = wikipedia.summary(user_query, sentences=1)
                self.speak('According to Wikipedia...')
                self.speak(result)
            except Exception as e:
                self.speak('Please try again later.')
                self.speak(e)

        elif 'youtube' in user_query:
            webbrowser.open('https://www.youtube.com')
            self.speak('Opening Youtube.')

        elif 'google' in user_query:
            webbrowser.open('https://www.google.com/')
            self.speak('Opening Google.')

        elif 'chrome' in user_query:  # You'll have to download google chrome first on your desktop/pc.
            try:
                chrome_path = 'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe'
                os.startfile(chrome_path)
                self.speak('Opening Chrome')
            except Exception:
                self.speak(
                    'No Google Chrome installation found on the host device.')

        elif 'cmd' in user_query:
            cmd_path = 'C:\\Windows\\system32\\cmd.exe'
            os.startfile(cmd_path)
            self.speak('Opening Command Prompt.')

        elif 'control panel' in user_query:

            cp_path = 'C:\\Windows\\system32\\control.exe'
            os.startfile(cp_path)
            self.speak('Opening Control Panel.')

        elif 'bye' in user_query or 'goodbye' in user_query or 'good night' in user_query or 'see you later' in user_query:
            self.speak(random.choice(self.bye))
            sys.exit()

        elif 'hello' in user_query or 'hi' in user_query:
            self.speak(random.choice(self.hello))

        elif 'joke' in user_query:
            self.speak(pyjokes.get_joke())

        elif 'who are you' in user_query:
            self.speak('I am Artigence, your artificial intelligence.')

        elif 'map' in user_query or 'maps' in user_query:
            self.speak('Opening Google Maps.')
            webbrowser.open("https://www.google.com/maps")

        elif 'open calculator' in user_query or 'calculator' in user_query:
            self.calculator_func()

        elif 'news' in user_query:
            self.news_func()
            self.speak(
                'Welcome to News.\nThese are the latest international headlines according to BBC News Network.'
            )

        elif 'weather' in user_query:
            self.weather_func()

        elif 'games' in user_query:
            self.games_func()

        elif 'pronunciator' in user_query or 'pronounce' in user_query:
            self.pronunciator_func()

        elif 'translate' in user_query:
            self.translate_func()

        elif 'music' in user_query:
            self.music_func()

        elif 'notepad' in user_query:
            self.notepad_func()

        else:
            try:
                question = user_query
                app_id = 'LLQ4QY-A7K3LEL4T8'
                client = wolframalpha.Client(app_id)
                res = client.query(question)
                answer = next(res.results).text
                self.label.setText(answer)
                self.label.adjustSize()

            except:
                new = 2
                google_url = "http://google.com/?#q="
                query = user_query
                webbrowser.open(google_url + query, new=new)

    # The A.I. will speak through this function
    def speak(self, audio):
        self.engine = pyttsx3.init('sapi5')
        voices = self.engine.getProperty('voices')
        self.engine.setProperty('voice', voices[1].id)
        self.engine.setProperty('rate', 165)
        self.label.setText(audio)
        self.engine.say(audio)
        self.engine.runAndWait()
        self.label.clear()

    def wish(self):
        hour = int(datetime.now().hour)
        if 0 <= hour < 12:
            self.speak('Good Morning.')
        elif 12 <= hour < 18:
            self.speak('Good Afternoon.')
        else:
            self.speak('Good Evening.')

        self.speak('I am Artigence.')
        self.speak('How may I help you today')

    hello = ['Kon\'nichiwa', 'Ciao', 'Hola', 'Bonjour', 'Hello', 'Hi', 'Hiya']
    bye = [
        'Adios', 'Goodbye', 'Bye-Bye', 'See you next time.', 'Artigence Out.',
        'It was nice talking to you sir. Have a nice day.'
    ]

    def dark(self):
        self.setPalette(self.palette)

    def light(self):
        self.setPalette(self.light_palette)
コード例 #7
0
ファイル: view.py プロジェクト: VasudevDevulapally/biopeaks
class View(QMainWindow):
    def __init__(self, model, controller):
        super().__init__()

        self._model = model
        self._controller = controller
        self.segmentcursor = False
        self.togglecolors = {"#1f77b4": "m", "m": "#1f77b4"}

        #################################################################
        # define GUI layout and connect input widgets to external slots #
        #################################################################

        self.setWindowTitle("biopeaks")
        self.setGeometry(50, 50, 1750, 750)
        self.setWindowIcon(QIcon(":/python_icon.png"))

        # figure0 for signal
        self.figure0 = Figure()
        self.canvas0 = FigureCanvas(self.figure0)
        # Enforce minimum height, otherwise resizing with self.splitter causes
        # mpl to throw an error because figure is resized to height 0. The
        # widget can still be fully collapsed with self.splitter-
        self.canvas0.setMinimumHeight(1)  # in pixels
        self.ax00 = self.figure0.add_subplot(1, 1, 1)
        self.ax00.set_frame_on(False)
        self.figure0.subplots_adjust(left=0.04, right=0.98, bottom=0.25)
        self.line00 = None
        self.scat = None
        self.segmentspan = None

        # figure1 for marker
        self.figure1 = Figure()
        self.canvas1 = FigureCanvas(self.figure1)
        self.canvas1.setMinimumHeight(1)
        self.ax10 = self.figure1.add_subplot(1, 1, 1, sharex=self.ax00)
        self.ax10.get_xaxis().set_visible(False)
        self.ax10.set_frame_on(False)
        self.figure1.subplots_adjust(left=0.04, right=0.98)
        self.line10 = None

        # figure2 for statistics
        self.figure2 = Figure()
        self.canvas2 = FigureCanvas(self.figure2)
        self.canvas2.setMinimumHeight(1)
        self.ax20 = self.figure2.add_subplot(3, 1, 1, sharex=self.ax00)
        self.ax20.get_xaxis().set_visible(False)
        self.ax20.set_frame_on(False)
        self.line20 = None
        self.ax21 = self.figure2.add_subplot(3, 1, 2, sharex=self.ax00)
        self.ax21.get_xaxis().set_visible(False)
        self.ax21.set_frame_on(False)
        self.line21 = None
        self.ax22 = self.figure2.add_subplot(3, 1, 3, sharex=self.ax00)
        self.ax22.get_xaxis().set_visible(False)
        self.ax22.set_frame_on(False)
        self.line22 = None
        self.figure2.subplots_adjust(left=0.04, right=0.98)

        # navigation bar
        self.navitools = CustomNavigationToolbar(self.canvas0, self)

        # peak editing
        self.editcheckbox = QCheckBox("editable", self)
        self.editcheckbox.stateChanged.connect(self._model.set_peakseditable)

        # peak saving batch
        self.savecheckbox = QCheckBox("save during batch processing", self)
        self.savecheckbox.stateChanged.connect(self._model.set_savebatchpeaks)

        # peak auto-correction batch
        self.correctcheckbox = QCheckBox("correct during batch processing",
                                         self)
        self.correctcheckbox.stateChanged.connect(
            self._model.set_correctbatchpeaks)

        # selecting stats for saving
        self.periodcheckbox = QCheckBox("period", self)
        self.periodcheckbox.stateChanged.connect(
            lambda: self.select_stats("period"))
        self.ratecheckbox = QCheckBox("rate", self)
        self.ratecheckbox.stateChanged.connect(
            lambda: self.select_stats("rate"))
        self.tidalampcheckbox = QCheckBox("tidal amplitude", self)
        self.tidalampcheckbox.stateChanged.connect(
            lambda: self.select_stats("tidalamp"))

        # channel selection
        self.sigchanmenulabel = QLabel("biosignal")
        self.sigchanmenu = QComboBox(self)
        self.sigchanmenu.addItem("A1")
        self.sigchanmenu.addItem("A2")
        self.sigchanmenu.addItem("A3")
        self.sigchanmenu.addItem("A4")
        self.sigchanmenu.addItem("A5")
        self.sigchanmenu.addItem("A6")
        self.sigchanmenu.currentTextChanged.connect(self._model.set_signalchan)
        # initialize with default value
        self._model.set_signalchan(self.sigchanmenu.currentText())

        self.markerchanmenulabel = QLabel("marker")
        self.markerchanmenu = QComboBox(self)
        self.markerchanmenu.addItem("none")
        self.markerchanmenu.addItem("I1")
        self.markerchanmenu.addItem("I2")
        self.markerchanmenu.addItem("A1")
        self.markerchanmenu.addItem("A2")
        self.markerchanmenu.addItem("A3")
        self.markerchanmenu.addItem("A4")
        self.markerchanmenu.addItem("A5")
        self.markerchanmenu.addItem("A6")
        self.markerchanmenu.currentTextChanged.connect(
            self._model.set_markerchan)
        # initialize with default value
        self._model.set_markerchan(self.markerchanmenu.currentText())

        # processing mode (batch or single file)
        self.batchmenulabel = QLabel("mode")
        self.batchmenu = QComboBox(self)
        self.batchmenu.addItem("single file")
        self.batchmenu.addItem("multiple files")
        self.batchmenu.currentTextChanged.connect(self._model.set_batchmode)
        self.batchmenu.currentTextChanged.connect(self.toggle_options)
        # initialize with default value
        self._model.set_batchmode(self.batchmenu.currentText())
        self.toggle_options(self.batchmenu.currentText())

        # modality selection
        self.modmenulabel = QLabel("modality")
        self.modmenu = QComboBox(self)
        self.modmenu.addItem("ECG")
        self.modmenu.addItem("PPG")
        self.modmenu.addItem("RESP")
        self.modmenu.currentTextChanged.connect(self._model.set_modality)
        self.modmenu.currentTextChanged.connect(self.toggle_options)
        # initialize with default value
        self._model.set_modality(self.modmenu.currentText())
        self.toggle_options(self.modmenu.currentText())

        # segment selection; this widget can be openend / set visible from
        # the menu and closed from within itself (see mapping of segmentermap);
        # it provides utilities to select a segment from the signal
        self.segmentermap = QSignalMapper(self)
        self.segmenter = QDockWidget("select a segment", self)
        # disable closing such that widget can only be closed by confirming
        # selection or custom button
        self.segmenter.setFeatures(QDockWidget.NoDockWidgetFeatures)
        # Limit number of decimals to four.
        regex = QRegExp("[0-9]*\.?[0-9]{4}")
        validator = QRegExpValidator(regex)

        self.startlabel = QLabel("start")
        self.startedit = QLineEdit()
        self.startedit.setValidator(validator)

        self.endlabel = QLabel("end")
        self.endedit = QLineEdit()
        self.endedit.setValidator(validator)

        segmentfromcursor = QAction(QIcon(":/mouse_icon.png"),
                                    "select with mouse", self)
        segmentfromcursor.triggered.connect(self.enable_segmentedit)
        self.startedit.addAction(segmentfromcursor, QLineEdit.TrailingPosition)
        self.endedit.addAction(segmentfromcursor, QLineEdit.TrailingPosition)

        self.previewedit = QPushButton("preview segment")
        lambdafn = lambda: self._model.set_segment(
            [self.startedit.text(), self.endedit.text()])
        self.previewedit.clicked.connect(lambdafn)

        self.confirmedit = QPushButton("confirm segment")
        self.confirmedit.clicked.connect(self._controller.segment_signal)
        self.confirmedit.clicked.connect(self.segmentermap.map)
        self.segmentermap.setMapping(self.confirmedit, 0)

        self.abortedit = QPushButton("abort segmentation")
        self.abortedit.clicked.connect(self.segmentermap.map)
        # reset the segment to None
        self.segmentermap.setMapping(self.abortedit, 2)

        self.segmenterlayout = QFormLayout()
        self.segmenterlayout.addRow(self.startlabel, self.startedit)
        self.segmenterlayout.addRow(self.endlabel, self.endedit)
        self.segmenterlayout.addRow(self.previewedit)
        self.segmenterlayout.addRow(self.confirmedit)
        self.segmenterlayout.addRow(self.abortedit)
        self.segmenterwidget = QWidget()
        self.segmenterwidget.setLayout(self.segmenterlayout)
        self.segmenter.setWidget(self.segmenterwidget)

        self.segmenter.setVisible(False)
        self.segmenter.setAllowedAreas(Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.RightDockWidgetArea, self.segmenter)

        # Set up dialog to gather user input for custom files.

        regex = QRegExp("[1-9][0-9]")
        validator = QRegExpValidator(regex)

        self.signallabel = QLabel("biosignal column")
        self.signaledit = QLineEdit()
        self.signaledit.setValidator(validator)

        self.markerlabel = QLabel("marker column")
        self.markeredit = QLineEdit()
        self.markeredit.setValidator(validator)

        regex = QRegExp("[0-9]{2}")
        validator = QRegExpValidator(regex)

        self.headerrowslabel = QLabel("number of header rows")
        self.headerrowsedit = QLineEdit()
        self.headerrowsedit.setValidator(validator)

        regex = QRegExp("[0-9]{5}")
        validator = QRegExpValidator(regex)

        self.sfreqlabel = QLabel("sampling rate")
        self.sfreqedit = QLineEdit()
        self.sfreqedit.setValidator(validator)

        self.separatorlabel = QLabel("column separator")
        self.separatormenu = QComboBox(self)
        self.separatormenu.addItem("comma")
        self.separatormenu.addItem("tab")
        self.separatormenu.addItem("colon")
        self.separatormenu.addItem("space")

        self.continuecustomfile = QPushButton("continue loading file")
        self.continuecustomfile.clicked.connect(self.set_customheader)

        self.customfiledialog = QDialog()
        self.customfiledialog.setWindowTitle("custom file info")
        self.customfiledialog.setWindowIcon(QIcon(":/file_icon.png"))
        self.customfiledialog.setWindowFlags(
            Qt.WindowCloseButtonHint
        )  # remove help button by only setting close button
        self.customfilelayout = QFormLayout()
        self.customfilelayout.addRow(self.signallabel, self.signaledit)
        self.customfilelayout.addRow(self.markerlabel, self.markeredit)
        self.customfilelayout.addRow(self.separatorlabel, self.separatormenu)
        self.customfilelayout.addRow(self.headerrowslabel, self.headerrowsedit)
        self.customfilelayout.addRow(self.sfreqlabel, self.sfreqedit)
        self.customfilelayout.addRow(self.continuecustomfile)
        self.customfiledialog.setLayout(self.customfilelayout)

        # set up menubar
        menubar = self.menuBar()

        # signal menu
        signalmenu = menubar.addMenu("biosignal")

        openSignal = signalmenu.addMenu("load")
        openEDF = QAction("EDF", self)
        openEDF.triggered.connect(lambda: self._model.set_filetype("EDF"))
        openEDF.triggered.connect(self._controller.get_fpaths)
        openSignal.addAction(openEDF)
        openOpenSignals = QAction("OpenSignals", self)
        openOpenSignals.triggered.connect(
            lambda: self._model.set_filetype("OpenSignals"))
        openOpenSignals.triggered.connect(self._controller.get_fpaths)
        openSignal.addAction(openOpenSignals)
        openCustom = QAction("Custom", self)
        openCustom.triggered.connect(
            lambda: self._model.set_filetype("Custom"))
        openCustom.triggered.connect(lambda: self.customfiledialog.exec_())
        openSignal.addAction(openCustom)

        segmentSignal = QAction("select segment", self)
        segmentSignal.triggered.connect(self.segmentermap.map)
        self.segmentermap.setMapping(segmentSignal, 1)
        signalmenu.addAction(segmentSignal)

        self.segmentermap.mapped.connect(self.toggle_segmenter)

        saveSignal = QAction("save", self)
        saveSignal.triggered.connect(self._controller.get_wpathsignal)
        signalmenu.addAction(saveSignal)

        # peak menu
        peakmenu = menubar.addMenu("peaks")

        findPeaks = QAction("find", self)
        findPeaks.triggered.connect(self._controller.find_peaks)
        peakmenu.addAction(findPeaks)

        autocorrectPeaks = QAction("autocorrect", self)
        autocorrectPeaks.triggered.connect(self._controller.autocorrect_peaks)
        peakmenu.addAction(autocorrectPeaks)

        savePeaks = QAction("save", self)
        savePeaks.triggered.connect(self._controller.get_wpathpeaks)
        peakmenu.addAction(savePeaks)

        loadPeaks = QAction("load", self)
        loadPeaks.triggered.connect(self._controller.get_rpathpeaks)
        peakmenu.addAction(loadPeaks)

        # stats menu
        statsmenu = menubar.addMenu("statistics")

        calculateStats = QAction("calculate", self)
        calculateStats.triggered.connect(self._controller.calculate_stats)
        statsmenu.addAction(calculateStats)

        saveStats = QAction("save", self)
        saveStats.triggered.connect(self._controller.get_wpathstats)
        statsmenu.addAction(saveStats)

        # set up status bar to display error messages and current file path
        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        self.progressBar = QProgressBar(self)
        self.progressBar.setRange(0, 1)
        self.statusBar.addPermanentWidget(self.progressBar)
        self.currentFile = QLabel()
        self.statusBar.addPermanentWidget(self.currentFile)

        # set up the central widget containing the plot and navigationtoolbar
        self.centwidget = QWidget()
        self.setCentralWidget(self.centwidget)

        # connect canvas0 to keyboard and mouse input for peak editing;
        # only widgets (e.g. canvas) that currently have focus capture
        # keyboard input: "You must enable keyboard focus for a widget if
        # it processes keyboard events."
        self.canvas0.setFocusPolicy(Qt.ClickFocus)
        self.canvas0.setFocus()
        self.canvas0.mpl_connect("key_press_event",
                                 self._controller.edit_peaks)
        self.canvas0.mpl_connect("button_press_event", self.get_xcursor)

        # arrange the three figure canvases in splitter object
        self.splitter = QSplitter(Qt.Vertical)
        # setting opaque resizing to false is important, since resizing gets
        # very slow otherwise once axes are populated
        self.splitter.setOpaqueResize(False)
        self.splitter.addWidget(self.canvas0)
        self.splitter.addWidget(self.canvas1)
        self.splitter.addWidget(self.canvas2)
        self.splitter.setChildrenCollapsible(False)

        # define GUI layout
        self.vlayout0 = QVBoxLayout(self.centwidget)
        self.vlayout1 = QVBoxLayout()
        self.vlayoutA = QFormLayout()
        self.vlayoutB = QFormLayout()
        self.vlayoutC = QVBoxLayout()
        self.vlayoutD = QVBoxLayout()
        self.hlayout0 = QHBoxLayout()

        self.optionsgroupA = QGroupBox("processing options")
        self.vlayoutA.addRow(self.modmenulabel, self.modmenu)
        self.vlayoutA.addRow(self.batchmenulabel, self.batchmenu)
        self.optionsgroupA.setLayout(self.vlayoutA)

        self.optionsgroupB = QGroupBox("channels")
        self.vlayoutB.addRow(self.sigchanmenulabel, self.sigchanmenu)
        self.vlayoutB.addRow(self.markerchanmenulabel, self.markerchanmenu)
        self.optionsgroupB.setLayout(self.vlayoutB)

        self.optionsgroupC = QGroupBox("peaks")
        self.vlayoutC.addWidget(self.editcheckbox)
        self.vlayoutC.addWidget(self.savecheckbox)
        self.vlayoutC.addWidget(self.correctcheckbox)
        self.optionsgroupC.setLayout(self.vlayoutC)

        self.optionsgroupD = QGroupBox("select statistics for saving")
        self.vlayoutD.addWidget(self.periodcheckbox)
        self.vlayoutD.addWidget(self.ratecheckbox)
        self.vlayoutD.addWidget(self.tidalampcheckbox)
        self.optionsgroupD.setLayout(self.vlayoutD)

        self.vlayout1.addWidget(self.optionsgroupA)
        self.vlayout1.addWidget(self.optionsgroupB)
        self.vlayout1.addWidget(self.optionsgroupC)
        self.vlayout1.addWidget(self.optionsgroupD)
        self.optionsgroupwidget = QWidget()
        self.optionsgroupwidget.setLayout(self.vlayout1)
        self.optionsgroup = QDockWidget("configurations", self)
        self.optionsgroup.setAllowedAreas(Qt.LeftDockWidgetArea)
        self.toggleoptionsgroup = self.optionsgroup.toggleViewAction()
        self.toggleoptionsgroup.setText("show/hide configurations")
        menubar.addAction(self.toggleoptionsgroup)
        self.optionsgroup.setWidget(self.optionsgroupwidget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.optionsgroup)

        self.vlayout0.addWidget(self.splitter)

        self.hlayout0.addWidget(self.navitools)
        self.vlayout0.addLayout(self.hlayout0)

        ##############################################
        # connect output widgets to external signals #
        ##############################################
        self._model.signal_changed.connect(self.plot_signal)
        self._model.marker_changed.connect(self.plot_marker)
        self._model.peaks_changed.connect(self.plot_peaks)
        self._model.period_changed.connect(self.plot_period)
        self._model.rate_changed.connect(self.plot_rate)
        self._model.tidalamp_changed.connect(self.plot_tidalamp)
        self._model.path_changed.connect(self.display_path)
        self._model.segment_changed.connect(self.plot_segment)
        self._model.status_changed.connect(self.display_status)
        self._model.progress_changed.connect(self.display_progress)
        self._model.model_reset.connect(self.reset_plot)

    ###########
    # methods #
    ###########

    def plot_signal(self, value):
        self.ax00.clear()
        self.ax00.relim()
        # reset navitools history
        self.navitools.update()
        self.line00 = self.ax00.plot(self._model.sec, value, zorder=1)
        self.ax00.set_xlabel("seconds", fontsize="large", fontweight="heavy")
        self.canvas0.draw()
#        print("plot_signal listening")
#        print(self.ax0.collections, self.ax0.patches, self.ax0.artists)

    def plot_peaks(self, value):
        # self.scat is listed in ax.collections
        if self.ax00.collections:
            self.ax00.collections[0].remove()
        self.scat = self.ax00.scatter(self._model.sec[value],
                                      self._model.signal[value],
                                      c="m",
                                      zorder=2)
        self.canvas0.draw()
#        print("plot_peaks listening")
#        print(self.ax0.collections, self.ax0.patches, self.ax0.artists)

    def plot_segment(self, value):
        # If an invalid signal has been selected reset the segmenter interface.
        if value is None:
            self.toggle_segmenter(1)
            return
        if self.ax00.patches:  # self.segementspan is listed in ax.patches
            self.ax00.patches[0].remove()
        self.segmentspan = self.ax00.axvspan(value[0],
                                             value[1],
                                             color="m",
                                             alpha=0.25)
        self.canvas0.draw()
        self.confirmedit.setEnabled(True)
#        print(self.ax0.collections, self.ax0.patches, self.ax0.artists)

    def plot_marker(self, value):
        self.ax10.clear()
        self.ax10.relim()
        self.line10 = self.ax10.plot(value[0], value[1])
        self.canvas1.draw()
#        print("plot_marker listening")

    def plot_period(self, value):
        self.ax20.clear()
        self.ax20.relim()
        self.navitools.home()
        if self._model.savestats["period"]:
            self.line20 = self.ax20.plot(self._model.sec, value, c="m")
        else:
            self.line20 = self.ax20.plot(self._model.sec, value)
        self.ax20.set_ylim(bottom=min(value), top=max(value))
        self.ax20.set_title("period", pad=0, fontweight="heavy")
        self.ax20.grid(True, axis="y")
        self.navitools.update()
        self.canvas2.draw()
#        print("plot_period listening")

    def plot_rate(self, value):
        self.ax21.clear()
        self.ax21.relim()
        self.navitools.home()
        if self._model.savestats["rate"]:
            self.line21 = self.ax21.plot(self._model.sec, value, c="m")
        else:
            self.line21 = self.ax21.plot(self._model.sec, value)
        self.ax21.set_ylim(bottom=min(value), top=max(value))
        self.ax21.set_title("rate", pad=0, fontweight="heavy")
        self.ax21.grid(True, axis="y")
        self.navitools.update()
        self.canvas2.draw()
#        print("plot_rate listening")

    def plot_tidalamp(self, value):
        self.ax22.clear()
        self.ax22.relim()
        self.navitools.home()
        if self._model.savestats["tidalamp"]:
            self.line22 = self.ax22.plot(self._model.sec, value, c="m")
        else:
            self.line22 = self.ax22.plot(self._model.sec, value)
        self.ax22.set_ylim(bottom=min(value), top=max(value))
        self.ax22.set_title("amplitude", pad=0, fontweight="heavy")
        self.ax22.grid(True, axis="y")
        self.navitools.update()
        self.canvas2.draw()
#        print("plot_tidalamp listening")

    def display_path(self, value):
        self.currentFile.setText(value)

    def display_status(self, status):
        # display status until new status is set
        self.statusBar.showMessage(status)

    def display_progress(self, value):
        # if value is 0, the progressbar indicates a busy state
        self.progressBar.setRange(0, value)

    def toggle_segmenter(self, value):
        if not self._model.loaded:
            return
        # Open segmenter when called from signalmenu or clear segmenter
        # upon selection of invalid segment.
        if value == 1:
            self.segmenter.setVisible(True)
            self.confirmedit.setEnabled(False)
            self.startedit.clear()
            self.endedit.clear()
            if self.ax00.patches:
                self.ax00.patches[0].remove()
                self.canvas0.draw()
        # Close segmenter after segment has been confirmed.
        elif value == 0:
            self.segmenter.setVisible(False)
            if self.ax00.patches:
                self.ax00.patches[0].remove()
                self.canvas0.draw()
        # Close segmenter after segmentation has been aborted (reset
        # segment).
        elif value == 2:
            self._model.set_segment([0,
                                     0])  # This will reset the model to None
            self.segmenter.setVisible(False)
            if self.ax00.patches:
                self.ax00.patches[0].remove()
                self.canvas0.draw()

    def enable_segmentedit(self):
        # disable peak editing to avoid interference
        self.editcheckbox.setChecked(False)
        if self.startedit.hasFocus():
            self.segmentcursor = "start"
        elif self.endedit.hasFocus():
            self.segmentcursor = "end"

    def set_customheader(self):
        """Populate the customheader with inputs from the customfiledialog"""

        # Check if one of the mandatory fields is missing.
        mandatoryfields = self.signaledit.text() and self.headerrowsedit.text(
        ) and self.sfreqedit.text()

        if not mandatoryfields:
            self._model.status = (
                "Please provide values for 'biosignal column'"
                ", 'number of header rows' and 'sampling"
                " rate'.")
            return

        seps = {"comma": ",", "tab": "\t", "colon": ":", "space": " "}
        self._model.customheader = dict.fromkeys(
            self._model.customheader, None
        )  # reset header here since it cannot be reset in controller.get_fpaths()

        self._model.customheader["signalidx"] = int(self.signaledit.text())
        self._model.customheader["skiprows"] = int(self.headerrowsedit.text())
        self._model.customheader["sfreq"] = int(self.sfreqedit.text())
        self._model.customheader["separator"] = seps[
            self.separatormenu.currentText()]
        if self.markeredit.text():  # not mandatory
            self._model.customheader["markeridx"] = int(self.markeredit.text())

        self.customfiledialog.done(QDialog.Accepted)  # close the dialog window
        self._controller.get_fpaths()  # move on to file selection

    def get_xcursor(self, event):
        # event.button 1 corresponds to left mouse button
        if event.button != 1:
            return
        # limit number of decimal places to two
        if self.segmentcursor == "start":
            self.startedit.selectAll()
            self.startedit.insert("{:.2f}".format(event.xdata))
        elif self.segmentcursor == "end":
            self.endedit.selectAll()
            self.endedit.insert("{:.2f}".format(event.xdata))
        # disable segment cursor again after value has been set
        self.segmentcursor = False

    def select_stats(self, event):
        """
        select or deselect statistics to be saved; toggle boolean with xor
        operator ^=, toggle color with dictionary
        """
        self._model.savestats[event] ^= True
        line = None
        if event == "period":
            if self.line20:
                line = self.line20[0]
        elif event == "rate":
            if self.line21:
                line = self.line21[0]
        elif event == "tidalamp":
            if self.line22:
                line = self.line22[0]
        if line:
            line.set_color(self.togglecolors[line.get_color()])
        self.canvas2.draw()

    def toggle_options(self, event):
        if event in ["ECG", "PPG"]:
            self.tidalampcheckbox.setEnabled(False)
            self.tidalampcheckbox.setChecked(False)
            self.ax22.set_visible(False)
            self.canvas2.draw()
        elif event == "RESP":
            self.tidalampcheckbox.setEnabled(True)
            self.ax22.set_visible(True)
            self.canvas2.draw()
        elif event == "multiple files":
            self.editcheckbox.setEnabled(False)
            self.editcheckbox.setChecked(False)
            self.savecheckbox.setEnabled(True)
            self.correctcheckbox.setEnabled(True)
            self.markerchanmenu.setEnabled(False)
        elif event == "single file":
            self.editcheckbox.setEnabled(True)
            self.markerchanmenu.setEnabled(True)
            self.savecheckbox.setEnabled(False)
            self.savecheckbox.setChecked(False)
            self.correctcheckbox.setEnabled(False)
            self.correctcheckbox.setChecked(False)

    def reset_plot(self):
        self.ax00.clear()
        self.ax00.relim()
        self.line00 = None
        self.scat = None
        self.segmentspan = None
        self.ax10.clear()
        self.ax10.relim()
        self.line10 = None
        self.ax20.clear()
        self.ax20.relim()
        self.line20 = None
        self.ax21.clear()
        self.ax21.relim()
        self.line21 = None
        self.ax22.clear()
        self.ax22.relim()
        self.line22 = None
        self.canvas0.draw()
        self.canvas1.draw()
        self.canvas2.draw()
        self.navitools.update()
        self.currentFile.clear()
コード例 #8
0
ファイル: main.py プロジェクト: cmiles33/waltersAuto
class Form(QDialog):
    def __init__(self, parent=None):
        super(Form, self).__init__(parent)
        self.setWindowTitle(
            "Automation.... WITH KITTENS!!!! AHHH I LOVE KITTENS")
        # Create Widgets
        self.fileLoader = QPushButton("Load Files")
        self.stopButton = QPushButton("Stop")
        self.fileBox = QComboBox()  # Holds name of files
        self.filePreview = QTextBrowser()  # Preview Files
        self.loadingBar = QProgressBar(self)
        self.preview = QTextBrowser()
        self.ConfirmButton = QPushButton("Start")
        # Variable Creation Area
        self.pictureDic = {}  # Holds the tings
        self.timerBool = bool
        # Create layout and add widgets
        layout = QVBoxLayout()
        # Design Area
        self.label2 = QLabel()
        self.label2.setText("Automating Kittens!")
        self.label2.setStyleSheet(
            "QLabel { background-color : black; color : white; font-size: 20px; text-align : "
            "center; }")
        self.label = QLabel()
        pixmap = QPixmap('pictures/helloKitten.png')
        w = 440
        h = 200
        pixmap = pixmap.scaled(w,
                               h,
                               aspectMode=Qt.IgnoreAspectRatio,
                               mode=Qt.FastTransformation)
        self.timer = QBasicTimer()
        self.step = 0
        self.label.setPixmap(pixmap)

        # Adding widgets to the layout
        layout.addWidget(self.label2)
        layout.addWidget(self.label)
        layout.addWidget(self.fileLoader)
        layout.addWidget(self.fileBox)
        layout.addWidget(self.filePreview)
        layout.addWidget(self.ConfirmButton)
        layout.addWidget(self.stopButton)
        self.loadingBar.setStyleSheet(
            "QProgressBar::chunk {background-color: red}")
        layout.addWidget(self.loadingBar)
        # Enable Minimize and maximize
        self.setWindowFlag(Qt.WindowMinimizeButtonHint, True)
        self.setWindowFlag(Qt.WindowMaximizeButtonHint, True)
        # Set layout
        self.setLayout(layout)
        p = self.palette()
        p.setColor(self.foregroundRole(), QColor(10, 10, 10, 127))
        p.setColor(self.backgroundRole(), QColor(0, 0, 127, 127))
        self.setPalette(p)
        self.setFixedWidth(450)
        self.setFixedHeight(700)
        # Connecting functions to buttons
        self.fileLoader.clicked.connect(self.loadFiles)
        self.ConfirmButton.clicked.connect(self.newStart)
        self.stopButton.clicked.connect(self.stop)
        self.fileBox.activated.connect(self.updatePreview)

    def start(self):
        print("Ready to Go")
        self.loadingBar.setStyleSheet(
            "QProgressBar::chunk {background-color: gold } QProgressBar {text-align: center}"
        )
        if bool(self.pictureDic) is False:
            self.filePreview.append("**** Empty Files **** \n")
            self.filePreview.append("**** Please load Files **** \n")
            self.timer.stop()
        else:
            self.filePreview.append("**** Starting Picture Search **** \n")
            self.searchThread = threadedSearch.thread_with_exception(
                "Searching", self.pictureDic)
            self.searchThread.start()
        pixmap = QPixmap('pictures/pawwingKitten.jpg')
        w = 440
        h = 200
        pixmap = pixmap.scaled(w,
                               h,
                               aspectMode=Qt.IgnoreAspectRatio,
                               mode=Qt.FastTransformation)
        self.label.setPixmap(pixmap)

    def loadFiles(self):
        print("We gone load them files doh")
        self.filePreview.append("**** Files Loaded **** \n")
        self.fileBox.clear()
        self.pictureDic.clear()
        with os.scandir('testpictures/') as files:
            for file in files:
                print(file.path)
                print(file.name)
                self.pictureDic.update({file.name: file.path})
                self.fileBox.addItem(file.name)
                self.filePreview.append("{} \n".format(file.name))
        self.filePreview.append("**** Files done loading **** \n")

    def newStart(self):
        pixmap = QPixmap('pictures/roaringKitten.jpg')
        w = 440
        h = 200
        pixmap = pixmap.scaled(w,
                               h,
                               aspectMode=Qt.IgnoreAspectRatio,
                               mode=Qt.FastTransformation)
        self.label.setPixmap(pixmap)
        self.timerBool = True
        global stepper
        stepper = 0
        self.loadingBar.setValue(0)
        self.loadingBar.setStyleSheet(
            "QProgressBar::chunk {background-color: red;} QProgressBar {text-align: center}"
        )
        self.startTracking()

    def updatePreview(self):
        self.label.clear()
        location = self.pictureDic[self.fileBox.currentText()]
        pixmap = QPixmap('{}'.format(location))
        w = 440
        h = 200
        pixmap = pixmap.scaled(w,
                               h,
                               aspectMode=Qt.IgnoreAspectRatio,
                               mode=Qt.FastTransformation)
        self.timer = QBasicTimer()
        self.step = 0
        self.label.setPixmap(pixmap)

    def startTracking(self):
        self.timer.start(80, self)

    def stop(self):
        self.timer.stop()
        try:
            self.searchThread.raise_exception()
            self.searchThread.join()
            self.filePreview.append("**** Sucessfully Killed thread **** \n")
        except:
            self.filePreview.append("**** No thread to kill! **** \n")
        pixmap = QPixmap('pictures/sadkitten.jpg')
        w = 440
        h = 200
        pixmap = pixmap.scaled(w,
                               h,
                               aspectMode=Qt.IgnoreAspectRatio,
                               mode=Qt.FastTransformation)
        self.label.setPixmap(pixmap)
        self.loadingBar.setValue(0)

    def timerEvent(self, event):
        if self.timerBool is True:
            global stepper
            stepper += 1
            self.loadingBar.setValue(stepper)
            if self.loadingBar.value() == 100:
                self.start()
                self.timerBool = False
                self.loadingBar.setStyleSheet(
                    "QProgressBar::chunk {background-color: green;} QProgressBar {text-align: center}"
                )
        else:
            try:
                printingMess = self.searchThread.getMessage()
                if printingMess != "":
                    self.filePreview.append("{} \n".format(printingMess))
            except:
                self.filePreview.append(
                    " *** No information from Thread *** \n")
コード例 #9
0
ファイル: sub.py プロジェクト: kiwitreekor/namuplant
class ConfigDialog(QDialog):
    config_changed = Signal()

    def __init__(self, requester, config, parent=None):
        super().__init__(parent)
        self.requester = requester
        self.requester.pin_needed.connect(self.input_pin)
        self.requester.umi_made.connect(self.write_umi)
        self.requester.msg_passed.connect(self.error_msg)
        self.config = config
        self.lbl_id = QLabel('계정명')
        self.lbl_id.setAlignment(Qt.AlignCenter)
        self.lbl_pw = QLabel('비밀번호')
        self.lbl_pw.setAlignment(Qt.AlignCenter)
        self.lbl_umi = QLabel('umi 쿠키')
        self.lbl_umi.setAlignment(Qt.AlignCenter)
        self.lbl_ua = QLabel('유저 에이전트')
        self.lbl_ua.setAlignment(Qt.AlignCenter)
        self.lbl_delay = QLabel('저속 간격')
        self.lbl_delay.setAlignment(Qt.AlignCenter)
        self.lbl_msg = QLabel('')
        self.line_id = QLineEdit()
        self.line_pw = QLineEdit()
        self.line_pw.setEchoMode(QLineEdit.PasswordEchoOnEdit)
        self.line_umi = QLineEdit()
        self.line_umi.setPlaceholderText('로그인 시 자동 입력')
        self.line_ua = QLineEdit()
        self.line_delay = QDoubleSpinBox()
        self.line_delay.setMinimum(3)
        self.line_delay.setDecimals(1)
        self.line_delay.setSuffix('초')
        self.line_delay.setSingleStep(0.1)
        self.btn_save = NPButton('저장', 10, self)
        self.btn_save.clicked.connect(self.save)
        self.btn_cancel = NPButton('취소', 10, self)
        self.btn_cancel.clicked.connect(self.reject)
        self.btn_get_umi = NPButton('로그인', 10, self)
        self.btn_get_umi.setSizePolicy(QSizePolicy.Preferred,
                                       QSizePolicy.MinimumExpanding)
        self.btn_get_umi.clicked.connect(self.get_umi)
        grid = QGridLayout()
        grid.addWidget(self.lbl_id, 0, 0, 1, 1)
        grid.addWidget(self.line_id, 0, 1, 1, 6)
        grid.addWidget(self.lbl_pw, 1, 0, 1, 1)
        grid.addWidget(self.line_pw, 1, 1, 1, 6)
        grid.addWidget(self.btn_get_umi, 0, 7, 2, 2)
        grid.addWidget(self.lbl_umi, 2, 0, 1, 1)
        grid.addWidget(self.line_umi, 2, 1, 1, 8)
        grid.addWidget(self.lbl_ua, 3, 0, 1, 1)
        grid.addWidget(self.line_ua, 3, 1, 1, 8)
        grid.addWidget(self.lbl_delay, 4, 0, 1, 1)
        grid.addWidget(self.line_delay, 4, 1, 1, 8)
        grid.addWidget(self.lbl_msg, 5, 0, 1, 4)
        grid.addWidget(self.btn_save, 5, 5, 1, 2)
        grid.addWidget(self.btn_cancel, 5, 7, 1, 2)
        self.setLayout(grid)
        self.input_dialog = InputDialog(self)
        self.input_dialog.input.setInputMask('999999')
        self.setWindowTitle('개인정보')
        self.setWindowIcon(QIcon('icon.png'))
        self.setStyleSheet('font: 10pt \'맑은 고딕\'')
        self.setWindowFlag(Qt.WindowContextHelpButtonHint, False)
        self.c_login, self.c_work = {}, {}

    @Slot(str)
    def error_msg(self, t):
        self.lbl_msg.setText(t)

    def load(self):
        self.line_id.setText(self.config.c['login']['ID'])
        self.line_pw.setText(self.config.c['login']['PW'])
        self.line_umi.setText(self.config.c['login']['UMI'])
        self.line_ua.setText(self.config.c['login']['UA'])
        self.line_ua.setCursorPosition(0)
        self.line_delay.setValue(float(self.config.c['work']['DELAY']))
        self.lbl_msg.clear()
        ok = self.exec_()
        if ok == QDialog.Accepted:
            self.config_changed.emit()

    def save(self):
        self.config.save(login={
            'ID': self.line_id.text().strip(),
            'PW': self.line_pw.text().strip(),
            'UMI': self.line_umi.text().strip(),
            'UA': self.line_ua.text().strip()
        },
                         delay=self.line_delay.value())
        self.accept()

    def get_umi(self):
        self.lbl_msg.setText('로그인 시도...')
        self.line_umi.clear()
        self.input_dialog.input.clear()
        self.requester.init_login(self.line_id.text().strip(),
                                  self.line_pw.text().strip())

    @Slot(str)
    def write_umi(self, umi):
        self.line_umi.setText(umi)

    @Slot(str)
    def input_pin(self, mail):
        pin, ok = self.input_dialog.get_text('로그인 PIN 입력',
                                             f'이메일({mail})로 전송된 PIN을 입력해주세요.')
        if ok:
            if pin:
                self.requester.typed_pin = pin
            else:
                self.requester.typed_pin = 'nothing'
        else:
            self.requester.typed_pin = 'deny'
コード例 #10
0
class View(QWidget):
    def __init__(self, db):
        super().__init__()
        self.db = db
        self.pragmas = Pragmas.unchanged()
        self.dirty = False
        self.make_widgets()
        self.make_layout()
        self.make_connections()

    def make_widgets(self):
        self.userVersionSpinbox = QSpinBox()
        self.userVersionSpinbox.setRange(0, MAX_I32)
        # TODO make all widgets
        self.pathLabel = QLabel()
        self.configLabel = QLabel(Config.filename())

    def make_layout(self):
        form = QFormLayout()
        form.addRow('User Version', self.userVersionSpinbox)
        # TODO add all widgets
        self._add_grouped(form, 'Database Path', self.pathLabel)
        self._add_grouped(form, 'Configuration File', self.configLabel)
        self.setLayout(form)

    def _add_grouped(self, form, title, widget):
        box = QGroupBox(title)
        vbox = QVBoxLayout()
        vbox.addWidget(widget)
        box.setLayout(vbox)
        form.addRow(box)

    def make_connections(self):
        self.userVersionSpinbox.valueChanged.connect(self.on_user_version)
        # TODO connect all widgets (excl. configLabel)

    def on_user_version(self):
        self.pragmas.user_version = self.userVersionSpinbox.value()
        self.dirty = True

    def refresh(self):
        self.clear()
        if bool(self.db):
            pragmas = self.db.pragmas()
            with BlockSignals(self):
                self.userVersionSpinbox.setValue(pragmas.user_version)
                # TODO refresh all widgets (excl. configLabel)
                path = str(pathlib.Path(self.db.filename).parent)
                if not path.endswith(('/', '\\')):
                    path += os.sep
                self.pathLabel.setText(path)
        self.dirty = False

    def clear(self):
        with BlockSignals(self):
            self.userVersionSpinbox.setValue(0)
            # TODO clear all widgets (excl. configLabel)
            self.pathLabel.clear()
        self.dirty = False

    def save(self, *, closing=False):
        saved = False
        errors = False
        if self.dirty and bool(self.db):
            if errors := self.db.pragmas_save(self.pragmas):
                if not closing:
                    error = '\n'.join(errors)
                    QMessageBox.warning(self, f'Pragma error — {APPNAME}',
                                        f'Failed to save pragmas:\n{error}')
            else:
                saved = True
                self.dirty = False
        return saved
コード例 #11
0
class AbrechnungenView(QWidget, ModifyInfo):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        ModifyInfo.__init__(self)
        #self.setWindowTitle( "Sonstige Ausgaben: Rechnungen, Abgaben, Gebühren etc." )
        self._mainLayout = QtWidgets.QGridLayout(self)
        self._toolbarLayout = QHBoxLayout()
        self._btnSave = QPushButton(self)

        self._tvAbrechnungen = TableViewExt(self)

        self._buchungsdatumLayout = QHBoxLayout()
        self._sdAbrechnungsdatum = SmartDateEdit(self)
        self._btnAddDayToAbrechnungsdatum = QPushButton(self)
        self._btnClearAbrechnungsdatum = QPushButton(self)

        self._sdBuchungsdatum = SmartDateEdit(self)
        self._btnAddDay = QPushButton(self)
        self._btnClearBuchungsdatum = QPushButton(self)

        self._abrechnungInfoLayout = QHBoxLayout()
        self._name = QLabel(self, text="")
        self._cboAbrechnungsjahr = QtWidgets.QComboBox(self)
        self._feBetrag: FloatEdit = FloatEdit(self)

        self._teBemerkung = QTextEdit(self)
        self._btnOk = QPushButton(self)
        self._btnClear = QPushButton(self)
        # actions für ContextMenu
        #self._contextMenuActions:List[QAction] = None
        # Callbacks
        self._abrechnungsjahrChangedCallback = None
        self._saveActionCallback = None

        self._submitChangesCallback = None
        self._justEditing: XAbrechnung = None
        self._suspendCallbacks = False

        self._createGui()
        self.connectWidgetsToChangeSlot(self.onChange, self.onResetChangeFlag)

    def _createGui(self):
        self._assembleToolbar()
        self._mainLayout.addLayout(self._toolbarLayout,
                                   0,
                                   0,
                                   alignment=Qt.AlignLeft)
        self._toolbarLayout.addStretch(50)
        ### tableView
        tv = self._tvAbrechnungen
        tv.setSelectionBehavior(QAbstractItemView.SelectRows)
        tv.setAlternatingRowColors(True)
        tv.verticalHeader().setVisible(False)
        tv.horizontalHeader().setMinimumSectionSize(0)
        self._mainLayout.addWidget(tv, 1, 0, 1, 1)
        #Buchungsdatum
        self._assembleBuchungsdatum()
        self._mainLayout.addLayout(self._buchungsdatumLayout,
                                   2,
                                   0,
                                   alignment=Qt.AlignLeft)
        # Name, Abrechnungsjahr, Betrag, Bemerkung, Buttons
        self._assembleAbrechnungInfo()
        self._mainLayout.addLayout(self._abrechnungInfoLayout,
                                   3,
                                   0,
                                   alignment=Qt.AlignLeft)
        # self._assembleRechnungsdaten()
        # self._mainLayout.addLayout( self._editRechnungLineLayout, 4, 0, alignment=Qt.AlignLeft )

    def _assembleToolbar(self):
        #### Combobox Buchungsjahr
        font = QFont("Arial", 14, weight=QFont.Bold)
        self._cboAbrechnungsjahr.setFont(font)
        self._cboAbrechnungsjahr.setToolTip(
            "Das hier eingestellte Jahr bestimmt die NK-Abrechnungen, die in der Tabelle angezeigt werden."
        )
        self._cboAbrechnungsjahr.currentIndexChanged.connect(
            self.onAbrechnungsjahrChanged)
        self._toolbarLayout.addWidget(self._cboAbrechnungsjahr,
                                      stretch=0,
                                      alignment=Qt.AlignLeft)

        #### save button
        btn = self._btnSave
        btn.clicked.connect(self.onSave)
        btn.setFlat(True)
        btn.setEnabled(False)
        btn.setToolTip("Änderungen dieser View speichern")
        icon = QIcon("./images/save_30.png")
        btn.setIcon(icon)
        size = QSize(30, 30)
        btn.setFixedSize(size)
        iconsize = QSize(30, 30)
        btn.setIconSize(iconsize)
        self._toolbarLayout.addWidget(btn, stretch=0)

    def _assembleBuchungsdatum(self):
        lbl = QLabel(self, text="Abrechng.datum: ")
        lbl.setFixedWidth(130)
        self._buchungsdatumLayout.addWidget(lbl)
        self._sdAbrechnungsdatum.setFixedWidth(85)
        self._sdAbrechnungsdatum.setToolTip("Datum der Forderung. Mussfeld.")
        self._buchungsdatumLayout.addWidget(self._sdAbrechnungsdatum)
        size = QSize(25, 25)
        self._btnAddDayToAbrechnungsdatum.setIcon(QIcon("./images/plus.png"))
        self._btnAddDayToAbrechnungsdatum.setFixedSize(size)
        self._btnAddDayToAbrechnungsdatum.setToolTip(
            "Abrechnungsdatum um 1 Tag erhöhen")
        self._btnAddDayToAbrechnungsdatum.clicked.connect(
            self.onAddDayToAbrechnungsdatum)
        self._buchungsdatumLayout.addWidget(self._btnAddDayToAbrechnungsdatum)
        self._btnClearAbrechnungsdatum.setIcon(QIcon("./images/cancel.png"))
        self._btnClearAbrechnungsdatum.setFixedSize(size)
        self._btnClearAbrechnungsdatum.setToolTip("Forderungsdatum löschen")
        self._btnClearAbrechnungsdatum.clicked.connect(
            self.onClearForderungsdatum)
        self._buchungsdatumLayout.addWidget(self._btnClearAbrechnungsdatum)

        lbl = QLabel(self, text="Buchungsdatum: ")
        lbl.setFixedWidth(120)
        self._buchungsdatumLayout.addWidget(lbl)
        self._sdBuchungsdatum.setFixedWidth(85)
        self._sdBuchungsdatum.setToolTip(
            "Buchungsdatum. Kann leer bleiben, wenn Buchung noch nicht erfolgt ist"
        )
        self._buchungsdatumLayout.addWidget(self._sdBuchungsdatum)
        size = QSize(25, 25)
        self._btnAddDay.setIcon(QIcon("./images/plus.png"))
        self._btnAddDay.setFixedSize(size)
        self._btnAddDay.setToolTip("Buchungsdatum um 1 Tag erhöhen")
        self._btnAddDay.clicked.connect(self.onAddDayToBuchungsdatum)
        self._buchungsdatumLayout.addWidget(self._btnAddDay)
        self._btnClearBuchungsdatum.setIcon(QIcon("./images/cancel.png"))
        self._btnClearBuchungsdatum.setFixedSize(size)
        self._btnClearBuchungsdatum.setToolTip("Buchungsdatum löschen")
        self._btnClearBuchungsdatum.clicked.connect(self.onClearBuchungsdatum)
        self._buchungsdatumLayout.addWidget(self._btnClearBuchungsdatum)

    def _assembleAbrechnungInfo(self):
        lbl = QLabel(self, text="Mieter/Verwalter: ")
        lbl.setFixedWidth(130)
        self._abrechnungInfoLayout.addWidget(lbl)

        self._name.setFrameShape(QFrame.Panel)
        self._name.setFrameShadow(QFrame.Sunken)
        self._name.setFixedWidth(150)
        self._name.setFixedHeight(25)
        self._abrechnungInfoLayout.addWidget(self._name)

        # Gutschrift/Nachzahlung
        lbl = QLabel(self, text="Betrag: ")
        self._abrechnungInfoLayout.addWidget(lbl)
        self._feBetrag.setAlignment(Qt.AlignRight)
        self._feBetrag.setToolTip("'+' für Einnahme, '-' für Ausgabe")
        self._feBetrag.setFixedWidth(60)
        self._abrechnungInfoLayout.addWidget(self._feBetrag)

        self._teBemerkung.setPlaceholderText("Bemerkung zur Zahlung")
        self._teBemerkung.setMaximumSize(QtCore.QSize(16777215, 50))
        self._abrechnungInfoLayout.addWidget(self._teBemerkung, stretch=1)

        # Buttons
        vbox = QVBoxLayout()
        self._btnOk.setIcon(QIcon("./images/checked.png"))
        self._btnOk.setDefault(True)
        self._btnOk.setToolTip("Daten in Tabelle übernehmen (kein Speichern)")
        self._btnOk.clicked.connect(self.onOkEditFields)
        vbox.addWidget(self._btnOk)
        self._btnClear.setIcon(QIcon("./images/cancel.png"))
        self._btnClear.setToolTip("Änderungen verwerfen und Felder leeren")
        self._btnClear.clicked.connect(self.onClearEditFields)
        vbox.addWidget(self._btnClear)
        self._abrechnungInfoLayout.addLayout(vbox)

    def onAbrechnungsjahrChanged(self, newindex):
        """
        Slot für die Änderung des Buchungsjahrs.
        :param newindex:
        :return:
        """
        if self._abrechnungsjahrChangedCallback and not self._suspendCallbacks:
            jahr = int(self._cboAbrechnungsjahr.currentText())
            self._abrechnungsjahrChangedCallback(jahr)

    def onAddDayToBuchungsdatum(self):
        val = self._sdBuchungsdatum.getDate()
        if val:
            dt = getQDateFromIsoString(val)
            dt = dt.addDays(1)
            self._sdBuchungsdatum.setDate(dt.year(), dt.month(), dt.day())

    def onClearBuchungsdatum(self):
        self._sdBuchungsdatum.clear()

    def onAddDayToAbrechnungsdatum(self):
        val = self._sdAbrechnungsdatum.getDate()
        if val:
            dt = getQDateFromIsoString(val)
            dt = dt.addDays(1)
            self._sdAbrechnungsdatum.setDate(dt.year(), dt.month(), dt.day())

    def onClearForderungsdatum(self):
        self._sdAbrechnungsdatum.clear()

    def setSaveButtonEnabled(self, enable: bool = True):
        self._btnSave.setEnabled(enable)

    def onSave(self):
        if self._saveActionCallback:
            self._saveActionCallback()

    def onOkEditFields(self, arg):
        """
        OK gedrückt. Änderungen an Callback-Funktion melden.
        :param arg:
        :return:
        """
        if self._submitChangesCallback:
            x: XAbrechnung = self._getEditedXAbrechnung()
            ok: bool = self._submitChangesCallback(x)
            if ok:
                self._tvAbrechnungen.clearSelection()

    def _getEditedXAbrechnung(self) -> XAbrechnung:
        if self._justEditing is None:
            self.showException("Interner Fehler",
                               "AbrechnungenView._getXAbrechnung()",
                               "XAbrechnung ist leer")
            return
        x: XAbrechnung = self._justEditing
        x.ab_datum = self._sdAbrechnungsdatum.getDate()
        x.buchungsdatum = self._sdBuchungsdatum.getDate()
        x.betrag = self._feBetrag.getFloatValue()
        x.bemerkung = self._teBemerkung.toPlainText()
        return x

    def onClearEditFields(self, arg):
        self.clearEditFields()
        self._tvAbrechnungen.clearSelection()

    def getAbrechnungenTableView(self) -> QTableView:
        return self._tvAbrechnungen

    def setAbrechnungenTableModel(self, tm: SonstAusTableModel):
        self._tvAbrechnungen.setModel(tm)
        self._tvAbrechnungen.resizeColumnsToContents()
        #self._tvAuszahlungen.setColumnWidth( 0, 10 )
        #self._tvAuszahlungen.setColumnWidth( 1, 10 )

    def setAbrechnungsjahre(self, jahre: List[int]):
        """
        setzt die Liste der auswählbaren Jahre für die Buchungsjahr-Combobox
        :param jahre:
        :return:
        """
        self._suspendCallbacks = True
        for jahr in jahre:
            self._cboAbrechnungsjahr.addItem(str(jahr))
        self._suspendCallbacks = False

    def clearEditFields(self):
        self._suspendCallbacks = True
        self._sdAbrechnungsdatum.clear()
        self._sdBuchungsdatum.clear()
        self._name.clear()
        self._feBetrag.clear()
        self._teBemerkung.clear()
        self._justEditing = None
        self._suspendCallbacks = False

    def provideEditFields(self, x: XAbrechnung):
        self.clearEditFields()
        #self._suspendCallbacks = True
        self._justEditing = x
        if x.ab_datum:
            y, m, d = getDateParts(x.ab_datum)
            self._sdAbrechnungsdatum.setDate(y, m, d)
        if x.buchungsdatum:
            y, m, d = getDateParts(x.buchungsdatum)
            self._sdBuchungsdatum.setDate(y, m, d)
        self._name.setText(x.getName())
        if x.betrag == 0.0:
            self._feBetrag.setText("0")
        else:
            self._feBetrag.setText(str(x.betrag))
        self._teBemerkung.setText(x.bemerkung)
        self._suspendCallbacks = False

    def getModel(self) -> IccTableModel:
        return self._tvAbrechnungen.model()

    def showException(self, title: str, exception: str, moretext: str = None):
        # todo: show Qt-Errordialog
        msgbox = QtWidgets.QMessageBox()
        msgbox.setWindowTitle(title)
        msgbox.setIcon(QMessageBox.Critical)
        msgbox.setText(exception)
        if moretext:
            msgbox.setInformativeText(moretext)
        msgbox.exec_()

    ################# SET CALLBACKS  ############################

    def setAbrechnungsjahrChangedCallback(self, cbfnc) -> None:
        """
        Die callback-Funktion muss als Argument das neu eingestellte Jahr als integer akzeptieren
        :param cbfnc:
        :return:
        """
        self._abrechnungsjahrChangedCallback = cbfnc

    def setSubmitChangesCallback(self, cbfnc):
        """
        sets the one and only callback when the user hits the OK button in the
        edit fields area.
        The given callback function has to accept the edited XAbrechnung object,
        :param cbfnc:
        :return:
        """
        self._submitChangesCallback = cbfnc

    def setSaveActionCallback(self, cbfnc) -> None:
        """
        Die callback-FUnktion braucht keine Parameter empfangen.
        :param cbfnc:
        :return:
        """
        self._saveActionCallback = cbfnc

    def onChange(self):
        self._btnSave.setEnabled(True)

    def onResetChangeFlag(self):
        self._btnSave.setEnabled(False)
コード例 #12
0
class PlainTextFindReplaceDialog(QDialog):
    """
    Modeless, stay-above-parent dialog that supports find and replace.

    Allows for searching case (in)sensitively, and whole-word.
    Find triggered by Enter / Shift+Enter, or corresponding button (Next / Previous), or if Replace clicked before
    Next / Previous.
    Find wraps.
    Highlights all matches, operating on the closest-to-user's-cursor selection first,
    in the user-selected direction (Next / Previous).
    Highlighting / found cursors retained on navigation back to text editor, and cleared on re-find/replace if
    user modified the document.
    Presents an info label (e.g. "x of y", "No matches found", ...)

    While no members have a leading underscore, the only explicit public interface is the static method `find_all`.
    I couldn't find a reason to need to interface with anything in here, so I didn't differentiate everything as
    "private".
    """
    def __init__(self, plain_text_edit: QPlainTextEdit, parent=None):
        """
        Sets up the dialog.

        :param plain_text_edit: Text Editor to operate on.
        :param parent: QWidget parent
        """
        super().__init__(parent=parent, f=Qt.Tool)
        self.plain_text_edit = plain_text_edit
        self.cursors_needed = True
        self.find_flags = QTextDocument.FindFlags()
        self.found_cursors: List[QTextCursor] = []
        self.current_cursor = QTextCursor()

        # UI
        layout = QVBoxLayout()
        find_and_replace_layout = QGridLayout()
        layout.addLayout(
            find_and_replace_layout
        )  # if QGL is sub-layout, add to parent layout before doing stuff.

        self.find_line_edit = QLineEdit()
        find_label = QLabel("&Find")
        find_label.setBuddy(self.find_line_edit)

        options_layout = QHBoxLayout()
        self.match_case_check_box = QCheckBox("Match Case")
        self.whole_word_check_box = QCheckBox("Whole Word")
        options_layout.addWidget(self.match_case_check_box)
        options_layout.addWidget(self.whole_word_check_box)
        options_layout.addStretch()

        self.found_info_label = QLabel()

        self.replace_line_edit = QLineEdit()
        replace_label = QLabel("&Replace")
        replace_label.setBuddy(self.replace_line_edit)

        find_and_replace_layout.addWidget(find_label, 0, 0)
        find_and_replace_layout.addWidget(self.find_line_edit, 0, 1)
        find_and_replace_layout.addLayout(options_layout, 1, 1)
        find_and_replace_layout.setRowMinimumHeight(2, 20)
        find_and_replace_layout.addWidget(self.found_info_label, 2, 1)
        find_and_replace_layout.addWidget(replace_label, 3, 0)
        find_and_replace_layout.addWidget(self.replace_line_edit, 3, 1)

        self.btn_box = QDialogButtonBox(QDialogButtonBox.Close)
        self.find_next_btn = QPushButton("Next")
        self.find_next_btn.setEnabled(False)
        self.find_prev_btn = QPushButton("Previous")
        self.find_prev_btn.setEnabled(False)
        self.replace_btn = QPushButton("Replace")
        self.replace_btn.setEnabled(False)
        self.replace_all_btn = QPushButton("Replace All")
        self.replace_all_btn.setEnabled(False)
        self.btn_box.addButton(self.replace_btn, QDialogButtonBox.ActionRole)
        self.btn_box.addButton(self.replace_all_btn,
                               QDialogButtonBox.ActionRole)
        self.btn_box.addButton(self.find_prev_btn, QDialogButtonBox.ActionRole)
        self.btn_box.addButton(self.find_next_btn, QDialogButtonBox.ActionRole)

        layout.addWidget(self.btn_box)
        self.setLayout(layout)
        # End UI

        self.btn_box.rejected.connect(self.reject)
        self.find_line_edit.textEdited.connect(self.handle_text_edited)
        self.find_next_btn.clicked.connect(self.next)
        self.find_prev_btn.clicked.connect(self.prev)
        self.replace_btn.clicked.connect(self.replace)
        self.replace_all_btn.clicked.connect(self.replace_all)
        self.plain_text_edit.document().contentsChanged.connect(
            self.set_cursors_needed_true)
        self.whole_word_check_box.stateChanged.connect(
            self.toggle_whole_word_flag)
        self.match_case_check_box.stateChanged.connect(
            self.toggle_match_case_flag)

    # SLOTS
    def next(self):
        """
        Finds all matches to the user's search. First highlight after cursor. Consecutive calls advance through matches.

        If there are matches or not, it says so. The user's cursor advances along with the current selection. Loops back
        to start after the last match.
        :return: Side effect: Highlights all matches, differentiating (maybe moving fwd) the current selection.
        """
        if self.cursors_needed:
            self.init_find()

        if not self.found_cursors:
            self.found_info_label.setText("No matches found")
            self.found_info_label.repaint()
            return

        if self.current_cursor >= self.found_cursors[
                -1]:  # loop back to start. cursor equality based on position.
            self.current_cursor = self.found_cursors[0]
        else:
            for cur in self.found_cursors:
                if cur > self.current_cursor:  # next in order
                    self.current_cursor = cur
                    break

        self.update_visuals()

    def prev(self):
        """
        Finds all matches to user's search. First highlight before cursor. Consecutive calls retreat through matches.

        If there are matches or not, it says so. The user's cursor moves along with the current selection. Loops back
        to end after the last (first in doc) match.
        :return: Side effect: Highlights all matches, differentiating (maybe moving back) the current selection.
        """
        if self.cursors_needed:
            self.init_find()

        if not self.found_cursors:
            self.found_info_label.setText("No matches found")
            self.found_info_label.repaint()
            return

        if self.current_cursor <= self.found_cursors[0]:  # loop back to end.
            self.current_cursor = self.found_cursors[-1]
        else:
            for cur in reversed(self.found_cursors):
                if cur < self.current_cursor:  # prev in order
                    self.current_cursor = cur
                    break

        self.update_visuals()

    def replace(self):
        """
        Replaces the word under focus by `next`.

        Replaces with the Replace line edit's text, and advances to next word. If no word under focus via this dialog,
        calls `next`.
        :return: Side effect: replaces word in text edit
        """
        if self.cursors_needed:
            self.next()
            return

        if not self.found_cursors:
            return

        self.plain_text_edit.document().contentsChanged.disconnect(
            self.set_cursors_needed_true)  # don't dup work.
        self.current_cursor.insertText(self.replace_line_edit.text())
        self.plain_text_edit.document().contentsChanged.connect(
            self.set_cursors_needed_true)
        self.found_cursors.remove(self.current_cursor)
        self.next()

    def replace_all(self):
        """
        Replaces all instances of Find's text with Replace's text.

        :return: Side effect: replaces words in text edit. Indicates success to user via info label on dialog.
        """
        if self.cursors_needed:
            self.init_find()

        for cur in self.found_cursors:
            cur.insertText(self.replace_line_edit.text())

        self.found_info_label.setText("Made {} replacements".format(
            len(self.found_cursors)))
        self.found_info_label.repaint()

    def handle_text_edited(self, text):
        """
        Modifies button states, clears info text, and sets self.cursors_needed to True.

        :param text: The find_line_edit's text.
        :return: Side effect: btn enabled / default
        """
        self.found_info_label.clear()

        self.cursors_needed = True

        find_enabled = text != ""
        self.find_next_btn.setEnabled(find_enabled)
        self.find_prev_btn.setEnabled(find_enabled)
        self.replace_btn.setEnabled(find_enabled)
        self.replace_all_btn.setEnabled(find_enabled)

        self.find_next_btn.setDefault(find_enabled)
        self.btn_box.button(
            QDialogButtonBox.Close).setDefault(not find_enabled)

    def set_cursors_needed_true(self):
        self.cursors_needed = True

    def toggle_match_case_flag(self, state: int):
        self.found_info_label.clear(
        )  # User will be performing a new search upon toggle, so want this reset.
        self.cursors_needed = True

        if state == Qt.Unchecked:
            self.find_flags &= ~QTextDocument.FindCaseSensitively
        elif state == Qt.Checked:
            self.find_flags |= QTextDocument.FindCaseSensitively

    def toggle_whole_word_flag(self, state: int):
        self.found_info_label.clear(
        )  # User will be performing a new search upon toggle, so want this reset.
        self.cursors_needed = True

        if state == Qt.Unchecked:
            self.find_flags &= ~QTextDocument.FindWholeWords
        elif state == Qt.Checked:
            self.find_flags |= QTextDocument.FindWholeWords

    # END SLOTS

    def init_find(self):
        """Sets up internal state for the case when cursors are needed (e.g. first find, user modifies doc...)"""
        self.found_cursors = self.find_all(self.find_line_edit.text(),
                                           self.plain_text_edit.document(),
                                           self.find_flags)
        self.cursors_needed = False
        self.current_cursor = self.plain_text_edit.textCursor(
        )  # returns copy of
        self.plain_text_edit.setExtraSelections([])

    def update_visuals(self):
        """
        Moves text editor's cursor to match currently highlighted `find` word, performs `find` highlighting,
        indicates index on dialog.
        """
        # x of y words indicator
        idx = self.found_cursors.index(self.current_cursor) + 1
        self.found_info_label.setText("{} of {} matches".format(
            idx, len(self.found_cursors)))
        self.found_info_label.repaint()

        # move along text editor's viewport
        next_pte_cursor = QTextCursor(self.current_cursor)
        next_pte_cursor.clearSelection()
        self.plain_text_edit.setTextCursor(next_pte_cursor)

        #highlighting
        normal_color = QColor(Qt.yellow).lighter()
        current_color = QColor(Qt.magenta).lighter()
        extra_selections: List[QTextEdit.ExtraSelection] = []
        for cur in self.found_cursors:
            selection = QTextEdit.ExtraSelection()
            selection.cursor = cur
            if cur == self.current_cursor:
                selection.format.setBackground(current_color)
            else:
                selection.format.setBackground(normal_color)
            extra_selections.append(selection)
        self.plain_text_edit.setExtraSelections(extra_selections)

    @staticmethod
    def find_all(
        text: str, document: QTextDocument, flags=QTextDocument.FindFlags()
    ) -> List[QTextCursor]:
        """
        Finds all occurrences of `text` in `document`, in order.

        :param text: Text to find.
        :param document: Document to search.
        :param flags: Conditions to set on the search: none or (whole word and/or match case)
        :return: Ordered list of all found instances.
        """
        cursor = QTextCursor(document)  # default pos == 0
        found: List[QTextCursor] = []

        while True:
            cursor = document.find(text, cursor, flags)
            if cursor.isNull():
                return found
            else:
                found.append(cursor)

    def done(self, arg__1: int):
        self.plain_text_edit.setExtraSelections([])
        super().done(arg__1)

    def keyPressEvent(self, arg__1: QKeyEvent):
        # Shift+Enter triggers find previous, if the corresponding btn is enabled.
        if (arg__1.key() in [Qt.Key_Return, Qt.Key_Enter]
                and arg__1.modifiers() == Qt.ShiftModifier
                and self.find_prev_btn.isEnabled()):
            self.prev()
        else:
            super().keyPressEvent(arg__1)
コード例 #13
0
ファイル: view.py プロジェクト: marshb/biopeaks
class View(QMainWindow):
    """View component of the MVC application.

    Presents the state of the application as well as the available means of
    interaction. Receives updates about the state from the Model and informs
    Controller about user interactions.

    """
    def __init__(self, model, controller):
        """Define GUI elements and their layout.

        Parameters
        ----------
        model : QObject
            Model component of the MVC application.
        controller : QObject
            Controller component of the MVC application.
        """
        super().__init__()

        self._model = model
        self._controller = controller
        self.segmentcursor = False
        self.togglecolors = {"#1f77b4": "m", "m": "#1f77b4"}

        self.setWindowTitle("biopeaks")
        self.setGeometry(50, 50, 1750, 750)
        self.setWindowIcon(QIcon(":/python_icon.png"))

        # Figure for biosignal.
        self.figure0 = Figure()
        self.canvas0 = FigureCanvas(self.figure0)
        # Enforce minimum height, otherwise resizing with self.splitter causes
        # mpl to throw an error because figure is resized to height 0. The
        # widget can still be fully collapsed with self.splitter.
        self.canvas0.setMinimumHeight(1)  # in pixels
        self.ax00 = self.figure0.add_subplot(1, 1, 1)
        self.ax00.set_frame_on(False)
        self.figure0.subplots_adjust(left=0.04, right=0.98, bottom=0.25)
        self.line00 = None
        self.scat = None
        self.segmentspan = None

        # Figure for marker.
        self.figure1 = Figure()
        self.canvas1 = FigureCanvas(self.figure1)
        self.canvas1.setMinimumHeight(1)
        self.ax10 = self.figure1.add_subplot(1, 1, 1, sharex=self.ax00)
        self.ax10.get_xaxis().set_visible(False)
        self.ax10.set_frame_on(False)
        self.figure1.subplots_adjust(left=0.04, right=0.98)
        self.line10 = None

        # Figure for statistics.
        self.figure2 = Figure()
        self.canvas2 = FigureCanvas(self.figure2)
        self.canvas2.setMinimumHeight(1)
        self.ax20 = self.figure2.add_subplot(3, 1, 1, sharex=self.ax00)
        self.ax20.get_xaxis().set_visible(False)
        self.ax20.set_frame_on(False)
        self.line20 = None
        self.ax21 = self.figure2.add_subplot(3, 1, 2, sharex=self.ax00)
        self.ax21.get_xaxis().set_visible(False)
        self.ax21.set_frame_on(False)
        self.line21 = None
        self.ax22 = self.figure2.add_subplot(3, 1, 3, sharex=self.ax00)
        self.ax22.get_xaxis().set_visible(False)
        self.ax22.set_frame_on(False)
        self.line22 = None
        self.figure2.subplots_adjust(left=0.04, right=0.98)

        self.navitools = CustomNavigationToolbar(self.canvas0, self)

        # Peak editing.
        self.editcheckbox = QCheckBox("editable", self)
        self.editcheckbox.stateChanged.connect(self._model.set_peakseditable)

        # Peak saving during batch processing.
        self.savecheckbox = QCheckBox("save during batch processing", self)
        self.savecheckbox.stateChanged.connect(self._model.set_savebatchpeaks)

        # Peak auto-correction during batch processing.
        self.correctcheckbox = QCheckBox("correct during batch processing",
                                         self)
        self.correctcheckbox.stateChanged.connect(
            self._model.set_correctbatchpeaks)

        # Selection of stats for saving.
        self.periodcheckbox = QCheckBox("period", self)
        self.periodcheckbox.stateChanged.connect(
            lambda: self.select_stats("period"))
        self.ratecheckbox = QCheckBox("rate", self)
        self.ratecheckbox.stateChanged.connect(
            lambda: self.select_stats("rate"))
        self.tidalampcheckbox = QCheckBox("tidal amplitude", self)
        self.tidalampcheckbox.stateChanged.connect(
            lambda: self.select_stats("tidalamp"))

        # Channel selection.
        self.sigchanmenulabel = QLabel("biosignal")
        self.sigchanmenu = QComboBox(self)
        self.sigchanmenu.addItem("A1")
        self.sigchanmenu.addItem("A2")
        self.sigchanmenu.addItem("A3")
        self.sigchanmenu.addItem("A4")
        self.sigchanmenu.addItem("A5")
        self.sigchanmenu.addItem("A6")
        self.sigchanmenu.currentTextChanged.connect(self._model.set_signalchan)
        self._model.set_signalchan(
            self.sigchanmenu.currentText())  # initialize with default value

        self.markerchanmenulabel = QLabel("marker")
        self.markerchanmenu = QComboBox(self)
        self.markerchanmenu.addItem("none")
        self.markerchanmenu.addItem("I1")
        self.markerchanmenu.addItem("I2")
        self.markerchanmenu.addItem("A1")
        self.markerchanmenu.addItem("A2")
        self.markerchanmenu.addItem("A3")
        self.markerchanmenu.addItem("A4")
        self.markerchanmenu.addItem("A5")
        self.markerchanmenu.addItem("A6")
        self.markerchanmenu.currentTextChanged.connect(
            self._model.set_markerchan)
        self._model.set_markerchan(self.markerchanmenu.currentText())

        # Processing mode.
        self.batchmenulabel = QLabel("mode")
        self.batchmenu = QComboBox(self)
        self.batchmenu.addItem("single file")
        self.batchmenu.addItem("multiple files")
        self.batchmenu.currentTextChanged.connect(self._model.set_batchmode)
        self.batchmenu.currentTextChanged.connect(self.toggle_options)
        self._model.set_batchmode(self.batchmenu.currentText())
        self.toggle_options(self.batchmenu.currentText())

        # Modality selection.
        self.modmenulabel = QLabel("modality")
        self.modmenu = QComboBox(self)
        self.modmenu.addItem("ECG")
        self.modmenu.addItem("PPG")
        self.modmenu.addItem("RESP")
        self.modmenu.currentTextChanged.connect(self._model.set_modality)
        self.modmenu.currentTextChanged.connect(self.toggle_options)
        self._model.set_modality(self.modmenu.currentText())
        self.toggle_options(self.modmenu.currentText())

        # Segment selection. This widget can be openend / set visible from
        # the menu and closed from within itself (see mapping of segmentermap).
        self.segmentermap = QSignalMapper(self)
        self.segmenter = QDockWidget("select a segment", self)
        self.segmenter.setFeatures(
            QDockWidget.NoDockWidgetFeatures
        )  # disable closing such that widget can only be closed by confirming selection or custom button
        regex = QRegExp(
            "[0-9]*\.?[0-9]{4}")  # Limit number of decimals to four

        validator = QRegExpValidator(regex)

        self.startlabel = QLabel("start")
        self.startedit = QLineEdit()
        self.startedit.setValidator(validator)

        self.endlabel = QLabel("end")
        self.endedit = QLineEdit()
        self.endedit.setValidator(validator)

        segmentfromcursor = QAction(QIcon(":/mouse_icon.png"),
                                    "select with mouse", self)
        segmentfromcursor.triggered.connect(self.enable_segmentedit)
        self.startedit.addAction(segmentfromcursor, QLineEdit.TrailingPosition)
        self.endedit.addAction(segmentfromcursor, QLineEdit.TrailingPosition)

        self.previewedit = QPushButton("preview segment")
        lambdafn = lambda: self._model.set_segment(
            [self.startedit.text(), self.endedit.text()])
        self.previewedit.clicked.connect(lambdafn)

        self.confirmedit = QPushButton("confirm segment")
        self.confirmedit.clicked.connect(self._controller.segment_dataset)
        self.confirmedit.clicked.connect(self.segmentermap.map)
        self.segmentermap.setMapping(self.confirmedit, 0)

        self.abortedit = QPushButton("abort segmentation")
        self.abortedit.clicked.connect(self.segmentermap.map)
        self.segmentermap.setMapping(self.abortedit,
                                     2)  # resets the segment to None

        self.segmenterlayout = QFormLayout()
        self.segmenterlayout.addRow(self.startlabel, self.startedit)
        self.segmenterlayout.addRow(self.endlabel, self.endedit)
        self.segmenterlayout.addRow(self.previewedit)
        self.segmenterlayout.addRow(self.confirmedit)
        self.segmenterlayout.addRow(self.abortedit)
        self.segmenterwidget = QWidget()
        self.segmenterwidget.setLayout(self.segmenterlayout)
        self.segmenter.setWidget(self.segmenterwidget)

        self.segmenter.setVisible(False)
        self.segmenter.setAllowedAreas(Qt.RightDockWidgetArea)
        self.addDockWidget(Qt.RightDockWidgetArea, self.segmenter)

        # Custom file dialog.
        regex = QRegExp("[1-9][0-9]")
        validator = QRegExpValidator(regex)

        self.signallabel = QLabel("biosignal column")
        self.signaledit = QLineEdit()
        self.signaledit.setValidator(validator)

        self.markerlabel = QLabel("marker column")
        self.markeredit = QLineEdit()
        self.markeredit.setValidator(validator)

        regex = QRegExp("[0-9]{2}")
        validator = QRegExpValidator(regex)

        self.headerrowslabel = QLabel("number of header rows")
        self.headerrowsedit = QLineEdit()
        self.headerrowsedit.setValidator(validator)

        regex = QRegExp("[0-9]{5}")
        validator = QRegExpValidator(regex)

        self.sfreqlabel = QLabel("sampling rate")
        self.sfreqedit = QLineEdit()
        self.sfreqedit.setValidator(validator)

        self.separatorlabel = QLabel("column separator")
        self.separatormenu = QComboBox(self)
        self.separatormenu.addItem("comma")
        self.separatormenu.addItem("tab")
        self.separatormenu.addItem("colon")
        self.separatormenu.addItem("space")

        self.continuecustomfile = QPushButton("continue loading file")
        self.continuecustomfile.clicked.connect(self.set_customheader)

        self.customfiledialog = QDialog()
        self.customfiledialog.setWindowTitle("custom file info")
        self.customfiledialog.setWindowIcon(QIcon(":/file_icon.png"))
        self.customfiledialog.setWindowFlags(
            Qt.WindowCloseButtonHint
        )  # remove help button by only setting close button
        self.customfilelayout = QFormLayout()
        self.customfilelayout.addRow(self.signallabel, self.signaledit)
        self.customfilelayout.addRow(self.markerlabel, self.markeredit)
        self.customfilelayout.addRow(self.separatorlabel, self.separatormenu)
        self.customfilelayout.addRow(self.headerrowslabel, self.headerrowsedit)
        self.customfilelayout.addRow(self.sfreqlabel, self.sfreqedit)
        self.customfilelayout.addRow(self.continuecustomfile)
        self.customfiledialog.setLayout(self.customfilelayout)

        # Layout.
        menubar = self.menuBar()

        signalmenu = menubar.addMenu("biosignal")

        openSignal = signalmenu.addMenu("load")
        openEDF = QAction("EDF", self)
        openEDF.triggered.connect(lambda: self._model.set_filetype("EDF"))
        openEDF.triggered.connect(self._controller.load_channels)
        openSignal.addAction(openEDF)
        openOpenSignals = QAction("OpenSignals", self)
        openOpenSignals.triggered.connect(
            lambda: self._model.set_filetype("OpenSignals"))
        openOpenSignals.triggered.connect(self._controller.load_channels)
        openSignal.addAction(openOpenSignals)
        openCustom = QAction("Custom", self)
        openCustom.triggered.connect(
            lambda: self._model.set_filetype("Custom"))
        openCustom.triggered.connect(lambda: self.customfiledialog.exec_())
        openSignal.addAction(openCustom)

        segmentSignal = QAction("select segment", self)
        segmentSignal.triggered.connect(self.segmentermap.map)
        self.segmentermap.setMapping(segmentSignal, 1)
        signalmenu.addAction(segmentSignal)

        self.segmentermap.mapped.connect(self.toggle_segmenter)

        saveSignal = QAction("save", self)
        saveSignal.triggered.connect(self._controller.save_channels)
        signalmenu.addAction(saveSignal)

        peakmenu = menubar.addMenu("peaks")

        findPeaks = QAction("find", self)
        findPeaks.triggered.connect(self._controller.find_peaks)
        peakmenu.addAction(findPeaks)

        autocorrectPeaks = QAction("autocorrect", self)
        autocorrectPeaks.triggered.connect(self._controller.autocorrect_peaks)
        peakmenu.addAction(autocorrectPeaks)

        savePeaks = QAction("save", self)
        savePeaks.triggered.connect(self._controller.save_peaks)
        peakmenu.addAction(savePeaks)

        loadPeaks = QAction("load", self)
        loadPeaks.triggered.connect(self._controller.load_peaks)
        peakmenu.addAction(loadPeaks)

        statsmenu = menubar.addMenu("statistics")

        calculateStats = QAction("calculate", self)
        calculateStats.triggered.connect(self._controller.calculate_stats)
        statsmenu.addAction(calculateStats)

        saveStats = QAction("save", self)
        saveStats.triggered.connect(self._controller.save_stats)
        statsmenu.addAction(saveStats)

        self.statusBar = QStatusBar()
        self.setStatusBar(self.statusBar)
        self.progressBar = QProgressBar(self)
        self.progressBar.setRange(0, 1)
        self.statusBar.addPermanentWidget(self.progressBar)
        self.currentFile = QLabel()
        self.statusBar.addPermanentWidget(self.currentFile)

        self.centwidget = QWidget()  # contains figures and navigationtoolbar
        self.setCentralWidget(self.centwidget)

        self.canvas0.setFocusPolicy(
            Qt.ClickFocus
        )  # only widgets (e.g. canvas) that currently have focus capture keyboard input
        self.canvas0.setFocus()
        self.canvas0.mpl_connect(
            "key_press_event", self._controller.edit_peaks
        )  # connect canvas to keyboard input for peak editing
        self.canvas0.mpl_connect(
            "button_press_event",
            self.get_xcursor)  # connect canvas to mouse input for peak editing

        self.splitter = QSplitter(
            Qt.Vertical
        )  # arrange the three figure canvases in splitter object
        self.splitter.setOpaqueResize(
            False)  # resizing gets very slow otherwise once axes are populated
        self.splitter.addWidget(self.canvas0)
        self.splitter.addWidget(self.canvas1)
        self.splitter.addWidget(self.canvas2)
        self.splitter.setChildrenCollapsible(False)

        self.vlayout0 = QVBoxLayout(self.centwidget)
        self.vlayout1 = QVBoxLayout()
        self.vlayoutA = QFormLayout()
        self.vlayoutB = QFormLayout()
        self.vlayoutC = QVBoxLayout()
        self.vlayoutD = QVBoxLayout()
        self.hlayout0 = QHBoxLayout()

        self.optionsgroupA = QGroupBox("processing options")
        self.vlayoutA.addRow(self.modmenulabel, self.modmenu)
        self.vlayoutA.addRow(self.batchmenulabel, self.batchmenu)
        self.optionsgroupA.setLayout(self.vlayoutA)

        self.optionsgroupB = QGroupBox("channels")
        self.vlayoutB.addRow(self.sigchanmenulabel, self.sigchanmenu)
        self.vlayoutB.addRow(self.markerchanmenulabel, self.markerchanmenu)
        self.optionsgroupB.setLayout(self.vlayoutB)

        self.optionsgroupC = QGroupBox("peaks")
        self.vlayoutC.addWidget(self.editcheckbox)
        self.vlayoutC.addWidget(self.savecheckbox)
        self.vlayoutC.addWidget(self.correctcheckbox)
        self.optionsgroupC.setLayout(self.vlayoutC)

        self.optionsgroupD = QGroupBox("select statistics for saving")
        self.vlayoutD.addWidget(self.periodcheckbox)
        self.vlayoutD.addWidget(self.ratecheckbox)
        self.vlayoutD.addWidget(self.tidalampcheckbox)
        self.optionsgroupD.setLayout(self.vlayoutD)

        self.vlayout1.addWidget(self.optionsgroupA)
        self.vlayout1.addWidget(self.optionsgroupB)
        self.vlayout1.addWidget(self.optionsgroupC)
        self.vlayout1.addWidget(self.optionsgroupD)
        self.optionsgroupwidget = QWidget()
        self.optionsgroupwidget.setLayout(self.vlayout1)
        self.optionsgroup = QDockWidget("configurations", self)
        self.optionsgroup.setAllowedAreas(Qt.LeftDockWidgetArea)
        self.toggleoptionsgroup = self.optionsgroup.toggleViewAction()
        self.toggleoptionsgroup.setText("show/hide configurations")
        menubar.addAction(self.toggleoptionsgroup)
        self.optionsgroup.setWidget(self.optionsgroupwidget)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.optionsgroup)

        self.vlayout0.addWidget(self.splitter)

        self.hlayout0.addWidget(self.navitools)
        self.vlayout0.addLayout(self.hlayout0)

        # Subscribe to updates from the Model.
        self._model.signal_changed.connect(self.plot_signal)
        self._model.marker_changed.connect(self.plot_marker)
        self._model.peaks_changed.connect(self.plot_peaks)
        self._model.period_changed.connect(self.plot_period)
        self._model.rate_changed.connect(self.plot_rate)
        self._model.tidalamp_changed.connect(self.plot_tidalamp)
        self._model.path_changed.connect(self.display_path)
        self._model.segment_changed.connect(self.plot_segment)
        self._model.status_changed.connect(self.display_status)
        self._model.progress_changed.connect(self.display_progress)
        self._model.model_reset.connect(self.reset_plot)

    def plot_signal(self, signal):
        """Plot the biosignal.

        Receives updates in signal from Model.

        Parameters
        ----------
        signal : ndarray of float
            Vector representing the biosignal.

        See Also
        --------
        model.Model.signal
        """
        self.ax00.clear()
        self.ax00.relim()
        self.navitools.update()  # reset navitools history
        self.line00 = self.ax00.plot(self._model.sec, signal, zorder=1)
        self.ax00.set_xlabel("seconds", fontsize="large", fontweight="heavy")
        self.canvas0.draw()

    def plot_peaks(self, peaks):
        """Plot the extrema.

        Receives updates in peaks from Model.

        Parameters
        ----------
        peaks : ndarray of int
            Vector representing the extrema.

        See Also
        --------
        model.Model.peaks
        """
        if self.ax00.collections:  # self.scat is listed in ax.collections
            self.ax00.collections[0].remove()
        self.scat = self.ax00.scatter(self._model.sec[peaks],
                                      self._model.signal[peaks],
                                      c="m",
                                      zorder=2)
        self.canvas0.draw()

    def plot_segment(self, segment):
        """Show preview of segment.

        Receives updates in segment from Model.

        Parameters
        ----------
        segment : list of float
            The start and end of the segment in seconds.

        See Also
        --------
        model.Model.segment
        """
        if segment is None:  # if an invalid segment has been selected reset the segmenter interface
            self.toggle_segmenter(1)
            return
        if self.ax00.patches:  # self.segementspan is listed in ax.patches
            self.ax00.patches[0].remove()
        self.segmentspan = self.ax00.axvspan(segment[0],
                                             segment[1],
                                             color="m",
                                             alpha=0.25)
        self.canvas0.draw()
        self.confirmedit.setEnabled(True)

    def plot_marker(self, marker):
        """Plot the marker channel.

        Receives updates in marker from Model.

        Parameters
        ----------
        marker : list of ndarray
            Seconds element is vector representing the marker channel and first
            element is a vector representing the seconds associated with each
            sample in the marker channel.

        See Also
        --------
        model.Model.marker
        """
        self.ax10.clear()
        self.ax10.relim()
        self.line10 = self.ax10.plot(marker[0], marker[1])
        self.canvas1.draw()

    def plot_period(self, period):
        """Plot instantaneous period.

        Receives updates in period from Model.

        Parameters
        ----------
        period : ndarray of float
            Vector representing the instantaneous period.

        See Also
        --------
        model.Model.periodintp
        """
        self.ax20.clear()
        self.ax20.relim()
        self.navitools.home()
        if self._model.savestats["period"]:
            self.line20 = self.ax20.plot(self._model.sec, period, c="m")
        else:
            self.line20 = self.ax20.plot(self._model.sec, period)
        self.ax20.set_ylim(bottom=min(period), top=max(period))
        self.ax20.set_title("period", pad=0, fontweight="heavy")
        self.ax20.grid(True, axis="y")
        self.navitools.update()
        self.canvas2.draw()

    def plot_rate(self, rate):
        """Plot instantaneous rate.

        Receives updates in rate from Model.

        Parameters
        ----------
        rate : ndarray of float
            Vector representing the instantaneous rate.

        See Also
        --------
        model.Model.rateintp
        """
        self.ax21.clear()
        self.ax21.relim()
        self.navitools.home()
        if self._model.savestats["rate"]:
            self.line21 = self.ax21.plot(self._model.sec, rate, c="m")
        else:
            self.line21 = self.ax21.plot(self._model.sec, rate)
        self.ax21.set_ylim(bottom=min(rate), top=max(rate))
        self.ax21.set_title("rate", pad=0, fontweight="heavy")
        self.ax21.grid(True, axis="y")
        self.navitools.update()
        self.canvas2.draw()

    def plot_tidalamp(self, tidalamp):
        """Plot instantaneous tidal amplitude.

        Receives updates in tidal amplitude from Model.

        Parameters
        ----------
        tidalamp : ndarray of float
            Vector representing the instantaneous tidal amplitude.

        See Also
        --------
        model.Model.tidalampintp
        """
        self.ax22.clear()
        self.ax22.relim()
        self.navitools.home()
        if self._model.savestats["tidalamp"]:
            self.line22 = self.ax22.plot(self._model.sec, tidalamp, c="m")
        else:
            self.line22 = self.ax22.plot(self._model.sec, tidalamp)
        self.ax22.set_ylim(bottom=min(tidalamp), top=max(tidalamp))
        self.ax22.set_title("amplitude", pad=0, fontweight="heavy")
        self.ax22.grid(True, axis="y")
        self.navitools.update()
        self.canvas2.draw()

    def display_path(self, path):
        """Display the path to the current dataset.

        Receives update in path from Model.

        Parameters
        ----------
        path : str
            The path to the file containing the current dataset.

        See Also
        --------
        model.Model.rpathsignal
        """
        self.currentFile.setText(path)

    def display_status(self, status):
        """Display a status message.

        Receives updates in status message from Model.

        Parameters
        ----------
        status : str
            A status message.

        See Also
        --------
        model.Model.status
        """
        self.statusBar.showMessage(status)

    def display_progress(self, progress):
        """Display task progress.

        Receives updates in progress from Model.

        Parameters
        ----------
        progress : int
            Integer indicating the current task progress.

        See Also
        --------
        model.Model.progress, controller.Worker, controller.threaded
        """
        self.progressBar.setRange(
            0, progress)  # indicates busy state if progress is 0

    def toggle_segmenter(self, visibility_state):
        """Toggle visibility of segmenter widget.

        Parameters
        ----------
        visibility_state : int
            Update in state of the segmenter widget's visibility.
        """
        if not self._model.loaded:
            return
        if visibility_state == 1:  # open segmenter when called from signalmenu or clear segmenter upon selection of invalid segment
            self.segmenter.setVisible(True)
            self.confirmedit.setEnabled(False)
            self.startedit.clear()
            self.endedit.clear()
        elif visibility_state == 0:  # close segmenter after segment has been confirmed
            self.segmenter.setVisible(False)
        elif visibility_state == 2:  # close segmenter after segmentation has been aborted (reset segment)
            self._model.set_segment([0, 0])
            self.segmenter.setVisible(False)
        if self.ax00.patches:
            self.ax00.patches[0].remove()
            self.canvas0.draw()

    def enable_segmentedit(self):
        """Associate cursor position with a specific segmenter text field.

        Regulate if cursor position is associated with editing the start or
        end of a segment.
        """
        self.editcheckbox.setChecked(
            False)  # disable peak editing to avoid interference
        if self.startedit.hasFocus():
            self.segmentcursor = "start"
        elif self.endedit.hasFocus():
            self.segmentcursor = "end"

    def get_xcursor(self, mouse_event):
        """Retrieve input to segmenter text fields from cursor position.

        Retrieve the start or end of a segment in seconds from the current
        cursor position.

        Parameters
        ----------
        mouse_event : MouseEvent
            Event containing information about the current cursor position
            in data coordinates.

        See Also
        --------
        matplotlib.backend_bases.MouseEvent
        """
        if mouse_event.button != 1:  # 1 = left mouse button
            return
        if self.segmentcursor == "start":
            self.startedit.selectAll()
            self.startedit.insert("{:.2f}".format(
                mouse_event.xdata))  # limit number of decimal places to two
        elif self.segmentcursor == "end":
            self.endedit.selectAll()
            self.endedit.insert("{:.2f}".format(mouse_event.xdata))
        self.segmentcursor = False  # disable segment cursor again after value has been set

    def set_customheader(self):
        """Populate the customheader with inputs from the customfiledialog."""
        mandatoryfields = self.signaledit.text() and self.headerrowsedit.text(
        ) and self.sfreqedit.text(
        )  # check if one of the mandatory fields is missing

        if not mandatoryfields:
            self._model.status = (
                "Please provide values for 'biosignal column'"
                ", 'number of header rows' and 'sampling"
                " rate'.")
            return

        seps = {"comma": ",", "tab": "\t", "colon": ":", "space": " "}
        self._model.customheader = dict.fromkeys(
            self._model.customheader, None
        )  # reset header here since it cannot be reset in controller.load_chanels

        self._model.customheader["signalidx"] = int(self.signaledit.text())
        self._model.customheader["skiprows"] = int(self.headerrowsedit.text())
        self._model.customheader["sfreq"] = int(self.sfreqedit.text())
        self._model.customheader["separator"] = seps[
            self.separatormenu.currentText()]
        if self.markeredit.text():  # not mandatory
            self._model.customheader["markeridx"] = int(self.markeredit.text())

        self.customfiledialog.done(QDialog.Accepted)  # close the dialog window
        self._controller.load_channels()  # move on to file selection

    def select_stats(self, statistic):
        """Select statistics to be saved.

        Parameters
        ----------
        statistic : str
            The selected statistic.
        """
        self._model.savestats[
            statistic] ^= True  # toggle boolean with xor operator
        line = None
        if statistic == "period":
            if self.line20:
                line = self.line20[0]
        elif statistic == "rate":
            if self.line21:
                line = self.line21[0]
        elif statistic == "tidalamp":
            if self.line22:
                line = self.line22[0]
        if line:
            line.set_color(self.togglecolors[line.get_color()])
        self.canvas2.draw()

    def toggle_options(self, state):
        """Toggle availability of configuration options.

        Based on current state.

        Parameters
        ----------
        state : str
            The aspect of the current state to which the availability of
            configuration options needs to be adapted.
        """
        if state in ["ECG", "PPG"]:
            self.tidalampcheckbox.setEnabled(False)
            self.tidalampcheckbox.setChecked(False)
            self.ax22.set_visible(False)
            self.canvas2.draw()
        elif state == "RESP":
            self.tidalampcheckbox.setEnabled(True)
            self.ax22.set_visible(True)
            self.canvas2.draw()
        elif state == "multiple files":
            self.editcheckbox.setEnabled(False)
            self.editcheckbox.setChecked(False)
            self.savecheckbox.setEnabled(True)
            self.correctcheckbox.setEnabled(True)
            self.markerchanmenu.setEnabled(False)
        elif state == "single file":
            self.editcheckbox.setEnabled(True)
            self.markerchanmenu.setEnabled(True)
            self.savecheckbox.setEnabled(False)
            self.savecheckbox.setChecked(False)
            self.correctcheckbox.setEnabled(False)
            self.correctcheckbox.setChecked(False)

    def reset_plot(self):
        """Reset plot elements associated with the current dataset."""
        self.ax00.clear()
        self.ax00.relim()
        self.line00 = None
        self.scat = None
        self.segmentspan = None
        self.ax10.clear()
        self.ax10.relim()
        self.line10 = None
        self.ax20.clear()
        self.ax20.relim()
        self.line20 = None
        self.ax21.clear()
        self.ax21.relim()
        self.line21 = None
        self.ax22.clear()
        self.ax22.relim()
        self.line22 = None
        self.canvas0.draw()
        self.canvas1.draw()
        self.canvas2.draw()
        self.navitools.update()
        self.currentFile.clear()
コード例 #14
0
class ColorChooser(QWidget):
    def __init__(self, default_color: str, show_pretty_name: bool = True):
        """
        Color chooser widget

        :param default_color: current color to set
        :param show_pretty_name: shows the pretty name of the color next to its hexa value
        """
        QWidget.__init__(self)

        # Convert 'regular' name colors into QColor to retrieve their hexa code
        self.color = QColor(default_color).name().lower()
        self.show_pretty_name = show_pretty_name

        # Widgets
        self.lab = QLabel()
        self.lab.setStyleSheet("color: black; font-style: italic;")

        self.btn = QPushButton(self.color.upper())
        self.btn.clicked.connect(self.__change_color)

        # Layout
        layout = QHBoxLayout()
        layout.setMargin(0)
        layout.addWidget(self.btn)
        if self.show_pretty_name:
            layout.addWidget(self.lab)
        self.setLayout(layout)

        self.update_bg()

    def update_bg(self) -> None:
        """
        Updates the background color given the button's name and looks for the color's display name
        """
        self.btn.setStyleSheet(f"background: {self.btn.text()}; color: black;")

        if self.btn.text().lower() in COLOR_DICT:
            pretty_name = COLOR_DICT[self.btn.text().lower()]
            if self.show_pretty_name:
                self.lab.setText(pretty_name)
            else:
                self.btn.setToolTip(pretty_name)
        else:
            if self.show_pretty_name:
                self.lab.clear()
            else:
                self.btn.setToolTip(None)

    def __change_color(self) -> None:
        """
        Displays the color chooser dialog to select a new color, then updates this widget
        """
        dlg = QColorDialog(self.color)
        if dlg.exec_():
            self.color = self.closest_color(dlg.currentColor().name())
            self.btn.setText(self.color.upper())
            self.update_bg()

    def get_color(self) -> str:
        """
        Retrieves the selected color to HEX format
        """
        return self.color

    def get_distance_color(self, c1, c2):
        """returns the distance between 2 colors"""
        def hex2dec(h):
            return int("0x" + h, 16)

        # normalize input format
        if c1[0] == "#":
            c1 = c1[1:]
        if c2[0] == "#":
            c2 = c2[1:]
        r1 = hex2dec(c1[0:2])
        g1 = hex2dec(c1[2:4])
        b1 = hex2dec(c1[4:6])
        r2 = hex2dec(c2[0:2])
        g2 = hex2dec(c2[2:4])
        b2 = hex2dec(c2[4:6])
        return (r2 - r1)**2 + (b2 - b1)**2 + (g2 - g1)**2

    def closest_color(self, c):
        min_d = 1000000
        for c1 in COLOR_DICT:
            d = self.get_distance_color(c, c1)
            if d == 0:
                return c1
            if d < min_d:
                min_c = c1
                min_d = d
        return min_c
コード例 #15
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.users = {}
        self.fps = 30

        self.playing = False

        self.capturing = False
        self.capture_frame = None

        self.flag_recognize = False
        self.recognizing_frame = None
        self.recognized_faces = []

        self.model = None

        self.setFixedSize(Config.width, Config.height)
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        self.setWindowIcon(QIcon('icons/icon.png'))
        self.setWindowTitle('人工智障人脸识别客户端')

        self.lbl_viewer = QLabel(self)
        self.lbl_viewer.setGeometry(
            QRect(10, 26, Config.width - 130, Config.height - 60))
        self.lbl_viewer.setText('没有图像')
        font = QFont()
        font.setPointSize(20)
        self.lbl_viewer.setFont(font)
        self.lbl_viewer.setAlignment(Qt.AlignCenter)
        self.lbl_viewer.setFrameShape(QFrame.StyledPanel)

        self.btn_open_camera = QPushButton(self)
        self.btn_open_camera.setGeometry(QRect(Config.width - 110, 10, 100,
                                               26))
        self.btn_open_camera.setText('打开摄像头')
        self.btn_open_camera.clicked.connect(self.btn_click)

        self.btn_close_camera = QPushButton(self)
        self.btn_close_camera.setGeometry(
            QRect(Config.width - 110, 46, 100, 26))
        self.btn_close_camera.setText('关闭摄像头')
        self.btn_close_camera.setDisabled(True)
        self.btn_close_camera.clicked.connect(self.btn_click)

        self.btn_open_video = QPushButton(self)
        self.btn_open_video.setGeometry(QRect(Config.width - 110, 82, 100, 26))
        self.btn_open_video.setText('播放视频')
        self.btn_open_video.clicked.connect(self.btn_click)

        self.btn_close_video = QPushButton(self)
        self.btn_close_video.setGeometry(
            QRect(Config.width - 110, 118, 100, 26))
        self.btn_close_video.setText('停止播放')
        self.btn_close_video.setDisabled(True)
        self.btn_close_video.clicked.connect(self.btn_click)

        self.cb_recognize = QCheckBox(self)
        self.cb_recognize.setText('启动识别')
        self.cb_recognize.setDisabled(True)
        self.cb_recognize.setGeometry(QRect(Config.width - 108, 154, 100, 26))
        self.cb_recognize.clicked.connect(self.change_recognize)

        self.cb_show_match_result = QCheckBox(self)
        self.cb_show_match_result.setText('显示匹配度')
        self.cb_show_match_result.setDisabled(True)
        self.cb_show_match_result.setGeometry(
            QRect(Config.width - 108, 192, 100, 26))
        if Config.show_match_result:
            self.cb_show_match_result.setChecked(True)
        self.cb_show_match_result.clicked.connect(
            self.change_show_match_result)

        lbl_threshold = QLabel(self)
        lbl_threshold.setText("识别精度")
        lbl_threshold.setGeometry(QRect(Config.width - 108, 228, 60, 26))

        self.sb_threshold = QSpinBox(self)
        self.sb_threshold.setValue(Config.threshold)
        self.sb_threshold.setMinimum(30)
        self.sb_threshold.setMaximum(100)
        self.sb_threshold.valueChanged.connect(self.change_threshold)
        self.sb_threshold.setGeometry(QRect(Config.width - 45, 228, 40, 26))

        self.btn_capture = QPushButton(self)
        self.btn_capture.setGeometry(
            QRect(Config.width - 110, Config.height - 200, 100, 26))
        self.btn_capture.setText('截屏')
        self.btn_capture.setDisabled(True)
        self.btn_capture.clicked.connect(self.btn_click)

        self.lbl_capture_pic = QLabel(self)
        self.lbl_capture_pic.setGeometry(
            QRect(Config.width - 110, Config.height - 160, 100, 100))
        self.lbl_capture_pic.setAlignment(Qt.AlignCenter)
        self.lbl_capture_pic.setFrameShape(QFrame.StyledPanel)

        self.btn_capture_save = QPushButton(self)
        self.btn_capture_save.setGeometry(
            QRect(Config.width - 110, Config.height - 60, 100, 26))
        self.btn_capture_save.setText('保存截图')
        self.btn_capture_save.setDisabled(True)
        self.btn_capture_save.clicked.connect(self.btn_click)

        self.train_model()

    def btn_click(self):
        btn = self.sender()
        if btn == self.btn_open_camera:
            self.btn_open_camera.setDisabled(True)
            self.btn_close_camera.setDisabled(False)
            self.btn_capture.setDisabled(False)
            self.cb_recognize.setDisabled(False)

            self.start_play(0)
        elif btn == self.btn_close_camera:
            self.stop_play()
            self.lbl_viewer.clear()
            self.btn_open_camera.setDisabled(False)
            self.btn_close_camera.setDisabled(True)
            self.btn_capture.setDisabled(True)
            self.cb_recognize.setDisabled(True)
        elif btn == self.btn_open_video:
            file_name = QFileDialog.getOpenFileName(
                self, "Open Video", "/",
                "Video Files (*.avi *.mp4 *.mpeg *.mov)")
            if file_name[0] != '':
                self.start_play(file_name[0])
                self.btn_close_video.setDisabled(False)
        elif btn == self.btn_close_video:
            self.stop_play()
            self.lbl_viewer.clear()
            self.btn_open_camera.setDisabled(False)
            self.btn_close_camera.setDisabled(True)
            self.btn_capture.setDisabled(True)
            self.cb_recognize.setDisabled(True)
        elif btn == self.btn_capture:
            self.capturing = True
            self.btn_capture_save.setDisabled(False)
        elif btn == self.btn_capture_save:
            AddUserFace(self.capture_frame).exec_()
            self.train_model()

    def change_recognize(self):
        if self.sender().isChecked():
            self.flag_recognize = True
            Thread(target=self.recognize).start()
            self.cb_show_match_result.setDisabled(False)
        else:
            self.flag_recognize = False
            self.cb_show_match_result.setDisabled(True)

    def change_show_match_result(self):
        Config.config_parser.set(
            "recognition", 'show_match_result',
            str(True if self.sender().isChecked() else False))
        Config.show_match_result = True if self.sender().isChecked() else False
        Config.save()

    @staticmethod
    def change_threshold(value):
        Config.config_parser.set("recognition", 'threshold', str(value))
        Config.threshold = value
        Config.save()

    def start_play(self, path):
        self.playing = True
        Thread(target=self.play, args=(path, )).start()

    def stop_play(self):
        self.lbl_viewer.clear()
        self.playing = False

    def play(self, path):
        video_capture = cv2.VideoCapture(path)
        fps = video_capture.get(cv2.CAP_PROP_FPS)
        while self.playing:
            start_time = time.time()
            ret, frame = video_capture.read()
            if ret:
                if self.flag_recognize:
                    # 存放当前帧给识别线程
                    if self.recognizing_frame is None:
                        self.recognizing_frame = frame.copy()
                    # 显示已识别的人脸
                    faces = self.recognized_faces.copy()
                    for face in faces:
                        x, y, w, h = face['position']
                        cv2.rectangle(frame, (x, y), (x + w, y + h),
                                      (255, 0, 0), 1, cv2.LINE_AA)
                        cv2.putText(
                            frame, face['name'] +
                            ('(' + str(face['degree']) +
                             ')' if Config.show_match_result else ''),
                            (x, y - 15), cv2.FONT_HERSHEY_SIMPLEX, 2,
                            (255, 0, 0), 2)

                img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                image = QImage(img, img.shape[1], img.shape[0],
                               img.shape[1] * 3, QImage.Format_RGB888)
                pix_map = QPixmap.fromImage(image)
                pix_map = pix_map.scaled(Config.width - 130,
                                         Config.height - 60,
                                         Qt.KeepAspectRatio)
                self.lbl_viewer.setPixmap(pix_map)

                # 保存截图
                if self.capturing:
                    self.capture_frame = frame.copy()
                    pix_map = pix_map.scaled(100, 100, Qt.KeepAspectRatio)
                    self.lbl_capture_pic.setPixmap(pix_map)
                    self.capturing = False

                # 根据FPS控制休眠
                end_time = time.time()
                diff_time = end_time - start_time
                if diff_time < 1 / fps:
                    time.sleep(1 / fps - diff_time)

    def recognize(self):
        while self.flag_recognize:
            try:
                if self.recognizing_frame is None:
                    time.sleep(0.05)
                    continue
                self.recognized_faces.clear()
                faces = HaarcascadeDetective.get_faces_position(
                    self.recognizing_frame)
                for (x, y, w, h) in faces:
                    recognized_face = {'position': (x, y, w, h)}
                    face = self.recognizing_frame[y:y + h, x:x + w]
                    if self.model is not None:
                        gray = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY)
                        params = self.model.predict(gray)
                        if params[1] <= Config.threshold:
                            recognized_face['name'] = self.users[params[0]]
                            recognized_face['degree'] = int(params[1])
                    self.recognized_faces.append(recognized_face)
                self.recognizing_frame = None
            except Exception as e:
                print(e)

    def train_model(self):
        users = DbHelper.query_users()
        for user in users:
            self.users[user[0]] = user[1]

        y, x = [], []
        if not os.path.exists("faces"):
            return
        faces_dir = os.listdir('faces')
        for user_dir in faces_dir:
            faces = os.listdir('faces{}{}'.format(os.sep, user_dir))
            for face in faces:
                y.append(int(user_dir))
                im = cv2.imread(
                    'faces{}{}{}{}'.format(os.sep, user_dir, os.sep, face), 0)
                x.append(np.asarray(im, dtype=np.uint8))
        if len(x) != 0 and len(y) != 0:
            self.model = cv2.face.LBPHFaceRecognizer_create()
            self.model.train(np.asarray(x), np.asarray(y, dtype=np.int64))

    def closeEvent(self, *args, **kwargs):
        self.playing = False
コード例 #16
0
lbl = QLabel(window)
lbl.setGeometry(100, 120, 1536, 761)


def showimage():
    # lbl.clear()
    selectedtran = transistorlist.currentText()
    selectedtran = selectedtran + '.png'
    image = QtGui.QImage(selectedtran)
    pixmap = QtGui.QPixmap(image)
    lbl.setPixmap(pixmap.scaled(lbl.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))


while 1:
    if transistorlist.currentText() == 'None.png':
        lbl.clear()
        image = QtGui.QImage('None.png')
        pixmap = QtGui.QPixmap(image)
        lbl.setPixmap(pixmap.scaled(lbl.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))
        window.show()
        app.exec_()
    elif transistorlist.currentIndexChanged != -1:
        lbl.clear()
        transistorlist.currentIndexChanged.connect(showimage())
        window.show()
        app.exec_()
    else:
        break

# window.show()
# app.exec_()
コード例 #17
0
class Main(QMainWindow):
    def __init__(self):
        super(Main, self).__init__()

        # Basic Settings
        self.setGeometry(300, 200, 591, 280)
        self.setMinimumSize(QSize(591, 280))
        self.setMaximumSize(QSize(591, 280))
        self.setWindowIcon(QIcon("arti.PNG"))
        self.setWindowTitle("Artigence Updates")
        self.setFont(QFont('Roboto', 12))

        # Color Scheme
        self.palette = QPalette()
        self.palette.setColor(self.palette.Window, QColor('#000000'))
        self.palette.setColor(self.palette.WindowText, QColor('#FFFFFF'))
        self.setPalette(self.palette)

        self.light_palette = QPalette()
        self.light_palette.setColor(self.light_palette.Window, QColor('#FFFFFF'))
        self.light_palette.setColor(self.light_palette.WindowText, QColor('#000000'))

        # Setting MenuBar
        self.menubar = QMenuBar(self)
        self.menubar.setGeometry(0, 0, 682, 21)
        self.menubar.setFont(QFont('Roboto', 10))

        self.date_menu = QMenu(self.menubar)
        self.date_menu.setTitle(str(datetime.now().strftime('%d-%m-%Y')))

        self.theme_menu = QMenu(self.menubar)
        self.theme_menu.setTitle('Theme')

        self.dark_theme = QAction('Dark Theme')
        self.dark_theme.setShortcut(QKeySequence('Ctrl+Shift+D'))
        self.theme_menu.addAction(self.dark_theme)
        self.dark_theme.triggered.connect(lambda: self.dark())

        self.light_theme = QAction('Light Theme')
        self.light_theme.setShortcut(QKeySequence('Ctrl+Shift+L'))
        self.theme_menu.addAction(self.light_theme)
        self.light_theme.triggered.connect(lambda: self.light())

        self.setMenuBar(self.menubar)
        self.menubar.addAction(self.date_menu.menuAction())
        self.menubar.addAction(self.theme_menu.menuAction())

        # Widgets

        self.update_label = QLabel(self)
        self.update_label.setGeometry(20, 30, 551, 41)
        self.update_label.setText('Update Checker')
        self.update_label.setAlignment(Qt.AlignCenter)

        self.available = QLabel(self)
        self.available.setGeometry(20, 110, 541, 61)
        self.available.setText('')
        self.available.setAlignment(Qt.AlignCenter)

        self.yes = QPushButton(self)
        self.yes.setGeometry(350, 230, 75, 33)
        self.yes.setText('Yes')

        self.no = QPushButton(self)
        self.no.setGeometry(440, 230, 145, 33)
        self.no.setText('Just Open My App')

        self.no.clicked.connect(lambda: self.main_func())

    def main_func(self):
        self.setWindowFlags(QtCore.Qt.Tool)
        time.sleep(2)
        from start import Artigence
        self.main = Artigence()
        self.main.show()



    def dark(self):
        self.setPalette(self.palette)

    def light(self):
        self.setPalette(self.light_palette)

    # The A.I. will speak through this function
    def speak(self, audio):
        self.engine = pyttsx3.init('sapi5')
        voices = self.engine.getProperty('voices')
        self.engine.setProperty('voice', voices[1].id)
        self.engine.setProperty('rate', 165)
        self.available.setText(audio)
        self.engine.say(audio)
        self.engine.runAndWait()
        self.available.clear()