Пример #1
0
class Weasel(QMainWindow):
    def __init__(self):
        """Creates the MDI container."""
        super().__init__()
        self.showFullScreen()
        self.setWindowTitle("WEASEL")
        self.centralwidget = QWidget(self)
        self.setCentralWidget(self.centralwidget)
        self.centralwidget.setLayout(QVBoxLayout(self.centralwidget))
        self.mdiArea = QMdiArea(self.centralwidget)
        self.mdiArea.tileSubWindows()
        self.centralwidget.layout().addWidget(self.mdiArea)
        self.statusBar = QStatusBar()
        self.centralwidget.layout().addWidget(self.statusBar)
        self.selectedStudy = ''
        self.selectedSeries = ''
        self.selectedImageName = ''
        self.currentImagePath = ''

        # XML reader object to process XML configuration file
        self.objConfigXMLReader = WeaselConfigXMLReader()
        menuXMLFile = self.objConfigXMLReader.getMenuFile()
        self.weaselDataFolder = self.objConfigXMLReader.getWeaselDataFolder()

        # XML reader object to process XML DICOM data file
        self.objXMLReader = WeaselXMLReader()

        menus.setupMenus(self, menuXMLFile)
        menus.buildContextMenu(self, menuXMLFile)
        #toolBar.setupToolBar(self)  commented out to remove Ferret from Weasel
        self.setStyleSheet(styleSheet.TRISTAN_GREY)
        logger.info("WEASEL GUI created successfully.")

    def getMDIAreaDimensions(self):
        return self.mdiArea.height(), self.mdiArea.width()
Пример #2
0
class MDIWindow(QMainWindow):

    count = 0

    def __init__(self):
        super().__init__()

        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        bar = self.menuBar()

        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("cascade")
        file.addAction("Tiled")
        file.triggered[QAction].connect(self.WindowTrig)
        self.setWindowTitle("MDI Application")

    def WindowTrig(self, p):

        if p.text() == "New":
            MDIWindow.count = MDIWindow.count + 1
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("Sub Window" + str(MDIWindow.count))
            self.mdi.addSubWindow(sub)
            sub.show()

        if p.text() == "cascade":
            self.mdi.cascadeSubWindows()

        if p.text() == "Tiled":
            self.mdi.tileSubWindows()
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.title = 'event annotation tool'
        self.left = 50
        self.top = 50
        self.v_width = 640-200 #1400#
        self.v_height = 480-200 #1000#
        self.set_input=0

        self.setWindowTitle(self.title)

        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        self.mdi.tileSubWindows()

        PATH_FILE = '/home/barbara/Desktop/demo'#'/home/barbara/Desktop/car_data/Normal/Nevsky prospect traffic surveillance video'
        video_feed=action_time_antation_tool.annotation_openCV(PATH_FILE)

        v_sub = SubWindow(video_feed)  # QMdiSubWindow()
        v_sub.setWidget(video_feed)
        v_sub.resize(self.v_width+25, self.v_height+75)
        v_sub.setMaximumSize(self.v_width+25, self.v_height+75)
        v_sub.setWindowTitle("Feed " + str(len(self.label_v_list)))
        self.mdi.addSubWindow(v_sub)  # self.mdi
        self.mdi.tileSubWindows()
        v_sub.show()
class MainWin(QMainWindow):
    """主窗口"""
    count = 0

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setWindowTitle("QMdiArea QMdiSubWidow 使用")

        self.mdi_area = QMdiArea()
        self.setCentralWidget(self.mdi_area)

        menu_bar = self.menuBar()
        menu_file = menu_bar.addMenu("文件")
        action_new = menu_file.addAction("新建")
        action_new.setData("new")
        action_save = menu_file.addAction("保存")
        action_save.setData("save")
        action_cascade = menu_file.addAction("级联&Cascade")
        action_cascade.setData("cascade")
        action_tiled = menu_file.addAction("平铺&Tiled")
        action_tiled.setData("tiled")
        menu_file.triggered.connect(self.window_action)

    def window_action(self, action):
        print("点击", action.data())
        if action.data() == "new":
            MainWin.count += 1
            sub_win = QMdiSubWindow()
            sub_win.setWidget(QTextEdit())
            sub_win.setWindowTitle("子窗口 %d" % MainWin.count)
            self.mdi_area.addSubWindow(sub_win)
        if action.data() == "csscade":
            self.mdi_area.cascadeSubWindows()  # 级联模式排列
        if action.data() == "tiled":
            self.mdi_area.tileSubWindows()  # 平铺排列
Пример #5
0
    def setupWindows(self):
        """
        Set up QMdiArea parent and subwindows.
        Add available cameras on local system as items to 
        list widget.
        """
        # Create images directory if it does not already exist
        path = 'images'
        if not os.path.exists(path):
            os.makedirs(path)

        # Set up list widget that will display identified
        # cameras on your computer.
        picture_label = QLabel("Press 'Spacebar' to take pictures.")
        camera_label = QLabel("Available Cameras")
        self.camera_list_widget = QListWidget()
        self.camera_list_widget.setAlternatingRowColors(True)

        # Add availableCameras to a list to be displayed in
        # list widget. Use QCameraInfo() to list available cameras.
        self.cameras = list(QCameraInfo().availableCameras())
        for camera in self.cameras:
            self.list_item = QListWidgetItem()
            self.list_item.setText(camera.deviceName())
            self.camera_list_widget.addItem(self.list_item)

        # Create button that will allow user to select camera
        choose_cam_button = QPushButton("Select Camera")
        choose_cam_button.clicked.connect(self.selectCamera)

        # Create child widgets and layout for camera controls subwindow
        controls_gbox = QGroupBox()
        controls_gbox.setTitle("Camera Controls")

        v_box = QVBoxLayout()
        v_box.addWidget(picture_label, alignment=Qt.AlignCenter)
        v_box.addWidget(camera_label)
        v_box.addWidget(self.camera_list_widget)
        v_box.addWidget(choose_cam_button)

        controls_gbox.setLayout(v_box)

        controls_sub_window = QMdiSubWindow()
        controls_sub_window.setWidget(controls_gbox)
        controls_sub_window.setAttribute(Qt.WA_DeleteOnClose)

        # Create view finder subwindow
        self.view_finder_window = QMdiSubWindow()
        self.view_finder_window.setWindowTitle("Camera View")
        self.view_finder_window.setAttribute(Qt.WA_DeleteOnClose)

        # Create QMdiArea widget to manage subwindows
        mdi_area = QMdiArea()
        mdi_area.tileSubWindows()
        mdi_area.addSubWindow(self.view_finder_window)
        mdi_area.addSubWindow(controls_sub_window)

        # Set mdi_area widget as the central widget of main window
        self.setCentralWidget(mdi_area)
Пример #6
0
class SubWin(QMainWindow):
    count = 0
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        self.toolBar = QToolBar()
        self.addToolBar(self.toolBar)
        self.toolBar.addAction("新建")
        self.toolBar.addAction("级联")
        self.toolBar.addAction("平铺")
        self.toolBar.addAction("关闭全部")
        self.toolBar.addAction("关闭活动窗口")
        self.toolBar.addAction("测试")
        self.toolBar.actionTriggered[QAction].connect(self.windowaction)
        bar = self.menuBar()
        file = bar.addMenu("File")
        # 添加子菜单
        file.addAction("新建")
        file.addAction("级联")
        file.addAction("平铺")
        file.triggered[QAction].connect(self.windowaction)
        self.setWindowTitle("MDI Demo")
        #self.showFullScreen() #全屏显示
        self.showMaximized() #窗口最大化
        #self.showNormal() #正常显示
        # self.setGeometry(QDesktopWidget().screenGeometry())
    def windowaction(self, q):
        type = q.text()
        print("Triggered : %s" % type)
        if type == "新建":
            # 子窗口增加一个
            self.count = self.count + 1
            # 实例化多文档界面对象
            sub = QMdiSubWindow()
            # 向sub内部添加控件
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("subWindow %d" % self.count)
            self.mdi.addSubWindow(sub)
            sub.show()
            #sub.hide()
        elif type == "级联":
            self.mdi.cascadeSubWindows()
        elif type == "平铺":
            self.mdi.tileSubWindows()
        elif type == "关闭全部":
            self.mdi.closeAllSubWindows()
        elif type == "关闭活动窗口":
            self.mdi.closeActiveSubWindow()
        elif type == "测试":
            lst = self.mdi.subWindowList()
            print(lst)
    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
Пример #7
0
    class MyMainWindow(QMainWindow):
        count = 0

        def __init__(self, widgets):
            super().__init__()

            self.widget_classes = widget_classes

            self.init_ui()

        def init_ui(self):
            self.setWindowTitle('MDI Application')
            self.setWindowIcon(QIcon('pyicon.png'))
            self.setGeometry(100, 100, 800, 600)

            # Create an instance of MDI.
            self.mdi = QMdiArea()
            self.setCentralWidget(self.mdi)

            # Menu bar.
            menu_bar = self.menuBar()

            file_menu = menu_bar.addMenu('File')
            file_menu.addAction('New')
            file_menu.addAction('Cascade')
            file_menu.addAction('Tiled')

            file_menu.triggered[QAction].connect(self.window_triggered)

            # Exit QAction.
            exit_action = QAction('Exit', self)
            exit_action.setShortcut(QKeySequence.Quit)
            exit_action.triggered.connect(self.close)

            file_menu.addAction(exit_action)

            # Status bar.
            status = self.statusBar()
            status.showMessage('Status bar')

        def window_triggered(self, p):
            if p.text() == 'New':
                MyMainWindow.count += 1

                sub = QMdiSubWindow()
                widget = self.widget_classes[MyMainWindow.count % 2]()
                sub.setWidget(widget)
                sub.setWindowTitle('Sub Window {}'.format(MyMainWindow.count))

                self.mdi.addSubWindow(sub)
                sub.show()

            if p.text() == 'Cascade':
                self.mdi.cascadeSubWindows()

            if p.text() == 'Tiled':
                self.mdi.tileSubWindows()
Пример #8
0
class MDIWindow(QMainWindow):
    count = 0

    def __init__(self):
        super().__init__()

        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        bar = self.menuBar()

        self.current_dir = None

        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("cascade")
        file.addAction("Tiled")
        file.triggered[QAction].connect(self.WindowTrig)
        self.setWindowTitle("MDI Application")

        load = bar.addMenu("Load")
        load.addAction("2D")
        load.addAction("3D")
        load.triggered[QAction].connect(self.self.dir_open)



    def WindowTrig(self, p):

        if p.text() == "New":
            MDIWindow.count = MDIWindow.count + 1
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("Sub Window" + str(MDIWindow.count))
            self.mdi.addSubWindow(sub)
            sub.show()

        if p.text() == "cascade":
            self.mdi.cascadeSubWindows()

        if p.text() == "Tiled":
            self.mdi.tileSubWindows()


    def dir_open(self, p):

        if p.text() == "1D":
            self.current_dir = dlg.File_dlg.openDirNameDialog(self)
            files_ls = glob.glob(self.current_dir + '/*.ibw')
            fls = [f[len(self.current_dir) + 1:] for f in files_ls]
            print(fls)
#            self.twoD_list.addItems(fls)
#            self.threeD_list.addItems(zip)
        if p.text() == "2D":
            self.current_dir = dlg.File_dlg.openDirNameDialog(self)
            zip_ls = glob.glob(self.current_dir + '/*.zip')
            zp = [f[len(self.current_dir) + 1:] for f in zip_ls]
            print(zp)
Пример #9
0
class MainWindow(QMainWindow):
    def __init__(self, application_name):
        super(MainWindow, self).__init__()
        self.title = application_name
        self.mdi = QMdiArea()
        self.initialize_ui()

    def initialize_ui(self):
        self.setCentralWidget(self.mdi)
        self.setWindowTitle(self.title)
        self.showMaximized()

    def add_tile(self, module):
        self.mdi.addSubWindow(module)

    def tile(self):
        self.mdi.tileSubWindows()
Пример #10
0
        def tile_subwindows(mdi: QtWidgets.QMdiArea,
                            except_type: Type = type(None)):
            """Tile all subwindows of an MDI area, except for objects of 'except_type'."""
            # Hide windows to keep them from being tiled:
            windows_hidden = list()  # type: List[QtWidgets.QMdiSubWindow]
            for window in mdi.subWindowList():
                if type(window) == except_type:
                    windows_hidden.append(window)
                    window.hide()

            mdi.tileSubWindows()

            # Show hidden windows again:
            for window in windows_hidden:
                window.show()

            # Move all tiled windows above the excluded ones:
            for window in mdi.subWindowList():
                if window not in windows_hidden:
                    mdi.setActiveSubWindow(window)
Пример #11
0
class MdiQWebViewWindows(BaseQWebViewWindows):
    def __init__(self):
        super().__init__()
        self._mdi_area = None

    def add_webview(self, webview):
        if self._mdi_area is None:
            self._mdi_area = QMdiArea()
            self._mdi_area.resize(1024, 768)
            # self._mdi_area.setWindowTitle()
            self._mdi_area.show()
        subwindow = self._mdi_area.addSubWindow(webview)
        webview.titleChanged.connect(subwindow.setWindowTitle)
        subwindow.show()
        self._mdi_area.tileSubWindows()

    def remove_webview(self, webview):
        subwindow = webview.parentWidget()
        webview.close()
        self._mdi_area.removeSubWindow(subwindow)
        self._mdi_area.tileSubWindows()
Пример #12
0
    def init_window(self):
        """
        Set up QMdiArea parent and sub_windows.
        Add available cameras on local system as items to
        list widget.
        """
        # Load image in sub_window_view
        self.load_image("images/chameleon.png")
        self.sub_window_view.setWidget(self.label_image)
        self.sub_window_models.setWidget(self.gbox_model)

        # Create QMdiArea widget to manage sub_windows
        mdi_area = QMdiArea()
        mdi_area.tileSubWindows()

        # mdi_area.addSubWindow(self.sub_window_camera)
        mdi_area.addSubWindow(self.sub_window_models)
        mdi_area.addSubWindow(self.sub_window_view)

        # Set up dock widget
        self.dock_camera.setWindowTitle("Camera Control")
        self.dock_camera.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea)
        self.dock_camera.setWidget(self.camera_contents)

        self.dock_filter.setWindowTitle("Camera Filter")
        self.dock_filter.setWidget(self.filter_contents)

        self.dock_color.setWindowTitle("Camera Color")
        self.dock_color.setWidget(self.color_contents)
        self.dock_color.setVisible(False)

        # Set initial location of dock widget in main window
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_camera)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_filter)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock_color)

        # Set mdi_area widget as the central widget of main window
        self.setCentralWidget(mdi_area)
Пример #13
0
class Ventana_Principal(QMainWindow):
    def __init__(self, parent=None):

        QMainWindow.__init__(self, parent)
        self.num_ventanas = 0
        self.setWindowTitle('Ejemplo de aplicacio MDI para getphones')
        self.setGeometry(0, 0, 800, 600)
        self.centraEnPantalla()

        self.mdi_area = QMdiArea()
        self.setCentralWidget(self.mdi_area)

    #personPhoto_FilePath is a string
    #personData is a tuple: #(name, surname, ubication, phone ext)
    #personExtension is a string
    def addNewFichaPersona(self, personPhoto_FilePath, personData,
                           personExtension):

        fichaPersona = Ficha_Persona()
        fichaPersona.setPersonPhoto(personPhoto_FilePath)
        fichaPersona.setPersonData(personData)
        fichaPersona.setPersonPhonenumber(personExtension)

        subventana = QMdiSubWindow()
        subventana.setWidget(fichaPersona)
        subventana.setWindowTitle('Subventana nº {}'.format(self.num_ventanas))
        self.mdi_area.addSubWindow(subventana)
        subventana.show()
        self.mdi_area.tileSubWindows()

    def centraEnPantalla(self):
        resolucion_pantalla = QDesktopWidget().screenGeometry()
        self.move(
            int(resolucion_pantalla.width() / 2 -
                self.frameSize().width() / 2),
            int(resolucion_pantalla.height() / 2 -
                self.frameSize().height() / 2))
class MDIWindow(QMainWindow):
    count = 0

    def __init__(self):

        super().__init__()
        uic.loadUi("mainwindow.ui", self)
        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        self.menu_File.triggered[QAction].connect(self.WindowTrig)
        #self.setWindowTitle("MDI Application")

    def WindowTrig(self, p):
        if p.text() == "&New":
            MDIWindow.count = MDIWindow.count + 1
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("Sub Window" + str(MDIWindow.count))
            self.mdi.addSubWindow(sub)
            sub.show()
        if p.text() == "&Cascade":
            self.mdi.cascadeSubWindows()
        if p.text() == "&Tile":
            self.mdi.tileSubWindows()
Пример #15
0
class GUIWindow(QMainWindow):
    def __init__(self, app, pipeline=Pipeline()):
        super().__init__()
        self._app = app
        self._logger = logging.getLogger(self.__class__.__name__)
        self._is_initialized = False
        self.init_basic(pipeline)
        self.init_ui()
        self.init_controls()
        self.setWindowTitle("Cognigraph")
        self.setWindowIcon(QIcon(':/cognigraph_icon.png'))

    def init_basic(self, pipeline):
        self._pipeline = pipeline  # type: Pipeline
        self._updater = AsyncUpdater(self._app, pipeline)
        self._pipeline._signal_sender.long_operation_started.connect(
            self._show_progress_dialog)
        self._pipeline._signal_sender.long_operation_finished.connect(
            self._hide_progress_dialog)
        self._pipeline._signal_sender.request_message.connect(
            self._show_message)
        self._pipeline._signal_sender.node_widget_added.connect(
            self._on_node_widget_added)
        self._controls = Controls(pipeline=self._pipeline)
        self._controls.setSizePolicy(QSizePolicy.Preferred,
                                     QSizePolicy.Expanding)

        self._controls.tree_widget.node_removed.connect(self._on_node_removed)
        if hasattr(self, "central_widget"):
            for w in self.central_widget.subWindowList():
                self.central_widget.removeSubWindow(w)

    def init_controls(self):
        self.controls_dock.setWidget(self._controls)
        self.run_toggle_action.triggered.disconnect()
        self.run_toggle_action.triggered.connect(self._updater.toggle)
        self._updater._sender.run_toggled.connect(self._on_run_button_toggled)
        self._updater._sender.errored.connect(self._show_message)
        self.is_initialized = False

    def init_ui(self):
        self.central_widget = QMdiArea()
        self.setCentralWidget(self.central_widget)

        # -------- controls widget -------- #
        self.controls_dock = QDockWidget("Processing pipeline setup", self)
        self.controls_dock.setObjectName("Controls")
        self.controls_dock.setAllowedAreas(Qt.LeftDockWidgetArea
                                           | Qt.RightDockWidgetArea)
        self.controls_dock.visibilityChanged.connect(
            self._update_pipeline_tree_widget_action_text)

        self.addDockWidget(Qt.LeftDockWidgetArea, self.controls_dock)

        # self._controls.setMinimumWidth(800)
        # --------------------------------- #

        file_menu = self.menuBar().addMenu("&File")  # file menu
        load_pipeline_action = self._createAction("&Load pipeline",
                                                  self._load_pipeline)
        save_pipeline_action = self._createAction("&Save pipeline",
                                                  self._save_pipeline)
        file_menu.addAction(load_pipeline_action)
        file_menu.addAction(save_pipeline_action)

        # -------- view menu & toolbar -------- #
        tile_windows_action = self._createAction(
            "&Tile windows", self.central_widget.tileSubWindows)
        view_menu = self.menuBar().addMenu("&View")
        view_menu.addAction(tile_windows_action)
        view_toolbar = self.addToolBar("View")
        view_toolbar.addAction(tile_windows_action)
        # ------------------------------------- #

        edit_menu = self.menuBar().addMenu("&Edit")
        self._toggle_pipeline_tree_widget_action = self._createAction(
            "&Hide pipeline settings", self._toggle_pipeline_tree_widget)
        edit_menu.addAction(self._toggle_pipeline_tree_widget_action)
        edit_toolbar = self.addToolBar("Edit")
        edit_toolbar.setObjectName("edit_toolbar")
        edit_toolbar.addAction(self._toggle_pipeline_tree_widget_action)

        # -------- run menu & toolbar -------- #
        self.run_toggle_action = self._createAction(
            "&Start", self._on_run_button_toggled)
        run_menu = self.menuBar().addMenu("&Run")
        self.initialize_pipeline = self._createAction("&Initialize pipeline",
                                                      self.initialize)
        run_menu.addAction(self.run_toggle_action)
        run_menu.addAction(self.initialize_pipeline)
        run_toolbar = self.addToolBar("Run")
        run_toolbar.setObjectName("run_toolbar")
        run_toolbar.addAction(self.run_toggle_action)
        run_toolbar.addAction(self.initialize_pipeline)
        # ------------------------------------ #

    def _toggle_pipeline_tree_widget(self):
        if self.controls_dock.isHidden():
            self.controls_dock.show()
        else:
            self.controls_dock.hide()

    def _update_pipeline_tree_widget_action_text(self, is_visible):
        if is_visible:
            self._toggle_pipeline_tree_widget_action.setText(
                "&Hide pipelne settings")
        else:
            self._toggle_pipeline_tree_widget_action.setText(
                "&Show pipelne settings")

    def _load_pipeline(self):
        file_dialog = QFileDialog(caption="Select pipeline file",
                                  directory=PIPELINES_DIR)
        ext_filter = "JSON file (*.json);; All files (*.*)"
        pipeline_path = file_dialog.getOpenFileName(filter=ext_filter)[0]
        if pipeline_path:
            self._logger.info("Loading pipeline configuration from %s" %
                              pipeline_path)
            if not self._updater.is_paused:
                self.run_toggle_action.trigger()
            with open(pipeline_path, "r") as db:
                try:
                    params_dict = json.load(db)
                except json.decoder.JSONDecodeError as e:
                    self._show_message("Bad pipeline configuration file",
                                       detailed_text=str(e))

                pipeline = self.assemble_pipeline(params_dict, "Pipeline")
                self.init_basic(pipeline)
                self.init_controls()
                # self.resize(self.sizeHint())
        else:
            return

    def _save_pipeline(self):
        self._logger.info("Saving pipeline")
        file_dialog = QFileDialog(caption="Select pipeline file",
                                  directory=PIPELINES_DIR)
        ext_filter = "JSON file (*.json);; All files (*.*)"
        pipeline_path = file_dialog.getSaveFileName(filter=ext_filter)[0]
        if pipeline_path:
            self._logger.info("Saving pipeline configuration to %s" %
                              pipeline_path)
            try:
                self._pipeline.save_pipeline(pipeline_path)
            except Exception as exc:
                self._show_message(
                    "Cant`t save pipeline configuration to %s" % pipeline_path,
                    detailed_text=str(exc),
                )
                self._logger.exception(exc)

    def assemble_pipeline(self, d, class_name):
        node_class = getattr(nodes, class_name)
        node = node_class(**d["init_args"])
        for child_class_name in d["children"]:
            child = self.assemble_pipeline(d["children"][child_class_name],
                                           child_class_name)
            node.add_child(child)
        return node

    def initialize(self):
        is_paused = self._updater.is_paused
        if not is_paused:
            self._updater.stop()
        self._logger.info("Initializing all nodes")
        async_initer = AsyncPipelineInitializer(pipeline=self._pipeline,
                                                parent=self)
        async_initer.no_blocking_execution()
        for node in self._pipeline.all_nodes:
            if hasattr(node, "widget"):
                if not node.widget.parent():  # widget not added to QMdiArea
                    self._add_subwindow(node.widget, repr(node))
        self.central_widget.tileSubWindows()
        self.run_toggle_action.setDisabled(False)
        if not is_paused:
            self._updater.start()

    def _finish_initialization(self):
        self.progress_dialog.hide()
        self.progress_dialog.deleteLater()
        for node in self._pipeline.all_nodes:
            if hasattr(node, "widget"):
                self._add_subwindow(node.widget, repr(node))
        self.central_widget.tileSubWindows()

    def _add_subwindow(self, widget, title):
        sw = _HookedSubWindow(self.central_widget)
        sw.setWidget(widget)
        sw.setWindowTitle(title)
        widget.show()

    def _show_progress_dialog(self, text):
        # -------- setup progress dialog -------- #
        self.progress_dialog = QProgressDialog(self)
        self.progress_dialog.setLabelText(text)
        self.progress_dialog.setCancelButtonText(None)
        self.progress_dialog.setRange(0, 0)
        self.progress_dialog.show()

    def _hide_progress_dialog(self):
        self.progress_dialog.hide()
        self.progress_dialog.deleteLater()

    def _on_subwindow_close(self, close_event):
        pass

    def _on_node_widget_added(self, widget, widget_name):
        self._add_subwindow(widget, widget_name)
        self.central_widget.tileSubWindows()

    def _on_node_removed(self, tree_item):
        if hasattr(tree_item.node, "widget"):
            try:
                self.central_widget.removeSubWindow(
                    tree_item.node.widget.parent())
            except AttributeError:
                pass
            except Exception as exc:
                self._show_message(
                    "Can`t remove widget for %s" % tree_item.node,
                    detailed_text=str(exc),
                )
                self._logger.exception(exc)

    def _show_message(self, text, detailed_text=None, level="error"):
        if level == "error":
            icon = QMessageBox.Critical
        elif level == "warning":
            icon = QMessageBox.Warning
        elif level == "info":
            icon = QMessageBox.Information
        msg = QMessageBox(self)
        msg.setIcon(icon)
        msg.setText(text)
        msg.setDetailedText(detailed_text)
        msg.show()

    def _createAction(
        self,
        text,
        slot=None,
        shortcut=None,
        icon=None,
        tip=None,
        checkable=False,
    ):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            action.triggered.connect(slot)
        if checkable:
            action.setCheckable(True)
        return action

    def moveEvent(self, event):
        return super(GUIWindow, self).moveEvent(event)

    def _on_run_button_toggled(self, is_paused=True):
        if is_paused:
            self.run_toggle_action.setText("Start")
        else:
            self.run_toggle_action.setText("Pause")

    @property
    def is_initialized(self):
        return self._is_initialized

    @is_initialized.setter
    def is_initialized(self, value):
        if value:
            self.run_toggle_action.setDisabled(False)
        else:
            self.run_toggle_action.setDisabled(True)
        self._is_initialized = value

    @property
    def _node_widgets(self) -> List[QWidget]:
        node_widgets = list()
        for node in self._pipeline.all_nodes:
            try:
                node_widgets.append(node.widget)
            except AttributeError:
                pass
        return node_widgets
Пример #16
0
class MainWindow(QMainWindow):
    count = 0
    linecount = 0
    maxLine = 100

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.item0 = BytesIO()

        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        bar = self.menuBar()

        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("cascade")
        file.addAction("Tiled")
        file.triggered[QAction].connect(self.windowaction)
        self.setWindowTitle("Camphor")

        MainWindow.count += 1
        self.output_window = OutputWindow()
        self.mdi.addSubWindow(self.output_window)

        MainWindow.count += 1
        self.script_window = ScriptWindow()
        self.mdi.addSubWindow(self.script_window)

        MainWindow.count += 1
        self.viewer_window = ViewerWindow()
        self.mdi.addSubWindow(self.viewer_window)

        #MainWindow.count += 1
        #self.spread_sheet = SpreadSheetWidget()
        #self.mdi.addSubWindow(self.spread_sheet)

        headers = ["000", "001", "002"]
        tableData0 = [['abc', 100, 200], ['fff', 130, 260], ['jjj', 190, 300],
                      ['ppp', 700, 500], ['yyy', 800, 900]]

        #model = MyTableModel(tableData0, headers)
        table_df = pd.DataFrame(tableData0, columns=headers)

        MainWindow.count += 1
        self.dataframe_viewer = DataFrameViewer(table_df)
        self.mdi.addSubWindow(self.dataframe_viewer)

        # QProcess object for external app
        self.process = QProcess(self)
        self.process.readyReadStandardOutput.connect(
            lambda: self.dataReady("std"))
        self.process.readyReadStandardError.connect(
            lambda: self.dataReady("error"))
        self.process.finished.connect(lambda: self.update_svg())

        #Connect Slots
        self.script_window.button_exec.clicked.connect(
            lambda: self.run_script())
        self.script_window.button_read.clicked.connect(lambda: self.read_svg())
        #self.viewer_window.button_save.clicked.connect(lambda: self.save_svg())

        #Assign Shortcuts
        self.shortcut_update = QShortcut(QKeySequence("Ctrl+R"), self)
        self.shortcut_update.activated.connect(lambda: self.run_script())
        self.shortcut_update = QShortcut(QKeySequence("Ctrl+O"), self)
        self.shortcut_update.activated.connect(lambda: self.read_svg())
        self.shortcut_update = QShortcut(QKeySequence("Ctrl+S"), self)
        self.shortcut_update.activated.connect(lambda: self.save_svg())

    def windowaction(self, q):
        if q.text() == "cascade":
            self.mdi.cascadeSubWindows()

        if q.text() == "Tiled":
            self.mdi.tileSubWindows()

    @pyqtSlot()
    def read_svg(self):
        print("READ")
        self.script_window.fname = QFileDialog.getOpenFileName(
            self, 'Open file', '/home')
        if self.script_window.fname[0]:
            # import script metadata
            svg_tree = ET.parse(self.script_window.fname[0])
            root = svg_tree.getroot()
            for metadata in root.findall(
                    "{http://www.w3.org/2000/svg}metadata"):
                for metadatum in metadata:
                    if metadatum.tag == "{https://korintje.com}script":
                        self.script_window.edit.setPlainText(metadatum.text)
                break
            self.run_script()

            # Parse original .svg
            print(self.script_window.fname[0])
            original_svg_tree = ET.parse(self.script_window.fname[0])
            original_root = original_svg_tree.getroot()
            for og in original_root.findall("{http://www.w3.org/2000/svg}g"):
                if "{http://www.inkscape.org/namespaces/inkscape}groupmode" in og.attrib and og.attrib[
                        "{http://www.inkscape.org/namespaces/inkscape}groupmode"] == "layer":
                    if "{http://www.inkscape.org/namespaces/inkscape}label" in og.attrib and og.attrib[
                            "{http://www.inkscape.org/namespaces/inkscape}label"] == "Layer_mpl":
                        original_root.remove(og)
            register_all_namespaces(self.script_window.fname[0])
            original_svg_tree.write("bkg_temp.svg",
                                    encoding="UTF-8",
                                    xml_declaration=True)
            self.update_bkg("bkg_temp.svg")

    @pyqtSlot()
    def run_script(self):
        self.output_window.stdout.clear()
        script = self.script_window.edit.toPlainText()
        self.process.start('python', ['-c', script])
        self.viewer_window.button_save.clicked.connect(lambda: self.save_svg())

    @pyqtSlot()
    def update_svg(self):
        self.viewer_window.view.load("temp.svg")

    @pyqtSlot()
    def dataReady(self, err_or_std):
        cursor = self.output_window.stdout.textCursor()
        cursor.movePosition(cursor.End)
        if err_or_std == "std":
            message = self.process.readAllStandardOutput().data().decode(
                "utf8")
            self.output_window.stdout.setTextColor(QColor(48, 255, 48))
        else:  #if err_or_std == "error":
            message = self.process.readAllStandardError().data().decode("utf8")
            self.output_window.stdout.setTextColor(QColor(255, 48, 48))
        self.output_window.stdout.insertPlainText(message)
        cursor.insertBlock()
        #self.output_window.setTopLevelWindow()

    @pyqtSlot()
    def update_bkg(self, filename):
        self.viewer_window.bkg.load(filename)

    @pyqtSlot()
    def save_svg(self):
        self.run_script()
        # Parse original .svg
        if self.script_window.fname[0]:
            print(self.script_window.fname[0])
            original_svg_tree = ET.parse(self.script_window.fname[0])
            original_root = original_svg_tree.getroot()
            for og in original_root.findall("{http://www.w3.org/2000/svg}g"):
                if "{http://www.inkscape.org/namespaces/inkscape}groupmode" in og.attrib and og.attrib[
                        "{http://www.inkscape.org/namespaces/inkscape}groupmode"] == "layer":
                    if "{http://www.inkscape.org/namespaces/inkscape}label" in og.attrib and og.attrib[
                            "{http://www.inkscape.org/namespaces/inkscape}label"] == "Layer_mpl":
                        original_root.remove(og)

        # Insert modified .svg into the original .svg
        modified_svg_tree = ET.parse("temp.svg")
        modified_root = modified_svg_tree.getroot()
        for mg in modified_root.findall("{http://www.w3.org/2000/svg}g"):
            if "id" in mg.attrib and mg.attrib["id"] == "figure_1":
                mg.set("inkscape:groupmode", "layer")
                mg.set("inkscape:label", "Layer_mpl")
                original_root.append(mg)
                print("done")

        # Update the script in the metadata
        for metadata in original_root.findall(
                "{http://www.w3.org/2000/svg}metadata"):
            for metadatum in metadata:
                print(metadatum.tag)
                if metadatum.tag == "{https://korintje.com}script":
                    metadatum.text = self.script_window.edit.toPlainText()
                    print(metadatum.text)
                break

        register_all_namespaces(self.script_window.fname[0])
        original_svg_tree.write("mod_test2.svg",
                                encoding="UTF-8",
                                xml_declaration=True)
Пример #17
0
class GUIWindow(QMainWindow):
    def __init__(self, pipeline=Pipeline()):
        super().__init__()
        self._pipeline = pipeline  # type: Pipeline
        self._controls = Controls(pipeline=self._pipeline)
        self._controls_widget = self._controls.widget
        self._controls_widget.setSizePolicy(QSizePolicy.Preferred,
                                            QSizePolicy.Expanding)

        # Start button

        # Resize screen
        self.resize(QSize(
            QDesktopWidget().availableGeometry().width() * 0.9,
            QDesktopWidget().availableGeometry().height() * 0.9))

    def init_ui(self):
        self.central_widget = QMdiArea()
        self.setCentralWidget(self.central_widget)

        # -------- controls widget -------- #
        self._controls.initialize()

        controls_dock = QDockWidget('Controls', self)
        controls_dock.setObjectName('Controls')
        controls_dock.setAllowedAreas(Qt.LeftDockWidgetArea |
                                      Qt.RightDockWidgetArea)

        controls_dock.setWidget(self._controls_widget)
        self.addDockWidget(Qt.LeftDockWidgetArea, controls_dock)

        self._controls_widget.setMinimumWidth(800)
        # --------------------------------- #

        self.menuBar().addMenu('&File')  # file menu

        # -------- view menu & toolbar -------- #
        tile_windows_action = self.createAction(
            '&Tile windows', self.central_widget.tileSubWindows)
        view_menu = self.menuBar().addMenu('&View')
        view_menu.addAction(tile_windows_action)
        view_toolbar = self.addToolBar('View')
        view_toolbar.addAction(tile_windows_action)
        # ------------------------------------- #

        # -------- run menu & toolbar -------- #
        self.run_toggle_action = self.createAction(
            '&Start', self._on_run_button_toggled)
        run_menu = self.menuBar().addMenu('&Run')
        run_menu.addAction(self.run_toggle_action)
        run_toolbar = self.addToolBar('Run')
        run_toolbar.setObjectName('run_toolbar')
        run_toolbar.addAction(self.run_toggle_action)
        # ------------------------------------ #

    def initialize(self):
        logger.debug('Initializing all nodes')
        async_initer = AsyncPipelineInitializer(pipeline=self._pipeline,
                                                parent=self)
        async_initer.no_blocking_execution()
        for node_widget in self._node_widgets:
            if node_widget:
                node_widget.setMinimumWidth(600)
                self.central_widget.addSubWindow(node_widget)
                node_widget.show()
            else:
                raise ValueError('Node widget is not defined')
        self.central_widget.tileSubWindows()

    def createAction(self, text, slot=None, shortcut=None, icon=None,
                     tip=None, checkable=False):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            action.triggered.connect(slot)
        if checkable:
            action.setCheckable(True)
        return action

    def moveEvent(self, event):
        return super(GUIWindow, self).moveEvent(event)

    def _on_run_button_toggled(self):
        if self.run_toggle_action.text() == "Pause":
            self.run_toggle_action.setText("Start")
        else:
            self.run_toggle_action.setText("Pause")

    @property
    def _node_widgets(self) -> List[QWidget]:
        node_widgets = list()
        for node in self._pipeline.all_nodes:
            try:
                node_widgets.append(node.widget)
            except AttributeError:
                pass
        return node_widgets
Пример #18
0
class MainWindow(QMainWindow):
    count = 0

    def __init__(self, parent=None, qtapp=None):
        super().__init__(parent)
        self.qtapp = qtapp
        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)

        self.app_manager = AppManager(None, gui_parent=self)
        self.mdi.subWindowActivated.connect(self.app_manager.
                                            on_view_activated)

        self.is_dark = self.light_or_dark(False)

        self.left = 100
        self.top = 50
        self.width = 1800
        self.height = 1200
        self.setGeometry(self.left, self.top, self.width, self.height)

        bar = self.menuBar()

        file_menu = bar.addMenu("File")
        file_menu.addAction("New")
        file_menu.addAction("Open...")
        file_menu.addSeparator()
        file_menu.addAction("Save")
        file_menu.addAction("Save As...")
        file_menu.addAction("Close")
        file_menu.triggered[QAction].connect(self.file_action)

        view_menu = bar.addMenu("Data View")
        view_menu.addAction("Spec Sheet")
        view_menu.addAction("Optical Layout")
        view_menu.addAction("Lens Table")
        view_menu.addAction("Element Table")
        view_menu.addAction("Glass Map")
        # view_menu.addAction("Lens View")
        view_menu.triggered[QAction].connect(self.view_action)

        parax_menu = bar.addMenu("Paraxial Model")
        parax_menu.addAction("Paraxial Model")
        parax_menu.addAction("y-ybar View")
        parax_menu.addAction("nu-nubar View")
        parax_menu.addAction("yui Ray Table")
        parax_menu.addAction("3rd Order Aberrations")
        parax_menu.triggered[QAction].connect(self.view_action)

        analysis_menu = bar.addMenu("Analysis")
        analysis_menu.addAction("Ray Table")
        analysis_menu.addAction("Ray Fans")
        analysis_menu.addAction("OPD Fans")
        analysis_menu.addAction("Spot Diagram")
        analysis_menu.addAction("Wavefront Map")
        analysis_menu.addAction("Astigmatism Curves")
        analysis_menu.triggered[QAction].connect(self.view_action)

        tools_menu = bar.addMenu("Tools")
        tools_menu.addAction("Paraxial Vignetting")
        tools_menu.triggered[QAction].connect(self.view_action)

        wnd_menu = bar.addMenu("Window")
        wnd_menu.addAction("Cascade")
        wnd_menu.addAction("Tiled")
        wnd_menu.addSeparator()
        wnd_menu.addAction("Light UI")
        wnd_menu.addAction("Dark UI")
        wnd_menu.addSeparator()

        dock.create_dock_windows(self)
        for pi in dock.panels.values():
            wnd_menu.addAction(pi.menu_action)

        wnd_menu.triggered[QAction].connect(self.window_action)

        self.setWindowTitle("Ray Optics")
        self.show()

        path = Path(rayoptics.__file__).parent
        self.cur_dir = path / "models"

        if False:
            # create new model
            self.new_model()

        else:
            # restore a default model

            # self.cur_dir = path / "codev/tests"
            # self.open_file(path / "codev/tests/asp46.seq")
            # self.open_file(path / "codev/tests/dar_test.seq")
            # self.open_file(path / "codev/tests/paraboloid.seq")
            # self.open_file(path / "codev/tests/paraboloid_f8.seq")
            # self.open_file(path / "codev/tests/schmidt.seq")
            # self.open_file(path / "codev/tests/questar35.seq")
            # self.open_file(path / "codev/tests/rc_f16.seq")
            # self.open_file(path / "codev/tests/ag_dblgauss.seq")
            # self.open_file(path / "codev/tests/threemir.seq")
            # self.open_file(path / "codev/tests/folded_lenses.seq")
            # self.open_file(path / "codev/tests/lens_reflection_test.seq")
            # self.open_file(path / "codev/tests/dec_tilt_test.seq")
            # self.open_file(path / "codev/tests/landscape_lens.seq")
            # self.open_file(path / "codev/tests/mangin.seq")
            # self.open_file(path / "codev/tests/CODV_32327.seq")
            # self.open_file(path / "codev/tests/dar_test.seq")
            # self.open_file(path / "optical/tests/cell_phone_camera.roa")
            # self.open_file(path / "optical/tests/singlet_f3.roa")

            # self.cur_dir = path / "models"
            # self.open_file(path / "models/Cassegrain.roa")
            # self.open_file(path / "models/collimator.roa")
            # self.open_file(path / "models/Dall-Kirkham.roa")
            # self.open_file(path / "models/petzval.roa")
            # self.open_file(path / "models/Ritchey_Chretien.roa")
            # self.open_file(path / "models/Sasian Triplet.roa")
            # self.open_file(path / "models/singlet_f5.roa")
            # self.open_file(path / "models/thinlens.roa")
            # self.open_file(path / "models/telephoto.roa")
            # self.open_file(path / "models/thin_triplet.roa")
            # self.open_file(path / "models/TwoMirror.roa")
            # self.open_file(path / "models/TwoSphericalMirror.roa")

            self.cur_dir = path / "zemax/tests"
            # self.open_file(path / "zemax/tests/US08427765-1.ZMX")
            # self.open_file(path / "zemax/tests/US00583336-2-scaled.zmx")
            # self.open_file(path / "zemax/tests/HoO-V2C18Ex03.zmx")
            # self.open_file(path / "zemax/tests/HoO-V2C18Ex27.zmx")
            # self.open_file(path / "zemax/tests/HoO-V2C18Ex46.zmx")
            # self.open_file(path / "zemax/tests/HoO-V2C18Ex66.zmx")
            # self.open_file(path / "zemax/tests/US05831776-1.zmx")
            self.open_file(path / "zemax/tests/354710-C-Zemax(ZMX).zmx")

            # self.cur_dir = path / "zemax/models/telescopes"
            # self.open_file(path / "zemax/models/telescopes/Figure4.zmx")
            # self.open_file(path / "zemax/models/telescopes/HoO-V2C18Ex11.zmx")

            # self.cur_dir = path / "zemax/models/PhotoPrime"
            # self.open_file(path / "zemax/models/PhotoPrime/US05321554-4.ZMX")
            # self.open_file(path / "zemax/models/PhotoPrime/US06476982-1.ZMX")
            # self.open_file(path / "zemax/models/PhotoPrime/US07190532-1.ZMX")
            # self.open_file(path / "zemax/models/PhotoPrime/US04331391-1.zmx")
            # self.open_file(path / "zemax/models/PhotoPrime/US05331467-1.zmx")

    def add_subwindow(self, widget, model_info):
        sub_wind = self.mdi.addSubWindow(widget)
        self.app_manager.add_view(sub_wind, widget, model_info)
        MainWindow.count += 1
        return sub_wind

    def delete_subwindow(self, sub_wind):
        self.app_manager.delete_view(sub_wind)
        self.mdi.removeSubWindow(sub_wind)
        MainWindow.count -= 1

    def add_ipython_subwindow(self):
        try:
            create_ipython_console(self, 'iPython console', 800, 600)
        except MultipleInstanceError:
            logging.debug("Unable to open iPython console. "
                          "MultipleInstanceError")
        except Exception as inst:
            print(type(inst))    # the exception instance
            print(inst.args)     # arguments stored in .args
            print(inst)          # __str__ allows args to be printed directly,
            pass                 # but may be overridden in exception subclasses

    def initial_window_offset(self):
        offset_x = 50
        offset_y = 25
        orig_x = (MainWindow.count - 1)*offset_x
        orig_y = (MainWindow.count - 1)*offset_y
        return orig_x, orig_y

    def file_action(self, q):
        if q.text() == "New":
            self.new_model()

        if q.text() == "Open...":
            options = QFileDialog.Options()
            # options |= QFileDialog.DontUseNativeDialog
            fileName, _ = QFileDialog.getOpenFileName(
                          self,
                          "QFileDialog.getOpenFileName()",
                          str(self.cur_dir),
                          "All files (*.seq *.zmx *.roa);;"
                          "CODE V files (*.seq);;"
                          "Ray-Optics files (*.roa);;"
                          "Zemax files (*.zmx)",
                          options=options)
            if fileName:
                logging.debug("open file: %s", fileName)
                filename = Path(fileName)
                self.cur_dir = filename.parent
                self.open_file(filename)

        if q.text() == "Save As...":
            options = QFileDialog.Options()
            # options |= QFileDialog.DontUseNativeDialog
            fileName, _ = QFileDialog.getSaveFileName(
                          self,
                          "QFileDialog.getSaveFileName()",
                          "",
                          "Ray-Optics Files (*.roa);;All Files (*)",
                          options=options)
            if fileName:
                logging.debug("save file: %s", fileName)
                self.save_file(fileName)

        if q.text() == "Close":
            self.close_model()

    def new_model(self):
        iid = cmds.create_new_ideal_imager(gui_parent=self,
                                           conjugate_type='infinite')

        self.add_ipython_subwindow()
        self.refresh_app_ui()

    def open_file(self, file_name, **kwargs):
        self.cur_filename = file_name
        opt_model = cmds.open_model(file_name, **kwargs)
        self.app_manager.set_model(opt_model)
        self.is_changed = True
        self.create_lens_table()
        cmds.create_live_layout_view(self.app_manager.model, gui_parent=self)
        self.add_ipython_subwindow()
        self.refresh_app_ui()

    def save_file(self, file_name):
        self.app_manager.model.save_model(file_name)
        self.cur_filename = file_name
        self.is_changed = False

    def close_model(self):
        """ NOTE: this does not check to save a modified model """
        self.app_manager.close_model(self.delete_subwindow)

    def view_action(self, q):
        opt_model = self.app_manager.model

        if q.text() == "Spec Sheet":
            cmds.create_new_ideal_imager(opt_model=opt_model, gui_parent=self)

        if q.text() == "Optical Layout":
            cmds.create_live_layout_view(opt_model, gui_parent=self)

        if q.text() == "Lens Table":
            self.create_lens_table()

        if q.text() == "Element Table":
            model = cmds.create_element_table_model(opt_model)
            self.create_table_view(model, "Element Table")

        if q.text() == "Glass Map":
            cmds.create_glass_map_view(opt_model, gui_parent=self)

        if q.text() == "Ray Fans":
            cmds.create_ray_fan_view(opt_model, "Ray", gui_parent=self)

        if q.text() == "OPD Fans":
            cmds.create_ray_fan_view(opt_model, "OPD", gui_parent=self)

        if q.text() == "Spot Diagram":
            cmds.create_ray_grid_view(opt_model, gui_parent=self)

        if q.text() == "Wavefront Map":
            cmds.create_wavefront_view(opt_model, gui_parent=self)

        if q.text() == "Astigmatism Curves":
            cmds.create_field_curves(opt_model, gui_parent=self)

        if q.text() == "3rd Order Aberrations":
            cmds.create_3rd_order_bar_chart(opt_model, gui_parent=self)

        if q.text() == "y-ybar View":
            cmds.create_paraxial_design_view_v2(opt_model, 'ht',
                                                gui_parent=self)

        if q.text() == "nu-nubar View":
            cmds.create_paraxial_design_view_v2(opt_model, 'slp',
                                                gui_parent=self)

        if q.text() == "yui Ray Table":
            model = cmds.create_parax_table_model(opt_model)
            self.create_table_view(model, "Paraxial Ray Table")

        if q.text() == "Paraxial Model":
            model = cmds.create_parax_model_table(opt_model)
            self.create_table_view(model, "Paraxial Model")

        if q.text() == "Ray Table":
            self.create_ray_table(opt_model)

        if q.text() == "Paraxial Vignetting":
            trace.apply_paraxial_vignetting(opt_model)
            self.refresh_gui()

    def window_action(self, q):
        if q.text() == "Cascade":
            self.mdi.cascadeSubWindows()

        if q.text() == "Tiled":
            self.mdi.tileSubWindows()

        if q.text() == "Light UI":
            self.is_dark = self.light_or_dark(False)
            self.app_manager.sync_light_or_dark(self.is_dark)

        if q.text() == "Dark UI":
            self.is_dark = self.light_or_dark(True)
            self.app_manager.sync_light_or_dark(self.is_dark)

    def light_or_dark(self, is_dark):
        """ set the UI to a light or dark scheme.

        Qt doesn't seem to support controlling the MdiArea's background from a
        style sheet. Set the widget directly and save the original color
        to reset defaults.
        """
        if not hasattr(self, 'mdi_background'):
            self.mdi_background = self.mdi.background()

        if is_dark:
            self.qtapp.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
            rgb = DarkPalette.color_palette()
            self.mdi.setBackground(QColor(rgb['COLOR_BACKGROUND_NORMAL']))
        else:
            self.qtapp.setStyleSheet('')
            self.mdi.setBackground(self.mdi_background)
        return is_dark

    def create_lens_table(self):
        seq_model = self.app_manager.model.seq_model

        def set_stop_surface(stop_surface):
            seq_model.stop_surface = stop_surface
            self.refresh_gui()

        def handle_context_menu(point):
            try:
                vheader = view.verticalHeader()
                row = vheader.logicalIndexAt(point.y())
            except NameError:
                pass
            else:
                # show menu about the row
                menu = QMenu(self)
                if row != seq_model.stop_surface:
                    menu.addAction('Set Stop Surface',
                                   lambda: set_stop_surface(row))
                if seq_model.stop_surface is not None:
                    menu.addAction('Float Stop Surface',
                                   lambda: set_stop_surface(None))
                menu.popup(vheader.mapToGlobal(point))

        model = cmds.create_lens_table_model(seq_model)
        view = self.create_table_view(model, "Surface Data Table")
        vheader = view.verticalHeader()
        vheader.setContextMenuPolicy(qt.CustomContextMenu)
        vheader.customContextMenuRequested.connect(handle_context_menu)

    def create_ray_table(self, opt_model):
        osp = opt_model.optical_spec
        pupil = [0., 1.]
        fi = 0
        wl = osp.spectral_region.reference_wvl
        fld, wvl, foc = osp.lookup_fld_wvl_focus(fi, wl)
        ray, ray_op, wvl = trace.trace_base(opt_model, pupil, fld, wvl)
#        ray, ray_op, wvl, opd = trace.trace_with_opd(opt_model, pupil,
#                                                     fld, wvl, foc)

#        cr = trace.RayPkg(ray, ray_op, wvl)
#        s, t = trace.trace_coddington_fan(opt_model, cr, foc)

        ray = [RaySeg(*rs) for rs in ray]
        model = cmds.create_ray_table_model(opt_model, ray)
        self.create_table_view(model, "Ray Table")

    def create_table_view(self, table_model, table_title, close_callback=None):
        # construct the top level widget
        widget = QWidget()
        # construct the top level layout
        layout = QVBoxLayout(widget)

        table_view = TableView(table_model)
        table_view.setAlternatingRowColors(True)

        # Add table to box layout
        layout.addWidget(table_view)

        # set the layout on the widget
        widget.setLayout(layout)

        sub = self.add_subwindow(widget, ModelInfo(self.app_manager.model,
                                                   cmds.update_table_view,
                                                   (table_view,)))
        sub.setWindowTitle(table_title)

        sub.installEventFilter(self)

        table_view.setMinimumWidth(table_view.horizontalHeader().length() +
                                   table_view.horizontalHeader().height())
#                                  The following line should work but returns 0
#                                  table_view.verticalHeader().width())

        view_width = table_view.width()
        view_ht = table_view.height()
        orig_x, orig_y = self.initial_window_offset()
        sub.setGeometry(orig_x, orig_y, view_width, view_ht)

        # table data updated successfully
        table_model.update.connect(self.on_data_changed)

        sub.show()

        return table_view

    def eventFilter(self, obj, event):
        """Used by table_view in response to installEventFilter."""
        if (event.type() == QEvent.Close):
            print('close event received:', obj)
        return False

    def refresh_gui(self, **kwargs):
        self.app_manager.refresh_gui(**kwargs)

    def refresh_app_ui(self):
        dock.update_dock_windows(self)

    def handle_ideal_imager_command(self, iid, command, specsheet):
        ''' link Ideal Imager Dialog buttons to model actions
        iid: ideal imager dialog
        command: text field with the action - same as button label
        specsheet: the input specsheet used to drive the actions
        '''
        if command == 'Apply':
            opt_model = self.app_manager.model
            opt_model.set_from_specsheet(specsheet)
            self.refresh_gui()
        elif command == 'Close':
            for view, info in self.app_manager.view_dict.items():
                if iid == info[0]:
                    self.delete_subwindow(view)
                    view.close()
                    break
        elif command == 'Update':
            opt_model = self.app_manager.model
            specsheet = opt_model.specsheet
            firstorder.specsheet_from_parax_data(opt_model, specsheet)
            iid.specsheet_dict[specsheet.conjugate_type] = specsheet
            iid.update_values()
        elif command == 'New':
            opt_model = cmds.create_new_optical_model_from_specsheet(specsheet)
            self.app_manager.set_model(opt_model)
            for view, info in self.app_manager.view_dict.items():
                if iid == info[0]:
                    w = iid
                    mi = info[1]
                    args = (iid, opt_model)
                    new_mi = ModelInfo(model=opt_model, fct=mi.fct,
                                       args=args, kwargs=mi.kwargs)
                    self.app_manager.view_dict[view] = w, new_mi
            self.refresh_gui()
            self.create_lens_table()
            cmds.create_live_layout_view(opt_model, gui_parent=self)
            cmds.create_paraxial_design_view_v2(opt_model, 'ht',
                                                gui_parent=self)
            self.refresh_gui()

    @pyqtSlot(object, int)
    def on_data_changed(self, rootObj, index):
        self.refresh_gui()
Пример #19
0
class DemoMdi(QMainWindow):
    def __init__(self, parent=None):
        super(DemoMdi, self).__init__(parent)

        # 设置窗口标题
        self.setWindowTitle('实战PyQt5: MDI多文档接口程序 演示')
        # 设置窗口大小
        self.resize(480, 360)

        self.initUi()

    def initUi(self):
        self.initMenuBar()
        self.initToolBar()

        self.mdiArea = QMdiArea(self)
        self.setCentralWidget(self.mdiArea)

        self.newDocIndex = 1

    def initMenuBar(self):
        menuBar = self.menuBar()
        style = QApplication.style()

        #==== 文件 ====#
        fileMenu = menuBar.addMenu('文件')

        #新建一个文档
        aFileNew = QAction('新建文档', self)
        aFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon))
        aFileNew.triggered.connect(self.onFileNew)
        fileMenu.addAction(aFileNew)

        #打开一个文档
        aFileOpen = QAction('打开文档', self)
        aFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton))
        aFileOpen.triggered.connect(self.onFileOpen)
        fileMenu.addAction(aFileOpen)

        #关闭一个文档
        aFileCloseAll = QAction('关闭全部', self)
        aFileCloseAll.setIcon(style.standardIcon(QStyle.SP_DialogCloseButton))
        aFileOpen.triggered.connect(self.onFileCloseAll)
        fileMenu.addAction(aFileCloseAll)

        #添加分割线
        fileMenu.addSeparator()

        #退出
        aFileExit = QAction('退出', self)
        aFileExit.triggered.connect(self.close)
        fileMenu.addAction(aFileExit)

        #==== 编辑 ====#
        editMenu = menuBar.addMenu('编辑')

        #剪切
        aEditCut = QAction('剪切', self)
        aEditCut.setIcon(QIcon(':/ico/cut.png'))
        aEditCut.triggered.connect(self.onEditCut)
        editMenu.addAction(aEditCut)

        #复制
        aEditCopy = QAction('复制', self)
        aEditCopy.setIcon(QIcon(':/ico/copy.png'))
        aEditCopy.triggered.connect(self.onEditCopy)
        editMenu.addAction(aEditCopy)

        #粘贴
        aEditPaste = QAction('粘贴', self)
        aEditPaste.setIcon(QIcon(':/ico/paste.png'))
        aEditPaste.triggered.connect(self.onEditPaste)
        editMenu.addAction(aEditPaste)

        #==== 窗口排列方式 ====#
        windowMenu = menuBar.addMenu('窗口')

        #子窗口模式
        aWndSubView = QAction('子窗口模式', self)
        aWndSubView.triggered.connect(lambda: self.onWinowdMode(0))
        windowMenu.addAction(aWndSubView)
        #标签页模式
        aWndTab = QAction('标签页模式', self)
        aWndTab.triggered.connect(lambda: self.onWinowdMode(1))
        windowMenu.addAction(aWndTab)

        windowMenu.addSeparator()

        #平铺模式
        aWndTile = QAction('平铺模式', self)
        aWndTile.triggered.connect(lambda: self.onWinowdMode(2))
        windowMenu.addAction(aWndTile)
        #窗口级联模式
        aWndCascade = QAction('窗口级联模式', self)
        aWndCascade.triggered.connect(lambda: self.onWinowdMode(3))
        windowMenu.addAction(aWndCascade)

    def initToolBar(self):
        toolBar = self.addToolBar('')
        style = QApplication.style()

        min_width = 64

        btnFileNew = QToolButton(self)
        btnFileNew.setText('新建文档')
        btnFileNew.setMinimumWidth(min_width)
        btnFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon))
        btnFileNew.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnFileNew.clicked.connect(self.onFileNew)
        toolBar.addWidget(btnFileNew)

        btnFileOpen = QToolButton(self)
        btnFileOpen.setText('打开文档')
        btnFileOpen.setMinimumWidth(min_width)
        btnFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton))
        btnFileOpen.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnFileOpen.clicked.connect(self.onFileOpen)
        toolBar.addWidget(btnFileOpen)

        btnFileCloseAll = QToolButton(self)
        btnFileCloseAll.setText('关闭全部')
        btnFileCloseAll.setMinimumWidth(min_width)
        btnFileCloseAll.setIcon(style.standardIcon(
            QStyle.SP_DialogCloseButton))
        btnFileCloseAll.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnFileCloseAll.clicked.connect(self.onFileCloseAll)
        toolBar.addWidget(btnFileCloseAll)

        toolBar.addSeparator()

        btnEditCut = QToolButton(self)
        btnEditCut.setText('剪切')
        btnEditCut.setMinimumWidth(64)
        btnEditCut.setIcon(QIcon(':/ico/cut.png'))
        btnEditCut.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnEditCut.clicked.connect(self.onEditCut)
        toolBar.addWidget(btnEditCut)

        btnEditCopy = QToolButton(self)
        btnEditCopy.setText('复制')
        btnEditCopy.setMinimumWidth(64)
        btnEditCopy.setIcon(QIcon(':/ico/copy.png'))
        btnEditCopy.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnEditCopy.clicked.connect(self.onEditCopy)
        toolBar.addWidget(btnEditCopy)

        btnEditPaste = QToolButton(self)
        btnEditPaste.setText('粘贴')
        btnEditPaste.setMinimumWidth(64)
        btnEditPaste.setIcon(QIcon(':/ico/paste.png'))
        btnEditPaste.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnEditPaste.clicked.connect(self.onEditPaste)
        toolBar.addWidget(btnEditPaste)

    def msgCritical(self, strInfo):
        dlg = QMessageBox(self)
        dlg.setIcon(QMessageBox.Critical)
        dlg.setText(strInfo)
        dlg.show()

    def onFileNew(self):
        newDoc = QMdiSubWindow(self)
        newDoc.setWindowTitle('新文档 ' + str(self.newDocIndex))
        self.newDocIndex += 1
        newDoc.setWidget(QPlainTextEdit(newDoc))
        self.mdiArea.addSubWindow(newDoc)
        newDoc.show()

    def onFileOpen(self):
        path, _ = QFileDialog.getOpenFileName(self, '打开文件', '', '文本文件 (*.txt)')
        if path:
            try:
                with open(path, 'rU') as f:
                    text = f.read()
            except Exception as e:
                self.msgCritical(str(e))
            else:
                openDoc = QMdiSubWindow(self)
                openDoc.setWindowTitle(path)
                txtEdit = QPlainTextEdit(openDoc)
                txtEdit.setPlainText(text)
                openDoc.setWidget(txtEdit)
                self.mdiArea.addSubWindow(openDoc)
                openDoc.show()

    def onFileCloseAll(self):
        self.mdiArea.closeAllSubWindows()

    def onEditCut(self):
        txtEdit = self.mdiArea.activeSubWindow().widget()
        txtEdit.cut()

    def onEditCopy(self):
        txtEdit = self.mdiArea.activeSubWindow().widget()
        txtEdit.copy()

    def onEditPaste(self):
        txtEdit = self.mdiArea.activeSubWindow().widget()
        txtEdit.paste()

    def onWinowdMode(self, index):
        if index == 3:
            self.mdiArea.cascadeSubWindows()
        elif index == 2:
            self.mdiArea.tileSubWindows()
        elif index == 1:
            self.mdiArea.setViewMode(QMdiArea.TabbedView)
        else:
            self.mdiArea.setViewMode(QMdiArea.SubWindowView)
Пример #20
0
class MDIWindow(QMainWindow):
    count = 0

    def __init__(self):
        super().__init__()

        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        bar = self.menuBar()

        self.current_dir = None

        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("cascade")
        file.addAction("Tiled")
        file.triggered[QAction].connect(self.WindowTrig)

        load = bar.addMenu("Load")
        load.addAction("2D")
        load.addAction("3D")
        load.triggered[QAction].connect(self.dir_open)

        self.setWindowTitle("MDI Application")

        self.base_wd = QMdiSubWindow()
        self.base_wd.plt_i = pg.PlotItem(labels={
            'bottom': ('slits', 'degrees'),
            'left': ('Kin. Energy', 'eV')
        })
        self.base_wd.plt_iv = pg.ImageView(view=self.base_wd.plt_i)
        self.base_wd.setWidget(self.base_wd.plt_iv)
        self.base_wd.setWindowTitle("plot window")
        self.mdi.addSubWindow(self.base_wd)
        self.base_wd.show()

        data_DockWidget = QDockWidget('data', self)
        data_DockWidget.setObjectName(('data window'))
        data_DockWidget.setAllowedAreas(Qt.RightDockWidgetArea)

        self.data_list = QListWidget()
        data_DockWidget.setWidget(self.data_list)
        self.addDockWidget(Qt.RightDockWidgetArea, data_DockWidget)

        self.data_list.itemClicked.connect(self.show_data)
        self.data_list.itemDoubleClicked.connect(self.get_data)

    def WindowTrig(self, p):

        if p.text() == "New":
            MDIWindow.count = MDIWindow.count + 1
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("Sub Window" + str(MDIWindow.count))
            self.mdi.addSubWindow(sub)
            sub.show()

        if p.text() == "cascade":
            self.mdi.cascadeSubWindows()

        if p.text() == "Tiled":
            self.mdi.tileSubWindows()

    def dir_open(self, p):
        self.current_dir = dlg.File_dlg.openDirNameDialog(self)
        print(self.current_dir)
        if p.text() == "2D":
            print('2D')
            files_ls = glob.glob(self.current_dir + '/*.ibw')
            fls = [f[len(self.current_dir) + 1:] for f in files_ls]
            print(files_ls)
            self.data_list.addItems(fls)
        if p.text() == "3D":
            zip_ls = glob.glob(self.current_dir + '/*.zip')
            zp = [f[len(self.current_dir) + 1:] for f in zip_ls]
            print(zp)
            self.data_list.addItems(zp)

    def show_data(self, s):
        file_name = s.text()
        self.data_dict = ut.ibw2dict(self.current_dir + '/' + file_name)

        e_sc = self.data_dict['E_axis'][1] - self.data_dict['E_axis'][0]
        a_sc = self.data_dict['A_axis'][1] - self.data_dict['A_axis'][0]
        e_str = self.data_dict['E_axis'][0]
        a_str = self.data_dict['A_axis'][0]
        self.base_wd.plt_i.setRange(xRange=[self.data_dict['E_axis'][0], self.data_dict['E_axis'][-1]], \
                            yRange=[self.data_dict['A_axis'][0], self.data_dict['A_axis'][-1]], update=True, padding = 0)

        self.base_wd.plt_i.getViewBox().setLimits(xMin= e_str, xMax = self.data_dict['E_axis'][-1],\
                                          yMin=self.data_dict['A_axis'][0], yMax=self.data_dict['A_axis'][-1])

        self.base_wd.plt_iv.setImage(
            self.data_dict['data'],
            pos=[self.data_dict['E_axis'][0], self.data_dict['A_axis'][0]],
            scale=[e_sc, a_sc])
        #        self.base_wd.plt_iv.ui.histogram.hide()
        self.base_wd.plt_iv.ui.roiBtn.hide()
        self.base_wd.plt_iv.ui.menuBtn.hide()

    def get_data(self, s):
        file_name = s.text()
        self.data_dict = ut.ibw2dict(self.current_dir + '/' + file_name)

        MDIWindow.count = MDIWindow.count + 1
        sub = QMdiSubWindow()

        sub.plt_i = pg.PlotItem(labels={
            'bottom': ('slits', 'degrees'),
            'left': ('Kin. Energy', 'eV')
        })
        sub.plt_iv = pg.ImageView(view=sub.plt_i)
        sub.setWidget(sub.plt_iv)
        sub.setWindowTitle(file_name)
        self.mdi.addSubWindow(sub)
        sub.show()

        e_sc = self.data_dict['E_axis'][1] - self.data_dict['E_axis'][0]
        a_sc = self.data_dict['A_axis'][1] - self.data_dict['A_axis'][0]
        e_str = self.data_dict['E_axis'][0]
        a_str = self.data_dict['A_axis'][0]
        e_end = self.data_dict['E_axis'][-1]
        a_end = self.data_dict['A_axis'][-1]
        sub.plt_i.setRange(xRange=[self.data_dict['E_axis'][0], self.data_dict['E_axis'][-1]], \
                            yRange=[self.data_dict['A_axis'][0], self.data_dict['A_axis'][-1]], update=True, padding = 0)

        sub.plt_i.getViewBox().setLimits(xMin= e_str, xMax = self.data_dict['E_axis'][-1],\
                                          yMin=self.data_dict['A_axis'][0], yMax=self.data_dict['A_axis'][-1])

        sub.plt_iv.setImage(
            self.data_dict['data'],
            pos=[self.data_dict['E_axis'][0], self.data_dict['A_axis'][0]],
            scale=[e_sc, a_sc])

        sub.plt_iv.ui.roiBtn.clicked.connect(lambda status, a_s = a_str,a_e = a_end,e_s = e_str,e_e = e_end, e_w = e_sc*10, a_w = a_sc*10, iv = sub.plt_iv:\
                                                 self.add_lin_ROI(status, a_s, a_e, e_s, e_e, e_w, a_w, iv))

    def add_lin_ROI(self, status, a_str, a_end, e_str, e_end, e_w, a_w, iv):

        if status:
            roi_edc = pg.LineSegmentROI(
                [[e_str, (a_str + a_end) / 2], [e_end, (a_str + a_end) / 2]],
                pen='r',
                removable=True)
            iv.addItem(roi_edc)

            roi_mdc = pg.LineSegmentROI(
                [[(e_str + e_end) / 2, a_str], [(e_str + e_end) / 2, a_end]],
                pen='b',
                removable=True)
            iv.addItem(roi_mdc)
        else:
            print(iv.getRoiPlot)
            iv.getRoiPlot.removeSegment()
            iv.removeItem(iv.getRoiPlot)
Пример #21
0
class Invoice(QMainWindow):
    '''Runs the main window of the invoice development
    Calls the table to be used for parts and labor from
    table_widget.py
    '''
    invoice_count = 0
    total_parts_ = 0
    labor_supplies_ = 0
    recent_open = False
    start_flag = False
    current_job = str
    labor_ = 0
    parts_ = 0
    supplies = 0
    freight_ = 0
    subtotal = 0
    taxed = 0
    totals = 0
    tax = 0
    partial = 0
    finance = 0
    new_total = 0
    open_list = []
    printed_list = {}

    def __init__(self):
        '''Initialize the window and get pertinent information read in:
            Set the window size
            Set the picture to be a BEI logo
            Read in the standard labor rates
            '''
        super().__init__()
        self.size_policy = QSizePolicy.Expanding
        self.font = QFont()
        self.font.setPointSize(12)
        self.showMaximized()
        self.setWindowIcon(QIcon('BEI_Logo.png'))
        #        backimage=QImage('BEI_Logo.png')
        self.setWindowTitle('Burl Equipment Inc. Invoices Beta')
        self.tray = QSystemTrayIcon(self)
        self.tray.setIcon(QIcon('BEI_Logo.png'))
        self.show()
        self.menu_bar()
        self.statusbar = QStatusBar()
        self.setStatusBar(self.statusbar)
        #this is the first time start up section, should only run the very
        #first time
        self.base_directory = str(
            Path(os.path.join(os.environ['USERPROFILE'], 'BEI_Invoices')))
        base_entries = os.listdir(os.environ['USERPROFILE'])
        if 'BEI_Invoices' not in base_entries:
            initi.First_Run(self.base_directory)

    def menu_bar(self):
        '''Create the menu bar for the main window will include
                Name:       Shortcut:         Function called:
            File:
                New         CTRL+N            new_invoice_begin
                Open        CTRL+O            existing_invoice_open
                Save        CTRL+S              print_invoice
                Quit        ALT       save_invoice
                Print       CTRL+P   +F4            exit_system
            Edit:
                Change Labor Rates            labor_rates
            View:
                View Totals                   view_totals
                View Labor Breakdown          labor_breakdown
            Help:
                View Current Cheat Sheet      cheat_sheet
                Add New Task to Cheat Sheet   add_cheat_task
        '''
        self.menuFile = self.menuBar().addMenu("&File")
        self.actionNew = QAction('&New', self)
        self.actionNew.setShortcut('Ctrl+N')
        self.actionNew.triggered.connect(self.new_invoice_begin)
        self.actionOpen = QAction("&Open", self)
        self.actionOpen.setShortcut('Ctrl+O')
        self.actionOpen.triggered.connect(self.existing_invoice_open)
        self.actionSave = QAction('&Save', self)
        self.actionSave.setShortcut('Ctrl+S')
        self.actionSave.setDisabled(True)
        self.actionSave.triggered.connect(self.save_invoice)
        #        self.actionImport=QAction('&Import Old Job',self)
        #        self.actionImport.triggered.connect(self.old_job)
        #        self.actionImport.setShortcut('Ctrl+I')
        self.actionPrint = QAction('&Print', self)
        self.actionPrint.setShortcut('Ctrl+P')
        self.actionPrint.setDisabled(True)
        self.actionPrint.triggered.connect(self.print_invoice)

        self.printMenu = QMenu('Print Envelopes', self)
        self.actionEnvelope = QAction('&Print All Billed Customer Envelopes',
                                      self)
        self.actionEnvelope.triggered.connect(self.envelop_write)
        self.actionEnvelope.setShortcut('Ctrl+E')
        self.actionEnvelope.setDisabled(True)

        self.actionEnvelope1 = QAction(
            '&Print Single Billed Customer Envelope', self)
        self.actionEnvelope1.triggered.connect(self.envelop_write1)
        self.actionEnvelope1.setShortcut('Ctrl+R')

        self.actionBilledEnvelopes = QAction('&Print Check Envelope', self)
        self.actionBilledEnvelopes.triggered.connect(self.billing_envelopes)
        self.actionBilledEnvelopes.setShortcut('Ctrl+C')

        self.printMenu.addActions([
            self.actionEnvelope, self.actionEnvelope1,
            self.actionBilledEnvelopes
        ])

        self.actionQuit = QAction('&Exit', self)
        self.actionQuit.triggered.connect(self.closing)
        self.actionQuit.setShortcut('Alt+F4')
        self.menuFile.addActions([
            self.actionNew, self.actionOpen, self.actionSave, self.actionPrint
        ])
        self.menuFile.addMenu(self.printMenu)
        self.menuFile.addAction(self.actionQuit)

        self.menuEdit = self.menuBar().addMenu('&Edit')
        self.menuEdit_Change_In = QMenu('Change Basic Invoice Information',
                                        self)
        self.menuEdit_Change_Sy = QMenu('Change Operating Data', self)

        self.actionLaborRates = QAction('&Change Standard Labor Rates', self)
        self.actionLaborRates.triggered.connect(self.labor_rates)
        self.actionAddTechnician = QAction('&Add Technician', self)
        self.actionAddTechnician.triggered.connect(self.add_tech)
        self.actionChangeDate = QAction('&Change Invoice Date', self)
        self.actionChangeDate.triggered.connect(self.date_change)
        self.actionChangeCustomerAddress = QAction('&Change Customer Address',
                                                   self)
        self.actionChangeCustomerAddress.triggered.connect(self.change_address)
        self.actionBasicInfo = QAction('&Change Basic Information', self)
        self.actionBasicInfo.triggered.connect(self.change_basic_info)
        self.actionBasicInfo.setDisabled(True)
        self.menuEdit_Change_In.addActions([self.actionBasicInfo])
        self.menuEdit_Change_Sy.addActions([
            self.actionLaborRates, self.actionAddTechnician,
            self.actionChangeDate, self.actionChangeCustomerAddress
        ])
        self.menuEdit.addMenu(self.menuEdit_Change_In)
        self.menuEdit.addMenu(self.menuEdit_Change_Sy)

        self.menuView = self.menuBar().addMenu('&View')
        self.actionViewLaborBreakdown = QAction('&View Labor Breakdown', self)
        self.actionViewLaborBreakdown.setDisabled(True)
        self.actionViewLaborBreakdown.triggered.connect(self.breakdown)
        self.actionViewAllWindows = QAction('&View All Windows', self)
        self.actionViewAllWindows.setDisabled(True)
        self.actionViewAllWindows.triggered.connect(self.view_windows)
        self.actionViewCutomer = QAction('&View Customer Invoice', self)
        self.actionViewCutomer.triggered.connect(self.view_customer)
        self.actionViewCutomer = QAction('&View Customer Invoice', self)
        self.actionViewCutomer.triggered.connect(self.view_customer)
        self.actionViewCutomer.setEnabled(False)
        self.actionViewCompany = QAction('&View Company Invoice', self)
        self.actionViewCompany.triggered.connect(self.view_company)
        self.actionViewCompany.setEnabled(False)
        self.menuView.addActions([
            self.actionViewLaborBreakdown, self.actionViewAllWindows,
            self.actionViewCutomer, self.actionViewCompany
        ])

        self.actionJobNumbers = QAction('&More Job Numbers', self)
        self.actionJobNumbers.triggered.connect(self.new_job_nums)
        self.menuJobNumbers = self.menuBar().addMenu('Job Numbers')
        self.menuJobNumbers.addAction(self.actionJobNumbers)

        self.menuPayment = self.menuBar().addMenu('&Finance/Payments')
        self.actionPartialPayment = QAction('&Partial Payment', self)
        self.actionPartialPayment.triggered.connect(self.partial_payment)
        self.actionPartialPayment.setDisabled(True)
        self.actionFinanceCharges = QAction('&Add Finance Charges', self)
        self.actionFinanceCharges.triggered.connect(self.finance_charges)
        self.actionFinanceCharges.setDisabled(True)
        self.menuPayment.addActions(
            [self.actionPartialPayment, self.actionFinanceCharges])

        self.menuHelp = self.menuBar().addMenu('&Help')
        self.actionViewCheatSheet = QAction('&View Cheat Sheet', self)
        self.actionViewCheatSheet.triggered.connect(self.cheat_sheet)
        self.actionNewCheat = QAction('&Add New Item to Cheat Sheet', self)
        self.actionNewCheat.triggered.connect(self.add_cheat_task)
        self.actionUpdate = QAction('&Update Application')
        self.actionUpdate.triggered.connect(self.updater)
        self.menuHelp.addActions([
            self.actionViewCheatSheet, self.actionNewCheat, self.actionUpdate
        ])

    def new_invoice_begin(self):
        '''Entering basic information:
            Job Number:
            Machine:
            Customer Name:
        '''
        try:
            self.docked.close()
            self.docked2.close()
            self.totals_table.close()
            self.save_invoice()
            self.new_window = New_Invoice(12, self.base_directory)
            #            self.new_window.basic_information()
            self.new_window.start.clicked.connect(self.job_num_insertion)
            self.new_window.customer_address_line_2.returnPressed.connect(
                self.new_window.information_)
            self.new_window.customer_address_line_2.returnPressed.connect(
                self.job_num_insertion)
        except:
            self.new_window = New_Invoice(12, self.base_directory)
            #            self.new_window.basic_information()
            self.new_window.start.clicked.connect(self.job_num_insertion)
            self.new_window.customer_address_line_2.returnPressed.connect(
                self.new_window.information_)
            self.new_window.customer_address_line_2.returnPressed.connect(
                self.job_num_insertion)

    def job_num_insertion(self):
        '''Call the table with the job number given in the new invoice
        '''
        self.reset_data()
        if not self.recent_open:
            self.recent_invoices()
        self.tax = self.new_window.tax
        self.customer = self.new_window.customer.replace('#', '')
        self.machine_text = self.new_window.machine_
        self.current_job = self.new_window.job_num
        if self.current_job not in self.open_list:
            self.open_list.append(self.current_job)
            self.recently_opened_invoice.appendRow(
                QStandardItem(str(self.current_job)))
        self.invoice_count += 1
        #make the folder for this invoice to be saved in
        self.job_dire = os.path.join(
            os.path.join(self.base_directory, 'Saved_Invoices'),
            self.current_job)
        try:
            os.mkdir(self.job_dire)
            #save the basic information
            location = os.path.join(
                os.path.join(self.base_directory, 'Saved_Invoices'),
                self.current_job)
            self.table(self.new_window.job_num)
            basic = os.path.join(location, 'Basic_Info.csv')
            f = open(basic, 'w')
            f.write(str(self.current_job) + '\n')

            f.write(self.new_window.customer + '\n')
            f.write(self.new_window.machine_ + '\n')
            f.write('{},{}\n'.format(str(self.new_window.tax),
                                     self.new_window.tax_code))
            f.write(self.new_window.line1 + '\n')
            f.write(self.new_window.line2 + '\n')
            f.close()
        except:
            buttonReply = QMessageBox.question(
                self, 'Confirm New Machine',
                'Job Number {} already exist.\nDo you want to overwrite it?'.
                format(self.new_window.job_num),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if buttonReply == QMessageBox.Yes:
                self.table(self.new_window.job_num)
                location = os.path.join(
                    os.path.join(self.base_directory, 'Saved_Invoices'),
                    self.current_job)
                basic = os.path.join(location, 'Basic_Info.csv')
                f = open(basic, 'w')
                f.write(str(self.current_job) + '\n')

                f.write(self.new_window.customer + '\n')
                f.write(self.new_window.machine_ + '\n')
                f.write('{},{}\n'.format(str(self.new_window.tax),
                                         self.new_window.tax_code))
                f.write(self.new_window.line1 + '\n')
                f.write(self.new_window.line2 + '\n')
                f.close()
            elif buttonReply == QMessageBox.No:
                self.current_job = str(self.current_job)
                self.read_in_data()

    def existing_invoice_open(self):
        '''Open an existing invoice
        '''
        try:
            self.docked.close()
            self.docked2.close()
            self.save_invoice()
        except:
            True
        if not self.recent_open:
            self.recent_invoices()
        #get the saved invoices
        loc = os.path.join(self.base_directory, 'Saved_Invoices')
        saved_jobs = os.listdir(loc)
        self.existing = QWidget()
        self.existing.setWindowIcon(QIcon('BEI_Logo.png'))
        self.existing.setWindowTitle('Open Existing Invoice')
        self.open = QPushButton('Open', self)
        self.open.setFont(self.font)
        self.open.setSizePolicy(self.size_policy, self.size_policy)
        self.open.clicked.connect(self.reader)

        self.job_to_open = QLineEdit(self)
        self.job_to_open.setFont(self.font)
        self.job_to_open.setSizePolicy(self.size_policy, self.size_policy)
        self.job_to_open.setCompleter(QCompleter(saved_jobs))
        #        self.job_to_open.returnPressed.connect(self.reader)

        layout = QVBoxLayout()
        layout.addWidget(self.job_to_open)
        layout.addWidget(self.open)
        self.existing.setLayout(layout)
        self.existing.setGeometry(400, 400, 300, 100)
        self.existing.show()

    def reader(self):
        self.current_job = self.job_to_open.text()
        self.read_in_data()
        self.existing.close()

    def table(self, num):
        '''Setup the table for use with a new invoice
        '''
        self.start_flag = True
        self.actionPrint.setEnabled(True)

        self.actionSave.setEnabled(True)
        self.actionViewLaborBreakdown.setEnabled(True)
        self.actionBasicInfo.setEnabled(True)
        self.actionViewAllWindows.setEnabled(True)
        self.actionViewCutomer.setEnabled(True)
        self.actionViewCompany.setEnabled(True)
        self.docked = QMdiSubWindow()
        self.docked.setWindowTitle('Invoice {}'.format(num))
        self.num = num
        self.tabs = QTabWidget(self)
        self.parts = Parts_Tabs(num)
        self.tabs.addTab(self.parts, 'Parts')
        self.labor = Labor_Tabs(num)
        self.tabs.addTab(self.labor, 'Labor')
        self.docked.setWidget(self.tabs)

        self.parts.total.connect(self.calculate_totals)
        self.labor.labor_total.connect(self.calculate_totals)

        cust_display = QWidget(self)
        self.cust_label = QLabel('Customer: {}'.format(self.customer), self)
        self.cust_label.setFont(self.font)
        self.machine_label = QLabel('Machine: {}'.format(self.machine_text),
                                    self)
        self.machine_label.setFont(self.font)
        lay = QHBoxLayout()
        lay.addWidget(self.cust_label)
        lay.addWidget(self.machine_label)
        cust_display.setLayout(lay)

        #design and insert the totals table
        self.totals_table = Table(7, 2)
        self.totals_table.tableWidget.setItem(0, 0, QTableWidgetItem('Parts:'))
        self.totals_table.tableWidget.setItem(1, 0, QTableWidgetItem('Labor:'))
        self.totals_table.tableWidget.setItem(2, 0,
                                              QTableWidgetItem('Supplies:'))
        self.totals_table.tableWidget.setItem(3, 0,
                                              QTableWidgetItem('Freight:'))
        self.totals_table.tableWidget.setItem(4, 0,
                                              QTableWidgetItem('Subtotal:'))
        self.totals_table.tableWidget.setItem(
            5, 0, QTableWidgetItem('Tax: {:.2f}%'.format(self.tax * 100)))
        self.totals_table.tableWidget.setItem(6, 0, QTableWidgetItem('Total:'))
        #set up the comments section
        self.comments = QTextEdit(self)
        self.comments.setFont(self.font)
        self.comments.setSizePolicy(self.size_policy, self.size_policy)
        self.comments.setText('Comments:\n')

        self.additional_docking = QWidget(self)
        layout = QVBoxLayout(self)
        layout.addWidget(cust_display)
        layout.addWidget(self.totals_table)
        layout.addWidget(self.comments)
        self.additional_docking.setLayout(layout)

        self.docked2 = QMdiSubWindow()
        self.docked2.setWidget(self.additional_docking)
        self.docked2.setWindowTitle('Information')

        self.mdi = QMdiArea()
        self.mdi.addSubWindow(self.docked2)
        self.mdi.addSubWindow(self.docked)

        self.mdi.tileSubWindows()
        self.setCentralWidget(self.mdi)
#        self.window_saved=self.saveState(1)

    def recent_invoices(self):
        '''Show a list of recently opened invoices
        '''
        self.recent_open = True
        self.recent = QDockWidget('Recently opened invoices', self)

        self.recently_opened_invoice = QStandardItemModel()
        self.invoices_open = QListView(self)
        self.invoices_open.setFont(self.font)
        self.invoices_open.setSizePolicy(self.size_policy, self.size_policy)
        self.invoices_open.setModel(self.recently_opened_invoice)
        self.invoices_open.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.invoices_open.doubleClicked[QModelIndex].connect(self.recall)

        self.notes = QTextEdit(self)
        self.notes.setFont(self.font)
        self.notes.setSizePolicy(self.size_policy, self.size_policy)
        self.notes.setText('Notes:\n')

        self.running_info = QWidget(self)
        layout = QVBoxLayout(self)
        layout.addWidget(self.invoices_open)
        layout.addWidget(self.notes)
        self.running_info.setLayout(layout)
        self.recent.setWidget(self.running_info)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.recent)

    def recall(self, index):
        item = self.recently_opened_invoice.itemFromIndex(index)
        job_number = item.text()
        self.docked.close()
        self.docked2.close()
        self.save_invoice()
        self.current_job = job_number
        self.read_in_data()

    def save_invoice(self, printing=False):
        '''Save both the parts and labor tables
        '''
        if self.current_job == str:
            pass
        else:
            location = os.path.join(
                os.path.join(self.base_directory, 'Saved_Invoices'),
                self.current_job)
            parts_file = os.path.join(location, 'Parts.csv')
            #first read and write the parts information
            f = open(parts_file, 'w')
            row = []
            for i in range(100):
                try:
                    for j in range(8):
                        if j == 0:
                            if self.parts.parts_table.tableWidget.item(
                                    i, j).text() != '*':
                                val = float(
                                    self.parts.parts_table.tableWidget.item(
                                        i, j).text())
                            elif self.parts.parts_table.tableWidget.item(
                                    i, j).text() == '*':
                                val = self.parts.parts_table.tableWidget.item(
                                    i, j).text()
                            row.append(val)
                        else:
                            try:
                                val = self.parts.parts_table.tableWidget.item(
                                    i, j).text()
                                row.append(val)
                            except:
                                row.append('')
                    if '\n' in row[-1]:
                        row[-1] = row[-1].split(sep='\n')[0]
                    row[2] = row[2].replace(',', '.')
                    f.write('{},{},{},{},{},{},{},{}\n'.format(*row))
                    row = []
                except:
                    break
            f.close()
            #save the total table
            total_location = os.path.join(location, 'Totals.csv')
            h = open(total_location, 'w')
            t_row = [
                self.parts_, self.labor_, self.supplies, self.freight_,
                self.subtotal, self.taxed, self.totals
            ]
            for i in t_row:
                try:
                    float(i)
                    h.write('{:.2f}\n'.format(i))
                except:
                    h.write('0')
            h.close()
            #save the comments
            comments_location = os.path.join(location, 'Comments.csv')
            v = open(comments_location, 'w')
            v.write(self.comments.toPlainText())
            v.close()
            #finally save the labor information
            #get the number of techs showing
            count = self.labor.counts

            for l in range(count):
                labor_location = os.path.join(location, 'tech{}.csv'.format(l))
                o = open(labor_location, 'w')
                #get the data from the labor class
                tech_labor = self.labor.read_data_out(l)
                for k in range(len(tech_labor)):
                    if '\n' in list(tech_labor[k][-1]):
                        tech_labor[k][-1] = float(tech_labor[k][-1])
                    o.write('{},{},{},{},{},{},{},{}\n'.format(*tech_labor[k]))
                o.close()

        self.statusbar.showMessage('Invoice {} saved'.format(self.current_job),
                                   5000)
        envelop_writer = EWriter(self.base_directory, self.current_job)
        envelop_writer.generate_latex()

        acrobat = 'Acrobat.exe' in (p.name() for p in psutil.process_iter())
        reader = 'AcroRd32.exe' in (p.name() for p in psutil.process_iter())
        if acrobat:
            lis = ['taskkill', '/F', '/IM', 'Acrobat.exe', '/T']
            subprocess.call(lis)
        if reader:
            os.system('taskkill /F /IM "AcroRd32.exe" /T')

        if printing == False:
            comp_cust = Saver(self, self.base_directory, self.current_job)
            comp_cust.out.connect(self.failure)
            comp_cust.start()

    def failure(self, value):
        if value == 1:
            QMessageBox.information(self, 'Save Failure',
                                    'Closing PDF and trying again',
                                    QMessageBox.Ok)


#            self.save_invoice()

    def add_tech(self):
        '''Adding a technician to the company:
            Changes to make:
                Add to the tabs 
                Add standard labor rates
                Change stuff in the base invoice, 
                not sure how this is going to work yet
        '''
        text, okPressed = QInputDialog.getText(self, "Tech Name", "Tech name:",
                                               QLineEdit.Normal, "")
        if okPressed and text != '':
            regular, okPressed1 = QInputDialog.getDouble(
                self, "Regular Rate", "Regular Hourly Rate: $", 80, 0, 150, 2)
            if okPressed1:
                overtime, okPressed2 = QInputDialog.getDouble(
                    self, "Overtime Rate", "Overtime Hourly Rate: $", 80, 0,
                    150, 2)
                if okPressed2:
                    directory = str(
                        Path(
                            os.path.join(
                                os.path.join(os.environ['USERPROFILE'],
                                             'BEI_Invoices')),
                            'Basic_Information_Totals'))
                    tech_data = open(
                        str(Path(os.path.join(directory, 'Labor_Rates.csv'))),
                        'a')
                    tech_data.write('{},{},{}\n'.format(
                        text, regular, overtime))
                    tech_data.close()
                    QMessageBox.information(
                        self, 'Updated',
                        'Application must be restarted to apply these changes',
                        QMessageBox.Ok)

    def read_in_data(self):
        self.actionPartialPayment.setEnabled(True)
        self.actionFinanceCharges.setEnabled(True)
        self.invoice_count += 1

        if self.current_job not in self.open_list:
            self.open_list.append(self.current_job)
            self.recently_opened_invoice.appendRow(
                QStandardItem(self.current_job))
        #open the basic information and read the tax percentage
        location = os.path.join(
            os.path.join(self.base_directory, 'Saved_Invoices'),
            '{}'.format(self.current_job))
        e = open(os.path.join(location, 'Basic_Info.csv'), 'r')
        basic = e.readlines()
        e.close()
        self.customer, self.machine_text = basic[1].replace(
            '\n', ''), basic[2].replace('\n', '')

        self.tax = float(basic[3].split(sep=',')[0])
        self.table(self.current_job)
        self.machine_label.setText('Machine: {}'.format(self.machine_text))
        self.cust_label.setText('Customer: {}'.format(self.customer))
        #read in the parts data from the file and hand it off the the parts_tab
        #class to be placed in the table
        location = os.path.join(
            os.path.join(self.base_directory, 'Saved_Invoices'),
            '{}'.format(self.current_job))
        parts_location = os.path.join(location, 'Parts.csv')
        p_d = open(parts_location, 'r')
        p_data = p_d.readlines()
        p_d.close()
        parts_data = [p_data[i].split(sep=',') for i in range(len(p_data))]
        self.parts.read_in_data(parts_data)

        #read in the totals information
        totals_information = os.path.join(location, 'Totals.csv')
        t_d = open(totals_information, 'r')
        t_data = t_d.readlines()
        t_d.close()
        totals = [float(i) for i in t_data]
        #reset all the s
        self.reset_data()
        #try to read in payments and finance cahrges if they exist
        try:
            par_d = open(os.path.join(location, 'Payments.csv'), 'r')
            self.partial = float(par_d.readlines()[0])
            par_d.close()
        except:
            self.partial = 0
        try:
            fin_d = open(os.path.join(location, 'Finance.csv'), 'r')
            self.finance = float(fin_d.readlines()[0])
            fin_d.close()
        except:
            self.finance = 0

        self.parts_, self.labor_, self.supplies, self.freight_, self.subtotal, self.taxed, self.totals = totals
        #set the values into the totals table
        #        self.totals=self.totals+self.finance-self.partial
        for i in range(len(totals)):
            self.totals_table.tableWidget.setItem(
                i, 1, QTableWidgetItem('${:,.2f}'.format(totals[i])))

        #read and put the comments in place
        comments_location = os.path.join(location, 'Comments.csv')
        c_data = open(comments_location, 'r')
        com_data = c_data.readlines()
        c_data.close()
        combi = ''
        for i in com_data:
            combi += str(i)
        self.comments.setText(combi)

        #read in the labor data
        #determine the number of tech there are
        tech_num = 0
        dir_ = os.listdir(location)
        for i in range(len(dir_)):
            if 'tech' in dir_[i]:
                tech_num += 1

        for l in range(tech_num):
            loca = os.path.join(location, 'tech{}.csv'.format(l))
            l_data = open(loca, 'r')
            lab_data = l_data.readlines()
            l_data.close()
            labor_data = [o.split(sep=',') for o in lab_data]
            self.labor.read_in_data(l, labor_data)

    def reset_data(self):
        self.parts_, self.labor_, self.supplies, self.freight_, self.subtotal, self.taxed, self.totals = [
            0, 0, 0, 0, 0, 0, 0
        ]
        self.partial, self.finance = 0, 0

    def labor_rates(self):
        '''Change the labor rates
        '''
        self.changes = Labor_Rates(self.base_directory, self.font,
                                   self.size_policy)
        self.changes.show()

    def update_parts_total(self):
        self.parts_calculator()
        #        self.parts_=round(self.parts.parts_total,2)
        #        self.freight_=round(self.parts.freight_total,2)
        self.totals_table.tableWidget.setItem(
            0, 1, QTableWidgetItem('${:,.2f}'.format(self.parts_)))
        self.totals_table.tableWidget.setItem(
            3, 1, QTableWidgetItem('${:,.2f}'.format(self.freight_)))
        self.total_parts_ = self.parts_ + self.freight_

    def parts_calculator(self):
        self.parts_ = 0
        self.freight_ = 0
        #        self.parts.parts_sumation()
        #        self.parts_=self.parts.parts_total
        #        self.freight_=self.parts.freight_total+1

        for i in range(100):
            try:
                self.parts_ += float(
                    self.parts.parts_table.tableWidget.item(i, 5).text())
                try:
                    self.freight_ += float(
                        self.parts.parts_table.tableWidget.item(i, 6).text())
                except:
                    self.freight_ += 0
            except:
                True

    def update_labor(self):
        total_labor = 0
        for i in range(self.labor.counts):
            total_labor += self.labor.find_tech_total(i)
        self.totals_table.tableWidget.setItem(
            1, 1, QTableWidgetItem('${:,.2f}'.format(round(total_labor, 2))))
        self.totals_table.tableWidget.setItem(
            2, 1,
            QTableWidgetItem('${:,.2f}'.format(round(total_labor * 0.05, 2))))
        self.supplies = round(total_labor * 0.05, 2)
        self.labor_ = total_labor
        self.labor_supplies_ = round(self.labor_, 2) + self.supplies

    def calculate_totals(self):
        '''Calculate the totals for the totals table and display it
        '''
        self.update_labor()
        #        self.parts.parts_sumation()
        self.update_parts_total()
        self.subtotal = self.labor_supplies_ + self.total_parts_
        self.totals_table.tableWidget.setItem(
            4, 1, QTableWidgetItem('${:,.2f}'.format(self.subtotal)))
        self.taxed = self.tax * self.subtotal
        self.totals_table.tableWidget.setItem(
            5, 1, QTableWidgetItem('${:,.2f}'.format(self.taxed)))
        self.totals = self.subtotal + self.taxed + self.finance - self.partial
        self.totals_table.tableWidget.setItem(
            6, 1, QTableWidgetItem('${:,.2f}'.format(self.totals)))

    def print_invoice(self):
        '''
        Print the customer and company invoices
        '''
        #make sure the invoice is saved
        self.save_invoice(printing=True)
        self.printed_list[self.current_job] = [
            self.customer, self.machine_text
        ]
        try:
            pdf2.PDF_Builder(self.current_job, self.base_directory,
                             'Company').print_tex()
            pdf2.PDF_Builder(self.current_job, self.base_directory,
                             'Customer').print_tex()
        except:
            QMessageBox.information(self, 'Print Failure',
                                    'Close file and try again', QMessageBox.Ok)

        #first check and see if the Envelopes directory has this
        #months print list
        envelope_date = EP(self.base_directory, self.customer,
                           self.current_job)
        self.envelope_date = envelope_date.dater()
        self.actionEnvelope.setEnabled(True)
        self.actionEnvelope1.setEnabled(True)

    def closing(self):
        #        self.save_invoice()
        self.close()

    def breakdown(self):
        '''view the labor break down
        '''
        #open the labor rates to get the names
        loc = os.path.join(self.base_directory, 'Basic_Information_Totals')
        file_loc = os.path.join(loc, 'Labor_Rates.csv')
        f = open(file_loc, 'r')
        f_data = f.readlines()
        f.close()
        names = []
        for i in range(len(f_data)):
            names.append(f_data[i].split(sep=',')[0])
        #get the totals from the labor page
        individauls = self.labor.find_tech_individual()
        #combine the two lists into a single string
        combined = ''
        for i in range(len(individauls)):
            combined += '{}: ${:,.2f}\n'.format(names[i], individauls[i])
        QMessageBox.information(self, 'Labor Breakdown', combined,
                                QMessageBox.Ok)

    def date_change(self):
        '''change the data on the invoices for the month
        '''
        self.date_changed = QWidget()
        self.date_changed.setWindowTitle('Change Invoice Date')
        self.date_changed.setWindowIcon(QIcon('BEI_Logo.png'))
        self.line = QLineEdit()
        self.line.setFont(self.font)
        self.line.setSizePolicy(self.size_policy, self.size_policy)
        self.save_date = QPushButton('Save Date')
        self.save_date.setFont(self.font)
        self.save_date.setSizePolicy(self.size_policy, self.size_policy)
        self.save_date.clicked.connect(self.saved_date)
        layout = QVBoxLayout()
        layout.addWidget(self.line)
        layout.addWidget(self.save_date)
        self.date_changed.setLayout(layout)

        d_location = os.path.join(self.base_directory,
                                  'Basic_Information_Totals')
        self.date_location = os.path.join(d_location, 'Invoice_Date.txt')

        y = open(self.date_location, 'r')
        date = y.readlines()
        y.close()
        self.line.setText(date[0])
        self.date_changed.show()

    def saved_date(self):
        '''
        Save the new date
        '''
        y = open(self.date_location, 'w')
        y.write(self.line.text())
        y.close()
        self.date_changed.close()

    def new_job_nums(self):
        '''Run the class to create more job numbers 
        '''
        self.n_jobs = Job_Numbers()

    def cheat_sheet(self):
        '''Open the cheat sheet for viewing
        '''
        self.chea = Read_Cheat_Sheet(self.font, self.size_policy,
                                     self.base_directory)

    def add_cheat_task(self):
        self.cheat = Write_Cheat_Sheet(self.font, self.size_policy,
                                       self.base_directory)

    def partial_payment(self):
        self.a = Partial_Payments(self.font, self.size_policy)
        self.a.add.clicked.connect(self.proce)

    def proce(self):
        try:
            self.a.process()
            self.this_payment = self.a.amount
            try:
                location = os.path.join(
                    os.path.join(self.base_directory, 'Saved_Invoices'),
                    '{}'.format(self.current_job))
                payments = os.path.join(location, 'Payments.csv')
                f = open(payments, 'r')
                value = float(f.readlines()[0])
                f.close()
                self.this_payment += value
            except:
                self.this_payment = self.this_payment
            self.comments.append(
                '''Partial payment of ${:,.2f} on {}, leaves a remaining balance of ${:,.2f}'''
                .format(self.a.amount, self.a.date,
                        self.totals - self.a.amount))
            f = open(payments, 'w')
            f.write(str(self.this_payment))
            self.partial = self.this_payment
            self.calculate_totals()
            f.close()
        except:
            pass

    def finance_charges(self):
        self.charg = Finance_Charges(self.font, self.size_policy)
        self.charg.add.clicked.connect(self.fin_process)

    def fin_process(self):
        self.charg.process()
        self.finance += self.charg.amount

        self.comments.append(
            'Finance Charge of ${:,.2f} applied on {}, kindly remit payment immediately.'
            .format(self.charg.amount, self.charg.date))
        location = os.path.join(
            os.path.join(self.base_directory, 'Saved_Invoices'),
            '{}'.format(self.current_job))
        fin_loc = os.path.join(location, 'Finance.csv')
        f = open(fin_loc, 'w')
        f.write(str(self.finance))
        f.close()
        self.calculate_totals()

    def change_basic_info(self):
        #first read in the current status of the basic info
        location = os.path.join(
            os.path.join(self.base_directory, 'Saved_Invoices'),
            '{}'.format(self.current_job))
        e = open(os.path.join(location, 'Basic_Info.csv'), 'r')
        basic = e.readlines()
        e.close()

        self.update_info = QWidget()
        self.update_info.setWindowTitle('Update Basic Information')
        self.update_info.setWindowIcon(QIcon('BEI_Logo.png'))
        mach = QLabel('Machine', self)
        mach.setFont(self.font)
        mach.setSizePolicy(self.size_policy, self.size_policy)

        tax = QLabel('Tax [%]', self)
        tax.setFont(self.font)
        tax.setSizePolicy(self.size_policy, self.size_policy)

        self.machine = QLineEdit(self)
        self.machine.setFont(self.font)
        self.machine.setSizePolicy(self.size_policy, self.size_policy)
        self.machine.setText(basic[2])

        self.tax_value = QLineEdit(self)
        self.tax_value.setFont(self.font)
        self.tax_value.setSizePolicy(self.size_policy, self.size_policy)
        self.tax_value.setText(
            str(round(float(basic[3].split(sep=',')[0]) * 100, 2)))

        update = QPushButton('Update', self)
        update.setFont(self.font)
        update.setSizePolicy(self.size_policy, self.size_policy)
        update.clicked.connect(self.update_basic_values)

        layout = QGridLayout()
        layout.addWidget(mach, 0, 0)
        layout.addWidget(self.machine, 0, 1)
        layout.addWidget(tax, 1, 0)
        layout.addWidget(self.tax_value, 1, 1)
        layout.addWidget(update, 2, 0)
        self.update_info.setLayout(layout)
        self.update_info.show()

    def update_basic_values(self):
        self.update_info.close()
        location = os.path.join(
            os.path.join(self.base_directory, 'Saved_Invoices'),
            '{}'.format(self.current_job))
        e = open(os.path.join(location, 'Basic_Info.csv'), 'r')
        basic = e.readlines()
        e.close()
        flag = False
        #change the information in basic[2] and basic[3] to match the new values
        if basic[2].split(sep='\n')[0] != self.machine.text():
            old = basic[2].split(sep='\n')[0].replace(' ', '_')
            cust = basic[1].split(sep='\n')[0].replace(' ', '_')
            file_name = basic[0].split(sep='\n')[0] + '.pdf'
            flag = True
            basic[2] = self.machine.text()
            self.machine_text = basic[2]
            self.machine_label.setText('Machine: {}'.format(self.machine_text))
        if float(basic[3].split(
                sep=',')[0]) != float(self.tax_value.text()) / 100:
            try:
                tax_code, ok = QInputDialog.getText(
                    self, 'Update Tax Code', 'Tax Code: ', QLineEdit.Normal,
                    basic[3].split(sep=',')[1].split(sep='\n')[0])
            except:
                tax_code, ok = QInputDialog.getText(self, 'Update Tax Code',
                                                    'Tax Code: ',
                                                    QLineEdit.Normal, "")
            basic[3] = '{},{}'.format(
                float(self.tax_value.text()) / 100, tax_code)

        self.tax = float(self.tax_value.text()) / 100

        f = open(os.path.join(location, 'Basic_Info.csv'), 'w')
        for i in range(len(basic)):
            if '\n' not in basic[i]:
                f.write('{}\n'.format(basic[i]))
            else:
                f.write('{}'.format(basic[i]))
        f.close()

        #change the percent shown in the total value
        self.totals_table.tableWidget.setItem(
            5, 0, QTableWidgetItem('Tax: {:.2f}%'.format(self.tax * 100)))
        #next update the totals
        self.calculate_totals()
        self.save_invoice()
        time.sleep(3)
        if flag:
            #depending on if the machine has been updated, get rid of the previous
            #version of the file and start change it to the new location
            location = os.path.join(os.path.expanduser('~/Desktop'),
                                    'BEI_Invoices')
            old_location_cust_ = os.path.join(
                os.path.join(location, 'Customer'), cust)
            old_location_cust = os.path.join(old_location_cust_, old)
            old_final_cust = os.path.join(old_location_cust, file_name)

            old_location_comp_ = os.path.join(
                os.path.join(location, 'Company'), cust)
            old_location_comp = os.path.join(old_location_comp_, old)
            len_old = len(os.listdir(old_location_comp))
            old_final_comp = os.path.join(old_location_comp, file_name)

            if len_old == 1:
                shutil.rmtree(old_location_comp)
                shutil.rmtree(old_location_cust)
            else:
                os.unlink(old_final_comp)
                os.unlink(old_final_cust)

    def view_windows(self):
        '''Used to re-initialize the totals and main window'''
        self.save_invoice()
        self.read_in_data()

    def closeEvent(self, event):
        if self.start_flag:
            self.save_invoice(printing=True)
            flag = self.save_no_threading()
            if flag == 0:
                reply = QMessageBox.question(
                    self, 'Close Window',
                    'Do you want to close the application?',
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

                if reply == QMessageBox.Yes:
                    event.accept()
                else:
                    event.ignore()
            else:
                event.ignore()
        else:
            event.accept()

    def updater(self):
        QMessageBox.information(self, 'Restart Required',
                                'Run BEI_Updater and Restart program',
                                QMessageBox.Ok)
        self.close()

    def change_address(self):
        self.edi = EDI(self.font, self.size_policy, self.base_directory)

    def view_customer(self):
        flag = self.save_no_threading()
        if flag == 0:
            location = os.path.join(os.path.expanduser('~/Desktop'),
                                    'BEI_Invoices')
            location = os.path.join(location, 'Customer')
            cust_location = os.path.join(location,
                                         self.customer.replace(' ', '_'))
            machine_location = os.path.join(
                cust_location, self.machine_text.replace(' ', '_'))
            job_location = os.path.join(machine_location, '{}.pdf'.format(
                self.current_job)).replace('&', '^&')
            print(job_location)
            subprocess.Popen(job_location, shell=True)
        else:
            pass

    def view_company(self):
        flag = self.save_no_threading()
        if flag == 0:
            location = os.path.join(os.path.expanduser('~/Desktop'),
                                    'BEI_Invoices')
            location = os.path.join(location, 'Company')
            cust_location = os.path.join(location,
                                         self.customer.replace(' ', '_'))
            machine_location = os.path.join(
                cust_location, self.machine_text.replace(' ', '_'))
            job_location = os.path.join(machine_location, '{}.pdf'.format(
                self.current_job)).replace('&', '^&')
            subprocess.Popen(job_location, shell=True)
        else:
            pass

    def save_no_threading(self):
        self.save_invoice(printing=True)
        try:
            pdf2.PDF_Builder(self.current_job, self.base_directory, 'Company')
            pdf2.PDF_Builder(self.current_job, self.base_directory, 'Customer')
            return 0
        except:
            QMessageBox.information(self, 'Opening Failure',
                                    'Close file and try again', QMessageBox.Ok)
            time.sleep(1)
            return 1

    def envelop_write(self):
        #navigate to the envelope folder
        loc = os.path.join(
            os.path.join(self.base_directory, 'Customer_Envelopes'),
            self.envelope_date + '.txt')
        f = open(loc, 'r')
        data = f.readlines()
        f.close()
        job_numbers = []
        for i in data:
            job_numbers.append(i.split()[1])
        QMessageBox.information(
            self, 'Envelope Printing',
            'Load {} invoices into printer before clicking OK'.format(
                len(job_numbers)), QMessageBox.Ok)
        base = os.path.join(self.base_directory, 'Saved_Invoices')
        for i in range(len(job_numbers)):
            enve_loc = os.path.join(os.path.join(base, job_numbers[i]),
                                    'envelope.pdf')
            os.startfile(enve_loc, 'print')

    def envelop_write1(self):
        #get the job number to print
        num, ok = QInputDialog.getText(self, 'Single Customer Envelope',
                                       'Job Number to print:',
                                       QLineEdit.Normal, '')
        if num != '' and ok:
            writer = EWriter(self.base_directory, num)
            writer.generate_latex()
            QMessageBox.information(
                self, 'Envelope Printing',
                'Load 1 invoices into printer before clicking OK',
                QMessageBox.Ok)
            writer.print_pdf()

    def billing_envelopes(self):
        self.billing_ = CE(self.base_directory)
Пример #22
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        # TODO put these in a data model object and xml file
        self.column_order = [
            SampleTypes.Time, SampleTypes.Pressure, SampleTypes.Temperature
        ]
        self.sample_types_requested_ordered = []
        self.delimiter = ','

        self.current_row = 0
        self.setWindowTitle("P-T Tester")
        self.arduino_thread = None
        self.arduino_worker = None
        self.test_state = State.ReadyNotRan
        self.output_file = None
        self.ax = None
        self.ax_secondaries = dict()
        self.plot_colors = dict()

        # CONFIG DOCK
        self.config_dock = ConfigDock("Test Options", self)
        self.config_dock.start_button_slot(self.start_test)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.config_dock)

        # FILE OUTPUT DOCK
        self.outfile_dock = OutfileDock("Output Selection", self)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.outfile_dock)

        # TABLE Window
        # TODO TableWidget members private, put table editing functions in TableWidget, not here
        self.table_view_tbl = TableWidget(self)

        # PLOT window
        self.plot_window = PlotWindow(self)

        # MDI SETUP
        self.mdi_area = QMdiArea()
        self.setCentralWidget(self.mdi_area)
        self.mdi_area.addSubWindow(self.table_view_tbl)
        self.mdi_area.addSubWindow(self.plot_window)
        self.mdi_area.tileSubWindows()

        # set initial state of window
        self.update_status(State.ReadyNotRan)

    def initialize_plot(self):
        plt.ion()
        self.plot_colors[
            SampleTypes.Pressure] = self.config_dock.pressure_color_name
        self.plot_colors[
            SampleTypes.Temperature] = self.config_dock.temperature_color_name
        self.plot_window.figure.clear()
        self.ax = self.plot_window.figure.add_subplot(111)
        self.ax.set_xlabel('time (s)')
        self.ax.set_ylabel(
            SampleNames.names[self.sample_types_requested_ordered[0]],
            color=self.plot_colors[self.sample_types_requested_ordered[0]])
        if len(self.sample_types_requested_ordered) > 1:
            for sample_type in self.sample_types_requested_ordered[1:]:
                self.ax_secondaries[sample_type] = self.ax.twinx()
                self.ax_secondaries[sample_type].set_ylabel(
                    SampleNames.names[sample_type],
                    color=self.plot_colors[sample_type])

    def plot_sample(self, current_time, sample):
        # TODO why doesn't it show the line?, only markers are shown.
        marker = dict()
        marker[SampleTypes.Pressure] = self.config_dock.pressure_marker()
        marker[SampleTypes.Temperature] = self.config_dock.temp_marker()
        self.ax.plot(
            current_time,
            sample.values[self.sample_types_requested_ordered[0]],
            color=self.plot_colors[self.sample_types_requested_ordered[0]],
            marker=marker[self.sample_types_requested_ordered[0]],
            linewidth='2',
            linestyle='-')

        for sample_type in self.sample_types_requested_ordered[1:]:
            self.ax_secondaries[sample_type].plot(current_time, sample.values[sample_type],\
                                                  color=self.plot_colors[sample_type], marker=marker[sample_type])

    def start_test(self):
        # is at least 1 type of reading set
        record_p = self.config_dock.record_pressure_is_checked()
        record_t = self.config_dock.record_temperature_is_checked()
        if not record_p and not record_t:
            QMessageBox.warning(self, "Invalid Test Parameters",
                                "Must select at least 1 reading type",
                                QMessageBox.Ok)
            return
        # check test parameters
        sample_rate = self.config_dock.sample_rate()
        nb_samples = self.config_dock.number_of_samples()
        if nb_samples <= 1:
            QMessageBox.warning(
                self, "Invalid Test Parameters",
                "Duration too short or sampling rate too large",
                QMessageBox.Ok)
            return
        if not self.config_dock.record_pressure_is_checked(
        ) and not self.config_dock.record_temperature_is_checked():
            QMessageBox(self, "Invalid Selection",
                        "At least one type of measurement must be selected",
                        QMessageBox.Ok)
            return
        # check if there is already a test in progress
        if self.test_state == State.InProgress:
            return
        # worker thread will check connection, not done here
        # if test(s) were run before, table may contain data
        if self.test_state != State.ReadyNotRan and self.current_row > 1:
            choice = QMessageBox.question(
                self, "Starting New Test",
                "Starting new test will erase current data,\
                                          do you want to continue?",
                QMessageBox.Yes | QMessageBox.No)
            if choice == QMessageBox.No:
                return
            else:
                self.table_view_tbl.clearContents()
        # check given folder+file can be created
        if not self.outfile_dock.is_file_ok():
            return
        # if here, test can begin
        self.sample_types_requested_ordered = []
        for samp_type in self.column_order:
            if samp_type == SampleTypes.Pressure and record_p:
                self.sample_types_requested_ordered.append(
                    SampleTypes.Pressure)
            if samp_type == SampleTypes.Temperature and record_t:
                self.sample_types_requested_ordered.append(
                    SampleTypes.Temperature)

        self.initialize_table()
        self.initialize_file()
        self.initialize_plot()

        # set up arduino worker and signal-slots
        self.initialize_worker(nb_samples, record_p, record_t, sample_rate)
        # reading of measurements starts here
        # TODO make sure QThread terminates successfully upon quitting app while second thread is running
        self.arduino_thread.start()

        # gui updates
        # timer is started by worker thread, not here
        # update_gui called by update_status
        self.update_status(State.InProgress)

    def initialize_worker(self, nb_samples, record_p, record_t, sample_rate):
        self.arduino_worker = ArduinoWorker(sample_rate, nb_samples, record_p,
                                            record_t)
        self.arduino_thread = QThread()
        self.arduino_worker.moveToThread(self.arduino_thread)
        self.arduino_thread.started.connect(self.arduino_worker.run)
        self.arduino_worker.sample_received.connect(self.process_sample)
        self.arduino_worker.timer_start.connect(self.update_test_timers)
        self.config_dock.stop_button_slot(
            self.arduino_thread.requestInterruption)
        self.arduino_worker.stopped.connect(self.stop_test)

    def update_gui(self, test_state):
        # config_dock runs its own update_gui through its update_label
        # so, no need to call it
        self.outfile_dock.update_gui(test_state)

    def update_test_timers(self):
        cur_time = QTime.currentTime()
        end_time = cur_time.addSecs(self.config_dock.duration())
        self.config_dock.set_start_time(cur_time.toString("hh:mm:ss"))
        self.config_dock.set_end_time(end_time.toString("hh:mm:ss"))

    def initialize_table(self):
        number_of_columns = len(
            self.sample_types_requested_ordered) + 1  # +1 for time
        number_of_samples = self.config_dock.number_of_samples()
        self.table_view_tbl.setColumnCount(number_of_columns)
        self.table_view_tbl.setRowCount(number_of_samples)
        headers = []
        headers.append(SampleNames.names[SampleTypes.Time])
        for sample_type in self.sample_types_requested_ordered:
            headers.append(SampleNames.names[sample_type])
        self.table_view_tbl.setHorizontalHeaderLabels(headers)
        self.table_view_tbl.clearContents()
        self.current_row = 0

    def initialize_file(self):
        self.output_file = open(self.outfile_dock.full_path(), "w")
        headers = []
        headers.append(SampleNames.names[SampleTypes.Time])
        for sample_type in self.sample_types_requested_ordered:
            headers.append(SampleNames.names[sample_type])
        for index, header in enumerate(headers):
            self.output_file.write(header)
            if index != len(headers) - 1:
                self.output_file.write(self.delimiter)
        self.output_file.write("\n")

    def process_sample(self, sample):
        current_time = self.current_row * self.config_dock.sample_rate()

        self.print_sample_qtable(current_time, sample)
        self.print_sample_csv(current_time, sample)
        self.plot_sample(current_time, sample)

        self.table_view_tbl.selectRow(self.current_row)
        self.current_row += 1

    def print_sample_qtable(self, current_time, sample):
        self.table_view_tbl.setItem(
            self.current_row, 0,
            QTableWidgetItem("{:.2f}".format(current_time)))
        for i, sample_type in enumerate(self.sample_types_requested_ordered,
                                        start=1):
            self.table_view_tbl.setItem(
                self.current_row, i,
                QTableWidgetItem("{:.2f}".format(sample.values[sample_type])))

    def print_sample_csv(self, current_time, sample):
        self.output_file.write("{:.2f}".format(current_time) + self.delimiter)
        for index, sample_type in enumerate(
                self.sample_types_requested_ordered):
            self.output_file.write("{:.2f}".format(sample.values[sample_type]))
            if index != len(self.sample_types_requested_ordered) - 1:
                self.output_file.write(self.delimiter)
        self.output_file.write("\n")
        logger.info(
            "P and T readings being written to csv: {:.2f}, {:.2f}".format(
                sample.values[SampleTypes.Pressure],
                sample.values[SampleTypes.Temperature]))

    def stop_test(self, state):
        if self.test_state == State.InProgress:
            self.update_status(state)
            self.test_state = state
            self.output_file.close()
            self.arduino_thread.quit()
            self.arduino_worker = None
            self.arduino_thread = None

    def update_status(self, test_state):
        self.test_state = test_state
        self.update_gui(test_state)
        self.config_dock.update_status(self.test_state)
class MainWindow(QMainWindow):

    _logname = 'MainWindow'
    _log = logging.getLogger(f'{_logname}')

    def __init__(self, LOGIN, isRunningOnPi=False, parent=None):
        super(MainWindow, self).__init__()

        self.main_widget = QWidget()
        self.mdi = QMdiArea()
        self.setWindowTitle('Brew Monitoring System')

        bar = self.menuBar()
        filebar = bar.addMenu("File")
        filebar.addAction("New User")
        filebar.addAction("New Brew")
        filebar.triggered.connect(self.fileaction)

        viewbar = bar.addMenu("View")
        viewbar.addAction("Mash and Boil Vessels")
        viewbar.addAction("Fermentation Vessels")
        viewbar.addAction("Past Brew Data")
        viewbar.triggered.connect(self.viewaction)

        windowbar = bar.addMenu("Window")
        windowbar.addAction("Cascade")
        windowbar.addAction("Tiled")
        windowbar.triggered.connect(self.windowaction)

        systembar = bar.addMenu("System")
        systembar.addAction("Check For Faults")

        self.mainwindow = MdiMainWindow(LOGIN,
                                        isRunningOnPi=isRunningOnPi,
                                        parent=self)

        quitButton = QPushButton("Quit")
        quitButton.clicked.connect(lambda: self.close())

        quitLayout = QHBoxLayout()
        quitLayout.addStretch(10)
        quitLayout.addWidget(quitButton)

        splitter = QSplitter()
        splitter.setOrientation(2)
        splitter.addWidget(self.mainwindow)
        splitter.addWidget(self.mdi)

        layout = QVBoxLayout()
        #layout.addWidget(self.mainwindow)
        #layout.addWidget(self.mdi)
        layout.addWidget(splitter)
        #layout.addLayout(quitLayout)
        #self.main_widget.setLayout(layout)
        # self.main_widget.showFullScreen()

        self.main_widget.setLayout(layout)

        self.setMinimumSize(700, 500)
        self.resize(0, 0)

        self.setCentralWidget(self.main_widget)
        # self.showFullScreen()

    def fileaction(self, selected):
        selected = selected.text()
        if selected == "New User":
            self.mainwindow.newUserClicked()
        elif selected == "New Brew":
            self.mainwindow.startBrewClicked()

    def windowaction(self, selected):
        selected = selected.text()
        if selected == "Cascade":
            self.mdi.cascadeSubWindows()
        elif selected == "Tiled":
            self.mdi.tileSubWindows()

    def viewaction(self, selected):
        selected = selected.text()
        if selected == "Fermentation Vessels":
            self.mainwindow.fermentButtonClicked()
        elif selected == "Mash and Boil Vessels":
            self.mainwindow.mashBoilButtonClicked()
        elif selected == "Past Brew Data":
            self.mainwindow.viewDataClicked()
Пример #24
0
class MDIWindow(QMainWindow):
    count = 0

    def __init__(self):
        super().__init__()

        self.data_dict = {}
        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)
        #        self.mdi.resize(950,950)

        bar = self.menuBar()

        self.current_dir = None
        self.opened_wd_names = []
        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("cascade")
        file.addAction("Tiled")
        file.triggered[QAction].connect(self.WindowTrig)

        load = bar.addMenu("Load")
        load.addAction("2D")
        load.addAction("3D")
        load.triggered[QAction].connect(self.dir_open)

        toolbar = QToolBar()
        self.addToolBar(toolbar)

        bw_button_action = QAction('base_wnd', self)
        bw_button_action.setStatusTip('base window button')
        bw_button_action.triggered.connect(self.onclicktb)
        toolbar.addAction(bw_button_action)

        self.setWindowTitle("MDI Application")

        self.base_wd = QMdiSubWindow()
        self.base_wd.setAttribute(Qt.WA_DeleteOnClose, False)
        self.base_wd.resize(400, 400)
        self.base_wd.plt_i = pg.PlotItem(labels={
            'left': ('slits', 'degrees'),
            'bottom': ('Kin. Energy', 'eV')
        })
        self.base_wd.plt_iv = pg.ImageView(view=self.base_wd.plt_i)
        self.base_wd.setWidget(self.base_wd.plt_iv)
        self.base_wd.setWindowTitle("plot window")
        self.mdi.addSubWindow(self.base_wd)
        self.base_wd.show()

        data_DockWidget = QDockWidget('data', self)
        data_DockWidget.setObjectName(('data window'))
        data_DockWidget.setAllowedAreas(Qt.RightDockWidgetArea)

        self.data_list = QListWidget()
        data_DockWidget.setWidget(self.data_list)
        self.addDockWidget(Qt.RightDockWidgetArea, data_DockWidget)

        self.data_list.itemClicked.connect(self.show_data)
        self.data_list.itemDoubleClicked.connect(self.get_data)
        self.mdi.subWindowActivated.connect(self.get_data)

    def WindowTrig(self, p):
        if p.text() == "New":
            MDIWindow.count = MDIWindow.count + 1
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("Sub Window" + str(MDIWindow.count))
            self.mdi.addSubWindow(sub)
            sub.show()

        if p.text() == "cascade":
            self.mdi.cascadeSubWindows()

        if p.text() == "Tiled":
            self.mdi.tileSubWindows()

    def dir_open(self, p):
        self.current_dir = dlg.File_dlg.openDirNameDialog(self)
        print(self.current_dir)
        if p.text() == "2D":
            print('2D')
            files_ls = glob.glob(self.current_dir + '/*.ibw')
            fls = [f[len(self.current_dir) + 1:] for f in files_ls]
            print(files_ls)
            self.data_list.addItems(fls)
        if p.text() == "3D":
            zip_ls = glob.glob(self.current_dir + '/*.zip')
            zp = [f[len(self.current_dir) + 1:] for f in zip_ls]
            print(zp)
            self.data_list.addItems(zp)

    def show_data(self, s):
        print('show data')
        file_name = s.text()
        self.data_dict = ut.ibw2dict(self.current_dir + '/' + file_name)

        e_sc = self.data_dict['E_axis'][1] - self.data_dict['E_axis'][0]
        a_sc = self.data_dict['A_axis'][1] - self.data_dict['A_axis'][0]
        e_str = self.data_dict['E_axis'][0]
        a_str = self.data_dict['A_axis'][0]
        self.base_wd.plt_i.setRange(xRange=[self.data_dict['E_axis'][0], self.data_dict['E_axis'][-1]], \
                            yRange=[self.data_dict['A_axis'][0], self.data_dict['A_axis'][-1]], update=True, padding = 0)

        self.base_wd.plt_i.getViewBox().setLimits(xMin= e_str, xMax = self.data_dict['E_axis'][-1],\
                                          yMin=self.data_dict['A_axis'][0], yMax=self.data_dict['A_axis'][-1])

        self.base_wd.plt_iv.setImage(
            self.data_dict['data'],
            pos=[self.data_dict['E_axis'][0], self.data_dict['A_axis'][0]],
            scale=[e_sc, a_sc])
        #        self.base_wd.plt_iv.ui.histogram.hide()
        self.base_wd.plt_iv.ui.roiBtn.hide()
        self.base_wd.plt_iv.ui.menuBtn.hide()

    def get_data(self, s):
        if isinstance(s, QMdiSubWindow) and str(
                s.objectName()) in self.opened_wd_names:
            sub = self.mdi.currentSubWindow()
            self.data_dict = ut.ibw2dict(self.current_dir + '/' +
                                         str(s.objectName()))
        elif isinstance(s, QListWidgetItem):
            file_name = s.text()
            self.opened_wd_names.append(file_name)
            MDIWindow.count = MDIWindow.count + 1
            sub = QMdiSubWindow()
            sub.resize(550, 550)
            sub.setWindowTitle(file_name)
            sub.setObjectName(file_name)
            self.data_dict = ut.ibw2dict(self.current_dir + '/' + file_name)
        else:
            print(isinstance(s, QMdiSubWindow), isinstance(s, QListWidgetItem))
            print(type(s))
            return
        e_sc = self.data_dict['E_axis'][1] - self.data_dict['E_axis'][0]
        a_sc = self.data_dict['A_axis'][1] - self.data_dict['A_axis'][0]
        e_rg = self.data_dict['E_axis'][-1] - self.data_dict['E_axis'][0]
        a_rg = self.data_dict['A_axis'][-1] - self.data_dict['A_axis'][0]

        e_str = self.data_dict['E_axis'][0]
        a_str = self.data_dict['A_axis'][0]
        e_end = self.data_dict['E_axis'][-1]
        a_end = self.data_dict['A_axis'][-1]
        print(e_str, a_str)
        print(e_end, a_end)
        print(e_rg, a_rg)
        print(e_sc, a_sc)

        gr_v = pg.GraphicsView()
        l = pg.GraphicsLayout()
        gr_v.setCentralWidget(l)
        sub.setWidget(gr_v)
        self.mdi.addSubWindow(sub)
        sub.show()

        p1 = l.addPlot(x=[1, 2],
                       y=[1, 2],
                       name="Plot1",
                       title="EDC",
                       pen="r",
                       row=0,
                       col=0)
        #       label1 = pg.LabelItem(justify='right')
        #        p1.addItem(label1)

        plt_i = pg.PlotItem(labels={
            'left': ('slits', 'degrees'),
            'bottom': ('Kin. Energy', 'eV')
        })
        plt_i.setRange(xRange=[e_str, e_end],
                       yRange=[a_str, a_end],
                       update=True,
                       padding=0)

        vb = plt_i.getViewBox()
        vb.setLimits(xMin=e_str, xMax=e_end, yMin=a_str, yMax=a_end)
        vb.setMouseMode(vb.RectMode)

        l.addItem(plt_i, row=1, col=0)
        img_i = pg.ImageItem(self.data_dict['data'], border=None)
        qrect = vb.viewRect()
        img_i.setRect(qrect)
        vb.addItem(img_i)
        vb.autoRange()
        #        vb.invertX()
        vb.invertY()
        hist = pg.HistogramLUTItem(image=img_i)

        l.addItem(hist, row=0, col=1)

        p2 = l.addPlot(x=[1, 2],
                       y=[2, 1],
                       name="Plot2",
                       title="MDC",
                       pen="g",
                       row=1,
                       col=1)
        #        label2 = pg.LabelItem(justify='left')
        #        plt_i.addItem(label2)

        # cross hair
        vLine = pg.InfiniteLine(angle=90, movable=False)
        hLine = pg.InfiniteLine(angle=0, movable=False)
        p1.addItem(vLine, ignoreBounds=False)
        p1.addItem(hLine, ignoreBounds=False)

        vb1 = p1.vb

        pcv = plt_i.addLine(x=e_end, pen='r')
        pch = plt_i.addLine(y=a_str, pen='r')

        #        lROI = pg.ROI(((e_str+e_end)/2,a_str), size=(5*e_sc,a_rg))
        #        vb.addItem(lROI)
        #        slice, coor = lROI.getArrayRegion(self.data_dict['data'], img_i ,returnMappedCoords = True)

        #        print('slice')
        #        sl_sum=np.sum(slice, axis=0)
        #        print(sl_sum[0:10])
        #        print(type(slice), slice.shape)
        #        print(type(coor), coor.shape)
        #        print(coor[1,0,0:10])
        #        p2.invertY()
        #        p2.setYLink(plt_i)
        #        p2.plot(y=coor[1,0,:], x=sl_sum)

        def onMouseMoved(point):
            p = vb.mapSceneToView(point)
            pcv.setValue(p.x())
            pch.setValue(p.y())
            #            print(p.x(), p.y())

            hROI = pg.ROI((e_str, p.y()), size=(e_rg, 5 * a_sc))
            vb.addItem(hROI)
            hROI.hide()
            sl, co = hROI.getArrayRegion(self.data_dict['data'],
                                         img_i,
                                         returnMappedCoords=True)
            sl_sum = np.sum(sl, axis=1)
            p1.setXLink(plt_i)
            p1.plot(x=co[0, :, 0], y=sl_sum, clear=True)

            vROI = pg.ROI((p.x(), a_str), size=(5 * e_sc, a_rg))
            vb.addItem(vROI)
            vROI.hide()
            slc, coo = vROI.getArrayRegion(self.data_dict['data'],
                                           img_i,
                                           returnMappedCoords=True)
            sl_sum = np.sum(slc, axis=0)
            p2.invertY()
            p2.setYLink(plt_i)
            p2.plot(y=coo[1, 0, :], x=sl_sum, clear=True)


#            label2.setText("{}-{}".format(p.x(), p.y()))

        img_i.scene().sigMouseMoved.connect(onMouseMoved)

    def onclicktb(self):
        self.base_wd.plt_i = pg.PlotItem(labels={
            'left': ('slits', 'degrees'),
            'bottom': ('Kin. Energy', 'eV')
        })
        self.base_wd.plt_iv = pg.ImageView(view=self.base_wd.plt_i)
        self.base_wd.setWidget(self.base_wd.plt_iv)
        self.base_wd.show()
Пример #25
0
class MainWindow(QMainWindow):
    CURVATURE, THICKNESS, MATERIAL, SEMIDIAM = range(4)
    count = 0

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.seq_model = seq.SequentialModel()
        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)

        bar = self.menuBar()

        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("Open...")
        file.addSeparator()
        file.addAction("Save")
        file.addAction("Save As...")
        file.triggered[QAction].connect(self.file_action)
        view = bar.addMenu("View")
        view.addAction("Table")
        view.addAction("Lens View")
        view.triggered[QAction].connect(self.view_action)
        wnd = bar.addMenu("Window")
        wnd.addAction("Cascade")
        wnd.addAction("Tiled")
        wnd.triggered[QAction].connect(self.window_action)
        self.setWindowTitle("Ray Optics")
        self.show()
        self.open_file(
            "/Users/Mike/Developer/PyProjects/ray-optics/codev/test/ag_dblgauss.seq"
        )

    def file_action(self, q):
        if q.text() == "New":
            MainWindow.count = MainWindow.count + 1
            sub = QMdiSubWindow()
            sub.setWidget(QTextEdit())
            sub.setWindowTitle("subwindow" + str(MainWindow.count))
            self.mdi.addSubWindow(sub)
            sub.show()

        if q.text() == "Open...":
            options = QFileDialog.Options()
            # options |= QFileDialog.DontUseNativeDialog
            fileName, _ = QFileDialog.getOpenFileName(
                self,
                "QFileDialog.getOpenFileName()",
                "",
                "CODE V Files (*.seq)",
                options=options)
            if fileName:
                logging.debug("open file: %s", fileName)
                self.open_file(fileName)

    def open_file(self, file_name):
        self.cur_filename = file_name
        self.is_changed = True
        cvp.read_lens(self.seq_model, file_name)
        self.create_lens_table()
        self.create_2D_lens_view()

    def view_action(self, q):
        print("view triggered")

        if q.text() == "Table":
            MainWindow.count = MainWindow.count + 1
            self.create_lens_table()

        if q.text() == "Lens View":
            MainWindow.count = MainWindow.count + 1
            self.create_2D_lens_view()

    def window_action(self, q):
        print("window triggered")

        if q.text() == "Cascade":
            self.mdi.cascadeSubWindows()

        if q.text() == "Tiled":
            self.mdi.tileSubWindows()

    def create_lens_table(self):
        # construct the top level widget
        widget = QWidget()
        # construct the top level layout
        layout = QVBoxLayout(widget)

        tableView = QTableView()
        tableView.setAlternatingRowColors(True)
        # table selection change
        #        self.tableView.doubleClicked.connect(self.on_click)

        # Add table to box layout
        layout.addWidget(tableView)

        # set the layout on the widget
        widget.setLayout(layout)

        sub = self.mdi.addSubWindow(widget)
        sub.setWindowTitle("Surface Data Table")

        model = self.createSurfaceModel(self)
        tableView.setModel(model)
        for s in range(len(self.seq_model.surfs)):
            self.addSurface(model, self.seq_model.list_surface_and_gap(s))

        tableView.setMinimumWidth(tableView.horizontalHeader().length() +
                                  tableView.horizontalHeader().height())
        #                                  The following line should work but returns 0
        #                                  tableView.verticalHeader().width())
        sub.show()

    def create_2D_lens_view(self):
        self.scene2d = QGraphicsScene()
        self.create_element_model(self.scene2d)
        self.create_ray_model(self.scene2d)
        self.scene2d.setBackgroundBrush(QColor(237, 243, 254))  # light blue
        sceneRect2d = self.scene2d.sceneRect()
        print("Scene rect1:",
              sceneRect2d.width() / sceneRect2d.height(), sceneRect2d.x(),
              sceneRect2d.y(), sceneRect2d.width(), sceneRect2d.height())

        # construct the top level widget
        widget = QWidget()
        # construct the top level layout
        layout = QVBoxLayout(widget)

        # set the layout on the widget
        widget.setLayout(layout)

        sub = self.mdi.addSubWindow(widget)
        sub.setWindowTitle("2D Lens View")
        view_width = 600
        view_ht = 400
        view_ratio = view_width / view_ht
        sub.setGeometry(100, 50, view_width, view_ht)

        self.gview2d = QGraphicsView(self.scene2d)
        #        self.gview2d.setGeometry(100, 50, view_width, view_ht)
        scene_ratio = sceneRect2d.width() / sceneRect2d.height()
        oversize_fraction = 1.2
        if scene_ratio > view_ratio:
            view_scale = view_width / (oversize_fraction * sceneRect2d.width())
        else:
            view_scale = view_ht / (oversize_fraction * sceneRect2d.height())

        print(view_ratio, scene_ratio, view_scale)
        frame_before = self.gview2d.frameGeometry()
        print("Frame before:", frame_before.x(), frame_before.y(),
              frame_before.width(), frame_before.height())
        self.gview2d.scale(view_scale, view_scale)
        layout.addWidget(self.gview2d)

        sub.show()

    def createSurfaceModel(self, parent):
        model = QStandardItemModel(0, 4, parent)
        model.setHeaderData(self.CURVATURE, Qt.Horizontal, "Curvature")
        model.setHeaderData(self.THICKNESS, Qt.Horizontal, "Thickness")
        model.setHeaderData(self.MATERIAL, Qt.Horizontal, "Material")
        model.setHeaderData(self.SEMIDIAM, Qt.Horizontal, "Semi-Diameter")
        return model

    def create_element_model(self, gscene):
        clut = rgbt.RGBTable(filename='gui/red_blue64.csv',
                             data_range=[10.0, 100.])
        ele_model = ele.ElementModel()
        ele_model.elements_from_sequence(self.seq_model)
        pen = QPen()
        pen.setCosmetic(True)
        for e in ele_model.elements:
            poly = e.shape()
            polygon = QPolygonF()
            for p in poly:
                polygon.append(QPointF(p[0], p[1]))
            gpoly = QGraphicsPolygonItem()
            gpoly.setPolygon(polygon)
            # set element color based on V-number
            gc = float(e.medium.glass_code())
            vnbr = round(100.0 * (gc - int(gc)), 3)
            ergb = clut.get_color(vnbr)
            gpoly.setBrush(QColor(*ergb))
            gpoly.setPen(pen)

            t = e.tfrm[1]
            gpoly.setPos(QPointF(t[2], -t[1]))
            gscene.addItem(gpoly)

    def create_ray_model(self, gscene, start_surf=1):
        tfrms = self.seq_model.compute_global_coords(start_surf)
        rayset = self.seq_model.trace_boundary_rays()

        start_offset = 0.1 * gscene.sceneRect().width()
        if abs(tfrms[0][1][2]) > start_offset:
            tfrms[0] = self.seq_model.shift_start_of_rayset(
                rayset, start_offset)

        pen = QPen()
        pen.setCosmetic(True)
        for rays in rayset:
            poly1 = []
            for i, r in enumerate(rays[3][0][0:]):
                rot, trns = tfrms[i]
                p = rot.dot(r[0]) + trns
                #                print(i, r[0], rot, trns, p)
                poly1.append(QPointF(p[2], -p[1]))

            poly2 = []
            for i, r in enumerate(rays[4][0][0:]):
                rot, trns = tfrms[i]
                p = rot.dot(r[0]) + trns
                #                print(i, r[0], rot, trns, p)
                poly2.append(QPointF(p[2], -p[1]))

            poly2.reverse()
            poly1.extend(poly2)
            polygon = QPolygonF()
            for p in poly1:
                polygon.append(p)
            gpoly = QGraphicsPolygonItem()
            gpoly.setPolygon(polygon)
            gpoly.setBrush(QColor(254, 197, 254, 64))  # magenta, 25%
            gpoly.setPen(pen)
            gscene.addItem(gpoly)

    def addSurface(self, model, surf_gap):
        itemList = []
        for i in range(4):
            item = QStandardItem()
            item.setData(surf_gap[i], Qt.DisplayRole)
            itemList.append(item)
        model.appendRow(itemList)
Пример #26
0
class MainWindow(QMainWindow):
    lampset = pyqtSignal(int, str, object)
    master_change = pyqtSignal(int)
    faderset = pyqtSignal(int, int)

    freq = 1
    add_fac = 0.01

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setFont(QFont('Sans Serif', 12))
        self.setWindowTitle("Open-light-control")

        self.global_timer = QTimer(self)
        self.global_timer.timeout.connect(self.update_error_log)
        self.global_timer.start(500)

        if GlobalVar.serial_enable:
            self.serial_thread = SerialThread()
            self.serial_thread.keystroke.connect(self.map_keys)
            self.serial_thread.fadermove.connect(self.map_faders)
            self.serial_thread.encodermove.connect(self.map_encoders)
            self.faderset.connect(self.serial_thread.set_fader)
            self.serial_thread.start()

        self.abstract_thread = AbstractThread()
        self.lampset.connect(self.abstract_thread.set_lamp)
        self.lampset.connect(self.set_output)
        self.master_change.connect(self.abstract_thread.dmx_thread.set_master)
        self.abstract_thread.start()

        sortact = QAction('Sort', self)
        sortact.triggered.connect(self.sort)

        quitact = QAction('Quit', self)
        quitact.setShortcut('Ctrl+Q')
        quitact.triggered.connect(self.close)

        self.freezelabel = QLabel("Output freezed")
        # self.freezelabel.setDisabled(True)

        self.freezeact = QAction('Freeze Output', self)
        self.freezeact.setCheckable(True)
        self.freezeact.toggled.connect(self.toggle_freeze)
        self.freezeact.setShortcut('Ctrl+F')
        self.freezeact.toggle()

        self.menubar = self.menuBar()
        self.fileMenu = self.menubar.addMenu('File')
        self.fileMenu.addAction(quitact)
        self.toolsMenu = self.menubar.addMenu('Tools')
        self.toolsMenu.addAction(sortact)
        self.toolsMenu.addAction(self.freezeact)
        self.windowMenu = self.menubar.addMenu('Windows')

        self.menubar.setCornerWidget(self.freezelabel)

        self.statusbar = self.statusBar()  # .showMessage('Ready')
        self.statusbarhistory = QLabel()
        self.statusbarhistory.setMinimumWidth(100)
        self.statuslinebar = QLineEdit()
        self.statuslinebar.setMinimumWidth(100)
        self.statuslinebar.returnPressed.connect(self.exec_program_line)
        self.statusbar.layout().addWidget(self.statusbarhistory)
        self.statusbar.layout().addWidget(self.statuslinebar, Qt.AlignRight)
        #self.statusbar.addWidget(self.statuslinebar)
        #self.statusbar.setLayout(self.statusbar_layout)

        # self.cuelist_thread = CuelistThread()
        # self.cuelist_thread.lampset.connect(lambda x,y,z: self.lampset.emit(x, y, z))
        #self.cuelist_thread.go()
        #self.cuelist_thread.start()
        #self.cuelist_thread.quit()

        self.chase_timer = QTimer(self)
        self.chase_timer.timeout.connect(self.chase_send)

        self.mdi = QMdiArea()

        for cuelist in GlobalVar.cuelist_dict.keys():
            setattr(self, "{0:s}_cue_thread".format(cuelist), CuelistThread())
            getattr(self, "{0:s}_cue_thread".format(cuelist)).lampset.connect(
                self.lampset_relay)
            getattr(self, "{0:s}_cue_thread".format(cuelist)).set_cuelist(
                str(cuelist))

        ### Essential subwindows
        self.create_error_log()
        self.create_master_fader()
        self.create_output()

        ### Serial Monitors
        self.create_encoders()
        self.create_faders()
        self.create_keys()

        ### Extras
        self.create_chase_test()
        self.create_color()
        # self.create_color_bar()
        self.create_xy_pad()
        self.create_pb_stueck()
        # self.create_pp_stueck()

        ### Show all
        self.master_slid_sub.show()
        self.output_sub.show()
        self.stueck_sub.show()
        # self.stock_sub.show()
        self.color_sub.show()
        # self.color1_sub.show()

        self.setCentralWidget(self.mdi)
        #pdb.set_trace()
        # self.change_led()

    ### Essential Functions
    def closeEvent(self, event):
        close = QMessageBox.question(self, "QUIT",
                                     "Are you sure want to quit?",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)
        if close == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    @pyqtSlot(bool)
    def toggle_freeze(self, toggled):
        if toggled:
            self.freezelabel.setText("Output freezed")
            GlobalVar.output_freeze[0] = True
        else:
            self.freezelabel.setText("")
            GlobalVar.output_freeze[0] = False
            self.abstract_thread.send_artnet_all_sock_relay()

    def sort(self):
        self.mdi.tileSubWindows()

    @pyqtSlot()
    def update_error_log(self):
        self.error_text.setPlainText("\n".join(GlobalVar.error_log_global))
        self.error_text.verticalScrollBar().setValue(
            self.error_text.verticalScrollBar().maximum())

    # @pyqtSlot(str)
    def key_pressed(self, key, pressed=True):
        try:
            if pressed:
                if GlobalVar.key_mapping[key][0] == "pad":
                    if GlobalVar.key_mapping.get(key, ["", False])[3]:
                        self.statuslinebar.insert(
                            GlobalVar.key_mapping.get(key, [""])[2])
                    else:
                        if GlobalVar.key_mapping.get(key, [""])[2] == "Enter":
                            self.statuslinebar.returnPressed.emit()
                elif GlobalVar.key_mapping[key][0] == "cuelist":
                    if GlobalVar.key_mapping[key][2] == "go":
                        self.cuelist_go(
                            getattr(
                                self, "{0:s}_cue_thread)".format(
                                    GlobalVar.key_mapping[key][1])))
                elif GlobalVar.key_mapping[key][0] == "command":
                    getattr(self, GlobalVar.key_mapping[key][1])()
                else:
                    raise (KeyError)
        except:
            GlobalVar.error_log_global.append(
                "Key press failed: num {0:s}".format(key))

    def exec_program_line(self):
        text = self.statuslinebar.text()
        clear = False
        try:
            if "/" in text:
                nums = text.split("*")[0].split("c")[0]
                number = nums.split("/")
                numbers = "+".join([
                    str(x) for x in range(int(number[0]),
                                          int(number[1]) + 1)
                ])
                text = numbers + text[text.index(nums) + len(nums):]
        except:
            GlobalVar.error_log_global.append(
                "Programmer Error: unkown command")
        try:
            if "*" in text:
                try:
                    dims = text.split("*")[1]
                    if len(text.split("*")) == 3:
                        dim = 100
                    elif dims == "":
                        dim = 0
                        clear = True
                    elif dims == "0":
                        dim = int(dims)
                    else:
                        dim = int(dims)
                        if dim > 100:
                            raise ValueError
                except ValueError:
                    GlobalVar.error_log_global.append(
                        "Programmer Error: value out of range")
                    self.statuslinebar.clear()
                    return
                if text.split("*")[0] == "":
                    lamps = self.statusbarhistory.text()
                else:
                    lamps = text.split("*")[0]
                if "+" in lamps:
                    lamp = lamps.split("+")
                else:
                    lamp = [lamps]
                for i in lamp:
                    if clear:
                        try:
                            GlobalVar.in_use_programmer.pop(i)
                        except KeyError:
                            pass
                    else:
                        GlobalVar.in_use_programmer[i] = dim
                    self.lampset.emit(int(i), "Dimmer", dim)
            elif "c" in text:
                if "+" in text.split("c")[0]:
                    lamp = text.split("c")[0].split("+")
                else:
                    lamp = [text.split("c")[0]]
                value = text.split("c")[1]
                if "r" in value:
                    setting = "Red"
                    set_value = int(value.split("r")[1])
                elif "g" in value:
                    setting = "Green"
                    set_value = int(value.split("g")[1])
                elif "b" in value:
                    setting = "Blue"
                    set_value = int(value.split("b")[1])
                else:
                    setting = "Color"
                    set_value = value.replace("(", "").replace(")",
                                                               "").split(",")
                if setting == "Color":
                    for i in lamp:
                        try:
                            dim = GlobalVar.in_use_programmer[i]
                        except KeyError:
                            dim = 0
                        GlobalVar.in_use_programmer[i] = dim
                        self.lampset.emit(int(i), "Red", int(set_value[0]))
                        self.lampset.emit(int(i), "Green", int(set_value[1]))
                        self.lampset.emit(int(i), "Blue", int(set_value[2]))
                else:
                    for i in lamp:
                        try:
                            dim = GlobalVar.in_use_programmer[i]
                        except KeyError:
                            dim = 0
                        GlobalVar.in_use_programmer[i] = dim
                        self.lampset.emit(int(i), setting, set_value)
            else:
                GlobalVar.error_log_global.append(
                    "Programmer Error: unkown command")
        except:
            GlobalVar.error_log_global.append(
                "Programmer Error: unkown command")
        self.statusbarhistory.setText("+".join(
            GlobalVar.in_use_programmer.keys()))
        self.statuslinebar.clear()

    ## build / exec func
    def create_error_log(self):
        self.error_text = QTextEdit()
        self.error_text.setReadOnly(1)
        self.create_sub_area("error", "Error Log", [[self.error_text, 0, 0]])

    def create_output(self):
        self.output_layout = QGridLayout()
        self.output_layout.addWidget(QLabel("Num"), 0, 0)
        self.output_layout.addWidget(QLabel("Dimmer"), 0, 1)
        self.output_layout.addWidget(QLabel("Color"), 0, 2)
        # self.output_layout.addWidget(QLabel("Gobo"),0,3)
        # self.output_layout.addWidget(QLabel("Pan"),0,4)
        # self.output_layout.addWidget(QLabel("Tilt"),0,5)
        line = 1
        for num in list(GlobalVar.nr_to_typ.keys()):
            self.output_layout.addWidget(QLabel(str(num)), line, 0)
            if GlobalVar.typ_to_func[GlobalVar.nr_to_typ[num]]['Dimmer']:
                setattr(self, "output_{0:d}_Dimmer".format(num), QLabel('0'))
                self.output_layout.addWidget(
                    getattr(self, "output_{0:d}_Dimmer".format(num)), line, 1)
            if not GlobalVar.typ_to_func[
                    GlobalVar.nr_to_typ[num]]['Color'] == False:
                setattr(self, "output_{0:d}_Color".format(num),
                        QLabel('(0,0,0)'))
                self.output_layout.addWidget(
                    getattr(self, "output_{0:d}_Color".format(num)), line, 2)
            # if not GlobalVar.typ_to_func[GlobalVar.nr_to_typ[num]]['Gobo'] == False:
            #     setattr(self,"output_{0:d}_Gobo".format(num),QLabel('Open'))
            #     self.output_layout.addWidget(getattr(self,"output_{0:d}_Gobo".format(num)),line,3)
            # if not GlobalVar.typ_to_func[GlobalVar.nr_to_typ[num]]['Pan'] == False:
            #     setattr(self,"output_{0:d}_Pan".format(num),QLabel('Open'))
            #     self.output_layout.addWidget(getattr(self,"output_{0:d}_Pan".format(num)),line,4)
            # if not GlobalVar.typ_to_func[GlobalVar.nr_to_typ[num]]['Tilt'] == False:
            #     setattr(self,"output_{0:d}_Tilt".format(num),QLabel('Open'))
            #     self.output_layout.addWidget(getattr(self,"output_{0:d}_Tilt".format(num)),line,4)
            line += 1

        col_count = self.output_layout.columnCount()
        for col in range(col_count):
            self.output_layout.setColumnMinimumWidth(col, 70)
        self.output_layout.setColumnMinimumWidth(2, 100)

        self.output_widget = QWidget()
        self.output_widget.setLayout(self.output_layout)
        self.output_scroll = QScrollArea()
        self.output_scroll.setWidget(self.output_widget)
        self.output_sub = QMdiSubWindow()
        self.output_sub.setWidget(self.output_scroll)
        self.output_sub.setWindowTitle('Output')
        self.output_sub.setFont(QFont('Sans Serif', 10))
        self.mdi.addSubWindow(self.output_sub)

    @pyqtSlot(int, str, object)
    def set_output(self, num, setting, value):
        try:
            if any(setting == x for x in ["Red", "Green", "Blue"]):
                self.text = getattr(self,
                                    "output_{0:d}_Color".format(num)).text()
                text = self.text.replace("(", "")
                text = text.replace(")", "")
                text = text.split(",")
                if setting == "Red":
                    text[0] = str(round(value, 1))
                elif setting == "Green":
                    text[1] = str(round(value, 1))
                elif setting == "Blue":
                    text[2] = str(round(value, 1))
                getattr(
                    self,
                    "output_{0:d}_Color".format(num)).setText("(" +
                                                              ",".join(text) +
                                                              ")")
            else:
                getattr(self, "output_{0:d}_{1:s}".format(num,
                                                          setting)).setText(
                                                              str(value))
        except:
            pass

    def create_master_fader(self):
        master_list = []

        self.master_slid = QSlider()
        self.master_slid.setMinimum(0)
        self.master_slid.setMaximum(100)
        self.master_slid.setStyleSheet(GlobalVar.slider_stylesheet)
        self.master_slid_max_button = QPushButton("Max")
        self.master_slid_min_button = QPushButton("Min")
        self.master_slid_resend_button = QPushButton("Resend")
        self.master_slid.valueChanged.connect(self.master_slid_fader)
        self.master_slid_max_button.clicked.connect(self.set_master_max)
        self.master_slid_min_button.clicked.connect(self.set_master_min)
        self.master_slid_resend_button.clicked.connect(
            self.abstract_thread.send_artnet_all_sock_relay)
        width_edit = QLineEdit()
        width_edit.setPlaceholderText(str(self.master_slid.size().width()))
        height_edit = QLineEdit()
        height_edit.setPlaceholderText(str(self.master_slid.size().height()))
        width_edit.returnPressed.connect(lambda: self.master_slid.resize(
            QSize(int(width_edit.text()),
                  self.master_slid.size().height())))
        height_edit.returnPressed.connect(lambda: self.master_slid.resize(
            QSize(self.master_slid.size().width(), int(height_edit.text()))))
        master_list.append([self.master_slid, 0, 0, 2, 1])
        master_list.append([self.master_slid_max_button, 0, 1])
        master_list.append([self.master_slid_min_button, 1, 1])
        master_list.append([self.master_slid_resend_button, 0, 3])
        master_list.append([width_edit, 0, 2])
        master_list.append([height_edit, 1, 2])

        self.create_sub_area("master_slid", "Master", master_list)

    @pyqtSlot(int)
    def master_slid_fader(self, i):
        self.master_change.emit(i)

    def set_master_max(self):
        self.master_slid.setValue(self.master_slid.maximum())

    def set_master_min(self):
        self.master_slid.setValue(self.master_slid.minimum())

    ### Serial Monitor Functions
    def create_keys(self):
        keys_list = []
        for row in range(GlobalVar.rows):
            for col in range(GlobalVar.cols):
                num = (row * GlobalVar.cols) + col
                setattr(
                    self, "key" + str(num),
                    QPushButton(
                        GlobalVar.key_mapping.get(str(num), ["", "None"])[1]))
                # getattr(self,"keys"+str(num)).setCheckable(True)
                getattr(self, "key" + str(num)).setSizePolicy(
                    QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)
                getattr(self, "key" + str(num)).pressed.connect(
                    partial(self.key_pressed, str(num)))
                keys_list.append([getattr(self, "key" + str(num)), row, col])
        self.create_sub_area("keys", "Buttons", keys_list, width=85)

    def create_faders(self):
        faders_list = []
        for fader in range(GlobalVar.faders):
            setattr(self, "fader" + str(fader), QLabel())
            getattr(self, "fader" + str(fader)).setAlignment(Qt.AlignCenter)
            getattr(self, "fader" + str(fader)).setText('0')
            faders_list.append([getattr(self, "fader" + str(fader)), 0, fader])
        self.create_sub_area("faders", "Faders", faders_list, width=50)

    def create_encoders(self):
        encoder_list = []
        for encoder in range(GlobalVar.encoders):
            setattr(self, "encoder" + str(encoder), QLabel())
            getattr(self,
                    "encoder" + str(encoder)).setAlignment(Qt.AlignCenter)
            getattr(self, "encoder" + str(encoder)).setText('0')
            encoder_list.append(
                [getattr(self, "encoder" + str(encoder)), 0, encoder])
        self.create_sub_area("encoders", "Encoders", encoder_list, width=30)

    @pyqtSlot(str, bool)
    def map_keys(self, key, pressed):
        try:
            self.key_pressed(key, pressed)
        except NameError:
            print("button {0:s} not found!".format(key))

    @pyqtSlot(str, int)
    def map_faders(self, fader, value):
        try:
            fader_to_set = GlobalVar.fader_mapping[fader] + "_slid"
            getattr(self, fader_to_set).setValue(
                (value / 1023) * getattr(self, fader_to_set).maximum())
        except KeyError:
            pass

    @pyqtSlot(str, int)
    def map_encoders(self, encoder, value):
        try:
            cur = int(getattr(self, "encoder" + encoder).text())
            getattr(self, "encoder" + encoder).setText(str(cur - value))
        except NameError:
            print("encoder {0:s} not found!".format(encoder))

    ### Extra Functions
    def create_xy_pad(self):
        self.xy_pad = XY_Pad()
        self.xy_pad.position_changed.connect(self.xy_pad_sola_map)

        self.create_sub_area("xy_pad", "XY Pad", [[self.xy_pad, 0, 0]])

    def create_chase_test(self):
        chase_list = []

        self.chase_edit = QLineEdit()
        self.chase_edit.returnPressed.connect(self.chase_update)
        chase_list.append([self.chase_edit, 0, 0])
        self.chase_abs_edit = QLineEdit()
        self.chase_abs_edit.returnPressed.connect(self.chase_abs_update)
        chase_list.append([self.chase_abs_edit, 1, 0])

        self.chase_start = QPushButton("Start")
        self.chase_start.clicked.connect(lambda: self.chase_timer.start(10))
        chase_list.append([self.chase_start, 0, 1])
        self.chase_stop = QPushButton("Stop")
        self.chase_stop.clicked.connect(lambda: self.chase_timer.stop())
        chase_list.append([self.chase_stop, 1, 1])

        self.create_fader("led_ma", "LED Master", chase_list, 0, 2)

        self.create_sub_area("chase_test", "LED Chase", chase_list, width=70)

    @pyqtSlot(int)
    def led_ma_slid_fader(self, sli):
        for i in range(110, 116):
            self.lampset.emit(i, 'Dimmer', sli)

    @pyqtSlot(float, float)
    def xy_pad_sola_map(self, x, y):
        self.lampset.emit(100, "Pan", x * 100)
        self.lampset.emit(100, "Tilt", y * 100)

    def chase_update(self):
        temp_freq = float(self.chase_edit.text())
        self.freq = temp_freq

    def chase_abs_update(self):
        self.add_fac = float(self.chase_abs_edit.text())

    def chase_send(self):
        for i in [110, 111, 113, 115, 114, 112]:
            #i = 100
            #if True:
            color_tup = colorsys.hsv_to_rgb(
                abs(
                    math.sin(self.freq * time.time() +
                             (self.add_fac * (i - 110)))), 1, 1)  # 0))),1,1)
            self.lampset.emit(i, "Red", color_tup[0] * 255)
            self.lampset.emit(i, "Blue", color_tup[1] * 255)
            self.lampset.emit(i, "Green", color_tup[2] * 255)

    def create_color(self):
        self.color_dia0 = NewColorDialog(parent=self)
        # self.color_dia0.setOption(2)
        self.color_dia0.currentColorChanged.connect(self.test_colors)

        self.create_sub_area("color", "Color Changer LED",
                             [[self.color_dia0, 0, 0]])

    def create_color_bar(self):
        self.color_dia1 = ColorDialog(parent=self)
        # self.color_dia0.setOption(2)
        self.color_dia1.currentColorChanged.connect(self.test_colors1)

        self.create_sub_area("color1", "Color Changer Bar",
                             [[self.color_dia1, 0, 0]])

    @pyqtSlot(QColor)
    def test_colors(self, col):
        for i in range(110, 116):  # 110,116
            #i=100
            #if True:
            self.lampset.emit(i, 'Red', col.red())
            self.lampset.emit(i, 'Green', col.green())
            self.lampset.emit(i, 'Blue', col.blue())

    @pyqtSlot(QColor)
    def test_colors1(self, col):
        for i in range(20, 22):
            #i=100
            #if True:
            self.lampset.emit(i, 'Red', col.red())
            self.lampset.emit(i, 'Green', col.green())
            self.lampset.emit(i, 'Blue', col.blue())

    def faders_next_com(self):
        if GlobalVar.curr_page + 1 < len(GlobalVar.fader_map):
            next_page = GlobalVar.curr_page + 1
        else:
            next_page = 0
        for i in range(GlobalVar.faders):
            GlobalVar.fader_map[GlobalVar.curr_page][i] = getattr(
                self, "fader_{0:d}_ma_slid".format(i)).value()
            getattr(self, "fader_{0:d}_ma_slid".format(i)).setValue(
                GlobalVar.fader_map[next_page][i])
            self.faderset.emit(i, GlobalVar.fader_map[next_page][i])
            GlobalVar.curr_page = next_page

    def create_pb_stueck(self):
        stueck_list = []

        self.create_fader("pub", "Pub", stueck_list, 0, 0)
        self.create_fader("back", "Backlight", stueck_list, 0, 1)
        self.create_fader("grund", "Grundlicht", stueck_list, 0, 2)
        self.create_fader("spot", "Spot", stueck_list, 0, 3)

        self.create_sub_area("stueck", "PB Stück", stueck_list, width=70)

    @pyqtSlot(int)
    def pub_slid_fader(self, i):
        self.lampset.emit(10, "Dimmer", i)
        self.lampset.emit(19, "Dimmer", i)
        self.lampset.emit(7, "Dimmer", i)

    @pyqtSlot(int)
    def back_slid_fader(self, i):
        self.lampset.emit(44, "Dimmer", i)

    @pyqtSlot(int)
    def grund_slid_fader(self, i):
        self.lampset.emit(22, "Dimmer", i)
        self.lampset.emit(21, "Dimmer", i)
        self.lampset.emit(17, "Dimmer", i)
        self.lampset.emit(14, "Dimmer", i)

    @pyqtSlot(int)
    def spot_slid_fader(self, i):
        self.lampset.emit(18, "Dimmer", i)

    def create_pp_stueck(self):
        stock_list = []

        self.create_fader("L", "L", stock_list, 0, 0)
        self.create_fader("R", "R", stock_list, 0, 1)
        self.create_fader("led_d", "LED Dim", stock_list, 0, 2)
        self.create_fader("bar_d", "Bar Dim R", stock_list, 0, 3)

        self.create_sub_area("stock", "PP Stück", stock_list, width=70)

    @pyqtSlot(int)
    def L_slid_fader(self, i):
        self.lampset.emit(1, "Dimmer", i)

    @pyqtSlot(int)
    def R_slid_fader(self, i):
        self.lampset.emit(2, "Dimmer", i)

    @pyqtSlot(int)
    def led_d_slid_fader(self, i):
        self.lampset.emit(10, "Dimmer", i)

    @pyqtSlot(int)
    def bar_d_slid_fader(self, i):
        self.lampset.emit(20, "Dimmer", i)
        self.lampset.emit(21, "Dimmer", i)

    def create_sub_area(self, name, title, wid_list, width=None):
        setattr(self, name + "_layout", QGridLayout())
        for wid in wid_list:
            if len(wid) == 3:
                wid.append(1)
                wid.append(1)
            getattr(self, name + "_layout").addWidget(wid[0], wid[1], wid[2],
                                                      wid[3], wid[4])
        if width:
            self.col_count = getattr(self, name + "_layout").columnCount()
            for col in range(self.col_count):
                getattr(self,
                        name + "_layout").setColumnMinimumWidth(col, width)
        setattr(self, name + "_widget", QWidget())
        getattr(self,
                name + "_widget").setLayout(getattr(self, name + "_layout"))
        setattr(self, name + "_sub", QMdiSubWindow())
        getattr(self, name + "_sub").setWidget(getattr(self, name + "_widget"))
        getattr(self, name + "_sub").setWindowTitle(title)
        self.mdi.addSubWindow(getattr(self, name + "_sub"))
        getattr(self, name + "_sub").hide()
        setattr(self, name + "act", QAction(title, self))
        getattr(self, name + "act").triggered.connect(
            lambda: getattr(self, name + "_sub").show())
        self.windowMenu.addAction(getattr(self, name + "act"))

        # setattr(self,name+"_scroll",QScrollArea())
        # getattr(self,name+"_scroll").setWidget(getattr(self,name+"_widget"))

    def create_fader(self, name, label, liste, start, start1, fad_max=100):
        setattr(self, name + "_slid", QSlider())
        getattr(self, name + "_slid").setMinimumHeight(200)
        getattr(self,
                name + "_slid").setStyleSheet(GlobalVar.slider_stylesheet)
        getattr(self, name + "_slid").setMinimum(0)
        getattr(self, name + "_slid").setMaximum(fad_max)
        getattr(self, name + "_slid").valueChanged.connect(
            getattr(self, name + "_slid_fader"))
        liste.append([QLabel(label), start, start1])
        liste.append([getattr(self, name + "_slid"), start + 1, start1])

    @pyqtSlot(int, str, object)
    def lampset_relay(self, x, y, z):
        self.lampset.emit(x, y, z)

    def cuelist_go(self, cuelist):
        if cuelist.isRunning():
            cuelist.go()
        else:
            cuelist.start()

    def unset_pub(self):
        if GlobalVar.fader_mapping["2"] == "pub":
            GlobalVar.fader_mapping["2"] = "spot"
        else:
            GlobalVar.fader_mapping["2"] = "pub"

    def change_led(self):
        self.lampset.emit(10, "Red", 255)
        self.lampset.emit(10, "Green", 191)
        self.lampset.emit(10, "Blue", 62)
        self.lampset.emit(11, "Red", 255)
        self.lampset.emit(20, "Red", 255)
        self.lampset.emit(20, "Green", 147)
        self.lampset.emit(20, "Blue", 52)
        self.lampset.emit(21, "Red", 255)
        self.lampset.emit(21, "Green", 147)
        self.lampset.emit(21, "Blue", 52)
Пример #27
0
class List_Mode_Viewer(QMainWindow):
    sync=False
    lis=False
    calibration=False
    def __init__(self):
        super().__init__()
        self.setWindowTitle('List Mode Viewer')
        self.font=QFont()
        self.font.setPointSize(12)
        self.size_policy=QSizePolicy.Expanding
        self.menu()
        self.geometry()
        self.showMaximized()
#        self.popup()
        self.show()
        
    def menu(self):
        self.menuFile=self.menuBar().addMenu('&File')
        self.load_new=QAction('&Load New Data')
        self.load_new.triggered.connect(self.loading)
        self.load_new.setShortcut('CTRL+N')
        self.save_file=QAction('&Save Spectrum')
        self.save_file.triggered.connect(self.save_spectrum)
        self.save_file.setShortcut('CTRL+S')
        self.save_file.setEnabled(False)
        self.save_roi=QAction('&Save ROI')
        self.save_roi.triggered.connect(self.save_roi_csv)
        self.save_roi.setEnabled(False)
        
        self.menuView=self.menuBar().addMenu('&View')
        self.view_pop=QAction('&Show Tools')
        self.view_pop.triggered.connect(self.popup_)
        self.view_pop.setShortcut('CTRL+U')
        self.view_pop.setEnabled(False)
        
        self.view_all=QAction('&Show Plots')
        self.view_all.triggered.connect(self.initiate)
        self.view_all.setShortcut('CTRL+V')
        
        self.view_variation=QAction('&Pulse Deviation')
        self.view_variation.triggered.connect(self.deviation)
        
        self.view_roi_arrive=QAction('&ROI Arrival Times')
        self.view_roi_arrive.triggered.connect(self.ROI_Arrivals)
        
        self.menuView.addActions([self.view_pop,self.view_all,self.view_variation,
                                  self.view_roi_arrive])
        self.menuFile.addActions([self.load_new,self.save_file,self.save_roi])
        
    def geometry(self):        
#        self.central_widget=QWidget()
        self.region1_plot=QWidget()
        self.region1_figure=Figure()
        self.region1_canvas=FigureCanvas(self.region1_figure)
        self.region1_toolbar=NavigationToolbar(self.region1_canvas,self)
        layout=QVBoxLayout()
        layout.addWidget(self.region1_toolbar)
        layout.addWidget(self.region1_canvas)
        self.region1_plot.setLayout(layout)
        self.region1_ax=self.region1_canvas.figure.subplots()
        
        self.region2_plot=QWidget()
        self.region2_figure=Figure()
        self.region2_canvas=FigureCanvas(self.region2_figure)
        self.region2_toolbar=NavigationToolbar(self.region2_canvas,self)
        layout=QVBoxLayout()
        layout.addWidget(self.region2_toolbar)
        layout.addWidget(self.region2_canvas)
        self.region2_plot.setLayout(layout)
        self.region2_ax=self.region2_canvas.figure.subplots()
        self.region2_ax.set_title('Region 2')
        
        self.total_plot=QWidget()
        self.total_figure=Figure()
        self.total_canvas=FigureCanvas(self.total_figure)
        self.total_toolbar=NavigationToolbar(self.total_canvas,self)
        layout=QVBoxLayout()
        layout.addWidget(self.total_toolbar)
        layout.addWidget(self.total_canvas)
        self.total_plot.setLayout(layout)
        self.total_ax=self.total_canvas.figure.subplots()
        self.total_ax.set_title('Total')
        
        self.time_plot=QWidget()
        self.time_figure=Figure()
        self.time_canvas=FigureCanvas(self.time_figure)
        self.time_toolbar=NavigationToolbar(self.time_canvas,self)
        layout=QVBoxLayout()
        layout.addWidget(self.time_toolbar)
        layout.addWidget(self.time_canvas)
        self.time_plot.setLayout(layout)
        self.time_ax=self.time_canvas.figure.subplots()
        self.time_ax.set_title('Time')
        self.setup()
        
    def setup(self):
        sub1=QMdiSubWindow()
        sub1.setWidget(self.region1_plot)
        sub1.setWindowTitle('Region 1 Plot')
        
        sub2=QMdiSubWindow()
        sub2.setWidget(self.region2_plot)
        sub2.setWindowTitle('Region 2 Plot')
        
        sub3=QMdiSubWindow()
        sub3.setWidget(self.total_plot)
        sub3.setWindowTitle('Total Plot')
        
        sub4=QMdiSubWindow()
        sub4.setWidget(self.time_plot)
        sub4.setWindowTitle('Time Plot')
        
        self.mdi=QMdiArea()
        self.mdi.addSubWindow(sub1)
        self.mdi.addSubWindow(sub2)
        self.mdi.addSubWindow(sub3)
        self.mdi.addSubWindow(sub4)
        
        self.mdi.tileSubWindows()
        self.setCentralWidget(self.mdi)
        
    def loading(self):
        self.loader=QWidget()
        self.loader.setWindowFlags(Qt.WindowStaysOnTopHint)
        self.sync_label=QLabel('Sync Pulse Location: ')
        self.sync_label.setSizePolicy(self.size_policy,self.size_policy)
        self.sync_label.setFont(self.font)
        
        self.sync_location=QPushButton('Browse')
        self.sync_location.setSizePolicy(self.size_policy,self.size_policy)
        self.sync_location.setFont(self.font)
        self.sync_location.clicked.connect(self.sync_browse)
        
        self.detector_label=QLabel('Detector List Mode Data: ')
        self.detector_label.setSizePolicy(self.size_policy,self.size_policy)
        self.detector_label.setFont(self.font)
        
        self.detector_location=QPushButton('Browse')
        self.detector_location.setSizePolicy(self.size_policy,self.size_policy)
        self.detector_location.setFont(self.font)
        self.detector_location.clicked.connect(self.detector_browse)
        
        self.calibration_label=QLabel('Calibration:(Optional)')
        self.calibration_label.setSizePolicy(self.size_policy,self.size_policy)
        self.calibration_label.setFont(self.font)
        
        self.calibration_location=QPushButton('Browse')
        self.calibration_location.setSizePolicy(self.size_policy,
                                                self.size_policy)
        self.calibration_location.setFont(self.font)
        self.calibration_location.clicked.connect(self.calibration_browse)
        
        self.process_new=QPushButton('Process')
        self.process_new.setSizePolicy(self.size_policy,self.size_policy)
        self.process_new.setFont(self.font)
        self.process_new.clicked.connect(self.processing_new)
        self.process_new.setEnabled(False)
        
        layout=QGridLayout()
        layout.addWidget(self.sync_label,0,0)
        layout.addWidget(self.sync_location,0,1)
        layout.addWidget(self.detector_label,1,0)
        layout.addWidget(self.detector_location,1,1)
        layout.addWidget(self.calibration_label,2,0)
        layout.addWidget(self.calibration_location,2,1)
        layout.addWidget(self.process_new,3,0,1,2)
        self.loader.setLayout(layout)
        self.loader.setWindowTitle('Load New List Mode')
        self.loader.show()
        
    def sync_browse(self):
        self.sync_filename=QFileDialog.getOpenFileName(self,
                           'Sync File Location',"",
                           'Comma Seperated File (*.csv);;Text File (*.txt)')
        if self.sync_filename[0]!="":
            self.sync=True
            self.sync_location.setStyleSheet("background-color: green")
            if self.lis==True:
                self.process_new.setEnabled(True)
    def detector_browse(self):
        self.list_filename=QFileDialog.getOpenFileName(self,
                           'Listmode File Location',"",
                           'Comma Seperated File (*.csv);;Text File (*.txt)')
        if self.list_filename[0]!="":
            self.lis=True
            self.detector_location.setStyleSheet("background-color: green")
            if self.sync==True:
                self.process_new.setEnabled(True)
    def calibration_browse(self):
        self.calib_filename=QFileDialog.getOpenFileName(self,
                           'calibration File Location',"",
                           'Text File (*.txt);;Comma Seperated File (*.csv)')
        if self.calib_filename[0]!='':
            self.calibration=True
            f=open(self.calib_filename[0],'r')
            data=f.readlines()
            f.close()
            self.calibration_data=[]
            for i in range(len(data)):
                self.calibration_data.append(float(data[i]))
            del data
            del f
    def processing_new(self):
        try:
            self.loader.close()
        except:
            True
        self.setWindowTitle(self.list_filename[0])
        self.save_file.setEnabled(True)
        self.save_roi.setEnabled(True)
        self.popup_()
        self.list_mode_processor=List_Mode()
        s=time.time()
        self.sync_time,sync_channel=Conversion.convert(self.sync_filename[0])
        del sync_channel
        self.list_time,self.list_channel=Conversion.convert(self.list_filename[0])
        
        print('Imported and conveted in {:.2f}s'.format(time.time()-s))
        winsound.MessageBeep()
        delt=(self.sync_time[2]-self.sync_time[1])
        #set the maximum value for the end time and start times
        maxe=int((self.list_time[-1]-self.list_time[0])*1e-6)
        self.end_time.setMaximum(maxe)
        self.end_time.setValue(maxe)
        self.start_time.setMaximum(maxe-1)
        self.start_time.setValue(0)
        self.offset.setMaximum(int(delt-self.duty_cycle.value()/100*delt))
        self.offset.setMinimum(int(-(delt*self.duty_cycle.value()/100)*.5))
        self.view_pop.setEnabled(True)
        self.updater()
        
    def popup_(self):
        self.popup=QWidget()
        self.popup.setWindowTitle('View Controls')
        self.popup.setSizePolicy(self.size_policy,self.size_policy)
        self.popup.setFont(self.font)
        
        start_label=QLabel('Start Time: s')
        start_label.setSizePolicy(self.size_policy, self.size_policy)
        start_label.setFont(self.font)
        self.s_label=start_label
        
        self.start_time=QSlider(Qt.Horizontal)
        self.start_time.setSizePolicy(self.size_policy,self.size_policy)
        self.start_time.setFont(self.font)
        self.start_time.setMinimum(0)
        self.start_time.setMaximum(100)
        self.start_time.setSingleStep(1)
        self.start_time.setValue(10)
        self.start_time.setTickInterval(100)
        self.start_time.setTickPosition(QSlider.TicksBelow)
        self.start_time.valueChanged.connect(self.start_updated)
        
        end_label=QLabel('End Time: s')
        end_label.setSizePolicy(self.size_policy, self.size_policy)
        end_label.setFont(self.font)
        self.e_label=end_label
        
        self.end_time=QSlider(Qt.Horizontal)
        self.end_time.setSizePolicy(self.size_policy,self.size_policy)
        self.end_time.setFont(self.font)
        self.end_time.setMinimum(1)
        self.end_time.setMaximum(100)
        self.end_time.setSingleStep(1)
        self.end_time.setValue(10)
        self.end_time.setTickInterval(100)
        self.end_time.setTickPosition(QSlider.TicksBelow)
        self.end_time.valueChanged.connect(self.end_updated)
        
        self.duty_label=QLabel('Duty Cycle [%]: ')
        self.duty_label.setSizePolicy(self.size_policy,self.size_policy)
        self.duty_label.setFont(self.font)
        
        self.duty_cycle=QSlider(Qt.Horizontal)
        self.duty_cycle.setSizePolicy(self.size_policy,self.size_policy)
        self.duty_cycle.setFont(self.font)
        self.duty_cycle.setMinimum(0)
        self.duty_cycle.setMaximum(100)
        self.duty_cycle.setSingleStep(1)
        self.duty_cycle.setValue(10)
        self.duty_cycle.setTickPosition(QSlider.TicksBelow)
        self.duty_cycle.valueChanged.connect(self.duty_changed)
        
        self.offset_label=QLabel('Offset from sync [us]: ')
        self.offset_label.setSizePolicy(self.size_policy,self.size_policy)
        self.offset_label.setFont(self.font)
        
        self.offset=QSlider(Qt.Horizontal)
        self.offset.setSizePolicy(self.size_policy,self.size_policy)
        self.offset.setFont(self.font)
        self.offset.setMinimum(0)
        self.offset.setMaximum(1000)
        self.offset.setSingleStep(1)
        self.offset.setValue(10)
        self.offset.setTickPosition(QSlider.TicksBelow)
        self.offset.setTickInterval(100)
        self.offset.setToolTip(
            'After end of pulse to divide into Region 1 and 2 in micro seconds')
        self.offset.valueChanged.connect(self.offset_changed)
        
        self.update=QPushButton('Update')
        self.update.setSizePolicy(self.size_policy,self.size_policy)
        self.update.setFont(self.font)
        self.update.clicked.connect(self.updater)
        
        layout=QGridLayout()
        layout.addWidget(start_label,0,0)
        layout.addWidget(self.start_time,0,1)
        layout.addWidget(end_label, 1, 0)
        layout.addWidget(self.end_time,1,1)
        layout.addWidget(self.duty_label,2,0)
        layout.addWidget(self.duty_cycle,2,1)
        layout.addWidget(self.offset_label,3,0)
        layout.addWidget(self.offset,3,1)
        layout.addWidget(self.update,4,0)
        
        self.popup.setLayout(layout)
        self.duty_changed()
        self.offset_changed()
        self.popup.show()
        
    def start_updated(self):
        time=self.start_time.value()
        self.s_label.setText('Start Time: {:.2f}s'.format(time))
        self.end_time.setMinimum(time+1)

    def end_updated(self):
        time=self.end_time.value()
        self.e_label.setText('End Time: {:.2f}s'.format(time))
        
    def duty_changed(self):
        self.duty_label.setText('Duty Cycle: {:.2f}%'.format(
            self.duty_cycle.value()))
        
    def offset_changed(self):
        self.offset_label.setText('Offset from sync: {:.1f} us'.format(
            self.offset.value()))
        
    def updater(self):
        delta_time=self.duty_cycle.value()/100*(
                self.sync_time[2]-self.sync_time[1])
        delt=(self.sync_time[2]-self.sync_time[1])
        self.offset.setMinimum(-int((delt*self.duty_cycle.value()/100)*.75))
        sync_width=delta_time
        delta_time+=self.offset.value()
        self.delta_time=delta_time
        start=float(self.start_time.value())*1e6
        end=float(self.end_time.value())*1e6
        sb,se=Timing.Splitter(self.sync_time,len(self.sync_time),
                                            start,end)
        cb,ce=Timing.Splitter(self.list_time,len(self.list_time),
                                            start,end)
        self.region1_spec,self.region2_spec,self.time=self.list_mode_processor.timing(
                                        delta_time,self.sync_time[sb:se],
                                        self.list_time[cb:ce],self.list_channel[cb:ce])
        total=[]
        for i in range(len(list(self.region2_spec.values()))):
            total.append(list(self.region2_spec.values())[i]+list(
                    self.region1_spec.values())[i])
        self.region1_ax.clear()
        self.region2_ax.clear()
        self.total_ax.clear()
        self.region1_ax.set_title('Region 1')
        self.region2_ax.set_title('Region 2')
        self.total_ax.set_title('Total')
        r1_values=list(self.region1_spec.values())[:-1]
        r2_values=list(self.region2_spec.values())[:-1]
        uncal_keys=list(self.region1_spec.keys())
        if self.calibration:
            self.region1_ax.set_xlim(self.calibration_data[0],
                                     14)
            self.region2_ax.set_xlim(self.calibration_data[0],
                                     14)
            self.total_ax.set_xlim(self.calibration_data[0],14)
            self.region1_ax.set_xlabel('Energy [MeV]')
            self.region2_ax.set_xlabel('Energy [MeV]')
            self.total_ax.set_xlabel('Energy [MeV]')
            self.region1_ax.plot(self.calibration_data,r1_values)
            self.region2_ax.plot(self.calibration_data,r2_values)
            self.total_ax.plot(self.calibration_data,total[:-1],label='Total')
            self.total_ax.plot(self.calibration_data,r1_values,label='Region 1')
            self.total_ax.plot(self.calibration_data,r2_values,label='Region 2')
        else:
            self.region1_ax.set_xlabel('Channel')
            self.region2_ax.set_xlabel('Channel')
            self.total_ax.set_xlabel('Channel')
            self.region1_ax.set_xlim(0,len(list(self.region1_spec.keys())))
            self.region2_ax.set_xlim(0,len(list(self.region2_spec.keys())))
            self.total_ax.set_xlim(0,len(list(self.region2_spec.keys())))
            self.region1_ax.plot(uncal_keys[:-1],r1_values)
            self.region2_ax.plot(uncal_keys[:-1],r2_values)
            self.total_ax.plot(uncal_keys[:-1],total[:-1],label='Total')
            self.total_ax.plot(uncal_keys[:-1],r1_values,label='Region 1')
            self.total_ax.plot(uncal_keys[:-1],r2_values,label='Region 2')
        self.region1_ax.set_yscale('log')
        self.region2_ax.set_yscale('log')
        self.total_ax.set_yscale('log')
        self.region1_ax.set_ylabel('Counts')
        self.region2_ax.set_ylabel('Counts')
        self.total_ax.set_ylabel('Counts')
        self.total_ax.legend()
        self.region1_canvas.draw()
        self.region2_canvas.draw()
        self.total_canvas.draw()
        
        #plot the timing stuff
        self.time_ax.clear()
        self.time_ax.plot(self.time[1][:-1],
                          self.time[0][:-1],'*',label='Time Distribution')
        height=max(self.time[0])
        ys=[0,height,height,0]
        xs=[0,0,sync_width,sync_width]
        self.time_ax.plot(xs,ys,
                  label='Sync Pulse, {:.1f}%'.format(self.duty_cycle.value()))
        self.time_ax.axvline(delta_time,
             label='Region divider, {:.1f}us\nafter pulse'.format(delta_time))
        self.time_ax.set_xlabel(r'Time [$\mu$s]')
        self.time_ax.set_title('Time')
        self.time_ax.set_ylabel('Counts')
        self.time_ax.set_yscale('log')
        self.time_ax.legend()
        self.time_canvas.draw()
        winsound.MessageBeep()
        
    def save_spectrum(self):
        items=['Region 1','Region 2','Time Decay']
        # self.updater()
        text,ok=QInputDialog.getItem(self,'Save Spectrum','Saving:',
                                     items,0,False)
        if ok and text:
            name=QFileDialog.getSaveFileName(self,'File Name','',
                             'Text File (*.txt);;Comma Seperated File (*.csv)')
            try:
                f=open(name[0],'w')
                if text==items[0] and name[0]!=" ":
                    counts=list(self.region1_spec.values())
                    bins=list(self.region1_spec.keys())
                    for i in range(len(bins)-1):
                        f.write('{}\n'.format(counts[i]))
                if text==items[1] and name[0]!='':
                    counts=list(self.region2_spec.values())
                    bins=list(self.region2_spec.keys())
                    for i in range(len(bins)-1):
                        f.write('{}\n'.format(counts[i]))
                if text==items[2] and name[0]!='':
                    times=self.time[1][:-1]
                    counts=self.time[0][:-1]
                    f.write('Time[us],counts\n')
                    for i in range(len(counts)):
                        f.write('{:.9f},{}\n'.format(times[i],counts[i]))
                    
                f.close()
            except:
                pass
    
    def initiate(self):
        self.geometry()
        self.updater()
        
    def deviation(self):
        Arrival_Spread(self.sync_filename[0]).process()
        
    def ROI_Arrivals(self):
        #check to see if a calibration file exists, if not make them get one
        if not self.calibration:
            self.calibration_browse()
        list_time=np.asarray(self.list_time)
        list_channel=np.asarray(self.list_channel)
        sync_time=np.asarray(self.sync_time)
        calibration=np.asarray(self.calibration_data)
        self.view=ROI_Viewer(list_time,list_channel,sync_time,calibration)
        self.view.processer.clicked.connect(self.roi_arrive)
        
    def roi_arrive(self):
#        while self.view.done!=True:
#            False
        self.time_ax.plot(self.view.bins,self.view.output,'*',
         label='ROI of {}MeV-{}MeV'.format(self.view.lower,self.view.upper))
        self.time_ax.legend()
        self.time_canvas.draw()
        
    def ROI_Spectrum_Saving(self):
        '''Saving the roi pulses and their respective timing to later perform
        an integration to find the MDM'''
        if not self.calibration:
            self.calibration_browse()
        list_time=np.asarray(self.list_time)
        list_channel=np.asarray(self.list_channel)
        calibration=np.asarray(self.calibration_data)
        sync_time=np.asarray(self.sync_time)
        lower,ok=QInputDialog.getDouble(self, 'Lower ROI', 'Lower Bound (MeV)',9.6,0,14,4)
        upper,ok2=QInputDialog.getDouble(self, 'Upper ROI', 'Upper Bound (MeV)',10.9,0,14,4)
        if ok and ok2:
    #     #outputs the pulses and associated times to save and integrate to
    #     #calculate the detection probability at integrated time windows
            s=time.time()
            print('Begin processing data')
            pulses,times=Timing.ROI_Timing(sync_time,int(len(sync_time)),
                                           list_time,list_channel, 
                                           self.delta_time,8192,
                                           calibration,upper,lower)
            print('Done processing in {:.2f}s'.format(time.time()-s))
        return pulses,times
    
    def save_roi_csv(self):
        name,ok=QFileDialog.getSaveFileName(self,'Safe File Name','',
                              'Comma Seperated File (*.csv)')
        if ok:
            f=open(name,'w')
            f.write('Pulse_Height(MeV),Time(s)\n')
            pulse,time=self.ROI_Spectrum_Saving()
            for i in range(len(pulse)):
                f.write('{:.3f},{:.3f}\n'.format(pulse[i],time[i]*1e-6))
            f.close()
            print('All finished')
Пример #28
0
class MDIWindow(QMainWindow):

    can_send_signal = pyqtSignal(object)

    PCAN_STATE_CONNECTED = 1
    PCAN_STATE_DISCONNECTED = 0

    def __init__(self):
        super().__init__()

        self.pcan_state = self.PCAN_STATE_DISCONNECTED
        self.can_row = 0
        self.can_data = {}
        self.dbc_windows = {}
        self.dbc_send_windows = {}
        self.config = configparser.ConfigParser()
        self.recentDBCFiles = {}

        self.loadPreferences()

        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)

        bar = self.menuBar()

        recentDBCMenu = QMenu('Recent DBCs...', self)

        file = bar.addMenu("File")
        file.addAction("Connect")
        file.addAction("Open DBC")
        file.triggered[QAction].connect(self.fileMenuClicked)
        file.addMenu(recentDBCMenu)

        for dbcFile in self.recentDBCFiles.keys():
            recentOpenAct = QAction(dbcFile, self)
            # var c is used to handle the triggered first arg
            recentOpenAct.triggered.connect(
                lambda c=dbcFile, f=dbcFile: self.loadDBCFile(
                    self.recentDBCFiles[f]))
            recentDBCMenu.addAction(recentOpenAct)

        view = bar.addMenu("View")
        view.addAction("Cascade")
        view.addAction("TiledC")
        view.triggered[QAction].connect(self.viewMenuClicked)

        self.setWindowTitle("WiCAN " + VERSION)
        self.statusBar().showMessage('Disconnected')

        self.createCANTableSubWindow()

        self.can_thread = CANThread()
        self.can_send_signal.connect(self.can_thread.send)
        self.can_thread.can_recv_signal.connect(self.handleCANMessage)
        self.can_thread.can_status_signal.connect(self.handleCANStatus)
        self.can_thread.start()

        timer = QTimer(self)
        timer.timeout.connect(self.tick)
        timer.start(50)

    def createCANTableSubWindow(self):
        self.can_table = QTableWidget(50, 9)

        sub = QMdiSubWindow()
        sub.setWidget(self.can_table)
        sub.setWindowTitle("Raw CAN Frames")
        self.mdi.addSubWindow(sub)
        sub.setGeometry(0, 0, 400, 800)

        self.can_table.verticalHeader().hide()
        self.can_table.setHorizontalHeaderItem(0, QTableWidgetItem("ID"))
        self.can_table.setColumnWidth(0, 10)
        for i in range(1, 9):
            item = QTableWidgetItem(str(i - 1))
            self.can_table.setHorizontalHeaderItem(i, item)
            self.can_table.setColumnWidth(i, 10)

        sub.show()

    def fileMenuClicked(self, menuitem):
        if menuitem.text() == "Connect":
            diag = ConnectDialog(self, self.last_connection)
            diag.show()
            diag.exec_()
            settings = diag.getSettings()
            self.CANConnect(settings)
        elif menuitem.text() == "Open DBC":
            self.loadDBCFileDialog()

    def viewMenuClicked(self, menuitem):
        if menuitem.text() == "Cascade":
            self.mdi.cascadeSubWindows()
        elif menuitem.text() == "Tiled":
            self.mdi.tileSubWindows()

    def loadPreferences(self):
        self.dbc_path = os.path.dirname(os.path.realpath(__file__))

        inifile = self.config.read('wican.ini')

        if len(inifile) == 0:
            self.config['WiCAN'] = {
                'CANAdaptor': 'PCAN',
                'CANBAUD': '250k',
                'CANPATH': ''
            }
            self.config['RecentDBCs'] = {}
            self.saveConfig()
            return

        can_adapter = self.config['WiCAN'].get('CANAdaptor', 'KVaser')
        can_baud = self.config['WiCAN'].get('CANBAUD', '250k')
        can_path = self.config['WiCAN'].get('CANPATH', '')

        self.last_connection = CANConnection(can_adapter, can_baud, can_path)

        for file, path in self.config.items("RecentDBCs"):
            if not os.path.exists(path):
                self.config.remove_option("RecentDBCs", file)
            else:
                self.recentDBCFiles[file] = path

    def saveConfig(self):
        with open('wican.ini', 'w') as configfile:
            self.config.write(configfile)
            configfile.close()

    def loadDBCFileDialog(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        types = "DBC Files (*.dbc)"
        file_path, _ = QFileDialog.getOpenFileName(self,
                                                   "Open DBC",
                                                   self.dbc_path,
                                                   types,
                                                   options=options)
        if file_path:
            self.loadDBCFile(file_path)

    def loadDBCFile(self, file_path):
        dbc_win = DBCRecvWindow(file_path, self)
        sub = QMdiSubWindow()
        sub.setWidget(dbc_win)
        sub.setGeometry(100, 100, 500, 500)
        self.mdi.addSubWindow(sub)
        sub.show()

        dbc_send_win = DBCSendWindow(file_path, self)
        sub2 = QMdiSubWindow()
        sub2.setWidget(dbc_send_win)
        sub2.setGeometry(100, 100, 500, 500)
        self.mdi.addSubWindow(sub2)
        sub2.show()

        self.config["RecentDBCs"][os.path.basename(file_path)] = file_path
        self.recentDBCFiles[os.path.basename(file_path)] = file_path
        self.dbc_path = os.path.split(file_path)[0]
        self.saveConfig()

    @pyqtSlot(int)
    def handleCANStatus(self, status):
        if status == 1:
            self.statusBar().showMessage("Failed to find CAN device")
            self.pcan_state = self.PCAN_STATE_DISCONNECTED

        elif status == 0:
            self.statusBar().showMessage("CAN device connected")
            self.pcan_state = self.PCAN_STATE_CONNECTED

        elif status == 2:
            self.statusBar().showMessage("Disconnected")
            self.pcan_state = self.PCAN_STATE_DISCONNECTED

    def CANConnect(self, connection):
        bustype = connection.bustype
        bitrate = connection.bitrate
        path = connection.path

        self.config["WiCAN"]["canadaptor"] = bustype
        self.config["WiCAN"]["canbaud"] = bitrate
        self.config["WiCAN"]["canpath"] = path

        #TODO: clean up
        if bustype == 'PCAN':
            bustype = 'pcan'
            interface = 'PCAN_USBBUS1'
        elif bustype == 'KVaser':
            bustype = 'kvaser'
            interface = '0'
        elif bustype == 'Ixxat':
            bustype = 'ixxat'
            interface = '0'
        else:
            print("Unknown bustype: " + bustype)

        if bitrate == "125k":
            bitrate = 125000
        elif bitrate == "250k":
            bitrate = 250000
        elif bitrate == "500k":
            bitrate = 500000
        elif bitrate == "1M":
            bitrate = 1000000

        if self.pcan_state == self.PCAN_STATE_DISCONNECTED:
            self.statusBar().showMessage("Connecting...")
            self.can_thread.connect(bustype, interface, bitrate)
        elif self.pcan_state == self.PCAN_STATE_CONNECTED:
            self.statusBar().showMessage("Disconnecting...")
            self.can_thread.disconnect()

    @pyqtSlot(object)
    def handleCANMessage(self, msg):
        for file_name, window in self.dbc_windows.items():
            window.handleCANMessage(msg)

        can_id_hex = msg.arbitration_id
        can_id_printable = hex(can_id_hex)

        if can_id_hex not in self.can_data.keys():
            self.can_data[can_id_hex] = self.can_row
            can_id_item = QTableWidgetItem(can_id_printable)
            self.can_table.setItem(self.can_row, 0, can_id_item)
            row = self.can_row
            self.can_row += 1
        else:
            row = self.can_data[can_id_hex]

        for c in range(0, len(msg.data)):
            item = QTableWidgetItem(hex(msg.data[c]))
            self.can_table.setItem(row, c + 1, item)

    def tick(self):
        for file_name, window in self.dbc_send_windows.items():
            window.tick()
Пример #29
0
class MainWindow(QMainWindow):
    count = 0

    def __init__(self, parent=None):
        super().__init__(parent)
        self.mdi = QMdiArea()
        self.setCentralWidget(self.mdi)

        self.app_manager = AppManager(None, gui_parent=self)
        self.mdi.subWindowActivated.connect(self.app_manager.on_view_activated)

        self.left = 100
        self.top = 50
        self.width = 1800
        self.height = 1200
        self.setGeometry(self.left, self.top, self.width, self.height)

        bar = self.menuBar()

        file = bar.addMenu("File")
        file.addAction("New")
        file.addAction("Open...")
        file.addSeparator()
        file.addAction("Save")
        file.addAction("Save As...")
        file.addAction("Close")
        file.triggered[QAction].connect(self.file_action)

        view = bar.addMenu("View")
        view.addAction("Spec Sheet")
        view.addAction("Optical Layout")
        view.addAction("Lens Table")
        view.addAction("Element Table")
        view.addAction("Lens View")
        view.addSeparator()
        view.addAction("Paraxial Model")
        view.addAction("Paraxial Height View")
        view.addAction("Paraxial Height View V2")
        view.addAction("Paraxial Slope View")
        view.addAction("Paraxial Ray Table")
        view.addAction("Ray Table")
        view.addSeparator()
        view.addAction("Ray Fans")
        view.addAction("OPD Fans")
        view.addAction("Spot Diagram")
        view.addAction("Wavefront Map")
        view.addAction("Astigmatism Curves")
        view.addAction("3rd Order Aberrations")
        view.addSeparator()
        view.triggered[QAction].connect(self.view_action)

        wnd = bar.addMenu("Window")
        wnd.addAction("Cascade")
        wnd.addAction("Tiled")
        wnd.addSeparator()

        dock.create_dock_windows(self)
        for pi in dock.panels.values():
            wnd.addAction(pi.menu_action)

        wnd.triggered[QAction].connect(self.window_action)

        self.setWindowTitle("Ray Optics")
        self.show()

        self.new_model()
        self.add_ipython_subwindow()

#        pth = Path(__file__).resolve()
#        try:
#            root_pos = pth.parts.index('rayoptics')
#        except ValueError:
#            logging.debug("Can't find rayoptics: path is %s", pth)
#        else:
#            path = Path(*pth.parts[:root_pos+1])
#            self.open_file(path / "codev/tests/asp46.seq")
#            self.open_file(path / "codev/tests/dar_test.seq")
#            self.open_file(path / "codev/tests/paraboloid.seq")
#            self.open_file(path / "codev/tests/paraboloid_f8.seq")
#            self.open_file(path / "codev/tests/schmidt.seq")
#            self.open_file(path / "codev/tests/questar35.seq")
#            self.open_file(path / "codev/tests/rc_f16.seq")
#            self.open_file(path / "codev/tests/ag_dblgauss.seq")
#            self.open_file(path / "codev/tests/threemir.seq")
#            self.open_file(path / "codev/tests/folded_lenses.seq")
#            self.open_file(path / "codev/tests/unfolded_lenses_w_ape.seq")
#            self.open_file(path / "codev/tests/lens_reflection_test.seq")
#            self.open_file(path / "codev/tests/dec_tilt_test.seq")
#            self.open_file(path / "codev/tests/landscape_lens.seq")
#            self.open_file(path / "codev/tests/mangin.seq")
#            self.open_file(path / "optical/tests/cell_phone_camera.roa")
#            self.open_file(path / "optical/tests/singlet_f3.roa")

#        try:
#            root_pos = pth.parts.index('ray-optics')
#        except ValueError:
#            logging.debug("Can't find ray-optics: path is %s", pth)
#        else:
#            path = Path(*pth.parts[:root_pos+1])
#            self.open_file(path / "models/TwoMirror.roa")
#            self.open_file(path / "models/TwoSphericalMirror.roa")
#            self.open_file(path / "models/Sasian Triplet.roa")
#            self.open_file(path / "models/singlet_f5.roa")
#            self.open_file(path / "models/thinlens.roa")
#            self.open_file(path / "models/thin_triplet.roa")
#            self.open_file(path / "models/Cassegrain.roa")
#            self.open_file(path / "models/Ritchey_Chretien.roa")
#        finally:
#            self.add_ipython_subwindow()

    def add_subwindow(self, widget, model_info):
        sub_wind = self.mdi.addSubWindow(widget)
        self.app_manager.add_view(sub_wind, widget, model_info)
        MainWindow.count += 1
        return sub_wind

    def delete_subwindow(self, sub_wind):
        self.app_manager.delete_view(sub_wind)
        self.mdi.removeSubWindow(sub_wind)
        MainWindow.count -= 1

    def add_ipython_subwindow(self):
        try:
            create_ipython_console(self, 'iPython console', 600, 400)
        except MultipleInstanceError:
            logging.debug("Unable to open iPython console. "
                          "MultipleInstanceError")
        except Exception as inst:
            print(type(inst))  # the exception instance
            print(inst.args)  # arguments stored in .args
            print(inst)  # __str__ allows args to be printed directly,
            pass  # but may be overridden in exception subclasses

    def initial_window_offset(self):
        offset_x = 50
        offset_y = 25
        orig_x = (MainWindow.count - 1) * offset_x
        orig_y = (MainWindow.count - 1) * offset_y
        return orig_x, orig_y

    def file_action(self, q):
        if q.text() == "New":
            self.new_model()

        if q.text() == "Open...":
            options = QFileDialog.Options()
            # options |= QFileDialog.DontUseNativeDialog
            fileName, _ = QFileDialog.getOpenFileName(
                self,
                "QFileDialog.getOpenFileName()",
                "",
                "CODE V Files (*.seq);;Ray-Optics Files (*.roa)",
                options=options)
            if fileName:
                logging.debug("open file: %s", fileName)
                self.open_file(fileName)

        if q.text() == "Save As...":
            options = QFileDialog.Options()
            # options |= QFileDialog.DontUseNativeDialog
            fileName, _ = QFileDialog.getSaveFileName(
                self,
                "QFileDialog.getSaveFileName()",
                "",
                "Ray-Optics Files (*.roa);;All Files (*)",
                options=options)
            if fileName:
                logging.debug("save file: %s", fileName)
                self.save_file(fileName)

        if q.text() == "Close":
            self.close_model()

    def new_model(self):
        iid = cmds.create_new_ideal_imager(gui_parent=self,
                                           conjugate_type='infinite')

        self.refresh_app_ui()

    def open_file(self, file_name):
        self.cur_filename = file_name
        self.app_manager.set_model(open_model(file_name))
        self.is_changed = True
        self.create_lens_table()
        cmds.create_live_layout_view(self.app_manager.model, gui_parent=self)
        #        cmds.create_lens_layout_view(self.app_manager.model, gui_parent=self)
        #        self.create_2D_lens_view()
        self.refresh_app_ui()

    def save_file(self, file_name):
        self.app_manager.model.save_model(file_name)
        self.cur_filename = file_name
        self.is_changed = False

    def close_model(self):
        """ NOTE: this does not check to save a modified model """
        self.app_manager.close_model(self.delete_subwindow)

    def view_action(self, q):
        opt_model = self.app_manager.model

        if q.text() == "Spec Sheet":
            cmds.create_new_ideal_imager(opt_model=opt_model, gui_parent=self)

        if q.text() == "Optical Layout":
            cmds.create_live_layout_view(opt_model, gui_parent=self)

        if q.text() == "Lens View":
            cmds.create_lens_layout_view(opt_model, gui_parent=self)


#            self.create_2D_lens_view()

        if q.text() == "Lens Table":
            self.create_lens_table()

        if q.text() == "Element Table":
            model = cmds.create_element_table_model(opt_model)
            self.create_table_view(model, "Element Table")

        if q.text() == "Ray Fans":
            cmds.create_ray_fan_view(opt_model, "Ray", gui_parent=self)

        if q.text() == "OPD Fans":
            cmds.create_ray_fan_view(opt_model, "OPD", gui_parent=self)

        if q.text() == "Spot Diagram":
            cmds.create_ray_grid_view(opt_model, gui_parent=self)

        if q.text() == "Wavefront Map":
            cmds.create_wavefront_view(opt_model, gui_parent=self)

        if q.text() == "Astigmatism Curves":
            cmds.create_field_curves(opt_model, gui_parent=self)

        if q.text() == "3rd Order Aberrations":
            cmds.create_3rd_order_bar_chart(opt_model, gui_parent=self)

        if q.text() == "Paraxial Height View":
            cmds.create_paraxial_design_view(opt_model, 'ht', gui_parent=self)

        if q.text() == "Paraxial Height View V2":
            cmds.create_paraxial_design_view_v2(opt_model,
                                                'ht',
                                                gui_parent=self)

        if q.text() == "Paraxial Slope View":
            cmds.create_paraxial_design_view(opt_model, 'slp', gui_parent=self)

        if q.text() == "Paraxial Ray Table":
            model = cmds.create_parax_table_model(opt_model)
            self.create_table_view(model, "Paraxial Ray Table")

        if q.text() == "Paraxial Model":
            model = cmds.create_parax_model_table(opt_model)
            self.create_table_view(model, "Paraxial Model")

        if q.text() == "Ray Table":
            self.create_ray_table(opt_model)

    def window_action(self, q):
        if q.text() == "Cascade":
            self.mdi.cascadeSubWindows()

        if q.text() == "Tiled":
            self.mdi.tileSubWindows()

    def create_lens_table(self):
        seq_model = self.app_manager.model.seq_model
        model = cmds.create_lens_table_model(seq_model)
        self.create_table_view(model, "Surface Data Table")

    def create_ray_table(self, opt_model):
        osp = opt_model.optical_spec
        pupil = [0., 1.]
        fi = 0
        wl = osp.spectral_region.reference_wvl
        fld, wvl, foc = osp.lookup_fld_wvl_focus(fi, wl)
        ray, ray_op, wvl = trace.trace_base(opt_model, pupil, fld, wvl)
        #        ray, ray_op, wvl, opd = trace.trace_with_opd(opt_model, pupil,
        #                                                     fld, wvl, foc)

        #        cr = trace.RayPkg(ray, ray_op, wvl)
        #        s, t = trace.trace_coddington_fan(opt_model, cr, foc)

        ray = [RaySeg(*rs) for rs in ray]
        model = cmds.create_ray_table_model(opt_model, ray)
        self.create_table_view(model, "Ray Table")

    def create_2D_lens_view(self):
        scene2d = QGraphicsScene()
        self.create_element_model(scene2d)
        self.create_ray_model(scene2d)
        scene2d.setBackgroundBrush(QColor(237, 243, 254))  # light blue
        sceneRect2d = scene2d.sceneRect()

        # construct the top level widget
        widget = QWidget()
        # construct the top level layout
        layout = QVBoxLayout(widget)

        # set the layout on the widget
        widget.setLayout(layout)

        sub = self.add_subwindow(
            widget,
            ModelInfo(self.app_manager.model, MainWindow.update_2D_lens_view,
                      (scene2d, )))
        sub.setWindowTitle("2D Lens View")
        view_width = 660
        view_ht = 440
        view_ratio = view_width / view_ht
        orig_x, orig_y = self.initial_window_offset()
        sub.setGeometry(orig_x, orig_y, view_width, view_ht)

        self.gview2d = QGraphicsView(scene2d)
        scene_ratio = sceneRect2d.width() / sceneRect2d.height()
        oversize_fraction = 1.2
        if scene_ratio > view_ratio:
            view_scale = view_width / (oversize_fraction * sceneRect2d.width())
        else:
            view_scale = view_ht / (oversize_fraction * sceneRect2d.height())

        self.gview2d.scale(view_scale, view_scale)
        layout.addWidget(self.gview2d)

        sub.show()

        return sub

    def update_2D_lens_view(scene2d):
        for gi in scene2d.items():
            gi.prepareGeometryChange()
            gi.update_shape()

    def create_element_model(self, gscene):
        ele_model = self.app_manager.model.ele_model
        ele_model.elements_from_sequence(self.app_manager.model.seq_model)
        for e in ele_model.elements:
            ge = OpticalElement(e)
            gscene.addItem(ge)

    def create_ray_model(self, gscene, start_surf=1):
        opt_model = self.app_manager.model

        img_dist = abs(opt_model.optical_spec.parax_data[2].img_dist)
        start_offset = 0.05 * (gscene.sceneRect().width() + img_dist)

        fov = opt_model.optical_spec.field_of_view
        for fi, f in enumerate(fov.fields):
            rb = RayBundle(opt_model, fi, start_offset)
            gscene.addItem(rb)

    def create_table_view(self, table_model, table_title, close_callback=None):
        # construct the top level widget
        widget = QWidget()
        # construct the top level layout
        layout = QVBoxLayout(widget)

        tableView = QTableView()
        tableView.setAlternatingRowColors(True)

        # Add table to box layout
        layout.addWidget(tableView)

        # set the layout on the widget
        widget.setLayout(layout)

        sub = self.add_subwindow(
            widget,
            ModelInfo(self.app_manager.model, cmds.update_table_view,
                      (tableView, )))
        sub.setWindowTitle(table_title)

        sub.installEventFilter(self)

        tableView.setModel(table_model)

        tableView.setMinimumWidth(tableView.horizontalHeader().length() +
                                  tableView.horizontalHeader().height())
        #                                  The following line should work but returns 0
        #                                  tableView.verticalHeader().width())

        view_width = tableView.width()
        view_ht = tableView.height()
        orig_x, orig_y = self.initial_window_offset()
        sub.setGeometry(orig_x, orig_y, view_width, view_ht)

        # table data updated successfully
        table_model.update.connect(self.on_data_changed)

        sub.show()

        return sub

    def eventFilter(self, obj, event):
        if (event.type() == QEvent.Close):
            print('close event received:', obj)
        return False

    def refresh_gui(self):
        self.app_manager.refresh_gui()

    def refresh_app_ui(self):
        dock.update_dock_windows(self)

    def handle_ideal_imager_command(self, iid, command, specsheet):
        if command == 'Apply':
            opt_model = self.app_manager.model
            opt_model.set_from_specsheet(specsheet)
            self.refresh_gui()
        elif command == 'Close':
            for view, info in self.app_manager.view_dict.items():
                if iid == info[0]:
                    view.close()
        elif command == 'Update':
            opt_model = self.app_manager.model
            specsheet = opt_model.specsheet
            firstorder.specsheet_from_parax_data(opt_model, specsheet)
            iid.specsheet_dict[specsheet.conjugate_type] = specsheet
            iid.update_values()
        elif command == 'New':
            opt_model = cmds.create_new_optical_model_from_specsheet(specsheet)
            self.app_manager.set_model(opt_model)
            for view, info in self.app_manager.view_dict.items():
                if iid == info[0]:
                    w = iid
                    mi = info[1]
                    args = (iid, opt_model)
                    new_mi = ModelInfo(model=opt_model,
                                       fct=mi.fct,
                                       args=args,
                                       kwargs=mi.kwargs)
                    self.app_manager.view_dict[view] = w, new_mi
            self.refresh_gui()
            self.create_lens_table()
            cmds.create_live_layout_view(opt_model, gui_parent=self)
            cmds.create_paraxial_design_view(opt_model, 'ht', gui_parent=self)
            self.refresh_gui()

    @pyqtSlot(object, int)
    def on_data_changed(self, rootObj, index):
        self.refresh_gui()
Пример #30
0
class DemoMdi(QMainWindow):
    def __init__(self, parent=None):
        super(DemoMdi, self).__init__(parent)

        # 设置窗口标题
        self.setWindowTitle(
            'MDI with a dockWidget tree and a tab-view mdiArea')
        # 设置窗口大小
        self.resize(800, 640)
        self.initUi()

        self.mytimer = QTimer(self)
        self.mytimer.start(1000)
        self.mytimer.timeout.connect(self.timerCallback)

    def initUi(self):
        self.initMenuBar()
        self.initToolBar()
        self.initDockTree()
        self.initStatusBar()

        self.mdiArea = QMdiArea(self)
        self.setCentralWidget(self.mdiArea)

        # set as tabbedView by default
        self.mdiArea.setViewMode(QMdiArea.TabbedView)
        self.mdiArea.setTabShape(QTabWidget.Triangular)
        self.mdiArea.setTabsClosable(True)
        self.mdiArea.setTabsMovable(True)

        # index of document
        self.newDocIndex = 1

    def initDockTree(self):
        self.dockWind = QDockWidget(self)
        self.dockWind.setWindowTitle('QProfile Explorer')

        self.initTree()
        self.dockWind.setWidget(self.tree)
        self.dockWind.setFloating(False)  # set floating = false
        self.addDockWidget(Qt.LeftDockWidgetArea,
                           self.dockWind)  # set the position at left side
        # remove all features of DockWidget like Closable, Moveable, Floatable, VerticalTitle etc.
        self.dockWind.setFeatures(QDockWidget.NoDockWidgetFeatures)

    def initTree(self):
        self.tree = QTreeWidget()
        self.tree.setColumnCount(1)  #设置列数
        #self.tree.setHeaderLabels(['QProfiler items'])  #设置树形控件头部的标题
        self.tree.setIndentation(20)  # 项目的缩进
        self.tree.setHeaderHidden(True)
        #设置根节点

        Perfmon = myQTreeWidgetItem(sin(pi * perfmon_x))
        Perfmon.setText(0, 'Perfmon')
        perfmon_00 = myQTreeWidgetItem(sin(2 * pi * perfmon_x))
        perfmon_00.setText(0, 'perfmon_00')
        Perfmon.addChild(perfmon_00)
        perfmon_01 = QTreeWidgetItem()
        perfmon_01.setText(0, 'perfmon_01')
        Perfmon.addChild(perfmon_01)
        perfmon_02 = QTreeWidgetItem()
        perfmon_02.setText(0, 'perfmon_02')
        Perfmon.addChild(perfmon_02)
        perfmon_03 = QTreeWidgetItem()
        perfmon_03.setText(0, 'perfmon_03')
        Perfmon.addChild(perfmon_03)
        self.tree.addTopLevelItem(Perfmon)
        # CPU
        cpuLoad = QTreeWidgetItem()
        cpuLoad.setText(0, 'CPU')
        cpuLoad_1 = QTreeWidgetItem()
        cpuLoad_1.setText(0, 'core 1')
        cpuLoad.addChild(cpuLoad_1)
        cpuLoad_2 = QTreeWidgetItem()
        cpuLoad_2.setText(0, 'core 2')
        cpuLoad.addChild(cpuLoad_2)
        self.tree.addTopLevelItem(cpuLoad)

        # treeItem signal
        self.tree.itemClicked[QTreeWidgetItem,
                              int].connect(self.treeItemClicked)

    def treeItemWindow_open(self, item):
        title = item.text(0)
        subWind = QMdiSubWindow(self)
        subWind.setAttribute(Qt.WA_DeleteOnClose)
        subWind.setWindowTitle(title)
        self.newDocIndex += 1
        mainWid = QWidget()
        l = QtWidgets.QVBoxLayout(mainWid)
        txtWind = QPlainTextEdit(mainWid)
        txtWind.setPlainText(f"perfmon.x = {item.x}, \n y = {item.y}")
        figWind = MyCanvas(mainWid,
                           width=5,
                           height=4,
                           dpi=100,
                           treeWidgetItem=item)
        l.addWidget(figWind)
        l.addWidget(txtWind)
        l.setStretch(0, 3)  # 设置第一列的伸展比例为 3
        l.setStretch(1, 1)  # 设置第二列的伸展比例为 1, 这样2列的伸展比为3:1

        subWind.setWidget(mainWid)
        self.mdiArea.addSubWindow(subWind)
        subWind.show()

    def treeItemClicked(self, item, column):
        tab = self.get_treeItem_tab(item.text(column))
        if tab is not None:
            tab.setFocus()
        else:
            if item.text(column) == 'Perfmon':
                self.treeItemWindow_open(item)
            else:
                newDoc = QMdiSubWindow(self)
                newDoc.setAttribute(Qt.WA_DeleteOnClose)
                newDoc.setWindowTitle(item.text(column))
                self.newDocIndex += 1
                newDoc.setWidget(QPlainTextEdit(
                    item.text(column) * 10, newDoc))
                self.mdiArea.addSubWindow(newDoc)
                newDoc.show()

    def get_treeItem_tab(self, title):
        for wind in self.mdiArea.subWindowList():
            if title == wind.windowTitle():
                return wind
        return None

    def initStatusBar(self):
        self.statusBar = self.statusBar()
        self.statusBar.showMessage('Ready to start ...', 0)

    def initMenuBar(self):
        menuBar = self.menuBar()
        style = QApplication.style()

        #==== 文件 ====#
        fileMenu = menuBar.addMenu('文件')

        #新建一个文档
        aFileNew = QAction('新建文档', self)
        aFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon))
        aFileNew.triggered.connect(self.onFileNew)
        fileMenu.addAction(aFileNew)

        #打开一个文档
        aFileOpen = QAction('打开文档', self)
        aFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton))
        aFileOpen.triggered.connect(self.onFileOpen)
        fileMenu.addAction(aFileOpen)

        #关闭一个文档
        aFileCloseAll = QAction('关闭全部', self)
        aFileCloseAll.setIcon(style.standardIcon(QStyle.SP_DialogCloseButton))
        aFileOpen.triggered.connect(self.onFileCloseAll)
        fileMenu.addAction(aFileCloseAll)

        #添加分割线
        fileMenu.addSeparator()

        #退出
        aFileExit = QAction('退出', self)
        aFileExit.triggered.connect(self.close)
        fileMenu.addAction(aFileExit)

        #==== 编辑 ====#
        editMenu = menuBar.addMenu('编辑')

        #剪切
        aEditCut = QAction('剪切', self)
        aEditCut.setIcon(QIcon(':/ico/cut.png'))
        aEditCut.triggered.connect(self.onEditCut)
        editMenu.addAction(aEditCut)

        #复制
        aEditCopy = QAction('复制', self)
        aEditCopy.setIcon(QIcon(':/ico/copy.png'))
        aEditCopy.triggered.connect(self.onEditCopy)
        editMenu.addAction(aEditCopy)

        #粘贴
        aEditPaste = QAction('粘贴', self)
        aEditPaste.setIcon(QIcon(':/ico/paste.png'))
        aEditPaste.triggered.connect(self.onEditPaste)
        editMenu.addAction(aEditPaste)

        #==== 窗口排列方式 ====#
        windowMenu = menuBar.addMenu('窗口')

        #子窗口模式
        aWndSubView = QAction('子窗口模式', self)
        aWndSubView.triggered.connect(lambda: self.onWinowdMode(0))
        windowMenu.addAction(aWndSubView)
        #标签页模式
        aWndTab = QAction('标签页模式', self)
        aWndTab.triggered.connect(lambda: self.onWinowdMode(1))
        windowMenu.addAction(aWndTab)

        windowMenu.addSeparator()

        #平铺模式
        aWndTile = QAction('平铺模式', self)
        aWndTile.triggered.connect(lambda: self.onWinowdMode(2))
        windowMenu.addAction(aWndTile)
        #窗口级联模式
        aWndCascade = QAction('窗口级联模式', self)
        aWndCascade.triggered.connect(lambda: self.onWinowdMode(3))
        windowMenu.addAction(aWndCascade)

    def initToolBar(self):
        toolBar = self.addToolBar('ToolBar')
        style = QApplication.style()

        min_width = 64

        btnFileNew = QToolButton(self)
        btnFileNew.setText('新建文档')
        btnFileNew.setMinimumWidth(min_width)
        btnFileNew.setIcon(style.standardIcon(QStyle.SP_FileIcon))
        btnFileNew.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnFileNew.clicked.connect(self.onFileNew)
        toolBar.addWidget(btnFileNew)

        btnFileOpen = QToolButton(self)
        btnFileOpen.setText('打开文档')
        btnFileOpen.setMinimumWidth(min_width)
        btnFileOpen.setIcon(style.standardIcon(QStyle.SP_DialogOpenButton))
        btnFileOpen.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnFileOpen.clicked.connect(self.onFileOpen)
        toolBar.addWidget(btnFileOpen)

        btnFileCloseAll = QToolButton(self)
        btnFileCloseAll.setText('关闭全部')
        btnFileCloseAll.setMinimumWidth(min_width)
        btnFileCloseAll.setIcon(style.standardIcon(
            QStyle.SP_DialogCloseButton))
        btnFileCloseAll.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnFileCloseAll.clicked.connect(self.onFileCloseAll)
        toolBar.addWidget(btnFileCloseAll)

        toolBar.addSeparator()

        btnEditCut = QToolButton(self)
        btnEditCut.setText('剪切')
        btnEditCut.setMinimumWidth(64)
        btnEditCut.setIcon(QIcon(':/ico/cut.png'))
        btnEditCut.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnEditCut.clicked.connect(self.onEditCut)
        toolBar.addWidget(btnEditCut)

        btnEditCopy = QToolButton(self)
        btnEditCopy.setText('复制')
        btnEditCopy.setMinimumWidth(64)
        btnEditCopy.setIcon(QIcon(':/ico/copy.png'))
        btnEditCopy.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnEditCopy.clicked.connect(self.onEditCopy)
        toolBar.addWidget(btnEditCopy)

        btnEditPaste = QToolButton(self)
        btnEditPaste.setText('粘贴')
        btnEditPaste.setMinimumWidth(64)
        btnEditPaste.setIcon(QIcon(':/ico/paste.png'))
        btnEditPaste.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        btnEditPaste.clicked.connect(self.onEditPaste)
        toolBar.addWidget(btnEditPaste)

    def msgCritical(self, strInfo):
        dlg = QMessageBox(self)
        dlg.setIcon(QMessageBox.Critical)
        dlg.setText(strInfo)
        dlg.show()

    def onFileNew(self):
        newDoc = QMdiSubWindow(self)
        newDoc.setAttribute(Qt.WA_DeleteOnClose)
        newDoc.setWindowTitle('新文档 ' + str(self.newDocIndex))
        self.newDocIndex += 1
        newDoc.setWidget(QPlainTextEdit(newDoc))
        self.mdiArea.addSubWindow(newDoc)
        newDoc.show()

    def onFileOpen(self):
        path, _ = QFileDialog.getOpenFileName(self, '打开文件', '',
                                              '文本文件 (*.txt, *.prf)')
        if path:
            try:
                with open(path, 'rU') as f:
                    text = f.read()
            except Exception as e:
                self.msgCritical(str(e))
            else:
                openDoc = QMdiSubWindow(self)
                openDoc.setWindowTitle(path)
                txtEdit = QPlainTextEdit(openDoc)
                txtEdit.setPlainText(text)
                openDoc.setWidget(txtEdit)
                self.mdiArea.addSubWindow(openDoc)
                openDoc.show()

    def onFileCloseAll(self):
        self.mdiArea.closeAllSubWindows()

    def onEditCut(self):
        txtEdit = self.mdiArea.activeSubWindow().widget()
        txtEdit.cut()

    def onEditCopy(self):
        txtEdit = self.mdiArea.activeSubWindow().widget()
        txtEdit.copy()

    def onEditPaste(self):
        txtEdit = self.mdiArea.activeSubWindow().widget()
        txtEdit.paste()

    def onWinowdMode(self, index):
        if index == 3:
            self.mdiArea.cascadeSubWindows()
        elif index == 2:
            self.mdiArea.tileSubWindows()
        elif index == 1:
            self.mdiArea.setViewMode(QMdiArea.TabbedView)
        else:
            self.mdiArea.setViewMode(QMdiArea.SubWindowView)

    def timerCallback(self):
        self.statusBar.showMessage(
            f'Document Index = {self.newDocIndex}, subWind num ={len(self.mdiArea.subWindowList())}',
            0)