def _fillTable(self): self._widgets = [] for track in self.tracks: item = QTreeWidgetItem([track['name'], 'ride']) self._list_widget.addTopLevelItem(item) cb = QComboBox() cb.addItems(['ride', 'run']) cb.setFocusPolicy(Qt.ClickFocus) cb.installEventFilter(self) self._list_widget.setItemWidget(item, 1, cb) self._widgets.append(cb)
class MainWindowStart(QMainWindow, MainWindow_Pro.Ui_MainWindow): def __init__(self, parent=None): super(MainWindowStart, self).__init__(parent) # Mappers for connecting buttons and labels self.myMapper = QSignalMapper(self) self.myMapper_StyleSheet = QSignalMapper(self) # Load UI self.setupUi(self) self.regex_edits = QRegExp(r"(^[0]+$|^$)") self._filter = Filter() self.filename = QString() self.edit1_delayh.installEventFilter(self._filter) self.sizeLabel = QLabel() self.sizeLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) self.statusBar1.addPermanentWidget(self.sizeLabel) self.statusBar1.setSizeGripEnabled(False) self.create_connections() self.assign_shortcuts() self.create_tool_bar() self.update_devices_list() # self.button_stop.clicked.connect(self.stop_all) # List of valve pushbuttons self.valve_list = [ self.valve1, self.valve2, self.valve3, self.valve4, self.valve5, self.valve6, self.valve7, self.valve8 ] # GroupBoxes for grouping labels and buttons on each row, used for applying StyleSheets self.group_boxes = [ self.groupbox1, self.groupbox2, self.groupbox3, self.groupbox4, self.groupbox5, self.groupbox6, self.groupbox7, self.groupbox8 ] # List of lineEdits self.lineEdits_list = [ (self.edit1_delayh, self.edit1_delaym, self.edit1_delays, self.edit1_onh, self.edit1_onm, self.edit1_ons, self.edit1_offh, self.edit1_offm, self.edit1_offs, self.edit1_totalh, self.edit1_totalm, self.edit1_totals), (self.edit2_delayh, self.edit2_delaym, self.edit2_delays, self.edit2_onh, self.edit2_onm, self.edit2_ons, self.edit2_offh, self.edit2_offm, self.edit2_offs, self.edit2_totalh, self.edit2_totalm, self.edit2_totals), (self.edit3_delayh, self.edit3_delaym, self.edit3_delays, self.edit3_onh, self.edit3_onm, self.edit3_ons, self.edit3_offh, self.edit3_offm, self.edit3_offs, self.edit3_totalh, self.edit3_totalm, self.edit3_totals), (self.edit4_delayh, self.edit4_delaym, self.edit4_delays, self.edit4_onh, self.edit4_onm, self.edit4_ons, self.edit4_offh, self.edit4_offm, self.edit4_offs, self.edit4_totalh, self.edit4_totalm, self.edit4_totals), (self.edit5_delayh, self.edit5_delaym, self.edit5_delays, self.edit5_onh, self.edit5_onm, self.edit5_ons, self.edit5_offh, self.edit5_offm, self.edit5_offs, self.edit5_totalh, self.edit5_totalm, self.edit5_totals), (self.edit6_delayh, self.edit6_delaym, self.edit6_delays, self.edit6_onh, self.edit6_onm, self.edit6_ons, self.edit6_offh, self.edit6_offm, self.edit6_offs, self.edit6_totalh, self.edit6_totalm, self.edit6_totals), (self.edit7_delayh, self.edit7_delaym, self.edit7_delays, self.edit7_onh, self.edit7_onm, self.edit7_ons, self.edit7_offh, self.edit7_offm, self.edit7_offs, self.edit7_totalh, self.edit7_totalm, self.edit7_totals), (self.edit8_delayh, self.edit8_delaym, self.edit8_delays, self.edit8_onh, self.edit8_onm, self.edit8_ons, self.edit8_offh, self.edit8_offm, self.edit8_offs, self.edit8_totalh, self.edit8_totalm, self.edit8_totals) ] for index, editLabels in enumerate(self.lineEdits_list, 1): for index2, lineedits in enumerate(editLabels, 0): # Apply mapper (GUIObject, objectIndex) self.myMapper_StyleSheet.setMapping( self.lineEdits_list[index - 1][index2], index - 1) # Connect mapper to signal (self.lineEdits_list[index - 1][index2]).textChanged.connect( self.myMapper_StyleSheet.map) # Set event Filter, for detecting when Focus changes self.lineEdits_list[index - 1][index2].installEventFilter( self._filter) # Set Mappers for buttons (1..8) self.myMapper.setMapping(self.valve_list[index - 1], index) # Connect mapper to signal for detecting clicks on buttons (self.valve_list[index - 1]).clicked.connect(self.myMapper.map) # Connect to signal for enabling labelEdits self.myMapper.mapped['int'].connect(self.enable_fields) # Connect to signal for changing color of groupbox used for visual indication self.myMapper_StyleSheet.mapped['int'].connect(self.valve_color_status) # Create Keyboard Shortcuts def assign_shortcuts(self): self.actionArchivo_Nuevo.setShortcut(QKeySequence.New) self.action_Abrir.setShortcut(QKeySequence.Open) self.action_Guardar.setShortcut(QKeySequence.Save) self.actionGuardar_Como.setShortcut(QKeySequence.SaveAs) self.action_Limpiar.setShortcut('Ctrl+L') self.actionVAL_508_Ayuda.setShortcut(QKeySequence.HelpContents) self.action_Salir.setShortcut(QKeySequence.Close) # self.actionPreferencias.setShortcut(QKeySequence.Preferences) self.action_Detener_USB.setShortcut('Ctrl+Shift+C') self.action_Ejecutar.setShortcut('Ctrl+Shift+X') self.action_Para_Valvulas.setShortcut('Ctrl+Shift+P') # Create connections to signals def create_connections(self): self.actionArchivo_Nuevo.triggered.connect(self.new_file) self.action_Abrir.triggered.connect(self.open_file) self.action_Guardar.triggered.connect(self.save_file) self.actionGuardar_Como.triggered.connect(self.save_file_as) self.action_Limpiar.triggered.connect(self.clean_fields) self.action_Salir.triggered.connect(self.close) self.actionVAL_508_Ayuda.triggered.connect(self.show_help) self.actionAcerca_de_VAL_508.triggered.connect(self.show_about) self.action_Detener_USB.triggered.connect(self.stop_usb) self.action_Ejecutar.triggered.connect(self.execute) self.action_Para_Valvulas.triggered.connect(self.stop_all) # Creation of About Dialog def show_about(self): about = aboutdialog.AboutDialog(self) about.show() # Creation of Help Form def show_help(self): form = helpform.HelpForm('Help.html', self) form.show() def new_file(self): self.filename = QString() self.clean_fields() # Close connection to arduino before closing Program def closeEvent(self, QCloseEvent): try: self.thread_connection.serial_connection.close() logging.debug("Thread running and killed at closing program") except AttributeError: logging.debug("Thread was not running when closing program OK") def clean_fields(self): for index, editLabels in enumerate(self.lineEdits_list, 1): for index2, lineedits in enumerate(editLabels, 0): self.lineEdits_list[index - 1][index2].setText('0') def save_file_as(self): filename_copy = self.filename logging.info("Current filename: %s" % self.filename) my_home = os.path.expanduser('~') self.filename = QFileDialog.getSaveFileName( self, self.tr('Guardar como'), os.path.join(my_home, "archivo.txt"), "", "", QFileDialog.DontUseNativeDialog) logging.info("Filename to save: %s" % self.filename) if not self.filename.isNull(): if self.filename.endsWith(QString('.txt')): self.write_data_to_file('w') else: self.filename.append(QString('.txt')) messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Advertencia')) messageBox.setText( self.tr(u"El archivo ya existe, ¿Reemplazar?")) messageBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) messageBox.setIconPixmap(QPixmap(':/broken_file.png')) if messageBox.exec_() == QMessageBox.Yes: self.write_data_to_file('w') else: try: while True: self.filename = QFileDialog.getSaveFileName( self, self.tr('Guardar como'), os.path.join(my_home, "archivo.txt"), "", "", QFileDialog.DontUseNativeDialog) if self.filename.isNull(): raise Saved_Canceled() else: messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}' ) messageBox.setWindowTitle( self.tr('Advertencia')) messageBox.setText( self.tr( u"El archivo ya existe, ¿Reemplazar?")) messageBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) messageBox.setIconPixmap( QPixmap(':/broken_file.png')) if messageBox.exec_() == QMessageBox.Yes: self.write_data_to_file('w') raise Saved_Accepted() except Saved_Canceled: self.filename = filename_copy except Saved_Accepted: pass logging.info("Current filename after operation: %s" % self.filename) def save_file(self): if self.filename.isNull(): self.save_file_as() else: self.write_data_to_file('w') # Colect data for arduino def execute(self): string_data = '' list_strings = [] if str(self.arduino_combobox.currentText()): self.statusBar1.showMessage(self.tr('Conectando...')) # Gather all the contents of each row of valves and create a list of lists with them for elem_edit in self.lineEdits_list: # delay string_data = string_data + str( ((int(elem_edit[0].text()) * 3600) + (int(elem_edit[1].text()) * 60) + (int(elem_edit[2].text()))) * 1000) + ';' # ON string_data = string_data + str( ((int(elem_edit[3].text()) * 3600) + (int(elem_edit[4].text()) * 60) + (int(elem_edit[5].text()))) * 1000) + ';' # OFF string_data = string_data + str( ((int(elem_edit[6].text()) * 3600) + (int(elem_edit[7].text()) * 60) + (int(elem_edit[8].text()))) * 1000) + ';' # Total string_data = string_data + str( ((int(elem_edit[9].text()) * 3600) + (int(elem_edit[10].text()) * 60) + (int(elem_edit[11].text()))) * 1000) + ';' list_strings.append(string_data) string_data = '' # Start QThread for communicating with arduino self.thread_connection = Arduino_Communication( str(self.arduino_combobox.currentText()), list_strings) self.thread_connection.start() self.action_Ejecutar.setEnabled(False) self.action_Para_Valvulas.setEnabled(False) # Connect to current QThread instance in order to know the status of it's termination # This line used only when stopping current task self.thread_connection.finished.connect(self.finished_thread) self.thread_connection.connection_exit_status.connect( self.finished_thread) else: messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Advertencia')) messageBox.setText(self.tr("Arduino no seleccionado")) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/usb_error.png')) messageBox.exec_() # Inform QThread to stop sending data to arduino def stop_usb(self): if str(self.arduino_combobox.currentText()): try: self.statusBar1.showMessage(self.tr(u'Conexión detenida')) if self.thread_connection.isRunning(): mutex.lock() self.thread_connection.kill_serial = True mutex.unlock() except AttributeError: logging.debug("Thread not running \'disconnected! \'") else: messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Advertencia')) messageBox.setText(self.tr("Arduino no seleccionado")) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/usb_error.png')) messageBox.exec_() def enable_fields(self, index): hours_reg = QRegExp(r"0*[0-9]{1,3}") sec_reg = QRegExp(r"(0*[0-9])|(0*[0-5][0-9])") for counter, line_edit in enumerate(self.lineEdits_list[index - 1]): line_edit.setEnabled(self.valve_list[index - 1].isChecked()) if counter % 3 == 0: line_edit.setValidator(QRegExpValidator(hours_reg, self)) else: line_edit.setValidator(QRegExpValidator(sec_reg, self)) def valve_color_status(self, index): logging.info("Checking color from valve button") for edit in self.lineEdits_list[index]: if edit.text().contains(self.regex_edits): self.group_boxes[index].setStyleSheet('''QGroupBox { border: 2px solid; border-color: rgba(255, 255, 255, 0);}''' ) else: self.group_boxes[index].setStyleSheet( '''QGroupBox {background-color: rgba(103, 255, 126, 150); border: 2px solid; border-color: rgba(255, 255, 255, 255);}''' ) break def create_tool_bar(self): self.label_arduino = QLabel(self.tr('Dispositivos: ')) self.toolBar.addWidget(self.label_arduino) self.arduino_combobox = QComboBox() self.arduino_combobox.setToolTip(self.tr('Seleccionar Arduino')) self.arduino_combobox.setFocusPolicy(Qt.NoFocus) # Update List of Arduino devices self.reload = QAction(QIcon(":/reload.png"), self.tr("&Refrescar"), self) self.reload.setShortcut(QKeySequence.Refresh) self.reload.setToolTip(self.tr('Refrescar Dispositivos')) self.reload.triggered.connect(self.update_devices_list) self.toolBar.addWidget(self.arduino_combobox) self.toolBar.addAction(self.reload) # Update current usb devices connected to PC def update_devices_list(self): device_list = serial.tools.list_ports.comports() current_arduino = self.arduino_combobox.currentText() self.arduino_combobox.clear() for device_index, device in enumerate(sorted(device_list)): self.arduino_combobox.addItem(device.device) if device.device == current_arduino: self.arduino_combobox.setCurrentIndex(device_index) # Stop current arduino task def stop_all(self): if str(self.arduino_combobox.currentText()): self.thread_connection = Arduino_Communication( str(self.arduino_combobox.currentText())) self.thread_connection.start() self.action_Ejecutar.setEnabled(False) self.action_Para_Valvulas.setEnabled(False) self.action_Detener_USB.setEnabled(False) self.thread_connection.finished.connect(self.finished_thread) self.thread_connection.connection_exit_status.connect( self.finished_thread) else: messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Advertencia')) messageBox.setText(self.tr("Arduino no seleccionado")) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/usb_error.png')) messageBox.exec_() def open_file(self): try: my_home = os.path.expanduser('~') file_name = QFileDialog.getOpenFileName( self, self.tr('Abrir archivo'), my_home, '*.txt', '*.txt', QFileDialog.DontUseNativeDialog) logging.warning("file_name type: %s" % type(file_name)) list_values = [] if not file_name.isNull(): with open(file_name) as fp: for line in fp: list_values.extend([line.replace('\n', '')]) logging.info("List Content: %s" % list_values) count = 0 for elems in self.lineEdits_list: for inner_elem in elems: if not unicode(list_values[count]).isdigit(): raise Uncompatible_Data() inner_elem.setText(list_values[count]) count = count + 1 self.filename = file_name except (IOError, OSError): messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Error')) messageBox.setText(self.tr('No se pudo abrir el archivo')) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/broken_file.png')) messageBox.exec_() except (IndexError, Uncompatible_Data): messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Error')) messageBox.setText(self.tr('Formato Incompatible')) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/broken_file.png')) messageBox.exec_() # Inform the user if we were able to send data successfully to arduino def finished_thread(self, error=None, message=''): if error == 'error': messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Error')) messageBox.setText(message) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/usb_error.png')) messageBox.exec_() return elif error == 'success': messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr(u'Éxito')) messageBox.setText(message) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/usb_success.png')) messageBox.exec_() return elif error == 'stopped': messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr(u'Éxito')) messageBox.setText(message) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIconPixmap(QPixmap(':/success_general.png')) messageBox.exec_() return self.action_Ejecutar.setEnabled(True) self.action_Para_Valvulas.setEnabled(True) self.action_Detener_USB.setEnabled(True) self.statusBar1.showMessage(self.tr('Finalizado')) # Save data to disk def write_data_to_file(self, open_mode): progressDialog = QProgressDialog() progressDialog.setModal(True) progressDialog.setLabelText(self.tr('Guardando...')) progressDialog.setMaximum(8) progressDialog.setCancelButton(None) progressDialog.show() try: # File is closed automatically even on error with open(unicode(self.filename), open_mode) as file_obj: for count, elem_edit in enumerate(self.lineEdits_list, 1): file_obj.write(''.join([str(elem_edit[0].text()), '\n'])) file_obj.write(''.join([str(elem_edit[1].text()), '\n'])) file_obj.write(''.join([str(elem_edit[2].text()), '\n'])) file_obj.write(''.join([str(elem_edit[3].text()), '\n'])) file_obj.write(''.join([str(elem_edit[4].text()), '\n'])) file_obj.write(''.join([str(elem_edit[5].text()), '\n'])) file_obj.write(''.join([str(elem_edit[6].text()), '\n'])) file_obj.write(''.join([str(elem_edit[7].text()), '\n'])) file_obj.write(''.join([str(elem_edit[8].text()), '\n'])) file_obj.write(''.join([str(elem_edit[9].text()), '\n'])) file_obj.write(''.join([str(elem_edit[10].text()), '\n'])) file_obj.write(''.join([str(elem_edit[11].text()), '\n'])) progressDialog.setValue(count) except (IOError, OSError): progressDialog.close() messageBox = QMessageBox(self) messageBox.setStyleSheet( 'QMessageBox QLabel {font: bold 14pt "Cantarell";}') messageBox.setWindowTitle(self.tr('Error')) messageBox.setText(self.tr('Error al guardar')) messageBox.setStandardButtons(QMessageBox.Ok) messageBox.setIcon(QMessageBox.Critical) messageBox.exec_() else: self.statusBar1.showMessage(self.tr('Guardado'), 3000)
class Window(QMainWindow): def __init__(self, parent=None): super(Window, self).__init__(parent) global time_start, x_arr, y_arr, arduino_connected # Flag variables self.filename = '' self.array_len = len(x_arr) self.clean_recorded_data = True self.recording_status = False self.file_saved = False self.recorded_list = [] self.record_cell_start = None self.record_cell_end = None self.follow_plot = True # Window Properties self.setWindowTitle("Arduino Plotter") self.setWindowIcon(QIcon(":/window_icon.png")) self.resize(800, 600) # Plot Settings and Creation self.plot_settings = dict(plotLineWidth=1, horizontalGrid=True, verticalGrid=True, gridOpacity=1, lineColor='b', arrayPlotSize=25, serialBaud=115200, separator=' ') pg.setConfigOption('background', 'w') self.load_settings() self.createPlot() # Create Bars self.createBars() # Get list of arduino devices self.updateDevicesList() # Add Widgets to Main Window self.addWidgets() # Add bar to display status messages status = self.statusBar() self.sizeLabel = QLabel() self.sizeLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) status.addPermanentWidget(self.sizeLabel) status.setSizeGripEnabled(False) # Start Thread & program time count(x axis) time_start = time.time() self.read_serial_thread = ReadSerialThread( self.arduino_combobox.currentText(), self.plot_settings['serialBaud'], self) self.read_serial_thread.start() self.update() def load_settings(self): settings = QSettings() self.plot_settings['horizontalGrid'] = settings.value( "horizontalGrid", self.plot_settings['horizontalGrid']).toBool() self.plot_settings['verticalGrid'] = settings.value( "verticalGrid", self.plot_settings['verticalGrid']).toBool() self.plot_settings['plotLineWidth'] = settings.value( "plotLineWidth", self.plot_settings['plotLineWidth']).toInt()[0] self.plot_settings['gridOpacity'] = settings.value( "gridOpacity", self.plot_settings['gridOpacity']).toFloat()[0] self.plot_settings['lineColor'] = unicode( settings.value("lineColor", self.plot_settings['lineColor']).toString()) self.plot_settings['arrayPlotSize'] = settings.value( "arrayPlotSize", self.plot_settings['arrayPlotSize']).toInt()[0] self.plot_settings['serialBaud'] = settings.value( "serialBaud", self.plot_settings['serialBaud']).toInt()[0] self.plot_settings['separator'] = settings.value( "separator", self.plot_settings['separator']).toString() # Save settings values def closeEvent(self, event): settings = QSettings() settings.setValue('horizontalGrid', QVariant(self.plot_settings['horizontalGrid'])) settings.setValue('verticalGrid', QVariant(self.plot_settings['verticalGrid'])) settings.setValue('plotLineWidth', QVariant(self.plot_settings['plotLineWidth'])) settings.setValue('gridOpacity', QVariant(self.plot_settings['gridOpacity'])) settings.setValue('lineColor', QVariant(self.plot_settings['lineColor'])) settings.setValue('arrayPlotSize', QVariant(self.plot_settings['arrayPlotSize'])) settings.setValue('serialBaud', QVariant(self.plot_settings['serialBaud'])) settings.setValue('separator', QVariant(self.plot_settings['separator'])) # Plot Creation def createPlot(self): self.plot_zone = pg.PlotWidget() self.pen = pg.mkPen(width=self.plot_settings['plotLineWidth'], color=self.plot_settings['lineColor'][0]) self.plot_zone.plotItem.showGrid(self.plot_settings['verticalGrid'], self.plot_settings['horizontalGrid'], self.plot_settings['gridOpacity']) self.plot_zone.plotItem.ctrlMenu = None self.plot_zone.setAutoPan(True) # self.plot_zone.plotItem.ctrlMenu # self.plot_zone.plotItem.enableAutoRange(enable=0.2) # self.plot_zone.autoRange() self.plot_zone.setXRange(0, 600) # self.plot_zone.setLabels(left=('Signal', 'V'), bottom=('Time')) self.plot_zone.setYRange(0, 5) # self.plot_zone.setMouseEnabled(x=False) self.plot_zone.scene().contextMenu = None # Create Bars # TODO Add Info button def createBars(self): # Create Bar1 controls_toolbar = self.addToolBar("Controls") controls_toolbar.setObjectName("ControlsToolBar") # Create Bar2 arduino_toolbar = self.addToolBar("Arduino") arduino_toolbar.setObjectName("ArduinoToolBar") # Add Elements to Bar1 # Record & Pause self.record_pause = QAction(QIcon(":/rec.png"), "&Rec", self) self.record_pause.setShortcut("Ctrl+R") self.record_pause.setToolTip('Record') self.record_pause.triggered.connect(self.recording) # Stop self.stop = QAction(QIcon(":/stop.png"), "&Detener", self) self.stop.setShortcut("Ctrl+Alt+D") self.stop.setToolTip('Stop') self.stop.triggered.connect(self.stopRecording) # Save self.save_file = QAction(QIcon(":/save.png"), "&Save", self) self.save_file.setShortcut(QKeySequence.Save) self.save_file.setToolTip('Save') self.save_file.triggered.connect(self.saveFile) # Save As self.save_as = QAction(QIcon(":/save_as.png"), "Save As", self) self.save_as.setShortcut(QKeySequence.SaveAs) self.save_as.setToolTip('Save As') self.save_as.triggered.connect(self.saveFileAs) # Configurations self.configurations = QAction(QIcon(":/configs.png"), "&Configurations", self) self.configurations.setShortcut("Ctrl+Alt+S") self.configurations.setToolTip('Settings') self.configurations.triggered.connect(self.changeSettings) # Add buttons to bar controls_toolbar.addAction(self.record_pause) controls_toolbar.addAction(self.stop) controls_toolbar.addAction(self.save_file) controls_toolbar.addAction(self.save_as) controls_toolbar.addAction(self.configurations) # Arduino ComboBox self.arduino_combobox = QComboBox() self.arduino_combobox.setToolTip('Select Arduino') self.arduino_combobox.setFocusPolicy(Qt.NoFocus) self.arduino_combobox.activated.connect(self.updateChoosenArduino) # Update List of Arduino devices self.reload = QAction(QIcon(":/reload.png"), "Reload", self) self.reload.setShortcut(QKeySequence.Refresh) self.reload.setToolTip('Reload Devices') self.reload.triggered.connect(self.updateDevicesList) # Timer Label self.timer_label = QLabel() self.timer_label.setText(' 00:00') # Info button for dialog self.info = QAction(QIcon(":/info.png"), "Reload", self) self.info.setShortcut(QKeySequence.HelpContents) self.info.setToolTip('Help') self.info.triggered.connect(self.showInfo) # Follow checkbox self.follow_label = QLabel("Follow Plot") self.follow_checkbox = QCheckBox() # self.arduino_combobox.setToolTip('Select Arduino') self.follow_checkbox.setFocusPolicy(Qt.NoFocus) self.follow_checkbox.clicked.connect(self.change_follow_status) self.follow_checkbox.setChecked(True) arduino_toolbar.addWidget(self.arduino_combobox) arduino_toolbar.addAction(self.reload) arduino_toolbar.addWidget(self.timer_label) arduino_toolbar.addAction(self.info) arduino_toolbar.addWidget(self.follow_checkbox) arduino_toolbar.addWidget(self.follow_label) # Show Info(Help) dialog def showInfo(self): self.info_dialog = InfoDialog(self) self.info_dialog.show() def change_follow_status(self): if self.follow_checkbox.isChecked(): self.follow_plot = True else: self.follow_plot = False # Update arduino list def updateDevicesList(self): device_list = serial.tools.list_ports.comports() current_arduino = self.arduino_combobox.currentText() self.arduino_combobox.clear() device_index = 0 for device in sorted(device_list): self.arduino_combobox.addItem(device.device) if device.device == current_arduino: self.arduino_combobox.setCurrentIndex(device_index) device_index = device_index + 1 # Update selected arduino def updateChoosenArduino(self): self.restart_values() # Add Widgets def addWidgets(self): self.widget = QWidget() self.setCentralWidget(self.widget) vbox_layout = QVBoxLayout() vbox_layout.addWidget(self.plot_zone) vbox_layout.setContentsMargins(5, 5, 5, 0) self.widget.setLayout(vbox_layout) # Saves indexes of recorded items, thus saves memory def recording(self): global time_start, x_arr, y_arr, arduino_connected status = self.statusBar() # If recording is "Stopped" clear data and start recording if self.clean_recorded_data: mutex.lock() del self.recorded_list[:] del x_arr[:] del y_arr[:] self.array_len = 0 width_visible = self.plot_zone.visibleRange().width() height_visible = self.plot_zone.visibleRange().height() bottom_visible = self.plot_zone.visibleRange().top() # self.plot_zone.visibleRange().setRect(0, 0, 150, 10) # print self.plot_zone.visibleRange() rect_me = QRectF(0, 0, width_visible, 5) self.plot_zone.setRange(rect=rect_me, disableAutoRange=True, xRange=(0, (0 + width_visible)), padding=0, yRange=(bottom_visible, bottom_visible + height_visible)) self.clean_recorded_data = False mutex.unlock() # Start Recording if not self.recording_status: self.record_pause.setIcon(QIcon(':/pause.png')) status.showMessage('Recording') mutex.lock() if x_arr: self.record_cell_start = len(x_arr) - 1 else: self.record_cell_start = len(x_arr) self.recording_status = True mutex.unlock() else: # Pause Recording self.record_pause.setIcon(QIcon(':/rec.png')) status.showMessage('Paused') mutex.lock() # Check if x_arr has no data if x_arr: self.record_cell_end = len(x_arr) - 1 else: self.record_cell_end = len(x_arr) self.recorded_list.append( [self.record_cell_start, self.record_cell_end]) self.recording_status = False mutex.unlock() # Update Arduino status and plot def update(self): global x_arr, y_arr, arduino_connected # self.plot_zone.sceneObj.sigMouseHover.connect(self.me) if arduino_connected: self.sizeLabel.setText('Arduino Connected') self.sizeLabel.setStyleSheet('color:green') mutex.lock() # print ("dasdasd",len(x_arr)) # print ("self", self.array_len) #if not len(x_arr) % self.plot_settings['arrayPlotSize'] and len(x_arr) != 0: #print self.array_len if len(x_arr) - self.array_len >= 50 and len(x_arr) != 0: self.array_len = len(x_arr) try: self.plot_zone.plot( x_arr[:-(self.plot_settings['arrayPlotSize'] + 1)], y_arr[:-(self.plot_settings['arrayPlotSize'] + 1)], clear=True, pen=self.pen) except Exception: if len(x_arr) > len(y_arr): x_arr.pop() else: y_arr.pop() self.plot_zone.plot( x_arr[:-(self.plot_settings['arrayPlotSize'] + 1)], y_arr[:-(self.plot_settings['arrayPlotSize'] + 1)], clear=True, pen=self.pen) #self.plot_zone.setXRange(x_arr[-1:][0] - self.plot_zone.visibleRange().width(), x_arr[-1:][0]) if self.follow_plot: if not (self.plot_zone.visibleRange().left() < x_arr[-1:][0] < self.plot_zone.visibleRange().right()): width_visible = self.plot_zone.visibleRange().width() height_visible = self.plot_zone.visibleRange().height() bottom_visible = self.plot_zone.visibleRange().top() # self.plot_zone.visibleRange().setRect(0, 0, 150, 10) # print self.plot_zone.visibleRange() rect_me = QRectF(x_arr[-1:][0], 0, width_visible, 5) #print rect_me #self.plot_zone.setXRange(x_arr[-1:][0], x_arr[-1:][0] + self.range_x) #self.plot_zone.setRange() #print "MOVE" #print bottom_visible #print height_visible #dest = self.plot_zone.visibleRange().width() #print range_x #print dest #print x_arr[-1:][0] self.plot_zone.setRange( rect=rect_me, disableAutoRange=True, xRange=(x_arr[-1:][0], (x_arr[-1:][0] + width_visible)), padding=0, yRange=(bottom_visible, bottom_visible + height_visible)) #self.plot_zone.sceneObj.sigMouseClicked.connect(self.me) #self.plot_zone.sceneObj.mouseMoveEvent(3) #print self.plot_zone.visibleRange() #range_me = self.plot_zone.visibleRange() #self.plot_zone.sigRangeChanged.connect(self.me) #self.plot_zone.sigYRangeChanged.connect(self.me) mutex.unlock() else: self.sizeLabel.setText('Arduino Disconnected') self.sizeLabel.setStyleSheet('color:red') # Updates the GUI timer time_to_display = int(round(time.time() - time_start, 2)) if time_to_display >= 60: self.timer_label.setText(' ' + str(time_to_display / 60) + ":" + str(time_to_display % 60)) else: if len(str(time_to_display)) == 1: self.timer_label.setText(" " + '0' + ':0' + str(time_to_display)) else: self.timer_label.setText(" " + '0' + ':' + str(time_to_display)) # Call myself every 50milliseconds timer = QTimer() timer.singleShot(100, self.update) # Stops recording def stopRecording(self): mutex.lock() if self.recording_status: if x_arr: self.record_cell_end = len(x_arr) - 1 else: self.record_cell_end = len(x_arr) self.recorded_list.append( [self.record_cell_start, self.record_cell_end]) mutex.unlock() self.clean_recorded_data = True self.recording_status = False self.record_pause.setIcon(QIcon(':/rec.png')) status = self.statusBar() status.showMessage('Stopped') # Save file method def saveFile(self): if not self.file_saved: self.saveFileAs() else: self.writeDataToFile('w') # Save as method def saveFileAs(self): my_home = os.path.expanduser('~') self.filename = QFileDialog.getSaveFileName( self, 'Save As', os.path.join(my_home, "new_file.dat"), "", "", QFileDialog.DontUseNativeDialog) self.writeDataToFile('w') # Write data to file def writeDataToFile(self, open_mode): global x_arr, y_arr try: if self.filename: file_obj = open(self.filename, open_mode) for pair in self.recorded_list: list_x = x_arr[pair[0]:pair[1]] list_y = y_arr[pair[0]:pair[1]] for elem in zip(list_x, list_y): # TODO Check if separator works file_obj.write( str(elem[0]) + self.plot_settings['separator'] + str(elem[1]) + '\n') file_obj.close() self.file_saved = True except (IOError, OSError) as error_file: message = QMessageBox.critical(self, 'Message', str(error_file), QMessageBox.Ok) # message.show() self.filename = '' self.file_saved = False # Create and show settings dialog def changeSettings(self): self.settings_dialog = SettingsDialog(self.plot_settings, self.refreshSettings, self) self.settings_dialog.show() # Refresh settings def refreshSettings(self): self.pen = pg.mkPen(width=self.plot_settings['plotLineWidth'], color=self.plot_settings['lineColor'][0]) self.plot_zone.plotItem.showGrid(self.plot_settings['verticalGrid'], self.plot_settings['horizontalGrid'], self.plot_settings['gridOpacity']) # Restart values and kills when new arduino connection is selected def restart_values(self): global x_arr, y_arr print('killing') self.read_serial_thread.__del__() mutex.lock() self.array_len = 0 del x_arr[:] del y_arr[:] #print x_arr del self.recorded_list[:] #print "clean" width_visible = self.plot_zone.visibleRange().width() height_visible = self.plot_zone.visibleRange().height() bottom_visible = self.plot_zone.visibleRange().top() # self.plot_zone.visibleRange().setRect(0, 0, 150, 10) #print self.plot_zone.visibleRange() rect_me = QRectF(0, 0, width_visible, 5) self.plot_zone.setRange(rect=rect_me, disableAutoRange=True, xRange=(0, (0 + width_visible)), padding=0, yRange=(bottom_visible, bottom_visible + height_visible)) mutex.unlock() #print "clean out" self.read_serial_thread = ReadSerialThread( self.arduino_combobox.currentText(), self.plot_settings['serialBaud'], self) self.read_serial_thread.start()
def createEditor(self, parent, option, index): editor = QComboBox(parent) # Note: Qt.AscendingOrder == 0 and Qt.DescendingOrder == 1 editor.addItems(["Ascending", "Descending"]) editor.setFocusPolicy(Qt.StrongFocus) return editor
class Ui_dev_client(object): def setupUi(self, dev_client): dev_client.resize(935, 660) dev_client.setWindowTitle(QApplication.translate("dev_client", "DevClient")) self.centralwidget = QWidget(dev_client) dev_client.setCentralWidget(self.centralwidget) main_layout = QGridLayout(self.centralwidget) main_layout.setContentsMargins(5, 5, 5, 3) main_layout.setSpacing(3) main_layout.setColumnStretch(0, 1) main_layout.setRowStretch(1, 1) top_layout = QHBoxLayout() top_layout.setContentsMargins(0, 0, 0, 0) top_layout.setSpacing(5) top_label_conn = QLabel() top_label_conn.setText(QApplication.translate("dev_client", "Connection")) top_layout.addWidget(top_label_conn) self.list_conn = QComboBox() self.list_conn.setFixedSize(145, 26) self.list_conn.setFocusPolicy(Qt.NoFocus) top_layout.addWidget(self.list_conn) self.list_account = QComboBox() self.list_account.setFixedSize(145, 26) self.list_account.setFocusPolicy(Qt.NoFocus) top_layout.addWidget(self.list_account) top_layout.addItem(QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) top_label_account = QLabel() top_label_account.setText(QApplication.translate("dev_client", "Account")) top_layout.addWidget(top_label_account) self.button_connect = QPushButton() self.button_connect.setFixedSize(105, 26) self.button_connect.setFocusPolicy(Qt.NoFocus) self.button_connect.setIcon(QIcon(":/images/connect.png")) self.button_connect.setIconSize(QSize(16, 16)) self.button_connect.setText(QApplication.translate("dev_client", "Connect")) top_layout.addWidget(self.button_connect) self.button_option = QPushButton() self.button_option.setFixedSize(105, 26) self.button_option.setFocusPolicy(Qt.NoFocus) self.button_option.setIcon(QIcon(":/images/option.png")) self.button_option.setIconSize(QSize(16, 16)) self.button_option.setText(QApplication.translate("dev_client", "Option")) top_layout.addWidget(self.button_option) main_layout.addLayout(top_layout, 0, 0) right_layout = QVBoxLayout() right_layout.setContentsMargins(0, 0, 0, 0) right_layout.addItem(QSpacerItem(40, 29, QSizePolicy.Minimum, QSizePolicy.Fixed)) self.rightpanel = QWidget() self.rightpanel.setMinimumWidth(225) right_layout.addWidget(self.rightpanel) main_layout.addLayout(right_layout, 0, 1, 3, 1) self.output_splitter = QSplitter(self.centralwidget) self.output_splitter.setOrientation(Qt.Vertical) self.output_splitter.setHandleWidth(3) self.output_splitter.setChildrenCollapsible(False) self.text_output = QTextEdit(self.output_splitter) self.text_output.setMinimumWidth(690) self.text_output.setFocusPolicy(Qt.NoFocus) self.text_output.setAutoFillBackground(True) self.text_output.setUndoRedoEnabled(False) self.text_output.setReadOnly(True) self.text_output_noscroll = QTextEdit(self.output_splitter) self.text_output_noscroll.setMinimumWidth(690) self.text_output_noscroll.setFocusPolicy(Qt.NoFocus) self.text_output_noscroll.setAutoFillBackground(True) self.text_output_noscroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.text_output_noscroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.text_output_noscroll.setUndoRedoEnabled(False) self.text_output_noscroll.setReadOnly(True) main_layout.addWidget(self.output_splitter, 1, 0) bottom_layout = QHBoxLayout() bottom_layout.setContentsMargins(0, 0, 0, 0) bottom_layout.setSpacing(5) self.text_input = QComboBox() self.text_input.setMinimumWidth(660) self.text_input.setFixedHeight(25) self.text_input.setEditable(True) self.text_input.addItem("") bottom_layout.addWidget(self.text_input) self.toggle_splitter = QPushButton() self.toggle_splitter.setFixedSize(25, 25) self.toggle_splitter.setFocusPolicy(Qt.NoFocus) self.toggle_splitter.setIcon(QIcon(":/images/split-window.png")) bottom_layout.addWidget(self.toggle_splitter) main_layout.addLayout(bottom_layout, 2, 0)