Пример #1
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 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()  # 平铺排列
Пример #3
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())
Пример #4
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()
Пример #5
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)
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()
Пример #7
0
class Example(QMainWindow):
    def __init__(self):
        '''
        一些初始设置
        '''
        super().__init__()
        self.InitUI()

    def InitUI(self):
        '''
        界面初始设置
        '''
        self.setWindowTitle('关注微信公众号:学点编程吧--扑克牌模拟')

        self.mid = QMdiArea()
        self.setCentralWidget(self.mid)
        # 新建一个QMdiArea类的对象,并将其设置为主窗口的中央小部件

        sendOnecardAct = QAction(QIcon('./res/sendOnecard.ico'), '发1张牌', self)
        sendOnecardAct.triggered.connect(self.sendOnecard)
        # 发1张牌命令

        sendFivecardsAct = QAction(QIcon('./res/sendFivecard.ico'), '随机5张牌', self)
        sendFivecardsAct.triggered.connect(self.sendFivecards)
        # 随机5张牌命令

        clearcardAct = QAction(QIcon('./res/clear.ico'), '清除牌', self)
        clearcardAct.triggered.connect(self.clearCards)
        # 清除牌命令

        foldcardAct = QAction(QIcon('./res/fold.ico'), '收牌', self)
        foldcardAct.triggered.connect(self.foldCards)
        # 收牌

        toolbar = self.addToolBar('工具栏')
        toolbar.addAction(sendOnecardAct)
        toolbar.addAction(sendFivecardsAct)
        toolbar.addAction(clearcardAct)
        toolbar.addAction(foldcardAct)
        #把上面的几个命令放到工具栏上

        toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        #文字在图标下面
    
    def sendOnecard(self):
        '''
        随机一张牌,发出去。
        '''
        randomflag = self.randomsend(1)
        subcard = QMdiSubWindow()
        subcard.setWidget(Card(randomflag))
        self.mid.addSubWindow(subcard)
        subcard.setWindowFlags(Qt.WindowMinimizeButtonHint)
        # 设置窗口属性,让其只显示最小化按钮。
        subcard.resize(150, 200)
        subcard.show()
    
    def sendFivecards(self):
        '''
        随机5张牌
        '''
        randomflag = self.randomsend(5)
        for card in randomflag:
            # 遍历5张牌,发出去。
            subcard = QMdiSubWindow()
            subcard.setWidget(Card(card))
            self.mid.addSubWindow(subcard)
            subcard.setWindowFlags(Qt.WindowMinimizeButtonHint)
            # 设置窗口属性,让其只显示最小化按钮。
            subcard.resize(150, 200)
            subcard.show()
        
    def clearCards(self):
        '''
        清除牌
        '''
        self.mid.closeAllSubWindows()
        # 所有窗口关闭

    def foldCards(self):
        '''
        收牌
        '''
        self.mid.cascadeSubWindows()
        # 所有窗口级联模式排列
    
    def randomsend(self, num):
        '''
        发送方式:
        1、要是发1张牌,从cardlist中随机取一个元素返回就行了。
        2、要是随机发5张牌,从cardlist中随机取出一段包含有5个元素的列表。
        '''
        cardlist = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "a", "j", "joker", "k", "q"]
        if num == 1:
            return random.choice(cardlist)
        elif num == 5:
            return random.sample(cardlist, 5)
Пример #8
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()
Пример #9
0
class Example(QMainWindow):
    def __init__(self):
        super().__init__()
        self.InitUI()

    def InitUI(self):
        self.setWindowTitle('扑克牌模拟')

        self.mid = QMdiArea()
        self.setCentralWidget(self.mid)

        sendOnecardAct = QAction(QIcon('./res/sendOnecard.ico'), '发1张牌', self)
        sendOnecardAct.triggered.connect(self.sendOnecard)

        sendFivecardsAct = QAction(QIcon('./res/sendFivecard.ico'), '随机5张牌',
                                   self)
        sendFivecardsAct.triggered.connect(self.sendFivecards)

        clearcardAct = QAction(QIcon('./res/clear.ico'), '清除牌', self)
        clearcardAct.triggered.connect(self.clearCards)

        foldcardAct = QAction(QIcon('./res/fold.ico'), '收牌', self)
        foldcardAct.triggered.connect(self.foldCards)

        toolbar = self.addToolBar('工具栏')
        toolbar.addAction(sendOnecardAct)
        toolbar.addAction(sendFivecardsAct)
        toolbar.addAction(clearcardAct)
        toolbar.addAction(foldcardAct)
        toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

    def sendOnecard(self):
        randomflag = self.randomsend(1)
        subcard = QMdiSubWindow()
        subcard.setWidget(Card(randomflag))
        self.mid.addSubWindow(subcard)
        subcard.setWindowFlags(Qt.WindowMinimizeButtonHint)
        subcard.show()

    def sendFivecards(self):
        randomflag = self.randomsend(5)
        for card in randomflag:
            subcard = QMdiSubWindow()
            subcard.setWidget(Card(card))
            self.mid.addSubWindow(subcard)
            subcard.setWindowFlags(Qt.WindowMinimizeButtonHint)
            subcard.show()

    def clearCards(self):
        self.mid.closeAllSubWindows()

    def foldCards(self):
        self.mid.cascadeSubWindows()

    def randomsend(self, num):
        cardlist = [
            "2", "3", "4", "5", "6", "7", "8", "9", "10", "a", "j", "joker",
            "k", "q"
        ]
        if num == 1:
            return random.choice(cardlist)
        elif num == 5:
            return random.sample(cardlist, 5)
Пример #10
0
    def setupTab4(self, tab4):
        """Layout widgets for preview panel"""
        scrollContainer = QVBoxLayout()
        scrollArea = QScrollArea()
        scrollArea.setWidgetResizable(True)
        mainWidget = QWidget()
        layout = QVBoxLayout()
        mainWidget.setLayout(layout)
        mainWidget.setMinimumSize(QSize(420, 500))
        scrollArea.setWidget(mainWidget)
        scrollContainer.addWidget(scrollArea)
        tab4.setLayout(scrollContainer)

        group1 = QGroupBox(self.tr("QHBoxLayout"))  # , "QHBoxLayout布局"))
        hbox = QHBoxLayout()
        for i in range(1, 5):
            hbox.addWidget(QPushButton(self.tr("Button") + str(i)))
        group1.setLayout(hbox)
        layout.addWidget(group1)

        group2 = QGroupBox(self.tr("QGridLayout"))  # , "QGridLayout布局"))
        group2.setCheckable(True)
        hbox = QGridLayout()
        hbox.addWidget(QLabel(self.tr("First line:")), 0, 0)  # "第一行数据:"))
        hbox.addWidget(QLabel(self.tr("Second line:")), 1, 0)
        hbox.addWidget(QLabel(self.tr("Third line:")), 2, 0)
        hbox.addWidget(QLineEdit(), 0, 1)
        hbox.addWidget(QLineEdit("0"), 1, 1)
        inputText = QLineEdit()
        inputText.setPlaceholderText(self.tr("please input"))  # "请输入:"))
        hbox.addWidget(inputText, 2, 1)
        text = QTextEdit(
            self.tr("This is a textedit, span 3 rows and 2 columns.")
        )  # "这是一个文本框,在QGridLayout中占三行两列。"))
        hbox.addWidget(text, 0, 2, 3, 2)
        group2.setLayout(hbox)
        layout.addWidget(group2)

        group3 = QGroupBox(self.tr("QFormLayout"))  # "QFormLayout布局"))
        group3.setCheckable(True)
        hbox = QFormLayout()

        hbox.addRow(self.tr("please input data"), QLineEdit())  # "请输入数据:")
        hbox.addRow(QLabel(self.tr("please select data")),
                    QSpinBox())  # "请选择数据:"
        box = QComboBox()
        box.addItem("Item1")
        box.addItem("Item2")
        box.addItem("Item3")
        hbox.addRow(self.tr("Please select item"), box)  # , "请选择选项:"
        group3.setLayout(hbox)
        layout.addWidget(group3)

        group4 = QGroupBox("Spliter MDI Dock")
        group4.setCheckable(True)
        hbox = QHBoxLayout()
        group4.setLayout(hbox)
        layout.addWidget(group4)

        splitter1 = QSplitter(Qt.Horizontal)
        splitter2 = QSplitter(Qt.Vertical)
        splitter1.resize(420, 350)
        splitter2.resize(350, 350)
        splitter2.setStretchFactor(0, 1)

        mdi = QMdiArea()
        mdi.addSubWindow(QWidget())
        mdi.addSubWindow(QWidget())
        mdi.cascadeSubWindows()
        w1 = QWidget()
        w2 = QWidget()
        d1 = QDockWidget("dock1", w1)
        d2 = QDockWidget("dock2", w1)
        d1.setAllowedAreas(Qt.LeftDockWidgetArea)
        d1.setFeatures(QDockWidget.AllDockWidgetFeatures
                       | QDockWidget.DockWidgetVerticalTitleBar)
        d2.setFeatures(QDockWidget.DockWidgetVerticalTitleBar)
        d3 = QDockWidget("dock3", w2)
        d3.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.TopDockWidgetArea)
        w1.resize(120, 120)
        splitter2.addWidget(w1)
        splitter2.addWidget(w2)
        splitter1.addWidget(mdi)
        splitter1.addWidget(splitter2)
        hbox.addWidget(splitter1)

        layout.addStretch(1)
Пример #11
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)
Пример #12
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()
Пример #13
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)
Пример #14
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)
Пример #15
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()
Пример #16
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)
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()
Пример #18
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)
Пример #19
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()