def __init__(self): QMainWindow.__init__(self) self.setWindowIcon(get_icon(os.path.join(APP_RESOURCES, 'icons', 'python.png'))) self.setupUi(self) # Redirect output to GUI's QTextEdit sys.stdout = OutLog(self.outputTextEdit, sys.stdout) sys.stderr = OutLog(self.outputTextEdit, sys.stderr, QColor(255,0,0) ) settings = QSettings() size = settings.value("MainWindow/Size", QVariant(QSize(600, 500))).toSize() self.resize(size) position = settings.value("MainWindow/Position", QVariant(QPoint(0, 0))).toPoint() self.move(position) self.restoreState( settings.value("MainWindow/State").toByteArray()) self.logger = Logger('Zupport.GUIloader') self.logger.debugging = settings.value("Logging/debugging").toBool() # Set up a ZupportManager to deal with the plugins self.manager = Manager(self) self.plugins = {} # Set up the extents menu self.extent = ExtentContainer() self.menuExtent = QMenu("Extent") resolutions = self.extent.resolutions self.extenactiongroup = QActionGroup(self.menuExtent) noneaction = QAction("None", self.menuExtent) self.extenactiongroup.addAction(noneaction) self.menuExtent.addAction(noneaction) for resolution in resolutions: resolution_text = str(resolution) submenu = self.menuExtent.addMenu(resolution_text) self.menuExtent.addMenu(submenu) for area in self.extent.get_names(resolution): subaction = QAction(str(area) + ": %s" % resolution_text, submenu) subaction.setCheckable(True) self.extenactiongroup.addAction(subaction) submenu.addAction(subaction) noneaction.isChecked() self.menuSettings.addMenu(self.menuExtent) self.actionDebugging_messages.setChecked(self.logger.debugging) self.setWindowTitle("Zupport GUI") self.load_tools() self.toolTreeWidget.itemSelectionChanged.connect(self.update_ui) self.actionDebugging_messages.toggled.connect(self._set_debugging) self.menuExtent.triggered.connect(self.update_ui) self.actionLoad_tool.triggered.connect(self.show_tool_gui) self.toolTreeWidget.doubleClicked.connect(self.show_tool_gui)
def __init__(self): QMainWindow.__init__(self) self.setWindowIcon(get_icon(os.path.join(APP_RESOURCES, 'icons', 'python.png'))) self.setupUi(self) # Redirect output to GUI's QTextEdit sys.stdout = OutLog(self.outputTextEdit, sys.stdout) sys.stderr = OutLog(self.outputTextEdit, sys.stderr, QColor(255,0,0) ) settings = QSettings() size = settings.value("MainWindow/Size", QVariant(QSize(600, 500))).toSize() self.resize(size) position = settings.value("MainWindow/Position", QVariant(QPoint(0, 0))).toPoint() self.move(position) self.restoreState( settings.value("MainWindow/State").toByteArray()) self.logger = Logger('Zupport.GUIloader') self.logger.debugging = settings.value("Logging/debugging").toBool() # Set up a ZupportManager to deal with the plugins self.manager = Manager(self) self.plugins = {} # Set up the extents menu self.extent = ExtentContainer() self.menuExtent = QMenu("Extent") resolutions = self.extent.resolutions self.extenactiongroup = QActionGroup(self.menuExtent) noneaction = QAction("None", self.menuExtent) self.extenactiongroup.addAction(noneaction) self.menuExtent.addAction(noneaction) for resolution in resolutions: resolution_text = str(resolution) submenu = self.menuExtent.addMenu(resolution_text) self.menuExtent.addMenu(submenu) for area in self.extent.get_names(resolution): subaction = QAction(str(area) + ": %s" % resolution_text, submenu) subaction.setCheckable(True) self.extenactiongroup.addAction(subaction) submenu.addAction(subaction) noneaction.isChecked() self.menuSettings.addMenu(self.menuExtent) self.actionDebugging_messages.setChecked(self.logger.debugging) self.setWindowTitle("Zupport GUI") self.load_tools() self.toolTreeWidget.itemSelectionChanged.connect(self.update_ui) self.actionDebugging_messages.toggled.connect(self._set_debugging) self.menuExtent.triggered.connect(self.update_ui) self.actionLoad_tool.triggered.connect(self.show_tool_gui) self.toolTreeWidget.doubleClicked.connect(self.show_tool_gui)
def _setup_menu(self): # File menu file_menu = self.menuBar().addMenu(_("File")) settings_action = create_action(self, _("Settings"), icon=get_icon('settings.png'), tip=_("Settings"), triggered=self.edit_settings) quit_action = create_action(self, _("Quit"), shortcut="Ctrl+Q", icon=get_std_icon("DialogCloseButton"), tip=_("Quit application"), triggered=self.close) add_actions(file_menu, (settings_action, None, quit_action)) # View menu view_menu = self.createPopupMenu() view_menu.setTitle(_(u"&View")) self.menuBar().addMenu(view_menu) # Help menu help_menu = self.menuBar().addMenu("?") about_action = create_action(self, _("About..."), icon=get_std_icon('MessageBoxInformation'), triggered=self.about) add_actions(help_menu, (about_action,)) # Base toolbar self.connectAction = QAction(QIcon('common/disconnected.png'), 'Connect', self) self.connectAction.triggered.connect( self.connect_button ) self.playAction = QAction(QIcon('common/play.png'), 'Play free', self) self.playAction.triggered.connect( self.start_free_session_button ) self.stopAction = QAction(QIcon('common/stop.png'), 'Stop', self) self.stopAction.triggered.connect( self.stop_button ) self.timedAction = QAction(QIcon('common/timed.png'), 'Start', self) self.timedAction.triggered.connect( self.start_timed_session_button ) self.toolbar = self.addToolBar('Controls') self.toolbar.addAction( self.connectAction ) self.toolbar.addAction( self.playAction ) self.toolbar.addAction( self.stopAction ) self.toolbar.addAction( self.timedAction ) self.toolbar.setObjectName('Controls') # Time toolbar self.timer = Timer( self ) self.connect( self.timer, SIGNAL( 'SessionStop' ), self.session_stop )
def create_action(parent, title, triggered=None, toggled=None, shortcut=None, icon=None, tip=None, checkable=None, context=Qt.WindowShortcut, enabled=None): """ Create a new QAction """ action = QAction(title, parent) if triggered: parent.connect(action, SIGNAL("triggered(bool)"), triggered) if checkable is not None: # Action may be checkable even if the toggled signal is not connected action.setCheckable(checkable) if toggled: parent.connect(action, SIGNAL("toggled(bool)"), toggled) action.setCheckable(True) if icon is not None: assert isinstance(icon, QIcon) action.setIcon( icon ) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if enabled is not None: action.setEnabled(enabled) action.setShortcutContext(context) return action
class MainWindow( QMainWindow ): def __init__(self): QMainWindow.__init__(self) self.setWindowTitle(APP_NAME) self.setWindowIcon(get_icon('python.png')) self.timeout = None # used to recognise the checkbox in settings self.bhpacketname = { 'RR':0, 'BREATHING':1, 'ECG':2, 'SUMMARY':3, 'ACC':4, } # Welcome message in statusbar: status = self.statusBar() status.showMessage(_("Zephyr BioHarness 3.0"), 5000) self._setup_layout() self._setup_menu() self._load_settings() self._init_objects() self.show() def _setup_menu(self): # File menu file_menu = self.menuBar().addMenu(_("File")) settings_action = create_action(self, _("Settings"), icon=get_icon('settings.png'), tip=_("Settings"), triggered=self.edit_settings) quit_action = create_action(self, _("Quit"), shortcut="Ctrl+Q", icon=get_std_icon("DialogCloseButton"), tip=_("Quit application"), triggered=self.close) add_actions(file_menu, (settings_action, None, quit_action)) # View menu view_menu = self.createPopupMenu() view_menu.setTitle(_(u"&View")) self.menuBar().addMenu(view_menu) # Help menu help_menu = self.menuBar().addMenu("?") about_action = create_action(self, _("About..."), icon=get_std_icon('MessageBoxInformation'), triggered=self.about) add_actions(help_menu, (about_action,)) # Base toolbar self.connectAction = QAction(QIcon('common/disconnected.png'), 'Connect', self) self.connectAction.triggered.connect( self.connect_button ) self.playAction = QAction(QIcon('common/play.png'), 'Play free', self) self.playAction.triggered.connect( self.start_free_session_button ) self.stopAction = QAction(QIcon('common/stop.png'), 'Stop', self) self.stopAction.triggered.connect( self.stop_button ) self.timedAction = QAction(QIcon('common/timed.png'), 'Start', self) self.timedAction.triggered.connect( self.start_timed_session_button ) self.toolbar = self.addToolBar('Controls') self.toolbar.addAction( self.connectAction ) self.toolbar.addAction( self.playAction ) self.toolbar.addAction( self.stopAction ) self.toolbar.addAction( self.timedAction ) self.toolbar.setObjectName('Controls') # Time toolbar self.timer = Timer( self ) self.connect( self.timer, SIGNAL( 'SessionStop' ), self.session_stop ) def _setup_layout(self): # Allow dockable widgets to be side by side self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks) self.setGeometry(300,100,1500,900) self.rrplot = RealTimePlot( self, 'RR-Interval', 'ms', QColor( 255, 0, 0 ) ) self.bwplot = RealTimePlot( self, 'Breathing','', QColor( 0, 0, 255 ) ) self.ecgplot = RealTimePlot( self, 'ECG Waveform','', QColor( 0, 0, 255 ) ) self.logarea = myDockableWidget(self, QTextEdit) self.bwpsd = RealTimePSD( self, 'Breathing PSD', inity=25000 ) self.rrpsd = RealTimePSD( self, 'RR-Interval PSD') self.logarea.widget.setReadOnly( True ) self.logarea.widget.setFont( QFont("Courier", 8) ) self.logarea.widget.setMinimumHeight(150) # Add the DockWidget to the main window self.ecgplot_dock = self.add_dockwidget( self.ecgplot.dockwidget, _("ECG Waveform") ) self.rrcurve_dock = self.add_dockwidget( self.rrplot.dockwidget, _("RR-Intervals Plot") ) self.rrpsd_dock = self.add_dockwidget( self.rrpsd.dockwidget, _("RRI PSD")) self.bwcurve_dock = self.add_dockwidget( self.bwplot.dockwidget, _("Breathing Plot") ) self.bwpsd_dock = self.add_dockwidget( self.bwpsd.dockwidget, _("Breathing PSD (not implemented)") ) self.splitDockWidget(self.rrcurve_dock, self.rrpsd_dock, Qt.Horizontal) self.splitDockWidget(self.bwcurve_dock, self.bwpsd_dock, Qt.Horizontal) self.log_dock = self.add_dockwidget( self.logarea, _("Messages"), position=Qt.BottomDockWidgetArea) #self.splitDockWidget(self.rrcurve_dock, self.ecgplot_dock, Qt.Horizontal) # setting the name of the dock widget is required to save correclty # the postion of the widget when the application close self.rrcurve_dock.setObjectName('rrcurve_dock') self.rrpsd_dock.setObjectName('rrpsd_dock') self.bwcurve_dock.setObjectName('bwcurve_dock') self.bwpsd_dock.setObjectName('bwpsd_dock') self.log_dock.setObjectName('log_dock') self.ecgplot_dock.setObjectName('ecgplot_dock') #self.log_dock.setMinimumHeight( 20 ) self.rrcurve_dock.setMinimumSize( 400, 200 ) self.bwcurve_dock.setMinimumSize( 400, 200 ) self.rrpsd_dock.setMinimumSize( 400, 200 ) self.bwpsd_dock.setMinimumSize( 400, 200 ) self.log_dock.setMinimumSize( 400, 100 ) self.log_dock.setMaximumHeight( 250 ) def _load_settings(self): self.appsettings = DataSetShowGroupBox("Settings", AppSettings, comment='', title=_("Application settings")) self.settings_storage = QSettings('settings.ini', QSettings.IniFormat) self.restoreGeometry( self.settings_storage.value('docksGeometry').toByteArray() ) self.restoreState( self.settings_storage.value('docksState').toByteArray() ) # load settings: self.settings_storage.beginGroup('BioHarnessPackets') rrdata = self.settings_storage.value('rrdata', True).toBool() breathing = self.settings_storage.value('breathing', True).toBool() ecg = self.settings_storage.value('ecg', False).toBool() summary = self.settings_storage.value('summary', False).toBool() accelerometer = self.settings_storage.value('accelerometer', False).toBool() self.settings_storage.endGroup() self.appsettings.dataset.bh_packets = [] if rrdata: self.appsettings.dataset.bh_packets.append(0) if breathing: self.appsettings.dataset.bh_packets.append(1) if ecg: self.appsettings.dataset.bh_packets.append(2) if summary: self.appsettings.dataset.bh_packets.append(3) if accelerometer: self.appsettings.dataset.bh_packets.append(4) self.settings_storage.beginGroup('Misc') self.appsettings.dataset.timedsession = self.settings_storage.value('TimedDuration', 5).toInt()[0] # handle windows and linux serial port name portname = self.settings_storage.value('Serial_Port').toString() if str(portname).isdigit() is True: self.appsettings.dataset.serialport = int(portname) else: self.appsettings.dataset.serialport = str(portname) self.appsettings.dataset.use_virtual_serial = self.settings_storage.value('Use_Virtual_Serial_Port', False).toBool() self.settings_storage.endGroup() self.settings_storage.beginGroup('Storage') self.appsettings.dataset.enable_database = self.settings_storage.value('db_enable', False).toBool() self.appsettings.dataset.db_url = self.settings_storage.value('db_url').toString() self.appsettings.dataset.db_port = self.settings_storage.value('db_port').toString() self.appsettings.dataset.db_user = self.settings_storage.value('db_user').toString() self.appsettings.dataset.db_pwd = self.settings_storage.value('db_pwd').toString() self.appsettings.dataset.db_dbname = self.settings_storage.value('db_dbname').toString() self.appsettings.dataset.enable_files = self.settings_storage.value('files_enable', False).toBool() self.appsettings.dataset.directory_storage = self.settings_storage.value('directory').toString() self.settings_storage.endGroup() def _init_objects(self): # The time series container hold the data of the heart beat and breathing signal self.timeseriescontainer = TimeSeriesContainer() self.sessiontype = 'free' # either free or timed self.zephyr_connect = ZephyrDevice() self.connect( self.zephyr_connect, SIGNAL( 'Message' ), self.printmessage ) self.connect( self.zephyr_connect, SIGNAL( 'rrinterval' ), self.update_RR_plot ) self.connect( self.zephyr_connect, SIGNAL( 'breathing_wave' ), self.update_BW_plot ) self.connect( self.zephyr_connect, SIGNAL( 'ecg' ), self.update_ECG_plot ) self.connect( self.zephyr_connect, SIGNAL( 'heart_rate' ), self.add_heart_rate ) self.connect( self.zephyr_connect, SIGNAL( 'respiration_rate' ), self.add_respiration_rate ) self.connect( self.zephyr_connect, SIGNAL( 'breathing_wave_amplitude' ), self.add_breathing_wave_amplitude ) self.connect( self.zephyr_connect, SIGNAL( 'activity' ), self.add_activity ) self.connect( self.zephyr_connect, SIGNAL( 'posture' ), self.add_posture ) self.zephyr_connect.virtual_serial = self.appsettings.dataset.use_virtual_serial # the button are disabled by default # they are enabled if the connection to the device is successfull self.stopAction.setEnabled( False ) self.playAction.setEnabled( False ) self.timedAction.setEnabled( False ) # InfluxDB storage configuration # Data storage need the application settings for db credentials self.datastorage = DataStorage() if self.appsettings.dataset.enable_database is True: self.datastorage.db_init( self.appsettings.dataset ) self._test_database_connection() # size for the ecg window is different that the default value # of 60' set at the creation of the real time plot self.ecgplot.window_length = 6 def sendbhcmd( self ): cmd = int(str(self.bhcmdinput.text()), 16) self.zephyr_connect.sendmessage(cmd, []) #------? def about( self ): QMessageBox.about( self, _("About ")+APP_NAME, """<b>%s</b> v%s<p>%s Darko Petrovic <br>(Lisence goes here) <p>Python %s, Qt %s, PyQt %s %s %s""" % \ (APP_NAME, VERSION, _("Developped by"), platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, _("on"), platform.system()) ) def edit_settings( self ): ok = self.appsettings.dataset.edit() # save settings in the .ini file if ok == 1: # Application settings (window position, view, ...): # ... # User settings: rrdata = breathing = ecg = summary = accelerometer = False for a in self.appsettings.dataset.bh_packets: if a == 0: rrdata = True elif a == 1: breathing = True elif a == 2: ecg = True elif a == 3: summary = True elif a == 4: accelerometer = True self.settings_storage.beginGroup('BioHarnessPackets') self.settings_storage.setValue('rrdata', str(rrdata) ) self.settings_storage.setValue('breathing', str(breathing) ) self.settings_storage.setValue('ecg', str(ecg) ) self.settings_storage.setValue('summary', str(summary) ) self.settings_storage.setValue('accelerometer', str(accelerometer) ) self.settings_storage.endGroup() self.settings_storage.beginGroup('Misc') self.settings_storage.setValue('TimedDuration', self.appsettings.dataset.timedsession ) self.settings_storage.setValue('Serial_Port', self.appsettings.dataset.serialport ) self.settings_storage.setValue('Use_Virtual_Serial_Port', self.appsettings.dataset.use_virtual_serial ) self.settings_storage.endGroup() self.settings_storage.beginGroup('Storage') self.settings_storage.setValue('db_enable', str(self.appsettings.dataset.enable_database) ) self.settings_storage.setValue('db_url', self.appsettings.dataset.db_url ) self.settings_storage.setValue('db_port', self.appsettings.dataset.db_port ) self.settings_storage.setValue('db_user', str(self.appsettings.dataset.db_user) ) self.settings_storage.setValue('db_pwd', str(self.appsettings.dataset.db_pwd) ) self.settings_storage.setValue('db_dbname', str(self.appsettings.dataset.db_dbname) ) self.settings_storage.setValue('files_enable', str(self.appsettings.dataset.enable_files) ) self.settings_storage.setValue('directory', str(self.appsettings.dataset.directory_storage) ) self.settings_storage.endGroup() if ok==1 and self.appsettings.dataset.enable_database: self.datastorage.db_init( self.appsettings.dataset ) self._test_database_connection() if ok==1: self.zephyr_connect.virtual_serial = self.appsettings.dataset.use_virtual_serial def _test_database_connection(self): result, message = self.datastorage.db_connection() if result: self.logmessage(message) else: self.logmessage("Connection to the database failed: %s" % message, 'error') #------GUI refresh/setup def add_dockwidget( self, child, title, orientation = Qt.Vertical, position=None ): """Add a QDockWidget to the main window.""" dockwidget, location = child.create_dockwidget( title ) if position is not None: location = position self.addDockWidget( location, dockwidget, orientation ) return dockwidget def logmessage( self, text, msgtype='info' ): """ Print a message in the message window """ if msgtype == 'error': self.logarea.widget.setTextColor( QColor( 255, 0, 0 ) ) else: self.logarea.widget.setTextColor( QColor( 0, 0, 0 ) ) self.logarea.widget.insertPlainText( text + "\n" ) sb = self.logarea.widget.verticalScrollBar() sb.setValue( sb.maximum() ) def update_RR_plot( self, value ): # Store value in the data-set. We store every value in the dataset # but we display only a certain duration specified by 'self.rrplot.window_length' self.timeseriescontainer.ts_rri.add_rrinterval( value ) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('rrintervals', value, self.timeseriescontainer.ts_rri.realtime[-1]*1000, 'm') # Set the data to the curve with values from the time series and update the plot self.rrplot.startIdx = self.timeseriescontainer.ts_rri.getSampleIndex( self.rrplot.window_length ) self.rrplot.update( self.timeseriescontainer.ts_rri.realtime, self.timeseriescontainer.ts_rri.series ) # Wait minimum 10 samples if len(self.timeseriescontainer.ts_rri.series) > 10: self.timeseriescontainer.ts_rri.computeLombPeriodogram() self.rrpsd.update(self.timeseriescontainer.ts_rri.psd_freq, self.timeseriescontainer.ts_rri.psd_mag) def update_BW_plot( self, values ): # Store value in the data-set. We store every value in the dataset # but we display only a certain duration specified by 'self.rrplot.window_length' self.timeseriescontainer.ts_bw.add_breath( values ) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('breathing_wave', values, self.timeseriescontainer.ts_bw.realtime[-len(values):]*1000, 'm') # Set the data to the curve with values from the data-set and update the plot self.bwplot.startIdx = self.timeseriescontainer.ts_bw.getSampleIndex( self.bwplot.window_length ) self.bwplot.update( self.timeseriescontainer.ts_bw.realtime, self.timeseriescontainer.ts_bw.series ) if len(self.timeseriescontainer.ts_bw.series) > 50: # ---- Compute and display the Power Spectral Density of breathing signal self.timeseriescontainer.ts_bw.computeWelchPeriodogram() self.bwpsd.update(self.timeseriescontainer.ts_bw.psd_freq, self.timeseriescontainer.ts_bw.psd_mag) def update_ECG_plot( self, values ): self.timeseriescontainer.ts_ecg.add_ecg( values ) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('ecg', values, self.timeseriescontainer.ts_ecg.realtime[-len(values):]*1000, 'm') self.ecgplot.startIdx = self.timeseriescontainer.ts_ecg.getSampleIndex( self.ecgplot.window_length ) self.ecgplot.update( self.timeseriescontainer.ts_ecg.realtime, self.timeseriescontainer.ts_ecg.series ) def add_heart_rate(self, value): self.timeseriescontainer.heart_rate = np.append(self.timeseriescontainer.heart_rate, value) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('heart_rate', value) def add_respiration_rate(self, value): self.timeseriescontainer.respiration_rate = np.append(self.timeseriescontainer.respiration_rate, value) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('respiration_rate', value) def add_breathing_wave_amplitude(self, value): self.timeseriescontainer.breathwave_ampltitude = np.append(self.timeseriescontainer.breathwave_ampltitude,value) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('breathing_wave_amplitude', value) def add_activity(self, value): self.timeseriescontainer.activity = np.append(self.timeseriescontainer.activity, value) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('activity', value) def add_posture(self, value): self.timeseriescontainer.posture = np.append(self.timeseriescontainer.posture, value) if self.appsettings.dataset.enable_database is True: self.datastorage.write_points('posture', value) def printmessage( self, message ): if message == 'connected': self.logmessage( "Successfully connected to the device %s." % self.zephyr_connect.SerialNumber ) self._toggle_connect_button() if self.timeout: self.timeout.stop() self.timeout = None if isinstance(message, zephyr.message.BatteryStatus): self.logmessage("Battery charge is %d%%" % message.Charge ) def _toggle_connect_button(self): if self.zephyr_connect.connected is True: self.connectAction.setIcon(QIcon('common/connected.png')) self.connectAction.setToolTip("Disconnect") self.connectAction.triggered.disconnect( self.connect_button ) self.connectAction.triggered.connect( self.disconnect_button ) self.playAction.setEnabled( True ) self.timedAction.setEnabled( True ) else: self.connectAction.setIcon(QIcon('common/disconnected.png')) self.connectAction.setToolTip("Connect") self.connectAction.triggered.disconnect( self.disconnect_button ) self.connectAction.triggered.connect( self.connect_button ) self.playAction.setEnabled( False ) self.timedAction.setEnabled( False ) def connect_button(self): # The connect button is first trying to open the com port. If the port can be opened, # the zephyr protocol functions are instancied and a message is send to the device # (the thread is started for this purpose and to let the reception of the response). # The device has 3 seconds to respond (a timeout is started to close the serial # and terminate the thread in case of no response). When the device responds a signal 'Message' # is sent to the GUI (the message is the Serial Number of the device). if self.zephyr_connect.connectTo( self.appsettings.dataset.serialport, self.appsettings.dataset.use_virtual_serial): self.zephyr_connect.start() if self.appsettings.dataset.use_virtual_serial is False: self.timeout = QTimer( self ) self.connect( self.timeout, SIGNAL( 'timeout()' ), self.connectionTimeout ) self.timeout.setSingleShot(True) self.timeout.start(3000) else: self.logmessage("Serial virtualization in use.") self._toggle_connect_button() else: self.logmessage( "Fail to open port '%s' !" % self.appsettings.dataset.serialport, 'error' ) def disconnect_button(self): self.zephyr_connect.terminate() if self.zephyr_connect.wait(): self._toggle_connect_button() if self.appsettings.dataset.use_virtual_serial is False: self.logmessage( "Successfully disconnected from the device." ) else: self.logmessage( "Virtual serial stopped." ) def connectionTimeout(self): self.logmessage("Unable to connected to the device on %s." % self.appsettings.dataset.serialport, 'error' ) self.zephyr_connect.terminate() if self.timeout: self.timeout = None def start_free_session_button( self ): self.sessiontype = 'free' self.timer.initialize( 0 ) self.session_start() def start_timed_session_button(self): if not self.timeout: self.sessiontype = 'timed' self.timer.initialize( self.appsettings.dataset.timedsession * 60 ) # the session will start after 'X' seconds X = 20 self.timeout = QTimer( self ) self.connect( self.timeout, SIGNAL( 'timeout()' ), self.session_start ) self.timeout.setSingleShot(True) self.timeout.start(X*1000) self.logmessage('The session will start in %d seconds.' % X) else: # the button is pressed a second time self.timeout.stop() self.timeout = None self.session_start() def stop_button( self ): sel = 0 if self.sessiontype == 'timed': sel = QMessageBox.warning( self, "Timed Session", "A Timed Session is currently active!\nIf you stop the session " "the session will be stored as a free session.", "OK", "Cancel") if sel == 0: self.session_stop() def session_start( self ): if self.timeout: self.timeout.stop() self.timeout = None # empty all arrays self.timeseriescontainer.clearContainer() if self.appsettings.dataset.use_virtual_serial is True: self.zephyr_connect.resume() for a in self.appsettings.dataset.bh_packets: if a == 0: self.zephyr_connect.enablePacket('RRDATA') self.timeseriescontainer.ts_rri.setStartTime() elif a == 1: self.zephyr_connect.enablePacket('BREATHING') self.timeseriescontainer.ts_bw.setStartTime() elif a == 2: self.zephyr_connect.enablePacket('ECG') self.timeseriescontainer.ts_ecg.setStartTime() elif a == 3: self.zephyr_connect.enablePacket('SUMMARY') self.timer.start() # handle graphical change: self.playAction.setEnabled( False ) self.timedAction.setEnabled( False ) self.stopAction.setEnabled( True ) self.connectAction.setEnabled( False ) # in any case, we create the new session in database because the # data are written in real time if self.appsettings.dataset.enable_database is True: self.datastorage.create_session() def session_stop(self): if self.appsettings.dataset.use_virtual_serial is True: self.zephyr_connect.pause() for a in self.appsettings.dataset.bh_packets: if a == 0: self.zephyr_connect.disablePacket('RRDATA') elif a == 1: self.zephyr_connect.disablePacket('BREATHING') elif a == 2: self.zephyr_connect.disablePacket('ECG') elif a == 3: self.zephyr_connect.disablePacket('SUMMARY') self.timer.stop() # handle graphical change: self.playAction.setEnabled( True ) self.timedAction.setEnabled( True ) self.stopAction.setEnabled( False ) self.connectAction.setEnabled( True ) # update session with the duration if self.appsettings.dataset.enable_database is True: self.datastorage.update_duration(self.timer.getRunningTime()) # store more info for the current session? if self.appsettings.dataset.enable_database or self.appsettings.dataset.enable_files: self.infosdialog = SessionInfos( self, self.datastorage ) self.connect(self.infosdialog, SIGNAL('accepted()'), self.add_more_infos ) self.infosdialog.exec_() def add_more_infos(self): sessiontype = 0 for i, r in enumerate(self.infosdialog.sessiontypes): if r.isChecked(): sessiontype = i+1 breathing_zone = self.infosdialog.breathzone.currentIndex() infos = { 'session_type': sessiontype, 'breathing_zone': '' if breathing_zone == 0 else breathing_zone, 'note': str(self.infosdialog.note.toPlainText()), } if self.appsettings.dataset.enable_database is True: self.datastorage.add_informations( infos ) self.logmessage("The information was stored in the database for this session.") def closeEvent(self, event): self.settings_storage.setValue( 'docksGeometry', self.saveGeometry() ) self.settings_storage.setValue( 'docksState', self.saveState() ) QMainWindow.closeEvent(self, event)
def create_action(parent, title, triggered=None, toggled=None, shortcut=None, icon=None, tip=None, checkable=None, context=Qt.WindowShortcut, enabled=None): """ Create a new QAction """ action = QAction(title, parent) if triggered: action.triggered.connect(triggered) if checkable is not None: # Action may be checkable even if the toggled signal is not connected action.setCheckable(checkable) if toggled: action.toggled.connect(toggled) action.setCheckable(True) if icon is not None: assert isinstance(icon, QIcon) action.setIcon(icon) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) if enabled is not None: action.setEnabled(enabled) action.setShortcutContext(context) return action
def __init__(self): QMainWindow.__init__(self) self.setWindowIcon(get_icon('python.png')) self.setWindowTitle("Electric motor simulator") # Dataset for editing motor parameters self.groupbox1 = DataSetShowGroupBox("Motor parameters", ExampleDataSet, comment='') self.groupbox2 = DataSetShowGroupBox("Controller parameters", AnotherDataSet, comment='') self.groupbox3 = DataSetEditGroupBox("Standard dataset", OtherDataSet, comment='') self.groupbox4 = DataSetEditGroupBox("Standard dataset", ExampleMultiGroupDataSet, comment='') #self.groupbox3.SIG_APPLY_BUTTON_CLICKED.connect(self.update_window) self.update_groupboxes() splitter = QSplitter(self) splitter.addWidget(self.groupbox1) splitter.addWidget(self.groupbox2) #splitter.addWidget(self.groupbox3) #splitter.addWidget(self.groupbox4) self.setCentralWidget(splitter) self.setContentsMargins(10, 5, 10, 5) # File menu file_menu = self.menuBar().addMenu("File") quit_action = create_action(self, "Quit", shortcut="Ctrl+Q", icon=get_std_icon("DialogCloseButton"), tip="Quit application", triggered=self.close) add_actions(file_menu, (quit_action, )) # Edit menu edit_menu = self.menuBar().addMenu("Edit") editparam1_action = create_action(self, "Edit dataset 1", triggered=self.edit_dataset1) editparam2_action = create_action(self, "Edit dataset 2", triggered=self.edit_dataset2) editparam4_action = create_action(self, "Edit dataset 4", triggered=self.edit_dataset4) add_actions(edit_menu, (editparam1_action, editparam2_action, editparam4_action)) # Toolbar tb = self.addToolBar("Tools") reset = QAction("Reset", self) tb.addAction(reset) pause = QAction("Pause", self) tb.addAction(pause) step = QAction("Step", self) tb.addAction(step) go = QAction("Go", self) tb.addAction(go)
def __init__(self, parent): QSplitter.__init__(self, parent) # List Widget self.arraylist = QListWidget(self) self.arraylist.setContextMenuPolicy(Qt.ActionsContextMenu) newArray = QAction(self) newArray.setText("Paste Array (no header name)") newArray.triggered.connect(self.pasteArray) newArrayWithName = QAction(self) newArrayWithName.setText("Paste Array (with header name)") newArrayWithName.triggered.connect(self.pasteArrayWithName) plotArray = QAction(self) plotArray.setText("Plot Array") plotArray.triggered.connect(self.plotArray) modifyArray = QAction(self) modifyArray.setText("Modify Array(Calibration)") modifyArray.triggered.connect(self.modifyArray) plotScatter = QAction(self) plotScatter.setText("Plot Scatter") plotScatter.triggered.connect(self.plotScatter) plotHist = QAction(self) plotHist.setText("Plot Histogram") plotHist.triggered.connect(self.plotHist) delete = QAction(self) delete.setText("Remove") delete.triggered.connect(self.removeItem) curveDialog = QAction(self) curveDialog.setText("Open Curve Dialog") curveDialog.triggered.connect(self.openCurveDialog) self.arraylist.addAction(newArray) self.arraylist.addAction(newArrayWithName) self.arraylist.addAction(plotArray) self.arraylist.addAction(plotScatter) self.arraylist.addAction(plotHist) self.arraylist.addAction(modifyArray) self.arraylist.addAction(curveDialog) self.arraylist.addAction(delete) self.addWidget(self.arraylist) # Properties widget self.properties = DataSetEditGroupBox(_("參數(Properties)"), CsvParam) self.properties.setEnabled(False) self.addWidget(self.properties)
def __init__(self, parent): QSplitter.__init__(self, parent) # List Widget self.csvlist = QListWidget(self) self.csvlist.setContextMenuPolicy(Qt.ActionsContextMenu) plotCSV = QAction(self) plotCSV.setText("Plot") plotCSV.triggered.connect(self.plotCSV) delete = QAction(self) delete.setText("Remove") delete.triggered.connect(self.removeItem) extractCSV = QAction(self) extractCSV.setText("Extract to Arrays") extractCSV.triggered.connect(self.extractArray) self.csvlist.addAction(plotCSV) self.csvlist.addAction(extractCSV) self.csvlist.addAction(delete) self.addWidget(self.csvlist) # Properties widget self.properties = DataSetEditGroupBox(_("參數(Properties)"), CsvParam) self.properties.setEnabled(False) self.addWidget(self.properties)
def setShortcuts(self): self.autoScaleAction = QAction(QIcon(), '&Autoscale', self) self.autoScaleAction.setShortcut("Ctrl+W") self.autoScaleAction.triggered.connect(self.plotWidget.autoScale)
class MainWindow(QMainWindow): def __init__(self, parent = None): QMainWindow.__init__(self, parent) self.console = None self.setup() def closeEvent(self, event): if self.console is not None: self.console.exit_interpreter() event.accept() def setup(self): """Setup window parameters""" self.setWindowIcon(get_icon('python.png')) self.setWindowTitle(APP_NAME) self.resize(QSize(600, 800)) # Welcome message in statusbar: status = self.statusBar() status.showMessage(_("Welcome to guiqwt application example!"), 5000) self.setupMainWidget() # File menu file_menu = self.menuBar().addMenu(_("File")) new_action = create_action(self, _("New..."), shortcut="Ctrl+N", icon=get_icon('filenew.png'), tip=_("Create a new image"), triggered=self.new_image) open_action = create_action(self, _("Open..."), shortcut="Ctrl+O", icon=get_icon('fileopen.png'), tip=_("Open an image"), triggered=self.open_image) quit_action = create_action(self, _("Quit"), shortcut="Ctrl+Q", icon=get_std_icon("DialogCloseButton"), tip=_("Quit application"), triggered=self.close) add_actions(file_menu, (new_action, open_action, None, quit_action)) processing_menu = self.menuBar().addMenu(_("Processing")) autoscale_action = create_action(self, _("Autoscale"), shortcut="Ctrl+W", tip=_("Autoscale Graph"), triggered=self.plotWidget.autoScale) add_actions(processing_menu, (autoscale_action,)) # Help menu help_menu = self.menuBar().addMenu("?") about_action = create_action(self, _("About..."), icon=get_std_icon('MessageBoxInformation'), triggered=self.about) add_actions(help_menu, (about_action,)) main_toolbar = self.addToolBar("Main") add_actions(main_toolbar, (new_action, open_action, )) self.curFIFOVal = 0 self.rdb = r.Redis('localhost') # self.setShortcuts() # self.setCentralWidget(self.plotWidget) self.setCentralWidget(self.main_dock) def setShortcuts(self): self.autoScaleAction = QAction(QIcon(), '&Autoscale', self) self.autoScaleAction.setShortcut("Ctrl+W") self.autoScaleAction.triggered.connect(self.plotWidget.autoScale) # print "initiating shortcuts" #------ def setupMainWidget(self) : self.main_dock = QDockWidget(_('')) self.addDockWidget(Qt.BottomDockWidgetArea, self.main_dock) self.dockTab = QTabWidget() dockSplitter = QSplitter() dockSplitter.setOrientation(Qt.Vertical) #----- toolbar = self.addToolBar("Curve") self.plotWidget = CentralWidget(self, toolbar) # Set central widget: self.dockTab.addTab(self.plotWidget, "Plot") #----- self.statusEdit = QTextEdit() self.statusEdit.setText("Status updates to go here.") self.statusEdit.setEnabled(False) self.statusEdit.moveCursor(QTextCursor.End) #----- self.testButton = QPushButton("Test Button") self.testButton.clicked.connect(self.__testClick__) dockSplitter.addWidget(self.testButton) dockSplitter.addWidget(self.statusEdit) self.dockTab.addTab(dockSplitter, "Status Info") if DockableConsole is None: self.console = None else: import time, scipy.signal as sps, scipy.ndimage as spi import sys, os import numpy as np ns = {'np': np, 'sps': sps, 'spi': spi, 'os': os, 'sys': sys, 'time': time} msg = "Example: np.arange(20)\n"\ "Modules imported at startup: "\ "os, sys, os.path as osp, time, "\ "numpy as np, scipy.signal as sps, scipy.ndimage as spi" self.console = DockableConsole(self, namespace=ns, message=msg) # console_dock = QDockWidget(_('Console')) # self.addDockWidget(Qt.BottomDockWidgetArea, console_dock) # console_dock.setWidget(self.console) self.dockTab.addTab(self.console, "Console") # dockSplitter.addWidget(self.console) # main_dock.setWidget(dockSplitter) self.main_dock.setWidget(self.dockTab) #------ def __testClick__(self): # self.statusEdit.append("Clicked") self.dataList = self.rdb.lrange('activeData', 0, -1) if self.curFIFOVal>20: self.curFIFOVal = 0 dataID = self.dataList[self.curFIFOVal] # metaDict, raw = WR.processDataJson(self.rdb, dataID) # metaDict, raw = WR.processData(self.rdb, dataID) metaDict, raw = WR.processDataSegmented(self.rdb, dataID) xVals = np.arange(len(raw)) self.curFIFOVal+=1 self.statusEdit.append(str(raw[0:5])) self.plotWidget.add_curve(dataID, xVals, raw) #------? def about(self): QMessageBox.about( self, _("About ")+APP_NAME, """<b>%s</b> v%s<p>%s Brian H. Clowers <br> <br>Copyright © 2016 <p>Python %s, Qt %s, PyQt %s %s %s""" % \ (APP_NAME, VERSION, _("Developped by"), platform.python_version(), QT_VERSION_STR, PYQT_VERSION_STR, _("on"), platform.system()) ) #------I/O def new_image(self): """Create a new image""" imagenew = ImageParamNew(title=_("Create a new image")) if not imagenew.edit(self): return image = ImageParam() image.title = imagenew.title if imagenew.type == 'zeros': image.data = np.zeros((imagenew.width, imagenew.height)) elif imagenew.type == 'rand': image.data = np.random.randn(imagenew.width, imagenew.height) self.mainwidget.add_image(image) def open_image(self): """Open image file""" saved_in, saved_out, saved_err = sys.stdin, sys.stdout, sys.stderr sys.stdout = None filename, _filter = getopenfilename(self, _("Open"), "", io.iohandler.get_filters('load')) sys.stdin, sys.stdout, sys.stderr = saved_in, saved_out, saved_err if filename: self.mainwidget.add_image_from_file(filename)
def __init__(self, xlabel=None, ylabel=None, winTitle=None): """ Boilerplate code for guiqwt image window. Includes qt application, x-,y-crosssection, itemlistpanel, contrast adjustment. Returns -------- win : guiqwt.plot.ImageDialog _app : PyQt4.QtGui.QApplication """ self._app = qapplication() self.win = ImageDialog(edit=False, toolbar=True, wintitle=winTitle, options=dict(xlabel=xlabel, ylabel=ylabel, yreverse=False, lock_aspect_ratio=False)) self.itemlist_panel = self.win.get_itemlist_panel() self.itemlist_panel.show() action = QAction(get_icon('busy.png'), "Reload", self.itemlist_panel) action.triggered.connect(self.reload_measurement) self.itemlist_panel.children()[-2].addAction(action) self.win.plot_widget.plot.SIG_ITEM_REMOVED.connect( self.remove_measurement) action = QAction(get_icon('save_all.png'), "Save all", self.itemlist_panel) action.triggered.connect(self.save_measurements) self.itemlist_panel.children()[-3].addAction(action) def fun(shape): shape.symbol.pen().setWidth(2) shape.symbol.setColor(QColor(255, 0, 0)) self.win.add_tool(PointTool, handle_final_shape_cb=fun) self.win.get_xcs_panel().show() self.win.get_ycs_panel().show() self.win.get_contrast_panel().show() action = QAction(get_icon('fileopen.png'), "Open measurement", self.itemlist_panel) action.triggered.connect(self.load_measurement) self.win.get_toolbar().addAction(action) self.win.get_toolbar().addAction("Load VNA measurement", self.load_VNAMeasurement) self.win.get_toolbar().addAction( "Load VNA measurement ...", self.load_VNAMeasurement_select_channels) self.win.get_toolbar().addAction( "Load VNA fields measurement ", self.load_VNASeparateFieldsMeasurement) self.win.get_toolbar().addAction("Get points", self.get_points) if peakit: self.win.get_toolbar().addAction("Fitting tool ...", self.launchFittingTool) self.fitting_controller = MeasurementController() else: self.fitting_controller = None self.operations_widget = OperationsWidget() bbfmr_operations = list( filter(None, [("bbFMR.processing.%s" % s) if "__" not in s else None for s in dir(bp)])) self.operations_widget.populate_available_operations(bbfmr_operations) self.itemlist_panel.layout().addWidget(self.operations_widget) self.itemlist_panel.listwidget.selectionModel( ).selectionChanged.connect(self.refresh_operations) self.operations_widget.operations_changed.connect( self.replot_measurement) self.plot_items = self.win.plot_widget.plot.items self.measurements = []