class VolumeScanningWidget(QWidget): def __init__(self, state, timer): super().__init__() self.state = state self.timer = timer self.setLayout(QVBoxLayout()) self.wid_volume = ParameterGui(state.volume_setting) self.chk_pause = QCheckBox("Pause after experiment") self.wid_wave = WaveformWidget(timer=self.timer, state=self.state) self.wid_collapsible_wave = CollapsibleWidget( child=self.wid_wave, name="Piezo impulse-response waveform") self.wid_collapsible_wave.toggle_collapse() self.layout().addWidget(self.wid_volume) self.layout().addWidget(self.chk_pause) self.layout().addWidget(self.wid_collapsible_wave) self.chk_pause.clicked.connect(self.change_pause_status) self.chk_pause.click() def change_pause_status(self): self.state.pause_after = self.chk_pause.isChecked()
class LoginPopup(QDialog): user_listed = pyqtSignal(dict) # 登录成功发出信号 def __init__(self, *args, **kwargs): super(LoginPopup, self).__init__(*args, **kwargs) layout = QVBoxLayout(spacing=0) # 手机 phone_layout = QHBoxLayout() phone_label = QLabel() phone_label.setPixmap(QPixmap('media/passport_icon/phone.png')) phone_layout.addWidget(phone_label) # 填写手机 self.phone_edit = QLineEdit(textEdited=self.phone_editing) phone_layout.addWidget(self.phone_edit) layout.addLayout(phone_layout) # 手机号错误提示框 self.phone_error = QLabel() layout.addWidget(QLabel(parent=self, objectName='phoneError')) # 密码 psd_layout = QHBoxLayout() password_label = QLabel() password_label.setPixmap(QPixmap('media/passport_icon/password.png')) psd_layout.addWidget(password_label) # 填写密码 self.password_edit = QLineEdit() self.password_edit.setEchoMode(QLineEdit.Password) psd_layout.addWidget(self.password_edit) layout.addLayout(psd_layout) # 密码错误提示框 layout.addWidget(QLabel(parent=self, objectName='psdError')) # 记住密码 remember_layout = QHBoxLayout(spacing=2) # 点击事件由代码不触发 self.remember_psd = QCheckBox('记住密码', objectName='rememberCheck', clicked=self.clicked_remember_psd) remember_layout.addWidget(self.remember_psd) # 记住登录 # self.remember_login = QCheckBox('自动登录', objectName='rememberCheck', clicked=self.clicked_auto_login) # remember_layout.addWidget(self.remember_login) remember_layout.addStretch() layout.addLayout(remember_layout) # 登录错误框 layout.addWidget(QLabel(parent=self, objectName='loginError')) # 确认登录 login_button = QPushButton('登录', clicked=self.commit_login, objectName='loginBtn') layout.addWidget(login_button) # 样式 self.setWindowTitle('登录') self.setMinimumWidth(300) self.setStyleSheet(""" #phoneError, #psdError, #loginError{ color: rgb(200,50,30) } #rememberCheck{ color: rgb(100,100,100) } #loginBtn{ background-color:rgb(46,158,224); color: rgb(240,240,240); font-weight:bold; min-height:28px; border:none; } #loginBtn:pressed{ background-color:rgb(28,76,202); } """) phone_label.setFixedSize(36, 35) phone_label.setScaledContents(True) self.phone_edit.setFixedHeight(35) password_label.setScaledContents(True) password_label.setFixedSize(36, 35) self.password_edit.setFixedHeight(35) # 布局 self.setLayout(layout) self._init_account() # 正在输入账号 def phone_editing(self): self.password_edit.setText('') self.remember_psd.setChecked(False) # self.remember_login.setChecked(False) # 选择记住密码 def clicked_remember_psd(self): remember = self.remember_psd.isChecked() phone, password = self.get_account() if not remember: # 保存用户名和密码 password = '' account = json.dumps({'phone': phone, 'password': password}) account = base64.b64encode(account.encode('utf-8')).decode('utf-8') settings.app_dawn.setValue('user', account) # 保存用户名和密码 # 选择自动登录 def clicked_auto_login(self): # auto_login = self.remember_login.isChecked() auto_login = False remember_psd_flag = self.remember_psd.isChecked() self.remember_psd.setChecked(False) # 保存用户名和密码 if auto_login: self.remember_psd.click() # 保存用户资料 settings.app_dawn.setValue('auto', 1) else: self.remember_psd.setChecked(remember_psd_flag) # 取消自动登录 settings.app_dawn.setValue('auto', 0) # 删除token settings.app_dawn.remove('AUTHORIZATION') # 读取用户名填入 def _init_account(self): user = settings.app_dawn.value('user') if user: account = base64.b64decode(user.encode('utf-8')) account = json.loads(account.decode('utf-8')) phone = account.get('phone', '') password = account.get('password', '') self.phone_edit.setText(phone) self.password_edit.setText(password) if password: self.remember_psd.setChecked(True) # if settings.app_dawn.value('auto') == '1': # self.remember_login.setChecked(True) # 获取手机号和密码 def get_account(self): # 获取手机 phone = re.match(r'^[1][3-9][0-9]{9}$', self.phone_edit.text()) if not phone: phone = '' else: phone = phone.group() # 获取密码 password = re.sub(r'\s+', '', self.password_edit.text()) if not password: password = '' return phone, password # 获取手机号和密码提交登录 def commit_login(self): phone, password = self.get_account() if not phone: self.findChild(QLabel, 'phoneError').setText('请输入正确的手机号') return # 登录成功 if self._login_post(phone, password): self.close() # 提交登录 def _login_post(self, phone, password): try: r = requests.post( url=settings.SERVER_ADDR + 'login/', headers={ "Content-Type": "application/json;charset=utf8", "AUTHORIZATION": settings.app_dawn.value('AUTHORIZATION'), }, data=json.dumps({ "phone": phone, "password": password, "machine_code":settings.app_dawn.value('machine', '') }), ) response = json.loads(r.content.decode('utf-8')) if r.status_code != 200: raise ValueError(response['message']) except Exception as e: self.findChild(QLabel, 'loginError').setText(str(e)) # 移除token settings.app_dawn.remove('AUTHORIZATION') return False else: self.user_listed.emit(response['user_data']) return True
class QtBoolEdit(QWidget): toggledSignal = pyqtSignal(bool) def __init__(self, parent=None): super(QtBoolEdit, self).__init__(parent) self.m_checkBox = QCheckBox(self) self.m_textVisible = True lt = QHBoxLayout() if (QApplication.layoutDirection() == Qt.LeftToRight): lt.setContentsMargins(4, 0, 0, 0) else: lt.setContentsMargins(0, 0, 4, 0) lt.addWidget(self.m_checkBox) self.setLayout(lt) self.m_checkBox.toggled.connect(self.toggledSignal) self.setFocusProxy(self.m_checkBox) self.m_checkBox.setText(self.tr("True")) def textVisible(self): return self.m_textVisible def setTextVisible(self, textVisible): if (self.m_textVisible == textVisible): return self.m_textVisible = textVisible if self.m_textVisible: if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) else: self.m_checkBox.setText('') def checkState(self): return self.m_checkBox.checkState() def setCheckState(self, state): self.m_checkBox.setCheckState(state) def isChecked(self): return self.m_checkBox.isChecked() def setChecked(self, c): self.m_checkBox.setChecked(c) if self.m_textVisible == False: return if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) def blockCheckBoxSignals(self, block): return self.m_checkBox.blockSignals(block) def mousePressEvent(self, event): if (event.buttons() == Qt.LeftButton): self.m_checkBox.click() event.accept() else: super(QtBoolEdit, self).mousePressEvent(event) def paintEvent(self, pt_QPaintEvent): opt = QStyleOption() opt.initFrom(self) p = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)
class QtBoolEdit(QWidget): toggledSignal = pyqtSignal(bool) def __init__(self,parent=None): super(QtBoolEdit, self).__init__(parent) self.m_checkBox = QCheckBox(self) self.m_textVisible = True lt = QHBoxLayout() if (QApplication.layoutDirection() == Qt.LeftToRight): lt.setContentsMargins(4, 0, 0, 0) else: lt.setContentsMargins(0, 0, 4, 0) lt.addWidget(self.m_checkBox) self.setLayout(lt) self.m_checkBox.toggled.connect(self.toggledSignal) self.setFocusProxy(self.m_checkBox) self.m_checkBox.setText(self.tr("True")) def textVisible(self): return self.m_textVisible def setTextVisible(self,textVisible): if (self.m_textVisible == textVisible): return self.m_textVisible = textVisible if self.m_textVisible: if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) else: self.m_checkBox.setText('') def checkState(self): return self.m_checkBox.checkState() def setCheckState(self,state): self.m_checkBox.setCheckState(state) def isChecked(self): return self.m_checkBox.isChecked() def setChecked(self,c): self.m_checkBox.setChecked(c) if self.m_textVisible==False: return if self.isChecked(): self.m_checkBox.setText(self.tr("True")) else: self.m_checkBox.setText(self.tr("False")) def blockCheckBoxSignals(self,block): return self.m_checkBox.blockSignals(block) def mousePressEvent(self, event): if (event.buttons() == Qt.LeftButton): self.m_checkBox.click() event.accept() else: super(QtBoolEdit, self).mousePressEvent(event) def paintEvent(self, pt_QPaintEvent): opt = QStyleOption() opt.initFrom(self) p = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, p, self)
class Button_Node(Node): def __init__(self, main_obg, parametrs=[ '0', 'Вкл', '50', '50', '1', '1', '0', '1', 'выкл', '1', 'Кнопка', 'None', '0' ]): super().__init__(main_obg, parametrs[10], int(parametrs[2]), int(parametrs[3])) self.main_window_obg = main_obg self.index_comand = parametrs[4] self.first_comand = parametrs[5] # Первая команда self.second_comand = parametrs[6] # Вторая команда self.btn_flag = True # Отправка первой или второй команды self.parametr_btn = False # наличие второй команды self.btn_name = parametrs[1] self.two_btn_name = parametrs[8] self.size_big_btn = float(parametrs[7]) self.mode = int( parametrs[9] ) # тип кнопки 1 - одна команда 2 - две попеременно 3 - две "нажал отпустил" self.key_state = bool(int(parametrs[12])) self.key_btn = int(parametrs[11]) if parametrs[11] != 'None' else None self.key_flag = False # |--------------------------------------------| обьявление виджетов self.big_btn = QPushButton(self.btn_name, self.main_window_obg) self.big_btn.clicked.connect(self.enter_comand) self.big_btn.pressed.connect(self.enter_comand_for_3_mode) self.text_set2 = QLabel(self.main_window_obg) self.text_set2.setText('Имя кнопки 1:') self.input_line2 = QLineEdit(self.btn_name, self.main_window_obg) self.input_line2.textChanged.connect(self.change_btn_name_1) self.input_line2.resize(60, 23) self.text_set3 = QLabel(self.main_window_obg) self.text_set3.setText('Индекс:') self.input_line3 = QLineEdit(self.index_comand, self.main_window_obg) self.input_line3.textChanged.connect(self.change_index) self.input_line3.resize(60, 23) self.text_set4 = QLabel(self.main_window_obg) self.text_set4.setText('Команда 1:') self.input_line4 = QLineEdit(self.first_comand, self.main_window_obg) self.input_line4.textChanged.connect(self.change_first_parametr) self.input_line4.resize(60, 23) self.text_set5 = QLabel(self.main_window_obg) self.text_set5.setText('Размер:') self.input_line5 = QLineEdit(str(self.size_big_btn), self.main_window_obg) self.input_line5.editingFinished.connect(self.change_size_big_btn) self.input_line5.resize(60, 23) self.rb_group = QButtonGroup(self.main_window_obg) self.rb1 = QRadioButton("Один сигнал", self.main_window_obg) self.rb1.move(50, 50) if self.mode == 1: self.rb1.click() self.rb1.clicked.connect(self.update_type) self.rb2 = QRadioButton("Два сигнала попеременно", self.main_window_obg) self.rb2.move(80, 50) if self.mode == 2: self.rb2.click() self.rb2.clicked.connect(self.update_type) self.rb3 = QRadioButton('Два сигнала "нажал-отпустил"', self.main_window_obg) self.rb3.move(120, 50) if self.mode == 3: self.rb3.click() self.rb3.clicked.connect(self.update_type) self.rb_group.addButton(self.rb1) self.rb_group.addButton(self.rb2) self.rb_group.addButton(self.rb3) self.text_set7 = QLabel(self.main_window_obg) self.text_set7.setText('Команда 2:') self.input_line7 = QLineEdit(self.second_comand, self.main_window_obg) self.input_line7.textChanged.connect(self.change_second_parametr) self.input_line7.resize(60, 23) self.text_set8 = QLabel(self.main_window_obg) self.text_set8.setText('Имя кнопки 2:') self.input_line8 = QLineEdit(self.two_btn_name, self.main_window_obg) self.input_line8.textChanged.connect(self.change_btn_name_2) self.input_line8.resize(60, 23) self.key_chekBox = QCheckBox('Использовать клавиши', self.main_window_obg) self.key_chekBox.stateChanged.connect(self.change_key_state) if self.key_state: self.key_chekBox.click() self.lit = QLabel(self.main_window_obg) if self.key_btn != None: self.lit.setText(chr(self.key_btn)) # |--------------------------------------------| # Список всех виджетов нода и их относительных координат self.arr_of_elem.extend([(self.big_btn, 0, 21), (self.text_set2, 0, 78), (self.input_line2, 84, 76), (self.text_set3, 0, 102), (self.input_line3, 46, 100), (self.text_set4, 0, 128), (self.input_line4, 66, 125), (self.text_set5, 0, 152), (self.input_line5, 50, 150), (self.rb1, 0, 170), (self.rb2, 0, 190), (self.rb3, 0, 210), (self.text_set7, 0, 232), (self.input_line7, 66, 230), (self.text_set8, 0, 257), (self.input_line8, 84, 255), (self.key_chekBox, 0, 280), (self.lit, 0, 50)]) # Список всех виджетов настроек self.elems_of_settings = [ self.text_set1, self.input_line1, self.text_set2, self.input_line2, self.input_line3, self.text_set3, self.text_set4, self.input_line4, self.text_set5, self.input_line5, self.rb1, self.rb2, self.rb3, self.text_set7, self.input_line7, self.text_set8, self.input_line8, self.key_chekBox, self.delete_btn, self.copy_btn ] # Список дополнительных настроек self.additional_widgets = [ self.text_set7, self.input_line7, self.text_set8, self.input_line8 ] for elem in self.elems_of_settings: elem.hide() self.big_btn.resize(int(100 * self.size_big_btn), int(30 * self.size_big_btn)) self.ubdate_cord(self.x, self.y) self.update_type() for elem in self.additional_widgets: elem.hide() self.change_key_state(None, self.key_btn) def del_widgets(self): if self.delete: for elem in self.arr_of_elem: elem[0].deleteLater() self.delete = False def parametrs_return(self): return [ '0', self.btn_name, str(self.x), str(self.y), self.index_comand, self.first_comand, self.second_comand, str(self.size_big_btn), self.two_btn_name, str(self.mode), self.name, str(self.key_btn), str(int(self.key_state)) ] def enter_comand(self): global ser if self.mode == 2: comand = self.left_com + self.index_comand + \ self.middle_com + self.first_comand + self.right_com if self.btn_flag else \ self.left_com + self.index_comand + \ self.middle_com + self.second_comand + self.right_com print('2', comand) if self.btn_flag: ser.write(comand.encode()) self.big_btn.setText(self.btn_name) self.btn_flag = False else: ser.write(comand.encode()) self.big_btn.setText(self.two_btn_name) self.btn_flag = True elif self.mode == 1: comand = self.left_com + self.index_comand + \ self.middle_com + self.first_comand + self.right_com self.big_btn.setText(self.btn_name) ser.write(comand.encode()) print(comand) elif self.mode == 3: comand = self.left_com + self.index_comand + \ self.middle_com + self.first_comand + self.right_com self.big_btn.setText(self.btn_name) ser.write(comand.encode()) print(comand) def enter_comand_for_3_mode(self): global ser if self.mode == 3: comand = self.left_com + self.index_comand + \ self.middle_com + self.second_comand + self.right_com self.big_btn.setText(self.two_btn_name) ser.write(comand.encode()) print(comand) def change_btn_name_1(self): self.big_btn.setText(self.input_line2.text()) self.btn_name = self.input_line2.text() self.big_btn.resize(self.big_btn.sizeHint()) def change_btn_name_2(self): self.two_btn_name = self.input_line8.text() def change_index(self): self.index_comand = self.input_line3.text() def change_parametr_btn(self): self.parametr_btn = not self.parametr_btn if self.parametr_btn: for elem in [self.text_set2]: elem.show() else: for elem in [self.text_set2]: elem.hide() def change_first_parametr(self): self.first_comand = self.input_line4.text() def change_second_parametr(self): self.second_comand = self.input_line7.text() def change_size_big_btn(self): self.size_big_btn = float(self.input_line5.text()) self.big_btn.resize(int(100 * self.size_big_btn), int(30 * self.size_big_btn)) def change_key_state(self, data, key=None, released=False): # self.key_state = not self.key_state try: if self.key_chekBox.isChecked() and key == None: self.key_state = True self.key_flag = True self.key_chekBox.setText('Нажмите на клавишу') elif key != None and self.key_flag: self.key_chekBox.setText('Нажата клавиша:' + chr(key)) self.lit.setText(chr(key)) #self.lit.resize(self.lit.sizeHint()) self.btn_flag = True self.key_btn = key self.key_flag = False elif self.key_btn == key and data != None: if self.mode == 3 and released: self.enter_comand() elif self.mode == 3 and not released: self.enter_comand_for_3_mode() elif not released: self.big_btn.click() elif not self.key_chekBox.isChecked(): self.key_btn = key self.lit.setText('') self.key_state = False self.key_chekBox.setText('Использовать клавиши') except Exception: pass def update_type(self): if self.rb1.isChecked(): self.mode = 1 self.big_btn.setCheckable(False) for elem in self.additional_widgets: elem.hide() elif self.rb2.isChecked(): self.mode = 2 self.big_btn.setCheckable(True) for elem in self.additional_widgets: elem.show() elif self.rb3.isChecked(): self.mode = 3 self.big_btn.setCheckable(False) for elem in self.additional_widgets: elem.show() def open_setings(self): if self.flag: self.settings_btn.setText('▼') self.flag = False for elem in self.elems_of_settings: elem.show() if self.mode == 1: for elem in self.additional_widgets: elem.hide() self.big_btn.resize(100, 30) self.lit.hide() else: self.settings_btn.setText('▲') self.flag = True for elem in self.elems_of_settings: elem.hide() self.big_btn.resize(int(100 * self.size_big_btn), int(30 * self.size_big_btn)) self.lit.show() def is_keyword(self): return True if self.key_state else False
class SettingsWindow(QMainWindow): def __init__(self, ruler, *args, **kwargs): super(SettingsWindow, self).__init__(*args, **kwargs) self.ruler = ruler self.setWindowTitle("Screen Ruler") app_icon = QIcon("ruler.ico") self.setWindowIcon(app_icon) central_widget = CentralWidget() self.setCentralWidget(central_widget) greeting = QLabel("This is the options menu\nSet up your ruler for accurate measurements") font = greeting.font() font.setPointSize(13) greeting.setFont(font) central_widget.addWidget(greeting, 0, 0) auto_widget = QWidget() auto_layout = QGridLayout(auto_widget) auto_label = QLabel("Auto") self.auto_checkbox = QCheckBox() self.auto_checkbox.clicked.connect(self.toggle_auto) auto_layout.addWidget(auto_label, 0, 0, Qt.AlignRight) auto_layout.addWidget(self.auto_checkbox, 0, 1) central_widget.addWidget(auto_widget, 1, 0) input_widget = QWidget() self.input_layout = QGridLayout(input_widget) self.input_layout.setContentsMargins(0, 10, 0, 35) central_widget.addWidget(input_widget, 2, 0) texts = ["horizontal resolution: ", "vertical resolution: ", "screen diagonal size (in inches): "] for index, text in enumerate(texts): label = QLabel(text) self.input_layout.addWidget(label, index, 0) default_values = ["1920", "1080", "23"] fields = [] for index, value in enumerate(default_values): input_field = QLineEdit(value) input_field.setStyleSheet("QLineEdit:read-only { background: darkgray; selection-background-color: gray; border: darkgray; }") input_field.setMaximumSize(80, 20) fields.append(input_field) self.input_layout.addWidget(input_field, index, 1, Qt.AlignLeft) confirm_button = QPushButton("confirm") confirm_button.clicked.connect(lambda: self.start_ruler(fields)) central_widget.addWidget(confirm_button, 3, 0, Qt.AlignCenter) self.auto_checkbox.click() def start_ruler(self, fields): if self.auto_checkbox.isChecked(): h_res = "auto" v_res = "auto" size = "auto" else: h_res = fields[0].text() v_res = fields[1].text() size = fields[2].text() self.ruler.set_sizes(h_res, v_res, size) self.ruler.showFullScreen() self.hide() def toggle_auto(self, state): for i in range(6): widget = self.input_layout.itemAt(i).widget() if type(widget) == QLineEdit: widget.setReadOnly(state)
class SerialTerminalWidget(QWidget): baudrates = OrderedDict([('1200', QSerialPort.Baud1200), ('2400', QSerialPort.Baud2400), ('4800', QSerialPort.Baud4800), ('9600', QSerialPort.Baud9600), ('19200', QSerialPort.Baud19200), ('38400', QSerialPort.Baud38400), ('57600', QSerialPort.Baud57600), ('115200', QSerialPort.Baud115200)]) databits = OrderedDict([('5', QSerialPort.Data5), ('6', QSerialPort.Data6), ('7', QSerialPort.Data7), ('8', QSerialPort.Data8)]) paritybit = OrderedDict([('None', QSerialPort.NoParity), ('Even', QSerialPort.EvenParity), ('Odd', QSerialPort.OddParity), ('Mark', QSerialPort.MarkParity), ('Space', QSerialPort.SpaceParity)]) stopbits = OrderedDict([('1', QSerialPort.OneStop), ('1.5', QSerialPort.OneAndHalfStop), ('2', QSerialPort.TwoStop)]) flowcontrol = OrderedDict([ ('None', QSerialPort.NoFlowControl), ('Hardware', QSerialPort.FlowControl), ]) lineendings = OrderedDict([('None', ''), ('LF', '\n'), ('CR', '\r'), ('CR/LF', '\r\n')]) def __init__(self, parent=None): super(SerialTerminalWidget, self).__init__(parent) fixed_width_font = QFontDatabase.systemFont(QFontDatabase.FixedFont) self.setLayout(QGridLayout()) self.serialport = None self.fl_autoscroll = None self.fl_hexinput = None self.fl_log = None self.logfile = None self.logfile_location = 'received.log' self.qfl = QFormLayout() self.layout().addLayout(self.qfl, 0, 0) self.qcb_ports = QComboBox() self.qcb_ports.setMinimumWidth(150) self.qcb_ports.currentTextChanged.connect(self.slot_ports) self.qfl.addRow("Serial Port:", self.qcb_ports) self.qcb_baudrates = QComboBox() self.qcb_baudrates.addItems(list(self.baudrates)) self.qcb_baudrates.currentTextChanged.connect(self.slot_baud) self.qfl.addRow("Baud rate:", self.qcb_baudrates) self.qcb_databits = QComboBox() self.qcb_databits.addItems(list(self.databits)) self.qcb_databits.currentTextChanged.connect(self.slot_data) self.qcb_paritybit = QComboBox() self.qcb_paritybit.addItems(list(self.paritybit)) self.qcb_paritybit.currentTextChanged.connect(self.slot_parity) self.qcb_stopbits = QComboBox() self.qcb_stopbits.addItems(list(self.stopbits)) self.qcb_stopbits.currentTextChanged.connect(self.slot_stop) self.qcb_flowcontrol = QComboBox() self.qcb_flowcontrol.addItems(list(self.flowcontrol)) self.qcb_flowcontrol.currentTextChanged.connect(self.slot_flow) self.qpb_refresh = QPushButton("Refresh") self.qpb_refresh.clicked.connect(self.slot_refresh) self.qpb_connect_disconnect = QPushButton("Connect") self.qpb_connect_disconnect.clicked.connect(self.slot_connect) self.qfl.addRow("Data bits:", self.qcb_databits) self.qfl.addRow("Parity:", self.qcb_paritybit) self.qfl.addRow("Stop bits:", self.qcb_stopbits) self.qfl.addRow("Flow control:", self.qcb_flowcontrol) self.qfl.addWidget(self.qpb_refresh) self.qfl.addWidget(self.qpb_connect_disconnect) self.qtb_receiver = QTextBrowser() self.qtb_receiver.setWordWrapMode(QTextOption.NoWrap) self.qtb_receiver.setFont(fixed_width_font) self.qtb_receiver.setMinimumWidth(400) self.layout().addWidget(self.qtb_receiver, 0, 1) self.qhbl_receiver = QHBoxLayout() self.qchb_autoscroll_receiver = QCheckBox("Autoscroll") self.qchb_autoscroll_receiver.clicked.connect(self.slot_autoscroll) self.qchb_autoscroll_receiver.click() self.qhbl_receiver.addWidget(self.qchb_autoscroll_receiver) self.qchb_receiver_log = QCheckBox("Log to") self.qchb_receiver_log.clicked.connect(self.slot_log) self.qhbl_receiver.addWidget(self.qchb_receiver_log) self.qle_receiver_log = QLineEdit() self.qle_receiver_log.setPlaceholderText(self.logfile_location) self.qhbl_receiver.addWidget(self.qle_receiver_log) self.qpb_receiver_log = QPushButton("...") self.qpb_receiver_log.clicked.connect(self.slot_receiver_log) self.qpb_receiver_log.setFixedWidth(30) self.qhbl_receiver.addWidget(self.qpb_receiver_log) self.qpb_clear_receiver = QPushButton("Clear") self.qpb_clear_receiver.clicked.connect(self.slot_clear_receiver) self.qpb_clear_receiver.setFixedWidth(70) self.qhbl_receiver.addWidget(self.qpb_clear_receiver) self.layout().addLayout(self.qhbl_receiver, 1, 1) self.qtb_sender = QTextBrowser() self.qtb_sender.setFont(fixed_width_font) self.qtb_sender.setFixedHeight(100) self.layout().addWidget(self.qtb_sender, 2, 1) self.qchb_hexinput = QCheckBox("Hex") self.qchb_hexinput.clicked.connect(self.slot_hexinput) self.qle_sender = QLineEdit() self.qle_sender.returnPressed.connect(self.return_pressed) self.qcb_lineending = QComboBox() self.qcb_lineending.addItems(self.lineendings) self.qcb_lineending.currentTextChanged.connect(self.slot_lineending) self.qpb_sender = QPushButton("Send") self.qpb_sender.clicked.connect(self.slot_input) self.qhbl_sender = QHBoxLayout() self.qhbl_sender.addWidget(self.qchb_hexinput) self.qhbl_sender.addWidget(self.qle_sender) self.qhbl_sender.addWidget(self.qcb_lineending) self.qhbl_sender.addWidget(self.qpb_sender) self.layout().addLayout(self.qhbl_sender, 3, 1) self.qhbl_session = QHBoxLayout() self.qpb_save_session = QPushButton("Save session") self.qpb_save_session.clicked.connect(self.slot_save_session) self.qhbl_session.addWidget(self.qpb_save_session) self.qpb_load_session = QPushButton("Load session") self.qpb_load_session.clicked.connect(self.slot_load_session) self.qhbl_session.addWidget(self.qpb_load_session) self.layout().addLayout(self.qhbl_session, 3, 0) self.serialport_name = None self.baud = '9600' self.data = '8' self.parity = 'None' self.stop = '1' self.flow = 'None' self.lineending = '' self.slot_refresh() def slot_ports(self, serial_portname): self.serialport_name = serial_portname def slot_baud(self, baud): self.baud = baud def slot_data(self, data): self.data = data def slot_parity(self, parity): self.parity = parity def slot_stop(self, stop): self.stop = stop def slot_flow(self, flow): self.flow = flow def slot_lineending(self, lineending): self.lineending = self.lineendings[lineending] def slot_save_session(self): d = OrderedDict([('baud', self.baud), ('data', self.data), ('parity', self.parity), ('stop', self.stop), ('flow', self.flow), ('fl_autoscroll', self.fl_autoscroll), ('fl_hexinput', self.fl_hexinput), ('fl_log', self.fl_log), ('logfile_location', self.logfile_location)]) with open('session.yaml', 'w') as f: yaml.dump(d, f) def slot_load_session(self): with open('session.yaml', 'r') as f: d = yaml.load(f) self.baud = d['baud'] self.data = d['data'] self.parity = d['parity'] self.stop = d['stop'] self.flow = d['flow'] self.fl_autoscroll = d['fl_autoscroll'] self.fl_hexinput = d['fl_hexinput'] self.fl_log = d['fl_log'] self.logfile_location = d['logfile_location'] self.qchb_autoscroll_receiver.setChecked(self.fl_autoscroll is True) self.qchb_hexinput.setChecked(self.fl_hexinput is True) self.qchb_receiver_log.setChecked(self.fl_log is True) self.slot_refresh() if self.fl_log: self.qle_receiver_log.setText(self.logfile_location) def slot_receiver_log(self): logfile_location = QFileDialog.getSaveFileName(self, 'Save file', '.', 'Log files (*.log)')[0] if logfile_location: self.logfile_location = logfile_location self.qle_receiver_log.setText(self.logfile_location) self.qchb_receiver_log.click() def slot_log(self): self.fl_log = not self.fl_log if self.fl_log: self.logfile = open(self.logfile_location, 'w') def slot_hexinput(self): self.fl_hexinput = not self.fl_hexinput def slot_clear_receiver(self): self.qtb_receiver.clear() def slot_refresh(self): self.qcb_ports.clear() available_ports = QSerialPortInfo.availablePorts() serialports = [ serialport.systemLocation() for serialport in available_ports ] self.qcb_ports.addItems(serialports) self.qcb_ports.setCurrentText(self.serialport_name) self.qcb_baudrates.setCurrentText(self.baud) self.qcb_databits.setCurrentText(self.data) self.qcb_paritybit.setCurrentText(self.parity) self.qcb_stopbits.setCurrentText(self.stop) self.qcb_flowcontrol.setCurrentText(self.flow) def slot_connect(self): self.serialport_name = self.qcb_ports.currentText() self.serialport = QSerialPort() self.serialport.setPortName(self.serialport_name) self.serialport.setBaudRate( self.baudrates[self.qcb_baudrates.currentText()]) self.serialport.setDataBits( self.databits[self.qcb_databits.currentText()]) self.serialport.setParity( self.paritybit[self.qcb_paritybit.currentText()]) self.serialport.setStopBits( self.stopbits[self.qcb_stopbits.currentText()]) self.serialport.setFlowControl(QSerialPort.NoFlowControl) # self.serialport.close() self.serialport.open(QIODevice.ReadWrite) if self.serialport.isOpen(): self.serialport.readyRead.connect(self.ready_read) self.qpb_connect_disconnect.setText("Disconnect") self.qpb_connect_disconnect.disconnect() self.qpb_connect_disconnect.clicked.connect(self.slot_disconnect) if self.fl_log: self.logfile = open(self.logfile_location, 'w') self.qcb_ports.setDisabled(True) self.qcb_baudrates.setDisabled(True) self.qcb_databits.setDisabled(True) self.qcb_paritybit.setDisabled(True) self.qcb_stopbits.setDisabled(True) self.qcb_flowcontrol.setDisabled(True) self.qpb_refresh.setDisabled(True) self.qpb_load_session.setDisabled(True) def slot_disconnect(self): self.serialport.close() self.qpb_connect_disconnect.setText("Connect") self.qpb_connect_disconnect.disconnect() self.qpb_connect_disconnect.clicked.connect(self.slot_connect) if self.fl_log: self.logfile.close() self.qcb_ports.setEnabled(True) self.qcb_baudrates.setEnabled(True) self.qcb_databits.setEnabled(True) self.qcb_paritybit.setEnabled(True) self.qcb_stopbits.setEnabled(True) self.qcb_flowcontrol.setEnabled(True) self.qpb_refresh.setEnabled(True) self.qpb_load_session.setEnabled(True) def ready_read(self): b = bytes(self.serialport.readAll()) try: read_all = b.decode("utf-8") except UnicodeDecodeError: read_all = str(b)[2:-1] if self.fl_log and self.logfile: self.logfile.write(read_all) flag = self.fl_autoscroll if not flag: v_val = self.qtb_receiver.verticalScrollBar().value() h_val = self.qtb_receiver.horizontalScrollBar().value() self.qtb_receiver.moveCursor(QTextCursor.End) self.qtb_receiver.insertPlainText(read_all) if not flag: self.qtb_receiver.verticalScrollBar().setValue(v_val) self.qtb_receiver.horizontalScrollBar().setValue(h_val) def slot_autoscroll(self): self.fl_autoscroll = not self.fl_autoscroll def return_pressed(self): self.slot_input() def slot_input(self): if self.serialport: text_to_send = self.qle_sender.text() bytes_to_send = bytes(text_to_send + self.lineending, "utf-8") if self.fl_hexinput is True and text_to_send.find('\\x') == 0: self.serialport.writeData(bytes.fromhex(text_to_send[2:])) else: self.serialport.writeData(bytes_to_send) self.qtb_sender.append(text_to_send)