def initUI(self): grid = QGridLayout() self.setLayout(grid) display = QLCDNumber(self) display.setFixedHeight(80) display.display(0) grid.addWidget(display, 0, 0, 1, 5) names = [ 'MC', 'MR', 'MS', 'M+', 'M-', '\u20D6', 'CE', 'C', '\u00B1', '\u221A', '7', '8', '9', '/', '%', '4', '5', '6', '*', '1/x', '1', '2', '3', '-', '=', '0', '', ',', '+', '' ] positions = [(i, j) for i in range(1, 7) for j in range(5)] for position, name in zip(positions, names): if name == '': continue button = QPushButton(name) if name == '0': grid.addWidget(button, 6, 0, 1, 2) elif name == '=': button.setFixedHeight(80) grid.addWidget(button, 5, 4, 2, 1) else: grid.addWidget(button, *position)
def __build_lcd_number_widget(self): """Build a LCD Number widget.""" lcdnumber = QLCDNumber(self) lcdnumber.setSegmentStyle(QLCDNumber.Filled) lcdnumber.setFixedHeight(40) lcdnumber.setFrameStyle(QFrame.NoFrame) return lcdnumber
def fillVbox(self, vbox): lcd = QLCDNumber() # lcd.setFixedSize(150, 70) lcd.setFixedHeight(150) layout = QGridLayout() vbox.addLayout(layout) label = [ 'MC', 'MR', 'MS', 'M+', 'M-', '<-', 'CE', 'C', '+/-', 'sqrt', 7, 8, 9, '/', '%', 4, 5, 6, '*', '1/x', 1, 2, 3, '-', 'x', 'x', 'x', '.', '+', 'x' ] for w in range(0, len(label)): layout.addWidget(QPushButton(str(label[w])), int(1 + w / 5), int(w % 5)) layout.addWidget(lcd, 0, 0, 1, 5) layout.addWidget(QPushButton(str("0")), 1 + 5, 0, 1, 2) layout.addWidget(QPushButton(str("\n\n=\n")), 1 + 4, 4, 2, 1)
class App(QMainWindow): def __init__(self): super().__init__() self.lcd = QLCDNumber() self.lcd.setFixedWidth(100) self.lcd.setFixedHeight(100) mySlyder = QSlider(Qt.Horizontal,self) mySlyder.setMaximun(254) mySlyder.setMinimun(0) mySlyder.setGeometry(30,40,200,30) mySlyder.valueChanged.connect(self.changedValue) self.setGeometry(50,50,320,200) self.setWindowTitle("Curso RPI4") layout = QVBoxLayout() layout.addWidget(self.lcd) layout.addWidget(mySlider) self.setLayout(layout)
class parameterWidget(QWidget): def __init__(self,minimum,maximum): super(parameterWidget,self).__init__() self.container = QVBoxLayout() self.container.addStretch(1) self.slider = QSlider(Qt.Horizontal, self) self.slider.setMinimum(minimum) self.slider.setMaximum(maximum) self.slider.setTickInterval(1) self.slider.setSingleStep(1) self.container.addWidget(self.slider) self.lcd = QLCDNumber() self.lcd.setFixedHeight(100) self.lcd.setFixedWidth(100) self.lcd.resize(50, 100) self.container.addWidget(self.lcd) self.lcd.setDigitCount(8) self.slider.valueChanged.connect(self.update_lcd) self.container.addStretch(1) self.setLayout(self.container) @pyqtSlot(int) def update_lcd(self,value): self.lcd.display(str(value))
class Run_gui(QMainWindow): def __init__(self): super().__init__() self.cwd = os.getcwd() self.load_() # Enable antialiasing for prettier plots self.initUI() def initUI(self): ################### MENU BARS START ################## MyBar = QMenuBar(self) fileMenu = MyBar.addMenu("File") self.fileSave = fileMenu.addAction("Save thinfilm config") self.fileSave.triggered.connect(self.save_) self.fileSave.setShortcut('Ctrl+S') self.fileLoadAs = fileMenu.addAction("Load config section") self.fileLoadAs.triggered.connect(self.load_config_dialog) fileClose = fileMenu.addAction("Close") fileClose.triggered.connect(self.close) # triggers closeEvent() fileClose.setShortcut('Ctrl+X') self.loadMenu = MyBar.addMenu("Load data") loadSubOlis = self.loadMenu.addAction("OLIS sub") loadSubFilmOlis = self.loadMenu.addAction("OLIS sub + thin film") loadSubFTIR = self.loadMenu.addAction("FTIR sub") loadSubFilmFTIR = self.loadMenu.addAction("FTIR sub + thin film") loadSubOlis.triggered.connect(self.loadSubOlisDialog) loadSubFilmOlis.triggered.connect(self.loadSubFilmOlisDialog) loadSubFTIR.triggered.connect(self.loadSubFTIRDialog) loadSubFilmFTIR.triggered.connect(self.loadSubFilmFTIRDialog) self.emailMenu = MyBar.addMenu("E-mail") self.emailSettings = self.emailMenu.addAction("E-mail settings") self.emailSettings.triggered.connect(self.email_set_dialog) self.emailData = self.emailMenu.addAction("E-mail data") self.emailData.triggered.connect(self.email_data_dialog) helpMenu = MyBar.addMenu("Help") helpParam = helpMenu.addAction("Instructions") helpParam.triggered.connect(self.helpParamDialog) contact = helpMenu.addAction("Contact") contact.triggered.connect(self.contactDialog) ################### MENU BARS END ################## # status info which button has been pressed Start_lbl = QLabel("PLOTS and analysis steps", self) Start_lbl.setStyleSheet("color: blue") self.Step0_Button = QPushButton("Raw data", self) self.Step0_Button.setToolTip("STEP 0. Plot raw data for OLIS and FTIR") self.button_style(self.Step0_Button, 'black') self.Step1_Button = QPushButton("Tmin and Tmax", self) self.Step1_Button.setToolTip( "STEP 1. Find all the minima and maxima positions using Gaussian filter" ) self.button_style(self.Step1_Button, 'black') self.Step2_Button = QPushButton("Std.Dev. in d", self) self.Step2_Button.setToolTip( "STEP 2. Minimize standard deviation in the film thickness d") self.button_style(self.Step2_Button, 'black') self.Step3_Button = QPushButton("Index n", self) self.Step3_Button.setToolTip( "STEP 3. Plot refractive indicies n1 and n2") self.button_style(self.Step3_Button, 'black') self.Step4_Button = QPushButton("Absorption alpha", self) self.Step4_Button.setToolTip( "STEP 4. Plot abosorption alpha based on n2") self.button_style(self.Step4_Button, 'black') self.Step5_Button = QPushButton("Wavenumber k", self) self.Step5_Button.setToolTip("STEP 5. Plot wavenumber k based on n2") self.button_style(self.Step5_Button, 'black') #################################################### # status info which button has been pressed self.NewFiles = QLabel('No files created yet!', self) self.NewFiles.setStyleSheet("color: blue") newfont = QFont("Times", 10, QFont.Normal) self.NewFiles.setFont(newfont) ''' self.NewFiles = numpy.zeros(5,dtype=object) for i in range(4): self.NewFiles[i] = QLabel(''.join([str(i+1),': ']), self) self.NewFiles[i].setStyleSheet("color: magenta") ''' #################################################### loads_lbl = QLabel("RAW data files", self) loads_lbl.setStyleSheet("color: blue") configFile_lbl = QLabel("Current thinfilm", self) self.config_file_lbl = QLabel("", self) self.config_file_lbl.setStyleSheet("color: green") loadSubOlis_lbl = QLabel("OLIS sub", self) self.loadSubOlisFile_lbl = QLabel("", self) self.loadSubOlisFile_lbl.setStyleSheet("color: magenta") loadSubFilmOlis_lbl = QLabel("OLIS sub + thin film", self) self.loadSubFilmOlisFile_lbl = QLabel("", self) self.loadSubFilmOlisFile_lbl.setStyleSheet("color: magenta") loadSubFTIR_lbl = QLabel("FTIR sub", self) self.loadSubFTIRFile_lbl = QLabel("", self) self.loadSubFTIRFile_lbl.setStyleSheet("color: magenta") loadSubFilmFTIR_lbl = QLabel("FTIR sub + thin film", self) self.loadSubFilmFTIRFile_lbl = QLabel("", self) self.loadSubFilmFTIRFile_lbl.setStyleSheet("color: magenta") self.cb_sub_olis = QCheckBox('', self) self.cb_sub_olis.toggle() self.cb_subfilm_olis = QCheckBox('', self) self.cb_subfilm_olis.toggle() self.cb_sub_ftir = QCheckBox('', self) self.cb_sub_ftir.toggle() self.cb_subfilm_ftir = QCheckBox('', self) self.cb_subfilm_ftir.toggle() plot_X_lbl = QLabel("Plot X axis in", self) self.combo2 = QComboBox(self) self.mylist2 = ["eV", "nm"] self.combo2.addItems(self.mylist2) self.combo2.setFixedWidth(70) #################################################### lbl1 = QLabel("GAUSSIAN filter settings", self) lbl1.setStyleSheet("color: blue") interpol_lbl = QLabel("Interpolation method", self) self.combo4 = QComboBox(self) self.mylist4 = ["spline", "linear"] self.combo4.setToolTip( "Interpolation method for local minima Tmin and local maxima Tmax can only be linear or spline." ) self.combo4.addItems(self.mylist4) self.combo4.setFixedWidth(70) factors_lbl = QLabel("Gaussian factors", self) self.factorsEdit = QLineEdit("", self) self.factorsEdit.setToolTip( "HIGH gaussian factor = broadband noise filtering.\nLOW gaussian factor = narrowband noise filtering.\nHigh gauissian factors (>2) will result in relatively large deviation from the raw data.\nGauissian factors of zero or near zero (<0.5) will closely follow trend of the raw data." ) self.factorsEdit.setFixedWidth(200) borders_lbl = QLabel("Gaussian borders [eV]", self) self.bordersEdit = QLineEdit("", self) self.bordersEdit.setToolTip( "Gaussian borders should be typed in ascending order and the number of\nborders is always one more compared with the number of Gaussian factors." ) self.bordersEdit.setFixedWidth(200) ############################################## lbl2 = QLabel("ABSORPTION alpha and n1 and n2", self) lbl2.setStyleSheet("color: blue") poly_lbl = QLabel("Polyfit order", self) self.combo1 = QComboBox(self) self.mylist1 = ["1", "2", "3", "4", "5"] self.combo1.addItems(self.mylist1) self.combo1.setFixedWidth(70) polybord_lbl = QLabel("Polyfit range(s) [eV]", self) self.poly_bordersEdit = QLineEdit("", self) self.poly_bordersEdit.setFixedWidth(140) self.cb_polybord = QCheckBox('', self) self.cb_polybord.toggle() ignore_data_lbl = QLabel("No. of ignored points", self) self.ignore_data_ptsEdit = QLineEdit("", self) self.ignore_data_ptsEdit.setFixedWidth(140) corr_slit_lbl = QLabel("Correction slit width [nm]", self) self.corr_slitEdit = QLineEdit("", self) self.corr_slitEdit.setToolTip( "Finite spectrometer bandwidth (slit width) in the transmission spectrum." ) self.corr_slitEdit.setFixedWidth(140) ############################################## lbl4 = QLabel("STORAGE location (folder/file)", self) lbl4.setStyleSheet("color: blue") self.filenameEdit = QLineEdit("", self) #self.filenameEdit.setFixedWidth(180) self.cb_save_figs = QCheckBox('Save figs', self) self.cb_save_figs.toggle() ############################################## self.lcd = QLCDNumber(self) self.lcd.setStyleSheet("color: red") self.lcd.setFixedHeight(60) self.lcd.setSegmentStyle(QLCDNumber.Flat) self.lcd.setToolTip("Timetrace for saving files") self.lcd.setNumDigits(11) ############################################## self.initUI_() ############################################## # Add all widgets g1_0 = QGridLayout() g1_0.addWidget(MyBar, 0, 0) g1_1 = QGridLayout() g1_1.addWidget(loads_lbl, 0, 0) g1_1.addWidget(configFile_lbl, 1, 0) g1_1.addWidget(self.config_file_lbl, 1, 1) g1_1.addWidget(loadSubOlis_lbl, 2, 0) g1_1.addWidget(self.loadSubOlisFile_lbl, 2, 1) g1_1.addWidget(self.cb_sub_olis, 2, 2) g1_1.addWidget(loadSubFilmOlis_lbl, 3, 0) g1_1.addWidget(self.loadSubFilmOlisFile_lbl, 3, 1) g1_1.addWidget(self.cb_subfilm_olis, 3, 2) g1_1.addWidget(loadSubFTIR_lbl, 4, 0) g1_1.addWidget(self.loadSubFTIRFile_lbl, 4, 1) g1_1.addWidget(self.cb_sub_ftir, 4, 2) g1_1.addWidget(loadSubFilmFTIR_lbl, 5, 0) g1_1.addWidget(self.loadSubFilmFTIRFile_lbl, 5, 1) g1_1.addWidget(self.cb_subfilm_ftir, 5, 2) g1_1.addWidget(plot_X_lbl, 6, 0) g1_1.addWidget(self.combo2, 6, 1) g1_2 = QGridLayout() g1_2.addWidget(lbl1, 0, 0) g1_3 = QGridLayout() g1_3.addWidget(interpol_lbl, 0, 0) g1_3.addWidget(self.combo4, 0, 1) g1_3.addWidget(factors_lbl, 1, 0) g1_3.addWidget(self.factorsEdit, 1, 1) g1_3.addWidget(borders_lbl, 2, 0) g1_3.addWidget(self.bordersEdit, 2, 1) g1_4 = QGridLayout() g1_4.addWidget(lbl2, 0, 0) g1_5 = QGridLayout() g1_5.addWidget(poly_lbl, 0, 0) g1_5.addWidget(self.combo1, 0, 1) g1_5.addWidget(polybord_lbl, 1, 0) g1_5.addWidget(self.poly_bordersEdit, 1, 1) g1_5.addWidget(self.cb_polybord, 1, 2) g1_5.addWidget(ignore_data_lbl, 2, 0) g1_5.addWidget(self.ignore_data_ptsEdit, 2, 1) g1_5.addWidget(corr_slit_lbl, 3, 0) g1_5.addWidget(self.corr_slitEdit, 3, 1) g4_0 = QGridLayout() g4_0.addWidget(lbl4, 0, 0) g4_0.addWidget(self.cb_save_figs, 0, 1) g4_1 = QGridLayout() g4_1.addWidget(self.filenameEdit, 0, 0) v1 = QVBoxLayout() v1.addLayout(g1_0) v1.addLayout(g1_1) v1.addLayout(g1_2) v1.addLayout(g1_3) v1.addLayout(g1_4) v1.addLayout(g1_5) v1.addLayout(g4_0) v1.addLayout(g4_1) ################################################### g1_6 = QGridLayout() g1_6.addWidget(Start_lbl, 0, 0) g1_7 = QGridLayout() g1_7.addWidget(self.Step0_Button, 0, 0) g1_7.addWidget(self.Step1_Button, 1, 0) g1_7.addWidget(self.Step2_Button, 2, 0) g1_7.addWidget(self.Step3_Button, 3, 0) g1_7.addWidget(self.Step4_Button, 4, 0) g1_7.addWidget(self.Step5_Button, 5, 0) g1_8 = QGridLayout() g1_8.addWidget(self.NewFiles, 0, 0) g1_8.addWidget(self.lcd, 1, 0) v0 = QVBoxLayout() v0.addLayout(g1_6) v0.addLayout(g1_7) v0.addLayout(g1_8) # SET ALL VERTICAL COLUMNS TOGETHER hbox = QHBoxLayout() hbox.addLayout(v1) hbox.addLayout(v0) ############################################################################### # reacts to choises picked in the menu self.combo1.activated[str].connect(self.onActivated1) self.combo2.activated[str].connect(self.onActivated2) self.combo4.activated[str].connect(self.onActivated4) # reacts to choises picked in the menu self.Step0_Button.clicked.connect(self.set_run) self.Step1_Button.clicked.connect(self.set_run) self.Step2_Button.clicked.connect(self.set_run) self.Step3_Button.clicked.connect(self.set_run) self.Step4_Button.clicked.connect(self.set_run) self.Step5_Button.clicked.connect(self.set_run) # reacts to choises picked in the checkbox self.cb_sub_olis.stateChanged.connect(self.sub_olis_check) self.cb_subfilm_olis.stateChanged.connect(self.subfilm_olis_check) self.cb_sub_ftir.stateChanged.connect(self.sub_ftir_check) self.cb_subfilm_ftir.stateChanged.connect(self.subfilm_ftir_check) self.cb_save_figs.stateChanged.connect(self.save_figs_check) self.cb_polybord.stateChanged.connect(self.polybord_check) self.threadpool = QThreadPool() print("Multithreading in TEST_gui_v1 with maximum %d threads" % self.threadpool.maxThreadCount()) self.isRunning = False self.move(0, 0) #self.setGeometry(50, 50, 800, 500) hbox.setSizeConstraint(hbox.SetFixedSize) self.setWindowTitle("Swanepoel method for thin film analysis") w = QWidget() w.setLayout(hbox) self.setCentralWidget(w) self.show() def bool_(self, txt): if txt == "True": return True elif txt == "False": return False def initUI_(self): self.config_file_lbl.setText(self.last_used_scan) self.loadSubOlisFile_lbl.setText(self.loadSubOlis_str) self.loadSubFilmOlisFile_lbl.setText(self.loadSubFilmOlis_str) self.loadSubFTIRFile_lbl.setText(self.loadSubFTIR_str) self.loadSubFilmFTIRFile_lbl.setText(self.loadSubFilmFTIR_str) ############################################## self.sub_olis_check(self.loadSubOlis_check) self.cb_sub_olis.setChecked(self.loadSubOlis_check) self.subfilm_olis_check(self.loadSubFilmOlis_check) self.cb_subfilm_olis.setChecked(self.loadSubFilmOlis_check) self.sub_ftir_check(self.loadSubFTIR_check) self.cb_sub_ftir.setChecked(self.loadSubFTIR_check) self.subfilm_ftir_check(self.loadSubFilmFTIR_check) self.cb_subfilm_ftir.setChecked(self.loadSubFilmFTIR_check) self.save_figs_check(self.save_figs) self.cb_save_figs.setChecked(self.save_figs) self.filenameEdit.setText(self.filename_str) ############################################## if len(self.fit_poly_ranges) == 0: self.fit_poly_ranges_check = False self.polybord_check(self.fit_poly_ranges_check) self.cb_polybord.setChecked(self.fit_poly_ranges_check) else: self.polybord_check(self.fit_poly_ranges_check) self.cb_polybord.setChecked(self.fit_poly_ranges_check) ############################################## self.factorsEdit.setText(self.gaussian_factors) self.bordersEdit.setText(self.gaussian_borders) ############################################## self.combo1.setCurrentIndex(self.mylist1.index(self.fit_poly_order)) self.combo2.setCurrentIndex(self.mylist2.index(self.plot_X)) self.combo4.setCurrentIndex(self.mylist4.index(self.fit_linear_spline)) ############################################## self.poly_bordersEdit.setText(self.fit_poly_ranges) self.ignore_data_ptsEdit.setText(self.ignore_data_pts) self.corr_slitEdit.setText(self.corr_slit) ############################################## self.NewFiles.setToolTip(''.join([ "Display newly created and saved files in ", os.sep, self.filename_str, os.sep ])) self.lcd.display(self.timetrace) def button_style(self, button, color): button.setStyleSheet(''.join([ 'QPushButton {background-color: lightblue; font-size: 18pt; color: ', color, '}' ])) button.setFixedWidth(260) button.setFixedHeight(65) def loadSubOlisDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog files, _ = QFileDialog.getOpenFileNames( self, "Open files", ''.join(['data', os.sep]), "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)", options=options) for afile in files: head, tail = os.path.split(str(afile)) self.loadSubOlis_str = tail self.loadSubOlisFile_lbl.setText(tail) self.cb_sub_olis.setEnabled(True) self.loadSubOlis_check = True self.cb_sub_olis(self.loadSubOlis_check) def loadSubFilmOlisDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog files, _ = QFileDialog.getOpenFileNames( self, "Open files", ''.join(['data', os.sep]), "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)", options=options) for afile in files: head, tail = os.path.split(str(afile)) self.loadSubFilmOlis_str = tail self.loadSubFilmOlisFile_lbl.setText(tail) self.cb_subfilm_olis.setEnabled(True) self.loadSubFilmOlis_check = True self.cb_subfilm_olis(self.loadSubFilmOlis_check) def loadSubFTIRDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog files, _ = QFileDialog.getOpenFileNames( self, "Open files", ''.join(['data', os.sep]), "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)", options=options) for afile in files: head, tail = os.path.split(str(afile)) self.loadSubFTIR_str = tail self.loadSubFTIRFile_lbl.setText(tail) self.cb_sub_ftir.setEnabled(True) self.loadSubFTIR_check = True self.cb_sub_ftir(self.loadSubFTIR_check) def loadSubFilmFTIRDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog files, _ = QFileDialog.getOpenFileNames( self, "Open files", ''.join(['data', os.sep]), "All Files (*);;Dat Files (*.dat);;Text Files (*.txt)", options=options) for afile in files: head, tail = os.path.split(str(afile)) self.loadSubFilmFTIR_str = tail self.loadSubFilmFTIRFile_lbl.setText(tail) self.cb_subfilm_ftir.setEnabled(True) self.loadSubFilmFTIR_check = True self.cb_subfilm_ftir.setChecked(self.loadSubFilmFTIR_check) def load_config_dialog(self): self.Load_config_dialog = Load_config_dialog.Load_config_dialog( self, self.config, self.load_, self.initUI_, self.cwd) self.Load_config_dialog.exec() def email_data_dialog(self): self.Send_email_dialog = Send_email_dialog.Send_email_dialog( self, self.cwd) self.Send_email_dialog.exec() def email_set_dialog(self): self.Email_dialog = Email_settings_dialog.Email_dialog( self, self.lcd, self.cwd) self.Email_dialog.exec() def helpParamDialog(self): helpfile = '' with open('config_Swanepoel_forklaringer.py', 'r') as f: for line in f: helpfile = helpfile + line msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText( "Apply the Swanepoel method using the following analysis steps:") msg.setInformativeText(helpfile) msg.setWindowTitle("Help") #msg.setDetailedText(helpfile) msg.setStandardButtons(QMessageBox.Ok) #msg.setGeometry(1000, 0, 1000+250, 350) msg.exec_() def contactDialog(self): QMessageBox.information( self, "Contact information", "Suggestions, comments or bugs can be reported to [email protected]" ) def onActivated1(self, text): self.fit_poly_order = int(text) def onActivated2(self, text): self.plot_X = str(text) def onActivated4(self, text): self.fit_linear_spline = str(text) def save_figs_check(self, state): if state in [Qt.Checked, True]: self.save_figs = True else: self.save_figs = False def sub_olis_check(self, state): if state in [Qt.Checked, True]: self.loadSubOlis_check = True self.loadSubOlisFile_lbl.setStyleSheet("color: magenta") self.cb_sub_olis.setText('incl') else: self.loadSubOlis_check = False self.loadSubOlisFile_lbl.setStyleSheet("color: grey") self.cb_sub_olis.setText('exc') def subfilm_olis_check(self, state): if state in [Qt.Checked, True]: self.loadSubFilmOlis_check = True self.loadSubFilmOlisFile_lbl.setStyleSheet("color: magenta") self.cb_subfilm_olis.setText('incl') else: self.loadSubFilmOlis_check = False self.loadSubFilmOlisFile_lbl.setStyleSheet("color: grey") self.cb_subfilm_olis.setText('exc') def sub_ftir_check(self, state): if state in [Qt.Checked, True]: self.loadSubFTIR_check = True self.loadSubFTIRFile_lbl.setStyleSheet("color: magenta") self.cb_sub_ftir.setText('incl') else: self.loadSubFTIR_check = False self.loadSubFTIRFile_lbl.setStyleSheet("color: grey") self.cb_sub_ftir.setText('exc') def subfilm_ftir_check(self, state): if state in [Qt.Checked, True]: self.loadSubFilmFTIR_check = True self.loadSubFilmFTIRFile_lbl.setStyleSheet("color: magenta") self.cb_subfilm_ftir.setText('incl') else: self.loadSubFilmFTIR_check = False self.loadSubFilmFTIRFile_lbl.setStyleSheet("color: grey") self.cb_subfilm_ftir.setText('exc') def polybord_check(self, state): if state in [Qt.Checked, True]: self.fit_poly_ranges_check = True self.poly_bordersEdit.setEnabled(True) self.cb_polybord.setText('incl') else: self.fit_poly_ranges_check = False self.poly_bordersEdit.setEnabled(False) self.cb_polybord.setText('exc') ############################################################ # Check input if a number, ie. digits or fractions such as 3.141 # Source: http://www.pythoncentral.io/how-to-check-if-a-string-is-a-number-in-python-including-unicode/ def is_int(self, s): try: int(s) return True except ValueError: return False def is_number(self, s): try: float(s) return True except ValueError: pass try: import unicodedata unicodedata.numeric(s) return True except (TypeError, ValueError): pass return False def create_file(self, mystr): head, ext = os.path.splitext(mystr) totalpath = ''.join([self.cwd, os.sep, head, '_', self.timetrace]) my_dir = os.path.dirname(totalpath) if not os.path.isdir(my_dir): QMessageBox.warning( self, "Message", "".join(["Folder(s) named ", my_dir, " will be created!"])) try: os.makedirs(my_dir, exist_ok=True) except Exception as e: QMessageBox.critical( self, "Message", "".join(["Folder named ", head, " not valid!\n\n", str(e)])) return "" return totalpath def set_run(self): # Save all the currently changed varaibles self.save_() # Register the sender of the command (a button or similar) sender = self.sender() ## gaussian_borders and gaussian_factors warnings and errors gaus_bord = str(self.bordersEdit.text()).split(',') for tal in gaus_bord: if not self.is_number(tal): QMessageBox.critical(self, 'Message', "Gaussian borders must be real numbers!") return elif float(tal) < 0.0: QMessageBox.critical( self, 'Message', "Gaussian borders must be positive or zero!") return if len(gaus_bord) < 2: QMessageBox.critical( self, 'Message', "You must enter at least 2 gaussian borders!") return if not numpy.array_equal([numpy.float(i) for i in gaus_bord], numpy.sort( [numpy.float(i) for i in gaus_bord])): QMessageBox.critical( self, 'Message', "The gaussian borders must be entered in the ascending order!") return gaus_fact = str(self.factorsEdit.text()).split(',') for tal in gaus_fact: if not self.is_number(tal): QMessageBox.critical(self, 'Message', "Gaussian factors must be real numbers!") return elif float(tal) < 0.0: QMessageBox.critical( self, 'Message', "Gaussian factors must be positive or zero!") return if len(gaus_fact) < 1: QMessageBox.critical(self, 'Message', "You must enter at least 1 gaussian factor!") return if len(gaus_bord) != len(gaus_fact) + 1: QMessageBox.critical( self, 'Message', "The number of gaussian factors is exactly one less than the number of gaussian borders!" ) return ## ignored data points warnings and errors ign_pts = str(self.ignore_data_ptsEdit.text()) if not self.is_int(ign_pts): QMessageBox.critical( self, 'Message', "The number of ignored points is an integer!") return elif int(ign_pts) < 0: QMessageBox.critical( self, 'Message', "The number of ignored points is a positive integer!") return ## correction slit width warnings and errors corr_pts = str(self.corr_slitEdit.text()) if not self.is_number(corr_pts): QMessageBox.critical( self, 'Message', "The correction slit width is a real number!") return elif float(corr_pts) < 0: QMessageBox.critical( self, 'Message', "The correction slit width is a positive number!") return ## fit_poly_ranges warnings and errors if self.fit_poly_ranges_check == True: polyfit_bord = str(self.poly_bordersEdit.text()).split(',') for tal in polyfit_bord: if not self.is_number(tal): QMessageBox.critical( self, 'Message', "The polyfit range enteries must be real numbers!") return elif float(tal) < 0.0: QMessageBox.critical( self, 'Message', "The polyfit range enteries must be positive or zero!") return if len(polyfit_bord) < 2 or len(polyfit_bord) % 2 != 0: QMessageBox.critical( self, 'Message', "The polyfit range list accepts minimum 2 or even number of enteries!" ) return if not numpy.array_equal( [numpy.float(i) for i in polyfit_bord], numpy.sort([numpy.float(i) for i in polyfit_bord])): QMessageBox.critical( self, 'Message', "The polyfit range list must be entered in ascending order!" ) return # When all user defined enteries are approved save the data self.create_file(str(self.filenameEdit.text())) if sender.text() != 'Raw data': ## raw data files warnings and errors if not self.loadSubOlis_check and not self.loadSubFilmOlis_check: pass elif self.loadSubOlis_check and self.loadSubFilmOlis_check: pass else: QMessageBox.critical( self, 'Message', "Select both OLIS data files subfilmRAW and subRAW!") return if not self.loadSubFTIR_check and not self.loadSubFilmFTIR_check: pass elif self.loadSubFTIR_check and self.loadSubFilmFTIR_check: pass else: QMessageBox.critical( self, 'Message', "Select both FTIR data files subfilmRAW and subRAW!") return if not self.loadSubOlis_check and not self.loadSubFilmOlis_check and not self.loadSubFTIR_check and not self.loadSubFilmFTIR_check: QMessageBox.critical(self, 'Message', "No data files selected!") return if sender.text() == 'Raw data': if not self.loadSubOlis_check and not self.loadSubFilmOlis_check and not self.loadSubFTIR_check and not self.loadSubFilmFTIR_check: QMessageBox.critical(self, 'Message', "No raw data files selected!") return self.button_style(self.Step0_Button, 'red') self.button_style(self.Step1_Button, 'grey') self.button_style(self.Step2_Button, 'grey') self.button_style(self.Step3_Button, 'grey') self.button_style(self.Step4_Button, 'grey') self.button_style(self.Step5_Button, 'grey') elif sender.text() == 'Tmin and Tmax': self.button_style(self.Step1_Button, 'red') self.button_style(self.Step0_Button, 'grey') self.button_style(self.Step2_Button, 'grey') self.button_style(self.Step3_Button, 'grey') self.button_style(self.Step4_Button, 'grey') self.button_style(self.Step5_Button, 'grey') elif sender.text() == 'Std.Dev. in d': self.button_style(self.Step2_Button, 'red') self.button_style(self.Step0_Button, 'grey') self.button_style(self.Step1_Button, 'grey') self.button_style(self.Step3_Button, 'grey') self.button_style(self.Step4_Button, 'grey') self.button_style(self.Step5_Button, 'grey') elif sender.text() == 'Index n': self.button_style(self.Step3_Button, 'red') self.button_style(self.Step0_Button, 'grey') self.button_style(self.Step1_Button, 'grey') self.button_style(self.Step2_Button, 'grey') self.button_style(self.Step4_Button, 'grey') self.button_style(self.Step5_Button, 'grey') elif sender.text() == 'Absorption alpha': self.button_style(self.Step4_Button, 'red') self.button_style(self.Step0_Button, 'grey') self.button_style(self.Step1_Button, 'grey') self.button_style(self.Step2_Button, 'grey') self.button_style(self.Step3_Button, 'grey') self.button_style(self.Step5_Button, 'grey') elif sender.text() == 'Wavenumber k': self.button_style(self.Step5_Button, 'red') self.button_style(self.Step0_Button, 'grey') self.button_style(self.Step1_Button, 'grey') self.button_style(self.Step2_Button, 'grey') self.button_style(self.Step3_Button, 'grey') self.button_style(self.Step4_Button, 'grey') else: return worker = Worker(sender.text(), self.cwd) worker.signals.pass_plots.connect(self.pass_plots) worker.signals.critical.connect(self.critical) worker.signals.finished.connect(self.finished) # Execute self.threadpool.start(worker) self.isRunning = True def pass_plots(self, obj): self.my_plots, sender = obj my_str = 'Data files:\n' try: self.datafiles = self.my_plots.make_plots() for i, ii in zip(self.datafiles, range(len(self.datafiles))): head, tail = os.path.split(i) my_str += ''.join([str(ii + 1), ': ', tail, '\n']) self.NewFiles.setText(my_str) self.my_plots.show_plots() except Exception as inst: QMessageBox.critical(self, 'Message', str(inst)) def load_(self): # Initial read of the config file self.config = configparser.ConfigParser() try: self.config.read(''.join([self.cwd, os.sep, "config.ini"])) self.last_used_scan = self.config.get('LastScan', 'last_used_scan') self.loadSubOlis_str = self.config.get( self.last_used_scan, "loadsubolis").strip().split(':')[0] self.loadSubOlis_check = self.bool_( self.config.get(self.last_used_scan, 'loadsubolis').strip().split(':')[1]) self.loadSubFilmOlis_str = self.config.get( self.last_used_scan, 'loadsubfilmolis').strip().split(':')[0] self.loadSubFilmOlis_check = self.bool_( self.config.get(self.last_used_scan, 'loadsubfilmolis').strip().split(':')[1]) self.loadSubFTIR_str = self.config.get( self.last_used_scan, 'loadsubftir').strip().split(':')[0] self.loadSubFTIR_check = self.bool_( self.config.get(self.last_used_scan, 'loadsubftir').strip().split(':')[1]) self.loadSubFilmFTIR_str = self.config.get( self.last_used_scan, 'loadsubfilmftir').strip().split(':')[0] self.loadSubFilmFTIR_check = self.bool_( self.config.get(self.last_used_scan, 'loadsubfilmftir').strip().split(':')[1]) self.fit_linear_spline = self.config.get(self.last_used_scan, 'fit_linear_spline') self.gaussian_factors = self.config.get(self.last_used_scan, 'gaussian_factors') self.gaussian_borders = self.config.get(self.last_used_scan, 'gaussian_borders') self.ignore_data_pts = self.config.get(self.last_used_scan, 'ignore_data_pts') self.corr_slit = self.config.get(self.last_used_scan, 'corr_slit') self.fit_poly_order = self.config.get(self.last_used_scan, 'fit_poly_order') self.fit_poly_ranges = self.config.get( self.last_used_scan, 'fit_poly_ranges').strip().split(':')[0] self.fit_poly_ranges_check = self.bool_( self.config.get(self.last_used_scan, 'fit_poly_ranges').strip().split(':')[1]) self.filename_str = self.config.get(self.last_used_scan, 'filename') self.timetrace = self.config.get(self.last_used_scan, 'timetrace') self.save_figs = self.bool_( self.config.get(self.last_used_scan, 'save_figs')) self.plot_X = self.config.get(self.last_used_scan, 'plot_x') self.emailset_str = self.config.get(self.last_used_scan, 'emailset').strip().split(',') self.emailrec_str = self.config.get(self.last_used_scan, 'emailrec').strip().split(',') except configparser.NoOptionError as nov: QMessageBox.critical( self, 'Message', ''.join([ "Main FAULT while reading the config.ini file\n", str(nov) ])) raise def save_(self): self.timetrace = time.strftime("%y%m%d-%H%M") self.lcd.display(self.timetrace) self.config.read(''.join([self.cwd, os.sep, "config.ini"])) self.config.set('LastScan', "last_used_scan", self.last_used_scan) self.config.set( self.last_used_scan, "loadSubOlis", ':'.join([self.loadSubOlis_str, str(self.loadSubOlis_check)])) self.config.set( self.last_used_scan, "loadSubFilmOlis", ':'.join( [self.loadSubFilmOlis_str, str(self.loadSubFilmOlis_check)])) self.config.set( self.last_used_scan, "loadSubFTIR", ':'.join([self.loadSubFTIR_str, str(self.loadSubFTIR_check)])) self.config.set( self.last_used_scan, "loadSubFilmFTIR", ':'.join( [self.loadSubFilmFTIR_str, str(self.loadSubFilmFTIR_check)])) self.config.set(self.last_used_scan, "fit_linear_spline", self.fit_linear_spline) self.config.set(self.last_used_scan, "gaussian_factors", str(self.factorsEdit.text())) self.config.set(self.last_used_scan, "gaussian_borders", str(self.bordersEdit.text())) self.config.set(self.last_used_scan, "ignore_data_pts", str(self.ignore_data_ptsEdit.text())) self.config.set(self.last_used_scan, "corr_slit", str(self.corr_slitEdit.text())) self.config.set(self.last_used_scan, "fit_poly_order", str(self.fit_poly_order)) self.config.set( self.last_used_scan, "fit_poly_ranges", ':'.join([ str(self.poly_bordersEdit.text()), str(self.fit_poly_ranges_check) ])) self.config.set(self.last_used_scan, "filename", str(self.filenameEdit.text())) self.config.set(self.last_used_scan, "timetrace", self.timetrace) self.config.set(self.last_used_scan, "save_figs", str(self.save_figs)) self.config.set(self.last_used_scan, "plot_x", self.plot_X) with open(''.join([self.cwd, os.sep, "config.ini"]), "w") as configfile: self.config.write(configfile) def finished(self): self.my_plots.close_plots() self.load_() if self.emailset_str[1] == "yes": self.send_notif() if self.emailset_str[2] == "yes": self.send_data() self.button_style(self.Step0_Button, 'black') self.button_style(self.Step1_Button, 'black') self.button_style(self.Step2_Button, 'black') self.button_style(self.Step3_Button, 'black') self.button_style(self.Step4_Button, 'black') self.button_style(self.Step5_Button, 'black') self.isRunning = False def allButtons_torf(self, trueorfalse, *argv): if argv[0] == 'allfalse': self.cb_sub_olis.setEnabled(False) self.cb_subfilm_olis.setEnabled(False) self.cb_sub_ftir.setEnabled(False) self.cb_subfilm_ftir.setEnabled(False) self.poly_bordersEdit.setEnabled(False) self.fileSave.setEnabled(trueorfalse) self.loadMenu.setEnabled(trueorfalse) self.emailMenu.setEnabled(trueorfalse) self.cb_save_figs.setEnabled(trueorfalse) self.cb_polybord.setEnabled(trueorfalse) self.Step0_Button.setEnabled(trueorfalse) self.Step1_Button.setEnabled(trueorfalse) self.Step2_Button.setEnabled(trueorfalse) self.Step3_Button.setEnabled(trueorfalse) self.Step4_Button.setEnabled(trueorfalse) self.Step5_Button.setEnabled(trueorfalse) self.combo1.setEnabled(trueorfalse) self.combo2.setEnabled(trueorfalse) self.combo4.setEnabled(trueorfalse) self.factorsEdit.setEnabled(trueorfalse) self.bordersEdit.setEnabled(trueorfalse) self.ignore_data_ptsEdit.setEnabled(trueorfalse) self.corr_slitEdit.setEnabled(trueorfalse) self.filenameEdit.setEnabled(trueorfalse) def warning(self, mystr): QMessageBox.warning(self, "Message", mystr) def send_notif(self): contents = [ "The scan is done. Please visit the experiment site and make sure that all light sources are switched off." ] subject = "The scan is done" obj = type( "obj", (object, ), { "subject": subject, "contents": contents, "settings": self.emailset_str, "receivers": self.emailrec_str }) worker = Send_Email_Worker(obj) worker.signals.critical.connect(self.critical) worker.signals.warning.connect(self.warning) worker.signals.finished.connect(self.finished1) # Execute self.md = Indicator_dialog.Indicator_dialog( self, "...sending notification...", "indicators/ajax-loader-ball.gif") self.threadpool.start(worker) self.isRunning = True def send_data(self): contents = [ "The scan is done and the logged data is attached to this email. Please visit the experiment site and make sure that all light sources are switched off." ] contents.extend(self.datafiles) subject = "The scan data from the latest scan!" obj = type( "obj", (object, ), { "subject": subject, "contents": contents, "settings": self.emailset_str, "receivers": self.emailrec_str }) worker = Send_Email_Worker(obj) worker.signals.critical.connect(self.critical) worker.signals.warning.connect(self.warning) worker.signals.finished.connect(self.finished1) # Execute self.md = Indicator_dialog.Indicator_dialog( self, "...sending files...", "indicators/ajax-loader-ball.gif") self.threadpool.start(worker) self.isRunning = True def finished1(self): self.isRunning = False self.md.close_() def critical(self, mystr): QMessageBox.critical(self, 'Message', mystr) def closeEvent(self, event): reply = QMessageBox.question(self, 'Message', "Quit now?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: if self.isRunning: QMessageBox.warning( self, 'Message', "Analysis in progress. Wait the analysis to finish and then quit!" ) event.ignore() else: event.accept() elif reply == QMessageBox.No: event.ignore()
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setupTrayicon() self.setupVariables() self.setupUi() self.setupConnections() self.show() def setupVariables(self): settings = QSettings() self.workEndTime = QTime( int(settings.value(workHoursKey, 0)), int(settings.value(workMinutesKey, 25)), int(settings.value(workSecondsKey, 0)), ) self.restEndTime = QTime( int(settings.value(restHoursKey, 0)), int(settings.value(restMinutesKey, 5)), int(settings.value(restSecondsKey, 0)), ) self.timeFormat = "hh:mm:ss" self.time = QTime(0, 0, 0, 0) self.workTime = QTime(0, 0, 0, 0) self.restTime = QTime(0, 0, 0, 0) self.totalTime = QTime(0, 0, 0, 0) self.currentMode = Mode.work self.maxRepetitions = -1 self.currentRepetitions = 0 def setupConnections(self): """ Create button connections """ self.startButton.clicked.connect(self.startTimer) self.startButton.clicked.connect( lambda: self.startButton.setDisabled(True)) self.startButton.clicked.connect( lambda: self.pauseButton.setDisabled(False)) self.startButton.clicked.connect( lambda: self.resetButton.setDisabled(False)) self.pauseButton.clicked.connect(self.pauseTimer) self.pauseButton.clicked.connect( lambda: self.startButton.setDisabled(False)) self.pauseButton.clicked.connect( lambda: self.pauseButton.setDisabled(True)) self.pauseButton.clicked.connect( lambda: self.resetButton.setDisabled(False)) self.pauseButton.clicked.connect( lambda: self.startButton.setText("continue")) self.resetButton.clicked.connect(self.resetTimer) self.resetButton.clicked.connect( lambda: self.startButton.setDisabled(False)) self.resetButton.clicked.connect( lambda: self.pauseButton.setDisabled(True)) self.resetButton.clicked.connect( lambda: self.resetButton.setDisabled(True)) self.resetButton.clicked.connect( lambda: self.startButton.setText("start")) self.acceptTaskButton.pressed.connect(self.insertTask) self.deleteTaskButton.pressed.connect(self.deleteTask) """ Create spinbox connections """ self.workHoursSpinBox.valueChanged.connect(self.updateWorkEndTime) self.workMinutesSpinBox.valueChanged.connect(self.updateWorkEndTime) self.workSecondsSpinBox.valueChanged.connect(self.updateWorkEndTime) self.restHoursSpinBox.valueChanged.connect(self.updateRestEndTime) self.restMinutesSpinBox.valueChanged.connect(self.updateRestEndTime) self.restSecondsSpinBox.valueChanged.connect(self.updateRestEndTime) self.repetitionsSpinBox.valueChanged.connect(self.updateMaxRepetitions) """ Create combobox connections """ self.modeComboBox.currentTextChanged.connect(self.updateCurrentMode) """ Create tablewidget connections """ self.tasksTableWidget.cellDoubleClicked.connect( self.markTaskAsFinished) def setupUi(self): self.size_policy = sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) """ Create tabwidget """ self.tabWidget = QTabWidget() """ Create tab widgets """ timerWidget = self.setupTimerTab() tasksWidget = self.setupTasksTab() statisticsWidget = self.setupStatisticsTab() """ add tab widgets to tabwidget""" self.timerTab = self.tabWidget.addTab(timerWidget, makeIcon("timer"), "Timer") self.tasksTab = self.tabWidget.addTab(tasksWidget, makeIcon("tasks"), "Tasks") self.statisticsTab = self.tabWidget.addTab(statisticsWidget, makeIcon("statistics"), "Statistics") """ Set mainwindows central widget """ self.setCentralWidget(self.tabWidget) def setupTimerTab(self): settings = QSettings() self.timerContainer = QWidget(self) self.timerContainerLayout = QVBoxLayout(self.timerContainer) self.timerContainer.setLayout(self.timerContainerLayout) """ Create work groupbox""" self.workGroupBox = QGroupBox("Work") self.workGroupBoxLayout = QHBoxLayout(self.workGroupBox) self.workGroupBox.setLayout(self.workGroupBoxLayout) self.workHoursSpinBox = QSpinBox( minimum=0, maximum=24, value=int(settings.value(workHoursKey, 0)), suffix="h", sizePolicy=self.size_policy, ) self.workMinutesSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(workMinutesKey, 25)), suffix="m", sizePolicy=self.size_policy, ) self.workSecondsSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(workSecondsKey, 0)), suffix="s", sizePolicy=self.size_policy, ) """ Create rest groupbox""" self.restGroupBox = QGroupBox("Rest") self.restGroupBoxLayout = QHBoxLayout(self.restGroupBox) self.restGroupBox.setLayout(self.restGroupBoxLayout) self.restHoursSpinBox = QSpinBox( minimum=0, maximum=24, value=int(settings.value(restHoursKey, 0)), suffix="h", sizePolicy=self.size_policy, ) self.restMinutesSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(restMinutesKey, 5)), suffix="m", sizePolicy=self.size_policy, ) self.restSecondsSpinBox = QSpinBox( minimum=0, maximum=60, value=int(settings.value(restSecondsKey, 0)), suffix="s", sizePolicy=self.size_policy, ) self.restGroupBoxLayout.addWidget(self.restHoursSpinBox) self.restGroupBoxLayout.addWidget(self.restMinutesSpinBox) self.restGroupBoxLayout.addWidget(self.restSecondsSpinBox) """ Create other groupbox""" self.otherGroupBox = QGroupBox("Other") self.otherGroupBoxLayout = QHBoxLayout(self.otherGroupBox) self.otherGroupBox.setLayout(self.otherGroupBoxLayout) self.repetitionsLabel = QLabel("Repetitions") self.repetitionsSpinBox = QSpinBox( minimum=0, maximum=10000, value=0, sizePolicy=self.size_policy, specialValueText="∞", ) self.modeLabel = QLabel("Mode") self.modeComboBox = QComboBox(sizePolicy=self.size_policy) self.modeComboBox.addItems(["work", "rest"]) self.otherGroupBoxLayout.addWidget(self.repetitionsLabel) self.otherGroupBoxLayout.addWidget(self.repetitionsSpinBox) self.otherGroupBoxLayout.addWidget(self.modeLabel) self.otherGroupBoxLayout.addWidget(self.modeComboBox) """ Create timer groupbox""" self.lcdDisplayGroupBox = QGroupBox("Time") self.lcdDisplayGroupBoxLayout = QHBoxLayout(self.lcdDisplayGroupBox) self.lcdDisplayGroupBox.setLayout(self.lcdDisplayGroupBoxLayout) self.timeDisplay = QLCDNumber(8, sizePolicy=self.size_policy) self.timeDisplay.setFixedHeight(100) self.timeDisplay.display("00:00:00") self.lcdDisplayGroupBoxLayout.addWidget(self.timeDisplay) """ Create pause, start and reset buttons""" self.buttonContainer = QWidget() self.buttonContainerLayout = QHBoxLayout(self.buttonContainer) self.buttonContainer.setLayout(self.buttonContainerLayout) self.startButton = self.makeButton("start", disabled=False) self.resetButton = self.makeButton("reset") self.pauseButton = self.makeButton("pause") """ Add widgets to container """ self.workGroupBoxLayout.addWidget(self.workHoursSpinBox) self.workGroupBoxLayout.addWidget(self.workMinutesSpinBox) self.workGroupBoxLayout.addWidget(self.workSecondsSpinBox) self.timerContainerLayout.addWidget(self.workGroupBox) self.timerContainerLayout.addWidget(self.restGroupBox) self.timerContainerLayout.addWidget(self.otherGroupBox) self.timerContainerLayout.addWidget(self.lcdDisplayGroupBox) self.buttonContainerLayout.addWidget(self.pauseButton) self.buttonContainerLayout.addWidget(self.startButton) self.buttonContainerLayout.addWidget(self.resetButton) self.timerContainerLayout.addWidget(self.buttonContainer) return self.timerContainer def setupTasksTab(self): settings = QSettings() """ Create vertical tasks container """ self.tasksWidget = QWidget(self.tabWidget) self.tasksWidgetLayout = QVBoxLayout(self.tasksWidget) self.tasksWidget.setLayout(self.tasksWidgetLayout) """ Create horizontal input container """ self.inputContainer = QWidget() self.inputContainer.setFixedHeight(50) self.inputContainerLayout = QHBoxLayout(self.inputContainer) self.inputContainerLayout.setContentsMargins(0, 0, 0, 0) self.inputContainer.setLayout(self.inputContainerLayout) """ Create text edit """ self.taskTextEdit = QTextEdit( placeholderText="Describe your task briefly.", undoRedoEnabled=True) """ Create vertical buttons container """ self.inputButtonContainer = QWidget() self.inputButtonContainerLayout = QVBoxLayout( self.inputButtonContainer) self.inputButtonContainerLayout.setContentsMargins(0, 0, 0, 0) self.inputButtonContainer.setLayout(self.inputButtonContainerLayout) """ Create buttons """ self.acceptTaskButton = QToolButton(icon=makeIcon("check")) self.deleteTaskButton = QToolButton(icon=makeIcon("trash")) """ Create tasks tablewidget """ self.tasksTableWidget = QTableWidget(0, 1) self.tasksTableWidget.setHorizontalHeaderLabels(["Tasks"]) self.tasksTableWidget.horizontalHeader().setStretchLastSection(True) self.tasksTableWidget.verticalHeader().setVisible(False) self.tasksTableWidget.setWordWrap(True) self.tasksTableWidget.setTextElideMode(Qt.ElideNone) self.tasksTableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tasksTableWidget.setSelectionMode( QAbstractItemView.SingleSelection) self.insertTasks(*settings.value(tasksKey, [])) """ Add widgets to container widgets """ self.inputButtonContainerLayout.addWidget(self.acceptTaskButton) self.inputButtonContainerLayout.addWidget(self.deleteTaskButton) self.inputContainerLayout.addWidget(self.taskTextEdit) self.inputContainerLayout.addWidget(self.inputButtonContainer) self.tasksWidgetLayout.addWidget(self.inputContainer) self.tasksWidgetLayout.addWidget(self.tasksTableWidget) return self.tasksWidget def setupStatisticsTab(self): """ Create statistics container """ self.statisticsContainer = QWidget() self.statisticsContainerLayout = QVBoxLayout(self.statisticsContainer) self.statisticsContainer.setLayout(self.statisticsContainerLayout) """ Create work time groupbox """ self.statisticsWorkTimeGroupBox = QGroupBox("Work Time") self.statisticsWorkTimeGroupBoxLayout = QHBoxLayout() self.statisticsWorkTimeGroupBox.setLayout( self.statisticsWorkTimeGroupBoxLayout) self.statisticsWorkTimeDisplay = QLCDNumber(8) self.statisticsWorkTimeDisplay.display("00:00:00") self.statisticsWorkTimeGroupBoxLayout.addWidget( self.statisticsWorkTimeDisplay) """ Create rest time groupbox """ self.statisticsRestTimeGroupBox = QGroupBox("Rest Time") self.statisticsRestTimeGroupBoxLayout = QHBoxLayout() self.statisticsRestTimeGroupBox.setLayout( self.statisticsRestTimeGroupBoxLayout) self.statisticsRestTimeDisplay = QLCDNumber(8) self.statisticsRestTimeDisplay.display("00:00:00") self.statisticsRestTimeGroupBoxLayout.addWidget( self.statisticsRestTimeDisplay) """ Create total time groupbox """ self.statisticsTotalTimeGroupBox = QGroupBox("Total Time") self.statisticsTotalTimeGroupBoxLayout = QHBoxLayout() self.statisticsTotalTimeGroupBox.setLayout( self.statisticsTotalTimeGroupBoxLayout) self.statisticsTotalTimeDisplay = QLCDNumber(8) self.statisticsTotalTimeDisplay.display("00:00:00") self.statisticsTotalTimeGroupBoxLayout.addWidget( self.statisticsTotalTimeDisplay) """ Add widgets to container """ self.statisticsContainerLayout.addWidget( self.statisticsTotalTimeGroupBox) self.statisticsContainerLayout.addWidget( self.statisticsWorkTimeGroupBox) self.statisticsContainerLayout.addWidget( self.statisticsRestTimeGroupBox) return self.statisticsContainer def setupTrayicon(self): self.trayIcon = QSystemTrayIcon(makeIcon("tomato")) self.trayIcon.setContextMenu(QMenu()) self.quitAction = self.trayIcon.contextMenu().addAction( makeIcon("exit"), "Quit", self.exit) self.quitAction.triggered.connect(self.exit) self.trayIcon.activated.connect(self.onActivate) self.trayIcon.show() def leaveEvent(self, event): super(MainWindow, self).leaveEvent(event) self.tasksTableWidget.clearSelection() def closeEvent(self, event): super(MainWindow, self).closeEvent(event) settings = QSettings() settings.setValue(workHoursKey, self.workHoursSpinBox.value()) settings.setValue( workMinutesKey, self.workMinutesSpinBox.value(), ) settings.setValue( workSecondsKey, self.workSecondsSpinBox.value(), ) settings.setValue(restHoursKey, self.restHoursSpinBox.value()) settings.setValue( restMinutesKey, self.restMinutesSpinBox.value(), ) settings.setValue( restSecondsKey, self.restSecondsSpinBox.value(), ) tasks = [] for i in range(self.tasksTableWidget.rowCount()): item = self.tasksTableWidget.item(i, 0) if not item.font().strikeOut(): tasks.append(item.text()) settings.setValue(tasksKey, tasks) def startTimer(self): try: if not self.timer.isActive(): self.createTimer() except: self.createTimer() def createTimer(self): self.timer = QTimer() self.timer.timeout.connect(self.updateTime) self.timer.timeout.connect(self.maybeChangeMode) self.timer.setInterval(1000) self.timer.setSingleShot(False) self.timer.start() def pauseTimer(self): try: self.timer.stop() self.timer.disconnect() except: pass def resetTimer(self): try: self.pauseTimer() self.time = QTime(0, 0, 0, 0) self.displayTime() except: pass def maybeStartTimer(self): if self.currentRepetitions != self.maxRepetitions: self.startTimer() started = True else: self.currentRepetitions = 0 started = False return started def updateWorkEndTime(self): self.workEndTime = QTime( self.workHoursSpinBox.value(), self.workMinutesSpinBox.value(), self.workSecondsSpinBox.value(), ) def updateRestEndTime(self): self.restEndTime = QTime( self.restHoursSpinBox.value(), self.restMinutesSpinBox.value(), self.restSecondsSpinBox.value(), ) def updateCurrentMode(self, mode: str): self.currentMode = Mode.work if mode == "work" else Mode.rest def updateTime(self): self.time = self.time.addSecs(1) self.totalTime = self.totalTime.addSecs(1) if self.modeComboBox.currentText() == "work": self.workTime = self.workTime.addSecs(1) else: self.restTime = self.restTime.addSecs(1) self.displayTime() def updateMaxRepetitions(self, value): if value == 0: self.currentRepetitions = 0 self.maxRepetitions = -1 else: self.maxRepetitions = 2 * value def maybeChangeMode(self): if self.currentMode is Mode.work and self.time >= self.workEndTime: self.resetTimer() self.modeComboBox.setCurrentIndex(1) self.incrementCurrentRepetitions() started = self.maybeStartTimer() self.showWindowMessage( Status.workFinished if started else Status.repetitionsReached) elif self.currentMode is Mode.rest and self.time >= self.restEndTime: self.resetTimer() self.modeComboBox.setCurrentIndex(0) self.incrementCurrentRepetitions() started = self.maybeStartTimer() self.showWindowMessage( Status.restFinished if started else Status.repetitionsReached) def incrementCurrentRepetitions(self): if self.maxRepetitions > 0: self.currentRepetitions += 1 def insertTask(self): task = self.taskTextEdit.toPlainText() self.insertTasks(task) def insertTasks(self, *tasks): for task in tasks: if task: rowCount = self.tasksTableWidget.rowCount() self.tasksTableWidget.setRowCount(rowCount + 1) self.tasksTableWidget.setItem(rowCount, 0, QTableWidgetItem(task)) self.tasksTableWidget.resizeRowsToContents() self.taskTextEdit.clear() def deleteTask(self): selectedIndexes = self.tasksTableWidget.selectedIndexes() if selectedIndexes: self.tasksTableWidget.removeRow(selectedIndexes[0].row()) def markTaskAsFinished(self, row, col): item = self.tasksTableWidget.item(row, col) font = self.tasksTableWidget.item(row, col).font() font.setStrikeOut(False if item.font().strikeOut() else True) item.setFont(font) def displayTime(self): self.timeDisplay.display(self.time.toString(self.timeFormat)) self.statisticsRestTimeDisplay.display( self.restTime.toString(self.timeFormat)) self.statisticsWorkTimeDisplay.display( self.workTime.toString(self.timeFormat)) self.statisticsTotalTimeDisplay.display( self.totalTime.toString(self.timeFormat)) def showWindowMessage(self, status): if status is Status.workFinished: self.trayIcon.showMessage("Break", choice(work_finished_phrases), makeIcon("tomato")) elif status is Status.restFinished: self.trayIcon.showMessage("Work", choice(rest_finished_phrases), makeIcon("tomato")) else: self.trayIcon.showMessage("Finished", choice(pomodoro_finished_phrases), makeIcon("tomato")) self.resetButton.click() def makeButton(self, text, iconName=None, disabled=True): button = QPushButton(text, sizePolicy=self.size_policy) if iconName: button.setIcon(makeIcon(iconName)) button.setDisabled(disabled) return button def exit(self): self.close() app = QApplication.instance() if app: app.quit() def onActivate(self, reason): if reason == QSystemTrayIcon.Trigger: self.show()
class ToolBar(QToolBar): def __init__(self, appctxt, params, parent): super(ToolBar, self).__init__(parent) self.appctxt = appctxt self.params = params self.setIconSize(QSize(30, 30)) self.playPause = QAction("Play/Pause (Space)", self) self.playPause.setShortcut(Qt.Key_Space) self.playPause.setShortcutContext(Qt.ApplicationShortcut) self.playPause.setIcon( QtGui.QIcon(self.appctxt.get_resource("Images/svg/play.svg"))) self.reset = QAction("Reset Memory (Ctrl+R)", self) self.reset.setShortcut("Ctrl+R") self.reset.setShortcutContext(Qt.ApplicationShortcut) self.reset.setIcon( QIcon(self.appctxt.get_resource("Images/svg/reset.svg"))) self.condition = QAction("Condition (Ctrl+C)", self) self.condition.setShortcut("Ctrl+C") self.condition.setShortcutContext(Qt.ApplicationShortcut) self.condition.setIcon( QIcon(self.appctxt.get_resource("Images/svg/upload.svg"))) self.preferences = QAction("Preferences (Ctrl+P)", self) self.preferences.setShortcut("Ctrl+P") self.preferences.setShortcutContext(Qt.ApplicationShortcut) self.preferences.setIcon( QIcon(self.appctxt.get_resource("Images/svg/settingsBlueBig.svg"))) self.save = QAction("Save (Ctrl+S)", self) self.save.setShortcut("Ctrl+S") self.save.setShortcutContext(Qt.ApplicationShortcut) self.save.setIcon( QIcon(self.appctxt.get_resource("Images/svg/save.svg"))) self.lcd = QLCDNumber(self) self.lcd.display(1) self.lcd.setDigitCount(1) self.lcd.setFixedHeight(35) self.lcd.setFixedWidth(35) #sld.valueChanged.connect(self.lineEdit.setText()) # # get the palette # palette = self.lcd.palette() # # foreground color # palette.setColor(palette.WindowText, QtGui.QColor(85, 85, 255)) # # background color # palette.setColor(palette.Background, QtGui.QColor(0, 170, 255)) # # "light" border # palette.setColor(palette.Light, QtGui.QColor(255, 0, 0)) # # "dark" border # palette.setColor(palette.Dark, QtGui.QColor(0, 255, 0)) # # set the palette # self.lcd.setPalette(palette) self.bpmBox = QSpinBox(self) self.bpmBox.setSuffix(" BPM") #self.bpmBox.setMinimumSize(30,30) self.bpmBox.setFixedHeight(35) self.bpmBox.setRange(20, 150) self.bpmBox.setSingleStep(5) self.bpmBox.setValue(self.params['metronome']["BPM"]) # self.enforce = QAction("Enforce",self) # self.enforce.setShortcut("Ctrl+E") # self.enforce.setShortcutContext(Qt.ApplicationShortcut) # self.clear = QAction("Clear",self) # #self.clear.setShortcut("Ctrl+E") # self.clear.setShortcutContext(Qt.ApplicationShortcut) #self.enforce.setIcon(QIcon(self.appctxt.get_resource("Images/reset.svg"))) #self.toolbarAction.setStatusTip("STARTPAUSE") #self.toolbarAction.setWhatsThis("srgsr") self.addAction(self.playPause) self.addAction(self.reset) self.addAction(self.condition) self.addAction(self.preferences) self.addAction(self.save) self.addWidget(self.bpmBox) self.addWidget(self.lcd) self.keyIndicator = QLabel(" ", objectName='keyIndicator')
class WheelBox(QWidget): valueChanged = pyqtSignal('double', name="valueChanged") def __init__(self, title, min, max, stepSize, parent): super().__init__(parent) self.__d_number = QLCDNumber(self) self.__d_number.setSegmentStyle(QLCDNumber.Filled) self.__d_number.setAutoFillBackground(True) self.__d_number.setFixedHeight(self.__d_number.sizeHint().height() * 2) self.__d_number.setFocusPolicy(Qt.WheelFocus) pal = QPalette(Qt.black) pal.setColor(QPalette.WindowText, Qt.green) self.__d_number.setPalette(pal) self.__d_wheel = Wheel(self) self.__d_wheel.setOrientation(Qt.Vertical) self.__d_wheel.setInverted(True) self.__d_wheel.setRange(min, max) self.__d_wheel.setSingleStep(stepSize) self.__d_wheel.setPageStepCount(5) self.__d_wheel.setFixedHeight(self.__d_number.height()) self.__d_number.setFocusProxy(self.__d_wheel) font = QFont("Helvetica", 10) font.setBold(True) self.__d_label = QLabel(title, self) self.__d_label.setFont(font) hLayout = QHBoxLayout() hLayout.setContentsMargins(0, 0, 0, 0) hLayout.setSpacing(2) hLayout.addWidget(self.__d_number, 10) hLayout.addWidget(self.__d_wheel) vLayout = QVBoxLayout(self) vLayout.addLayout(hLayout, 10) vLayout.addWidget(self.__d_label, 0, Qt.AlignTop | Qt.AlignHCenter) self.__d_wheel.valueChanged.connect(self.display) self.__d_wheel.valueChanged.connect(self.valueChanged) def display(self, value): self.__d_number.display(value) def theme(self): return self.__d_wheel.palette().color(QPalette.Window) def setTheme(self, color): self.__d_wheel.setPalette(QPalette(color)) def setValue(self, value): self.__d_wheel.setValue(value) self.__d_number.display(value) def value(self): return self.__d_wheel.value() theme = pyqtProperty(QColor, theme, setTheme)
class Timer(QDialog): timeout = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.time=0 self.timeInterval = 1000 #默认秒 self.timerUp = QTimer() self.timerUp.setInterval(self.timeInterval) self.timerUp.timeout.connect(self.updateUptime) self.timerDown = QTimer() self.timerDown.setInterval(self.timeInterval) self.timerDown.timeout.connect(self.updateDowntime) self.initUi() self.buttonStart.clicked.connect(self.timerUp.start) self.buttonStop.clicked.connect(self.timerUp.stop) self.buttonReset.clicked.connect(self.reset) self.buttonCountDown.clicked.connect(self.timerDown.start) self.buttonStopAlarm.clicked.connect(self.timerDown.stop) self.timeSpinBox.valueChanged.connect(self.settimer) def initUi(self): mainLayout = QVBoxLayout() self.setLayout(mainLayout) self.groupBox = QGroupBox("unit") self.radioButton1 = QRadioButton("s") self.radioButton1.toggled.connect(self.setUnit) self.radioButton2 = QRadioButton("0.1s") self.radioButton2.toggled.connect(self.setUnit) self.radioButton3 = QRadioButton("0.01s") self.radioButton3.toggled.connect(self.setUnit) self.radioButton4 = QRadioButton("1ms") self.radioButton4.toggled.connect(self.setUnit) self.radioButton1.setChecked(True) self.unitLayout = QHBoxLayout() self.unitLayout.addWidget(self.radioButton1) self.unitLayout.addWidget(self.radioButton2) self.unitLayout.addWidget(self.radioButton3) self.unitLayout.addWidget(self.radioButton4) self.groupBox.setLayout(self.unitLayout) mainLayout.addWidget(self.groupBox) self.buttonStart = QPushButton(self.tr("start")) mainLayout.addWidget(self.buttonStart) self.buttonStop = QPushButton(self.tr("stop")) mainLayout.addWidget(self.buttonStop) self.timeViewer = QLCDNumber() self.timeViewer.setFixedHeight(45) mainLayout.addWidget(self.timeViewer) self.timeForHuman = QLabel() mainLayout.addWidget(self.timeForHuman) self.buttonReset = QPushButton(self.tr("reset")) mainLayout.addWidget(self.buttonReset) self.timeSpinBox = QSpinBox() self.timeSpinBox.setRange(0,10000) mainLayout.addWidget(self.timeSpinBox) self.buttonCountDown = QPushButton(self.tr("countdown")) mainLayout.addWidget(self.buttonCountDown) self.buttonStopAlarm = QPushButton(self.tr("stopalarm")) mainLayout.addWidget(self.buttonStopAlarm) def setUnit(self): if self.radioButton1.isChecked(): self.timeInterval = 1000 elif self.radioButton2.isChecked(): self.timeInterval = 100 elif self.radioButton3.isChecked(): self.timeInterval = 10 elif self.radioButton1.isChecked(): self.timeInterval = 1 self.timerUp.setInterval(self.timeInterval) self.timerDown.setInterval(self.timeInterval) def updateUptime(self): self.time += 1 self.settimer(self.time) print(self.time) def updateDowntime(self): self.time =self.time-1 self.settimer(self.time) print(self.time) if self.time <=0: self.timeout.emit() def settimer(self,int): self.time=int self.timeViewer.display(self.time) if self.timeInterval ==1000: self.timeForHuman.setText(time.strftime('%H hour %M minute %S second',time.gmtime(self.time))) elif self.timeInterval ==100: self.timeForHuman.setText(time.strftime('%H hour %M minute %S second',time.gmtime(self.time/10))) elif self.timeInterval ==10: self.timeForHuman.setText(time.strftime('%H hour %M minute %S second',time.gmtime(self.time/100))) elif self.timeInterval ==1: self.timeForHuman.setText(time.strftime('%H hour %M minute %S second',time.gmtime(self.time/1000))) def reset(self): self.time=0 self.settimer(self.time)
class GameGUI(QMainWindow): BEFORE_START = 0 RUNNING = 1 PAUSED = 2 OVER = 3 sgn_game_over = pyqtSignal() sgn_update_score = pyqtSignal(int) def __init__(self, speed=1000): super().__init__() self.speed = speed # flag self.game_status = self.BEFORE_START # 0:未开始 1:正在运行 2:暂停 3:游戏结束 # signal self.sgn_game_over.connect(self.game_over) self.sgn_update_score.connect(self.update_score) # gui self.board = None self.next_panel = None self.score_ui = None self.timer = None self.init_gui() self.start() def init_gui(self, width_block=10, height_block=22, grid_size=20): center_widget = QWidget() h_layout = QHBoxLayout() self.board = Board(None, grid_size, width_block, height_block) self.next_panel = NextBlockPanel(None, grid_size, self.board.core.next_shape) self.score_ui = QLCDNumber(self) self.score_ui.setDigitCount(6) self.score_ui.setSegmentStyle(QLCDNumber.Flat) self.score_ui.setFixedHeight(50) self.score_ui.display(0) right_widget = QWidget() right_layout = QVBoxLayout() right_layout.addWidget(self.next_panel, 0, Qt.AlignCenter | Qt.AlignTop) right_layout.addWidget(QLabel("<h3>Score</h3>"), 0, Qt.AlignLeft | Qt.AlignTop) right_layout.addWidget(self.score_ui, 1, Qt.AlignCenter | Qt.AlignTop) right_layout.setSpacing(0) right_widget.setLayout(right_layout) h_layout.addWidget(self.board) h_layout.addWidget(right_widget) h_layout.setSpacing(0) self.timer = QBasicTimer() self.setFocusPolicy(Qt.StrongFocus) self.setWindowTitle('Tetris') center_widget.setFixedSize(self.board.width() + self.next_panel.width() + 30, self.board.height()+15) self.setFixedSize(center_widget.width(), center_widget.height()) center_widget.setLayout(h_layout) self.setCentralWidget(center_widget) print(self.dockOptions()) self.show() def start(self): self.board.core.remove_lines() self.board.core.generate_next_shape() self.next_panel.set_shape(self.board.core.next_shape) self.game_status = self.RUNNING self.timer.start(self.speed, self) self.update() def update_window(self): self.board.update() self.next_panel.update() # self.score_ui.update() self.update() def next_block(self): if self.board.core.merge_board(): self.board.core.remove_lines() self.sgn_update_score.emit(self.board.core.score) self.board.core.generate_next_shape() self.next_panel.set_shape(self.board.core.next_shape) return True else: self.sgn_game_over.emit() return False def game_over(self): print('close') self.close() def update_score(self, score): self.score_ui.display(score) def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if self.board.core.move_down(): pass else: self.next_block() self.update_window() else: super().timerEvent(event) def keyPressEvent(self, event): if self.game_status == self.RUNNING: key = event.key() if key in {Qt.Key_Left, Qt.Key_A}: self.board.core.move_left() self.update_window() return elif key in {Qt.Key_Right, Qt.Key_D}: self.board.core.move_right() self.update_window() return elif key in {Qt.Key_Up, Qt.Key_W}: self.board.core.rotate_right() self.update_window() return elif key in {Qt.Key_Down, Qt.Key_S}: if not self.board.core.move_down(): self.next_block() self.update_window() super().keyPressEvent(event) return
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() settings = QSettings() self.setup_trayicon() self.setup_ui() self.update_work_end_time() self.update_rest_end_time() self.setup_connections() self.timeFormat = "hh:mm:ss" self.time = QTime(0, 0, 0, 0) self.workTime = QTime(0, 0, 0, 0) self.restTime = QTime(0, 0, 0, 0) self.totalTime = QTime(0, 0, 0, 0) self.currentMode = Mode.work self.maxRepetitions = -1 self.currentRepetitions = 0 self.show() def leaveEvent(self, event): super(MainWindow, self).leaveEvent(event) self.tasksTableWidget.clearSelection() def closeEvent(self, event): super(MainWindow, self).closeEvent(event) settings = QSettings() settings.setValue("timer/work/hours", self.workHoursSpinBox.value()) settings.setValue("timer/work/minutes", self.workMinutesSpinBox.value()) settings.setValue("timer/work/seconds", self.workSecondsSpinBox.value()) settings.setValue("timer/rest/hours", self.restHoursSpinBox.value()) settings.setValue("timer/rest/minutes", self.restMinutesSpinBox.value()) settings.setValue("timer/rest/seconds", self.restSecondsSpinBox.value()) tasks = [] for i in range(self.tasksTableWidget.rowCount()): item = self.tasksTableWidget.item(i, 0) if not item.font().strikeOut(): tasks.append(item.text()) settings.setValue("tasks/tasks", tasks) def start_timer(self): try: if not self.timer.isActive(): self.create_timer() except: self.create_timer() def create_timer(self): self.timer = QTimer() self.timer.timeout.connect(self.update_time) self.timer.timeout.connect(self.maybe_change_mode) self.timer.setInterval(1000) self.timer.setSingleShot(False) self.timer.start() def pause_timer(self): try: self.timer.stop() self.timer.disconnect() except: pass def reset_timer(self): try: self.pause_timer() self.time = QTime(0, 0, 0, 0) self.display_time() except: pass def maybe_start_timer(self): if self.currentRepetitions != self.maxRepetitions: self.start_timer() started = True else: self.currentRepetitions = 0 started = False return started def update_work_end_time(self): self.workEndTime = QTime(self.workHoursSpinBox.value(), self.workMinutesSpinBox.value(), self.workSecondsSpinBox.value()) def update_rest_end_time(self): self.restEndTime = QTime(self.restHoursSpinBox.value(), self.restMinutesSpinBox.value(), self.restSecondsSpinBox.value()) def update_current_mode(self, mode: str): self.currentMode = Mode.work if mode == "work" else Mode.rest def update_time(self): self.time = self.time.addSecs(1) self.totalTime = self.totalTime.addSecs(1) if self.modeComboBox.currentText() == "work": self.workTime = self.workTime.addSecs(1) else: self.restTime = self.restTime.addSecs(1) self.display_time() def update_max_repetitions(self, value): if value == 0: self.currentRepetitions = 0 self.maxRepetitions = -1 else: self.maxRepetitions = 2 * value def maybe_change_mode(self): if self.currentMode is Mode.work and self.time >= self.workEndTime: self.reset_timer() self.modeComboBox.setCurrentIndex(1) self.increment_current_repetitions() started = self.maybe_start_timer() self.show_window_message( Status.workFinished if started else Status.repetitionsReached) elif self.currentMode is Mode.rest and self.time >= self.restEndTime: self.reset_timer() self.modeComboBox.setCurrentIndex(0) self.increment_current_repetitions() started = self.maybe_start_timer() self.show_window_message( Status.restFinished if started else Status.repetitionsReached) def increment_current_repetitions(self): if self.maxRepetitions > 0: self.currentRepetitions += 1 def insert_task(self): task = self.taskTextEdit.toPlainText() self.insert_tasks(task) def insert_tasks(self, *tasks): for task in tasks: if task: rowCount = self.tasksTableWidget.rowCount() self.tasksTableWidget.setRowCount(rowCount + 1) self.tasksTableWidget.setItem(rowCount, 0, QTableWidgetItem(task)) self.tasksTableWidget.resizeRowsToContents() self.taskTextEdit.clear() def delete_task(self): selectedIndexes = self.tasksTableWidget.selectedIndexes() if selectedIndexes: self.tasksTableWidget.removeRow(selectedIndexes[0].row()) def mark_task_as_finished(self, row, col): item = self.tasksTableWidget.item(row, col) font = self.tasksTableWidget.item(row, col).font() font.setStrikeOut(False if item.font().strikeOut() else True) item.setFont(font) def display_time(self): self.timeDisplay.display(self.time.toString(self.timeFormat)) self.statisticsRestTimeDisplay.display( self.restTime.toString(self.timeFormat)) self.statisticsWorkTimeDisplay.display( self.workTime.toString(self.timeFormat)) self.statisticsTotalTimeDisplay.display( self.totalTime.toString(self.timeFormat)) def show_window_message(self, status): if status is Status.workFinished: self.trayIcon.showMessage("Break", choice(work_finished_phrases), QIcon("icons/tomato.png")) elif status is Status.restFinished: self.trayIcon.showMessage("Work", choice(rest_finished_phrases), QIcon("icons/tomato.png")) else: self.trayIcon.showMessage("Finished", choice(pomodoro_finished_phrases), QIcon("icons/tomato.png")) self.resetButton.click() def setup_connections(self): self.playButton.clicked.connect(self.start_timer) self.playButton.clicked.connect( lambda: self.playButton.setDisabled(True)) self.playButton.clicked.connect( lambda: self.pauseButton.setDisabled(False)) self.playButton.clicked.connect( lambda: self.resetButton.setDisabled(False)) self.pauseButton.clicked.connect(self.pause_timer) self.pauseButton.clicked.connect( lambda: self.playButton.setDisabled(False)) self.pauseButton.clicked.connect( lambda: self.pauseButton.setDisabled(True)) self.pauseButton.clicked.connect( lambda: self.resetButton.setDisabled(False)) self.resetButton.clicked.connect(self.reset_timer) self.resetButton.clicked.connect( lambda: self.playButton.setDisabled(False)) self.resetButton.clicked.connect( lambda: self.pauseButton.setDisabled(True)) self.resetButton.clicked.connect( lambda: self.resetButton.setDisabled(True)) self.workHoursSpinBox.valueChanged.connect(self.update_work_end_time) self.workMinutesSpinBox.valueChanged.connect(self.update_work_end_time) self.workSecondsSpinBox.valueChanged.connect(self.update_work_end_time) self.restHoursSpinBox.valueChanged.connect(self.update_rest_end_time) self.restMinutesSpinBox.valueChanged.connect(self.update_rest_end_time) self.restSecondsSpinBox.valueChanged.connect(self.update_rest_end_time) self.modeComboBox.currentTextChanged.connect(self.update_current_mode) self.repetitionsSpinBox.valueChanged.connect( self.update_max_repetitions) self.acceptTaskButton.pressed.connect(self.insert_task) self.deleteTaskButton.pressed.connect(self.delete_task) self.tasksTableWidget.cellDoubleClicked.connect( self.mark_task_as_finished) def setup_ui(self): settings = QSettings() self.size_policy = sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) #TABWIDGET self.tabWidget = QTabWidget() self.pomodoroWidget = QWidget(self) self.pomodoroWidgetLayout = QVBoxLayout(self.pomodoroWidget) self.pomodoroWidget.setLayout(self.pomodoroWidgetLayout) # work self.workGroupBox = QGroupBox("Work") self.workGroupBoxLayout = QHBoxLayout(self.workGroupBox) self.workGroupBox.setLayout(self.workGroupBoxLayout) self.workHoursSpinBox = QSpinBox(minimum=0, maximum=24, value=settings.value( "timer/work/hours", 0), suffix="h", sizePolicy=self.size_policy) self.workMinutesSpinBox = QSpinBox(minimum=0, maximum=60, value=settings.value( "timer/work/minutes", 25), suffix="m", sizePolicy=self.size_policy) self.workSecondsSpinBox = QSpinBox(minimum=0, maximum=60, value=settings.value( "timer/work/seconds", 0), suffix="s", sizePolicy=self.size_policy) self.workGroupBoxLayout.addWidget(self.workHoursSpinBox) self.workGroupBoxLayout.addWidget(self.workMinutesSpinBox) self.workGroupBoxLayout.addWidget(self.workSecondsSpinBox) # rest self.restGroupBox = QGroupBox("Rest") self.restGroupBoxLayout = QHBoxLayout(self.restGroupBox) self.restGroupBox.setLayout(self.restGroupBoxLayout) self.restHoursSpinBox = QSpinBox(minimum=0, maximum=24, value=settings.value( "timer/rest/hours", 0), suffix="h", sizePolicy=self.size_policy) self.restMinutesSpinBox = QSpinBox(minimum=0, maximum=60, value=settings.value( "timer/rest/minutes", 5), suffix="m", sizePolicy=self.size_policy) self.restSecondsSpinBox = QSpinBox(minimum=0, maximum=60, value=settings.value( "timer/rest/seconds", 0), suffix="s", sizePolicy=self.size_policy) self.restGroupBoxLayout.addWidget(self.restHoursSpinBox) self.restGroupBoxLayout.addWidget(self.restMinutesSpinBox) self.restGroupBoxLayout.addWidget(self.restSecondsSpinBox) #OTHER self.otherGroupBox = QGroupBox("Other") self.otherGroupBoxLayout = QHBoxLayout(self.otherGroupBox) self.otherGroupBox.setLayout(self.otherGroupBoxLayout) self.repetitionsLabel = QLabel("Repetitions", sizePolicy=self.size_policy) self.repetitionsSpinBox = QSpinBox(minimum=0, maximum=10000, value=0, sizePolicy=self.size_policy, specialValueText="∞") self.modeLabel = QLabel("Mode", sizePolicy=self.size_policy) self.modeComboBox = QComboBox() self.modeComboBox.addItems(["work", "rest"]) self.otherGroupBoxLayout.addWidget(self.repetitionsLabel) self.otherGroupBoxLayout.addWidget(self.repetitionsSpinBox) self.otherGroupBoxLayout.addWidget(self.modeLabel) self.otherGroupBoxLayout.addWidget(self.modeComboBox) #LCDDISPLAY self.lcdDisplayGroupBox = QGroupBox("Time") self.lcdDisplayGroupBoxLayout = QHBoxLayout(self.lcdDisplayGroupBox) self.lcdDisplayGroupBox.setLayout(self.lcdDisplayGroupBoxLayout) self.timeDisplay = QLCDNumber(8, sizePolicy=self.size_policy) self.timeDisplay.setFixedHeight(100) self.timeDisplay.display("00:00:00") self.lcdDisplayGroupBoxLayout.addWidget(self.timeDisplay) #BUTTONS self.buttonWidget = QWidget() self.buttonWidgetLayout = QHBoxLayout(self.buttonWidget) self.buttonWidget.setLayout(self.buttonWidgetLayout) self.playButton = self.make_button("start", disabled=False) self.resetButton = self.make_button("reset") self.pauseButton = self.make_button("pause") self.buttonWidgetLayout.addWidget(self.pauseButton) self.buttonWidgetLayout.addWidget(self.playButton) self.buttonWidgetLayout.addWidget(self.resetButton) #CENTRALWIDGET self.pomodoroWidgetLayout.addWidget(self.workGroupBox) self.pomodoroWidgetLayout.addWidget(self.restGroupBox) self.pomodoroWidgetLayout.addWidget(self.otherGroupBox) self.pomodoroWidgetLayout.addWidget(self.lcdDisplayGroupBox) self.pomodoroWidgetLayout.addWidget(self.buttonWidget) #CREATE TASKS TAB self.tasksWidget = QWidget(self.tabWidget) self.tasksWidgetLayout = QVBoxLayout(self.tasksWidget) self.tasksWidget.setLayout(self.tasksWidgetLayout) self.inputWidget = QWidget() self.inputWidget.setFixedHeight(50) self.inputWidgetLayout = QHBoxLayout(self.inputWidget) self.inputWidgetLayout.setContentsMargins(0, 0, 0, 0) self.inputWidget.setLayout(self.inputWidgetLayout) self.taskTextEdit = QTextEdit( placeholderText="Describe your task briefly.", undoRedoEnabled=True) self.inputButtonContainer = QWidget() self.inputButtonContainerLayout = QVBoxLayout( self.inputButtonContainer) self.inputButtonContainerLayout.setContentsMargins(0, 0, 0, 0) self.inputButtonContainer.setLayout(self.inputButtonContainerLayout) self.acceptTaskButton = QToolButton(icon=QIcon("icons/check.png")) self.deleteTaskButton = QToolButton(icon=QIcon("icons/trash.png")) self.inputButtonContainerLayout.addWidget(self.acceptTaskButton) self.inputButtonContainerLayout.addWidget(self.deleteTaskButton) self.inputWidgetLayout.addWidget(self.taskTextEdit) self.inputWidgetLayout.addWidget(self.inputButtonContainer) self.tasksTableWidget = QTableWidget(0, 1) self.tasksTableWidget.setHorizontalHeaderLabels(["Tasks"]) self.tasksTableWidget.horizontalHeader().setStretchLastSection(True) self.tasksTableWidget.verticalHeader().setVisible(False) self.tasksTableWidget.setWordWrap(True) self.tasksTableWidget.setTextElideMode(Qt.ElideNone) self.tasksTableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) self.tasksTableWidget.setSelectionMode( QAbstractItemView.SingleSelection) self.insert_tasks(*settings.value("tasks/tasks", [])) self.tasksWidgetLayout.addWidget(self.inputWidget) self.tasksWidgetLayout.addWidget(self.tasksTableWidget) #CREATE STATISTICS TAB self.statisticsWidget = QWidget() self.statisticsWidgetLayout = QVBoxLayout(self.statisticsWidget) self.statisticsWidget.setLayout(self.statisticsWidgetLayout) self.statisticsWorkTimeGroupBox = QGroupBox("Work Time") self.statisticsWorkTimeGroupBoxLayout = QHBoxLayout() self.statisticsWorkTimeGroupBox.setLayout( self.statisticsWorkTimeGroupBoxLayout) self.statisticsWorkTimeDisplay = QLCDNumber(8) self.statisticsWorkTimeDisplay.display("00:00:00") self.statisticsWorkTimeGroupBoxLayout.addWidget( self.statisticsWorkTimeDisplay) self.statisticsRestTimeGroupBox = QGroupBox("Rest Time") self.statisticsRestTimeGroupBoxLayout = QHBoxLayout() self.statisticsRestTimeGroupBox.setLayout( self.statisticsRestTimeGroupBoxLayout) self.statisticsRestTimeDisplay = QLCDNumber(8) self.statisticsRestTimeDisplay.display("00:00:00") self.statisticsRestTimeGroupBoxLayout.addWidget( self.statisticsRestTimeDisplay) self.statisticsTotalTimeGroupBox = QGroupBox("Total Time") self.statisticsTotalTimeGroupBoxLayout = QHBoxLayout() self.statisticsTotalTimeGroupBox.setLayout( self.statisticsTotalTimeGroupBoxLayout) self.statisticsTotalTimeDisplay = QLCDNumber(8) self.statisticsTotalTimeDisplay.display("00:00:00") self.statisticsTotalTimeGroupBoxLayout.addWidget( self.statisticsTotalTimeDisplay) self.statisticsWidgetLayout.addWidget(self.statisticsTotalTimeGroupBox) self.statisticsWidgetLayout.addWidget(self.statisticsWorkTimeGroupBox) self.statisticsWidgetLayout.addWidget(self.statisticsRestTimeGroupBox) #ADD TABS self.timerTab = self.tabWidget.addTab(self.pomodoroWidget, QIcon("icons/timer.png"), "Timer") self.tasksTab = self.tabWidget.addTab(self.tasksWidget, QIcon("icons/tasks.png"), "Tasks") self.statisticsTab = self.tabWidget.addTab( self.statisticsWidget, QIcon("icons/statistics.png"), "Statistics") self.setCentralWidget(self.tabWidget) def make_button(self, text, iconPath=None, disabled=True): button = QPushButton(text, sizePolicy=self.size_policy) if iconPath: button.setIcon(QIcon(iconPath)) button.setDisabled(disabled) return button def setup_trayicon(self): self.trayIcon = QSystemTrayIcon(QIcon("icons/tomato.png")) self.trayIcon.setContextMenu(QMenu()) self.quitAction = self.trayIcon.contextMenu().addAction( QIcon("icons/exit.png"), "Quit", self.exit) self.quitAction.triggered.connect(self.exit) self.trayIcon.activated.connect(self.onActivate) self.trayIcon.show() def exit(self): self.close() app = QApplication.instance() if app: app.quit() def onActivate(self, reason): if reason == QSystemTrayIcon.Trigger: self.show()
class view(QWidget): def __init__(self): super().__init__() self.data_storage = datastorage.DataStorage() self.parser = parser.Parser(self.data_storage) self.thread = QThread() self.parser.dataChanged.connect(self.append_data) self.parser.moveToThread(self.thread) self.thread.started.connect(self.parser.parse) self.thread.start() self.timer = QTimer(self) self.timer.timeout.connect(self.plot_data) self.timer.start(100) self.lastUpdate = pg.ptime.time() self.avgFps = 0.0 self.cutoff = 0 self.scroll_status = True self.plotting_status = True """Optimization settings""" self.end_dots = True self.graph_update_count = 0 self.graph_update_interval = 3 # Increase this value to speed up graphing self.optimize_fps = True self.goal_fps = 30 # Max 60 self.bounds = 10 """Latest Telemetry Info""" self.lat = 0 self.long = 0 self.time = 0 self.alt = 0 self.vel = 0 self.sat = 0 self.accel = 0 self.temp = 0 self.gyro_x = 0 self.antenna_angle = [0, 0] self.antenna_precision = 7 self.antenna_font_size = 32 self.initUI() def initUI(self): pg.setConfigOptions(antialias=False) ## expensive ass setting for fps but yolo """Declare layouts""" hbox_Window = QHBoxLayout(self) vbox_LogoAndGraphs = QVBoxLayout() vbox_Logo = QVBoxLayout() hbox_Banner = QHBoxLayout() hbox_Graphs = QHBoxLayout() vbox_inner_Graphs = QVBoxLayout() # vbox for non-position graphs vbox_Indicators = QVBoxLayout() hbox_position = QHBoxLayout() vbox_Buttons = QVBoxLayout() """Declare widgets""" self.fps_label = QLabel() self.antenna_angle_label = QLabel() self.antenna_angle_label.setFont(QFont("Times", self.antenna_font_size, QFont.Bold)) self.altitude_graph = pg.PlotWidget(title='Altitude', left='Height', bottom='Time') self.rssi_graph = pg.PlotWidget(title='RSSI', left='RSSI', bottom='Time') self.velocity_graph = pg.PlotWidget(title='Velocity', left='Velocity', bottom='Time') self.acceleration_graph = pg.PlotWidget(title='Acceleration', left='Acceleration', bottom='Time') self.position_graph = pg.PlotWidget(title='Position', left='Y Coordinate', bottom='X Coordinate') # self.altitude_graph.setClipToView(True) # OPTIMIZATION OPTIONS # self.altitude_graph.setDownsampling(mode='peak') # self.temperature_graph.setClipToView(True) # self.temperature_graph.setDownsampling(mode='peak') # self.velocity_graph.setClipToView(True) # self.velocity_graph.setDownsampling(mode='peak') # self.acceleration_graph.setClipToView(True) # self.acceleration_graph.setDownsampling(mode='peak') # self.position_graph.setClipToView(True) # self.position_graph.setDownsampling(mode='peak') # self.altitude_graph.setRange(xRange=[0, 10]) # self.altitude_graph.setLimits(xMax=100) self.text_box = QLineEdit(self) self.text_box.setFixedWidth(250) self.button = QPushButton('Update Cutoff', self) self.button.clicked.connect(self.on_click) self.button.setFixedWidth(250) self.button_reset = QPushButton('RESET DATA', self) self.button_reset.clicked.connect(self.on_click_reset) self.button_reset.setFixedWidth(250) self.button_reset.setStyleSheet("background-color: red") self.scroll_checkbox = QCheckBox("Toggle Scrolling", self) self.scroll_checkbox.setChecked(self.scroll_status) self.scroll_checkbox.stateChanged.connect(self.on_click_scrolling) self.plot_checkbox = QCheckBox("Toggle Plotting", self) self.plot_checkbox.setChecked(self.plotting_status) self.plot_checkbox.stateChanged.connect(self.on_click_plotting) self.altitude_LCD = QLCDNumber(self) self.rssi_LCD = QLCDNumber(self) self.velocity_LCD = QLCDNumber(self) self.acceleration_LCD = QLCDNumber(self) self.positionX_LCD = QLCDNumber(self) self.positionY_LCD = QLCDNumber(self) self.altitude_LCD.setFixedHeight(LCD_HEIGHT) self.rssi_LCD.setFixedHeight(LCD_HEIGHT) self.velocity_LCD.setFixedHeight(LCD_HEIGHT) self.acceleration_LCD.setFixedHeight(LCD_HEIGHT) self.positionX_LCD.setFixedHeight(LCD_HEIGHT) self.positionY_LCD.setFixedHeight(LCD_HEIGHT) self.altitude_LCD.setDigitCount(9) self.rssi_LCD.setDigitCount(4) self.velocity_LCD.setDigitCount(9) self.acceleration_LCD.setDigitCount(9) self.positionX_LCD.setDigitCount(10) self.positionY_LCD.setDigitCount(10) altitude_label = QLabel("Current Altitude") rssi_label = QLabel("RSSI") velocity_label = QLabel("Current Velocity") acceleration_label = QLabel("Current Acceleration") position_label = QLabel("Current Position") MRT_Logo = QPixmap('./../media/MRT-logo.png') smaller_MRT_Logo = MRT_Logo.scaledToHeight(100) logo_Lbl = QLabel(self) logo_Lbl.setPixmap(smaller_MRT_Logo) MRT_label = QLabel("McGill Rocket Team Ground Station") MRT_label.setFont(QFont("Times", 30, QFont.Bold)) """Layout Management""" vbox_Logo.addWidget(self.fps_label) vbox_Logo.addLayout(hbox_Banner) hbox_Banner.addWidget(logo_Lbl) hbox_Banner.addWidget(MRT_label) hbox_Banner.addStretch(1) vbox_inner_Graphs.addWidget(self.altitude_graph) vbox_inner_Graphs.addWidget(self.rssi_graph) vbox_inner_Graphs.addWidget(self.velocity_graph) vbox_inner_Graphs.addWidget(self.acceleration_graph) hbox_Graphs.addLayout(vbox_inner_Graphs) hbox_Graphs.addWidget(self.position_graph) vbox_Indicators.addWidget(altitude_label) vbox_Indicators.addWidget(self.altitude_LCD) vbox_Indicators.addWidget(rssi_label) vbox_Indicators.addWidget(self.rssi_LCD) vbox_Indicators.addWidget(velocity_label) vbox_Indicators.addWidget(self.velocity_LCD) vbox_Indicators.addWidget(acceleration_label) vbox_Indicators.addWidget(self.acceleration_LCD) vbox_Indicators.addWidget(position_label) hbox_position.addWidget(self.positionX_LCD) hbox_position.addWidget(self.positionY_LCD) vbox_Indicators.addLayout(hbox_position) vbox_Indicators.addLayout(vbox_Buttons) vbox_Buttons.addWidget(self.antenna_angle_label) vbox_Buttons.addWidget(self.text_box) vbox_Buttons.addWidget(self.button) vbox_Buttons.addWidget(self.button_reset) vbox_Buttons.addWidget(self.scroll_checkbox) vbox_Buttons.addWidget(self.plot_checkbox) vbox_LogoAndGraphs.addLayout(vbox_Logo) vbox_LogoAndGraphs.addLayout(hbox_Graphs) hbox_Window.addLayout(vbox_LogoAndGraphs) hbox_Window.addLayout(vbox_Indicators) """ Telemetry values """ self.time_list = [] self.temperature_list = [] self.altitude_list = [] self.velocity_list = [] self.acceleration_list = [] """ GPS values """ self.latitude_list = [] self.longitude_list = [] """ Redundancy GPS values """ self.redundancy_latitude_list = [] self.redundancy_longitude_list = [] self.rssi_list = [] """Build main window""" self.setLayout(hbox_Window) self.setGeometry(100, 100, 1720, 968) self.setWindowTitle('MRT Ground Station') self.altitude_curve = self.altitude_graph.plot(self.time_list, self.altitude_list) self.rssi_curve = self.rssi_graph.plot(self.time_list, self.rssi_list) self.velocity_curve = self.velocity_graph.plot(self.time_list, self.velocity_list) self.acceleration_curve = self.acceleration_graph.plot(self.time_list, self.acceleration_list) if show_graphs is True: self.show() @pyqtSlot(list) def append_data(self, telemetry_data): """ telemetry long data format: Slat,long,time,alt,vel,sat,acc,temp,gyro_x,RSSI,E\n backup GPS data: Slat,long,time,gps_alt,gps_speed,sat,RSSI,E\n """ """ Append telemetry data to lists """ if len(telemetry_data) == 2: self.antenna_angle = telemetry_data else: try: self.lat = float(telemetry_data[0]) self.long = float(telemetry_data[1]) self.time = float(telemetry_data[2]) self.alt = float(telemetry_data[3]) self.vel = float(telemetry_data[4]) self.sat = float(telemetry_data[5]) self.accel = 0 self.temp = 0 self.gyro_x = 0 self.rssi = 0 if len(telemetry_data) >= 9: self.accel = float(telemetry_data[6]) self.temp = float(telemetry_data[7]) self.gyro_x = float(telemetry_data[8]) if len(telemetry_data) == 10: self.rssi = float(telemetry_data[9]) if self.plotting_status: self.rssi_list.append(float(self.rssi)) elif len(telemetry_data) == 7: self.rssi = float(telemetry_data[6]) if self.plotting_status: self.rssi_list.append(float(self.rssi)) if self.plotting_status: self.time_list.append(float(self.time)) self.altitude_list.append(float(self.alt)) self.temperature_list.append(float(self.temp)) self.velocity_list.append(float(self.vel)) self.acceleration_list.append(float(self.accel)) except: print('INVALID DATA SENT TO VIEW') """ Append GPS data to lists """ try: if self.plotting_status: self.latitude_list.append(float(self.lat)) self.longitude_list.append(float(self.long)) except: print("latlong broken") @pyqtSlot() def plot_data(self): try: now = pg.ptime.time() fps = 1.0 / (now - self.lastUpdate) self.lastUpdate = now self.avgFps = self.avgFps * 0.8 + fps * 0.2 self.fps_label.setText("Generating {0:3.2f} fps Update interval: {1}".format(self.avgFps, self.graph_update_interval)) self.antenna_angle_label.setText('XY:{}\nZ:{}'.format(str(self.antenna_angle[0])[0:self.antenna_precision], str(self.antenna_angle[1])[0:self.antenna_precision])) if self.plotting_status: if self.graph_update_count > self.graph_update_interval: self.graph_update_count = 0 if self.optimize_fps: if self.avgFps < (self.goal_fps-self.bounds): self.graph_update_interval += 1 elif self.avgFps > (self.goal_fps+self.bounds): self.graph_update_interval -= 1 self.position_graph.clear() if len(self.altitude_list) > self.cutoff+1: self.altitude_curve.setData(self.time_list[-self.cutoff:-1], self.altitude_list[-self.cutoff:-1], pen='r') self.rssi_curve.setData(self.time_list[-self.cutoff:-1], self.altitude_list[-self.cutoff:-1], pen='r') self.velocity_curve.setData(self.time_list[-self.cutoff:-1], self.velocity_list[-self.cutoff:-1], pen='r') self.acceleration_curve.setData(self.time_list[-self.cutoff:-1], self.acceleration_list[-self.cutoff:-1], pen='r') if self.scroll_status: try: self.altitude_graph.setRange(xRange=[self.time_list[-1] - graph_range, self.time_list[-1]]) self.rssi_graph.setRange(xRange=[self.time_list[-1] - graph_range, self.time_list[-1]]) self.velocity_graph.setRange(xRange=[self.time_list[-1] - graph_range, self.time_list[-1]]) self.acceleration_graph.setRange(xRange=[self.time_list[-1] - graph_range, self.time_list[-1]]) except: print("Scrolling broke somehow") self.position_graph.plot(self.latitude_list[-self.cutoff:-1], self.longitude_list[-self.cutoff:-1]) # if self.end_dots: # self.velocity_graph.plot([self.time], [self.vel], pen=None, symbol='o', symbolBrush=(0, 0, 255), symbolSize=6.5) # self.acceleration_graph.plot([self.time], [self.accel], pen=None, symbol='o', symbolBrush=(0, 0, 255), symbolSize=6.5) # self.altitude_graph.plot([self.time], [self.alt], pen=None, symbol='o', symbolBrush=(0, 0, 255), symbolSize=6.5) # if len(self.time_list) == len(self.rssi_list): # self.rssi_graph.plot(self.time_list[-self.cutoff:-1], self.rssi_list[-self.cutoff:-1], pen='r') # if self.end_dots: # self.rssi_graph.plot([self.time], [self.rssi], pen=None, symbol='o', symbolBrush=(0, 0, 255), symbolSize=6.5) # This line adds an X marking the last gps location self.position_graph.plot([self.lat], [self.long], pen=None, symbol='o', symbolBrush=(255, 0, 0), symbolSize=6.5) else: self.graph_update_count = self.graph_update_count + 1 self.altitude_LCD.display(self.alt) self.rssi_LCD.display(self.rssi) self.velocity_LCD.display(self.vel) self.acceleration_LCD.display(self.accel) self.positionX_LCD.display(self.lat) self.positionY_LCD.display(self.long) self.timer.start(0) except: print("Problem with graphing") @pyqtSlot() def on_click(self): text_value = self.text_box.text() try: num_value = int(text_value) num_value = abs(num_value) if num_value < len(self.longitude_list): self.cutoff = num_value else: self.cutoff = 0 except: print('Data limit {} is invalid \nInput a number between 0 and {}'.format(text_value, len(self.longitude_list))) self.cutoff = 0 @pyqtSlot() def on_click_reset(self): """ Telemetry values """ self.time_list = [] self.temperature_list = [] self.altitude_list = [] self.velocity_list = [] self.acceleration_list = [] """ GPS values """ self.latitude_list = [] self.longitude_list = [] """ Redundancy GPS values """ self.redundancy_latitude_list = [] self.redundancy_longitude_list = [] self.rssi_list = [] @pyqtSlot() def on_click_scrolling(self): if self.scroll_checkbox.isChecked(): self.scroll_status = True else: self.scroll_status = False @pyqtSlot() def on_click_plotting(self): if self.plot_checkbox.isChecked(): self.plotting_status = True else: self.plotting_status = False
class Run_CM110(QMainWindow): def __init__(self): super().__init__() self.cwd = os.getcwd() self.load_() # Enable antialiasing for prettier plots pg.setConfigOptions(antialias=True) self.initUI() def initUI(self): ################### MENU BARS START ################## MyBar = QMenuBar(self) fileMenu = MyBar.addMenu("File") fileSavePlt = fileMenu.addAction("Save plots") fileSavePlt.triggered.connect(self.save_plots) fileSavePlt.setShortcut('Ctrl+P') fileSaveSet = fileMenu.addAction("Save settings") fileSaveSet.triggered.connect(self.save_) # triggers closeEvent() fileSaveSet.setShortcut('Ctrl+S') fileClose = fileMenu.addAction("Close") fileClose.triggered.connect(self.close) # triggers closeEvent() fileClose.setShortcut('Ctrl+X') instMenu = MyBar.addMenu("Instruments") self.conMode = instMenu.addAction("Load instruments") self.conMode.triggered.connect(self.instrumentsDialog) ################### MENU BARS END ################## ##################################################### lbl1 = QLabel("MONOCHROMATOR CM110 settings:", self) lbl1.setStyleSheet("color: blue") intervals_lbl = QLabel("Number of intervals", self) self.combo4 = QComboBox(self) mylist4=["1","2"] self.combo4.addItems(mylist4) self.combo4.setCurrentIndex(mylist4.index(str(self.numofintervals))) start_lbl = QLabel("Start[nm]",self) stop_lbl = QLabel("Stop[nm]",self) step_lbl = QLabel("Step[nm]",self) dwelltime = QLabel("Dwell[s]",self) self.startEdit = [QLineEdit("",self) for tal in range(2)] self.stopEdit = [QLineEdit("",self) for tal in range(2)] self.stepEdit = [QLineEdit("",self) for tal in range(2)] self.dwelltimeEdit = [QLineEdit("",self) for tal in range(2)] # disable those fields that will be ignored anyway for tal in range(2): if tal<self.numofintervals: self.startEdit[tal].setText(str(self.start_[tal])) self.stopEdit[tal].setText(str(self.stop[tal])) self.stepEdit[tal].setText(str(self.step[tal])) self.dwelltimeEdit[tal].setText(str(self.dwell_time[tal])) else: self.startEdit[tal].setEnabled(False) self.stopEdit[tal].setEnabled(False) self.stepEdit[tal].setEnabled(False) self.dwelltimeEdit[tal].setEnabled(False) lbl3 = QLabel("NEWPORT stepper SMC100:", self) lbl3.setStyleSheet("color: blue") startst_lbl = QLabel("Start",self) stopst_lbl = QLabel("Stop",self) stepst_lbl = QLabel("Step",self) lcdst_lbl = QLabel("Current pos",self) self.startst_Edit = QLineEdit(str(self.startst),self) self.stopst_Edit = QLineEdit(str(self.stopst),self) self.stepst_Edit = QLineEdit(str(self.stepst),self) self.lcdst = QLCDNumber(self) self.lcdst.setStyleSheet("color: blue") #self.lcdst.setFixedHeight(40) self.lcdst.setSegmentStyle(QLCDNumber.Flat) self.lcdst.setNumDigits(5) self.lcdst.display("-----") lbl2 = QLabel("ARDUINO Mega2560 settings:", self) lbl2.setStyleSheet("color: blue") dwelltime_lbl = QLabel("Dwell time [ms]",self) self.dwelltimeEdit_ard = QLineEdit(str(self.dwell_time_ard),self) avgpts_lbl = QLabel("Averaging points", self) self.combo1 = QComboBox(self) mylist=["1","5","10","50","100","200"] self.combo1.addItems(mylist) self.combo1.setCurrentIndex(mylist.index(str(self.avg_pts))) lbl4 = QLabel("STORAGE filename and location settings:", self) lbl4.setStyleSheet("color: blue") filename = QLabel("folder/file",self) self.filenameEdit = QLineEdit(self.filename_str,self) lbl6 = QLabel("PLOT options:", self) lbl6.setStyleSheet("color: blue") mylist2=["200","400","800","1600","3200","6400"] schroll_lbl = QLabel("Schroll time after",self) self.combo2 = QComboBox(self) self.combo2.addItems(mylist2) self.combo2.setCurrentIndex(mylist2.index(str(self.schroll_time))) schroll2_lbl = QLabel("Schroll wavelength after",self) self.combo3 = QComboBox(self) self.combo3.addItems(mylist2) self.combo3.setCurrentIndex(mylist2.index(str(self.schroll_wl))) ############################################## lbl5 = QLabel("RECORD data and save images:", self) lbl5.setStyleSheet("color: blue") #save_str = QLabel("Store settings", self) #self.saveButton = QPushButton("Save",self) #self.saveButton.setEnabled(True) run_str = QLabel("Record lock-in data", self) self.runButton = QPushButton("Load instruments",self) #saveplots_str = QLabel("Save plots as png", self) #self.saveplotsButton = QPushButton("Save plots",self) #self.saveplotsButton.setEnabled(True) ''' elapsedtime_str = QLabel('Show voltage vs. time', self) self.elapsedtimeButton = QPushButton("Plot 2",self) self.elapsedtimeButton.setEnabled(False) ''' cancel_str = QLabel("Stop current run", self) self.stopButton = QPushButton("STOP",self) self.stopButton.setEnabled(False) ############################################## # status info which button has been pressed #self.status_str = QLabel("Edit settings and press SAVE!", self) #self.status_str.setStyleSheet("color: green") ############################################## # status info which button has been pressed self.elapsedtime_str = QLabel("TIME trace for storing plots and data:", self) self.elapsedtime_str.setStyleSheet("color: blue") ############################################## self.lcd = QLCDNumber(self) self.lcd.setStyleSheet("color: red") self.lcd.setFixedHeight(60) self.lcd.setSegmentStyle(QLCDNumber.Flat) self.lcd.setNumDigits(11) self.lcd.display(self.timestr) ############################################## # Add all widgets g1_0 = QGridLayout() g1_0.addWidget(MyBar,0,0) g1_0.addWidget(lbl1,1,0) g1_1 = QGridLayout() #g1_1.addWidget(cm110port,0,0) #g1_1.addWidget(self.cm110portEdit,0,1) g1_3 = QGridLayout() g1_3.addWidget(intervals_lbl,0,0) g1_3.addWidget(self.combo4,0,1) g1_2 = QGridLayout() g1_2.addWidget(start_lbl,0,0) g1_2.addWidget(stop_lbl,0,1) g1_2.addWidget(step_lbl,0,2) g1_2.addWidget(dwelltime,0,3) for tal in range(2): g1_2.addWidget(self.startEdit[tal],1+tal,0) g1_2.addWidget(self.stopEdit[tal],1+tal,1) g1_2.addWidget(self.stepEdit[tal],1+tal,2) g1_2.addWidget(self.dwelltimeEdit[tal],1+tal,3) v1 = QVBoxLayout() v1.addLayout(g1_0) v1.addLayout(g1_1) v1.addLayout(g1_3) v1.addLayout(g1_2) g9_0 = QGridLayout() g9_0.addWidget(lbl3,0,0) g9_1 = QGridLayout() g9_1.addWidget(startst_lbl,0,0) g9_1.addWidget(stopst_lbl,0,1) g9_1.addWidget(stepst_lbl,0,2) g9_1.addWidget(lcdst_lbl,0,3) g9_1.addWidget(self.startst_Edit,1,0) g9_1.addWidget(self.stopst_Edit,1,1) g9_1.addWidget(self.stepst_Edit,1,2) g9_1.addWidget(self.lcdst,1,3) v9 = QVBoxLayout() v9.addLayout(g9_0) v9.addLayout(g9_1) g2_0 = QGridLayout() g2_0.addWidget(lbl2,0,0) g2_1 = QGridLayout() #g2_1.addWidget(ardport,0,0) g2_1.addWidget(dwelltime_lbl,0,0) g2_1.addWidget(avgpts_lbl,1,0) #g2_1.addWidget(self.ardportEdit,0,1) g2_1.addWidget(self.dwelltimeEdit_ard,0,1) g2_1.addWidget(self.combo1,1,1) v2 = QVBoxLayout() v2.addLayout(g2_0) v2.addLayout(g2_1) g4_0 = QGridLayout() g4_0.addWidget(lbl4,0,0) g4_1 = QGridLayout() g4_1.addWidget(filename,0,0) g4_1.addWidget(self.filenameEdit,0,1) v4 = QVBoxLayout() v4.addLayout(g4_0) v4.addLayout(g4_1) g7_0 = QGridLayout() g7_0.addWidget(lbl6,0,0) g7_1 = QGridLayout() g7_1.addWidget(schroll2_lbl,0,0) g7_1.addWidget(self.combo3,0,1) g7_1.addWidget(schroll_lbl,1,0) g7_1.addWidget(self.combo2,1,1) v7 = QVBoxLayout() v7.addLayout(g7_0) v7.addLayout(g7_1) g5_0 = QGridLayout() g5_0.addWidget(lbl5,0,0) g5_1 = QGridLayout() #g5_1.addWidget(save_str,0,0) g5_1.addWidget(run_str,0,0) #g5_1.addWidget(saveplots_str,2,0) g5_1.addWidget(cancel_str,1,0) #g5_1.addWidget(self.saveButton,0,1) g5_1.addWidget(self.runButton,0,1) #g5_1.addWidget(self.saveplotsButton,2,1) g5_1.addWidget(self.stopButton,1,1) v5 = QVBoxLayout() v5.addLayout(g5_0) v5.addLayout(g5_1) g6_0 = QGridLayout() g6_0.addWidget(self.elapsedtime_str,0,0) g6_0.addWidget(self.lcd,1,0) v6 = QVBoxLayout() v6.addLayout(g6_0) # add all groups from v1 to v6 in one vertical group v7 v8 = QVBoxLayout() v8.addLayout(v1) v8.addLayout(v9) v8.addLayout(v2) v8.addLayout(v4) v8.addLayout(v7) v8.addLayout(v5) v8.addLayout(v6) # set graph and toolbar to a new vertical group vcan vcan = QVBoxLayout() self.pw1 = pg.PlotWidget(name="Plot1") ## giving the plots names allows us to link their axes together vcan.addWidget(self.pw1) self.pw2 = pg.PlotWidget(name="Plot2") vcan.addWidget(self.pw2) # SET ALL VERTICAL COLUMNS TOGETHER hbox = QHBoxLayout() hbox.addLayout(v8,1) hbox.addLayout(vcan,3.75) ############################################## # PLOT 1 settings # create plot and add it to the figure canvas self.p0 = self.pw1.plotItem self.curve1=[self.p0.plot()] # create plot and add it to the figure self.p0vb = pg.ViewBox() self.curve5=pg.PlotCurveItem(pen=None) self.p0vb.addItem(self.curve5) # connect respective axes to the plot self.p0.showAxis('right') self.p0.getAxis('right').setLabel("10-bit Arduino output") self.p0.scene().addItem(self.p0vb) self.p0.getAxis('right').linkToView(self.p0vb) self.p0vb.setXLink(self.p0) # Use automatic downsampling and clipping to reduce the drawing load self.pw1.setDownsampling(mode='peak') self.pw1.setClipToView(True) # PLOT 2 settings # create plot and add it to the figure canvas self.p1 = self.pw2.plotItem self.curve2=self.p1.plot(pen='r') self.curve3=self.p1.plot() # create plot and add it to the figure self.p2 = pg.ViewBox() self.curve4=pg.PlotCurveItem(pen='y') self.curve6=pg.PlotCurveItem(pen='m') self.p2.addItem(self.curve4) self.p2.addItem(self.curve6) # connect respective axes to the plot self.p1.showAxis('right') self.p1.getAxis('right').setLabel("Wavelength", units='m', color='yellow') self.p1.scene().addItem(self.p2) self.p1.getAxis('right').linkToView(self.p2) self.p2.setXLink(self.p1) # Use automatic downsampling and clipping to reduce the drawing load self.pw2.setDownsampling(mode='peak') self.pw2.setClipToView(True) # Initialize and set titles and axis names for both plots self.clear_vars_graphs() ############################################################################### self.inst_list = {} self.colors = itertools.cycle(["r", "b", "g", "y", "m", "c", "w"]) self.threadpool = QThreadPool() print("Multithreading in Run_COMPexPRO with maximum %d threads" % self.threadpool.maxThreadCount()) # reacts to choises picked in the menu self.combo1.activated[str].connect(self.onActivated1) self.combo2.activated[str].connect(self.onActivated2) self.combo3.activated[str].connect(self.onActivated3) self.combo4.activated[str].connect(self.onActivated4) # save all paramter data in the config file #self.saveButton.clicked.connect(self.save_) #self.saveButton.clicked.connect(self.set_elapsedtime_text) # run the main script self.runButton.clicked.connect(self.set_run) # cancel the script run self.stopButton.clicked.connect(self.set_stop) self.allFields(False) ############################################## self.timer = QTimer(self) self.timer.timeout.connect(self.set_disconnect) self.timer.setSingleShot(True) ############################################## self.setGeometry(100, 100, 1100, 650) self.setWindowTitle("Monochromator CM110 Control And Data Acqusition") w = QWidget() w.setLayout(hbox) self.setCentralWidget(w) self.show() def instrumentsDialog(self): self.Inst = Instruments_dialog.Instruments_dialog(self,self.inst_list,self.cwd,self.lcdst) self.Inst.exec() if self.inst_list.get("CM110") or self.inst_list.get("Ard") or self.inst_list.get("SR530") or self.inst_list.get("SMC100"): self.allFields(True) self.runButton.setText("Scan") self.timer.start(1000*60*self.minutes) else: self.allFields(False) self.runButton.setText("Load instrument!") def allFields(self,trueorfalse): for tal in range(2): if tal<self.numofintervals: self.startEdit[tal].setEnabled(trueorfalse) self.stopEdit[tal].setEnabled(trueorfalse) self.stepEdit[tal].setEnabled(trueorfalse) self.dwelltimeEdit[tal].setEnabled(trueorfalse) self.startst_Edit.setEnabled(trueorfalse) self.stopst_Edit.setEnabled(trueorfalse) self.stepst_Edit.setEnabled(trueorfalse) self.dwelltimeEdit_ard.setEnabled(trueorfalse) self.combo1.setEnabled(trueorfalse) self.combo2.setEnabled(trueorfalse) self.combo3.setEnabled(trueorfalse) self.combo4.setEnabled(trueorfalse) self.filenameEdit.setEnabled(trueorfalse) self.runButton.setEnabled(trueorfalse) def onActivated1(self, text): self.avg_pts = str(text) def onActivated2(self, text): self.schroll_time=int(text) def onActivated3(self, text): self.schroll_wl=int(text) def onActivated4(self, text): self.numofintervals = int(text) for tal in range(2): if tal<self.numofintervals: self.startEdit[tal].setEnabled(True) self.stopEdit[tal].setEnabled(True) self.stepEdit[tal].setEnabled(True) self.dwelltimeEdit[tal].setEnabled(True) else: self.startEdit[tal].setEnabled(False) self.stopEdit[tal].setEnabled(False) self.stepEdit[tal].setEnabled(False) self.dwelltimeEdit[tal].setEnabled(False) # Check input if a number, ie. digits or fractions such as 3.141 # Source: http://www.pythoncentral.io/how-to-check-if-a-string-is-a-number-in-python-including-unicode/ def is_number(self,s): try: float(s) return True except ValueError: pass try: import unicodedata unicodedata.numeric(s) return True except (TypeError, ValueError): pass return False def create_file(self, mystr): head, ext = os.path.splitext(mystr) #print("head: ",head) #print("ext: ",ext) #print("filename: ",self.filenameEdit.text()) totalpath = ''.join([self.cwd,os.sep,head,'_',self.timestr,ext]) my_dir = os.path.dirname(totalpath) if not os.path.isdir(my_dir): QMessageBox.warning(self, "Message","".join(["Folder(s) named ",my_dir," will be created!"])) try: os.makedirs(my_dir, exist_ok=True) except Exception as e: QMessageBox.critical(self, "Message","".join(["Folder named ",head," not valid!\n\n",str(e)])) return "" return totalpath def set_run(self): # MINIMUM REQUIREMENTS for proper run if not self.inst_list.get("CM110") and not self.inst_list.get("SR530") and not self.inst_list.get("Ard") and not self.inst_list.get("SMC100"): QMessageBox.critical(self, 'Message',"No instruments connected. At least 1 instrument is required.") return ######################################################## if self.inst_list.get("SMC100"): val = self.inst_list.get("SMC100").return_ts(1) if val[-2:] not in ["32","33","34","35"]: # RESET the stepper if active self.Reset_dialog = Reset_dialog.Reset_dialog(self, self.inst_list) self.Reset_dialog.exec() # Checkif the stepper is ready val = self.inst_list.get("SMC100").return_ts(1) if val[-2:] not in ["32","33","34","35"]: return ######################################################## try: for i in range(self.numofintervals): arr = numpy.arange(int(self.startEdit[i].text()),int(self.stopEdit[i].text()),int(self.stepEdit[i].text())) if len(arr)==0: QMessageBox.warning(self, 'Message',''.join(["Empty array returned. Check wavelength start and stop values!"])) return except Exception as e: QMessageBox.warning(self, 'Message',''.join(["All wavelength scan parameters should be integers!\n\n",str(e)])) return try: arr = numpy.arange(float(self.startst_Edit.text()),float(self.stopst_Edit.text()),float(self.stepst_Edit.text())) if len(arr)==0: QMessageBox.warning(self, 'Message',''.join(["Empty array returned. Check Newport start and stop values!"])) return except Exception as e: QMessageBox.warning(self, 'Message',''.join(["All stepper position parameters should be real numbers!\n\n",str(e)])) return for i in range(self.numofintervals): if not self.is_number(self.dwelltimeEdit[i].text()): QMessageBox.warning(self, 'Message',"Dwell time scan parameter is not a real number!") return # For SAVING data if "\\" in self.filenameEdit.text(): self.filenameEdit.setText(self.filenameEdit.text().replace("\\",os.sep)) if "/" in self.filenameEdit.text(): self.filenameEdit.setText(self.filenameEdit.text().replace("/",os.sep)) if not self.filenameEdit.text(): self.filenameEdit.setText(''.join(["data",os.sep,"data"])) if not os.sep in self.filenameEdit.text(): self.filenameEdit.setText(''.join(["data", os.sep, self.filenameEdit.text()])) # Initial read of the config file start_sc = [int(self.startEdit[i].text()) for i in range(self.numofintervals)] stop_sc = [int(self.stopEdit[i].text()) for i in range(self.numofintervals)] step_sc = [int(self.stepEdit[i].text()) for i in range(self.numofintervals)] start_st = float(self.startst_Edit.text()) stop_st = float(self.stopst_Edit.text()) step_st = float(self.stepst_Edit.text()) dwelltime = [float(self.dwelltimeEdit[ii].text()) for ii in range(self.numofintervals)] dwell_ard = float(self.dwelltimeEdit_ard.text()) file_txt = self.create_file(''.join([self.filenameEdit.text(),".txt"])) file_hdf5 = self.create_file(''.join([self.filenameEdit.text(),".hdf5"])) for start,stop,step,dwell in zip(start_sc,stop_sc,step_sc,dwelltime): if start<0 or start>9000: QMessageBox.warning(self, 'Message',"Minimum start wavelength is 0 nm and maximum 9000 nm!") return if stop<0 or stop>9000: QMessageBox.warning(self, 'Message',"Minimum stop wavelength is 0 nm and maximum 9000 nm!") return if step<0 or step>127: QMessageBox.warning(self, 'Message',"Minimum step is 0 units and maximum 127 units!") return if dwell<3*dwell_ard/1000 or dwell>100: QMessageBox.warning(self, 'Message',"Monochromator dwell time is minimum 3 times Arduino dwell time and maximum 100 s!") return if dwell_ard<10 or dwell_ard>dwell*1000: QMessageBox.warning(self, 'Message',"Arduino dwell time is minimum 10 ms and maximum CM110 dwell time!") return self.clear_vars_graphs() self.allFields(False) self.conMode.setEnabled(False) self.runButton.setEnabled(False) self.stopButton.setEnabled(True) self.stopButton.setText("STOP") self.runButton.setText("Scanning...") self.timer.stop() self.get_thread=Run_CM110_Thread(start_sc,stop_sc,step_sc,dwelltime,dwell_ard,self.avg_pts,file_txt,file_hdf5,self.timestr,self.analogref,self.inst_list,start_st,stop_st,step_st) self.get_thread.signals.make_update1.connect(self.make_update1) self.get_thread.signals.make_update2.connect(self.make_update2) self.get_thread.signals.make_update3.connect(self.make_update3) self.get_thread.signals.make_update4.connect(self.make_update4) self.get_thread.signals.finished.connect(self.finished) # Execute self.threadpool.start(self.get_thread) def make_update1(self,set_position,real_positions,endpoint_data,endpoints_times,raw_data): self.set_wl.extend([ 1e-9*set_position ]) self.real_wl.extend([ 1e-9*real_positions ]) self.all_volts.extend([ endpoint_data ]) self.all_times.extend([ endpoints_times ]) self.all_raw.extend([ raw_data ]) if len(self.set_wl)>self.schroll_wl: self.plot_volts[:-1] = self.plot_volts[1:] # shift data in the array one sample left self.plot_volts[-1] = endpoint_data self.plot_wl[:-1] = self.plot_wl[1:] # shift data in the array one sample left self.plot_wl[-1] = 1e-9*set_position self.plot_set_wl[:-1] = self.plot_set_wl[1:] # shift data in the array one sample left self.plot_set_wl[-1] = 1e-9*set_position self.plot_real_wl[:-1] = self.plot_real_wl[1:] # shift data in the array one sample left self.plot_real_wl[-1] = 1e-9*real_positions self.plot_raw[:-1] = self.plot_raw[1:] # shift data in the array one sample left self.plot_raw[-1] = raw_data else: self.plot_volts.extend([ float(endpoint_data) ]) self.plot_wl.extend([ 1e-9*set_position ]) self.plot_set_wl.extend([ 1e-9*set_position ]) self.plot_real_wl.extend([ 1e-9*real_positions ]) self.plot_raw.extend([ int(raw_data) ]) self.curve1[-1].setData(self.plot_wl, self.plot_volts) self.curve5.setData(self.plot_set_wl, self.plot_raw) ## Handle view resizing def updateViews(): ## view has resized; update auxiliary views to match self.p0vb.setGeometry(self.p0.vb.sceneBoundingRect()) ## need to re-update linked axes since this was called ## incorrectly while views had different shapes. ## (probably this should be handled in ViewBox.resizeEvent) self.p0vb.linkedViewChanged(self.p0.vb, self.p0vb.XAxis) updateViews() self.p0.vb.sigResized.connect(updateViews) ########################################################### # Update curve3 in different plot if len(self.set_wl_tr)>=self.schroll_time: local_times=self.all_times[-self.counter:] local_volts=self.all_volts[-self.counter:] self.curve3.setData(local_times, local_volts) else: self.curve3.setData(self.all_times, self.all_volts) def make_update2(self,set_position,real_positions,all_data,timelist): self.set_wl_tr.extend([ 1e-9*set_position ]) self.real_wl_tr.extend([ 1e-9*real_positions ]) #self.all_volts_tr.extend([ float(all_data) ]) #self.all_time_tr.extend([ float(timelist) ]) if len(self.set_wl_tr)==self.schroll_time: self.counter=len(self.set_wl) if len(self.set_wl_tr)>self.schroll_time: self.plot_time_tr[:-1] = self.plot_time_tr[1:] # shift data in the array one sample left self.plot_time_tr[-1] = timelist self.plot_volts_tr[:-1] = self.plot_volts_tr[1:] # shift data in the array one sample left self.plot_volts_tr[-1] = all_data self.plot_set_wl_tr[:-1] = self.plot_set_wl_tr[1:] # shift data in the array one sample left self.plot_set_wl_tr[-1] = 1e-9*set_position self.plot_real_wl_tr[:-1] = self.plot_real_wl_tr[1:] # shift data in the array one sample left self.plot_real_wl_tr[-1] = 1e-9*real_positions else: self.plot_set_wl_tr.extend([ 1e-9*set_position ]) self.plot_real_wl_tr.extend([ 1e-9*real_positions ]) self.plot_volts_tr.extend([ all_data ]) self.plot_time_tr.extend([ timelist ]) ## Handle view resizing def updateViews(): ## view has resized; update auxiliary views to match self.p2.setGeometry(self.p1.vb.sceneBoundingRect()) #p3.setGeometry(p1.vb.sceneBoundingRect()) ## need to re-update linked axes since this was called ## incorrectly while views had different shapes. ## (probably this should be handled in ViewBox.resizeEvent) self.p2.linkedViewChanged(self.p1.vb, self.p2.XAxis) #p3.linkedViewChanged(p1.vb, p3.XAxis) updateViews() self.p1.vb.sigResized.connect(updateViews) self.curve2.setData(self.plot_time_tr, self.plot_volts_tr) self.curve4.setData(self.plot_time_tr, self.plot_set_wl_tr) self.curve6.setData(self.plot_time_tr, self.plot_real_wl_tr) def make_update3(self): self.plot_wl = [] self.plot_volts = [] mycol=next(self.colors) self.curve1.extend( [self.p0.plot(pen=pg.mkPen(mycol,width=1), symbolPen=mycol, symbolBrush=mycol, symbolSize=3)] ) def make_update4(self,val): self.lcdst.display(str(val)[:5]) def set_disconnect(self): ########################################## if self.inst_list.get("CM110"): if self.inst_list.get("CM110").is_open(): self.inst_list.get("CM110").close() self.inst_list.pop("CM110", None) ########################################## if self.inst_list.get("Ard"): if self.inst_list.get("Ard").is_open(): self.inst_list.get("Ard").close() self.inst_list.pop("Ard", None) ########################################## if self.inst_list.get("SR530"): if self.inst_list.get("SR530").is_open(): self.inst_list.get("SR530").close() self.inst_list.pop("SR530", None) ########################################## if self.inst_list.get("SMC100"): if self.inst_list.get("SMC100").is_open(): self.inst_list.get("SMC100").close() self.inst_list.pop("SMC100", None) ########################################## print("All com ports DISCONNECTED") self.allFields(False) self.conMode.setEnabled(True) self.runButton.setText("Load instrument!") self.runButton.setEnabled(False) def set_stop(self): self.stopButton.setEnabled(False) self.stopButton.setText("Stopped") if hasattr(self, "get_thread"): self.get_thread.abort() self.stop_pressed = True def clear_vars_graphs(self): # PLOT 1 initial canvas settings self.set_wl=[] self.real_wl=[] self.all_volts=[] self.all_times=[] self.all_raw=[] self.plot_set_wl=[] self.plot_real_wl=[] self.plot_raw=[] self.plot_volts=[] self.plot_wl=[] for c in self.curve1: c.setData([],[]) self.curve5.setData(self.plot_set_wl, self.plot_raw) self.curve3.setData([], []) self.pw1.enableAutoRange() # Labels and titels are placed here since they change dynamically self.pw1.setTitle(''.join(["CM110 scan as function of wavelength"])) self.pw1.setLabel('left', "Voltage", units='V') self.pw1.setLabel('bottom', "Wavelength", units='m') # PLOT 2 initial canvas settings self.set_wl_tr=[] self.real_wl_tr=[] self.plot_set_wl_tr=[] self.plot_real_wl_tr=[] self.plot_volts_tr=[] self.plot_time_tr=[] self.curve2.setData(self.plot_time_tr, self.plot_volts_tr) self.curve4.setData(self.plot_time_tr, self.plot_set_wl_tr) self.curve6.setData(self.plot_time_tr, self.plot_real_wl_tr) self.pw2.enableAutoRange() # Labels and titels are placed here since they change dynamically self.p1.setTitle(''.join(["CM110 scan as function of time"])) self.p1.setLabel('left', "Voltage", units='V', color='red') self.p1.setLabel('bottom', "Elapsed time", units='s') self.stop_pressed = False def load_(self): # Initial read of the config file self.config = configparser.ConfigParser() try: self.config.read(''.join([self.cwd,os.sep,"config.ini"])) self.last_used_scan = self.config.get("LastScan","last_used_scan") self.numofintervals = int(self.config.get(self.last_used_scan,"numofintervals")) self.start_ = [int(i) for i in self.config.get(self.last_used_scan,"start").strip().split(',')] self.stop = [int(i) for i in self.config.get(self.last_used_scan,"stop").strip().split(',')] self.step = [int(i) for i in self.config.get(self.last_used_scan,"step").strip().split(',')] self.startst = float(self.config.get(self.last_used_scan,"startst")) self.stopst = float(self.config.get(self.last_used_scan,"stopst")) self.stepst = float(self.config.get(self.last_used_scan,"stepst")) self.dwell_time = [int(i) for i in self.config.get(self.last_used_scan,"wait_time").strip().split(',')] self.dwell_time_ard = int(self.config.get(self.last_used_scan,"wait_time_ard")) self.avg_pts = int(self.config.get(self.last_used_scan,"avg_pts")) self.schroll_time = int(self.config.get(self.last_used_scan,"schroll_time")) self.schroll_wl = int(self.config.get(self.last_used_scan,"schroll_wl")) self.filename_str = self.config.get(self.last_used_scan,"filename") self.timestr = self.config.get(self.last_used_scan,"timestr") self.analogref = float(self.config.get(self.last_used_scan,"analogref")) self.minutes = float(self.config.get(self.last_used_scan,"timer")) except configparser.NoOptionError as nov: QMessageBox.critical(self, "Message","".join(["Main FAULT while reading the config.ini file\n",str(nov)])) raise def save_(self): self.timestr=time.strftime("%y%m%d-%H%M") self.lcd.display(self.timestr) self.config.set("LastScan","last_used_scan", self.last_used_scan ) self.config.set(self.last_used_scan,"numofintervals",str(self.numofintervals) ) self.config.set(self.last_used_scan,"start",','.join([str(self.startEdit[ii].text()) for ii in range(self.numofintervals)]) ) self.config.set(self.last_used_scan,"stop",','.join([str(self.stopEdit[ii].text()) for ii in range(self.numofintervals)]) ) self.config.set(self.last_used_scan,"step",','.join([str(self.stepEdit[ii].text()) for ii in range(self.numofintervals)]) ) self.config.set(self.last_used_scan,"wait_time",','.join([str(self.dwelltimeEdit[ii].text()) for ii in range(self.numofintervals)]) ) self.config.set(self.last_used_scan,"startst", str(self.startst_Edit.text()) ) self.config.set(self.last_used_scan,"stopst", str(self.stopst_Edit.text()) ) self.config.set(self.last_used_scan,"stepst", str(self.stepst_Edit.text()) ) self.config.set(self.last_used_scan,"wait_time_ard", str(self.dwelltimeEdit_ard.text()) ) self.config.set(self.last_used_scan,"avg_pts", str(self.avg_pts) ) self.config.set(self.last_used_scan,"schroll_time", str(self.schroll_time) ) self.config.set(self.last_used_scan,"schroll_wl", str(self.schroll_wl) ) self.config.set(self.last_used_scan,"filename", self.filenameEdit.text() ) self.config.set(self.last_used_scan,"timestr", str(self.timestr) ) self.config.set(self.last_used_scan,"analogref", str(self.analogref) ) with open(''.join([self.cwd,os.sep,"config.ini"]), "w") as configfile: self.config.write(configfile) def finished(self): if not self.stop_pressed: self.stopButton.setEnabled(False) if hasattr(self, "get_thread"): self.get_thread.abort() self.stop_pressed = True self.allFields(True) self.conMode.setEnabled(True) if self.inst_list.get("CM110") or self.inst_list.get("SR530") or self.inst_list.get("Ard") or self.inst_list.get("SMC100"): self.allFields(True) self.runButton.setText("Scan") else: self.allFields(False) self.runButton.setText("Load instrument!") self.timer.start(1000*60*self.minutes) def closeEvent(self, event): reply = QMessageBox.question(self, 'Message', "Quit now? Any changes that are not saved will stay unsaved!", QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: if self.inst_list.get("CM110"): if not hasattr(self, "get_thread"): if self.inst_list.get("CM110").is_open(): self.inst_list.get("CM110").close() else: if not self.stop_pressed: QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!") event.ignore() return else: if self.inst_list.get("CM110").is_open(): self.inst_list.get("CM110").close() if self.inst_list.get("SR530"): if not hasattr(self, "get_thread"): if self.inst_list.get("SR530").is_open(): self.inst_list.get("SR530").close() else: if not self.stop_pressed: QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!") event.ignore() return else: if self.inst_list.get("SR530").is_open(): self.inst_list.get("SR530").close() if self.inst_list.get("SMC100"): if not hasattr(self, "get_thread"): if self.inst_list.get("SMC100").is_open(): self.inst_list.get("SMC100").close() else: if not self.stop_pressed: QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!") event.ignore() return else: if self.inst_list.get("SMC100").is_open(): self.inst_list.get("SMC100").close() if self.inst_list.get("Ard"): if not hasattr(self, "get_thread"): if self.inst_list.get("Ard").is_open(): self.inst_list.get("Ard").close() else: if not self.stop_pressed: QMessageBox.warning(self, "Message", "Scan in progress. Stop the scan then quit!") event.ignore() return else: if self.inst_list.get("Ard").is_open(): self.inst_list.get("Ard").close() if hasattr(self, "timer"): if self.timer.isActive(): self.timer.stop() event.accept() else: event.ignore() ########################################## def save_plots(self): # For SAVING data if "\\" in self.filenameEdit.text(): self.filenameEdit.setText(self.filenameEdit.text().replace("\\",os.sep)) if "/" in self.filenameEdit.text(): self.filenameEdit.setText(self.filenameEdit.text().replace("/",os.sep)) if not self.filenameEdit.text(): self.filenameEdit.setText(''.join(["data",os.sep,"data"])) if not os.sep in self.filenameEdit.text(): self.filenameEdit.setText(''.join(["data", os.sep, self.filenameEdit.text()])) save_plot1 = self.create_file(''.join([self.filenameEdit.text(),".png"])) save_plot2 = self.create_file(''.join([self.filenameEdit.text(),"_elapsedtime",".png"])) # create an exporter instance, as an argument give it # the item you wish to export exporter = pg.exporters.ImageExporter(self.pw1.plotItem) exporter.params.param('width').setValue(1920, blockSignal=exporter.widthChanged) exporter.params.param('height').setValue(1080, blockSignal=exporter.heightChanged) # set export parameters if needed #exporter.parameters()['width'] = 100 # (note this also affects height parameter) # save to file exporter.export(save_plot1) exporter = pg.exporters.ImageExporter(self.pw2.plotItem) exporter.params.param('width').setValue(1920, blockSignal=exporter.widthChanged) exporter.params.param('height').setValue(1080, blockSignal=exporter.heightChanged) # set export parameters if needed #exporter.parameters()['width'] = 100 # (note this also affects height parameter) # save to file exporter.export(save_plot2)
class Timer(QDialog): timeout = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.time = 0 self.timeInterval = 1000 #默认秒 self.timerUp = QTimer() self.timerUp.setInterval(self.timeInterval) self.timerUp.timeout.connect(self.updateUptime) self.timerDown = QTimer() self.timerDown.setInterval(self.timeInterval) self.timerDown.timeout.connect(self.updateDowntime) self.initUi() self.buttonStart.clicked.connect(self.timerUp.start) self.buttonStop.clicked.connect(self.timerUp.stop) self.buttonReset.clicked.connect(self.reset) self.buttonCountDown.clicked.connect(self.timerDown.start) self.buttonStopAlarm.clicked.connect(self.timerDown.stop) self.timeSpinBox.valueChanged.connect(self.settimer) def initUi(self): mainLayout = QVBoxLayout() self.setLayout(mainLayout) self.groupBox = QGroupBox("unit") self.radioButton1 = QRadioButton("s") self.radioButton1.toggled.connect(self.setUnit) self.radioButton2 = QRadioButton("0.1s") self.radioButton2.toggled.connect(self.setUnit) self.radioButton3 = QRadioButton("0.01s") self.radioButton3.toggled.connect(self.setUnit) self.radioButton4 = QRadioButton("1ms") self.radioButton4.toggled.connect(self.setUnit) self.radioButton1.setChecked(True) self.unitLayout = QHBoxLayout() self.unitLayout.addWidget(self.radioButton1) self.unitLayout.addWidget(self.radioButton2) self.unitLayout.addWidget(self.radioButton3) self.unitLayout.addWidget(self.radioButton4) self.groupBox.setLayout(self.unitLayout) mainLayout.addWidget(self.groupBox) self.buttonStart = QPushButton(self.tr("start")) mainLayout.addWidget(self.buttonStart) self.buttonStop = QPushButton(self.tr("stop")) mainLayout.addWidget(self.buttonStop) self.timeViewer = QLCDNumber() self.timeViewer.setFixedHeight(45) mainLayout.addWidget(self.timeViewer) self.timeForHuman = QLabel() mainLayout.addWidget(self.timeForHuman) self.buttonReset = QPushButton(self.tr("reset")) mainLayout.addWidget(self.buttonReset) self.timeSpinBox = QSpinBox() self.timeSpinBox.setRange(0, 10000) mainLayout.addWidget(self.timeSpinBox) self.buttonCountDown = QPushButton(self.tr("countdown")) mainLayout.addWidget(self.buttonCountDown) self.buttonStopAlarm = QPushButton(self.tr("stopalarm")) mainLayout.addWidget(self.buttonStopAlarm) def setUnit(self): if self.radioButton1.isChecked(): self.timeInterval = 1000 elif self.radioButton2.isChecked(): self.timeInterval = 100 elif self.radioButton3.isChecked(): self.timeInterval = 10 elif self.radioButton1.isChecked(): self.timeInterval = 1 self.timerUp.setInterval(self.timeInterval) self.timerDown.setInterval(self.timeInterval) def updateUptime(self): self.time += 1 self.settimer(self.time) print(self.time) def updateDowntime(self): self.time = self.time - 1 self.settimer(self.time) print(self.time) if self.time <= 0: self.timeout.emit() def settimer(self, int): self.time = int self.timeViewer.display(self.time) if self.timeInterval == 1000: self.timeForHuman.setText( time.strftime('%H hour %M minute %S second', time.gmtime(self.time))) elif self.timeInterval == 100: self.timeForHuman.setText( time.strftime('%H hour %M minute %S second', time.gmtime(self.time / 10))) elif self.timeInterval == 10: self.timeForHuman.setText( time.strftime('%H hour %M minute %S second', time.gmtime(self.time / 100))) elif self.timeInterval == 1: self.timeForHuman.setText( time.strftime('%H hour %M minute %S second', time.gmtime(self.time / 1000))) def reset(self): self.time = 0 self.settimer(self.time)
class Window(QWidget): def __init__(self, parent=None): super(Window, self).__init__(parent) self.setGeometry(100, 100, 800, 600) # pos pos width height self.PortLabel = QLabel("Port:") self.LabelProd = QLabel("Production:") self.LabelLoad = QLabel("Load:") port_selectBox = QComboBox(self) ports = self.available_serial_ports() for port in ports: port_selectBox.addItem(port) self.buttonConnect = QPushButton('Connect') # self.button.clicked.connect(self.plot) self.b1 = QCheckBox("SerialRead") self.b1.setChecked(True) # self.b1.stateChanged.connect(self.myThread.btnstate(self.b1)) self.b2 = QCheckBox("activateLog") self.b2.setChecked(True) # self.b2.stateChanged.connect(lambda:self.btnstate(self.b2)) self.figure_bar = plt.figure() self.figure_timeseries = plt.figure() self.canvas_bar = FigureCanvas(self.figure_bar) self.canvas_timeseries = FigureCanvas(self.figure_timeseries) # this is the Navigation widget # it takes the Canvas widget and a parent # self.toolbar = NavigationToolbar(self.canvas, self) # set the layout # self.b1.stateChanged.connect(self.SerialRead(self,b1)) self.b1.stateChanged.connect(lambda: self.SerialRead(self.b1)) self.b2.stateChanged.connect(self.SerialLog) self.lcdProd = QLCDNumber(self) self.lcdLoad = QLCDNumber(self) self.lcdProd.setFixedHeight(100) self.lcdLoad.setFixedHeight(100) # --------------------------- Layout col1 = QVBoxLayout() col1.addWidget(self.PortLabel) col1.addWidget(port_selectBox) col1.addWidget(self.buttonConnect) col1.addWidget(self.b1) col1.addWidget(self.b2) col2 = QVBoxLayout() col2.addWidget(self.LabelProd) col2.addWidget(self.lcdProd) col2.addWidget(self.LabelLoad) col2.addWidget(self.lcdLoad) toprow = QHBoxLayout() toprow.addLayout(col1) toprow.addLayout(col2) toprow.addWidget(self.canvas_bar) layout = QVBoxLayout() layout.addLayout(toprow) layout.addWidget(self.canvas_timeseries) # layout.addWidget(self.toolbar) # layout.addWidget(self.button) self.setLayout(layout) # --------------------------------------------------- self.wt = WorkerThread() # This is the thread object self.wt.start() # Connect the signal from the thread to the slot_method self.wt.measurements_signals.connect( self.slot_method) ### 3) connect to the slot app.aboutToQuit.connect( self.wt.stop) # to stop the thread when closing the GUI timespan = 600 load = [0] * timespan production = [550] * timespan pdc = [0] * timespan def slot_method(self, p, l): print("p=", p) print("l=", l) self.lcdProd.display(p) self.lcdLoad.display(l) self.update_chart_timeseries(p, l) self.update_chart_bar(p, l) def SerialRead(self, b): enable = b.isChecked() print("enable=" + str(enable)) # self.myThread.start() def SerialLog(self, b2): print("b2") def threadDone(self): print("Done") # def update_chart(self, produzione, carico): # load.pop(0) # load.append(carico) # production.pop(0) # production.append(produzione) # # self.figure.clear() #questo è importante # plt.plot(production, color="b") # plt.plot(load, color="r") # #plt.set_ylim([0,max(load, production)]) # plt.ylim(ymin=0) # plt.legend(['PV', 'Load'], loc='upper left') # self.canvas.draw() def update_chart_bar(self, produzione, carico): # bar objects = ('Carico', 'Produzione', 'Immissione') y_pos = np.arange(len(objects)) immissione = produzione - carico performance = [carico, produzione, immissione] self.figure_bar.clear() plt.figure(num=self.figure_bar.number) # aggiunta da massimo maggi :) plt.bar(y_pos, performance, align='center', alpha=0.5) plt.xticks(y_pos, objects) plt.ylabel('Power [W]') plt.title('Power usage') # is printing this in the wrong canvas self.canvas_bar.draw() def update_chart_timeseries(self, produzione, carico): # time series load.pop(0) load.append(carico) production.pop(0) production.append(produzione) self.figure_timeseries.clear() # questo è importante plt.figure( num=self.figure_timeseries.number) # aggiunta da massimo maggi :) plt.plot(production, color="b") plt.plot(load, color="r") # plt.set_ylim([0,max(load, production)]) plt.ylim(ymin=0) plt.legend(['PV', 'Load'], loc='upper left') self.canvas_timeseries.draw() def available_serial_ports(self): """ Lists serial port names :raises EnvironmentError: On unsupported or unknown platforms :returns: A list of the serial ports available on the system """ if sys.platform.startswith('win'): ports = ['COM%s' % (i + 1) for i in range(256)] elif sys.platform.startswith('linux') or sys.platform.startswith( 'cygwin'): # this excludes your current terminal "/dev/tty" ports = glob.glob('/dev/tty[A-Za-z]*') elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') else: raise EnvironmentError('Unsupported platform') result = [] for port in ports: try: s = serial.Serial(port) s.close() result.append(port) except (OSError, serial.SerialException): pass return result
class GUV_TEST_dialog(QDialog): def __init__(self, parent): super().__init__(parent) # Initial read of the config file self.config = configparser.ConfigParser() try: self.config.read('config.ini') self.last_used_scan = self.config.get('LastScan', 'last_used_scan') #self.log_guv=self.bool_(self.config.get(self.last_used_scan,'log_guv')) self.schroll_pts = int( self.config.get(self.last_used_scan, 'schroll')) self.log_guv_str = self.config.get(self.last_used_scan, 'log_guv').strip().split(',')[0] self.log_guv_check = self.bool_( self.config.get(self.last_used_scan, 'log_guv').strip().split(',')[1]) self.guvip = self.config.get("Instruments", 'guvport').strip().split(',')[0] self.guvport = self.config.get("Instruments", 'guvport').strip().split(',')[1] self.guvtype_str = self.config.get("Instruments", 'guvtype') except configparser.NoOptionError as e: QMessageBox.critical( self, 'Message', ''.join( ["Main FAULT while reading the config.ini file\n", str(e)])) raise self.setupUi() def bool_(self, txt): if txt == "True": return True elif txt == "False": return False def setupUi(self): ipport = QLabel("TCP/IP port", self) self.ipportEdit = QLineEdit(self.guvip, self) tcpport = QLabel("TCP port", self) self.tcpportEdit = QLineEdit(self.guvport, self) guvtype_lbl = QLabel("GUV type", self) self.guvtype_cb = QComboBox(self) mylist = ["GUV-541", "GUV-2511", "GUV-3511"] self.guvtype_cb.addItems(mylist) self.guvtype_cb.setCurrentIndex(mylist.index(self.guvtype_str)) ############################################## self.runstopButton = QPushButton("START", self) self.clearButton = QPushButton("Clear", self) ############################################## schroll_lbl = QLabel("Schroll elapsed time ", self) self.combo0 = QComboBox(self) mylist0 = ["100", "200", "400", "600", "800", "1000", "1500", "2000"] self.combo0.addItems(mylist0) self.combo0.setCurrentIndex(mylist0.index(str(self.schroll_pts))) ############################################## self.cb_logdata = QCheckBox('Log data to file', self) self.cb_logdata.toggle() self.cb_logdata.setChecked(self.log_guv_check) #self.cb_logdata.setLayoutDirection(Qt.RightToLeft) self.file_edit = QLineEdit(self.log_guv_str, self) self.file_edit.setStyleSheet("color: blue") if self.cb_logdata.isChecked(): self.file_edit.setEnabled(True) else: self.file_edit.setEnabled(False) self.lcd = QLCDNumber(self) self.lcd.setStyleSheet("color: red") self.lcd.setFixedWidth(170) self.lcd.setFixedHeight(35) self.lcd.setSegmentStyle(QLCDNumber.Flat) self.lcd.setNumDigits(11) self.time_str = time.strftime("%y%m%d-%H%M") self.lcd.display(self.time_str) ############################################## g0_1 = QGridLayout() g0_1.addWidget(ipport, 0, 0) g0_1.addWidget(self.ipportEdit, 0, 1) g0_1.addWidget(tcpport, 0, 2) g0_1.addWidget(self.tcpportEdit, 0, 3) g0_1.addWidget(guvtype_lbl, 0, 4) g0_1.addWidget(self.guvtype_cb, 0, 5) g0_2 = QGridLayout() g0_2.addWidget(schroll_lbl, 0, 0) g0_2.addWidget(self.combo0, 0, 1) g0_2.addWidget(self.runstopButton, 0, 2) g0_2.addWidget(self.clearButton, 0, 3) g0_2.addWidget(self.cb_logdata, 1, 0) g0_2.addWidget(self.lcd, 1, 1) g0_4 = QVBoxLayout() g0_4.addLayout(g0_1) g0_4.addLayout(g0_2) g0_4.addWidget(self.file_edit) ############################################## # set graph and toolbar to a new vertical group vcan self.pw1 = pg.PlotWidget() self.pw1.setFixedWidth(600) ############################################## # create table self.tableWidget = self.createTable() ############################################## # SET ALL VERTICAL COLUMNS TOGETHER vbox = QVBoxLayout() vbox.addLayout(g0_4) vbox.addWidget(self.pw1) hbox = QVBoxLayout() hbox.addLayout(vbox) hbox.addWidget(self.tableWidget) self.threadpool = QThreadPool() print("Multithreading in the GUV dialog with maximum %d threads" % self.threadpool.maxThreadCount()) self.isRunning = False self.setLayout(hbox) self.setWindowTitle("Test GUV") # PLOT 2 settings # create plot and add it to the figure canvas self.p1 = self.pw1.plotItem self.curves = [] colors = itertools.cycle(["r", "b", "g", "y", "m", "c", "w"]) for i in range(20): mycol = next(colors) self.curves.append( self.p1.plot(pen=pg.mkPen(color=mycol), symbol='s', symbolPen=mycol, symbolBrush=mycol, symbolSize=4)) # create plot and add it to the figure self.p0_1 = pg.ViewBox() self.curve2 = pg.PlotCurveItem(pen='r') self.p0_1.addItem(self.curve2) # connect respective axes to the plot #self.p1.showAxis('left') self.p1.getAxis('left').setLabel("Power density", units="", color='yellow') self.p1.showAxis('right') self.p1.getAxis('right').setLabel("Arb unit", units="", color='red') self.p1.scene().addItem(self.p0_1) self.p1.getAxis('right').linkToView(self.p0_1) self.p0_1.setXLink(self.p1) self.p1.getAxis('bottom').setLabel("Time passed", units="s", color='yellow') # Use automatic downsampling and clipping to reduce the drawing load self.pw1.setDownsampling(mode='peak') self.pw1.setClipToView(True) # Initialize and set titles and axis names for both plots self.clear_vars_graphs() self.combo0.activated[str].connect(self.onActivated0) self.guvtype_cb.activated[str].connect(self.onActivated1) self.cb_logdata.toggled.connect(self.logdata) # run or cancel the main script self.runstopButton.clicked.connect(self.runstop) self.clearButton.clicked.connect(self.set_clear) self.clearButton.setEnabled(False) def logdata(self): if self.cb_logdata.isChecked(): self.time_str = time.strftime("%y%m%d-%H%M") head, tail = os.path.split(str(self.file_edit.text())) self.log_guv_str = ''.join( [head, '/log_', self.guvtype_str, '_', self.time_str]) self.lcd.display(self.time_str) self.file_edit.setText(self.log_guv_str) self.file_edit.setEnabled(True) else: self.file_edit.setEnabled(False) def onActivated0(self, text): old_st = self.schroll_pts self.schroll_pts = int(str(text)) if old_st > self.schroll_pts: self.set_clear() def onActivated1(self, text): old_guvtype = self.guvtype_str self.guvtype_str = str(text) if old_guvtype != self.guvtype_str: head, tail = os.path.split(str(self.file_edit.text())) self.log_guv_str = ''.join( [head, '/log_', self.guvtype_str, '_', self.time_str]) self.file_edit.setText(self.log_guv_str) self.set_clear() ''' self.config.set(self.last_used_scan, 'guvtype', self.guvtype_str) with open('config.ini', 'w') as configfile: self.config.write(configfile) ''' def createTable(self): tableWidget = QTableWidget() #tableWidget.setFixedWidth(175) # set row count #tableWidget.setRowCount(20) # set column count tableWidget.setColumnCount(2) # hide grid tableWidget.setShowGrid(False) # hide vertical header vh = tableWidget.verticalHeader() vh.setVisible(False) # set the font font = QFont("Courier New", 9) tableWidget.setFont(font) tableWidget.setStyleSheet("color: blue") # place content into individual table fields #tableWidget.setItem(0,0, QTableWidgetItem("abe")) tableWidget.setHorizontalHeaderLabels( ["Time[s]", "Channel power density"]) #tableWidget.setVerticalHeaderLabels(["aa","bb","cc","dd"]) # set horizontal header properties hh = tableWidget.horizontalHeader() hh.setStretchLastSection(True) # set column width to fit contents tableWidget.resizeColumnsToContents() # enable sorting #tableWidget.setSortingEnabled(True) return tableWidget def set_cancel(self): self.worker.abort() self.clearButton.setEnabled(True) self.runstopButton.setText("START") def set_clear(self): self.clear_vars_graphs() self.clearButton.setEnabled(False) self.clearButton.setText("Cleared") def runstop(self): sender = self.sender() if sender.text() == "START": self.set_run() elif sender.text() == "STOP": self.set_cancel() def set_run(self): if self.cb_logdata.isChecked(): # Check if folder exists and if not create it head, tail = os.path.split(str(self.file_edit.text())) if head: if head[0] == '/': QMessageBox.critical( self, 'Message', 'Path name should not start with a forward slash (/)') return else: QMessageBox.critical(self, 'Message', 'No path to folder(s) provided!') return try: os.makedirs(os.path.dirname(str(self.file_edit.text())), exist_ok=True) except Exception as e: QMessageBox.critical( self, 'Message', ''.join(["Folder named ", head, " not valid!\n", str(e)])) return self.log_guv_str = str(self.file_edit.text()) self.config.set(self.last_used_scan, 'log_guv', ','.join([self.log_guv_str, str(True)])) else: self.config.set(self.last_used_scan, 'log_guv', ','.join([self.log_guv_str, str(False)])) with open('config.ini', 'w') as configfile: self.config.write(configfile) try: self.GUV = GUV.GUV([ str(self.ipportEdit.text()), str(self.tcpportEdit.text()), self.guvtype_str ], False, self.config) except Exception as e: reply = QMessageBox.critical( self, ''.join([self.guvtype_str, ' TEST MODE']), ''.join([ self.guvtype_str, " could not return valid echo signal. Check the port name and check the connection.\n", str(e), "\n\nShould the program proceeds into the TEST MODE?" ]), QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.GUV = GUV.GUV([ str(self.ipportEdit.text()), str(self.tcpportEdit.text()), self.guvtype_str ], True, self.config) else: return #self.set_clear() self.runstopButton.setEnabled(True) self.runstopButton.setText("STOP") self.clearButton.setEnabled(False) self.combo0.setEnabled(False) self.ipportEdit.setEnabled(False) self.tcpportEdit.setEnabled(False) self.guvtype_cb.setEnabled(False) self.cb_logdata.setEnabled(False) self.file_edit.setEnabled(False) self.isRunning = True setrun_obj = type('setscan_obj', (object, ), {'guv': self.GUV}) self.worker = GUV_Worker(setrun_obj) self.worker.signals.update0.connect(self.update0) self.worker.signals.finished.connect(self.finished) # Execute self.threadpool.start(self.worker) def update0(self, times, volts): self.tal += 1 times = [i + self.stoptime for i in times] # set row height self.tableWidget.setRowCount(self.tal + 1) self.tableWidget.setRowHeight(self.tal, 12) # add row elements self.tableWidget.setItem(self.tal, 0, QTableWidgetItem(format(times[0], '.2e'))) self.tableWidget.setItem( self.tal, 1, QTableWidgetItem(', '.join( [format(float(i), '.2e') for i in volts]))) if self.tal > self.schroll_pts: self.times[:-1] = self.times[ 1:] # shift data in the array one sample left self.times[-1] = times self.plot_volts_tr[:-1] = self.plot_volts_tr[ 1:] # shift data in the array one sample left self.plot_volts_tr[-1] = volts else: self.times.append(times) self.plot_volts_tr.append(volts) ## Handle view resizing def updateViews(): ## view has resized; update auxiliary views to match self.p0_1.setGeometry(self.p1.vb.sceneBoundingRect()) #p3.setGeometry(p1.vb.sceneBoundingRect()) ## need to re-update linked axes since this was called ## incorrectly while views had different shapes. ## (probably this should be handled in ViewBox.resizeEvent) self.p0_1.linkedViewChanged(self.p1.vb, self.p0_1.XAxis) #p3.linkedViewChanged(p1.vb, p3.XAxis) updateViews() self.p1.vb.sigResized.connect(updateViews) times_ = list(map(list, zip(*self.times))) plot_volts_tr_ = list(map(list, zip(*self.plot_volts_tr))) for i in range(len(times_)): self.curves[i].setData(times_[i], plot_volts_tr_[i]) #self.curve2.setData(self.times, self.plot_volts_tr) def finished(self): self.stoptime = self.times[-1][-1] self.isRunning = False self.ipportEdit.setEnabled(True) self.tcpportEdit.setEnabled(True) self.guvtype_cb.setEnabled(True) self.cb_logdata.setEnabled(True) if self.cb_logdata.isChecked(): self.file_edit.setEnabled(True) else: self.file_edit.setEnabled(False) self.combo0.setEnabled(True) self.clearButton.setEnabled(True) self.clearButton.setText("Clear") def clear_vars_graphs(self): # PLOT 2 initial canvas settings self.stoptime = 0 self.tal = -1 self.times = [] self.plot_volts_tr = [] for i in range(20): self.curves[i].clear() self.curve2.clear() self.tableWidget.clearContents() def closeEvent(self, event): reply = QMessageBox.question(self, 'Message', "Quit now? Changes will not be saved!", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: if hasattr(self, 'GUV'): if self.isRunning: QMessageBox.warning( self, 'Message', "Run in progress. Cancel the scan then quit!") event.ignore() return event.accept() else: event.ignore()