コード例 #1
0
class MainWindow(QMainWindow):
    SETTING_LAST_DIRECTORY = 'MainFrame/last_directory'
    SETTING_GEOMETRY = 'MainFrame/geometry'
    SETTING_PLOT_SMPSIGNAL = 'MainFrame/plot/smpsignal'
    SETTING_PLOT_SURFACE_AND_GROUND = 'MainFrame/plot/surface+ground'
    SETTING_PLOT_MARKERS = 'MainFrame/plot/markers'
    SETTING_PLOT_DRIFT = 'MainFrame/plot/drift'
    SETTING_PLOT_SSA_PROKSCH2015 = 'MainFrame/plot/ssa_proksch2015'
    SETTING_PLOT_DENSITY_PROKSCH2015 = 'MainFrame/plot/density_proksch2015'

    DEFAULT_GEOMETRY = QRect(100, 100, 800, 600)

    def __init__(self, log_window, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setWindowTitle(APP_NAME)

        self.log_window = log_window
        self.notify_dialog = NotificationDialog()
        self.marker_dialog = MarkerDialog(self)
        self.prefs_dialog = PreferencesDialog()

        self.documents = []
        self.preferences = Preferences.load()

        homedir = expanduser('~')
        self._last_directory = QSettings().value(self.SETTING_LAST_DIRECTORY,
                                                 defaultValue=homedir)

        self.plot_canvas = PlotCanvas(main_window=self)
        self.superpos_canvas = SuperposCanvas(self)

        self.plot_toolbar = NavigationToolbar(self.plot_canvas, self)
        self.plot_toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.superpos_toolbar = NavigationToolbar(self.superpos_canvas, self)
        self.superpos_toolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.superpos_toolbar.setVisible(False)

        self.addToolBar(Qt.BottomToolBarArea, self.plot_toolbar)
        self.addToolBar(Qt.BottomToolBarArea, self.superpos_toolbar)

        self.sidebar = SidebarWidget(self)

        self.plot_stacked_widget = QStackedWidget(self)
        self.plot_stacked_widget.addWidget(self.plot_canvas)
        self.plot_stacked_widget.addWidget(self.superpos_canvas)

        splitter = QSplitter()
        splitter.addWidget(self.plot_stacked_widget)
        splitter.addWidget(self.sidebar)

        self.stacked_widget = QStackedWidget(self)
        self.stacked_widget.addWidget(NoDocWidget())
        self.stacked_widget.addWidget(splitter)

        self.setCentralWidget(self.stacked_widget)

        self.about_action = QAction('About', self)
        self.quit_action = QAction('Quit', self)
        self.preferences_action = QAction('Preferences', self)
        self.open_action = QAction('&Open', self)
        self.save_action = QAction('&Save', self)
        self.saveall_action = QAction('Save &All', self)
        self.drop_action = QAction('&Drop', self)
        self.export_action = QAction('&Export', self)
        self.next_action = QAction('Next Profile', self)
        self.previous_action = QAction('Previous Profile', self)
        self.plot_smpsignal_action = QAction('Plot SMP Signal', self)
        self.plot_surface_and_ground_action = QAction('Plot Surface && Ground',
                                                      self)
        self.plot_markers_action = QAction('Plot other Markers', self)
        self.plot_drift_action = QAction('Plot Drift', self)
        self.plot_ssa_proksch2015_action = QAction('Proksch 2015', self)
        self.plot_density_proksch2015_action = QAction('Proksch 2015', self)
        self.detect_surface_action = QAction('Auto Detect Surface', self)
        self.detect_ground_action = QAction('Auto Detect Ground', self)
        self.add_marker_action = QAction('New Marker', self)
        self.kml_action = QAction('Export to KML', self)
        self.show_log_action = QAction('Show Log', self)
        self.superpos_action = QAction('Superposition', self)

        self.profile_combobox = QComboBox(self)
        self.profile_combobox.setSizeAdjustPolicy(QComboBox.AdjustToContents)

        self._init_ui()
        self.switch_document()

    def _init_ui(self):
        geometry = QSettings().value('MainFrame/geometry',
                                     defaultValue=MainWindow.DEFAULT_GEOMETRY)
        self.setGeometry(geometry)

        self.profile_combobox.currentIndexChanged.connect(self.switch_document)

        action = self.about_action
        action.setStatusTip('About ' + APP_NAME)
        action.triggered.connect(self._about_triggered)

        action = self.quit_action
        action.setIcon(QIcon(':/icons/shutdown.png'))
        action.setShortcut('Ctrl+Q')
        action.setStatusTip('Quit application')
        # Call MainFrame.close when user want's to quit the application,
        # causing a call of MainFrame.closeEvent where we close all
        # other windows too (like LogWindow for example), which quits
        # the application itself
        action.triggered.connect(self.close)

        action = self.preferences_action
        action.setIcon(QIcon(':/icons/settings.png'))
        action.setShortcut('Ctrl+;')
        action.setStatusTip('Preferences')
        action.triggered.connect(self._preferences_triggered)

        action = self.open_action
        action.setIcon(QIcon(':/icons/open.png'))
        action.setShortcut('Ctrl+O')
        action.setStatusTip('Open')
        action.triggered.connect(self._open_triggered)

        action = self.save_action
        action.setIcon(QIcon(':/icons/save.png'))
        action.setShortcut('Ctrl+S')
        action.setStatusTip('Save')
        action.triggered.connect(self._save_triggered)

        action = self.saveall_action
        action.setIcon(QIcon(':/icons/saveall.png'))
        action.setShortcut('Ctrl+Alt+S')
        action.setStatusTip('Save All Profiles')
        action.triggered.connect(self._saveall_triggered)

        action = self.drop_action
        action.setIcon(QIcon(':/icons/drop.png'))
        action.setShortcut('Ctrl+X')
        action.setStatusTip('Drop Profile')
        action.triggered.connect(self._drop_triggered)

        action = self.export_action
        action.setIcon(QIcon(':/icons/csv.png'))
        action.setShortcut('Ctrl+E')
        action.setStatusTip('Export Profile to CSV')
        action.triggered.connect(self._export_triggered)

        action = self.next_action
        action.setIcon(QIcon(':/icons/next.png'))
        action.setShortcut('Ctrl+N')
        action.setStatusTip('Next Profile')
        action.triggered.connect(self._next_triggered)

        action = self.previous_action
        action.setIcon(QIcon(':/icons/previous.png'))
        action.setShortcut('Ctrl+P')
        action.setStatusTip('Previous Profile')
        action.triggered.connect(self._previous_triggered)

        action = self.detect_surface_action
        action.setIcon(QIcon(':/icons/detect_surface.png'))
        action.setShortcut('Ctrl+T')
        action.setStatusTip('Auto Detection of Surface')
        action.triggered.connect(self._detect_surface_triggered)

        action = self.detect_ground_action
        action.setIcon(QIcon(':/icons/detect_ground.png'))
        action.setShortcut('Ctrl+G')
        action.setStatusTip('Auto Detection of Ground')
        action.triggered.connect(self._detect_ground_triggered)

        def force_plot():
            self.update()

        action = self.plot_smpsignal_action
        action.setShortcut('Alt+P')
        action.setStatusTip('Plot SMP Signal')
        action.setCheckable(True)
        action.triggered.connect(force_plot)
        setting = MainWindow.SETTING_PLOT_SMPSIGNAL
        enabled = QSettings().value(setting, defaultValue=True, type=bool)
        action.setChecked(enabled)

        action = self.plot_surface_and_ground_action
        action.setShortcut('Alt+G')
        action.setStatusTip('Plot Surface + Ground')
        action.setCheckable(True)
        action.triggered.connect(force_plot)
        setting = MainWindow.SETTING_PLOT_SURFACE_AND_GROUND
        enabled = QSettings().value(setting, defaultValue=True, type=bool)
        action.setChecked(enabled)

        action = self.plot_markers_action
        action.setShortcut('Alt+M')
        action.setStatusTip('Plot Markers')
        action.setCheckable(True)
        action.triggered.connect(force_plot)
        setting = MainWindow.SETTING_PLOT_MARKERS
        enabled = QSettings().value(setting, defaultValue=True, type=bool)
        action.setChecked(enabled)

        action = self.plot_drift_action
        action.setShortcut('Alt+R')
        action.setStatusTip('Plot Drift')
        action.setCheckable(True)
        action.triggered.connect(force_plot)
        setting = MainWindow.SETTING_PLOT_DRIFT
        enabled = QSettings().value(setting, defaultValue=False, type=bool)
        action.setChecked(enabled)

        action = self.add_marker_action
        action.setShortcut('Ctrl+M')
        action.setIcon(QIcon(':/icons/marker_add.png'))
        action.setStatusTip('Add New Marker...')
        action.triggered.connect(
            lambda checked: self.new_marker(default_value=0))

        action = self.plot_ssa_proksch2015_action
        action.setShortcut('Alt+A,P')
        action.setStatusTip('Show SSA according Proksch 2015')
        action.setCheckable(True)
        action.triggered.connect(force_plot)
        setting = MainWindow.SETTING_PLOT_SSA_PROKSCH2015
        enabled = QSettings().value(setting, defaultValue=False, type=bool)
        action.setChecked(enabled)

        action = self.plot_density_proksch2015_action
        action.setShortcut('Alt+D,P')
        action.setStatusTip('Show Density according Proksch 2015')
        action.setCheckable(True)
        action.triggered.connect(force_plot)
        setting = MainWindow.SETTING_PLOT_DENSITY_PROKSCH2015
        enabled = QSettings().value(setting, defaultValue=False, type=bool)
        action.setChecked(enabled)

        action = self.kml_action
        action.setIcon(QIcon(':/icons/kml.png'))
        action.setShortcut('Ctrl+K')
        action.setStatusTip('Export to KML')
        action.triggered.connect(self._kml_triggered)

        action = self.show_log_action
        action.setIcon(QIcon(':/icons/logs.png'))
        action.setShortcut('Ctrl+L')
        action.setStatusTip('Show Log Window')
        action.triggered.connect(self._showlog_triggered)

        action = self.superpos_action
        action.setIcon(QIcon(':/icons/superpos.png'))
        action.setStatusTip('Show Superposition')
        action.triggered.connect(self._show_superpos)
        action.setCheckable(True)

        menubar = self.menuBar()

        menu = menubar.addMenu('&File')
        menu.addAction(self.about_action)
        menu.addAction(self.quit_action)
        menu.addAction(self.open_action)
        menu.addAction(self.save_action)
        menu.addAction(self.saveall_action)
        menu.addSeparator()
        menu.addAction(self.export_action)
        menu.addSeparator()
        menu.addAction(self.drop_action)
        menu.addSeparator()
        menu.addAction(self.preferences_action)

        menu = menubar.addMenu('&View')
        menu.addAction(self.plot_smpsignal_action)

        ssa_menu = menu.addMenu('Plot &SSA')
        ssa_menu.addAction(self.plot_ssa_proksch2015_action)

        density_menu = menu.addMenu('Plot &Density')
        density_menu.addAction(self.plot_density_proksch2015_action)

        menu.addSeparator()
        menu.addAction(self.plot_surface_and_ground_action)
        menu.addSeparator()
        menu.addAction(self.plot_markers_action)
        menu.addSeparator()
        menu.addAction(self.plot_drift_action)
        menu.addSeparator()
        menu.addAction(self.next_action)
        menu.addAction(self.previous_action)
        menu.addSeparator()
        menu.addAction(self.show_log_action)

        menu = menubar.addMenu('&Profile')
        menu.addAction(self.detect_surface_action)
        menu.addAction(self.detect_ground_action)
        menu.addAction(self.add_marker_action)

        toolbar = self.addToolBar('Exit')
        toolbar.addAction(self.quit_action)
        toolbar.addAction(self.preferences_action)
        toolbar.addSeparator()
        toolbar.addAction(self.open_action)
        toolbar.addAction(self.drop_action)
        toolbar.addAction(self.save_action)
        toolbar.addAction(self.export_action)
        toolbar.addSeparator()
        toolbar.addAction(self.detect_surface_action)
        toolbar.addAction(self.detect_ground_action)
        toolbar.addAction(self.add_marker_action)
        toolbar.addSeparator()
        toolbar.addAction(self.previous_action)
        toolbar.addWidget(self.profile_combobox)
        toolbar.addAction(self.next_action)
        toolbar.addSeparator()
        toolbar.addAction(self.kml_action)
        toolbar.addAction(self.saveall_action)
        toolbar.addAction(self.superpos_action)
        toolbar.setContextMenuPolicy(Qt.PreventContextMenu)

    def closeEvent(self, event):
        log.info('Saving settings of MainWindow')
        QSettings().setValue(MainWindow.SETTING_GEOMETRY, self.geometry())
        QSettings().setValue(MainWindow.SETTING_LAST_DIRECTORY,
                             self._last_directory)
        QSettings().setValue(MainWindow.SETTING_PLOT_SMPSIGNAL,
                             self.plot_smpsignal_action.isChecked())
        QSettings().setValue(MainWindow.SETTING_PLOT_SURFACE_AND_GROUND,
                             self.plot_surface_and_ground_action.isChecked())
        QSettings().setValue(MainWindow.SETTING_PLOT_MARKERS,
                             self.plot_markers_action.isChecked())
        QSettings().setValue(MainWindow.SETTING_PLOT_DRIFT,
                             self.plot_drift_action.isChecked())
        QSettings().setValue(MainWindow.SETTING_PLOT_SSA_PROKSCH2015,
                             self.plot_ssa_proksch2015_action.isChecked())
        QSettings().setValue(MainWindow.SETTING_PLOT_DENSITY_PROKSCH2015,
                             self.plot_density_proksch2015_action.isChecked())
        QSettings().sync()
        # This is the main window. In case it's closed, we close all
        # other windows too which results in quitting the application
        QApplication.instance().closeAllWindows()

    def _open_triggered(self):
        cap = "Open Profile(s)"
        filtr = "pnt Files (*.pnt)"
        opts = QFileDialog.ReadOnly
        startdir = self._last_directory
        files, _ = QFileDialog.getOpenFileNames(self,
                                                cap,
                                                startdir,
                                                filtr,
                                                options=opts)
        if files:
            self.open_pnts(files)

        # Save directory where we were to open at same place next time
        # for user's convenience
        if self.current_document:
            self._last_directory = dirname(
                self.current_document.profile.pnt_file)

    def open_pnts(self, files):
        new_docs = []
        for f in files:
            p = snowmicropyn.Profile.load(f)
            doc = Document(p)
            doc.recalc_derivatives(self.preferences.window_size,
                                   self.preferences.overlap)
            new_docs.append(doc)
            self.superpos_canvas.add_doc(doc)
        self.documents.extend(new_docs)
        first_new_index = self.profile_combobox.count()
        self.profile_combobox.addItems([d.profile.name for d in new_docs])

        # Set active to first of newly loaded profiles, this causes
        # also a call of method switch_document triggered by the combobox.
        self.profile_combobox.setCurrentIndex(first_new_index)

    def _save_triggered(self):
        self.current_document.profile.save()
        f = self.current_document.profile.ini_file
        self.notify_dialog.notifyFilesWritten([f])

    def _saveall_triggered(self):
        for doc in self.documents:
            doc.profile.save()
        f = [doc.profile.ini_file for doc in self.documents]
        self.notify_dialog.notifyFilesWritten(f)

    def _export_triggered(self):
        p = self.current_document.profile

        window = self.preferences.window_size
        overlap = self.preferences.overlap

        meta_file = p.export_meta(include_pnt_header=True)
        samples_file = p.export_samples()
        derivatives_file = p.export_derivatives(window_size=window,
                                                overlap_factor=overlap)
        self.notify_dialog.notifyFilesWritten(
            [meta_file, samples_file, derivatives_file])

    @property
    def current_document(self):
        i = self.profile_combobox.currentIndex()
        return self.documents[i] if i != -1 else None

    def _drop_triggered(self):
        doc = self.current_document
        self.superpos_canvas.remove_doc(doc)
        i = self.profile_combobox.currentIndex()
        del self.documents[i]
        # We just remove the item from the combobox, which causes
        # a call of method ``switch_profile``. The work is done there.
        self.profile_combobox.removeItem(i)

    def _next_triggered(self):
        log.debug('method next_profile called')

        # Fix for https://github.com/slf-dot-ch/snowmicropyn/issues/7
        # In case the lineedit widget to edit a markers value in the sidebar
        # has the focus, we clear that focus first, otherwise the marker would
        # set on the new profile instead.
        w = QApplication.focusWidget()
        if w:
            w.clearFocus()
        QApplication.processEvents()

        i = self.profile_combobox.currentIndex() + 1
        size = self.profile_combobox.count()
        if i > size - 1:
            i = 0
        # We just set a new index on the combobox, which causes a call
        # of method ``switch_profile``. The work is done there.
        self.profile_combobox.setCurrentIndex(i)

    def _previous_triggered(self):
        log.debug('method previous_profile called')

        # Fix for https://github.com/slf-dot-ch/snowmicropyn/issues/7
        # In case the lineedit widget to edit a markers value in the sidebar
        # has the focus, we clear that focus first, otherwise the marker would
        # set on the new profile instead.
        w = QApplication.focusWidget()
        if w:
            w.clearFocus()
        QApplication.processEvents()

        i = self.profile_combobox.currentIndex() - 1
        size = self.profile_combobox.count()
        if i < 0:
            i = size - 1
        # We just set a new index on the combobox, which causes a call
        # of method ``switch_profile``. The work is done there.
        self.profile_combobox.setCurrentIndex(i)

    def _detect_ground_triggered(self):
        doc = self.current_document
        doc.profile.detect_ground()
        self.set_marker('ground', doc.profile.ground)
        self.update()

    def _detect_surface_triggered(self):
        doc = self.current_document
        doc.profile.detect_surface()
        self.set_marker('surface', doc.profile.surface)
        self.update()

    def _showlog_triggered(self):
        self.log_window.show()
        self.log_window.activateWindow()
        self.log_window.raise_()

    @staticmethod
    def _about_triggered():
        # Read the content of the file about.html located in the same directory
        # as this file, read its content and use string.Template to replace
        # some content
        here = dirname(abspath(__file__))
        with open(join(here, 'about.html'), encoding='utf-8') as f:
            content = f.read()
        githash = GITHASH if GITHASH else 'None'
        tmpl = Template(content)
        content = tmpl.substitute(app_name=APP_NAME,
                                  version=VERSION,
                                  hash=githash)

        label = QLabel(content)
        label.setOpenExternalLinks(True)

        layout = QVBoxLayout()
        layout.addWidget(label)

        # noinspection PyArgumentList
        dialog = QDialog()
        dialog.setWindowTitle('About')
        dialog.setLayout(layout)
        dialog.exec_()

    def _kml_triggered(self):
        profile = self.current_document.profile
        f = join(dirname(profile.pnt_file), 'snowmicropyn_profiles.kml')
        snowmicropyn.pyngui.kml.export2kml(f, self.documents)
        self.notify_dialog.notifyFilesWritten(f)

    def _preferences_triggered(self):
        modified = self.prefs_dialog.modifyPreferences(self.preferences)
        if modified:
            self.preferences.save()
            # Recalculate derivations
            for doc in self.documents:
                ws = self.preferences.window_size
                of = self.preferences.overlap / 100
                doc.recalc_derivatives(ws, of)
            self.plot_canvas.set_limits()
            self.plot_canvas.draw()
            self.plot_toolbar.update()

    def switch_document(self):
        # Fix for https://github.com/slf-dot-ch/snowmicropyn/issues/7
        # In case the lineedit widget to edit a markers value in the sidebar
        # has the focus, we clear that focus first, otherwise the marker would
        # set on the new profile instead.
        w = QApplication.focusWidget()
        if w:
            w.clearFocus()
        QApplication.processEvents()

        doc = self.current_document
        log.debug(
            'Switching to document: {}'.format(doc.profile if doc else None))

        at_least_one = len(self.documents) > 0
        multiple = len(self.documents) >= 2
        self.profile_combobox.setEnabled(at_least_one)
        self.previous_action.setEnabled(multiple)
        self.next_action.setEnabled(multiple)
        self.drop_action.setEnabled(at_least_one)
        self.save_action.setEnabled(at_least_one)
        self.saveall_action.setEnabled(at_least_one)
        self.export_action.setEnabled(at_least_one)
        self.detect_surface_action.setEnabled(at_least_one)
        self.detect_ground_action.setEnabled(at_least_one)
        self.add_marker_action.setEnabled(at_least_one)
        self.kml_action.setEnabled(at_least_one)

        self.stacked_widget.setCurrentIndex(1 if at_least_one else 0)

        self.sidebar.set_document(doc)

        if doc is not None:
            self.calc_drift()

        self.plot_canvas.set_document(doc)
        self.plot_canvas.draw()
        # Reset toolbar history
        self.plot_toolbar.update()

        self.superpos_canvas.set_active_doc(doc)

    # This method is called by PlotCanvas and Sidebar when a marker is set to
    # a new value. This method then causes the required update of visualization
    def set_marker(self, label, value):
        doc = self.current_document
        p = doc.profile
        if value is not None:
            value = float(value)
        log.info('Setting marker {} of profile {} to {}'.format(
            repr(label), p.name, value))
        p.set_marker(label, value)

        self.sidebar.set_marker(label, value)
        self.plot_canvas.set_marker(label, value)

        if label in ('surface', 'drift_begin', 'drift_end'):
            self.calc_drift()
            self.plot_canvas.set_plot('force', 'drift',
                                      (doc._fit_x, doc._fit_y))

        if label in ('surface', 'ground'):
            doc.recalc_derivatives(self.preferences.window_size,
                                   self.preferences.overlap)
            self.plot_canvas.set_plot(
                'ssa', 'P2015_ssa',
                (doc.derivatives.distance, doc.derivatives.P2015_ssa))
            self.plot_canvas.set_plot(
                'density', 'P2015_density',
                (doc.derivatives.distance, doc.derivatives.P2015_density))

        self.plot_canvas.draw()

    def new_marker(self, default_value=0):
        name, value = self.marker_dialog.getMarker(default_value=default_value)
        if name is not None:
            self.set_marker(name, value)

    def calc_drift(self):
        p = self.current_document.profile

        try:
            begin = p.marker('drift_begin')
            begin_label = 'Marker drift_begin'
        except KeyError:
            # Skip the first few values of profile fo drift calculation
            begin = p.samples.distance.iloc[10]
            begin_label = 'Begin of Profile'

        try:
            end = p.marker('drift_end')
            end_label = 'Marker drift_end'
        except KeyError:
            try:
                end = p.marker('surface')
                end_label = 'Marker surface'
            except KeyError:
                end = p.samples.distance.iloc[-1]
                end_label = 'End of Profile'

        log.debug('Calculating drift from {} to {}'.format(begin, end))

        # Flip begin and end to make sure begin is always smaller then end
        if end < begin:
            begin, end = end, begin

        drift_range = p.samples[p.samples.distance.between(begin, end)]

        x_fit, y_fit, drift, offset, noise = snowmicropyn.tools.lin_fit(
            drift_range.distance, drift_range.force)
        self.current_document._fit_x = x_fit
        self.current_document._fit_y = y_fit
        self.current_document._dirft = drift
        self.current_document._offset = offset
        self.current_document._noise = noise

        self.sidebar.set_drift(begin_label, end_label, drift, offset, noise)

    def update(self):
        self.plot_canvas.draw()

    def _show_superpos(self, checked):
        log.info('Show superposition view: {}'.format(checked))
        self.plot_stacked_widget.setCurrentIndex(1 if checked else 0)

        self.superpos_toolbar.setVisible(checked)
        self.plot_toolbar.setVisible(not checked)

    def all_marker_labels(self):
        labels = set()
        for d in self.documents:
            labels.update(d.profile.markers.keys())
        return labels
コード例 #2
0
ファイル: multitab.py プロジェクト: apodemus/grafico
 def add(self, canvas, parent):
     tool = NavigationToolbar(canvas, parent)
     self.toolbars.append( tool )
     self.vbox.addWidget( tool )
     tool.setVisible(False)
コード例 #3
0
class QmyFigureCanvas(QWidget):
    def __init__(self, parent=None, toolbarVisible=True, showHint=False):
        super().__init__(parent)

        self.figure = mpl.figure.Figure()  #公共的figure属性
        figCanvas = FigureCanvas(self.figure)  #创建FigureCanvas对象,必须传递一个Figure对象

        self.naviBar = NavigationToolbar(figCanvas, self)  #公共属性naviBar
        self.__changeActionLanguage()  #改为汉语

        actList = self.naviBar.actions()  #关联的Action列表
        count = len(actList)  #Action的个数
        self.__lastActtionHint = actList[count - 1]  #最后一个Action,坐标提示标签
        self.__showHint = showHint  #是否在工具栏上显示坐标提示
        self.__lastActtionHint.setVisible(self.__showHint)  #隐藏其原有的坐标提示

        self.__showToolbar = toolbarVisible  #是否显示工具栏
        self.naviBar.setVisible(self.__showToolbar)

        layout = QVBoxLayout(self)
        layout.addWidget(self.naviBar)  #添加工具栏
        layout.addWidget(figCanvas)  #添加FigureCanvas对象
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        #鼠标滚轮缩放
        self.__cid = figCanvas.mpl_connect("scroll_event", self.do_scrollZoom)


##=====公共接口函数

    def setToolbarVisible(self, isVisible=True):  ##是否显示工具栏
        self.__showToolbar = isVisible
        self.naviBar.setVisible(isVisible)

    def setDataHintVisible(self, isVisible=True):  ##是否显示工具栏最后的坐标提示标签
        self.__showHint = isVisible
        self.__lastActtionHint.setVisible(isVisible)

    def redraw(self):  ##重绘曲线,快捷调用
        self.figure.canvas.draw()

    def __changeActionLanguage(self):  ##汉化工具栏
        actList = self.naviBar.actions()  #关联的Action列表
        actList[0].setText("复位")  #Home
        actList[0].setToolTip("复位到原始视图")  #Reset original view

        actList[1].setText("回退")  #Back
        actList[1].setToolTip("回退前一视图")  #Back to previous view

        actList[2].setText("前进")  #Forward
        actList[2].setToolTip("前进到下一视图")  #Forward to next view

        actList[4].setText("平动")  #Pan
        actList[4].setToolTip(
            "左键平移坐标轴,右键缩放坐标轴")  #Pan axes with left mouse, zoom with right

        actList[5].setText("缩放")  #Zoom
        actList[5].setToolTip("框选矩形框缩放")  #Zoom to rectangle

        actList[6].setText("子图")  #Subplots
        actList[6].setToolTip("设置子图")  #Configure subplots

        actList[7].setText("定制")  #Customize
        actList[7].setToolTip("定制图表参数")  #Edit axis, curve and image parameters

        actList[9].setText("保存")  #Save
        actList[9].setToolTip("保存图表")  #Save the figure

    def do_scrollZoom(self, event):  #通过鼠标滚轮缩放
        ax = event.inaxes  # 产生事件axes对象
        if ax == None:
            return

        self.naviBar.push_current(
        )  #Push the current view limits and position onto the stack,这样才可以还原
        xmin, xmax = ax.get_xbound()
        xlen = xmax - xmin
        ymin, ymax = ax.get_ybound()
        ylen = ymax - ymin

        xchg = event.step * xlen / 20  #step [scalar],positive = ’up’, negative ='down'
        xmin = xmin + xchg
        xmax = xmax - xchg
        ychg = event.step * ylen / 20
        ymin = ymin + ychg
        ymax = ymax - ychg

        ax.set_xbound(xmin, xmax)
        ax.set_ybound(ymin, ymax)
        event.canvas.draw()