class ExperimentSetup(QWidget): """ Class for setting-up the experiment: choosing condition""" def __init__(self, parent=None): super(ExperimentSetup, self).__init__(parent) self.title = QLabel("EXPERIMENTER ONLY") # titleFont = QFont() # titleFont.setPointSize(36) # titleFont.setItalic(True) # self.title.setFont(titleFont) import os print(os.getcwd()) self.mypixmap = QPixmap(os.getcwd() + "/ido.jpg") self.title.setPixmap(self.mypixmap) self.title.setGeometry(10, 10, 10, 10) # conditions list self.conditions_combo = QComboBox() conditions_list = config.CONDITIONS['condition'] self.conditions_combo.addItems(conditions_list) # layout formLayout = QGridLayout() formLayout.setSpacing(20) formLayout.setColumnStretch(0, 5) formLayout.setColumnStretch(1, 2) formLayout.setColumnStretch(2, 5) formLayout.setRowStretch(0, 1) formLayout.setRowStretch(3, 1) formLayout.addWidget(self.title, 1, 1, 1, 2) formLayout.setRowMinimumHeight(2, 5) formLayout.addWidget(self.conditions_combo, 2, 1) self.setLayout(formLayout)
class DocumentTab(QWidget): def __init__(self, parent): self.parent = parent super(DocumentTab, self).__init__(parent) self.name = 'Documents' self.formats = config.document_formats convertQL = QLabel(self.tr('Convert to:')) self.extQCB = QComboBox() final_layout = utils.add_to_layout('h', convertQL, self.extQCB, None) self.setLayout(final_layout) def fill_extension_combobox(self, extraformats): self.extQCB.clear() self.extQCB.addItems(sorted(self.formats + extraformats)) def ok_to_continue(self): """ Check if everything is ok with documenttab to continue conversion. Checks if: - unoconv is missing. Return True if all tests pass, else False. """ if not self.parent.unoconv: QMessageBox.warning(self, 'FF Multi Converter - ' + self.tr('Error!'), self.tr('Unocov is not installed!')) return False return True
class ChooseFixedFont( ChoiceWidget ) : def __init__( self, explainer ) : super().__init__( _TR( 'Preference item title line', 'Choose a monospaced font for the Editor' ), explainer ) self.fcb = QComboBox() self.fcb.addItems( fonts.list_of_good_families() ) self.fcb.activated[str].connect( self.choice_made ) self.layout().addWidget(self.fcb) self.reset() # set the current font self.explanation = _TR( 'Preference item details', '''Select the font to use in the Edit panel. Choose a monospaced font that shows a clear difference 1/l and 0/O, and that has a wide selection of Unicode characters. Good choices are Cousine and Liberation Mono. When you select a font from the menu, that font is applied to this window. To apply it to the Edit panel, click Apply.''') self.reset() def choice_made(self, family) : self.choice = family qf = fonts.font_from_family( family ) self.explainer.setFont(qf) def reset(self) : self.choice = fonts.get_fixed().family() self.fcb.setCurrentText( self.choice ) def apply(self) : fonts.set_fixed( fonts.font_from_family( self.choice ) )
def _get_combobox(self, column, relations, main_window): """ Return combobox for foreign fields. """ label = column.name if label.endswith('_id'): label = label[:-3] foreign_model = relations.get(label).mapper.class_ items = list(db.SESSION.query(foreign_model).filter(foreign_model.deleted == False)) self.foreigns[column.name] = items items_labels = [str(i) for i in items] widget = QWidget() widget.setStyleSheet('margin:0;') combo_box = QComboBox() combo_box.addItems(items_labels) combo_box.currentIndexChanged.connect(self._check_input) combo_box.setObjectName(column.name) hbox = QHBoxLayout() hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) hbox.addWidget(combo_box, stretch=95) for icon, new in zip(('pencil_g.png', 'plus.png'), (False, True)): b = QPushButton() b.setObjectName('icon') b.setIcon(QIcon(os.path.join(options.STATIC_DIR, 'icons', icon))) b.clicked.connect(functools.partial( self.open_crud, main_window, foreign_model, new, combo_box)) hbox.addWidget(b, stretch=2) widget.setLayout(hbox) return label, widget
def __init__(self): super().__init__() vbox = QVBoxLayout(self) self.setTitle("Python Project") frame = QFrame() frame.setLineWidth(2) vbox.addStretch(1) frame.setFrameShape(QFrame.StyledPanel) vbox.addWidget(frame) box = QGridLayout(frame) box.addWidget(QLabel("Project Name:"), 0, 0) self._line_project_name = QLineEdit() self.registerField("name*", self._line_project_name) box.addWidget(self._line_project_name, 0, 1) box.addWidget(QLabel("Create in:"), 1, 0) self.line = QLineEdit() self.registerField("path", self.line) choose_dir_action = self.line.addAction( QIcon(self.style().standardPixmap( self.style().SP_DirIcon)), QLineEdit.TrailingPosition) box.addWidget(self.line, 1, 1) box.addWidget(QLabel("Interpreter:"), 2, 0) line_interpreter = QComboBox() line_interpreter.setEditable(True) line_interpreter.addItems(utils.get_python()) box.addWidget(line_interpreter, 2, 1) # from ninja_ide.utils import utils choose_dir_action.triggered.connect(self._choose_dir) self.line.setText(utils.get_home_dir())
def refresh_table(self): self._manual_change = True self._custom_fields = list( self._configuration.scheduler_info.data.keys()) labels = self._header + self._custom_fields self.setRowCount(len(labels)) self.setVerticalHeaderLabels(labels) self.horizontalHeader().setStretchLastSection(False) header = self.horizontalHeader() header.setSectionResizeMode(0, QHeaderView.Stretch) header.setSectionResizeMode(1, QHeaderView.Interactive) #header.setSectionResizeMode(2, QHeaderView.Interactive) self.horizontalHeader().hide() combo = QComboBox() combo.addItems(['Custom scheduler...'] + list(get_schedulers())) self.setCellWidget(0, 0, combo) self.setSpan(0, 0, 1, 2) name = self._configuration.scheduler_info.filename scheduler_item = QTableWidgetItem(name and os.path.relpath( name, self._configuration.cur_dir)) scheduler_item.setFlags(scheduler_item.flags() ^ (Qt.ItemIsEditable)) self.setItem(1, 0, scheduler_item) self._btn_open = QPushButton(self) self._btn_open.setText('Open') self._btn_open.clicked.connect(self._open_scheduler) self.setCellWidget(1, 1, self._btn_open) combo.currentIndexChanged['QString'].connect(self._select_scheduler) if self._configuration.scheduler_info.clas: i = combo.findText(self._configuration.scheduler_info.clas) if i <= 0: i = 0 combo.setCurrentIndex(i) self.setItem( 2, 0, QTableWidgetItem(str( self._configuration.scheduler_info.overhead)) ) self.setSpan(2, 0, 1, 2) self.setItem( 3, 0, QTableWidgetItem(str( self._configuration.scheduler_info.overhead_activate)) ) self.setSpan(3, 0, 1, 2) self.setItem( 4, 0, QTableWidgetItem(str( self._configuration.scheduler_info.overhead_terminate)) ) self.setSpan(4, 0, 1, 2) i = 5 for name, value in self._configuration.scheduler_info.data.items(): self.setItem(i, 0, QTableWidgetItem(str(value))) self.setSpan(i, 0, 1, 2) i += 1
def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex): editor = QComboBox(parent) if sys.platform == "win32": # Ensure text entries are visible with windows combo boxes editor.setMinimumHeight(self.sizeHint(option, index).height() + 10) editor.addItems(self.items) if self.is_editable: editor.setEditable(True) editor.setInsertPolicy(QComboBox.NoInsert) if self.current_edit_text: editor.setEditText(self.current_edit_text) if self.colors: img = QImage(16, 16, QImage.Format_RGB32) painter = QPainter(img) painter.fillRect(img.rect(), Qt.black) rect = img.rect().adjusted(1, 1, -1, -1) for i, item in enumerate(self.items): color = self.colors[i] painter.fillRect(rect, QColor(color.red(), color.green(), color.blue(), 255)) editor.setItemData(i, QPixmap.fromImage(img), Qt.DecorationRole) del painter editor.currentIndexChanged.connect(self.currentIndexChanged) editor.editTextChanged.connect(self.on_edit_text_changed) return editor
class PropertyChanger(QWidget): @update_paths def __init__(self, objects, type, controller): super().__init__() # list of properties self.property_list = QComboBox() self.property_list.addItems(map(str, object_properties[type])) self.value_edit = QLineEdit() confirmation_button = QPushButton() confirmation_button.setText('OK') confirmation_button.clicked.connect(lambda: self.confirm(objects)) # position in the grid layout = QGridLayout() layout.addWidget(self.property_list, 0, 0) layout.addWidget(self.value_edit, 1, 0) layout.addWidget(confirmation_button, 2, 0) self.setLayout(layout) def confirm(self, objects): selected_property = pretty_name_to_class[self.property_list.currentText()] str_value = self.value_edit.text() value = self.network.objectizer(selected_property.name, str_value) for object in objects: setattr(object, selected_property.name, value) self.close()
def __init__(self, parent=None, *args, **kwargs): super(SettingsForm, self).__init__(parent, *args, **kwargs) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.setWindowTitle('Settings') self.setModal(True) self.resize(240, 120) label = QLabel('Old Style (Username/Password)?') old_checkbox = QCheckBox( checked=KeyValue.get('old_style')) label2 = QLabel('Evaluation Type') box = QComboBox() box.addItems(EVALUATION_CHOICES) index = box.findText( KeyValue.get('evaluation_type'), QtCore.Qt.MatchFixedString) if not index < 0: box.setCurrentIndex(index) ok_button = QPushButton('OK') ok_button.setFixedWidth(90) layout = QGridLayout() layout.addWidget(label, 1, 1) layout.addWidget(old_checkbox, 1, 2) layout.addWidget(label2, 2, 1) layout.addWidget(box, 2, 2) layout.addWidget(ok_button, 3, 1, 3, 2, QtCore.Qt.AlignCenter) old_checkbox.stateChanged.connect( lambda: self.set_old_style(old_checkbox)) box.currentIndexChanged.connect(lambda: self.set_eval_type(box)) ok_button.clicked.connect(self.close) self.setLayout(layout)
def createEditor(self, parent, option, index): if index.column() == 1: combo = QComboBox(parent) combo.addItem('') combo.addItems(self._action_list) return combo return super().createEditor(parent, option, index)
def createEditor(self, parent, option, index): # residNum,residNum_color, residName, atomName, atomNum, X,Y,Z if index.column() == residNum: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() == residName: combobox = QComboBox(parent) combobox.addItems(comboBoxList) combobox.insertSeparator(23) combobox.setEditable(True) return combobox elif index.column() == atomName: editor = QLineEdit(parent) editor.returnPressed.connect(self.commitAndCloseEditor) return editor elif index.column() == atomNum: spinbox = QSpinBox(parent) spinbox.setRange(1, 200000) spinbox.setSingleStep(1) spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return spinbox elif index.column() in (X, Y, Z): ###this works dspinbox = QDoubleSpinBox(parent) dspinbox.setRange(-200000, 200000) dspinbox.setSingleStep(0.1) dspinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter) return dspinbox else: return QStyledItemDelegate.createEditor(self, parent, option, index)
class OffsetRow(QWidget): def __init__(self): super(OffsetRow, self).__init__() self.layout = QHBoxLayout() self.layout.setContentsMargins(0,0,0,0) self.sign = QComboBox() self.sign.addItems(['-', '+']) self.amount = QLineEdit() self.amount.setInputMask('99999999') self.unit = QComboBox() self.unit.addItems(['sec', 'min', 'hrs', 'day']) self.layout.addWidget(self.sign) self.layout.addWidget(self.amount, stretch = 1) self.layout.addWidget(self.unit) def show(self): self.sign.show() self.amount.show() self.unit.show() def hide(self): self.sign.hide() self.amount.hide() self.unit.hide() def set_values(self, sign, amount, unit): self.sign.setCurrentText(sign) self.amount.setText(str(amount)) self.unit.setCurrentText(unit)
def __addRangesLine(self): """ Private slot to add a line of entry widgets for character ranges. """ hbox = QWidget(self.rangesItemsBox) hboxLayout = QHBoxLayout(hbox) hboxLayout.setContentsMargins(0, 0, 0, 0) hboxLayout.setSpacing(6) hbox.setLayout(hboxLayout) cb1 = QComboBox(hbox) cb1.setEditable(False) cb1.addItems(self.comboItems) hboxLayout.addWidget(cb1) l1 = QLabel(self.tr("Between:"), hbox) hboxLayout.addWidget(l1) le1 = QLineEdit(hbox) le1.setValidator(self.charValidator) hboxLayout.addWidget(le1) l2 = QLabel(self.tr("And:"), hbox) hboxLayout.addWidget(l2) le2 = QLineEdit(hbox) le2.setValidator(self.charValidator) hboxLayout.addWidget(le2) self.rangesItemsBoxLayout.addWidget(hbox) cb1.activated[int].connect(self.__rangesCharTypeSelected) hbox.show() self.rangesItemsBox.adjustSize() self.rangesEntries.append([cb1, le1, le2])
class CueItemWidget(QWidget): def __init__(self, target, action, cue_dialog, **kwargs): super().__init__(**kwargs) self.target = target self.cue_dialog = cue_dialog self.setLayout(QHBoxLayout(self)) self.layout().setContentsMargins(2, 1, 2, 1) self.selectButton = QPushButton(self) self.selectButton.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed) self.selectButton.setText(target.name) self.selectButton.setToolTip(target.name) self.selectButton.clicked.connect(self.select_target) self.layout().addWidget(self.selectButton) self.targetActionsCombo = QComboBox(self) self.targetActionsCombo.addItems([a.name for a in CueAction]) self.targetActionsCombo.setCurrentText(CueAction[action].name) self.layout().addWidget(self.targetActionsCombo) self.layout().setStretch(0, 3) self.layout().setStretch(1, 1) def get_target(self): return self.target.id, self.targetActionsCombo.currentText() def select_target(self): if self.cue_dialog.exec_() == QDialog.Accepted: self.target = self.cue_dialog.selected_cues()[0] self.selectButton.setText(self.target.name) self.selectButton.setToolTip(self.target.name)
class StyleWindow(QWidget): def __init__(self): super().__init__() self.setWindowTitle('Styles') self.original_palette = QApplication.palette() styles = QLabel('Styles :') self.style_list = QComboBox() self.style_list.addItems(QStyleFactory.keys()) self.style_list.setCurrentIndex(3) self.style_list.activated[str].connect(self.change_style) self.standard_palette = QCheckBox("Standard palette") self.standard_palette.setChecked(False) self.standard_palette.toggled.connect(self.change_palette) self.change_style('Fusion') grid = QGridLayout() grid.addWidget(styles, 0, 0, 1, 1) grid.addWidget(self.style_list, 0, 1, 1, 1) grid.addWidget(self.standard_palette, 1, 0, 1, 2) self.setLayout(grid) def change_style(self, name): QApplication.setStyle(QStyleFactory.create(name)) self.change_palette() def change_palette(self): if self.standard_palette.isChecked(): QApplication.setPalette(QApplication.style().standardPalette()) else: QApplication.setPalette(self.original_palette)
class FormatChoice( ChoiceWidget ) : # combobox value def __init__( self, title, explainer ) : super().__init__( title, explainer ) #Current color and line style are kept in this QTextCharFormat self.text_format = QTextCharFormat() # Set up the underline menu self.ul_menu = QComboBox() self.ul_menu.addItems( list( UNDERLINES.values() ) ) self.ul_menu.currentIndexChanged[int].connect(self.ul_change) self.layout().addWidget( self.ul_menu, 0 ) # Set up the color swatch self.swatch = Swatch( self ) self.layout().addWidget( self.swatch, 0 ) self.swatch.clicked.connect( self.color_change ) # Set up the text sample self.sample = Sample() self.layout().addWidget( self.sample ) self.reset() # set widgets to current value # Combine the underline choice and swatch color into a QTextCharFormat. def make_format( self, ul_index, qc ) : qtcf = QTextCharFormat() qtcf.setUnderlineStyle( ul_index ) if ul_index == QTextCharFormat.NoUnderline : qtcf.setBackground(QBrush(qc)) else : qtcf.setUnderlineColor(qc) # underline color gets a QColor qtcf.clearBackground() return qtcf # Parse self.text_format and display it in the swatch and combobox. def show_format( self ) : un = self.text_format.underlineStyle() if un == QTextCharFormat.NoUnderline : qc = self.text_format.background().color() else : qc = self.text_format.underlineColor() self.swatch.set_color( qc ) self.ul_menu.setCurrentIndex( un ) self.sample.change_format(self.text_format) # Handle a change in selection of the underline popup def ul_change( self, index ) : self.text_format = self.make_format( index, self.swatch.qc ) self.show_format() # Handle a click on the color swatch. Show the color dialog. After it # ends, the Preferences dialog will be behind the main window. Why? Who # knows! But raise it back up to visibility. def color_change(self) : qc = colors.choose_color( _TR('Browse dialog for color preference', 'Choose a color for scanno marking'), self.swatch.qc ) BIG_FAT_KLUDGE.raise_() if qc is not None : self.text_format = self.make_format( self.ul_menu.currentIndex(), qc ) self.show_format()
class AlsaSinkSettings(SettingsSection): NAME = "ALSA Sink" ELEMENT = AlsaSink def __init__(self, size, Id, parent=None): super().__init__(size, parent) self.id = Id self.devs = self._discover_pcm_devices() self.devs['default'] = 'default' self.group = QGroupBox(self) self.group.setTitle('ALSA device') self.group.setGeometry(0, 0, self.width(), 100) self.group.setLayout(QHBoxLayout()) self.device = QComboBox(self.group) self.device.addItems(self.devs.keys()) self.device.setCurrentText('default') self.device.setToolTip('ALSA device, as defined in an asound ' 'configuration file') self.group.layout().addWidget(self.device) self.label = QLabel('ALSA device', self.group) self.label.setAlignment(QtCore.Qt.AlignCenter) self.group.layout().addWidget(self.label) def sizeHint(self): return QSize(450, 100) def enable_check(self, enable): self.group.setCheckable(enable) self.group.setChecked(False) def set_configuration(self, conf): if self.id in conf: device = conf[self.id].get('device', 'default') for name in self.devs: if device == self.devs[name]: self.device.setCurrentText(name) break def get_configuration(self): if not (self.group.isCheckable() and not self.group.isChecked()): return {self.id: {'device': self.devs[self.device.currentText()]}} else: return {} def _discover_pcm_devices(self): devices = {} with open('/proc/asound/pcm', mode='r') as f: for dev in f.readlines(): dev_name = dev[7:dev.find(':', 7)].strip() dev_code = 'hw:' + dev[:5].replace('-', ',') devices[dev_name] = dev_code return devices
class SubFileDialog(QFileDialog): def __init__(self, parent = None, caption = "", directory = "", filter = ""): super().__init__(parent, caption, directory, filter) self.setOption(QFileDialog.DontUseNativeDialog) def _initAllSubFormats(self, formatList): self._formats = {} for f in formatList: self._formats[f.NAME] = f def _addEncodingsBox(self, row, addAuto): mainLayout = self.layout() encodingLabel = QLabel(_("File encoding:"), self) self._encodingBox = QComboBox(self) if addAuto is True: self._encodingBox.addItem(AUTO_ENCODING_STR) self._encodingBox.addItems(ALL_ENCODINGS) self._encodingBox.setToolTip(_("Change file encoding")) self._encodingBox.setEditable(True) mainLayout.addWidget(encodingLabel, row, 0) mainLayout.addWidget(self._encodingBox, row, 1) def _addFormatBox(self, row, formatList): self._initAllSubFormats(formatList) displayedFormats = list(self._formats.keys()) displayedFormats.sort() mainLayout = self.layout() formatLabel = QLabel(_("Subtitle format:"), self) self._formatBox = QComboBox(self) self._formatBox.addItems(displayedFormats) mainLayout.addWidget(formatLabel, row, 0) mainLayout.addWidget(self._formatBox, row, 1) def getEncoding(self): encoding = self._encodingBox.currentText() if encoding == AUTO_ENCODING_STR: encoding = None return encoding def setEncoding(self, encoding): index = self._encodingBox.findText(encoding) self._encodingBox.setCurrentIndex(index) def getSubFormat(self): return self._formats.get(self._formatBox.currentText()) def setSubFormat(self, subFormat): for key, val in self._formats.items(): if val == subFormat: index = self._formatBox.findText(key) self._formatBox.setCurrentIndex(index) return
class General(SettingsPage): NAME = 'General' def __init__(self, **kwargs): super().__init__(**kwargs) self.setLayout(QVBoxLayout()) self.layout().setAlignment(Qt.AlignTop) # Startup layout self.layoutGroup = QGroupBox(self) self.layoutGroup.setTitle('Startup layout') self.layoutGroup.setLayout(QVBoxLayout()) self.layout().addWidget(self.layoutGroup) self.startupDialogCheck = QCheckBox(self.layoutGroup) self.startupDialogCheck.setText('Use startup dialog') self.layoutGroup.layout().addWidget(self.startupDialogCheck) self.layoutCombo = QComboBox(self.layoutGroup) self.layoutCombo.addItems([lay.NAME for lay in layouts.get_layouts()]) self.layoutGroup.layout().addWidget(self.layoutCombo) self.startupDialogCheck.clicked.connect( lambda check: self.layoutCombo.setEnabled(not check)) # Application style self.themeGroup = QGroupBox(self) self.themeGroup.setTitle('Application theme') self.themeGroup.setLayout(QVBoxLayout()) self.layout().addWidget(self.themeGroup) self.themeCombo = QComboBox(self.themeGroup) self.themeCombo.addItems(styles.get_styles()) self.themeGroup.layout().addWidget(self.themeCombo) def get_settings(self): conf = {'Layout': {}, 'Theme': {}} if self.startupDialogCheck.isChecked(): conf['Layout']['default'] = 'NoDefault' else: conf['Layout']['default'] = self.layoutCombo.currentText() conf['Theme']['theme'] = self.themeCombo.currentText() styles.apply_style(self.themeCombo.currentText()) return conf def load_settings(self, settings): if 'default' in settings['Layout']: if settings['Layout']['default'].lower() == 'nodefault': self.startupDialogCheck.setChecked(True) self.layoutCombo.setEnabled(False) else: self.layoutCombo.setCurrentText(settings['Layout']['default']) if 'theme' in settings['Theme']: self.themeCombo.setCurrentText(settings['Theme']['theme'])
class StartSession(preferences.Group): def __init__(self, page): super(StartSession, self).__init__(page) grid = QGridLayout() self.setLayout(grid) def changed(): self.changed.emit() self.combo.setEnabled(self.custom.isChecked()) self.none = QRadioButton(toggled=changed) self.lastused = QRadioButton(toggled=changed) self.custom = QRadioButton(toggled=changed) self.combo = QComboBox(currentIndexChanged=changed) grid.addWidget(self.none, 0, 0, 1, 2) grid.addWidget(self.lastused, 1, 0, 1, 2) grid.addWidget(self.custom, 2, 0, 1, 1) grid.addWidget(self.combo, 2, 1, 1, 1) app.translateUI(self) def translateUI(self): self.setTitle(_("Session to load if Frescobaldi is started without arguments")) self.none.setText(_("Start with no session")) self.lastused.setText(_("Start with last used session")) self.custom.setText(_("Start with session:")) def loadSettings(self): s = QSettings() s.beginGroup("session") startup = s.value("startup", "none", str) if startup == "lastused": self.lastused.setChecked(True) elif startup == "custom": self.custom.setChecked(True) else: self.none.setChecked(True) sessionNames = sessions.sessionNames() self.combo.clear() self.combo.addItems(sessionNames) custom = s.value("custom", "", str) if custom in sessionNames: self.combo.setCurrentIndex(sessionNames.index(custom)) def saveSettings(self): s = QSettings() s.beginGroup("session") s.setValue("custom", self.combo.currentText()) if self.custom.isChecked(): startup = "custom" elif self.lastused.isChecked(): startup = "lastused" else: startup = "none" s.setValue("startup", startup)
class DisjointSPWindow(QWidget): algorithms = ( 'Constrained A*', 'Bhandari algorithm', 'Suurbale algorithm', 'Linear programming' ) def __init__(self, controller): super().__init__() self.controller = controller self.setWindowTitle('Disjoint shortest paths algorithms') algorithm = QLabel('Algorithm') self.dsp_list = QComboBox() self.dsp_list.addItems(self.algorithms) source = QLabel('Source') self.source_edit = QLineEdit() destination = QLabel('Destination') self.destination_edit = QLineEdit() number_of_paths = QLabel('Number of paths') self.number_of_paths_edit = QLineEdit() # confirmation button button_compute = QPushButton() button_compute.setText('Compute') button_compute.clicked.connect(self.compute_dsp) # position in the grid layout = QGridLayout() layout.addWidget(algorithm, 0, 0, 1, 1) layout.addWidget(self.dsp_list, 0, 1, 1, 1) layout.addWidget(source, 1, 0, 1, 1) layout.addWidget(self.source_edit, 1, 1, 1, 1) layout.addWidget(destination, 2, 0, 1, 1) layout.addWidget(self.destination_edit, 2, 1, 1, 1) layout.addWidget(number_of_paths, 3, 0, 1, 1) layout.addWidget(self.number_of_paths_edit, 3, 1, 1, 1) layout.addWidget(button_compute, 4, 0, 1, 2) self.setLayout(layout) @update_paths def compute_dsp(self, _): source = self.network.nf(name=self.source_edit.text()) destination = self.network.nf(name=self.destination_edit.text()) algorithm = { 'Constrained A*': self.network.A_star_shortest_pair, 'Bhandari algorithm': self.network.bhandari, 'Suurbale algorithm': self.network.suurbale, 'Linear programming': lambda: 'to repair' }[self.dsp_list.currentText()] nodes, physical_links = algorithm(source, destination) self.view.select(*(nodes + physical_links))
class JackSinkSettings(SettingsSection): NAME = "Jack Sink" ELEMENT = JackSink def __init__(self, size, Id, parent=None): super().__init__(size, parent) self.id = Id self.group = QGroupBox(self) self.group.setTitle('Jack') self.group.setGeometry(0, 0, self.width(), 100) self.group.setLayout(QGridLayout()) self.client = QLineEdit(self.group) self.client.setToolTip('The client name of the Jack instance') self.client.setText('Linux Show Player') self.group.layout().addWidget(self.client, 0, 0) self.clientLabel = QLabel('Client name', self.group) self.clientLabel.setAlignment(QtCore.Qt.AlignCenter) self.group.layout().addWidget(self.clientLabel, 0, 1) self.connection = QComboBox(self.group) self.connection.setToolTip('Specify how the output ports will be' 'connected') self.connection.addItems([JackSink.CONNECT_NONE, JackSink.CONNECT_AUTO, JackSink.CONNECT_AUTO_FORCED]) self.connection.setCurrentIndex(1) self.group.layout().addWidget(self.connection, 1, 0) self.connLabel = QLabel('Connection mode', self.group) self.connLabel.setAlignment(QtCore.Qt.AlignCenter) self.group.layout().addWidget(self.connLabel, 1, 1) def sizeHint(self): return QSize(450, 100) def enable_check(self, enable): self.group.setCheckable(enable) self.group.setChecked(False) def set_configuration(self, conf): if self.id in conf: if 'client-name' in conf[self.id]: self.client.setText(conf[self.id]['client-name']) if 'connection' in conf[self.id]: self.connection.setCurrentText(conf[self.id]['connection']) def get_configuration(self): if not (self.group.isCheckable() and not self.group.isChecked()): return {self.id: {'client-name': self.client.text(), 'connection': self.connection.currentText()}} else: return {}
def _make_cb(self, default, text) : cb = QComboBox() cb.addItems(stream_names) cb.setCurrentIndex(default) tt = _TR( 'Footnote panel popup menus', 'Choose the format to use when renumbering Note Keys such as:', 'will be followed by e.g. "[A]" or "[5]"' ) cb.setToolTip(tt+text) return cb
def _add_task_to_table(self, row, task): self._ignore_cell_changed = True self.setItem(row, self._dict_header['id'], QTableWidgetItem(str(task.identifier))) self.item(row, self._dict_header['id']) \ .setTextAlignment(Qt.AlignCenter) self.setItem(row, self._dict_header['name'], QTableWidgetItem(str(task.name))) combo = QComboBox() items = [task_type for task_type in Task.task_types_names] combo.addItems(items) combo.setCurrentIndex(combo.findText(task.task_type)) combo.currentIndexChanged.connect( lambda x: self._cell_changed(row, self._dict_header['task_type'])) self.setCellWidget(row, self._dict_header['task_type'], combo) item = QTableWidgetItem(task.abort_on_miss and 'Yes' or 'No') item.setFlags( Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsSelectable) item.setCheckState(task.abort_on_miss and Qt.Checked or Qt.Unchecked) self.setItem(row, self._dict_header['abort'], item) self.setItem(row, self._dict_header['list_activation_dates'], QTableWidgetItem( ', '.join(map(str, task.list_activation_dates)))) self.item(row, self._dict_header['list_activation_dates']) \ .setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) for i in ['activation_date', 'period', 'deadline', 'wcet', 'base_cpi', 'n_instr', 'mix', 'acet', 'et_stddev', 'preemption_cost']: self.setItem(row, self._dict_header[i], QTableWidgetItem(str(task.__dict__[i]))) self.item(row, self._dict_header[i]) \ .setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) stack_item = QTableWidgetItem(str(task.stack_file)) stack_item.setFlags(stack_item.flags() ^ (Qt.ItemIsEditable)) self.setItem(row, self._dict_header['sdp'], stack_item) combo = QComboBox() combo.currentIndexChanged.connect( lambda x: self._cell_changed(row, self._dict_header['followed'])) self.setCellWidget(row, self._dict_header['followed'], combo) for col in range(len(self._custom_fields)): key = self._custom_fields[col] if key in task.data and task.data[key] is not None: item = QTableWidgetItem(str(task.data[key])) else: item = QTableWidgetItem('') item.setBackgroundColor(QColor.fromRgb(200, 255, 200)) self.setItem(row, col + len(self._header), item) self._ignore_cell_changed = False self._show_period(task, row)
class ASOperation(QWidget): # - add objects to an AS # - remove objects from an AS # - enter the AS management window @update_paths def __init__(self, mode, obj, AS=set(), controller=None): super().__init__() title = { 'add': 'Add to AS', 'remove': 'Remove from AS', 'manage': 'Manage AS' }[mode] self.setWindowTitle(title) if mode == 'add': # all AS are proposed values = tuple(map(str, self.network.pnAS)) else: # only the common AS among all selected objects values = tuple(map(str, AS)) # list of existing AS self.AS_list = QComboBox() self.AS_list.addItems(values) # confirmation button button_AS_operation = QPushButton() button_AS_operation.setText('OK') button_AS_operation.clicked.connect(lambda: self.as_operation(mode, *obj)) # cancel button cancel_button = QPushButton() cancel_button.setText('Cancel') # position in the grid layout = QGridLayout() layout.addWidget(self.AS_list, 0, 0, 1, 2) layout.addWidget(button_AS_operation, 1, 0, 1, 1) layout.addWidget(cancel_button, 1, 1, 1, 1) self.setLayout(layout) def as_operation(self, mode, *objects): selected_AS = self.network.AS_factory(name=self.AS_list.currentText()) if mode == 'add': selected_AS.management.add_to_AS(*objects) elif mode == 'remove': selected_AS.management.remove_from_AS(*objects) else: selected_AS.management.show() self.close()
class General(SettingsSection): NAME = 'General' def __init__(self, size, parent=None): super().__init__(size, parent) # Startup layout self.layoutGroup = QGroupBox(self) self.layoutGroup.setTitle('Startup layout') self.layoutGroup.setLayout(QVBoxLayout()) self.layoutGroup.setGeometry(0, 0, self.width(), 120) self.startupDialogCheck = QCheckBox(self.layoutGroup) self.startupDialogCheck.setText('Use startup dialog') self.layoutGroup.layout().addWidget(self.startupDialogCheck) self.layoutCombo = QComboBox(self.layoutGroup) self.layoutCombo.addItems([lay.NAME for lay in layouts.get_layouts()]) self.layoutGroup.layout().addWidget(self.layoutCombo) self.startupDialogCheck.clicked.connect( lambda check: self.layoutCombo.setEnabled(not check)) # Application style self.themeGroup = QGroupBox(self) self.themeGroup.setTitle('Application theme') self.themeGroup.setLayout(QVBoxLayout()) self.themeGroup.setGeometry(0, 125, self.width(), 80) self.themeCombo = QComboBox(self.themeGroup) self.themeCombo.addItems(styles.get_styles()) self.themeGroup.layout().addWidget(self.themeCombo) def get_configuration(self): conf = {'Layout': {}, 'Theme': {}} if self.startupDialogCheck.isChecked(): conf['Layout']['default'] = 'NoDefault' else: conf['Layout']['default'] = self.layoutCombo.currentText() conf['Theme']['current'] = self.themeCombo.currentText() styles.apply_style(self.themeCombo.currentText()) return conf def set_configuration(self, conf): if 'default' in conf['Layout']: if conf['Layout']['default'].lower() == 'nodefault': self.startupDialogCheck.setChecked(True) self.layoutCombo.setEnabled(False) else: self.layoutCombo.setCurrentText(conf['Layout']['default']) if 'current' in conf['Theme']: self.themeCombo.setCurrentText(conf['Theme']['current'])
def createEditor(self, parent, option, index): if index.column() == 2: dictionary_paths = [ shorten_path(dictionary.get_path()) for dictionary in self._dictionary_list ] combo = QComboBox(parent) combo.addItems(dictionary_paths) return combo return super(DictionaryItemDelegate, self).createEditor(parent, option, index)
def createEditor(self, parent, option, index): # Add null editor to action buttons column if index.column() == index.model().column_position[ACTION_BUTTONS]: return if index.column() == index.model().column_position['category']: cbox = QComboBox(parent) cbox.addItems(CATEGORY_LIST) return cbox return super(TriblerButtonsDelegate, self).createEditor(parent, option, index)
def createEditor(self, parent, option, index): editor = QComboBox(parent=parent) editor.addItems(COMBO_BOX_ITEMS) # setFrame(): tell whether the line edit draws itself with a frame. # If enabled (the default) the line edit draws itself inside a frame, otherwise the line edit draws itself without any frame. editor.setFrame(False) return editor
class TestStripsDialog(QDialog): GHBox = None KHBox = None pHBox = None NO2Box = None NO3Box = None def __init__(self): super(TestStripsDialog, self).__init__() self.GHBox = QComboBox() self.KHBox = QComboBox() self.pHBox = QComboBox() self.NO2Box = QComboBox() self.NO3Box = QComboBox() self.createFormGroupBox() buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttonBox.accepted.connect(self.accept) buttonBox.rejected.connect(self.reject) mainLayout = QVBoxLayout() mainLayout.addWidget(self.formGroupBox) mainLayout.addWidget(buttonBox) self.setLayout(mainLayout) self.setWindowTitle("Aquarium Data Form") def createFormGroupBox(self): self.formGroupBox = QGroupBox("5-in-1 Test Strips") layout = QFormLayout() # Create the GH combobox GHItems = ['0','30','60','120','180'] self.GHBox.addItems(GHItems) # Create the KH combobox KHItems = ['0','40','80','120','180','240'] self.KHBox.addItems(KHItems) # Create the pH combobox pHItems = ['6.0','6.5','7.0','7.5','8.0','8.5','9.0'] self.pHBox.addItems(pHItems) # Create the Nitrite combobox NO2Items = ['0 ppm','0.50 ppm','1.0 ppm','3.0 ppm','5.0 ppm','10.0 ppm'] self.NO2Box.addItems(NO2Items) # Create the Nitrate combobox NO3Items = ['20 ppm','40 ppm','80 ppm','160 ppm','200 ppm'] self.NO3Box.addItems(NO3Items) layout.addRow(QLabel("General Hardness (GH):"), self.GHBox) layout.addRow(QLabel("Carbonate Hardness (KH):"), self.KHBox) layout.addRow(QLabel("pH"), self.pHBox) layout.addRow(QLabel("Nitrite (NO2-):"), self.NO2Box) layout.addRow(QLabel("Nitrate (NO3-):"), self.NO3Box) self.formGroupBox.setLayout(layout) def accept(self): date = datetime.datetime.now() print("\n5-in-1 Test Strip Results - " + str(date)) print(" GH Level:\t\t" + self.GHBox.currentText()) print(" KH Level:\t\t" + self.KHBox.currentText()) print(" pH Level:\t\t" + self.pHBox.currentText()) print(" Nitrite Level:\t" + self.NO2Box.currentText()) print(" Nitrate Level:\t" + self.NO3Box.currentText()) self.writeTestStrips(self.GHBox.currentText(), self.KHBox.currentText(), self.pHBox.currentText(), self.NO2Box.currentText(), self.NO3Box.currentText()) self.done(0) def writeTestStrips(self, GH, KH, pH, NO2, NO3): with open(".aquadata", "r") as fp: tsLine = fp.readline() fmtkLine = fp.readline() tempLine = fp.readline() fmtkLine = GH + "," + KH + "," + pH + "," + NO2 + "," + NO3 + "\n" with open(".aquadata", "w") as fp: fp.write(tsLine) fp.write(fmtkLine) fp.write(tempLine)
class FileDialog(QWidget): def __init__(self, parent: DetectVideoApp = None): super().__init__() self.parent = parent self.args = argparse.Namespace() self.args.is_classifier = False self.classifier_cfg = None self.classifier_weights = None self.setWindowIcon(QIcon('../images/Logo.png')) layout = QVBoxLayout() self.startDir = os.getcwd() # Create video selector self.useWebCam = QCheckBox("Use web cam") self.useWebCam.setChecked(False) self.useWebCamLabel = QLabel("Use web cam") self.useWebCam.stateChanged.connect(self.use_webcam_clicked) horizontal_layout = QHBoxLayout() horizontal_layout.addWidget(self.useWebCamLabel) horizontal_layout.addWidget(self.useWebCam, alignment=Qt.AlignLeft) horizontal_layout.addStretch(1) self.btnIm = QPushButton("Select video to detect") self.btnIm.clicked.connect(self.get_video) self.textIm = QTextEdit() layout.addLayout(horizontal_layout, 1) layout.addStretch(1) layout.addLayout(SelectQPushButton(self.btnIm), 1) layout.addLayout(SelectQText(self.textIm), 2) layout.addStretch(1) self.textIm.setReadOnly(True) # Select data set self.select_ds_label = QLabel("Select dataset") self.select_ds = DataSetsManager.get_data_set_combo() self.select_ds.setObjectName("SelectCombo") self.select_ds.currentTextChanged.connect(self.on_data_set_changed) layout.addLayout(SelectQCombo(self.select_ds_label, self.select_ds), 2) layout.addStretch(1) # Select weights file self.btnW = QPushButton("Select weights file") self.btnW.clicked.connect(self.get_weights) self.textW = QLineEdit() self.textW.setReadOnly(True) layout.addLayout(SelectQPushButton(self.btnW), 1) layout.addLayout(SelectQPushButton(self.textW), 1) layout.addStretch(1) # Select Config file self.btnConf = QPushButton("Select Config file") self.btnConf.clicked.connect(self.get_config) self.textConf = QLineEdit() self.textConf.setReadOnly(True) layout.addLayout(SelectQPushButton(self.btnConf), 1) layout.addLayout(SelectQText(self.textConf), 1) layout.addStretch(1) # Select Names file self.btnNames = QPushButton("Select Names file") self.btnNames.clicked.connect(self.get_names) self.textNames = QLineEdit() self.textNames.setReadOnly(True) layout.addLayout(SelectQPushButton(self.btnNames), 1) layout.addLayout(SelectQText(self.textNames), 1) layout.addStretch(1) bs_label = QLabel('Batch size') conf_label = QLabel('Confidence') nms_label = QLabel('Nms threshold') res_label = QLabel('Resolution') self.bsEdit = QLineEdit() self.confEdit = QLineEdit() self.nmsEdit = QLineEdit() self.resEdit = QLineEdit() self.bsEdit.setText("1") self.confEdit.setText("0.5") self.nmsEdit.setText("0.4") self.resEdit.setText("416") self.textIm.setText("../vid1_Driving_in_Gothenburg_Sweden.mp4") self.args.video = "../vid1_Driving_in_Gothenburg_Sweden.mp4" self.on_data_set_changed('Swedish') self.select_ds.setCurrentText('Swedish') grid = QGridLayout() grid.setSpacing(10) grid.addWidget(bs_label, 1, 0) grid.addWidget(conf_label, 2, 0) grid.addWidget(nms_label, 3, 0) grid.addWidget(res_label, 4, 0) grid.addWidget(self.bsEdit, 1, 1) grid.addWidget(self.confEdit, 2, 1) grid.addWidget(self.nmsEdit, 3, 1) grid.addWidget(self.resEdit, 4, 1) grid.setColumnStretch(0, 1) grid.setColumnStretch(1, 1) grid.setColumnStretch(2, 2) layout.addLayout(grid, 5) tracking_layout = QHBoxLayout() self.use_tracking = QCheckBox("Use tracking") self.use_tracking.setChecked(True) self.use_tracking_label = QLabel("Use tracking: ") self.use_tracking.stateChanged.connect(self.use_tracking_clicked) tracking_layout.addWidget(self.use_tracking_label) tracking_layout.addWidget(self.use_tracking) tracking_layout.addStretch(1) layout.addLayout(tracking_layout, 1) self.tracking = None self.select_tracking_label = QLabel("Select tracking") self.select_tracking = QComboBox() self.select_tracking.setItemDelegate(QStyledItemDelegate()) self.select_tracking.setObjectName("SelectCombo") self.select_tracking.addItems(["Sort", "Deep Sort"]) self.select_tracking.currentIndexChanged.connect(self.selection_tracking_change) self.select_tracking.setCurrentIndex(1) layout.addLayout(SelectQCombo(self.select_tracking_label, self.select_tracking), 2) count_layout = QHBoxLayout() self.count_enabled = False self.use_count = QCheckBox("Count performance") self.use_count.setChecked(False) self.use_count_label = QLabel("Count statistics: ") count_layout.addWidget(self.use_count_label) count_layout.addWidget(self.use_count) count_layout.addStretch(1) layout.addLayout(count_layout, 1) layout.addStretch(1) back_button = QPushButton("Back") ok_button = QPushButton("OK") cancel_button = QPushButton("Cancel") hor_box = QHBoxLayout() hor_box.addWidget(back_button, alignment=Qt.AlignLeft) hor_box.addStretch(2) hor_box.addWidget(ok_button) hor_box.addWidget(cancel_button) back_button.clicked.connect(self.back_detection) ok_button.clicked.connect(self.start_detection) cancel_button.clicked.connect(cancel_detection) layout.addLayout(hor_box, 2) self.setLayout(layout) def get_video(self): file_names = QFileDialog.getOpenFileName(self, 'Open Video', self.startDir, 'Videos (*.webm *.mpg *.ogg *.mp4 *.avi *.mov)', "", QFileDialog.DontUseNativeDialog) if file_names[0]: self.args.video = file_names[0] self.textIm.setText(file_names[0]) self.startDir = str(Path(file_names[0][0]).parent) def use_webcam_clicked(self, checked): if checked: self.args.video = 0 self.textIm.setText("") self.textIm.setReadOnly(True) self.btnIm.clicked.disconnect() self.btnIm.hide() self.textIm.hide() else: self.args.video = None self.textIm.setReadOnly(False) self.btnIm.clicked.connect(self.get_video) self.btnIm.show() self.textIm.show() def selection_tracking_change(self, i): if i == 0: self.tracking = "sort" else: self.tracking = "deep_sort" def use_tracking_clicked(self, checked): if checked: self.select_tracking.show() self.select_tracking.itemText(1) self.select_tracking_label.show() self.tracking = "deep_sort" else: self.select_tracking.hide() self.select_tracking_label.hide() self.tracking = None def get_weights(self): filename = QFileDialog.getOpenFileName(self, 'Open Weightsfile', self.startDir, 'Weightsfile (*.weights)', "", QFileDialog.DontUseNativeDialog) if filename[0]: self.args.weights = filename[0] self.textW.setText(filename[0]) self.startDir = str(Path(filename[0]).parent) def get_config(self): filename = QFileDialog.getOpenFileName(self, 'Open Configfile', self.startDir, 'Configfile (*.cfg)', "", QFileDialog.DontUseNativeDialog) if filename[0]: self.args.cfg = filename[0] self.textConf.setText(filename[0]) self.startDir = str(Path(filename[0]).parent) def get_names(self): filename = QFileDialog.getOpenFileName(self, 'Open Namesfile', self.startDir, 'Nmesfile (*.names)', "", QFileDialog.DontUseNativeDialog) if filename[0]: self.args.names = filename[0] self.textNames.setText(filename[0]) self.startDir = str(Path(filename[0]).parent) def start_detection(self): self.args.bs = self.bsEdit.text() self.args.confidence = self.confEdit.text() self.args.nms_thresh = self.nmsEdit.text() self.args.reso = self.resEdit.text() for arg in vars(self.args): if not arg: QMessageBox.critical(self, "Error!", f"Parameter {arg} is empty!") self.count_enabled = self.use_count.isChecked() if self.select_ds.currentText() in ["European", "Belgium", "GTSRB"]: self.args.is_classifier = True base_model = "Croat" self.set_classifier_parameters(base_model) self.parent.show_video_viewer("Video Viewer") def set_classifier_parameters(self, set_name): self.args.classifier_cfg = f"../cfg/{set_name}.cfg" self.args.classifier_weights = f"../weights/{set_name}.weights" self.args.classifier_names = f"../data/{set_name}.names" self.args.classifier_inp_dim = 416 self.args.classifier_confidence = 0.5 self.args.classifier_nms_thresh = 0.4 def back_detection(self): self.parent.back_to_parent() def on_data_set_changed(self, text): self.args.weights = f"../weights/{text}.weights" self.textW.setText(self.args.weights) self.args.cfg = f"../cfg/{text}.cfg" self.textConf.setText(self.args.cfg) self.args.names = f"../data/{text}.names" self.textNames.setText(self.args.names)
class SettingMenu(QFrame): S_port_info = pyqtSignal(str, str, name='PortInfo') S_save_butt_clicked = pyqtSignal(bool, name='SaveButtClicked') S_update_ports = pyqtSignal(bool, name="UpdateButtClicked") def __init__(self, port, port_speed): super().__init__() self.setting_info_ = {'Port': port, 'Speed': port_speed} self.ports_ = {} speeds_ = { "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200" } self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) portEditLabel = QLabel("Port Number:") portEditLabel.setObjectName("SettMenuLabel") self.portBox = QComboBox() self.portBox.addItems(self.ports_) self.portBox.setCurrentText(self.setting_info_["Port"]) speedEditLabel = QLabel("Port Speed: ") speedEditLabel.setObjectName("SettMenuLabel") self.speedBox = QComboBox() self.speedBox.addItems(speeds_) self.speedBox.setCurrentText(self.setting_info_["Speed"]) configSaveButt = QPushButton("SAVE") configSaveButt.setObjectName("SettMenuSaveButt") configSaveButt.clicked.connect(self.set_port_info) updateButt = QPushButton("Update") updateButt.clicked.connect(self.act_update_ports) hPortBoxLay = QHBoxLayout() hPortBoxLay.addWidget(portEditLabel) hPortBoxLay.addWidget(self.portBox) hPortBoxLay.addSpacing(20) hPortBoxLay.addWidget(speedEditLabel) hPortBoxLay.addWidget(self.speedBox) hPortBoxLay.addStretch() saveButtHBoxLay = QHBoxLayout() saveButtHBoxLay.addWidget(configSaveButt) updateButtHBoxLay = QHBoxLayout() updateButtHBoxLay.addWidget(updateButt) # Создаем вертикальное пространство vBoxLay = QVBoxLayout() # Прикрепляем пространство к левому верхнему краю vBoxLay.setAlignment(Qt.AlignTop | Qt.AlignLeft) vBoxLay.addLayout(hPortBoxLay) vBoxLay.addStretch(1) vBoxLay.addLayout(saveButtHBoxLay) vBoxLay.addLayout(updateButtHBoxLay) self.setLayout(vBoxLay) self.hide() def set_port_info(self): self.setting_info_['Port'] = self.portBox.currentText() self.setting_info_['Speed'] = self.speedBox.currentText() self.S_port_info.emit(self.setting_info_["Port"], self.setting_info_['Speed']) self.S_save_butt_clicked.emit(True) def update_ports(self, ports): print("ports updated") self.ports_ = ports self.portBox.clear() self.portBox.addItems(self.ports_) def act_update_ports(self): self.S_update_ports.emit(True)
class StatsWindow(QWidget): def __init__(self): super().__init__() self.setGeometry(150 + 1024, 150, 800, 600) main_box = QVBoxLayout() self.graph_rfi = PlotWidget() self.graph_rfi.setBackground("w") self.graph_rfi.setTitle("RFI", color="k") self.graph_rfi.plot = self.graph_rfi.plot([0,0], [0], pen=mkPen('k', width=1), stepMode=True) self.graph_cand = PlotWidget() self.graph_cand.setBackground("w") self.graph_cand.setTitle("Candidates", color="k") self.graph_cand.plot = self.graph_cand.plot([0,0], [0], pen=mkPen('k', width=1), stepMode=True) self.dist_plot = PlotWidget() self.dist_plot.setMouseEnabled(y=False) self.dist_plot.setBackground("w") self.dist_plot.setTitle("Full distribution", color="k") self.dist_plot.plot = self.dist_plot.plot([0,0], [0], pen=mkPen('k', width=1), stepMode=True) plots_box = QHBoxLayout() plots_box.addWidget(self.graph_rfi) plots_box.addWidget(self.graph_cand) main_box.addLayout(plots_box) main_box.addWidget(self.dist_plot) limits_box = QHBoxLayout() limits_box.setAlignment(Qt.AlignLeft) self.limits_choice = QComboBox() self.limits_choice.addItems(["DM", "MJD"]) self.limits_choice.setFixedWidth(100) limits_box.addWidget(self.limits_choice) self.start_limit = QLineEdit() self.start_limit.setPlaceholderText("from") self.start_limit.setFixedWidth(150) limits_box.addWidget(self.start_limit) self.end_limit = QLineEdit() self.end_limit.setPlaceholderText("to") self.end_limit.setFixedWidth(150) limits_box.addWidget(self.end_limit) self.apply_limits_button = QPushButton() self.apply_limits_button.setFixedWidth(150) self.apply_limits_button.setText("Remove limits") limits_box.addWidget(self.apply_limits_button) self.remove_label = QLabel() limits_box.addWidget(self.remove_label) main_box.addLayout(limits_box) self.setLayout(main_box) def _update(self, rfi_data, cand_data): y_rfi, x_rfi = histogram([cand[1] for cand in rfi_data], bins=min(len(rfi_data) + 1, 100)) self.graph_rfi.plot.setData(x_rfi, y_rfi) y_cand, x_cand = histogram([cand[1] for cand in cand_data], bins=min(len(cand_data) + 1, 100)) self.graph_cand.plot.setData(x_cand, y_cand) def update_dist_plot(self, data, extra_dec=False): y_dist, x_dist = histogram(data, bins=100) ax = self.dist_plot.getAxis("bottom") min_val = min(data) max_val = max(data) tick_vals = linspace(min_val, max_val, num=6) decimals = 2 + extra_dec * 4 ticks = [(val, "{:.{dec}f}".format(val, dec=decimals)) for val in tick_vals] ax.setTicks( [ticks, []]) ax.setStyle(tickLength=-5) self.dist_plot.plot.setData(x_dist, y_dist) self.dist_plot.autoRange()
class QSessionWidget(QWidget): """ Create a new session widget to be put inside a tab in the main window For each session we can have many displays """ # define a signal when the user successful log in logged_in = pyqtSignal(str) sessions_changed = pyqtSignal(collections.deque) def __init__(self, parent): super(QWidget, self).__init__(parent) self.user = "" self.displays = {} self.config_file_name = os.path.join(os.path.expanduser('~'), '.rcm', 'RCM2.cfg') self.sessions_list = None self.parser = RawConfigParser() # widgets self.session_combo = QComboBox(self) self.host_line = QLineEdit(self) self.user_line = QLineEdit(self) self.pssw_line = QLineEdit(self) # containers self.containerLoginWidget = QWidget() self.containerSessionWidget = QWidget() # layouts self.session_ver_layout = QVBoxLayout() self.rows_ver_layout = QVBoxLayout() # icons self.connect_ico = QIcon() self.kill_ico = QIcon() self.share_ico = QIcon() self.init_ui() self.uuid = uuid.uuid4().hex def init_ui(self): """ Initialize the interface """ # Login Layout # grid login layout grid_login_layout = QGridLayout() # parse config file to load the most recent sessions if os.path.exists(self.config_file_name): try: with open(self.config_file_name, 'r') as config_file: self.parser.read_file(config_file, source=self.config_file_name) sessions_list = self.parser.get('LoginFields', 'hostList') self.sessions_list = collections.deque( json.loads(sessions_list), maxlen=5) except: logger.error( "Failed to load the sessions list from the config file") session_label = QLabel(self) session_label.setText('Sessions:') self.session_combo.clear() self.session_combo.addItems(self.sessions_list) self.session_combo.activated.connect(self.on_session_change) if self.sessions_list: self.session_combo.activated.emit(0) grid_login_layout.addWidget(session_label, 0, 0) grid_login_layout.addWidget(self.session_combo, 0, 1) host_label = QLabel(self) host_label.setText('Host:') grid_login_layout.addWidget(host_label, 1, 0) grid_login_layout.addWidget(self.host_line, 1, 1) user_label = QLabel(self) user_label.setText('User:'******'Password:'******'Login', self) pybutton.clicked.connect(self.login) pybutton.setShortcut("Return") login_hor_layout = QHBoxLayout() login_hor_layout.addStretch(1) login_hor_layout.addWidget(pybutton) login_hor_layout.addStretch(1) # login layout # it disappears when the user logged in login_layout = QVBoxLayout() login_layout.addLayout(grid_login_layout) login_layout.addLayout(login_hor_layout) self.containerLoginWidget.setLayout(login_layout) # Create the main layout new_tab_main_layout = QVBoxLayout() new_tab_main_layout.addWidget(self.containerLoginWidget) # Session Layout plusbutton_layout = QGridLayout() self.rows_ver_layout.setContentsMargins(0, 0, 0, 0) self.rows_ver_layout.setSpacing(0) self.session_ver_layout.addLayout(plusbutton_layout) self.session_ver_layout.addLayout(self.rows_ver_layout) self.session_ver_layout.addStretch(1) self.connect_ico.addFile(resource_path('icons/connect.png')) self.kill_ico.addFile(resource_path('icons/kill.png')) self.share_ico.addFile(resource_path('icons/share.png')) font = QFont() font.setBold(True) name = QLabel() name.setText("Name") name.setFont(font) plusbutton_layout.addWidget(name, 0, 0) status = QLabel() status.setText("Status") status.setFont(font) plusbutton_layout.addWidget(status, 0, 1) time = QLabel() time.setText("Time") time.setFont(font) plusbutton_layout.addWidget(time, 0, 2) resources = QLabel() resources.setText("Resources") resources.setFont(font) plusbutton_layout.addWidget(resources, 0, 3) x = QLabel() x.setText("") plusbutton_layout.addWidget(x, 0, 4) plusbutton_layout.addWidget(x, 0, 5) new_display_ico = QIcon() new_display_ico.addFile(resource_path('icons/plus.png'), QSize(16, 16)) new_display_btn = QPushButton() new_display_btn.setIcon(new_display_ico) new_display_btn.setToolTip('Create a new display session') new_display_btn.clicked.connect(self.add_new_display) new_display_layout = QHBoxLayout() new_display_layout.addSpacing(100) new_display_layout.addWidget(new_display_btn) plusbutton_layout.addLayout(new_display_layout, 0, 6) self.containerSessionWidget.setLayout(self.session_ver_layout) new_tab_main_layout.addWidget(self.containerSessionWidget) self.containerSessionWidget.hide() self.setLayout(new_tab_main_layout) def on_session_change(self): """ Update the user and host fields when the user selects a different session in the combo :return: """ try: user, host = self.session_combo.currentText().split('@') self.user_line.setText(user) self.host_line.setText(host) except ValueError: pass def login(self): session_name = str(self.user_line.text()) + "@" + str( self.host_line.text()) try: logger.info("Logging into " + session_name) ssh_login(self.host_line.text(), 22, self.user_line.text(), self.pssw_line.text(), 'ls') except AuthenticationException: logger.error("Failed to login: invalid credentials") return logger.info("Logged in " + session_name) self.user = self.user_line.text() # update sessions list if session_name in list(self.sessions_list): self.sessions_list.remove(session_name) self.sessions_list.appendleft(session_name) self.sessions_changed.emit(self.sessions_list) # update config file self.update_config_file(session_name) # Hide the login view and show the session one self.containerLoginWidget.hide() self.containerSessionWidget.show() # Emit the logged_in signal. self.logged_in.emit(session_name) def add_new_display(self): # cannot have more than 5 sessions if len(self.displays) >= 5: logger.warning("You have already 5 displays") return display_win = QDisplayDialog(list(self.displays.keys())) display_win.setModal(True) if display_win.exec() != 1: return display_hor_layout = QHBoxLayout() display_hor_layout.setContentsMargins(0, 2, 0, 2) display_hor_layout.setSpacing(2) display_ver_layout = QVBoxLayout() display_ver_layout.setContentsMargins(0, 0, 0, 0) display_ver_layout.setSpacing(0) display_ver_layout.addLayout(display_hor_layout) display_widget = QWidget() display_widget.setLayout(display_ver_layout) id = display_win.display_name print(id) name = QLabel() name.setText(str(id)[:16]) display_hor_layout.addWidget(name) status = QLabel() status.setText("Pending...") display_hor_layout.addWidget(status) time = QLabel() time.setText("24H") display_hor_layout.addWidget(time) resources = QLabel() resources.setText("1 Node") display_hor_layout.addWidget(resources) connect_btn = QPushButton() connect_btn.setIcon(self.connect_ico) connect_btn.setToolTip('Connect to the remote display') connect_btn.clicked.connect(lambda: self.connect_display(id)) display_hor_layout.addWidget(connect_btn) share_btn = QPushButton() share_btn.setIcon(self.share_ico) share_btn.setToolTip('Share the remote display via file') share_btn.clicked.connect(lambda: self.share_display(id)) display_hor_layout.addWidget(share_btn) kill_btn = QPushButton() kill_btn.setIcon(self.kill_ico) kill_btn.setToolTip('Kill the remote display') kill_btn.clicked.connect(lambda: self.kill_display(id)) display_hor_layout.addWidget(kill_btn) separator = QFrame() separator.setFrameShape(QFrame.HLine) separator.setFrameShadow(QFrame.Sunken) display_ver_layout.addWidget(separator) self.rows_ver_layout.addWidget(display_widget) self.displays[id] = display_widget logger.info("Added new display") def update_config_file(self, session_name): """ Update the config file with the new session name :param session_name: name of the last session inserted by the user :return: """ if not self.parser.has_section('LoginFields'): self.parser.add_section('LoginFields') self.parser.set('LoginFields', 'hostList', json.dumps(list(self.sessions_list))) try: config_file_dir = os.path.dirname(self.config_file_name) if not os.path.exists(config_file_dir): os.makedirs(config_file_dir) with open( os.path.join(os.path.expanduser('~'), '.rcm', 'RCM2.cfg'), 'w') as config_file: self.parser.write(config_file) except: logger.error( "failed to dump the session list in the configuration file") def connect_display(self, id): print(self.displays[id]) logger.info("Connected to remote display " + str(id)) def share_display(self, id): print(self.displays[id]) logger.info("Shared display " + str(id)) def kill_display(self, id): # first we hide the display logger.debug("Hiding display " + str(id)) self.displays[id].hide() # then we remove it from the layout and the dictionary self.rows_ver_layout.removeWidget(self.displays[id]) del self.displays[id] logger.info("Killed display " + str(id))
app = QApplication([]) print('initialised app') data = networkData() print('initialised data') window = QWidget() print('initialised window') print('program initialised') print('setting layout') layout = QVBoxLayout() layout.addWidget(QLabel('Program to graph network speeds and ping times')) print('Added label') QComboBox() ssids = QComboBox() ssids.addItems(data.ssids) layout.addWidget(ssids) metrics = QComboBox() metrics.addItems(data.data[data.ssids[0]].columns) layout.addWidget(metrics) window.setLayout(layout) window.show() app.exec_() data = networkData() data.plotter(data.ssids[1])
class NetworkChoiceLayout(object): def __init__(self, network: Network, config: 'SimpleConfig', wizard=False): self.network = network self.config = config self.tor_proxy = None self.tabs = tabs = QTabWidget() proxy_tab = QWidget() blockchain_tab = QWidget() tabs.addTab(blockchain_tab, _('Overview')) tabs.addTab(proxy_tab, _('Proxy')) fixed_width_hostname = 24 * char_width_in_lineedit() fixed_width_port = 6 * char_width_in_lineedit() # Proxy tab grid = QGridLayout(proxy_tab) grid.setSpacing(8) # proxy setting self.proxy_cb = QCheckBox(_('Use proxy')) self.proxy_cb.clicked.connect(self.check_disable_proxy) self.proxy_cb.clicked.connect(self.set_proxy) self.proxy_cb.setEnabled(self.config.is_modifiable('proxy')) self.proxy_mode = QComboBox() self.proxy_mode.addItems(['SOCKS4', 'SOCKS5']) self.proxy_host = QLineEdit() self.proxy_host.setFixedWidth(fixed_width_hostname) self.proxy_port = QLineEdit() self.proxy_port.setFixedWidth(fixed_width_port) self.proxy_user = QLineEdit() self.proxy_user.setPlaceholderText(_("Proxy user")) self.proxy_password = PasswordLineEdit() self.proxy_password.setPlaceholderText(_("Password")) self.proxy_password.setFixedWidth(fixed_width_port) self.proxy_mode.currentIndexChanged.connect(self.set_proxy) self.proxy_host.editingFinished.connect(self.set_proxy) self.proxy_port.editingFinished.connect(self.set_proxy) self.proxy_user.editingFinished.connect(self.set_proxy) self.proxy_password.editingFinished.connect(self.set_proxy) self.proxy_mode.currentIndexChanged.connect( self.proxy_settings_changed) self.proxy_host.textEdited.connect(self.proxy_settings_changed) self.proxy_port.textEdited.connect(self.proxy_settings_changed) self.proxy_user.textEdited.connect(self.proxy_settings_changed) self.proxy_password.textEdited.connect(self.proxy_settings_changed) self.tor_cb = QCheckBox(_("Use Tor Proxy")) self.tor_cb.setIcon(read_QIcon("tor_logo.png")) self.tor_cb.hide() self.tor_cb.clicked.connect(self.use_tor_proxy) self.tor_auto_on_cb = QCheckBox(self.network.TOR_AUTO_ON_MSG) self.tor_auto_on_cb.setIcon(read_QIcon("tor_logo.png")) self.tor_auto_on_cb.setChecked(self.config.get('tor_auto_on', True)) self.tor_auto_on_cb.clicked.connect(self.use_tor_auto_on) self.fiat_bypass_tor_cb = QCheckBox(self.network.FIAT_BYPASS_TOR_MSG) fiat_bypass_tor = self.config.get('fiat_bypass_tor', False) self.fiat_bypass_tor_cb.setChecked(fiat_bypass_tor) self.fiat_bypass_tor_cb.clicked.connect(self.fiat_bypass_tor) grid.addWidget(self.tor_cb, 1, 0, 1, 3) grid.addWidget(self.proxy_cb, 2, 0, 1, 3) grid.addWidget( HelpButton( _('Proxy settings apply to all connections: with Dash Electrum servers, but also with third-party services.' )), 2, 4) grid.addWidget(self.proxy_mode, 4, 1) grid.addWidget(self.proxy_host, 4, 2) grid.addWidget(self.proxy_port, 4, 3) grid.addWidget(self.proxy_user, 5, 2) grid.addWidget(self.proxy_password, 5, 3) grid.addWidget(self.tor_auto_on_cb, 6, 0, 1, 3) grid.addWidget( HelpButton( _('During wallet startup try to detect and use Tor Proxy.')), 6, 4) grid.addWidget(self.fiat_bypass_tor_cb, 7, 0, 1, 3) grid.setRowStretch(8, 1) # Blockchain Tab grid = QGridLayout(blockchain_tab) msg = ' '.join([ _("Dash Electrum connects to several nodes in order to download block headers and find out the longest blockchain." ), _("This blockchain is used to verify the transactions sent by your transaction server." ) ]) self.status_label = QLabel('') grid.addWidget(QLabel(_('Status') + ':'), 0, 0) grid.addWidget(self.status_label, 0, 1, 1, 3) grid.addWidget(HelpButton(msg), 0, 4) self.autoconnect_cb = QCheckBox(_('Select server automatically')) self.autoconnect_cb.setEnabled( self.config.is_modifiable('auto_connect')) self.autoconnect_cb.clicked.connect(self.set_server) self.autoconnect_cb.clicked.connect(self.update) msg = ' '.join([ _("If auto-connect is enabled, Dash Electrum will always use a server that is on the longest blockchain." ), _("If it is disabled, you have to choose a server you want to use. Dash Electrum will warn you if your server is lagging." ) ]) grid.addWidget(self.autoconnect_cb, 1, 0, 1, 3) grid.addWidget(HelpButton(msg), 1, 4) self.server_e = QLineEdit() self.server_e.setFixedWidth(fixed_width_hostname + fixed_width_port) self.server_e.editingFinished.connect(self.set_server) msg = _( "Dash Electrum sends your wallet addresses to a single server, in order to receive your transaction history." ) grid.addWidget(QLabel(_('Server') + ':'), 2, 0) grid.addWidget(self.server_e, 2, 1, 1, 3) grid.addWidget(HelpButton(msg), 2, 4) self.height_label = QLabel('') msg = _('This is the height of your local copy of the blockchain.') grid.addWidget(QLabel(_('Blockchain') + ':'), 3, 0) grid.addWidget(self.height_label, 3, 1) grid.addWidget(HelpButton(msg), 3, 4) self.split_label = QLabel('') grid.addWidget(self.split_label, 4, 0, 1, 3) self.nodes_list_widget = NodesListWidget(self) grid.addWidget(self.nodes_list_widget, 6, 0, 1, 5) vbox = QVBoxLayout() vbox.addWidget(tabs) self.layout_ = vbox # tor detector self.td = td = TorDetector() td.found_proxy.connect(self.suggest_proxy) td.start() self.fill_in_proxy_settings() self.update() def clean_up(self): if self.td: self.td.found_proxy.disconnect() self.td.stop() self.td = None def check_disable_proxy(self, b): if not self.config.is_modifiable('proxy'): b = False for w in [ self.proxy_mode, self.proxy_host, self.proxy_port, self.proxy_user, self.proxy_password ]: w.setEnabled(b) def enable_set_server(self): if self.config.is_modifiable('server'): enabled = not self.autoconnect_cb.isChecked() self.server_e.setEnabled(enabled) else: for w in [ self.autoconnect_cb, self.server_e, self.nodes_list_widget ]: w.setEnabled(False) def update(self): net_params = self.network.get_parameters() server = net_params.server auto_connect = net_params.auto_connect if not self.server_e.hasFocus(): self.server_e.setText(server.to_friendly_name()) self.autoconnect_cb.setChecked(auto_connect) height_str = "%d " % (self.network.get_local_height()) + _('blocks') self.height_label.setText(height_str) n = len(self.network.get_interfaces()) status = _("Connected to {0} nodes.").format(n) if n > 1 else _( "Connected to {0} node.").format(n) if n == 1 else _( "Not connected") self.status_label.setText(status) chains = self.network.get_blockchains() if len(chains) > 1: chain = self.network.blockchain() forkpoint = chain.get_max_forkpoint() name = chain.get_name() msg = _('Chain split detected at block {0}').format( forkpoint) + '\n' msg += (_('You are following branch') if auto_connect else _('Your server is on branch')) + ' ' + name msg += ' (%d %s)' % (chain.get_branch_size(), _('blocks')) else: msg = '' self.split_label.setText(msg) self.nodes_list_widget.update(network=self.network, servers=self.network.get_servers(), use_tor=self.tor_cb.isChecked()) self.enable_set_server() def fill_in_proxy_settings(self): proxy_config = self.network.get_parameters().proxy if not proxy_config: proxy_config = { "mode": "none", "host": "localhost", "port": "9050" } b = proxy_config.get('mode') != "none" self.check_disable_proxy(b) if b: self.proxy_cb.setChecked(True) self.proxy_mode.setCurrentIndex( self.proxy_mode.findText(str( proxy_config.get("mode").upper()))) self.proxy_host.setText(proxy_config.get("host")) self.proxy_port.setText(proxy_config.get("port")) self.proxy_user.setText(proxy_config.get("user", "")) self.proxy_password.setText(proxy_config.get("password", "")) def layout(self): return self.layout_ def follow_branch(self, chain_id): self.network.run_from_another_thread( self.network.follow_chain_given_id(chain_id)) self.update() def follow_server(self, server: ServerAddr): self.network.run_from_another_thread( self.network.follow_chain_given_server(server)) self.update() def accept(self): pass def set_server(self): net_params = self.network.get_parameters() try: server = ServerAddr.from_str_with_inference( str(self.server_e.text())) if not server: raise Exception("failed to parse") except Exception: return net_params = net_params._replace( server=server, auto_connect=self.autoconnect_cb.isChecked()) self.network.run_from_another_thread( self.network.set_parameters(net_params)) def set_proxy(self): net_params = self.network.get_parameters() if self.proxy_cb.isChecked(): proxy = { 'mode': str(self.proxy_mode.currentText()).lower(), 'host': str(self.proxy_host.text()), 'port': str(self.proxy_port.text()), 'user': str(self.proxy_user.text()), 'password': str(self.proxy_password.text()) } else: proxy = None self.tor_cb.setChecked(False) net_params = net_params._replace(proxy=proxy) self.network.run_from_another_thread( self.network.set_parameters(net_params)) def suggest_proxy(self, found_proxy): if found_proxy is None: self.tor_cb.hide() return self.tor_proxy = found_proxy self.tor_cb.setText("Use Tor proxy at port " + str(found_proxy[1])) if (self.proxy_cb.isChecked() and self.proxy_mode.currentIndex() == self.proxy_mode.findText('SOCKS5') and self.proxy_host.text() == "127.0.0.1" and self.proxy_port.text() == str(found_proxy[1])): self.tor_cb.setChecked(True) self.tor_cb.show() def use_tor_proxy(self, use_it): if not use_it: self.proxy_cb.setChecked(False) else: socks5_mode_index = self.proxy_mode.findText('SOCKS5') if socks5_mode_index == -1: _logger.info("can't find proxy_mode 'SOCKS5'") return self.proxy_mode.setCurrentIndex(socks5_mode_index) self.proxy_host.setText("127.0.0.1") self.proxy_port.setText(str(self.tor_proxy[1])) self.proxy_user.setText("") self.proxy_password.setText("") self.tor_cb.setChecked(True) self.proxy_cb.setChecked(True) self.check_disable_proxy(use_it) self.set_proxy() def fiat_bypass_tor(self, bypass): self.config.set_key('fiat_bypass_tor', bypass, False) coro = self.network.restart() self.network.run_from_another_thread(coro) def proxy_settings_changed(self): self.tor_cb.setChecked(False) def use_tor_auto_on(self, use_it): self.config.set_key('tor_auto_on', use_it, True)
def __init__(self, parent: 'ElectrumWindow', config: 'SimpleConfig'): WindowModalDialog.__init__(self, parent, _('Preferences')) self.config = config self.window = parent self.need_restart = False self.fx = self.window.fx self.wallet = self.window.wallet vbox = QVBoxLayout() tabs = QTabWidget() gui_widgets = [] tx_widgets = [] oa_widgets = [] # language lang_help = _( 'Select which language is used in the GUI (after restart).') lang_label = HelpLabel(_('Language') + ':', lang_help) lang_combo = QComboBox() lang_combo.addItems(list(languages.values())) lang_keys = list(languages.keys()) lang_cur_setting = self.config.get("language", '') try: index = lang_keys.index(lang_cur_setting) except ValueError: # not in list index = 0 lang_combo.setCurrentIndex(index) if not self.config.is_modifiable('language'): for w in [lang_combo, lang_label]: w.setEnabled(False) def on_lang(x): lang_request = list(languages.keys())[lang_combo.currentIndex()] if lang_request != self.config.get('language'): self.config.set_key("language", lang_request, True) self.need_restart = True lang_combo.currentIndexChanged.connect(on_lang) gui_widgets.append((lang_label, lang_combo)) nz_help = _( 'Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"' ) nz_label = HelpLabel(_('Zeros after decimal point') + ':', nz_help) nz = QSpinBox() nz.setMinimum(0) nz.setMaximum(self.config.decimal_point) nz.setValue(self.config.num_zeros) if not self.config.is_modifiable('num_zeros'): for w in [nz, nz_label]: w.setEnabled(False) def on_nz(): value = nz.value() if self.config.num_zeros != value: self.config.num_zeros = value self.config.set_key('num_zeros', value, True) self.window.history_list.update() self.window.address_list.update() nz.valueChanged.connect(on_nz) gui_widgets.append((nz_label, nz)) #use_rbf = bool(self.config.get('use_rbf', True)) #use_rbf_cb = QCheckBox(_('Use Replace-By-Fee')) #use_rbf_cb.setChecked(use_rbf) #use_rbf_cb.setToolTip( # _('If you check this box, your transactions will be marked as non-final,') + '\n' + \ # _('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \ # _('Note that some merchants do not accept non-final transactions until they are confirmed.')) #def on_use_rbf(x): # self.config.set_key('use_rbf', bool(x)) # batch_rbf_cb.setEnabled(bool(x)) #use_rbf_cb.stateChanged.connect(on_use_rbf) #tx_widgets.append((use_rbf_cb, None)) #batch_rbf_cb = QCheckBox(_('Batch RBF transactions')) #batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False))) #batch_rbf_cb.setEnabled(use_rbf) #batch_rbf_cb.setToolTip( # _('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \ # _('This will save fees.')) #def on_batch_rbf(x): # self.config.set_key('batch_rbf', bool(x)) #batch_rbf_cb.stateChanged.connect(on_batch_rbf) #tx_widgets.append((batch_rbf_cb, None)) # lightning lightning_widgets = [] help_local_wt = _("""If this option is checked, Electrum will run a local watchtower and protect your channels even if your wallet is not open. For this to work, your computer needs to be online regularly.""") local_wt_cb = QCheckBox(_("Run a local watchtower")) local_wt_cb.setToolTip(help_local_wt) local_wt_cb.setChecked( bool(self.config.get('run_local_watchtower', False))) def on_local_wt_checked(x): self.config.set_key('run_local_watchtower', bool(x)) local_wt_cb.stateChanged.connect(on_local_wt_checked) lightning_widgets.append((local_wt_cb, None)) help_persist = _( """If this option is checked, Electrum will persist after you close all your wallet windows, and the Electrum icon will be visible in the taskbar. Use this if you want your local watchtower to keep running after you close your wallet.""" ) persist_cb = QCheckBox(_("Persist after all windows are closed")) persist_cb.setToolTip(help_persist) persist_cb.setChecked(bool(self.config.get('persist_daemon', False))) def on_persist_checked(x): self.config.set_key('persist_daemon', bool(x)) persist_cb.stateChanged.connect(on_persist_checked) lightning_widgets.append((persist_cb, None)) help_remote_wt = _( """To use a remote watchtower, enter the corresponding URL here""") remote_wt_cb = QCheckBox(_("Use a remote watchtower")) remote_wt_cb.setToolTip(help_remote_wt) remote_wt_cb.setChecked(bool(self.config.get('use_watchtower', False))) def on_remote_wt_checked(x): self.config.set_key('use_watchtower', bool(x)) self.watchtower_url_e.setEnabled(bool(x)) remote_wt_cb.stateChanged.connect(on_remote_wt_checked) watchtower_url = self.config.get('watchtower_url') self.watchtower_url_e = QLineEdit(watchtower_url) self.watchtower_url_e.setEnabled( self.config.get('use_watchtower', False)) def on_wt_url(): url = self.watchtower_url_e.text() or None watchtower_url = self.config.set_key('watchtower_url', url) self.watchtower_url_e.editingFinished.connect(on_wt_url) lightning_widgets.append((remote_wt_cb, self.watchtower_url_e)) msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\ + _('The following alias providers are available:') + '\n'\ + '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\ + 'For more information, see https://openalias.org' alias_label = HelpLabel(_('OpenAlias') + ':', msg) alias = self.config.get('alias', '') self.alias_e = QLineEdit(alias) self.set_alias_color() self.alias_e.editingFinished.connect(self.on_alias_edit) oa_widgets.append((alias_label, self.alias_e)) # units units = base_units_list msg = (_( 'Base unit of your wallet.' ) + '\n1 BTC = 1000 mBTC. 1 mBTC = 1000 bits. 1 bit = 100 sat.\n' + _( 'This setting affects the Send tab, and all balance related fields.' )) unit_label = HelpLabel(_('Base unit') + ':', msg) unit_combo = QComboBox() unit_combo.addItems(units) unit_combo.setCurrentIndex(units.index(self.window.base_unit())) def on_unit(x, nz): unit_result = units[unit_combo.currentIndex()] if self.window.base_unit() == unit_result: return edits = self.window.amount_e, self.window.receive_amount_e amounts = [edit.get_amount() for edit in edits] self.config.set_base_unit(unit_result) nz.setMaximum(self.config.decimal_point) self.window.history_list.update() self.window.request_list.update() self.window.address_list.update() for edit, amount in zip(edits, amounts): edit.setAmount(amount) self.window.update_status() unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz)) gui_widgets.append((unit_label, unit_combo)) system_cameras = qrscanner._find_system_cameras() qr_combo = QComboBox() qr_combo.addItem("Default", "default") for camera, device in system_cameras.items(): qr_combo.addItem(camera, device) #combo.addItem("Manually specify a device", config.get("video_device")) index = qr_combo.findData(self.config.get("video_device")) qr_combo.setCurrentIndex(index) msg = _("Install the zbar package to enable this.") qr_label = HelpLabel(_('Video Device') + ':', msg) qr_combo.setEnabled(qrscanner.libzbar is not None) on_video_device = lambda x: self.config.set_key( "video_device", qr_combo.itemData(x), True) qr_combo.currentIndexChanged.connect(on_video_device) gui_widgets.append((qr_label, qr_combo)) colortheme_combo = QComboBox() colortheme_combo.addItem(_('Light'), 'default') colortheme_combo.addItem(_('Dark'), 'dark') index = colortheme_combo.findData( self.config.get('qt_gui_color_theme', 'default')) colortheme_combo.setCurrentIndex(index) colortheme_label = QLabel(_('Color theme') + ':') def on_colortheme(x): self.config.set_key('qt_gui_color_theme', colortheme_combo.itemData(x), True) self.need_restart = True colortheme_combo.currentIndexChanged.connect(on_colortheme) gui_widgets.append((colortheme_label, colortheme_combo)) updatecheck_cb = QCheckBox( _("Automatically check for software updates")) updatecheck_cb.setChecked(bool(self.config.get('check_updates', False))) def on_set_updatecheck(v): self.config.set_key('check_updates', v == Qt.Checked, save=True) updatecheck_cb.stateChanged.connect(on_set_updatecheck) gui_widgets.append((updatecheck_cb, None)) filelogging_cb = QCheckBox(_("Write logs to file")) filelogging_cb.setChecked(bool(self.config.get('log_to_file', False))) def on_set_filelogging(v): self.config.set_key('log_to_file', v == Qt.Checked, save=True) self.need_restart = True filelogging_cb.stateChanged.connect(on_set_filelogging) filelogging_cb.setToolTip( _('Debug logs can be persisted to disk. These are useful for troubleshooting.' )) gui_widgets.append((filelogging_cb, None)) preview_cb = QCheckBox(_('Advanced preview')) preview_cb.setChecked(bool(self.config.get('advanced_preview', False))) preview_cb.setToolTip( _("Open advanced transaction preview dialog when 'Pay' is clicked." )) def on_preview(x): self.config.set_key('advanced_preview', x == Qt.Checked) preview_cb.stateChanged.connect(on_preview) tx_widgets.append((preview_cb, None)) usechange_cb = QCheckBox(_('Use change addresses')) usechange_cb.setChecked(self.window.wallet.use_change) if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False) def on_usechange(x): usechange_result = x == Qt.Checked if self.window.wallet.use_change != usechange_result: self.window.wallet.use_change = usechange_result self.window.wallet.db.put('use_change', self.window.wallet.use_change) multiple_cb.setEnabled(self.window.wallet.use_change) usechange_cb.stateChanged.connect(on_usechange) usechange_cb.setToolTip( _('Using change addresses makes it more difficult for other people to track your transactions.' )) tx_widgets.append((usechange_cb, None)) def on_multiple(x): multiple = x == Qt.Checked if self.wallet.multiple_change != multiple: self.wallet.multiple_change = multiple self.wallet.db.put('multiple_change', multiple) multiple_change = self.wallet.multiple_change multiple_cb = QCheckBox(_('Use multiple change addresses')) multiple_cb.setEnabled(self.wallet.use_change) multiple_cb.setToolTip('\n'.join([ _('In some cases, use up to 3 change addresses in order to break ' 'up large coin amounts and obfuscate the recipient address.'), _('This may result in higher transactions fees.') ])) multiple_cb.setChecked(multiple_change) multiple_cb.stateChanged.connect(on_multiple) tx_widgets.append((multiple_cb, None)) def fmt_docs(key, klass): lines = [ln.lstrip(" ") for ln in klass.__doc__.split("\n")] return '\n'.join([key, "", " ".join(lines)]) choosers = sorted(coinchooser.COIN_CHOOSERS.keys()) if len(choosers) > 1: chooser_name = coinchooser.get_name(self.config) msg = _( 'Choose coin (UTXO) selection method. The following are available:\n\n' ) msg += '\n\n'.join( fmt_docs(*item) for item in coinchooser.COIN_CHOOSERS.items()) chooser_label = HelpLabel(_('Coin selection') + ':', msg) chooser_combo = QComboBox() chooser_combo.addItems(choosers) i = choosers.index(chooser_name) if chooser_name in choosers else 0 chooser_combo.setCurrentIndex(i) def on_chooser(x): chooser_name = choosers[chooser_combo.currentIndex()] self.config.set_key('coin_chooser', chooser_name) chooser_combo.currentIndexChanged.connect(on_chooser) tx_widgets.append((chooser_label, chooser_combo)) def on_unconf(x): self.config.set_key('confirmed_only', bool(x)) conf_only = bool(self.config.get('confirmed_only', False)) unconf_cb = QCheckBox(_('Spend only confirmed coins')) unconf_cb.setToolTip(_('Spend only confirmed inputs.')) unconf_cb.setChecked(conf_only) unconf_cb.stateChanged.connect(on_unconf) tx_widgets.append((unconf_cb, None)) def on_outrounding(x): self.config.set_key('coin_chooser_output_rounding', bool(x)) enable_outrounding = bool( self.config.get('coin_chooser_output_rounding', True)) outrounding_cb = QCheckBox(_('Enable output value rounding')) outrounding_cb.setToolTip( _('Set the value of the change output so that it has similar precision to the other outputs.' ) + '\n' + _('This might improve your privacy somewhat.') + '\n' + _('If enabled, at most 100 satoshis might be lost due to this, per transaction.' )) outrounding_cb.setChecked(enable_outrounding) outrounding_cb.stateChanged.connect(on_outrounding) tx_widgets.append((outrounding_cb, None)) block_explorers = sorted(util.block_explorer_info().keys()) msg = _( 'Choose which online block explorer to use for functions that open a web browser' ) block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg) block_ex_combo = QComboBox() block_ex_combo.addItems(block_explorers) block_ex_combo.setCurrentIndex( block_ex_combo.findText(util.block_explorer(self.config))) def on_be(x): be_result = block_explorers[block_ex_combo.currentIndex()] self.config.set_key('block_explorer', be_result, True) block_ex_combo.currentIndexChanged.connect(on_be) tx_widgets.append((block_ex_label, block_ex_combo)) # Fiat Currency hist_checkbox = QCheckBox() hist_capgains_checkbox = QCheckBox() fiat_address_checkbox = QCheckBox() ccy_combo = QComboBox() ex_combo = QComboBox() def update_currencies(): if not self.window.fx: return currencies = sorted( self.fx.get_currencies(self.fx.get_history_config())) ccy_combo.clear() ccy_combo.addItems([_('None')] + currencies) if self.fx.is_enabled(): ccy_combo.setCurrentIndex( ccy_combo.findText(self.fx.get_currency())) def update_history_cb(): if not self.fx: return hist_checkbox.setChecked(self.fx.get_history_config()) hist_checkbox.setEnabled(self.fx.is_enabled()) def update_fiat_address_cb(): if not self.fx: return fiat_address_checkbox.setChecked(self.fx.get_fiat_address_config()) def update_history_capgains_cb(): if not self.fx: return hist_capgains_checkbox.setChecked( self.fx.get_history_capital_gains_config()) hist_capgains_checkbox.setEnabled(hist_checkbox.isChecked()) def update_exchanges(): if not self.fx: return b = self.fx.is_enabled() ex_combo.setEnabled(b) if b: h = self.fx.get_history_config() c = self.fx.get_currency() exchanges = self.fx.get_exchanges_by_ccy(c, h) else: exchanges = self.fx.get_exchanges_by_ccy('USD', False) ex_combo.blockSignals(True) ex_combo.clear() ex_combo.addItems(sorted(exchanges)) ex_combo.setCurrentIndex( ex_combo.findText(self.fx.config_exchange())) ex_combo.blockSignals(False) def on_currency(hh): if not self.fx: return b = bool(ccy_combo.currentIndex()) ccy = str(ccy_combo.currentText()) if b else None self.fx.set_enabled(b) if b and ccy != self.fx.ccy: self.fx.set_currency(ccy) update_history_cb() update_exchanges() self.window.update_fiat() def on_exchange(idx): exchange = str(ex_combo.currentText()) if self.fx and self.fx.is_enabled( ) and exchange and exchange != self.fx.exchange.name(): self.fx.set_exchange(exchange) def on_history(checked): if not self.fx: return self.fx.set_history_config(checked) update_exchanges() self.window.history_model.refresh('on_history') if self.fx.is_enabled() and checked: self.fx.trigger_update() update_history_capgains_cb() def on_history_capgains(checked): if not self.fx: return self.fx.set_history_capital_gains_config(checked) self.window.history_model.refresh('on_history_capgains') def on_fiat_address(checked): if not self.fx: return self.fx.set_fiat_address_config(checked) self.window.address_list.refresh_headers() self.window.address_list.update() update_currencies() update_history_cb() update_history_capgains_cb() update_fiat_address_cb() update_exchanges() ccy_combo.currentIndexChanged.connect(on_currency) hist_checkbox.stateChanged.connect(on_history) hist_capgains_checkbox.stateChanged.connect(on_history_capgains) fiat_address_checkbox.stateChanged.connect(on_fiat_address) ex_combo.currentIndexChanged.connect(on_exchange) fiat_widgets = [] fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo)) fiat_widgets.append((QLabel(_('Source')), ex_combo)) fiat_widgets.append((QLabel(_('Show history rates')), hist_checkbox)) fiat_widgets.append((QLabel(_('Show capital gains in history')), hist_capgains_checkbox)) fiat_widgets.append((QLabel(_('Show Fiat balance for addresses')), fiat_address_checkbox)) tabs_info = [ (gui_widgets, _('General')), (tx_widgets, _('Transactions')), (lightning_widgets, _('Lightning')), (fiat_widgets, _('Fiat')), (oa_widgets, _('OpenAlias')), ] for widgets, name in tabs_info: tab = QWidget() tab_vbox = QVBoxLayout(tab) grid = QGridLayout() for a, b in widgets: i = grid.rowCount() if b: if a: grid.addWidget(a, i, 0) grid.addWidget(b, i, 1) else: grid.addWidget(a, i, 0, 1, 2) tab_vbox.addLayout(grid) tab_vbox.addStretch(1) tabs.addTab(tab, name) vbox.addWidget(tabs) vbox.addStretch(1) vbox.addLayout(Buttons(CloseButton(self))) self.setLayout(vbox)
class UploadCard(QWidget): def __init__(self, filename): super(UploadCard, self).__init__() self.filename = filename self.photo_index = 0 # 用于记录存储了几张图片 self.powerStatus = False # 图像显示 layout = QGridLayout() self.capture = None self.timer = QTimer(self) self.useBtn = QPushButton("亮证经营拍照取证") self.useBtn.setDisabled(True) self.useBtn.clicked.connect(self.useTake) self.noBtn = QPushButton("重新拍照") self.noBtn.setDisabled(True) self.noBtn.clicked.connect(self.restartTake) self.camera = QLabel("摄像头准备中。。。。") self.startBtn = QPushButton("打开摄像头") self.startBtn.clicked.connect(self.startCamera) self.takeBtn = QPushButton("拍照") self.takeBtn.clicked.connect(self.takePhoto) self.nextBtn = QPushButton("下一步") # 跳过上传许可证的备注说明 self.remarkLable = QLabel("未亮证理由说明:") self.remarkComb = QComboBox() self.remarkComb.addItems(["无证", "其他"]) self.edit_reason = QLineEdit() self.edit_reason.setPlaceholderText('选择"其他"时需要填入理由') layout.addWidget(self.camera, 0, 0, 1, 3) layout.addWidget(self.startBtn, 1, 0) layout.addWidget(self.takeBtn, 1, 1) layout.addWidget(self.noBtn, 1, 2) layout.addWidget(self.useBtn, 2, 0, 1, 3) layout.addWidget(self.remarkLable, 3, 0) layout.addWidget(self.remarkComb, 3, 1) layout.addWidget(self.edit_reason, 3, 2) layout.addWidget(self.nextBtn, 4, 0, 1, 3) self.takeBtn.setDisabled(True) self.noBtn.setDisabled(True) self.useBtn.setDisabled(True) self.setLayout(layout) # 绘制文件格式 style_str = "QLabel{font-size: 30px;}" + "QLineEdit{font-size: 30px;}" + \ "QPushButton{font-size: 25px; background-color: green; min-height: 50px; min-width: 300px}" + \ "QComboBox{font-size: 30px;}" self.setStyleSheet(style_str) def startCamera(self): if not self.powerStatus: self.takeBtn.setDisabled(False) self.noBtn.setDisabled(True) self.useBtn.setDisabled(True) self.powerStatus = True self.startBtn.setText("关闭摄像头") self.capture = cv2.VideoCapture(1) self.timer.timeout.connect(self.display) self.timer.start(100) else: self.powerStatus = False self.startBtn.setText("打开摄像头") self.takeBtn.setDisabled(True) self.noBtn.setDisabled(True) self.useBtn.setDisabled(True) self.timer.stop() self.capture.release() # 下一步 def release(self): try: self.timer.stop() self.capture.release() except Exception as e: print(e) # 如果没有上传过许可证,填入许可证明 if self.photo_index == 0: # 判断选择无证还是其他原因 if self.remarkComb.currentText() == "无证": reason = "无证" else: reason = self.edit_reason.text() if not reason: QMessageBox.critical(self, "错误", "选择<其他>原因时需要填写具体原因", QMessageBox.Yes) return False wb = openpyxl.load_workbook(self.filename) try: ws = wb["许可证照片"] except Exception as e: print(e) ws = wb.create_sheet(title="许可证照片") ws["A1"] = reason wb.save(self.filename) return True # 从摄像头中获取图片信息 def get_image(self): ret, frame = self.capture.read() if ret: frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) self.pil_image = PILImage.fromarray(frame) height, width = frame.shape[:2] img = QImage(frame, width, height, QImage.Format_RGB888) return img else: return None # 显示图片 def display(self): img = self.get_image() if img: img = QPixmap.fromImage(img) self.camera.setPixmap(img) self.camera.setScaledContents(True) else: pass # 拍照 def takePhoto(self): self.timer.stop() self.takeBtn.setDisabled(True) self.useBtn.setDisabled(False) self.noBtn.setDisabled(False) # 重新拍照 def restartTake(self): self.timer.start(100) self.takeBtn.setDisabled(False) self.useBtn.setDisabled(True) self.noBtn.setDisabled(True) # 使用该照片并上传 def useTake(self): # 读写excel并存储图片 self.uploadPhoto() self.timer.start(100) self.takeBtn.setDisabled(False) self.useBtn.setDisabled(True) self.noBtn.setDisabled(True) # 读写excel数据 def uploadPhoto(self): # 1现场 2许可证 wb = openpyxl.load_workbook(self.filename) try: ws = wb["许可证照片"] except Exception as e: print(e) ws = wb.create_sheet(title="许可证照片") self.pil_image.save("./tmp.jpg") img_file = Image("./tmp.jpg") ws.add_image(img_file, "A" + str(self.photo_index * 30 + 2)) wb.save(self.filename) self.photo_index += 1
class ctdSensorDifferencePlot(QMainPlotterTemplate): def __init__(self, database, type): super().__init__() self.database = database self.type = type self.apply_button.clicked.connect(self.draw_data) self.setWindowTitle(f'CTD {type} Sensor to Bottle Difference') self.main_plot.set_title('CTD Sensor - Bottle', fontsize=18) self.main_plot.set_xlabel('Deployment / Rosette Position', fontsize=15) self.main_plot.set_ylabel('Difference (CTD Sensor - Bottle)', fontsize=15) self.main_plot.grid(alpha=0.1) self.run_list_label.setText('Select Deployment:') sensor_label = QLabel('Sensor:', self) self.sensor_selector = QComboBox() self.sensor_selector.setFont(QFont('Segoe UI')) self.sensor_selector.addItems(['Salinity', 'Oxygen']) self.sensor_selector.setEditable(True) self.sensor_selector.setEditable(False) #self.sensor_selector.currentTextChanged.connect(self.populate_fields) sensor_number_label = QLabel('# Sensor:') self.sensor_number_selector = QComboBox() self.sensor_number_selector.setFont(QFont('Segoe UI')) self.sensor_number_selector.addItems(['Primary', 'Secondary', 'Both']) self.sensor_number_selector.setEditable(True) self.sensor_number_selector.setEditable(False) self.sensor_selector.setCurrentText(type) self.qvbox_layout.insertWidget(0, sensor_label) self.qvbox_layout.insertWidget(1, self.sensor_selector) self.qvbox_layout.insertWidget(2, sensor_number_label) self.qvbox_layout.insertWidget(3, self.sensor_number_selector) self.populate_fields() self.show() self.canvas.mpl_connect('pick_event', self.on_pick) def populate_fields(self): sensor = self.sensor_selector.currentText() print(sensor) conn = sqlite3.connect(self.database) c = conn.cursor() c.execute('SELECT DISTINCT deployment from %sData' % sensor.lower()) available_deployments = sorted(list(c.fetchall())) conn.close() for dep in available_deployments: self.run_list.addItem(str(dep[0])) def draw_data(self): sensor = self.sensor_selector.currentText() sensor_number = self.sensor_number_selector.currentText() analyte_db_converter = {'Salinity': 'salinity', 'Oxygen': 'oxygenMoles'} ctd_db_converter = {'Salinity': 'salt', 'Oxygen': 'oxygen'} sensor_converter = {'Primary': 1, 'Secondary': 2} selected = self.run_list.selectedItems() selected_deps = [int(item.text()) for item in selected] if selected_deps: # Get data from database for both bottles and CTD conn = sqlite3.connect(self.database) query_placeholder = ', '.join('?' for unused in selected_deps) bottle_data_df = pd.read_sql_query(f'SELECT * FROM %sData WHERE deployment IN ({query_placeholder})' %sensor.lower(), conn, params=selected_deps) ctd_data_df = pd.read_sql_query(f'SELECT deployment, bottleposition, salt1, salt2, oxygen1, oxygen2 ' f'FROM ctdData ' f'WHERE deployment IN ({query_placeholder})', conn, params=selected_deps) self.bottle_deps = list(bottle_data_df['deployment']) self.bottle_rps = list(bottle_data_df['rosettePosition']) # Match up the CTD data to the bottle data, as there will always be less bottle data... matched_ctd_data = pd.DataFrame() for i, dep in enumerate(self.bottle_deps): rp = self.bottle_rps[i] matched = ctd_data_df.loc[(ctd_data_df['deployment'] == dep) & (ctd_data_df['bottleposition'] == rp)] matched_ctd_data = matched_ctd_data.append(matched, ignore_index=True) bottle_data = np.asarray(bottle_data_df[analyte_db_converter[sensor]]) # If both sensors are to be plotted, use the correct data if sensor_number != 'Both': sensor_one = np.asarray(list(matched_ctd_data[str(ctd_db_converter[sensor]) + str(sensor_converter[sensor_number])])) else: sensor_one = np.asarray(list(matched_ctd_data[str(ctd_db_converter[sensor]) + '1'])) sensor_two = np.asarray(list(matched_ctd_data[str(ctd_db_converter[sensor]) + '2'])) difference_two = sensor_two - bottle_data # Plotted the same as in oxygen processing difference_one = sensor_one - bottle_data max_rp = get_max_rp(self.bottle_rps) plottable_dep_rp = [(((dep - 1) * max_rp) + self.bottle_rps[i]) for i, dep in enumerate(self.bottle_deps)] sensor_difference_plot(self.figure, self.main_plot, plottable_dep_rp, difference_one, max_rp) if sensor_number == 'Both': sensor_difference_plot(self.figure, self.main_plot, plottable_dep_rp, difference_two, max_rp) self.main_plot.legend() self.canvas.draw() def on_pick(self, event): if self.sensor_selector.currentText() == 'Salinity': self.base_on_pick(event, self.database, self.bottle_deps, self.bottle_rps, salinity=True) elif self.sensor_selector.currentText() == 'Oxygen': self.base_on_pick(event, self.database, self.bottle_deps, self.bottle_rps, oxygen=True)
class HistoryList(MyTreeView, AcceptFileDragDrop): filter_columns = [ HistoryColumns.STATUS_TEXT, HistoryColumns.DESCRIPTION, HistoryColumns.COIN_VALUE, HistoryColumns.TXID ] def tx_item_from_proxy_row(self, proxy_row): hm_idx = self.model().mapToSource(self.model().index(proxy_row, 0)) return self.hm.transactions.value_from_pos(hm_idx.row()) def should_hide(self, proxy_row): if self.start_timestamp and self.end_timestamp: tx_item = self.tx_item_from_proxy_row(proxy_row) date = tx_item['date'] if date: in_interval = self.start_timestamp <= date <= self.end_timestamp if not in_interval: return True return False def __init__(self, parent, model: HistoryModel): super().__init__(parent, self.create_menu, stretch_column=HistoryColumns.DESCRIPTION) self.hm = model self.proxy = HistorySortModel(self) self.proxy.setSourceModel(model) self.setModel(self.proxy) self.config = parent.config AcceptFileDragDrop.__init__(self, ".txn") self.setSortingEnabled(True) self.start_timestamp = None self.end_timestamp = None self.years = [] self.create_toolbar_buttons() self.wallet = self.parent.wallet # type: Abstract_Wallet self.sortByColumn(HistoryColumns.STATUS_ICON, Qt.AscendingOrder) self.editable_columns |= {HistoryColumns.FIAT_VALUE} self.header().setStretchLastSection(False) for col in HistoryColumns: sm = QHeaderView.Stretch if col == self.stretch_column else QHeaderView.ResizeToContents self.header().setSectionResizeMode(col, sm) def format_date(self, d): return str(datetime.date(d.year, d.month, d.day)) if d else _('None') def on_combo(self, x): s = self.period_combo.itemText(x) x = s == _('Custom') self.start_button.setEnabled(x) self.end_button.setEnabled(x) if s == _('All'): self.start_timestamp = None self.end_timestamp = None self.start_button.setText("-") self.end_button.setText("-") else: try: year = int(s) except: return self.start_timestamp = start_date = datetime.datetime(year, 1, 1) self.end_timestamp = end_date = datetime.datetime(year + 1, 1, 1) self.start_button.setText( _('From') + ' ' + self.format_date(start_date)) self.end_button.setText(_('To') + ' ' + self.format_date(end_date)) self.hide_rows() def create_toolbar_buttons(self): self.period_combo = QComboBox() self.start_button = QPushButton('-') self.start_button.pressed.connect(self.select_start_date) self.start_button.setEnabled(False) self.end_button = QPushButton('-') self.end_button.pressed.connect(self.select_end_date) self.end_button.setEnabled(False) self.period_combo.addItems([_('All'), _('Custom')]) self.period_combo.activated.connect(self.on_combo) def get_toolbar_buttons(self): return self.period_combo, self.start_button, self.end_button def on_hide_toolbar(self): self.start_timestamp = None self.end_timestamp = None self.hide_rows() def save_toolbar_state(self, state, config): config.set_key('show_toolbar_history', state) def select_start_date(self): self.start_timestamp = self.select_date(self.start_button) self.hide_rows() def select_end_date(self): self.end_timestamp = self.select_date(self.end_button) self.hide_rows() def select_date(self, button): d = WindowModalDialog(self, _("Select date")) d.setMinimumSize(600, 150) d.date = None vbox = QVBoxLayout() def on_date(date): d.date = date cal = QCalendarWidget() cal.setGridVisible(True) cal.clicked[QDate].connect(on_date) vbox.addWidget(cal) vbox.addLayout(Buttons(OkButton(d), CancelButton(d))) d.setLayout(vbox) if d.exec_(): if d.date is None: return None date = d.date.toPyDate() button.setText(self.format_date(date)) return datetime.datetime(date.year, date.month, date.day) def show_summary(self): h = self.model().sourceModel().summary if not h: self.parent.show_message(_("Nothing to summarize.")) return start_date = h.get('start_date') end_date = h.get('end_date') format_amount = lambda x: self.parent.format_amount( x.value) + ' ' + self.parent.base_unit() d = WindowModalDialog(self, _("Summary")) d.setMinimumSize(600, 150) vbox = QVBoxLayout() grid = QGridLayout() grid.addWidget(QLabel(_("Start")), 0, 0) grid.addWidget(QLabel(self.format_date(start_date)), 0, 1) grid.addWidget(QLabel(str(h.get('fiat_start_value')) + '/BTC'), 0, 2) grid.addWidget(QLabel(_("Initial balance")), 1, 0) grid.addWidget(QLabel(format_amount(h['start_balance'])), 1, 1) grid.addWidget(QLabel(str(h.get('fiat_start_balance'))), 1, 2) grid.addWidget(QLabel(_("End")), 2, 0) grid.addWidget(QLabel(self.format_date(end_date)), 2, 1) grid.addWidget(QLabel(str(h.get('fiat_end_value')) + '/BTC'), 2, 2) grid.addWidget(QLabel(_("Final balance")), 4, 0) grid.addWidget(QLabel(format_amount(h['end_balance'])), 4, 1) grid.addWidget(QLabel(str(h.get('fiat_end_balance'))), 4, 2) grid.addWidget(QLabel(_("Income")), 5, 0) grid.addWidget(QLabel(format_amount(h.get('incoming'))), 5, 1) grid.addWidget(QLabel(str(h.get('fiat_incoming'))), 5, 2) grid.addWidget(QLabel(_("Expenditures")), 6, 0) grid.addWidget(QLabel(format_amount(h.get('outgoing'))), 6, 1) grid.addWidget(QLabel(str(h.get('fiat_outgoing'))), 6, 2) grid.addWidget(QLabel(_("Capital gains")), 7, 0) grid.addWidget(QLabel(str(h.get('fiat_capital_gains'))), 7, 2) grid.addWidget(QLabel(_("Unrealized gains")), 8, 0) grid.addWidget(QLabel(str(h.get('fiat_unrealized_gains', ''))), 8, 2) vbox.addLayout(grid) vbox.addLayout(Buttons(CloseButton(d))) d.setLayout(vbox) d.exec_() def plot_history_dialog(self): if plot_history is None: self.parent.show_message( _("Can't plot history.") + '\n' + _("Perhaps some dependencies are missing...") + " (matplotlib?)") return try: plt = plot_history(list(self.hm.transactions.values())) plt.show() except NothingToPlotException as e: self.parent.show_message(str(e)) def on_edited(self, index, user_role, text): index = self.model().mapToSource(index) row, column = index.row(), index.column() tx_item = self.hm.transactions.value_from_pos(row) key = tx_item['txid'] if column == HistoryColumns.DESCRIPTION: if self.wallet.set_label(key, text): #changed self.hm.update_label(row) self.parent.update_completions() elif column == HistoryColumns.FIAT_VALUE: self.wallet.set_fiat_value(key, self.parent.fx.ccy, text, self.parent.fx, tx_item['value'].value) value = tx_item['value'].value if value is not None: self.hm.update_fiat(row, index) else: assert False def mouseDoubleClickEvent(self, event: QMouseEvent): idx = self.indexAt(event.pos()) if not idx.isValid(): return tx_item = self.tx_item_from_proxy_row(idx.row()) if self.hm.flags(self.model().mapToSource(idx)) & Qt.ItemIsEditable: super().mouseDoubleClickEvent(event) else: self.show_transaction(tx_item['txid']) def show_transaction(self, tx_hash): tx = self.wallet.db.get_transaction(tx_hash) if not tx: return label = self.wallet.get_label( tx_hash ) or None # prefer 'None' if not defined (force tx dialog to hide Description field if missing) self.parent.show_transaction(tx, label) def create_menu(self, position: QPoint): org_idx: QModelIndex = self.indexAt(position) idx = self.proxy.mapToSource(org_idx) if not idx.isValid(): # can happen e.g. before list is populated for the first time return tx_item = self.hm.transactions.value_from_pos(idx.row()) column = idx.column() if column == HistoryColumns.STATUS_ICON: column_title = _('Transaction ID') column_data = tx_item['txid'] else: column_title = self.hm.headerData(column, Qt.Horizontal, Qt.DisplayRole) column_data = self.hm.data(idx, Qt.DisplayRole).value() tx_hash = tx_item['txid'] tx = self.wallet.db.get_transaction(tx_hash) if not tx: return tx_URL = block_explorer_URL(self.config, 'tx', tx_hash) height = self.wallet.get_tx_height(tx_hash).height is_relevant, is_mine, v, fee = self.wallet.get_wallet_delta(tx) is_unconfirmed = height <= 0 pr_key = self.wallet.invoices.paid.get(tx_hash) menu = QMenu() if height == TX_HEIGHT_LOCAL: menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash)) amount_columns = [ HistoryColumns.COIN_VALUE, HistoryColumns.RUNNING_COIN_BALANCE, HistoryColumns.FIAT_VALUE, HistoryColumns.FIAT_ACQ_PRICE, HistoryColumns.FIAT_CAP_GAINS ] if column in amount_columns: column_data = column_data.strip() menu.addAction( _("Copy {}").format(column_title), lambda: self.parent.app.clipboard().setText(column_data)) for c in self.editable_columns: if self.isColumnHidden(c): continue label = self.hm.headerData(c, Qt.Horizontal, Qt.DisplayRole) # TODO use siblingAtColumn when min Qt version is >=5.11 persistent = QPersistentModelIndex( org_idx.sibling(org_idx.row(), c)) menu.addAction(_("Edit {}").format(label), lambda p=persistent: self.edit(QModelIndex(p))) menu.addAction(_("Details"), lambda: self.show_transaction(tx_hash)) if is_unconfirmed and tx: # note: the current implementation of RBF *needs* the old tx fee rbf = is_mine and not tx.is_final() and fee is not None if rbf: menu.addAction(_("Increase fee"), lambda: self.parent.bump_fee_dialog(tx)) else: child_tx = self.wallet.cpfp(tx, 0) if child_tx: menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp(tx, child_tx)) if pr_key: menu.addAction(read_QIcon("seal"), _("View invoice"), lambda: self.parent.show_invoice(pr_key)) if tx_URL: menu.addAction(_("View on block explorer"), lambda: webbrowser.open(tx_URL)) menu.exec_(self.viewport().mapToGlobal(position)) def remove_local_tx(self, delete_tx): to_delete = {delete_tx} to_delete |= self.wallet.get_depending_transactions(delete_tx) question = _("Are you sure you want to remove this transaction?") if len(to_delete) > 1: question = _( "Are you sure you want to remove this transaction and {} child transactions?" .format(len(to_delete) - 1)) answer = QMessageBox.question(self.parent, _("Please confirm"), question, QMessageBox.Yes, QMessageBox.No) if answer == QMessageBox.No: return for tx in to_delete: self.wallet.remove_transaction(tx) self.wallet.storage.write() # need to update at least: history_list, utxo_list, address_list self.parent.need_update.set() def onFileAdded(self, fn): try: with open(fn) as f: tx = self.parent.tx_from_text(f.read()) self.parent.save_transaction_into_wallet(tx) except IOError as e: self.parent.show_error(e) def export_history_dialog(self): d = WindowModalDialog(self, _('Export History')) d.setMinimumSize(400, 200) vbox = QVBoxLayout(d) defaultname = os.path.expanduser('~/electrum-history.csv') select_msg = _('Select file to export your wallet transactions to') hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg) vbox.addLayout(hbox) vbox.addStretch(1) hbox = Buttons(CancelButton(d), OkButton(d, _('Export'))) vbox.addLayout(hbox) #run_hook('export_history_dialog', self, hbox) self.update() if not d.exec_(): return filename = filename_e.text() if not filename: return try: self.do_export_history(filename, csv_button.isChecked()) except (IOError, os.error) as reason: export_error_label = _( "Electrum was unable to produce a transaction export.") self.parent.show_critical(export_error_label + "\n" + str(reason), title=_("Unable to export history")) return self.parent.show_message( _("Your wallet history has been successfully exported.")) def do_export_history(self, file_name, is_csv): hist = self.wallet.get_full_history(domain=self.hm.get_domain(), from_timestamp=None, to_timestamp=None, fx=self.parent.fx, show_fees=True) txns = hist['transactions'] lines = [] if is_csv: for item in txns: lines.append([ item['txid'], item.get('label', ''), item['confirmations'], item['value'], item.get('fiat_value', ''), item.get('fee', ''), item.get('fiat_fee', ''), item['date'] ]) with open(file_name, "w+", encoding='utf-8') as f: if is_csv: import csv transaction = csv.writer(f, lineterminator='\n') transaction.writerow([ "transaction_hash", "label", "confirmations", "value", "fiat_value", "fee", "fiat_fee", "timestamp" ]) for line in lines: transaction.writerow(line) else: from electrum.util import json_encode f.write(json_encode(txns)) def text_txid_from_coordinate(self, row, col): idx = self.model().mapToSource(self.model().index(row, col)) tx_item = self.hm.transactions.value_from_pos(idx.row()) return self.hm.data(idx, Qt.DisplayRole).value(), tx_item['txid']
class mainWindow(QMainWindow): def __init__(self): super(mainWindow, self).__init__() self.full_filename_dict = {} # { full_filename: group_name } self.group_name_dict = {} #group name dict, not necessary now? self.current_full_filename = None #current selected full filename self.current_hdf5 = None #open( self.current_full_filename, r ) self.current_hdf5_item = None self.current_group_name = None self.current_base_filename = '' #current selected base filename self.current_item_path = '' #current item full path. /io/md/... self.current_item_name = '' #current selected item name md self.legend = None self.values = np.array([]) self.logX_plot = False self.logY_plot = False self.X = None self.guiplot_count = 0 self.testplot_count = 1 self.image_plot_count = 0 self.surface_plot_count = 0 self.plot_type = 'curve' self.colormap_string = 'jet' self.colorscale_string = 'log' self.show_image_data = False self.rot_image_data = False self.attributes_flag = False self.current_selected_HDF = '' self.dataset_type_list = [ 'CFN', 'LiX', 'CHX', ] self.default_dataset_type = 'CFN' self.current_dataset_type = 'CFN' #########################Tobecleaned self.image_data_keys = [ 'avg_img', 'mask', 'pixel_mask', 'roi_mask', 'g12b' ] self.pds_keys = [ 'g2_fit_paras', 'g2b_fit_paras', 'spec_km_pds', 'spec_pds', 'qr_1d_pds' ] ##################### self.PWT = PlotWidget(self) self.MPWT = MATPlotWidget(self) self.initialise_user_interface() self.vstack_sampling = 20 self.vstack_yshift = 10 def initialise_user_interface(self): ''' Initialises the main window. ''' grid = QGridLayout() grid.setSpacing(10) self.grid = grid #self.file_items_list = ht.titledTree('File Tree') self.file_items_list = ht.tree() self.file_items_list_property = {} self.file_items_list.tree.itemClicked.connect(self.item_clicked) #self.file_items_list.tree.itemDoubleClicked.connect(self.item_double_clicked) self.guiplot_grid_fromRow = 5 self.guiplot_grid_fromColumn = 1 self.guiplot_grid_rowSpan = 5 self.guiplot_grid_columnSpan = 8 self.testplot_grid_fromRow = 6 self.testplot_grid_fromColumn = 1 self.testplot_grid_rowSpan = 4 self.testplot_grid_columnSpan = 8 self.plotLibrary = 'matplotlib' self.plot_buttons_array = [] # Make dataset table self.dataset_table = ht.titledTable('Values') # Make attribute table self.attribute_table = ht.titledTable('Attribute') # QTableWidget() self.attribute_table.table.setShowGrid(True) #dataset type to set buttons layout self.dataset_type_obj_string = self.default_dataset_type # Initialise all buttons self.open_button = self.add_open_button() self.remove_button = self.add_remove_button() self.create_button = self.add_create_button() self.dataset_type_box = self.add_dataset_type_box() self.add_all_plot_buttons() self.setX_button = self.add_setX_button() self.resetX_button = self.add_resetX_button() self.setlogX_box = self.add_setlogX_box() self.setlogY_box = self.add_setlogY_box() #self.clr_plot_checkbox = self.add_clr_plot_box() self.clr_plot_button = self.add_clr_plot_button() self.resizeEvent = self.onresize # Add 'extra' window components self.make_menu_bar() self.filename_label = QLabel('H5FileName') ## Add plot window self.guiplot = pg.PlotWidget() ##using pg self.testplot = Figure() self.ax = self.testplot.add_subplot(111) self.canvas = FigureCanvas(self.testplot) self.toolbar = NavigationToolbar(self.canvas, self) self.cbWidget = None #self.guiplot = pg.ImageView() # Add the created layouts and widgets to the window grid.addLayout(self.open_button, 1, 0, 1, 1, QtCore.Qt.AlignLeft) grid.addLayout(self.remove_button, 6, 0, 1, 1, QtCore.Qt.AlignLeft) grid.addLayout(self.create_button, 7, 0, 1, 1, QtCore.Qt.AlignLeft) grid.addLayout(self.dataset_type_box, 1, 0, 1, 1, QtCore.Qt.AlignRight) grid.addLayout(self.clr_plot_button, 1, 4, 1, 1, QtCore.Qt.AlignLeft) grid.addLayout(self.setX_button, 1, 8, 1, 1, QtCore.Qt.AlignLeft) grid.addLayout(self.resetX_button, 2, 8, 1, 1, QtCore.Qt.AlignLeft) grid.addLayout(self.setlogX_box, 1, 7, 1, 1, QtCore.Qt.AlignLeft) grid.addLayout(self.setlogY_box, 2, 7, 1, 1, QtCore.Qt.AlignLeft) grid.addWidget(self.filename_label, 2, 0, 1, 1) #filename list #grid.addLayout(self.file_items_list.layout, 4, 0, 3, 1) grid.addLayout(self.file_items_list.datalayout, 4, 0, 2, 1) #data dataset table grid.addLayout(self.dataset_table.layout, 4, 1, 1, 8) # Add toolbar grid.addWidget(self.toolbar, 5, 1, 1, 7) ## Add guiplot window, it's not the default so hide grid.addWidget(self.guiplot, self.guiplot_grid_fromRow, self.guiplot_grid_fromColumn, self.guiplot_grid_rowSpan, self.guiplot_grid_columnSpan) self.guiplot.setWindowOpacity(0) self.guiplot.hide() grid.addWidget(self.canvas, self.testplot_grid_fromRow, self.testplot_grid_fromColumn, self.testplot_grid_rowSpan, self.testplot_grid_columnSpan) # attribute tabel grid.addLayout(self.attribute_table.layout, 8, 0, 3, 1) #grid.addWidget(self.attribute_table, 7, 0, 2, 1 ) self.dev_cur_layout(plot_type='curve') self.dev_cur_layout(plot_type='image') self.setCentralWidget(QWidget(self)) self.centralWidget().setLayout(grid) # Other tweaks to the window such as icons etc self.setWindowTitle('XSH5View--Ver1') #QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Cleanlooks')) self.initialise_layout( ) #to add different type of layout based on self.dataset_type_obj_string ########Start Deal with layout def initialise_layout(self): if self.dataset_type_obj_string == 'CFN': self.delete_dataset_buttons('CHX') self.dev_dataset_buttons(self.dataset_type_obj_string) elif self.dataset_type_obj_string == 'LIX': self.delete_dataset_buttons('CHX') elif self.dataset_type_obj_string == 'CHX': self.dev_dataset_buttons(self.dataset_type_obj_string) else: pass def dev_cur_layout(self, plot_type): if plot_type in plot_curve_type: self.CurCrossHair = QLabel() self.CurCrossHair.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid.addWidget(self.CurCrossHair, 9, 2, 1, 1) self.CrossHair_type = 'curve' elif plot_type in plot_image_type: self.imageCrossHair = QLabel() self.imageCrossHair.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.grid.addWidget(self.imageCrossHair, 9, 1, 1, 1) self.CrossHair_type = 'image' else: self.CrossHair_type = 'None' def delete_cur_layout(self, plot_type): if plot_type in plot_curve_type: try: self.deleteLayout(self.imageCrossHair) except: pass elif plot_type in plot_image_type: try: self.deleteLayout(self.CurCrossHair) except: pass else: pass def dev_dataset_buttons(self, dataset_type): if dataset_type == 'CHX': self.plot_g2_button = self.add_plot_g2_button() self.plot_c12_button = self.add_plot_c12_button() self.q_box_input = self.add_q_box() self.plot_qiq_button = self.add_plot_qiq_button() self.grid.addLayout(self.plot_g2_button, 2, 1, 1, 1, QtCore.Qt.AlignLeft) self.grid.addLayout(self.plot_c12_button, 2, 2, 1, 1, QtCore.Qt.AlignLeft) self.grid.addLayout(self.plot_qiq_button, 2, 3, 1, 1, QtCore.Qt.AlignLeft) self.grid.addLayout(self.q_box_input, 2, 6, 1, 1, QtCore.Qt.AlignLeft) if dataset_type == 'CFN': self.rot_image_button = self.add_rot_image_button() self.grid.addLayout(self.rot_image_button, 2, 2, 1, 1, QtCore.Qt.AlignLeft) self.stack_plot_button = self.add_stack_plot_button() self.grid.addLayout(self.stack_plot_button, 2, 1, 1, 1, QtCore.Qt.AlignLeft) def add_rot_image_button(self): rot_image_button = QPushButton("rot image") rot_image_button.clicked.connect(self.rot_image) button_section = QHBoxLayout() button_section.addWidget(rot_image_button) return button_section def rot_image(self): #print('here') try: self.value = self.value.T except: pass def delete_dataset_buttons(self, dataset_type): if dataset_type == 'CHX' and self.current_dataset_type == 'CHX': self.deleteLayout(self.plot_g2_button) self.deleteLayout(self.plot_c12_button) self.deleteLayout(self.plot_qiq_button) self.deleteLayout(self.q_box_input) def deleteLayout(self, layout): for i in range(layout.count()): layout.itemAt(i).widget().close() ########End Deal with layout def onresize(self, event): #print('Here for resize') self.file_items_list.tree.setMaximumWidth(int(0.3 * self.width())) #self.dataset_table.table.setMinimumHeight(0.1*self.height()) #self.dataset_table.table.setMaximumWidth( 0.3*self.height() ) self.attribute_table.table.setMaximumWidth(int(0.3 * self.width())) #self.guiplot.setMinimumHeight( 0.6*self.height() ) #self.guiplot.setMinimumHeight( 0.6*self.height() ) def add_open_button(self): ''' Initialises the buttons in the button bar at the top of the main window. ''' open_file_btn = QPushButton('Open') open_file_btn.clicked.connect(self.choose_file) button_section = QHBoxLayout() button_section.addWidget(open_file_btn) #button_section.addStretch(0) return button_section def add_remove_button(self): remove_file_btn = QPushButton('Remove File') remove_file_btn.clicked.connect(self.remove_file) button_section = QHBoxLayout() button_section.addWidget(remove_file_btn) return button_section def add_create_button(self): create_file_btn = QPushButton('Create File') create_file_btn.clicked.connect(self.create_file) button_section = QHBoxLayout() button_section.addWidget(create_file_btn) return button_section def add_dataset_type_box(self): self.dataset_type_obj = QComboBox() self.dataset_type_obj.addItems(self.dataset_type_list) self.dataset_type_obj.currentIndexChanged.connect( self.dataset_type_selection_change) self.dataset_type_obj_string = self.dataset_type_obj.currentText() box_section = QHBoxLayout() box_section.addWidget(self.dataset_type_obj) return box_section def dataset_type_selection_change(self, i): self.dataset_type_obj_string = self.dataset_type_obj.currentText() self.initialise_layout() self.current_dataset_type = self.dataset_type_obj.currentText() #print( self.dataset_type_obj_string , self.dataset_type_obj.currentText() ) def add_all_plot_buttons(self): self.plot_curve_button = self.add_plot_curve_button() self.plot_img_button = self.add_plot_img_button() if self.plotLibrary != 'matplotlib': self.plot_surface_button = self.add_plot_surface_button() self.grid.addLayout(self.plot_surface_button, 1, 3, 1, 1, QtCore.Qt.AlignLeft) else: self.plot_acr_datasets_button = self.add_plot_acr_datasets_button() self.grid.addLayout(self.plot_acr_datasets_button, 2, 3, 1, 1, QtCore.Qt.AlignLeft) self.grid.addLayout(self.plot_curve_button, 1, 1, 1, 1, QtCore.Qt.AlignLeft) self.grid.addLayout(self.plot_img_button, 1, 2, 1, 1, QtCore.Qt.AlignLeft) def add_stack_plot_button(self): return self.add_generic_plot_button(plot_type='plot_stack', button_name='Stack Plot') def add_plot_acr_datasets_button(self): return self.add_generic_plot_button( plot_type='stack_across', button_name='Stack Across Datasets') def add_plot_g2_button(self): return self.add_generic_plot_button(plot_type='g2', button_name='Plot_g2') def add_plot_c12_button(self): return self.add_generic_plot_button(plot_type='C12', button_name='Plot_TwoTime') def add_plot_curve_button(self): return self.add_generic_plot_button(plot_type='curve', button_name='Plot_Curve') def add_plot_qiq_button(self): return self.add_generic_plot_button(plot_type='qiq', button_name='Plot_qiq') def add_plot_img_button(self): return self.add_generic_plot_button(plot_type='image', button_name='Plot_Image') def add_plot_surface_button(self): return self.add_generic_plot_button(plot_type='surface', button_name='Plot_Surface') def add_generic_plot_button(self, plot_type, button_name): plot_btn = QPushButton(button_name) pg_plot_type_dict = { 'curve': self.PWT.plot_curve, 'g2': self.PWT.plot_g2, 'qiq': self.PWT.plot_qiq, 'surface': self.PWT.plot_surface, 'image': self.PWT.plot_image, 'C12': self.PWT.plot_C12, 'plot_stack': self.PWT.plot_stack, } mat_plot_type_dict = { 'curve': self.MPWT.plot_curve, 'g2': self.PWT.plot_g2, 'qiq': self.PWT.plot_qiq, 'surface': self.MPWT.plot_surface, 'image': self.MPWT.plot_image, 'C12': self.PWT.plot_C12, 'plot_stack': self.MPWT.plot_stack, 'stack_across': self.MPWT.plot_across, } if self.plotLibrary == 'pyqtgraph': plot_btn.clicked.connect(pg_plot_type_dict[plot_type]) if self.plotLibrary == 'matplotlib': plot_btn.clicked.connect(mat_plot_type_dict[plot_type]) button_section = QHBoxLayout() button_section.addWidget(plot_btn) self.plot_buttons_array.append(plot_btn) return button_section def add_setlogX_box(self): self.setlogX_box_obj = QCheckBox("logX") self.setlogX_box_obj.stateChanged.connect(self.click_setlogX_box) button_section = QHBoxLayout() button_section.addWidget(self.setlogX_box_obj) return button_section def click_setlogX_box(self, state): if state == QtCore.Qt.Checked: self.logX_plot = True else: self.logX_plot = False try: self.guiplot.setLogMode(x=self.logX_plot, y=self.logY_plot) except: pass def add_setlogY_box(self): self.setlogY_box_obj = QCheckBox("logY") self.setlogY_box_obj.stateChanged.connect(self.click_setlogY_box) button_section = QHBoxLayout() button_section.addWidget(self.setlogY_box_obj) return button_section def click_setlogY_box(self, state): if state == QtCore.Qt.Checked: self.logY_plot = True else: self.logY_plot = False try: self.guiplot.setLogMode(x=self.logX_plot, y=self.logY_plot) except: pass def get_dict_from_qval_dict(self): l = list(self.current_hdf5['qval_dict'].attrs.items()) dc = {int(i[0]): i[1] for i in l} return dc def add_setX_button(self): self.setX_btn = QPushButton('SetX') self.setX_btn.clicked.connect(self.setX) button_section = QHBoxLayout() button_section.addWidget(self.setX_btn) return button_section def add_resetX_button(self): self.resetX_btn = QPushButton('ReSetX') self.resetX_btn.clicked.connect(self.resetX) button_section = QHBoxLayout() button_section.addWidget(self.resetX_btn) return button_section def add_clr_plot_button(self): self.clr_plot_button = QPushButton("clear plot") self.clr_plot_button.clicked.connect(self.plot_clear) button_section = QHBoxLayout() button_section.addWidget(self.clr_plot_button) return button_section def plot_clear(self): if self.plotLibrary == 'matplotlib': if self.plot_type in plot_curve_type or self.plot_type in plot_image_type: if self.plot_type in plot_image_type: self.grid.removeWidget(self.MPWT.cb) self.MPWT.cb.setWindowOpacity(0) self.MPWT.cb.hide() self.ax.clear() self.canvas.draw() self.canvas.hide() self.canvas.show() self.testplot_count = 0 elif self.plotLibrary == 'pyqtgraph': self.guiplot.clear() #self.surface_plot_count = 0 #self.grid.removeWidget(self.testplot) #self.guiplot.setWindowOpacity(0) #self.guiplot.hide() try: self.legend.scene().removeItem(self.legend) except: pass def add_q_box(self): # Create textbox self.q_box = QLineEdit( placeholderText="Please enter q-number (int) of two-time function." ) button_section = QHBoxLayout() button_section.addWidget(self.q_box) return button_section def make_menu_bar(self): ''' Initialises the menu bar at the top. ''' menubar = self.menuBar() # Create a File menu and add an open button self.file_menu = menubar.addMenu('&File') open_action = QtGui.QAction('&Open', self) open_action.setShortcut('Ctrl+o') open_action.triggered.connect(self.choose_file) self.file_menu.addAction(open_action) # Add a shortcut to copy and paste data copy_data_action = QtGui.QAction('&Copy Data', self) copy_data_action.setShortcut('Ctrl+c') copy_data_action.triggered.connect(self.copy_data) self.file_menu.addAction(copy_data_action) paste_data_action = QtGui.QAction('&Paste Data', self) paste_data_action.setShortcut('Ctrl+v') paste_data_action.triggered.connect(self.paste_data) self.file_menu.addAction(paste_data_action) new_key_action = QtGui.QAction('&Add New Key', self) new_key_action.setShortcut('Ctrl+n') new_key_action.triggered.connect(self.create_key) self.file_menu.addAction(new_key_action) # Add an exit button to the file menu exit_action = QtGui.QAction('&Exit', self) exit_action.setShortcut('Ctrl+Z') exit_action.setStatusTip('Exit application') exit_action.triggered.connect(QtGui.qApp.quit) self.file_menu.addAction(exit_action) ## Create a view manu self.view_menu = menubar.addMenu('&View') #self.view_menu.setShortcut('Alt+v') self.plot_type_options_menu = self.view_menu.addMenu('&Plot Library') group = QActionGroup(self.plot_type_options_menu) texts = ["matplotlib", "pyqtgraph"] for text in texts: action = QAction(text, self.plot_type_options_menu, checkable=True, checked=text == texts[0]) self.plot_type_options_menu.addAction(action) group.addAction(action) group.setExclusive(True) group.triggered.connect(self.onTriggered_plotLibrary) self.image_plot_options_menu = self.view_menu.addMenu( '&Image Plot Options') self.colormap_options_menu = self.image_plot_options_menu.addMenu( '&Colormap') group = QActionGroup(self.colormap_options_menu) texts = image_colors for text in texts: action = QAction(text, self.colormap_options_menu, checkable=True, checked=text == texts[0]) self.colormap_options_menu.addAction(action) group.addAction(action) group.setExclusive(True) group.triggered.connect(self.onTriggered_colormap) self.colorscale_options_menu = self.image_plot_options_menu.addMenu( '&ColorScale') group = QActionGroup(self.colorscale_options_menu) texts = ["linear", "log"] for text in texts: action = QAction(text, self.colormap_options_menu, checkable=True, checked=text == texts[1]) self.colorscale_options_menu.addAction(action) group.addAction(action) group.setExclusive(True) group.triggered.connect(self.onTriggered_colorscale) self.display_image_data_options_menu = self.view_menu.addMenu( '&Display Image Data') show_image_data_action = QAction('show data', self, checkable=True, checked=False) show_image_data_action.triggered.connect( self.onTriggered_show_image_data) self.display_image_data_options_menu.addAction(show_image_data_action) self.stack_plot_options_menu = self.view_menu.addMenu( '&Stack Plot Options') set_stack_action = QtGui.QAction('Sampling and yshift', self) set_stack_action.triggered.connect(self.onTriggered_set_stack) self.stack_plot_options_menu.addAction(set_stack_action) # Create a Help menu and add an about button help_menu = menubar.addMenu('&Help') about_action = QtGui.QAction('About XSH5FView', self) about_action.setStatusTip('About this program') about_action.triggered.connect(self.show_about_menu) help_menu.addAction(about_action) def onTriggered_set_stack(self, action): print('set stack opt here.') i, okPressed = QInputDialog.getInt(self, "Set Sampling Number", "sampling:", self.vstack_sampling, 0, 10000, 10) if okPressed: self.vstack_sampling = i print(i) d, okPressed = QInputDialog.getDouble(self, "Set yshift", "Value:", self.vstack_yshift, 0, 1e8, 2) if okPressed: self.vstack_yshift = d print(d) def onTriggered_show_image_data(self, action): #print(action.text()) self.show_image_data = action #.text() def onTriggered_colormap(self, action): #print(action.text()) self.colormap_string = action.text() def onTriggered_colorscale(self, action): #print(action.text()) self.colorscale_string = action.text() def onTriggered_plotLibrary(self, action): self.plotLibrary = action.text() for i in range(len(self.plot_buttons_array)): button_to_remove = self.plot_buttons_array.pop() self.grid.removeWidget(button_to_remove) button_to_remove.setWindowOpacity(0) button_to_remove.hide() if action.text() == 'matplotlib': self.toolbar.setWindowOpacity(100) self.toolbar.show() self.canvas.setWindowOpacity(100) self.canvas.show() else: self.toolbar.setWindowOpacity(0) self.toolbar.hide() self.canvas.setWindowOpacity(0) self.canvas.hide() if action.text() == 'pyqtgraph': self.guiplot.setWindowOpacity(100) self.guiplot.show() else: self.guiplot.setWindowOpacity(0) self.guiplot.hide() self.add_all_plot_buttons() self.initialise_layout() def show_about_menu(self): ''' Shows the about menu by initialising an about_window object. This class is described in _window_classes.py ''' self.about_window = ht.aboutWindow() self.about_window.show() def choose_file(self): ''' Opens a QFileDialog window to allow the user to choose the hdf5 file they would like to view. ''' filenames_list = QtGui.QFileDialog.getOpenFileNames( self, 'Open file', '/home/yugang/Desktop/XPCS_GUI/TestData/test.h5', filter='*.hdf5 *.h5 *.lst')[0] for f in filenames_list: ext = f.split('/')[-1].split('.')[-1] if ext == 'lst': full_filename_list = np.loadtxt( f, dtype=object, ) group_name = f.split('/')[-1] if group_name not in list(self.group_name_dict.keys()): self.group_name_dict[group_name] = full_filename_list for fp in full_filename_list: self.initiate_file_open(fp, group_name=group_name) else: self.initiate_file_open(f) def initiate_file_open(self, full_filename, group_name=None): base_filename = full_filename.split('/')[-1] self.full_filename_dict[full_filename] = group_name self.dataset_table.clear() self.attribute_table.clear() try: self.file_items_list.add_file(full_filename, group_name) if group_name is None: self.filename_label.setText(base_filename) else: self.filename_label.setText(group_name) self.setWindowTitle('XSH5View@CHX - ' + base_filename) except: self.filename = '' # if it didn't work keep the old value self.filename_label.setText('') self.setWindowTitle('XSH5View@CHX') self.clear_file_items() self.dataset_table.clear() self.attribute_table.clear() print("Error opening file") def create_file(self): filename = self.file_items_list.create_file() self.initiate_file_open(filename) def remove_file(self, filename): self.file_items_list.remove_file() def clear_file_items(self): self.file_items_list.clear() def copy_data(self): self.file_items_list.copy_data() def paste_data(self): destination = self.file_items_list.tree.currentItem().text(1) item_path = self.file_items_list.tree.currentItem().text(2) #self.file_items_list.remove_file() self.file_items_list.paste_data(destination, item_path, self) #self.initiate_file_open(destination) def create_key(self): item = self.file_items_list.tree.currentItem() self.file_items_list.create_key(item.text(1), item.text(2), self) def get_selected_row_col(self): selected_items = self.dataset_table.table.selectedItems() shape = np.shape(self.value) Ns = len(shape) if len(selected_items) > 0: min_row = selected_items[0].row() max_row = selected_items[-1].row() + 1 min_col = selected_items[0].column() max_col = selected_items[-1].column() + 1 self.selected_flag = True else: if len(shape) == 1: max_col = 1 else: max_col = shape[1] min_row = 0 max_row = shape[0] min_col = 0 self.selected_flag = False self.min_row, self.max_row, self.min_col, self.max_col = min_row, max_row, min_col, max_col def setX(self): self.get_selected_row_col() min_row, max_row, min_col, max_col = self.min_row, self.max_row, self.min_col, self.max_col if self.selected_flag: try: self.X = self.value[min_row:max_row, min_col] except: self.X = self.value[min_row:max_row] def resetX(self): self.X = None def get_filename_selected(self): self.dataset_table.clear() self.item = self.file_items_list.tree.currentItem() self.current_full_filename = self.item.text(1) self.current_group_name = self.full_filename_dict[ self.current_full_filename] #print("in get filename selected:", self.current_full_filename) self.current_hdf5 = h5py.File(self.current_full_filename, 'r') self.current_base_filename = self.current_full_filename.split('/')[-1] self.current_item_path = self.item.text(2) if self.current_item_path == '': self.current_hdf5_item = self.current_hdf5 self.current_item_name = self.item.text(2) else: self.current_hdf5_item = self.current_hdf5[self.current_item_path] self.current_item_name = self.item.text(2).split('/')[-1] def display_dataset(self): self.get_filename_selected() text = self.current_item_path #self.item.text(2) if self.current_item_path != '': hdf5_file = self.current_hdf5_item if isinstance(hdf5_file, h5py.Dataset): #print( 'shows dataset-------------->') self.group_data = False #self.current_dataset = self.item_path.split('/')[-1] shape = hdf5_file.shape Ns = len(shape) if Ns == 0: try: self.value = bstring_to_string(hdf5_file) #[0] except: self.value = np.array([hdf5_file]) #[0] numrows = 1 numcols = 1 elif Ns == 1: numrows = shape[0] numcols = 1 self.value = hdf5_file[:] elif Ns == 2: numrows = shape[0] numcols = shape[1] self.value = hdf5_file[:] elif Ns >= 3: #a 3D array, [x,y,z], show [x,y ] if self.current_dataset_type == 'CHX': numrows = shape[0] numcols = shape[1] try: self.value = hdf5_file[:, :, self.qth] except: print('The max q-th is %s.' % shape[2]) self.value = hdf5_file[text][:, :, 0] else: numrows = shape[-2] numcols = shape[-1] try: self.value = hdf5_file[self.qth, :, :] except: print('The max q-th is %s.' % shape[0]) elif isinstance(hdf5_file, h5py.Group): print('display the group data here') if text in self.pds_keys: d = pds.read_hdf(self.filename, key=text) #[:] self.value = np.array(d) shape = self.value.shape numrows = shape[0] numcols = shape[1] Ns = len(shape) self.group_data_label = np.array(d.columns)[:] self.group_data = True else: self.dataset_table.clear() self.value = np.array([]) self.plot_btn.hide() else: print('Other format!') try: self.dataset_table.table.setRowCount(numrows) self.dataset_table.table.setColumnCount(numcols) show_data_flag = True if not self.show_image_data: if text in self.image_data_keys: self.dataset_table.clear() show_data_flag = False try: if self.value.shape[0] > 100 and self.value.shape[ 1] > 100: show_data_flag = False except: pass if show_data_flag: if Ns != -1: for i in range(numrows): if numcols > 1: for j in range(numcols): self.dataset_table.set_item( i, j, str(self.value[i, j])) else: self.dataset_table.set_item( i, 0, str(self.value[i])) #print( self.attributes_flag ) if not self.attributes_flag: self.attribute_table.clear() self.attribute_table.table.setRowCount(1) self.attribute_table.table.setColumnCount(Ns + 1) self.attribute_table.table.setItem( 0, 0, QTableWidgetItem('shape')) for i, s in enumerate(shape): self.attribute_table.table.setItem( 0, i + 1, QTableWidgetItem('%s' % s)) except: pass self.current_hdf5.close() def display_attributes(self): # reset the value self.attribute_table.clear() self.get_filename_selected() if self.current_item_path != '': #print('Here shows the attributes') hdf5_file = self.current_hdf5_item try: attributes = list(hdf5_file.attrs.items()) num_attributes = len(attributes) self.attribute_table.table.setRowCount(num_attributes) self.attribute_table.table.setColumnCount(0) except: num_attributes = 0 if num_attributes > 0: self.attribute_table.table.setColumnCount(2) self.attributes_flag = True else: self.attributes_flag = False print(num_attributes, self.attributes_flag) # Populate the table for i in range(num_attributes): value = attributes[i][1] self.attribute_table.table.setItem( i, 0, QTableWidgetItem(attributes[i][0])) if isinstance(value, np.ndarray): N = len(value) self.attribute_table.table.setColumnCount(N + 1) j = 1 for v in value: self.attribute_table.table.setItem( i, j, QTableWidgetItem(str(v))) #self.attribute_table.setItem(i, 1, QTableWidgetItem(str(value[0].decode()))) j += 1 else: self.attribute_table.table.setItem( i, 1, QTableWidgetItem(str(value))) self.current_hdf5.close() def item_double_clicked(self): ''' Responds to a double click on an item in the file_items_list.''' #self.display_attributes() try: self.display_attributes() #print('display attributes') except: pass def item_clicked(self): ############# #self.display_dataset() #################3 try: self.qth = int(self.q_box.text()) except: self.qth = 0 try: self.display_attributes() #print('display attributes') except: pass try: self.display_dataset() except: pass try: self.filename_label.setText(self.current_base_filename) self.setWindowTitle('XSH5View@CHX - ' + self.current_full_filename) except: pass
class MIDISettings(SettingsPage): Name = QT_TRANSLATE_NOOP('SettingsPageName', 'MIDI settings') def __init__(self, **kwargs): super().__init__(**kwargs) self.setLayout(QVBoxLayout()) self.layout().setAlignment(Qt.AlignTop) self.midiGroup = QGroupBox(self) self.midiGroup.setTitle( translate('MIDISettings', 'MIDI default devices')) self.midiGroup.setLayout(QGridLayout()) self.layout().addWidget(self.midiGroup) self.inputLabel = QLabel(translate('MIDISettings', 'Input'), self.midiGroup) self.midiGroup.layout().addWidget(self.inputLabel, 0, 0) self.inputCombo = QComboBox(self.midiGroup) self.midiGroup.layout().addWidget(self.inputCombo, 0, 1) self.outputLabel = QLabel(translate('MIDISettings', 'Output'), self.midiGroup) self.midiGroup.layout().addWidget(self.outputLabel, 1, 0) self.outputCombo = QComboBox(self.midiGroup) self.midiGroup.layout().addWidget(self.outputCombo, 1, 1) self.midiGroup.layout().setColumnStretch(0, 2) self.midiGroup.layout().setColumnStretch(1, 3) if check_module('Midi'): self._load_devices() else: self.setEnabled(False) def get_settings(self): conf = {} if self.isEnabled(): conf['inputdevice'] = self.inputCombo.currentText() MIDIInput().change_port(conf['inputdevice']) if self.isEnabled(): conf['outputdevice'] = self.outputCombo.currentText() MIDIOutput().change_port(conf['outputdevice']) return {'MIDI': conf} def load_settings(self, settings): if 'inputdevice' in settings['MIDI']: self.inputCombo.setCurrentText('AppDefault') self.inputCombo.setCurrentText(settings['MIDI']['inputdevice']) if 'outputdevice' in settings['MIDI']: self.outputCombo.setCurrentText('AppDefaut') self.outputCombo.setCurrentText(settings['MIDI']['outputdevice']) def _load_devices(self): backend = mido_backend() self.inputCombo.clear() self.inputCombo.addItems(['AppDefault', 'SysDefault']) self.inputCombo.addItems(backend.get_input_names()) self.outputCombo.clear() self.outputCombo.addItems(['AppDefault', 'SysDefault']) self.outputCombo.addItems(backend.get_output_names())
def createEditor(self, parent, option, index): editor = QComboBox(parent) editor.addItems(self.options) editor.currentIndexChanged.connect(self.currentItemChanged) return editor
class GalleryDialog(QWidget): """ A window for adding/modifying gallery. Pass a list of QModelIndexes to edit their data or pass a path to preset path """ gallery_queue = queue.Queue() SERIES = pyqtSignal(list) SERIES_EDIT = pyqtSignal(list, int) #gallery_list = [] # might want to extend this to allow mass gallery adding def __init__(self, parent=None, arg=None): super().__init__(parent, Qt.Dialog) self.setAttribute(Qt.WA_DeleteOnClose) self.parent_widget = parent log_d('Triggered Gallery Edit/Add Dialog') m_l = QVBoxLayout() self.main_layout = QVBoxLayout() dummy = QWidget(self) scroll_area = QScrollArea(self) scroll_area.setWidgetResizable(True) scroll_area.setFrameStyle(scroll_area.StyledPanel) dummy.setLayout(self.main_layout) scroll_area.setWidget(dummy) m_l.addWidget(scroll_area, 3) final_buttons = QHBoxLayout() final_buttons.setAlignment(Qt.AlignRight) m_l.addLayout(final_buttons) self.done = QPushButton("Done") self.done.setDefault(True) cancel = QPushButton("Cancel") final_buttons.addWidget(cancel) final_buttons.addWidget(self.done) def new_gallery(): self.setWindowTitle('Add a new gallery') self.newUI() self.commonUI() self.done.clicked.connect(self.accept) cancel.clicked.connect(self.reject) if arg: if isinstance(arg, list): self.setWindowTitle('Edit gallery') self.position = arg[0].row() for index in arg: gallery = index.data(Qt.UserRole + 1) self.commonUI() self.setGallery(gallery) self.done.clicked.connect(self.accept_edit) cancel.clicked.connect(self.reject_edit) elif isinstance(arg, str): new_gallery() self.choose_dir(arg) else: new_gallery() log_d('GalleryDialog: Create UI: successful') #TODO: Implement a way to mass add galleries #IDEA: Extend dialog in a ScrollArea with more forms... self.setLayout(m_l) self.resize(500, 560) frect = self.frameGeometry() frect.moveCenter(QDesktopWidget().availableGeometry().center()) self.move(frect.topLeft()) #self.setAttribute(Qt.WA_DeleteOnClose) def commonUI(self): f_web = QGroupBox("Metadata from the Web") f_web.setCheckable(False) self.main_layout.addWidget(f_web) web_main_layout = QVBoxLayout() web_layout = QHBoxLayout() web_main_layout.addLayout(web_layout) f_web.setLayout(web_main_layout) f_gallery = QGroupBox("Gallery Info") f_gallery.setCheckable(False) self.main_layout.addWidget(f_gallery) gallery_layout = QFormLayout() f_gallery.setLayout(gallery_layout) def basic_web(name): return QLabel(name), QLineEdit(), QPushButton( "Get metadata"), QProgressBar() url_lbl, self.url_edit, url_btn, url_prog = basic_web("URL:") url_btn.clicked.connect( lambda: self.web_metadata(self.url_edit.text(), url_btn, url_prog)) url_prog.setTextVisible(False) url_prog.setMinimum(0) url_prog.setMaximum(0) web_layout.addWidget(url_lbl, 0, Qt.AlignLeft) web_layout.addWidget(self.url_edit, 0) web_layout.addWidget(url_btn, 0, Qt.AlignRight) web_layout.addWidget(url_prog, 0, Qt.AlignRight) self.url_edit.setPlaceholderText( "Paste g.e-hentai/exhentai gallery url or just press the button.") url_prog.hide() self.title_edit = QLineEdit() self.author_edit = QLineEdit() author_completer = misc.GCompleter(self, False, True, False) author_completer.setCaseSensitivity(Qt.CaseInsensitive) self.author_edit.setCompleter(author_completer) self.descr_edit = QTextEdit() self.descr_edit.setFixedHeight(45) self.descr_edit.setAcceptRichText(True) self.lang_box = QComboBox() self.lang_box.addItems(["English", "Japanese", "Other"]) self.lang_box.setCurrentIndex(0) tags_l = QVBoxLayout() tag_info = misc.ClickedLabel( "How do i write namespace & tags? (hover)", parent=self) tag_info.setToolTip( "Ways to write tags:\n\nNormal tags:\ntag1, tag2, tag3\n\n" + "Namespaced tags:\nns1:tag1, ns1:tag2\n\nNamespaced tags with one or more" + " tags under same namespace:\nns1:[tag1, tag2, tag3], ns2:[tag1, tag2]\n\n" + "Those three ways of writing namespace & tags can be combined freely.\n" + "Tags are seperated by a comma, NOT whitespace.\nNamespaces will be capitalized while tags" + " will be lowercased.") tag_info.setToolTipDuration(99999999) tags_l.addWidget(tag_info) self.tags_edit = misc.CompleterTextEdit() self.tags_edit.setCompleter(misc.GCompleter(self, False, False)) tags_l.addWidget(self.tags_edit, 3) self.tags_edit.setFixedHeight(70) self.tags_edit.setPlaceholderText( "Press Tab to autocomplete (Ctrl + E to show popup)") self.type_box = QComboBox() self.type_box.addItems([ "Manga", "Doujinshi", "Artist CG Sets", "Game CG Sets", "Western", "Image Sets", "Non-H", "Cosplay", "Other" ]) self.type_box.setCurrentIndex(0) #self.type_box.currentIndexChanged[int].connect(self.doujin_show) #self.doujin_parent = QLineEdit() #self.doujin_parent.setVisible(False) self.status_box = QComboBox() self.status_box.addItems(["Unknown", "Ongoing", "Completed"]) self.status_box.setCurrentIndex(0) self.pub_edit = QDateEdit() self.pub_edit.setCalendarPopup(True) self.pub_edit.setDate(QDate.currentDate()) self.path_lbl = QLabel("") self.path_lbl.setWordWrap(True) link_layout = QHBoxLayout() self.link_lbl = QLabel("") self.link_lbl.setWordWrap(True) self.link_edit = QLineEdit() link_layout.addWidget(self.link_edit) link_layout.addWidget(self.link_lbl) self.link_edit.hide() self.link_btn = QPushButton("Modify") self.link_btn.setFixedWidth(50) self.link_btn2 = QPushButton("Set") self.link_btn2.setFixedWidth(40) self.link_btn.clicked.connect(self.link_modify) self.link_btn2.clicked.connect(self.link_set) link_layout.addWidget(self.link_btn) link_layout.addWidget(self.link_btn2) self.link_btn2.hide() gallery_layout.addRow("Title:", self.title_edit) gallery_layout.addRow("Author:", self.author_edit) gallery_layout.addRow("Description:", self.descr_edit) gallery_layout.addRow("Language:", self.lang_box) gallery_layout.addRow("Tags:", tags_l) gallery_layout.addRow("Type:", self.type_box) gallery_layout.addRow("Status:", self.status_box) gallery_layout.addRow("Publication Date:", self.pub_edit) gallery_layout.addRow("Path:", self.path_lbl) gallery_layout.addRow("Link:", link_layout) self.title_edit.setFocus() def _find_combobox_match(self, combobox, key, default): f_index = combobox.findText(key, Qt.MatchFixedString) try: combobox.setCurrentIndex(f_index) except: combobox.setCurrentIndex(default) def setGallery(self, gallery): "To be used for when editing a gallery" self.gallery = gallery self.url_edit.setText(gallery.link) self.title_edit.setText(gallery.title) self.author_edit.setText(gallery.artist) self.descr_edit.setText(gallery.info) self.tags_edit.setText(utils.tag_to_string(gallery.tags)) self._find_combobox_match(self.lang_box, gallery.language, 2) self._find_combobox_match(self.type_box, gallery.type, 0) self._find_combobox_match(self.status_box, gallery.status, 0) gallery_pub_date = "{}".format(gallery.pub_date).split(' ') try: self.gallery_time = datetime.strptime(gallery_pub_date[1], '%H:%M:%S').time() except IndexError: pass qdate_pub_date = QDate.fromString(gallery_pub_date[0], "yyyy-MM-dd") self.pub_edit.setDate(qdate_pub_date) self.link_lbl.setText(gallery.link) self.path_lbl.setText(gallery.path) def newUI(self): f_local = QGroupBox("Directory/Archive") f_local.setCheckable(False) self.main_layout.addWidget(f_local) local_layout = QHBoxLayout() f_local.setLayout(local_layout) choose_folder = QPushButton("From Directory") choose_folder.clicked.connect(lambda: self.choose_dir('f')) local_layout.addWidget(choose_folder) choose_archive = QPushButton("From Archive") choose_archive.clicked.connect(lambda: self.choose_dir('a')) local_layout.addWidget(choose_archive) self.file_exists_lbl = QLabel() local_layout.addWidget(self.file_exists_lbl) self.file_exists_lbl.hide() def choose_dir(self, mode): """ Pass which mode to open the folder explorer in: 'f': directory 'a': files Or pass a predefined path """ self.done.show() self.file_exists_lbl.hide() if mode == 'a': name = QFileDialog.getOpenFileName(self, 'Choose archive', filter=utils.FILE_FILTER) name = name[0] elif mode == 'f': name = QFileDialog.getExistingDirectory(self, 'Choose folder') elif mode: if os.path.exists(mode): name = mode else: return None if not name: return head, tail = os.path.split(name) name = os.path.join(head, tail) parsed = utils.title_parser(tail) self.title_edit.setText(parsed['title']) self.author_edit.setText(parsed['artist']) self.path_lbl.setText(name) l_i = self.lang_box.findText(parsed['language']) if l_i != -1: self.lang_box.setCurrentIndex(l_i) if gallerydb.GalleryDB.check_exists(name): self.file_exists_lbl.setText( '<font color="red">Gallery already exists.</font>') self.file_exists_lbl.show() # check galleries gs = 1 if name.endswith(utils.ARCHIVE_FILES): gs = len(utils.check_archive(name)) elif os.path.isdir(name): g_dirs, g_archs = utils.recursive_gallery_check(name) gs = len(g_dirs) + len(g_archs) if gs == 0: self.file_exists_lbl.setText( '<font color="red">Invalid gallery source.</font>') self.file_exists_lbl.show() self.done.hide() if app_constants.SUBFOLDER_AS_GALLERY: if gs > 1: self.file_exists_lbl.setText( '<font color="red">More than one galleries detected in source! Use other methods to add.</font>' ) self.file_exists_lbl.show() self.done.hide() def check(self): if len(self.title_edit.text()) is 0: self.title_edit.setFocus() self.title_edit.setStyleSheet( "border-style:outset;border-width:2px;border-color:red;") return False elif len(self.author_edit.text()) is 0: self.author_edit.setText("Unknown") if len(self.path_lbl.text()) == 0 or self.path_lbl.text( ) == 'No path specified': self.path_lbl.setStyleSheet("color:red") self.path_lbl.setText('No path specified') return False return True def set_chapters(self, gallery_object, add_to_model=True): path = gallery_object.path chap_container = gallerydb.ChaptersContainer(gallery_object) metafile = utils.GMetafile() try: log_d('Listing dir...') con = scandir.scandir(path) # list all folders in gallery dir log_i('Gallery source is a directory') log_d('Sorting') chapters = sorted([ sub.path for sub in con if sub.is_dir() or sub.name.endswith(utils.ARCHIVE_FILES) ]) #subfolders # if gallery has chapters divided into sub folders if len(chapters) != 0: log_d('Chapters divided in folders..') for ch in chapters: chap = chap_container.create_chapter() chap.title = utils.title_parser(ch)['title'] chap.path = os.path.join(path, ch) metafile.update(utils.GMetafile(chap.path)) chap.pages = len(list(scandir.scandir(chap.path))) else: #else assume that all images are in gallery folder chap = chap_container.create_chapter() chap.title = utils.title_parser( os.path.split(path)[1])['title'] chap.path = path metafile.update(utils.GMetafile(path)) chap.pages = len(list(scandir.scandir(path))) except NotADirectoryError: if path.endswith(utils.ARCHIVE_FILES): gallery_object.is_archive = 1 log_i("Gallery source is an archive") archive_g = sorted(utils.check_archive(path)) for g in archive_g: chap = chap_container.create_chapter() chap.path = g chap.in_archive = 1 metafile.update(utils.GMetafile(g, path)) arch = utils.ArchiveFile(path) chap.pages = len(arch.dir_contents(g)) arch.close() metafile.apply_gallery(gallery_object) if add_to_model: self.SERIES.emit([gallery_object]) log_d('Sent gallery to model') def reject(self): if self.check(): msgbox = QMessageBox() msgbox.setText( "<font color='red'><b>Noo oniichan! You were about to add a new gallery.</b></font>" ) msgbox.setInformativeText("Do you really want to discard?") msgbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msgbox.setDefaultButton(QMessageBox.No) if msgbox.exec() == QMessageBox.Yes: self.close() else: self.close() def web_metadata(self, url, btn_widget, pgr_widget): self.link_lbl.setText(url) f = fetch.Fetch() thread = QThread(self) thread.setObjectName('Gallerydialog web metadata') btn_widget.hide() pgr_widget.show() def status(stat): def do_hide(): try: pgr_widget.hide() btn_widget.show() except RuntimeError: pass if stat: do_hide() else: danger = """QProgressBar::chunk { background: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0,stop: 0 #FF0350,stop: 0.4999 #FF0020,stop: 0.5 #FF0019,stop: 1 #FF0000 ); border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; border: .px solid black;}""" pgr_widget.setStyleSheet(danger) QTimer.singleShot(3000, do_hide) f.deleteLater() def gallery_picker(gallery, title_url_list, q): self.parent_widget._web_metadata_picker(gallery, title_url_list, q, self) try: dummy_gallery = self.make_gallery(self.gallery) except AttributeError: dummy_gallery = self.make_gallery(gallerydb.Gallery(), False) if not dummy_gallery: status(False) return None dummy_gallery.link = url f.galleries = [dummy_gallery] f.moveToThread(thread) f.GALLERY_PICKER.connect(gallery_picker) f.GALLERY_EMITTER.connect(self.set_web_metadata) thread.started.connect(f.auto_web_metadata) thread.finished.connect(thread.deleteLater) f.FINISHED.connect(status) thread.start() def set_web_metadata(self, metadata): assert isinstance(metadata, gallerydb.Gallery) self.link_lbl.setText(metadata.link) self.title_edit.setText(metadata.title) self.author_edit.setText(metadata.artist) tags = "" lang = ['English', 'Japanese'] self._find_combobox_match(self.lang_box, metadata.language, 2) self.tags_edit.setText(utils.tag_to_string(metadata.tags)) pub_string = "{}".format(metadata.pub_date) pub_date = QDate.fromString(pub_string.split()[0], "yyyy-MM-dd") self.pub_edit.setDate(pub_date) self._find_combobox_match(self.type_box, metadata.type, 0) def make_gallery(self, new_gallery, add_to_model=True, new=False): if self.check(): new_gallery.title = self.title_edit.text() log_d('Adding gallery title') new_gallery.artist = self.author_edit.text() log_d('Adding gallery artist') log_d('Adding gallery path') if new and app_constants.MOVE_IMPORTED_GALLERIES: app_constants.OVERRIDE_MONITOR = True new_gallery.path = utils.move_files(self.path_lbl.text()) else: new_gallery.path = self.path_lbl.text() new_gallery.info = self.descr_edit.toPlainText() log_d('Adding gallery descr') new_gallery.type = self.type_box.currentText() log_d('Adding gallery type') new_gallery.language = self.lang_box.currentText() log_d('Adding gallery lang') new_gallery.status = self.status_box.currentText() log_d('Adding gallery status') new_gallery.tags = utils.tag_to_dict(self.tags_edit.toPlainText()) log_d('Adding gallery: tagging to dict') qpub_d = self.pub_edit.date().toString("ddMMyyyy") dpub_d = datetime.strptime(qpub_d, "%d%m%Y").date() try: d_t = self.gallery_time except AttributeError: d_t = datetime.now().time().replace(microsecond=0) dpub_d = datetime.combine(dpub_d, d_t) new_gallery.pub_date = dpub_d log_d('Adding gallery pub date') new_gallery.link = self.link_lbl.text() log_d('Adding gallery link') if not new_gallery.chapters: log_d('Starting chapters') thread = threading.Thread(target=self.set_chapters, args=(new_gallery, add_to_model), daemon=True) thread.start() thread.join() log_d('Finished chapters') return new_gallery def link_set(self): t = self.link_edit.text() self.link_edit.hide() self.link_lbl.show() self.link_lbl.setText(t) self.link_btn2.hide() self.link_btn.show() def link_modify(self): t = self.link_lbl.text() self.link_lbl.hide() self.link_edit.show() self.link_edit.setText(t) self.link_btn.hide() self.link_btn2.show() def accept(self): new_gallery = self.make_gallery(gallerydb.Gallery(), new=True) if new_gallery: self.close() def accept_edit(self): new_gallery = self.make_gallery(self.gallery) #for ser in self.gallery: if new_gallery: self.SERIES_EDIT.emit([new_gallery], self.position) self.close() def reject_edit(self): self.close()
class MainGUI(QWidget): waveforms_generated = pyqtSignal(object, object, list, int) #%% def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) os.chdir('./') # Set directory to current folder. self.setFont(QFont("Arial")) # self.setMinimumSize(900, 1020) self.setWindowTitle("Screening Analysis") self.layout = QGridLayout(self) self.popnexttopimgcounter = 0 self.Tag_round_infor = [] self.Lib_round_infor = [] #************************************************************************************************************************************** #-----------------------------------------------------------GUI for Billboard display------------------------------------------------------ #************************************************************************************************************************************** ImageDisplayContainer = QGroupBox("Billboard") ImageDisplayContainerLayout = QGridLayout() self.GraphyDisplayTab = QTabWidget() #---------------------------------------------------------------------- MatDsiplayPart = QWidget() MatDsiplayPart.layout = QGridLayout() # a figure instance to plot on self.Matdisplay_Figure = Figure() self.Matdisplay_Canvas = FigureCanvas(self.Matdisplay_Figure) self.Matdisplay_toolbar = NavigationToolbar(self.Matdisplay_Canvas, self) MatDsiplayPart.layout.addWidget(self.Matdisplay_toolbar, 0, 0) MatDsiplayPart.layout.addWidget(self.Matdisplay_Canvas, 1, 0) MatDsiplayPart.setLayout(MatDsiplayPart.layout) self.OriginalImgWidget = pg.ImageView() self.OriginalImg_item = self.OriginalImgWidget.getImageItem( ) #setLevels self.OriginalImg_view = self.OriginalImgWidget.getView() self.OriginalImg_item.setAutoDownsample(True) self.OriginalImgWidget.ui.roiBtn.hide() self.OriginalImgWidget.ui.menuBtn.hide() self.OriginalImgWidget.ui.normGroup.hide() self.OriginalImgWidget.ui.roiPlot.hide() self.GraphyDisplayTab.addTab(self.OriginalImgWidget, "Image loaded") self.GraphyDisplayTab.addTab(MatDsiplayPart, "Scatter") ImageDisplayContainerLayout.addWidget(self.GraphyDisplayTab, 1, 1) #---------------------------------------------------------------------- ImageButtonContainer = QGroupBox() ImageButtonContainerLayout = QGridLayout() ButtonRankResetCoordImg = QPushButton('Reset coord', self) ButtonRankResetCoordImg.clicked.connect(self.ResetRankCoord) ImageButtonContainerLayout.addWidget(ButtonRankResetCoordImg, 0, 6) ButtonRankPreviousCoordImg = QPushButton('Previous', self) ButtonRankPreviousCoordImg.setShortcut('a') ButtonRankPreviousCoordImg.clicked.connect( lambda: self.GoThroughTopCells('previous')) ImageButtonContainerLayout.addWidget(ButtonRankPreviousCoordImg, 1, 6) self.ButtonShowInScatter = QPushButton('Show in scatter', self) self.ButtonShowInScatter.setShortcut('s') self.ButtonShowInScatter.setCheckable(True) self.ButtonShowInScatter.clicked.connect(self.ShowScatterPos) ImageButtonContainerLayout.addWidget(self.ButtonShowInScatter, 2, 6) ButtonRankNextCoordImg = QPushButton('Next', self) ButtonRankNextCoordImg.setShortcut('d') ButtonRankNextCoordImg.clicked.connect( lambda: self.GoThroughTopCells('next')) ImageButtonContainerLayout.addWidget(ButtonRankNextCoordImg, 1, 7) GoSeqButton = QPushButton('Go to Cell_: ', self) GoSeqButton.clicked.connect(self.GotoSequence) ImageButtonContainerLayout.addWidget(GoSeqButton, 3, 6) self.ShowSequenceScatterButton = QPushButton( 'Show this cell in scatter', self) self.ShowSequenceScatterButton.setCheckable(True) self.ShowSequenceScatterButton.clicked.connect( self.ShowSequenceScatter) ImageButtonContainerLayout.addWidget(self.ShowSequenceScatterButton, 4, 6) self.CellSequenceBox = QSpinBox(self) self.CellSequenceBox.setMaximum(9000) self.CellSequenceBox.setMinimum(1) self.CellSequenceBox.setValue(1) self.CellSequenceBox.setSingleStep(1) ImageButtonContainerLayout.addWidget(self.CellSequenceBox, 3, 7) # ButtonRankDeleteFromList = QPushButton('Delete', self) # ButtonRankDeleteFromList.clicked.connect(self.DeleteFromTopCells) # ImageButtonContainerLayout.addWidget(ButtonRankDeleteFromList, 2, 7) ButtonRankSaveList = QPushButton('Save Excel', self) ButtonRankSaveList.clicked.connect(self.SaveCellsDataframetoExcel) ImageButtonContainerLayout.addWidget(ButtonRankSaveList, 2, 7) self.ConsoleTextDisplay = QTextEdit() self.ConsoleTextDisplay.setFontItalic(True) self.ConsoleTextDisplay.setPlaceholderText( 'Notice board from console.') self.ConsoleTextDisplay.setMaximumHeight(300) ImageButtonContainerLayout.addWidget(self.ConsoleTextDisplay, 5, 6, 3, 2) ImageButtonContainer.setLayout(ImageButtonContainerLayout) ImageDisplayContainer.setLayout(ImageDisplayContainerLayout) ImageDisplayContainer.setMinimumHeight(700) ImageDisplayContainer.setMinimumWidth(700) self.layout.addWidget(ImageDisplayContainer, 0, 0, 2, 2) self.layout.addWidget(ImageButtonContainer, 0, 2) #************************************************************************************************************************************** #-----------------------------------------------------------GUI for Image processing settings------------------------------------------ #************************************************************************************************************************************** self.PostProcessTab = QTabWidget() self.PostProcessTab.setMaximumWidth(400) self.PostProcessTab.setFixedHeight(250) ImageProcessingContainer = QGroupBox() IPLayout = QGridLayout() IPLayout.addWidget(QLabel("Contour/soma ratio threshold:"), 0, 0) self.Contour_soma_ratio_thres_box = QDoubleSpinBox(self) self.Contour_soma_ratio_thres_box.setDecimals(4) self.Contour_soma_ratio_thres_box.setMinimum(-10) self.Contour_soma_ratio_thres_box.setMaximum(10) self.Contour_soma_ratio_thres_box.setValue(1.000) self.Contour_soma_ratio_thres_box.setSingleStep(0.0001) IPLayout.addWidget(self.Contour_soma_ratio_thres_box, 0, 1) IPLayout.addWidget(QLabel("Mean intensity in contour threshold:"), 0, 2) self.Mean_intensity_in_contour_thres_box = QDoubleSpinBox(self) self.Mean_intensity_in_contour_thres_box.setDecimals(4) self.Mean_intensity_in_contour_thres_box.setMinimum(-10) self.Mean_intensity_in_contour_thres_box.setMaximum(10) self.Mean_intensity_in_contour_thres_box.setValue(0.250) self.Mean_intensity_in_contour_thres_box.setSingleStep(0.0001) IPLayout.addWidget(self.Mean_intensity_in_contour_thres_box, 0, 3) ImageProcessingContainer.setLayout(IPLayout) #---------------------------Loading------------------------------------ LoadSettingContainer = QGroupBox() LoadSettingLayout = QGridLayout() self.FilepathSwitchBox = QComboBox() self.FilepathSwitchBox.addItems(['All', 'Tag', 'Lib']) LoadSettingLayout.addWidget(self.FilepathSwitchBox, 1, 0) self.AnalysisRoundBox = QSpinBox(self) self.AnalysisRoundBox.setMaximum(2000) self.AnalysisRoundBox.setValue(1) self.AnalysisRoundBox.setSingleStep(1) LoadSettingLayout.addWidget(self.AnalysisRoundBox, 1, 2) self.AddAnalysisRoundButton = QtWidgets.QPushButton('Add Round:') self.AddAnalysisRoundButton.clicked.connect(self.SetAnalysisRound) LoadSettingLayout.addWidget(self.AddAnalysisRoundButton, 1, 1) self.datasavedirectorytextbox = QLineEdit(self) self.datasavedirectorytextbox.setPlaceholderText('Data directory') LoadSettingLayout.addWidget(self.datasavedirectorytextbox, 0, 0, 1, 4) self.toolButtonOpenDialog = QtWidgets.QPushButton('Set path') self.toolButtonOpenDialog.clicked.connect(self.SetAnalysisPath) LoadSettingLayout.addWidget(self.toolButtonOpenDialog, 0, 4) ExecuteAnalysisButton = QPushButton('Load images', self) # ExecuteAnalysisButton.setObjectName('Startbutton') ExecuteAnalysisButton.clicked.connect(lambda: self.ScreeningAnalysis()) LoadSettingLayout.addWidget(ExecuteAnalysisButton, 1, 3) self.ClearAnalysisInforButton = QtWidgets.QPushButton('Clear infor') self.ClearAnalysisInforButton.clicked.connect(self.ClearAnalysisInfor) LoadSettingLayout.addWidget(self.ClearAnalysisInforButton, 1, 4) self.X_axisBox = QComboBox() self.X_axisBox.addItems(['Lib_Tag_contour_ratio']) LoadSettingLayout.addWidget(self.X_axisBox, 2, 1) LoadSettingLayout.addWidget(QLabel('X axis: '), 2, 0) self.WeightBoxSelectionFactor_1 = QDoubleSpinBox(self) self.WeightBoxSelectionFactor_1.setDecimals(2) self.WeightBoxSelectionFactor_1.setMinimum(0) self.WeightBoxSelectionFactor_1.setMaximum(1) self.WeightBoxSelectionFactor_1.setValue(1) self.WeightBoxSelectionFactor_1.setSingleStep(0.1) LoadSettingLayout.addWidget(self.WeightBoxSelectionFactor_1, 2, 3) LoadSettingLayout.addWidget(QLabel("Weight:"), 2, 2) self.Y_axisBox = QComboBox() self.Y_axisBox.addItems(['Contour_soma_ratio_Lib']) LoadSettingLayout.addWidget(self.Y_axisBox, 3, 1) LoadSettingLayout.addWidget(QLabel('Y axis: '), 3, 0) self.WeightBoxSelectionFactor_2 = QDoubleSpinBox(self) self.WeightBoxSelectionFactor_2.setDecimals(2) self.WeightBoxSelectionFactor_2.setMinimum(0) self.WeightBoxSelectionFactor_2.setMaximum(1) self.WeightBoxSelectionFactor_2.setValue(0.5) self.WeightBoxSelectionFactor_2.setSingleStep(0.1) LoadSettingLayout.addWidget(self.WeightBoxSelectionFactor_2, 3, 3) LoadSettingLayout.addWidget(QLabel("Weight:"), 3, 2) LoadSettingContainer.setLayout(LoadSettingLayout) #************************************************************************************************************************************** #-----------------------------------------------------------GUI for Selection threshold settings--------------------------------------- #************************************************************************************************************************************** self.PostProcessTab.addTab(LoadSettingContainer, "Loading settings") self.PostProcessTab.addTab(ImageProcessingContainer, "Image analysis thresholds") self.layout.addWidget(self.PostProcessTab, 1, 2) self.setLayout(self.layout) #---------------------------------------------------------------functions for console display------------------------------------------------------------ def normalOutputWritten(self, text): """Append text to the QTextEdit.""" # Maybe QTextEdit.append() works as well, but this is how I do it: cursor = self.ConsoleTextDisplay.textCursor() cursor.movePosition(QTextCursor.End) cursor.insertText(text) self.ConsoleTextDisplay.setTextCursor(cursor) self.ConsoleTextDisplay.ensureCursorVisible() #%% """ # ============================================================================= # FUNCTIONS FOR DATA ANALYSIS AND DISPLAY # ============================================================================= """ def SetAnalysisPath(self): self.Analysissavedirectory = str( QtWidgets.QFileDialog.getExistingDirectory()) self.datasavedirectorytextbox.setText(self.Analysissavedirectory) if self.FilepathSwitchBox.currentText() == 'Tag': self.Tag_folder = self.Analysissavedirectory elif self.FilepathSwitchBox.currentText() == 'Lib': self.Lib_folder = self.Analysissavedirectory elif self.FilepathSwitchBox.currentText() == 'All': self.Tag_folder = self.Analysissavedirectory self.Lib_folder = self.Analysissavedirectory def SetAnalysisRound(self): if self.FilepathSwitchBox.currentText() == 'Tag': self.Tag_round_infor.append(self.AnalysisRoundBox.value()) elif self.FilepathSwitchBox.currentText() == 'Lib': self.Lib_round_infor.append(self.AnalysisRoundBox.value()) self.normalOutputWritten( 'Tag_round_infor: {}\nLib_round_infor: {}\n'.format( str(self.Tag_round_infor), str(self.Lib_round_infor))) def ClearAnalysisInfor(self): self.Tag_folder = None self.Lib_folder = None self.Tag_round_infor = [] self.Lib_round_infor = [] def StartScreeningAnalysisThread(self): self.ScreeningAnalysis_thread = threading.Thread( target=self.ScreeningAnalysis, daemon=True) self.ScreeningAnalysis_thread.start() def ScreeningAnalysis(self): Mean_intensity_in_contour_thres = self.Mean_intensity_in_contour_thres_box.value( ) Contour_soma_ratio_thres = self.Contour_soma_ratio_thres_box.value() # For the brightness screening self.ProcessML = ProcessImageML() self.normalOutputWritten('Start loading images...\n') tag_folder = self.Tag_folder lib_folder = self.Lib_folder tag_round = 'Round{}'.format(self.Tag_round_infor[0]) lib_round = 'Round{}'.format(self.Lib_round_infor[0]) cell_Data_1 = self.ProcessML.FluorescenceAnalysis( tag_folder, tag_round) cell_Data_2 = self.ProcessML.FluorescenceAnalysis( lib_folder, lib_round) Cell_DataFrame_Merged = self.ProcessML.MergeDataFrames(cell_Data_1, cell_Data_2, method='TagLib') DataFrames_filtered = self.ProcessML.FilterDataFrames( Cell_DataFrame_Merged, Mean_intensity_in_contour_thres, Contour_soma_ratio_thres) self.DataFrame_sorted = self.ProcessML.Sorting_onTwoaxes( DataFrames_filtered, axis_1=self.X_axisBox.currentText(), axis_2=self.Y_axisBox.currentText(), weight_1=self.WeightBoxSelectionFactor_1.value(), weight_2=self.WeightBoxSelectionFactor_2.value()) self.SaveCellsDataframetoExcel() self.UpdateSelectionScatter() #%% def UpdateSelectionScatter(self): self.EvaluatingPara_list = [ self.X_axisBox.currentText(), self.Y_axisBox.currentText() ] self.Matdisplay_Figure.clear() if len(self.EvaluatingPara_list) == 2: ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.scatter(self.DataFrame_sorted.loc[:, self.EvaluatingPara_list[0]], self.DataFrame_sorted.loc[:, self.EvaluatingPara_list[1]], s=np.pi * 3, c='blue', alpha=0.5) ax1.set_xlabel(self.EvaluatingPara_list[0]) ax1.set_ylabel(self.EvaluatingPara_list[1]) self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() # Some numbers ready for tracing back self.TotaNumofCellSelected = len(self.DataFrame_sorted) self.TotalCellNum = len(self.DataFrame_sorted) self.normalOutputWritten( '---- Total cells selected: {}; Total cells: {}----\n'.format( self.TotaNumofCellSelected, self.TotalCellNum)) saving_directory = os.path.join( self.Tag_folder, datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + '_Screening scatters.html') self.ProcessML.showPlotlyScatter( self.DataFrame_sorted, x_axis=self.EvaluatingPara_list[0], y_axis=self.EvaluatingPara_list[1], saving_directory=saving_directory) def GoThroughTopCells(self, direction): """ ! Cell dataframe index starts from Cell 1, which corresponds to popnexttopimgcounter = 0. """ if direction == 'next': if self.popnexttopimgcounter > ( self.TotaNumofCellSelected - 1): #Make sure it doesn't go beyond the last coords. self.popnexttopimgcounter -= 1 self.CurrentRankCellpProperties = self.DataFrame_sorted.iloc[ self.popnexttopimgcounter] #--------------------Show image with cell in box---------------------- spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag'] print(spec) # #-------------- readin image--------------- tag_imagefilename = os.path.join(self.Tag_folder, spec + '_PMT_0Zmax.tif') print(tag_imagefilename) loaded_tag_image_display = imread(tag_imagefilename, as_gray=True) # Retrieve boundingbox information Each_bounding_box = self.CurrentRankCellpProperties.loc[ 'BoundingBox_Tag'] minr = int(Each_bounding_box[Each_bounding_box.index('minr') + 4:Each_bounding_box.index('_maxr')]) maxr = int( Each_bounding_box[Each_bounding_box.index('maxr') + 4:Each_bounding_box.index('_minc')]) - 1 minc = int(Each_bounding_box[Each_bounding_box.index('minc') + 4:Each_bounding_box.index('_maxc')]) maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') + 4:len(Each_bounding_box)]) - 1 loaded_tag_image_display[minr, minc:maxc] = 4 loaded_tag_image_display[maxr, minc:maxc] = 4 loaded_tag_image_display[minr:maxr, minc] = 4 loaded_tag_image_display[minr:maxr, maxc] = 4 # -------Show image in imageview------------- self.OriginalImg_item.setImage(np.fliplr( np.rot90(loaded_tag_image_display)), autoLevels=True) self.OriginalImg_item.setLevels((0, 1)) self.Matdisplay_Figure.clear() ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.imshow(loaded_tag_image_display) #Show the first image #--------------------------------------------------Add red boundingbox to axis---------------------------------------------- rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr, fill=False, edgecolor='cyan', linewidth=2) ax1.add_patch(rect) ax1.text(maxc, minr, 'NO_{}'.format(self.popnexttopimgcounter), fontsize=10, color='orange', style='italic') self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() #-------------------Print details of cell of interest---------------- self.normalOutputWritten( '------------------No.{} out of {}----------------\n'.format( self.popnexttopimgcounter + 1, self.TotaNumofCellSelected)) self.normalOutputWritten('ID: {}\n{}: {}\n{}: {}\n{}: {}\n'.format(spec, self.EvaluatingPara_list[0], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[0]], 4), \ self.EvaluatingPara_list[1], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[1]], 4), 'IDNumber', self.CurrentRankCellpProperties.name)) #------------------Stage move---------------------------------------- # self.CurrentPos = spec[spec.index('_R')+2:len(spec)].split('C') # self.ludlStage.moveAbs(int(self.CurrentPos[0]),int(self.CurrentPos[1])) self.popnexttopimgcounter += 1 # Alwasy plus 1 to get it ready for next move. elif direction == 'previous': self.popnexttopimgcounter -= 2 if self.popnexttopimgcounter >= 0: self.CurrentRankCellpProperties = self.DataFrame_sorted.iloc[ self.popnexttopimgcounter] #--------------------Show image with cell in box---------------------- spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag'] print(spec) # #-------------- readin image--------------- tag_imagefilename = os.path.join(self.Tag_folder, spec + '_PMT_0Zmax.tif') print(tag_imagefilename) loaded_tag_image_display = imread(tag_imagefilename, as_gray=True) # Retrieve boundingbox information Each_bounding_box = self.CurrentRankCellpProperties.loc[ 'BoundingBox_Tag'] minr = int( Each_bounding_box[Each_bounding_box.index('minr') + 4:Each_bounding_box.index('_maxr')]) maxr = int( Each_bounding_box[Each_bounding_box.index('maxr') + 4:Each_bounding_box.index('_minc')]) - 1 minc = int( Each_bounding_box[Each_bounding_box.index('minc') + 4:Each_bounding_box.index('_maxc')]) maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') + 4:len(Each_bounding_box)]) - 1 loaded_tag_image_display[minr, minc:maxc] = 4 loaded_tag_image_display[maxr, minc:maxc] = 4 loaded_tag_image_display[minr:maxr, minc] = 4 loaded_tag_image_display[minr:maxr, maxc] = 4 # -------Show image in imageview------------- self.OriginalImg_item.setImage(np.fliplr( np.rot90(loaded_tag_image_display)), autoLevels=True) self.OriginalImg_item.setLevels((0, 1)) self.Matdisplay_Figure.clear() ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.imshow(loaded_tag_image_display) #Show the first image #--------------------------------------------------Add red boundingbox to axis---------------------------------------------- rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr, fill=False, edgecolor='cyan', linewidth=2) ax1.add_patch(rect) ax1.text(maxc, minr, 'NO_{}'.format(self.popnexttopimgcounter), fontsize=10, color='orange', style='italic') self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() #-------------------Print details of cell of interest---------------- self.normalOutputWritten( '------------------No.{} out of {}----------------\n'. format(self.popnexttopimgcounter + 1, self.TotaNumofCellSelected)) self.normalOutputWritten('ID: {}\n{}: {}\n{}: {}\n{}: {}\n'.format(spec, self.EvaluatingPara_list[0], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[0]], 4), \ self.EvaluatingPara_list[1], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[1]], 4), 'IDNumber', self.CurrentRankCellpProperties.name)) #------------------Stage move---------------------------------------- # self.CurrentPos = spec[spec.index('_R')+2:len(spec)].split('C') # self.ludlStage.moveAbs(int(self.CurrentPos[0]),int(self.CurrentPos[1])) if self.popnexttopimgcounter < (self.TotaNumofCellSelected - 1): self.popnexttopimgcounter += 1 else: self.popnexttopimgcounter = 0 elif direction == 'null': self.popnexttopimgcounter -= 1 self.CurrentRankCellpProperties = self.DataFrame_sorted.iloc[ self.popnexttopimgcounter] #--------------------Show image with cell in box---------------------- spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag'] print(spec) # #-------------- readin image--------------- tag_imagefilename = os.path.join(self.Tag_folder, spec + '_PMT_0Zmax.tif') print(tag_imagefilename) loaded_tag_image_display = imread(tag_imagefilename, as_gray=True) # Retrieve boundingbox information Each_bounding_box = self.CurrentRankCellpProperties.loc[ 'BoundingBox_Tag'] minr = int(Each_bounding_box[Each_bounding_box.index('minr') + 4:Each_bounding_box.index('_maxr')]) maxr = int( Each_bounding_box[Each_bounding_box.index('maxr') + 4:Each_bounding_box.index('_minc')]) - 1 minc = int(Each_bounding_box[Each_bounding_box.index('minc') + 4:Each_bounding_box.index('_maxc')]) maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') + 4:len(Each_bounding_box)]) - 1 loaded_tag_image_display[minr, minc:maxc] = 4 loaded_tag_image_display[maxr, minc:maxc] = 4 loaded_tag_image_display[minr:maxr, minc] = 4 loaded_tag_image_display[minr:maxr, maxc] = 4 # -------Show image in imageview------------- self.OriginalImg_item.setImage(np.fliplr( np.rot90(loaded_tag_image_display)), autoLevels=True) self.OriginalImg_item.setLevels((0, 1)) self.Matdisplay_Figure.clear() ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.imshow(loaded_tag_image_display) #Show the first image #--------------------------------------------------Add red boundingbox to axis---------------------------------------------- rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr, fill=False, edgecolor='cyan', linewidth=2) ax1.add_patch(rect) ax1.text(maxc, minr, 'NO_{}'.format(self.popnexttopimgcounter), fontsize=10, color='orange', style='italic') self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() self.popnexttopimgcounter += 1 elif direction == 'IDNumber': self.GotoSequence() def GotoSequence(self): """ Go to a specific cell """ self.SpecificIndexInArray = 'Cell ' + str(self.CellSequenceBox.value()) self.CurrentRankCellpProperties = self.DataFrame_sorted.loc[ self.SpecificIndexInArray, :] #--------------------Show image with cell in box---------------------- spec = self.CurrentRankCellpProperties.loc['ImgNameInfor_Tag'] print(spec) # #-------------- readin image--------------- tag_imagefilename = os.path.join(self.Tag_folder, spec + '_PMT_0Zmax.tif') print(tag_imagefilename) loaded_tag_image_display = imread(tag_imagefilename, as_gray=True) # Retrieve boundingbox information Each_bounding_box = self.CurrentRankCellpProperties.loc[ 'BoundingBox_Tag'] minr = int(Each_bounding_box[Each_bounding_box.index('minr') + 4:Each_bounding_box.index('_maxr')]) maxr = int(Each_bounding_box[Each_bounding_box.index('maxr') + 4:Each_bounding_box.index('_minc')]) - 1 minc = int(Each_bounding_box[Each_bounding_box.index('minc') + 4:Each_bounding_box.index('_maxc')]) maxc = int(Each_bounding_box[Each_bounding_box.index('maxc') + 4:len(Each_bounding_box)]) - 1 loaded_tag_image_display[minr, minc:maxc] = 4 loaded_tag_image_display[maxr, minc:maxc] = 4 loaded_tag_image_display[minr:maxr, minc] = 4 loaded_tag_image_display[minr:maxr, maxc] = 4 # -------Show image in imageview------------- self.OriginalImg_item.setImage(np.fliplr( np.rot90(loaded_tag_image_display)), autoLevels=True) self.OriginalImg_item.setLevels((0, 1)) self.Matdisplay_Figure.clear() ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.imshow(loaded_tag_image_display) #Show the first image #--------------------------------------------------Add red boundingbox to axis---------------------------------------------- rect = mpatches.Rectangle((minc, minr), maxc - minc, maxr - minr, fill=False, edgecolor='cyan', linewidth=2) ax1.add_patch(rect) ax1.text(maxc, minr, 'NO_{}'.format(self.CurrentRankCellpProperties.name), fontsize=10, color='orange', style='italic') self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() #-------------------Print details of cell of interest---------------- self.normalOutputWritten( '------------------IDNumber {}----------------\n'.format( self.CurrentRankCellpProperties.name)) self.normalOutputWritten('ID: {}\n{}: {}\n{}: {}\n'.format(spec, self.EvaluatingPara_list[0], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[0]], 4), \ self.EvaluatingPara_list[1], round(self.CurrentRankCellpProperties.loc[self.EvaluatingPara_list[1]], 4))) def ShowScatterPos(self): if self.ButtonShowInScatter.isChecked(): self.Matdisplay_Figure.clear() ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.scatter(self.DataFrame_sorted.loc[:, self.EvaluatingPara_list[0]], self.DataFrame_sorted.loc[:, self.EvaluatingPara_list[1]], s=np.pi * 3, c='blue', alpha=0.5) ax1.scatter(self.DataFrame_sorted.iloc[ self.popnexttopimgcounter - 1, :].loc[self.EvaluatingPara_list[0]], self.DataFrame_sorted.iloc[ self.popnexttopimgcounter - 1, :].loc[self.EvaluatingPara_list[1]], s=np.pi * 6, c='red', alpha=0.5) ax1.set_xlabel(self.EvaluatingPara_list[0]) ax1.set_ylabel(self.EvaluatingPara_list[1]) self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() else: self.GoThroughTopCells('null') def ShowSequenceScatter(self): if self.ShowSequenceScatterButton.isChecked(): self.Matdisplay_Figure.clear() ax1 = self.Matdisplay_Figure.add_subplot(111) ax1.scatter(self.DataFrame_sorted.loc[:, self.EvaluatingPara_list[0]], self.DataFrame_sorted.loc[:, self.EvaluatingPara_list[1]], s=np.pi * 3, c='blue', alpha=0.5) ax1.scatter( self.DataFrame_sorted.loc[self.SpecificIndexInArray, :].loc[ self.EvaluatingPara_list[0]], self.DataFrame_sorted.loc[self.SpecificIndexInArray, :].loc[ self.EvaluatingPara_list[1]], s=np.pi * 6, c='red', alpha=0.5) ax1.set_xlabel(self.EvaluatingPara_list[0]) ax1.set_ylabel(self.EvaluatingPara_list[1]) self.Matdisplay_Figure.tight_layout() self.Matdisplay_Canvas.draw() else: self.GoThroughTopCells('sequence') def SaveCellsDataframetoExcel(self): os.path.join( self.Tag_folder, datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + '_CellsProperties.xlsx') self.DataFrame_sorted.to_excel( os.path.join( self.Tag_folder, datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + '_CellsProperties.xlsx')) # np.save(os.path.join(self.Tag_folder, datetime.now().strftime('%Y-%m-%d_%H-%M-%S')+'_CellsProperties'), self.Overview_LookupBook) def ResetRankCoord(self): self.popnexttopimgcounter = 0
class SelectionWindowdemo(QWidget): def __init__(self): super(SelectionWindowdemo, self).__init__() self.initUI() def initUI(self): self.resize(800, 800) self.setWindowTitle('特征选择窗口') self.setWindowIcon(QIcon('../image/选择.png')) self.parameter_dict = None self.data = None self.y_predict = None self.df = None self.res_list = None self.var_list = None self.tool_bar = QToolBar() self.set_parameter = QAction(QIcon('../image/参数.png'), '设置参数', self) self.run = QAction(QIcon('../image/运行程序.png'), '运行程序', self) self.save = QAction(QIcon('../image/下载保存.png'), '保存结果', self) self.analysis = QAction(QIcon('../image/对比分析.png'), '分析预测', self) self.tool_bar.addAction(self.set_parameter) self.tool_bar.addAction(self.run) self.tool_bar.addAction(self.analysis) self.tool_bar.addAction(self.save) self.status_bar = QStatusBar() self.lable = QLabel('选择算法:') self.comb1 = QComboBox() self.comb1.addItems(['FSFS', 'Lasso']) # self.comb2 = QComboBox() # self.comb2.addItems(['算法','内容']) self.line_edit = QLineEdit() self.button = QPushButton('搜索') hlayout = QHBoxLayout() hlayout.addWidget(self.lable) hlayout.addWidget(self.comb1) # hlayout.addWidget(self.comb2) hlayout.addWidget(self.line_edit) hlayout.addWidget(self.button) hlayout.addWidget(self.tool_bar) hlayout.addStretch(3) hlayout.setSpacing(10) self.text_edit = QTextEdit() self.text_edit.setText( 'Four steps for features selection:\nFliter,Semi_weapper,Union,Voting.' ) self.text_edit.setReadOnly(True) self.run.setEnabled(False) vlayout = QVBoxLayout() vlayout.addItem(hlayout) vlayout.addWidget(self.text_edit) vlayout.addWidget(self.status_bar) self.setLayout(vlayout) self.comb1.currentIndexChanged.connect(self.selectionChange1) # self.comb2.currentIndexChanged(self.selecttionChange2) self.button.clicked.connect(self.clickSearch) self.set_parameter.triggered.connect(self.getParameter) self.run.triggered.connect(self.runProcess) self.analysis.triggered.connect(self.runAnalysis) self.save.triggered.connect(self.triggeredSave) #选择特征选择的算法 def selectionChange1(self): self.status_bar.showMessage(self.comb1.currentText(), 5000) text = 'Features selection information' if self.comb1.currentText() == 'FSFS': text = 'four steps for features selection:\nFliter,Semi_weapper,Union,Voting.' elif self.comb1.currentText() == 'Lasso': text = ''' Lasso的全称叫做Least absolute shrinkage and selection operator, 直译过来为最小收缩与选择算子。 其本质就是在常规的线性回归的基础上对参数加了一个L1正则化约束。 ''' self.text_edit.setText(text) #搜索算法 def clickSearch(self): text = self.line_edit.text() index = self.comb1.findText(text) if index != -1: self.comb1.setCurrentIndex(index) else: print('没有找到{}'.format(text)) #获取参数对话框的相关参数 def getParameter(self): if self.comb1.currentText() == 'FSFS': self.dialog = SetParameterDialog.ParamerterDemo() elif self.comb1.currentText() == 'Lasso': self.dialog = SetParameterDialog.ParamerterDemo2() self.dialog.signal.sender.connect(self.setParameter) self.dialog.show() #设置算法的参数 def setParameter(self, dic): print(dic) self.parameter_dict = dic self.text_edit.setText(str(dic)) self.run.setEnabled(True) #执行特征选择 def runProcess(self): if self.data is None or self.data[0][1] == '': QMessageBox.critical(self, '错误', '请先导入数据', QMessageBox.Yes, QMessageBox.No) return if self.var_list is None: QMessageBox.information(self, '提示', '请在数据导入页设置变量', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) return try: self.run.setEnabled(False) # print(self.data) # print('-'*100) dtl = DTL() self.df = dtl.list_to_DataFrame(self.data) res_list = [] start = time.time() self.status_bar.showMessage('特征选择中...') print('特征选择中...') f = None if self.comb1.currentText() == 'FSFS': f = FSFS.FSFSDemo(self.df, self.var_list, self.parameter_dict) elif self.comb1.currentText() == 'Lasso': f = Lasso.LassoDemo(self.df, self.var_list, self.parameter_dict) if f is None: return self.res_list = f.run() #得到用于分析的数据 self.RMSE, self.y_predict = f.analysis() end = time.time() str_res = ',\n'.join(self.res_list) res = '最终选择出的特征共{0}个:\n{1}'.format(len(self.res_list), str_res) self.text_edit.setText(res) self.status_bar.showMessage('特征选择完成,耗时{}秒'.format(end - start)) except Exception as e: print(e) #执行数据分析 def runAnalysis(self): self.plot_widget = AnalysisWindow.AnalysisWindowDemo() if self.y_predict is not None: self.plot_widget.RMSE = self.RMSE self.plot_widget.y_predict = self.y_predict self.plot_widget.show() #将选出的特征所对应的数据分离出来保存为单独的文件 def triggeredSave(self): if self.data is None or self.res_list is None: return file_path, _ = QFileDialog.getSaveFileName( self, '保存文件', '../result', 'ALL Files(*);;xlsx(*.xlsx);;xls(*.xls);;csv(*.csv)') if file_path == '': return try: best_features_df = self.df[self.res_list] # print(best_features_df) name, type = file_path.split('.', maxsplit=1) best_features_df.to_excel(excel_writer='{}_best.{}'.format( name, type), index=True, encoding='utf-8') # print('-'*100) columns = self.df.columns.values.tolist() other_features_df = self.df[[ column for column in columns if column not in self.res_list ]] # print(other_features_df) other_features_df.to_excel(excel_writer='{}_other.{}'.format( name, type), index=True, encoding='utf-8') self.status_bar.showMessage('保存完毕!') # print('保存完毕!') except Exception as e: print(e)
class MainWidgetWindow(QWidget): def __init__(self, conf, obj): super().__init__() #self.reader = obj['reader'] self.conf = conf self.obj = obj self.dm = DataManager(5000) self.initUI() # self.vert_velo_list=[] def initUI(self): self.labels = {} #### Do wyrzucenia labels = self.conf['labels'] #labels[0].update({'value': conf.get("elevation") }) #dodawanie value do "elevation" items = [ 'time/rssi', 'time/positionX', 'time/positionY', 'time/temperature', 'time/pressure', 'time/altitude', 'time/pm25', 'time/pm10', 'time/altitude_p', 'time/air_quality', 'time/humidity', 'time/battery', 'time/send_num', 'time/altitude_p_rel', 'time/vertical_velocity', 'altitude_p_rel/pressure', 'altitude_p_rel/temperature', 'altitude_p_rel/pm10', 'altitude_p_rel/air_quality', 'altitude_p_rel/humidity' ] ''' self.locationX_label=QLabel('Pozycja X:') self.locationY_label=QLabel('Pozycja Y:') self.height_label=QLabel('Wysokość:') self.speed_label=QLabel('Wysokość:') self.temperature_label=QLabel('Temperatura:') self.pressure_label=QLabel('Ciśnienie:') self.RRSI_label=QLabel('RRSI:') self.frequency_label=QLabel('Częstotliwość:') ''' #menubar = self.menuBar() self.main_grid = QVBoxLayout() self.top_widget = QWidget() self.top_grid = QGridLayout() self.top_widget.setLayout(self.top_grid) self.bottom_widget = QWidget() self.bottom_grid = QGridLayout() self.bottom_widget.setLayout(self.bottom_grid) self.info_grid = QGridLayout() self.info_widget = QWidget() self.panel_grid = QGridLayout() self.option_grid = QGridLayout() self.panel_grid.addLayout(self.info_grid, 1, 0) self.panel_grid.addLayout(self.option_grid, 2, 0) self.info_widget.setLayout(self.panel_grid) self.info_grid_structure = {} self.top_splitter = QSplitter(QtCore.Qt.Horizontal) self.top_splitter.addWidget(self.info_widget) self.vertical_splitter = QSplitter(QtCore.Qt.Vertical) self.vertical_splitter.addWidget(self.top_splitter) self.vertical_splitter.addWidget(self.bottom_widget) self.info_grid.setSpacing(10) ''' elements=len(labels) if elements%2==0: elements=elements/2 else: elements=(elements+1)/2 for i in range(0,len(labels)): if i<elements: k=i j=0 else: k=i-elements j=3 self.labels[labels[i]['id']]={'text':QLabel(labels[i]['text']), 'value':QLabel('-')} self.info_grid.addWidget(self.labels[labels[i]['id']]['text'], k+1, j) self.info_grid.addWidget(self.labels[labels[i]['id']]['value'], k+1, j+1) frame=QFrame() frame.setFrameShape(QFrame.VLine) self.info_grid.addWidget(frame, 1, 3, elements, 1) ''' cwd = os.getcwd() + "/maps/map.html" self.webView = QtWebEngineWidgets.QWebEngineView() self.webView.setUrl(QtCore.QUrl(cwd)) #MAPS PATH #self.webView.page.run #page().runJavaScript("[map.getBounds().getSouthWest().lat, map.getBounds().getSouthWest().lng, map.getBounds().getNorthEast().lat, map.getBounds().getNorthEast().lng]") self.top_grid.addWidget(self.webView, 1, 1) self.left_plot = self.draw_plot('time', 'rssi', self.dm) self.right_plot = self.draw_plot('time', 'rssi', self.dm) self.bottom_grid.addWidget(self.left_plot.get_widget(), 1, 0) self.bottom_grid.addWidget(self.right_plot.get_widget(), 1, 1) self.webView.loadFinished.connect(self.webView_loaded_event) self.top_splitter.addWidget(self.webView) self.new_flight_button = QPushButton('New Flight', self) self.new_flight_button.clicked.connect(self.new_flight) self.center_map_button = QPushButton('Center Map', self) self.center_map_button.clicked.connect(self.center_map) self.option_grid.addWidget(self.new_flight_button, 1, 0) self.option_grid.addWidget(self.center_map_button, 1, 1) self.load_button = QPushButton('Load Flight', self) self.load_button.clicked.connect(self.load_flight) self.configuration_button = QPushButton('Configuration', self) self.configuration_button.clicked.connect(self.open_configuration) self.option_grid.addWidget(self.load_button, 2, 0) self.option_grid.addWidget(self.configuration_button, 2, 1) self.prediction_button = QPushButton('Prediction', self) self.prediction_button.clicked.connect(self.change_prediction_state) self.option_grid.addWidget(self.prediction_button, 3, 1) self.change_prediction_state() self.left_plot_box = QComboBox(self) self.left_plot_box.addItems(items) #dodawanie listy wykresów self.left_plot_box.currentIndexChanged.connect(self.change_plots) self.right_plot_box = QComboBox(self) self.right_plot_box.addItems(items) #dodawanie listy wykresów self.right_plot_box.currentIndexChanged.connect(self.change_plots) self.left_plot_box_label = QLabel('Left Plot') self.right_plot_box_label = QLabel('Right Plot') self.option_grid.addWidget(self.left_plot_box_label, 4, 0) self.option_grid.addWidget(self.left_plot_box, 4, 1) self.option_grid.addWidget(self.right_plot_box_label, 5, 0) self.option_grid.addWidget(self.right_plot_box, 5, 1) self.time_control = TimeControlWidget(self) self.panel_grid.addWidget(self.time_control, 3, 0) self.main_grid.addWidget(self.vertical_splitter) self.setLayout(self.main_grid) #self.map_functions() ''' self.plot=plt.plot([1,2,3,4]) self.plot.ylabel('some numbers') self.main_grid.addWidget(self.plot,2,1) ''' self.vertical_splitter.splitterMoved.connect(self.resize_map) self.top_splitter.splitterMoved.connect(self.resize_map) self.input_grid = QGridLayout() self.qtimer = QtCore.QTimer() self.qtimer.setInterval(200) #IMPORTANT Update interval self.qtimer.timeout.connect(self.update) self.setGeometry(300, 300, 590, 350) self.setWindowTitle('SobieskiSat') self.show() def new_flight(self): info = copy.deepcopy(self.conf.all()) info['type'] = 'radio' #self.reader(info, self.obj, self.update) self.obj['type'] = 'Radio' #self.obj['dm'].new_save() self.obj['dc'].new_radio() self.obj['timer'].reset() self.qtimer.start() def load_flight(self): self.obj['type'] = 'RawFile' self.obj['raw_file'] = 'C:/saves/2/raw.txt' self.obj['dc'].run_raw_file_reader() self.qtimer.start() def change_prediction_state(self): if 'prediction' not in self.obj: self.obj['prediction'] = True self.obj['prediction'] = not self.obj['prediction'] if self.obj['prediction']: self.prediction_button.setStyleSheet("background-color: green") else: self.prediction_button.setStyleSheet("background-color: red") def open_configuration(self): self.conf_win = ConfiguratorWindow(self.conf, self.obj) self.conf_win.show() def change_plots(self): left = self.left_plot_box.currentText() right = self.right_plot_box.currentText() left = left.split('/') right = right.split('/') self.left_plot.lx = left[0] self.left_plot.ly = left[1] self.right_plot.lx = right[0] self.right_plot.ly = right[1] def center_map(self): try: posX = str(self.dm.get_by_id('positionX', 1)[0]) posY = str(self.dm.get_by_id('positionY', 1)[0]) self.webView.page().runJavaScript('centerMap(' + posX + ', ' + posY + ')') except Exception as e: print(e) def update(self): posX = None posY = None rssi = None data = self.obj['dc'].get() data.append({ 'id': 'Elevation', 'num': 0, 'text': 'Start Altitude: ', 'value': str(self.conf['elevation']) }) #add elevation data = copy.deepcopy(data) #copy data self.dm.add(data) elements = len(data) self.parsed_data = {} def haversine(lon1, lat1, lon2, lat2): # convert decimal degrees to radians #print(lon1) #print(lon2) #print(lat1) #print(lat2) lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2]) # haversine formula dlon = lon2 - lon1 dlat = lat2 - lat1 a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2 c = 2 * asin(sqrt(a)) r = 6300 # Radius of earth in kilometers. Use 3956 for miles #print(c*r*1000) return c * r * 1000 # km to m for d in data: self.parsed_data[d['id']] = d['value'] try: data[11]['value'] = str( round(float(data[11]['value']) / 1024 * 100, 2)) except Exception as e: print(e) try: altitude_p = 44330 * (1 - np.power( float(self.parsed_data['pressure']) / float(self.conf['pressure']), 0.1903)) data.append({ 'id': 'altitude_p', 'num': 0, 'text': 'Altitude (pressure): ', 'value': str(round(altitude_p, 2)) }) altitude_p_rel = altitude_p - float(self.conf['elevation']) data.append({ 'id': 'altitude_p_rel', 'num': 0, 'text': 'Rel Altitude (pressure): ', 'value': str(round(altitude_p_rel, 2)) }) distance = haversine(float(self.conf['start_positionX']), float(self.conf['start_positionY']), float(self.parsed_data['positionX']), float(self.parsed_data['positionY'])) data.append({ 'id': 'distance_plane', 'num': 0, 'text': 'Distance (plane-GPS): ', 'value': str(round(distance, 2)) }) vertical_velocity = 0 try: num = 20 if (len(self.dm.get_by_id('altitude_p', num)) == num and len(self.dm.get_by_id('time', num)) == num): alts = self.dm.get_by_id('altitude_p', num) d_alts = alts[num - 1] - alts[0] times = self.dm.get_by_id('time', num) d_times = times[num - 1] - times[0] vertical_velocity = d_alts / d_times # z 'num' pakietów # + w górę, - w dół # self.vert_velo_list.append(vertical_velocity) # print(np.mean(self.vert_velo_list)) except Exception as e: print(e) data.append({ 'id': 'vertical_velocity', 'num': 0, 'text': 'Vertical velocity: ', 'value': str(round(vertical_velocity, 2)) }) except Exception as e: print(e) try: self.map_add_point(self.conf['start_positionX'], self.conf['start_positionY'], str(0), str("start point")) except Exception as e: print(e) for d in data: if d['id'] in self.info_grid_structure.keys(): self.info_grid_structure[d['id']].setText(d['value']) else: self.info_grid_structure = {} #print(self.info_grid_structure) if self.info_grid_structure == {}: while self.info_grid.count(): child = self.info_grid.takeAt(0) if child.widget(): child.widget().deleteLater() if elements % 2 == 0: elements = elements / 2 else: elements = (elements + 1) / 2 for i in range(0, len(data)): if i < elements: k = i j = 0 else: k = i - elements j = 3 #print(data[i]) self.info_grid_structure[data[i]['id']] = QLabel( data[i]['value']) self.info_grid.addWidget(QLabel(data[i]['text']), k, j) self.info_grid.addWidget( self.info_grid_structure[data[i]['id']], k, j + 1) #frame=QFrame() #frame.setFrameShape(QFrame.VLine) #self.info_grid.addWidget(frame, 1, 3, elements, 1) try: self.map_add_point(self.parsed_data['positionX'], self.parsed_data['positionY'], self.parsed_data['rssi'], str(self.parsed_data)) #print(' try plot') except Exception as e: print(e) try: self.left_plot.update() self.right_plot.update() except Exception as e: print('Graf nie działa!!!' + str(e)) if self.obj['prediction'] == True: try: predicts_num = 50 if (len(self.dm.get_by_id('positionX', predicts_num)) == predicts_num): pred = self.obj['predictor'].predict( [ self.dm.get_by_id('positionX', predicts_num), self.dm.get_by_id('positionY', predicts_num), self.dm.get_by_id('altitude_p', predicts_num) ], float(self.conf.get("elevation")) ) #nowe zmiana stałej 202 na stałą ustalaną podczas startu programu w gui.py try: if self.conf['multi_prediction'] == False: self.webView.page().runJavaScript( 'clearPrediction()') self.webView.page().runJavaScript('drawPrediction(' + str(pred['x']) + ', ' + str(pred['y']) + ', ' + str(pred['r']) + ')') except Exception as e: print(e) except Exception as e: print(e) super().update() def map_functions(self): #self.webView.page().runJavaScript('addPoint(50.05925, 19.92293, 13, "aaa")') self.webView.page().runJavaScript('alert("aa")') def map_add_point(self, posX, posY, signal, text): self.webView.page().runJavaScript('addPoint(' + posX + ', ' + posY + ', ' + signal + ', "' + text + '")') def resizeEvent(self, event): QWidget.resizeEvent(self, event) self.resize_map() def webView_loaded_event(self): self.webView_loaded = True self.webView.page().runJavaScript('init(' + self.conf['positionX'] + ',' + self.conf['positionY'] + ', 15)') self.resize_map() def resize_map(self): w = self.webView.frameSize().width() h = self.webView.frameSize().height() self.webView.page().runJavaScript('resizeMap("' + str(w) + 'px","' + str(h) + 'px")') def draw_plot(self, typex, typey, dm): return PlotG(typex, typey, dm, self.obj) def __del__(self): pass '''
class SongsTableToolbar(QWidget): play_all_needed = pyqtSignal() filter_albums_needed = pyqtSignal([list]) filter_text_changed = pyqtSignal([str]) def __init__(self, parent=None): super().__init__(parent) self.play_all_btn = QPushButton('Play All', self) self.play_all_btn.clicked.connect(self.play_all_needed.emit) # album filters self.filter_albums_combobox = QComboBox(self) self.filter_albums_combobox.addItems(['所有专辑', '标准', '单曲与EP', '现场', '合辑']) self.filter_albums_combobox.currentIndexChanged.connect( self.on_albums_filter_changed) # 8 works on macOS, don't know if it works on various Linux DEs self.filter_albums_combobox.setMinimumContentsLength(8) self.filter_albums_combobox.hide() self._setup_ui() def before_change_mode(self): """filter all filter buttons""" self.filter_albums_combobox.hide() self.play_all_btn.hide() def albums_mode(self): self.before_change_mode() self.filter_albums_combobox.show() def songs_mode(self): self.before_change_mode() self.play_all_btn.show() def enter_state_playall_start(self): self.play_all_btn.setEnabled(False) # currently, this is called only when feeluown is fetching songs, # so when we enter state_playall_start, we set play all btn text # to this. self.play_all_btn.setText('正在获取全部歌曲...') def enter_state_playall_end(self): self.play_all_btn.setText('正在获取全部歌曲...done') self.play_all_btn.setEnabled(True) self.play_all_btn.setText('播放全部') def _setup_ui(self): self._layout = QHBoxLayout(self) # left margin of meta widget is 30, we align with it # bottom margin of meta widget is 15, we should be larger than that self._layout.setContentsMargins(30, 15, 30, 10) self._layout.addWidget(self.play_all_btn) self._layout.addStretch(0) self._layout.addWidget(self.filter_albums_combobox) def on_albums_filter_changed(self, index): # ['所有', '专辑', '单曲与EP', '现场', '合辑'] if index == 0: types = [] elif index == 1: types = [AlbumType.standard] elif index == 2: types = [AlbumType.single, AlbumType.ep] elif index == 3: types = [AlbumType.live] else: types = [AlbumType.compilation, AlbumType.retrospective] self.filter_albums_needed.emit(types)
class ConfiguratorWindow(QWidget): def __init__(self, conf, obj): super().__init__() self.conf = conf self.obj = obj self.initUI() self.structure = { 'baudrate': self.r_baudrate_edit, 'port': self.r_port_edit, 'timeout': self.r_timeout_edit, 'elevation': self.g_elevation_edit, 'pressure': self.g_pressure_edit, 'save_path': self.g_current_path_label, 'multi_prediction': self.g_multi_prediction_edit, 'start_positionX': self.g_start_positionX_edit, 'start_positionY': self.g_start_positionY_edit } def initUI(self): self.main_grid = QGridLayout() self.tabs = QTabWidget() self.radio_tab = QWidget() self.parser_tab = QWidget() self.general_tab = QWidget() self.tabs.addTab(self.radio_tab, 'Radio') self.tabs.addTab(self.parser_tab, 'Parser') self.tabs.addTab(self.general_tab, 'General') self.setFixedSize(600, 400) #### Radio tab self.radio_layout = QGridLayout() self.r_port_label = QLabel('Port:') self.r_autoport_label = QLabel('Automatic Port Finder:') self.r_baudrate_label = QLabel('Baudrate:') self.r_timeout_label = QLabel('Timeout:') self.r_baudrate_edit = QLineEdit() self.r_port_edit = QComboBox() self.r_load_ports() self.r_autoport_edit = QCheckBox() self.r_timeout_edit = QLineEdit() self.radio_layout.addWidget(self.r_port_label, 1, 0) self.radio_layout.addWidget(self.r_port_edit, 1, 1) self.radio_layout.addWidget(self.r_autoport_label, 2, 0) self.radio_layout.addWidget(self.r_autoport_edit, 2, 1) self.radio_layout.addWidget(self.r_baudrate_label, 3, 0) self.radio_layout.addWidget(self.r_baudrate_edit, 3, 1) self.radio_layout.addWidget(self.r_timeout_label, 4, 0) self.radio_layout.addWidget(self.r_timeout_edit, 4, 1) self.radio_tab.setLayout(self.radio_layout) ### Parser tab self.parser_layout = QGridLayout() self.p_stu = QTableWidget() self.p_stu.setRowCount(5) self.p_stu.setColumnCount(3) self.p_stu.setHorizontalHeaderLabels(['ID', 'Name', 'Number']) self.p_stu.horizontalHeader().setSectionResizeMode( 1, QHeaderView.Stretch) self.p_tab_control_grid = QGridLayout() self.p_add_button = QPushButton('Add') self.p_add_button.clicked.connect(self.p_add) self.p_tab_control_grid.addWidget(self.p_add_button, 0, 0) self.p_remove_button = QPushButton('Remove') self.p_remove_button.clicked.connect(self.p_remove) self.p_tab_control_grid.addWidget(self.p_remove_button, 0, 1) self.parser_layout.addWidget(self.p_stu, 1, 0) self.parser_layout.addLayout(self.p_tab_control_grid, 2, 0) self.parser_tab.setLayout(self.parser_layout) ### General tab self.general_layout = QGridLayout() self.g_elevation_label = QLabel('Starting Altitude (from pressure):') self.g_pressure_label = QLabel('Absolute Pressure:') self.g_multi_prediction_label = QLabel('Multipoint Prediction:') self.g_save_path_label = QLabel('Set Save Path:') self.g_current_path_label_label = QLabel('Current Path:') self.g_current_path_label = QLabel('-') self.g_start_positionX_label = QLabel('Start Position X:') self.g_start_positionY_label = QLabel('Start Position Y:') self.g_elevation_edit = QLineEdit() self.g_pressure_edit = QLineEdit() self.g_multi_prediction_edit = QCheckBox() self.g_save_path_edit = QPushButton('Wybierz') self.g_start_positionX_edit = QLineEdit() self.g_start_positionY_edit = QLineEdit() self.g_save_path_edit.clicked.connect(self.r_file_dialog) self.general_layout.addWidget(self.g_elevation_label, 1, 0) self.general_layout.addWidget(self.g_elevation_edit, 1, 1) self.general_layout.addWidget(self.g_pressure_label, 2, 0) self.general_layout.addWidget(self.g_pressure_edit, 2, 1) self.general_layout.addWidget(self.g_start_positionX_label, 3, 0) self.general_layout.addWidget(self.g_start_positionX_edit, 3, 1) self.general_layout.addWidget(self.g_start_positionY_label, 4, 0) self.general_layout.addWidget(self.g_start_positionY_edit, 4, 1) self.general_layout.addWidget(self.g_multi_prediction_label, 5, 0) self.general_layout.addWidget(self.g_multi_prediction_edit, 5, 1) self.general_layout.addWidget(self.g_save_path_label, 6, 0) self.general_layout.addWidget(self.g_save_path_edit, 6, 1) self.general_layout.addWidget(self.g_current_path_label_label, 7, 0) self.general_layout.addWidget(self.g_current_path_label, 7, 1) self.general_tab.setLayout(self.general_layout) ### Finish self.main_grid.addWidget(self.tabs, 0, 0) self.bottom_grid = QGridLayout() self.save_button = QPushButton('Save') self.save_button.clicked.connect(self.save) self.bottom_grid.addWidget(self.save_button, 0, 3) self.main_grid.addLayout(self.bottom_grid, 1, 0) self.setLayout(self.main_grid) self.setWindowTitle('Configuration') #print(isinstance(self.r_port_edit, QLineEdit)) sprawdzanie typu def p_add(self): self.p_stu.insertRow(self.p_stu.currentRow() + 1) def p_remove(self): buttonReply = QMessageBox.question( self, 'Remove?', 'Do you want to remove ' + str(self.p_stu.currentRow() + 1) + ' row?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if buttonReply == QMessageBox.Yes: self.p_stu.removeRow(self.p_stu.currentRow()) def r_file_dialog(self): file_name = QFileDialog.getExistingDirectory(self, 'Select', '/home') if file_name: self.conf['save_path'] = file_name self.load() def save(self): new = {} for k, v in self.structure.items(): if isinstance(v, QLineEdit): new[k] = v.text() elif isinstance(v, QComboBox): new[k] = v.currentText() elif isinstance(v, QCheckBox): new[k] = v.isChecked() ### Dodać Obsługę Pliki self.p_save_structure() self.conf.update(new) self.close() def load(self): data = self.conf.all() for k, v in self.structure.items(): if k in data: try: if isinstance(v, QLineEdit): v.setText(str(data[k])) elif isinstance(v, QCheckBox): v.setChecked(data[k]) elif isinstance(v, QComboBox): v.setCurrentText(str(data[k])) #może nie działać elif isinstance(v, QLabel): v.setText(str(data[k])) except Exception as e: print(e) self.load_structure() def r_load_ports(self): sl = self.obj['sl'] dev = sl.all_serials() names = [] for d in dev: names.append(d.device) self.r_port_edit.addItems(names) if self.conf['port'] in names: self.r_port_edit.setCurrentText(self.conf['port']) def load_structure(self): labels = self.conf.all()['labels'] self.p_stu.setRowCount(len(labels)) counter = 0 for i in labels: self.p_stu.setItem(counter, 0, QTableWidgetItem(i['id'])) self.p_stu.setItem(counter, 1, QTableWidgetItem(i['text'])) self.p_stu.setItem(counter, 2, QTableWidgetItem(str(i['num']))) counter += 1 def p_save_structure(self): stru = [] for r in range(0, self.p_stu.rowCount()): id = self.p_stu.item(r, 0).text() name = self.p_stu.item(r, 1).text() num = self.p_stu.item(r, 2).text() stru.append({'id': id, 'num': int(num), 'text': name}) self.conf['labels'] = stru def show(self): self.load() super().show()
class PID_Tuner_Widget(QWidget): ''' This class is a PyQt widget for tunning the 6 degree of freedom PID control system. ''' def __init__(self): ''' Initialize the layout for the widget by setting its color and instantiating its components: Parameters: N/A Returns: N/A ''' QWidget.__init__(self) configs = MechOS_Network_Configs( MECHOS_CONFIG_FILE_PATH)._get_network_parameters() self.pid_gui_node = mechos.Node("PID_TUNER_GUI", '192.168.1.2', '192.168.1.14') #Publisher to tell the navigation/movement controller when new PID values are saved. self.pid_configs_update_publisher = self.pid_gui_node.create_publisher( "UPDATE_PID_CONFIGS", Bool(), protocol="tcp") #Subscriber to get PID ERRORS #self.pid_errors_subscriber = self.pid_gui_node.create_subscriber("PE", self._update_error_plot, configs["sub_port"]) #self.pid_error_proto = pid_errors_pb2.PID_ERRORS() #Mechos parameter server #Initialize parameter server client to get and set parameters related to sub self.param_serv = mechos.Parameter_Server_Client( configs["param_ip"], configs["param_port"]) self.param_serv.use_parameter_database(configs["param_server_path"]) #Set background color of the widget #nav_gui_palette = self.palette() #nav_gui_palette.setColor(self.backgroundRole(), QColor(64, 64, 64)) #self.setPalette(nav_gui_palette) #Create widgets main layout structure self.primary_linking_layout = QVBoxLayout(self) self.setLayout(self.primary_linking_layout) #Options widget self.options_linking_layout = QGridLayout() self._error_plotter() self._PID_controller_select() self._PID_sliders() self.set_desired_position = Set_Desired_Position_GUI() #Set up QTimer to update the PID errors self.pid_error_update_timer = QTimer() #self.pid_error_update_timer.timeout.connect(lambda: self.pid_gui_node.spinOnce(self.pid_errors_subscriber)) self.primary_linking_layout.addLayout(self.options_linking_layout, 1) self.primary_linking_layout.addWidget(self.set_desired_position, 2) #Start PID errors update errors. Update 100 timers a second self.pid_error_update_timer.start(10) def _PID_controller_select(self): ''' ''' self.PID_controller_layout = QGridLayout() #A combo box to select which PID channel to tune self.pid_channel_select = QComboBox() self.pid_channel_select.addItem("roll_pid") self.pid_channel_select.addItem("pitch_pid") self.pid_channel_select.addItem("yaw_pid") self.pid_channel_select.addItem("x_pid") self.pid_channel_select.addItem("y_pid") self.pid_channel_select.addItem("z_pid") #Signal to change which PID controller is being tunned when selection changes self.pid_channel_select.currentIndexChanged.connect( self._PID_controller_change) self.pid_channel_select_label = QLabel("PID Controller:") self.pid_channel_select_label.setStyleSheet("color: black") #A button to save the PID values to the parameter server. This is how to sub #will update its PID values self.PID_save_values_layout = QVBoxLayout() self.pid_values_save = QPushButton("Save PID Values") self.pid_values_save.setStyleSheet( "background-color:#2C878F; color:#01535B") self.pid_values_save.setIcon(QIcon(QPixmap("save_symbol.png"))) self.pid_values_save.clicked.connect(self._save_pid_values) self.PID_save_values_layout.addWidget(self.pid_values_save, 0) self.PID_controller_layout.addWidget(self.pid_channel_select_label, 0, 0) self.PID_controller_layout.addWidget(self.pid_channel_select, 0, 1) self.PID_save_values_layout.addLayout(self.PID_controller_layout, 1) self.options_linking_layout.addLayout(self.PID_save_values_layout, 0, 1) def _PID_sliders(self): ''' Set up the proportional, integral, and derivatives gain sliders for tunning the PID controls. Parameters: N/A Returns: N/A ''' self.slider_layout = QGridLayout() self.k_p_precision_layout = QGridLayout() self.k_i_precision_layout = QGridLayout() self.k_d_precision_layout = QGridLayout() self.k_p_slider = QSlider(Qt.Horizontal) self.k_p_slider.setMaximum(10) self.k_p_slider.setMinimum(0) self.k_p_slider.setValue(0) self.k_p_slider.valueChanged.connect(self._update_gains_with_slider) self.k_p_label = QLabel("K_P:") self.k_p_label.setStyleSheet("color: black") self.k_p_display = QLineEdit() self.k_p_display.editingFinished.connect( self._update_gain_with_line_edits) self.k_p_max_value_line_edit = QLineEdit() self.max_k_p = 10.0 self.k_p_max_value_line_edit.setText(str(self.max_k_p)) self.k_p_max_value_line_edit.editingFinished.connect( self._update_PID_precision) self.k_p_max_value_label = QLabel("Max K_P:") self.k_p_max_value_label.setStyleSheet("color: black") self.k_p_precision_combobox = QComboBox() self.k_p_precision_combobox.addItems(["1", "0.1", "0.01", "0.001"]) self.precision_k_p = float(self.k_p_precision_combobox.currentText()) self.k_p_precision_combobox.currentIndexChanged.connect( self._update_PID_precision) self.k_p_precision_label = QLabel("K_P Precision:") self.k_p_precision_label.setStyleSheet("color: black") self.k_i_slider = QSlider(Qt.Horizontal) self.k_i_slider.setMaximum(10) self.k_i_slider.setMinimum(0) self.k_i_slider.setValue(0) self.k_i_slider.valueChanged.connect(self._update_gains_with_slider) self.k_i_label = QLabel("K_I:") self.k_i_label.setStyleSheet("color: black") self.k_i_display = QLineEdit() self.k_i_display.editingFinished.connect( self._update_gain_with_line_edits) self.k_i_max_value_line_edit = QLineEdit() self.max_k_i = 10.0 self.k_i_max_value_line_edit.setText(str(self.max_k_i)) self.k_i_max_value_line_edit.editingFinished.connect( self._update_PID_precision) self.k_i_max_value_label = QLabel("Max K_I:") self.k_i_max_value_label.setStyleSheet("color: black") self.k_i_precision_combobox = QComboBox() self.k_i_precision_combobox.addItems(["1", "0.1", "0.01", "0.001"]) self.precision_k_i = float(self.k_i_precision_combobox.currentText()) self.k_i_precision_combobox.currentIndexChanged.connect( self._update_PID_precision) self.k_i_precision_label = QLabel("K_I Precision:") self.k_i_precision_label.setStyleSheet("color: black") self.k_d_slider = QSlider(Qt.Horizontal) self.k_d_slider.setMaximum(10) self.k_d_slider.setMinimum(0) self.k_d_slider.setValue(0) self.k_d_slider.valueChanged.connect(self._update_gains_with_slider) self.k_d_label = QLabel("K_D:") self.k_d_label.setStyleSheet("color: black") self.k_d_display = QLineEdit() self.k_d_display.editingFinished.connect( self._update_gain_with_line_edits) self.k_d_max_value_line_edit = QLineEdit() self.max_k_d = 10.0 self.k_d_max_value_line_edit.setText(str(self.max_k_d)) self.k_d_max_value_line_edit.editingFinished.connect( self._update_PID_precision) self.k_d_max_value_label = QLabel("Max K_D:") self.k_d_max_value_label.setStyleSheet("color: black") self.k_d_precision_combobox = QComboBox() self.k_d_precision_combobox.addItems(["1", "0.1", "0.01", "0.001"]) self.precision_k_d = float(self.k_d_precision_combobox.currentText()) self.k_d_precision_combobox.currentIndexChanged.connect( self._update_PID_precision) self.k_d_precision_label = QLabel("K_D Precision:") self.k_d_precision_label.setStyleSheet("color: black") self.k_p_precision_layout.addWidget(self.k_p_max_value_label, 0, 0) self.k_p_precision_layout.addWidget(self.k_p_max_value_line_edit, 0, 1) self.k_p_precision_layout.addWidget(self.k_p_precision_label, 1, 0) self.k_p_precision_layout.addWidget(self.k_p_precision_combobox, 1, 1) self.k_i_precision_layout.addWidget(self.k_i_max_value_label, 0, 0) self.k_i_precision_layout.addWidget(self.k_i_max_value_line_edit, 0, 1) self.k_i_precision_layout.addWidget(self.k_i_precision_label, 1, 0) self.k_i_precision_layout.addWidget(self.k_i_precision_combobox, 1, 1) self.k_d_precision_layout.addWidget(self.k_d_max_value_label, 0, 0) self.k_d_precision_layout.addWidget(self.k_d_max_value_line_edit, 0, 1) self.k_d_precision_layout.addWidget(self.k_d_precision_label, 1, 0) self.k_d_precision_layout.addWidget(self.k_d_precision_combobox, 1, 1) self.slider_layout.addWidget(self.k_p_label, 0, 0) self.slider_layout.addWidget(self.k_p_slider, 0, 1) self.slider_layout.addWidget(self.k_p_display, 0, 2) self.slider_layout.addLayout(self.k_p_precision_layout, 0, 3) self.slider_layout.addWidget(self.k_i_label, 1, 0) self.slider_layout.addWidget(self.k_i_slider, 1, 1) self.slider_layout.addWidget(self.k_i_display, 1, 2) self.slider_layout.addLayout(self.k_i_precision_layout, 1, 3) self.slider_layout.addWidget(self.k_d_label, 2, 0) self.slider_layout.addWidget(self.k_d_slider, 2, 1) self.slider_layout.addWidget(self.k_d_display, 2, 2) self.slider_layout.addLayout(self.k_d_precision_layout, 2, 3) self.options_linking_layout.addLayout(self.slider_layout, 0, 0) self._PID_controller_change() def _error_plotter(self): ''' Initialize a real time plotter widget to display the PID error of the sub. Parameters: N/A Returns: N/A ''' self.error_plot = Real_Time_Plotter(title="PID Error") self.error_plot.add_curve("Current Error", (255, 0, 0)) self.error_plot.add_curve("Zero Error", (0, 255, 0)) self.primary_linking_layout.addWidget(self.error_plot, 0) def _update_error_plot(self, pid_error_proto): ''' Update the error plot by calling the pid error subscriber. This function is the callback function to the pid_error_suscriber. Parameters: pid_error_proto: The pid error protobuf recieved from the pid error subscriber. Returns: N/A ''' self.pid_error_proto.ParseFromString(pid_error_proto) self.channel = self.pid_channel_select.currentIndex() if (self.channel == 0): current_error = self.pid_error_proto.roll_error elif (self.channel == 1): current_error = self.pid_error_proto.pitch_error elif (self.channel == 2): current_error = self.pid_error_proto.yaw_error elif (self.channel == 3): current_error = self.pid_error_proto.x_pos_error elif (self.channel == 4): current_error = self.pid_error_proto.y_pos_error elif (self.channel == 5): current_error = self.pid_error_proto.z_pos_error self.error_plot.update_values(current_error, 0) def _PID_controller_change(self): ''' If the PID controller desired to be tune changes, this callback is called to position the sliders in the last set PID control position. Parameters: N/A Returns: N/A ''' self.channel = self.pid_channel_select.currentText() k_p = self.param_serv.get_param('Control/PID/' + self.channel + '/p') k_i = self.param_serv.get_param('Control/PID/' + self.channel + '/i') k_d = self.param_serv.get_param('Control/PID/' + self.channel + '/d') #Set the max of each channel as the value from the Parameter server k_p_disp = "%.3f" % (float(k_p) + 0.10 * float(k_p)) k_i_disp = "%.3f" % (float(k_i) + 0.10 * float(k_i)) k_d_disp = "%.3f" % (float(k_d) + 0.10 * float(k_d)) self.k_p_max_value_line_edit.setText(k_p_disp) self.k_i_max_value_line_edit.setText(k_i_disp) self.k_d_max_value_line_edit.setText(k_d_disp) #Set the precision to the max precision of the self.k_p_precision_combobox.setCurrentIndex(3) self.k_i_precision_combobox.setCurrentIndex(3) self.k_d_precision_combobox.setCurrentIndex(3) self._update_PID_precision() self._update_gain_displays(k_p, k_i, k_d) self._update_sliders(k_p, k_i, k_d) def _save_pid_values(self): ''' This is the callback for the save pid values button. When it is pressed, it sets the PID gain values currently selected on the sliders/gain displays and writes it to the parameter server. Then it tells the navigation controller to update these values. Parameters: N/A Returns: N/A ''' channel = self.pid_channel_select.currentText() #Get the current PID values seen by the sliders/gain displays. Set it #to the parameter server. k_p = self.k_p_display.text() k_i = self.k_i_display.text() k_d = self.k_d_display.text() self.param_serv.set_param('Control/PID/' + channel + '/p', k_p) self.param_serv.set_param('Control/PID/' + channel + '/i', k_i) self.param_serv.set_param('Control/PID/' + channel + '/d', k_d) time.sleep(0.01) #Make sure that the parameters are properly sent. #Tell the navigation controller/movement controller to update its PIDs self.pid_configs_update_publisher.publish(bytes( '1', 'utf-8')) #The value that is sent does not matter print("[INFO]: Saving and Updating PID Configurations.") def _update_PID_precision(self): ''' This function is the callback for when the desired PID gain floating point precision is changed. It allows for the selection of the max p, i, and d values for each channel. Parameters: N/A Returns: N/A ''' k_p = self.k_p_display.text() k_i = self.k_i_display.text() k_d = self.k_d_display.text() self.max_k_p = float(self.k_p_max_value_line_edit.text()) self.precision_k_p = float(self.k_p_precision_combobox.currentText()) self.k_p_slider.setMaximum(self.max_k_p * (1 / self.precision_k_p)) self.max_k_i = float(self.k_i_max_value_line_edit.text()) self.precision_k_i = float(self.k_i_precision_combobox.currentText()) self.k_i_slider.setMaximum(self.max_k_i * (1 / self.precision_k_i)) self.max_k_d = float(self.k_d_max_value_line_edit.text()) self.precision_k_d = float(self.k_d_precision_combobox.currentText()) self.k_d_slider.setMaximum(self.max_k_d * (1 / self.precision_k_d)) #self._update_gain_displays(k_p, k_i, k_d) #self._update_sliders(k_p, k_i, k_d) def _update_gains_with_slider(self): ''' This function is the callback called when any of the sliders change in value. It will update the gain displays to view what the current gain is via number. Parameters: N/A Returns: N/A ''' k_p = self.k_p_slider.value() * self.precision_k_p k_i = self.k_i_slider.value() * self.precision_k_i k_d = self.k_d_slider.value() * self.precision_k_d self._update_gain_displays(k_p, k_i, k_d) def _update_gain_with_line_edits(self): ''' This function is the callback called when any of the gain displays change in value and the enter key is pressed. It will update the slider position to view what the current gain isvia number. Parameters: N/A Returns: N/A ''' k_p = float(self.k_p_display.text()) if (k_p > self.max_k_p): k_p = self.max_k_p k_i = float(self.k_i_display.text()) if (k_i > self.max_k_i): k_i = self.max_k_i k_d = float(self.k_d_display.text()) if (k_d > self.max_k_d): k_d = self.max_k_d self._update_sliders(k_p, k_i, k_d) self._update_gain_displays(k_p, k_i, k_d) def _update_gain_displays(self, k_p, k_i, k_d): ''' Set the text for the gain displays. Parameters: k_p: The proportional gain k_i: Integral gain k_d: Derivative gain Returns: N/A ''' self.k_p_display.setText(str(round(float(k_p), 3))) self.k_i_display.setText(str(round(float(k_i), 3))) self.k_d_display.setText(str(round(float(k_d), 3))) def _update_sliders(self, k_p, k_i, k_d): ''' Set the position for the sliders. Parameters: k_p: The proportional gain k_i: Integral gain k_d: Derivative gain Returns: N/A ''' self.k_p_slider.setValue(float(k_p) / self.precision_k_p) self.k_i_slider.setValue(float(k_i) / self.precision_k_i) self.k_d_slider.setValue(float(k_d) / self.precision_k_d)
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.config = ConfigParser() self.setting_widget = QWidget() self.show_widget = QWidget() self.heart_function_widget = QWidget() self.main_widget = QSplitter() self.main_layout = QHBoxLayout() self.left_layout = QVBoxLayout() self.show_layout = QVBoxLayout() self.open_serial_button = QPushButton() self.init_ui() def init_ui(self): self.config.read('config.ini') self.setGeometry(self.config.getint('Size Setting', 'Geometry_ax'), self.config.getint('Size Setting', 'Geometry_ay'), self.config.getint('Size Setting', 'Geometry_xs'), self.config.getint('Size Setting', 'Geometry_ys')) # todo: change the version number automatically self.setWindowTitle( self.config.get('Text Setting', 'MainWindow_Title') + '--V1.0') self.setWindowIcon( QIcon(self.config.get('Picture Setting', 'MainWind_icon'))) self.main_widget.addWidget(self.setting_widget) self.main_widget.addWidget(self.show_widget) self.main_widget.addWidget(self.heart_function_widget) self.main_widget.setStretchFactor(0, 2) self.main_widget.setStretchFactor(1, 12) self.main_widget.setStretchFactor(2, 2) self.open_serial_button.setText('') self.open_serial_button.setStyleSheet("background-color:red") self.init_show_widget() self.init_statue_bar() self.init_menu_bar() self.init_setting_widget() self.init_heart_function_widget() self.setCentralWidget(self.main_widget) def init_menu_bar(self): scan_action = QAction('Scan(&S)', self) self.load_action = QAction('Load(&L)', self) scan_action.setShortcut('Ctrl+S') port_menu = self.menuBar().addMenu('Port(&P)') port_menu.addAction(scan_action) view_menu = self.menuBar().addMenu('View(&V)') tools_menu = self.menuBar().addMenu('Tools(&T)') self.reload_action = QAction('Reload', self) tools_menu.addAction(self.reload_action) view_menu.addAction(self.load_action) def init_setting_widget(self): # port set part # 结构一定要严谨 group_box = QGroupBox('SerialSetting') serial_setting_layout = QFormLayout() self.serial_port_combobox = QComboBox() self.serial_baudrate_combobox = QComboBox() self.serial_bytes_combobox = QComboBox() self.serial_parity_combobox = QComboBox() self.serial_stop_combobox = QComboBox() self.serial_flow_combobox = QComboBox() self.serial_baudrate_combobox.addItems([ '1200', '2400', '4800', '9600', '19200', '38400', '57600', '115200' ]) self.serial_baudrate_combobox.setCurrentIndex(3) self.serial_baudrate_combobox.setEditable(True) self.serial_bytes_combobox.addItems(['5', '6', '7', '8']) self.serial_bytes_combobox.setCurrentIndex(3) self.serial_parity_combobox.addItems( ['No', 'Odd', 'Space', 'Even', 'Mark']) self.serial_parity_combobox.setCurrentIndex(0) self.serial_stop_combobox.addItems(['One', 'OneAndHalf', 'Two']) self.serial_flow_combobox.addItems( ['NoFlow', 'Hardware', 'Software', 'UnknownFlow']) self.serial_flow_combobox.setCurrentIndex(0) # learn QFromLayout serial_setting_layout.addRow(QLabel(r'端口'), self.serial_port_combobox) serial_setting_layout.addRow(QLabel(r'波特率'), self.serial_baudrate_combobox) serial_setting_layout.addRow(QLabel(r'分割符'), self.serial_parity_combobox) serial_setting_layout.addRow(QLabel(r'数据位数'), self.serial_bytes_combobox) serial_setting_layout.addRow(QLabel(r'流控制'), self.serial_flow_combobox) serial_setting_layout.addRow(QLabel(r'打开串口'), self.open_serial_button) group_box.setLayout(serial_setting_layout) # receive set part receive_group_box = QGroupBox('Receive') receive_hex_ascii_layout = QHBoxLayout() self.receive_hex_checkbox = QCheckBox('RECHEX') self.receive_asc_checkbox = QCheckBox('RECASCII') self.receive_hex_checkbox.setChecked(True) self.receive_asc_checkbox.setChecked(False) self.receive_asc_checkbox.setAutoExclusive(True) self.receive_hex_checkbox.setAutoExclusive(True) receive_hex_ascii_layout.addWidget(self.receive_hex_checkbox) receive_hex_ascii_layout.addWidget(self.receive_asc_checkbox) receive_group_box.setLayout(receive_hex_ascii_layout) # send send_group_box = QGroupBox("发送") send_formlayout = QFormLayout() send_layout = QVBoxLayout() self.send_code_combox = QComboBox() self.send_code_combox.addItems(['ASCII', 'HEX']) self.times_send_chebox = QCheckBox("启动定时发送") self.times_edit = QLineEdit() self.times_edit.setText(self.config.get('Send Config', 'send times')) self.send_interval_edit = QLineEdit() self.send_interval_edit.setText( self.config.get('Send Config', 'send interval')) self.send_area = QTextEdit() self.send_area.setText(self.config.get('Send Config', 'send data')) self.send_button = QPushButton("发送") send_formlayout.addRow(QLabel("字符编码"), self.send_code_combox) send_formlayout.addRow(QLabel("发送次数:"), self.times_edit) send_formlayout.addRow(QLabel("发送间隔:"), self.send_interval_edit) send_layout.addWidget(self.times_send_chebox) send_layout.addLayout(send_formlayout) send_layout.addWidget(self.send_area) send_layout.addWidget(self.send_button) send_group_box.setLayout(send_layout) # processing data_process_group_box = QGroupBox('数据处理') data_process_layout = QHBoxLayout() self.transform_data_checkbox = QCheckBox('转换') # todo:后面判断参数的时候可以通过ObjectName判断发送者 # self.transform_data_checkbox.setObjectName('transform_data_checkbox') data_process_layout.addWidget(self.transform_data_checkbox) data_process_group_box.setLayout(data_process_layout) # collection self.left_layout.addWidget(group_box) self.left_layout.addWidget(receive_group_box) self.left_layout.addWidget(send_group_box) self.left_layout.addWidget(data_process_group_box) self.left_layout.addStretch() self.setting_widget.setLayout(self.left_layout) pass def init_show_widget(self): show_button_layout = QGridLayout() show_info_layout = QHBoxLayout() self.decoding_combobox = QComboBox() self.decoding_combobox.addItems(['ASCII', 'GB2312']) self.decoding_combobox.setEditable(False) self.heart_led_show = QLCDNumber() self.receive_area = QTextEdit() line_plot_area = pg.GraphicsLayoutWidget() self.plot_1 = line_plot_area.addPlot(title='Original Signal') self.plot_1.hideAxis('left') line_plot_area.nextRow() self.plot_2 = line_plot_area.addPlot(title='Processed Signal') line_plot_area.removeItem(self.plot_2) self.receive_area.setTabletTracking(True) self.clear_button = QPushButton( self.config.get('Button Setting', 'Clear')) show_button_layout.addWidget(self.clear_button, 0, 0) show_info_layout.addWidget(self.decoding_combobox) show_info_layout.addStretch() show_info_layout.addWidget(QLabel('Func:')) show_info_layout.addWidget(self.heart_led_show) self.show_widget.setLayout(self.show_layout) self.show_layout.addWidget(self.receive_area) self.show_layout.addWidget(line_plot_area) self.show_layout.addLayout(show_info_layout) self.show_layout.addLayout(show_button_layout) pass # detail information show and seq setting def init_heart_function_widget(self): function_layout = QVBoxLayout() # Data Format parameter data_format_group = QGroupBox('Data Format') data_format_layout = QFormLayout() self.bytes_of_stop_point = QLineEdit() self.bytes_of_start_point = QLineEdit() self.bytes_of_total_edit = QLineEdit() self.bytes_of_start_point.setText( self.config.get('Data Format', 'Data Begin')) self.bytes_of_stop_point.setText( self.config.get('Data Format', 'Data Stop')) self.bytes_of_total_edit.setText( self.config.get('Data Format', 'Total Len')) data_format_layout.addRow(QLabel('Data Begin:'), self.bytes_of_start_point) data_format_layout.addRow(QLabel('Data Stop'), self.bytes_of_stop_point) data_format_layout.addRow(QLabel('Total Bytes:'), self.bytes_of_total_edit) data_format_group.setLayout(data_format_layout) # Heart Rate Parameter heart_parameter = QGroupBox('Heart Rate Parameter') heart_parameter_layout = QFormLayout() self.fs_parameter = QLineEdit() self.fs_parameter.setValidator(QIntValidator(0, 96000)) self.fs_parameter.setPlaceholderText('0~96000') self.fs_parameter.setText(self.config.get('Heart Rate', 'Fs')) self.threshold_parameter = QLineEdit() self.threshold_parameter.setValidator(QIntValidator(0, 96000)) self.threshold_parameter.setPlaceholderText('0~96000') self.threshold_parameter.setText( self.config.get('Heart Rate', 'Threshold')) self.scalar_parameter = QLineEdit() self.scalar_parameter.setValidator(QIntValidator(1, 20)) self.scalar_parameter.setPlaceholderText('1~20') self.scalar_parameter.setText(self.config.get('Heart Rate', 'Scalar')) self.smooth_level = QLineEdit() self.smooth_level.setValidator(QIntValidator(1, 20)) self.smooth_level.setPlaceholderText('2~6') self.smooth_level.setText(self.config.get('Heart Rate', 'Smooth Level')) heart_parameter_layout.addRow(QLabel("FS:"), self.fs_parameter) heart_parameter_layout.addRow(QLabel('Threshold:'), self.threshold_parameter) heart_parameter_layout.addRow(QLabel('Scalar:'), self.scalar_parameter) heart_parameter_layout.addRow(QLabel('Smooth Level:'), self.smooth_level) heart_parameter.setLayout(heart_parameter_layout) # Heart Function parameter heart_function_group = QGroupBox("Heart rate cal") heart_function_layout = QGridLayout() self.heart_rate_debug_button = QPushButton("Debug") self.save_data_button = QPushButton("Save") self.heart_rate_release = QRadioButton("Release") self.smooth_switch = QCheckBox("Smooth") self.begin_cal_index_edit = QLineEdit() self.begin_cal_index_edit.setValidator(QIntValidator()) self.end_cal_index_edit = QLineEdit() self.end_cal_index_edit.setValidator(QIntValidator()) heart_function_layout.addWidget(self.heart_rate_debug_button, 0, 0) heart_function_layout.addWidget(self.save_data_button, 0, 1) heart_function_layout.addWidget(self.heart_rate_release, 1, 0) heart_function_layout.addWidget(self.smooth_switch, 1, 1) heart_function_layout.addWidget(self.begin_cal_index_edit, 2, 0) heart_function_layout.addWidget(self.end_cal_index_edit, 2, 1) heart_function_group.setLayout(heart_function_layout) function_layout.addWidget(data_format_group) function_layout.addWidget(heart_parameter) function_layout.addWidget(heart_function_group) self.heart_function_widget.setLayout(function_layout) function_layout.addStretch() pass def init_statue_bar(self): # todo: 可以增加状态闪烁的功能 使用QTime self.status_bar_status = QLabel() self.status_bar_status.setMinimumWidth(80) self.status_bar_status.setText( "<font color=%s>%s</font>" % ("#008200", self.config.get('Status Bar', 'OK'))) self.status_bar_recieve_count = QLabel(r'Receive ' + r'Bytes:' + '0') self.statusBar().addWidget(self.status_bar_status) self.statusBar().addWidget(self.status_bar_recieve_count, 2) # todo: 加入每次串口打开使用时间 pass
def __init__(self, parent: 'ElectrumWindow', config: 'SimpleConfig'): WindowModalDialog.__init__(self, parent, _('Preferences')) self.config = config self.window = parent self.need_restart = False self.fx = self.window.fx self.wallet = self.window.wallet vbox = QVBoxLayout() tabs = QTabWidget() gui_widgets = [] tx_widgets = [] oa_widgets = [] # language lang_help = _( 'Select which language is used in the GUI (after restart).') lang_label = HelpLabel(_('Language') + ':', lang_help) lang_combo = QComboBox() lang_combo.addItems(list(languages.values())) lang_keys = list(languages.keys()) lang_cur_setting = self.config.get("language", '') try: index = lang_keys.index(lang_cur_setting) except ValueError: # not in list index = 0 lang_combo.setCurrentIndex(index) if not self.config.is_modifiable('language'): for w in [lang_combo, lang_label]: w.setEnabled(False) def on_lang(x): lang_request = list(languages.keys())[lang_combo.currentIndex()] if lang_request != self.config.get('language'): self.config.set_key("language", lang_request, True) self.need_restart = True lang_combo.currentIndexChanged.connect(on_lang) gui_widgets.append((lang_label, lang_combo)) nz_help = _( 'Number of zeros displayed after the decimal point. For example, if this is set to 2, "1." will be displayed as "1.00"' ) nz_label = HelpLabel(_('Zeros after decimal point') + ':', nz_help) nz = QSpinBox() nz.setMinimum(0) nz.setMaximum(self.config.decimal_point) nz.setValue(self.config.num_zeros) if not self.config.is_modifiable('num_zeros'): for w in [nz, nz_label]: w.setEnabled(False) def on_nz(): value = nz.value() if self.config.num_zeros != value: self.config.num_zeros = value self.config.set_key('num_zeros', value, True) self.window.need_update.set() nz.valueChanged.connect(on_nz) gui_widgets.append((nz_label, nz)) #use_rbf = bool(self.config.get('use_rbf', True)) #use_rbf_cb = QCheckBox(_('Use Replace-By-Fee')) #use_rbf_cb.setChecked(use_rbf) #use_rbf_cb.setToolTip( # _('If you check this box, your transactions will be marked as non-final,') + '\n' + \ # _('and you will have the possibility, while they are unconfirmed, to replace them with transactions that pay higher fees.') + '\n' + \ # _('Note that some merchants do not accept non-final transactions until they are confirmed.')) #def on_use_rbf(x): # self.config.set_key('use_rbf', bool(x)) # batch_rbf_cb.setEnabled(bool(x)) #use_rbf_cb.stateChanged.connect(on_use_rbf) #tx_widgets.append((use_rbf_cb, None)) #batch_rbf_cb = QCheckBox(_('Batch RBF transactions')) #batch_rbf_cb.setChecked(bool(self.config.get('batch_rbf', False))) #batch_rbf_cb.setEnabled(use_rbf) #batch_rbf_cb.setToolTip( # _('If you check this box, your unconfirmed transactions will be consolidated into a single transaction.') + '\n' + \ # _('This will save fees.')) #def on_batch_rbf(x): # self.config.set_key('batch_rbf', bool(x)) #batch_rbf_cb.stateChanged.connect(on_batch_rbf) #tx_widgets.append((batch_rbf_cb, None)) # lightning lightning_widgets = [] help_recov = _(messages.MSG_RECOVERABLE_CHANNELS) recov_cb = QCheckBox(_("Create recoverable channels")) enable_toggle_use_recoverable_channels = bool( self.wallet.lnworker and self.wallet.lnworker.can_have_recoverable_channels()) recov_cb.setEnabled(enable_toggle_use_recoverable_channels) recov_cb.setToolTip(messages.to_rtf(help_recov)) recov_cb.setChecked( bool(self.config.get('use_recoverable_channels', True)) and enable_toggle_use_recoverable_channels) def on_recov_checked(x): self.config.set_key('use_recoverable_channels', bool(x)) recov_cb.stateChanged.connect(on_recov_checked) lightning_widgets.append((recov_cb, None)) help_trampoline = _(messages.MSG_HELP_TRAMPOLINE) trampoline_cb = QCheckBox(_("Use trampoline routing (disable gossip)")) trampoline_cb.setToolTip(messages.to_rtf(help_trampoline)) trampoline_cb.setChecked( not bool(self.config.get('use_gossip', False))) def on_trampoline_checked(use_trampoline): use_gossip = not bool(use_trampoline) self.config.set_key('use_gossip', use_gossip) if use_gossip: self.window.network.start_gossip() else: self.window.network.run_from_another_thread( self.window.network.stop_gossip()) util.trigger_callback('ln_gossip_sync_progress') # FIXME: update all wallet windows util.trigger_callback('channels_updated', self.wallet) trampoline_cb.stateChanged.connect(on_trampoline_checked) lightning_widgets.append((trampoline_cb, None)) help_remote_wt = ' '.join([ _("A watchtower is a daemon that watches your channels and prevents the other party from stealing funds by broadcasting an old state." ), _("If you have private a watchtower, enter its URL here."), _("Check our online documentation if you want to configure Electrum as a watchtower." ), ]) remote_wt_cb = QCheckBox(_("Use a remote watchtower")) remote_wt_cb.setToolTip('<p>' + help_remote_wt + '</p>') remote_wt_cb.setChecked(bool(self.config.get('use_watchtower', False))) def on_remote_wt_checked(x): self.config.set_key('use_watchtower', bool(x)) self.watchtower_url_e.setEnabled(bool(x)) remote_wt_cb.stateChanged.connect(on_remote_wt_checked) watchtower_url = self.config.get('watchtower_url') self.watchtower_url_e = QLineEdit(watchtower_url) self.watchtower_url_e.setEnabled( self.config.get('use_watchtower', False)) def on_wt_url(): url = self.watchtower_url_e.text() or None watchtower_url = self.config.set_key('watchtower_url', url) self.watchtower_url_e.editingFinished.connect(on_wt_url) lightning_widgets.append((remote_wt_cb, self.watchtower_url_e)) msg = _('OpenAlias record, used to receive coins and to sign payment requests.') + '\n\n'\ + _('The following alias providers are available:') + '\n'\ + '\n'.join(['https://cryptoname.co/', 'http://xmr.link']) + '\n\n'\ + 'For more information, see https://openalias.org' alias_label = HelpLabel(_('OpenAlias') + ':', msg) alias = self.config.get('alias', '') self.alias_e = QLineEdit(alias) self.set_alias_color() self.alias_e.editingFinished.connect(self.on_alias_edit) oa_widgets.append((alias_label, self.alias_e)) msat_cb = QCheckBox(_("Show amounts with msat precision")) msat_cb.setChecked( bool(self.config.get('amt_precision_post_satoshi', False))) def on_msat_checked(v): prec = 3 if v == Qt.Checked else 0 if self.config.amt_precision_post_satoshi != prec: self.config.amt_precision_post_satoshi = prec self.config.set_key('amt_precision_post_satoshi', prec) self.window.need_update.set() msat_cb.stateChanged.connect(on_msat_checked) lightning_widgets.append((msat_cb, None)) # units units = base_units_list msg = (_( 'Base unit of your wallet.' ) + '\n1 BTC = 1000 mBTC. 1 mBTC = 1000 bits. 1 bit = 100 sat.\n' + _( 'This setting affects the Send tab, and all balance related fields.' )) unit_label = HelpLabel(_('Base unit') + ':', msg) unit_combo = QComboBox() unit_combo.addItems(units) unit_combo.setCurrentIndex(units.index(self.window.base_unit())) def on_unit(x, nz): unit_result = units[unit_combo.currentIndex()] if self.window.base_unit() == unit_result: return edits = self.window.amount_e, self.window.receive_amount_e amounts = [edit.get_amount() for edit in edits] self.config.set_base_unit(unit_result) nz.setMaximum(self.config.decimal_point) self.window.update_tabs() for edit, amount in zip(edits, amounts): edit.setAmount(amount) self.window.update_status() unit_combo.currentIndexChanged.connect(lambda x: on_unit(x, nz)) gui_widgets.append((unit_label, unit_combo)) thousandsep_cb = QCheckBox( _("Add thousand separators to bitcoin amounts")) thousandsep_cb.setChecked( bool(self.config.get('amt_add_thousands_sep', False))) def on_set_thousandsep(v): checked = v == Qt.Checked if self.config.amt_add_thousands_sep != checked: self.config.amt_add_thousands_sep = checked self.config.set_key('amt_add_thousands_sep', checked) self.window.need_update.set() thousandsep_cb.stateChanged.connect(on_set_thousandsep) gui_widgets.append((thousandsep_cb, None)) qr_combo = QComboBox() qr_combo.addItem("Default", "default") msg = (_("For scanning QR codes.") + "\n" + _("Install the zbar package to enable this.")) qr_label = HelpLabel(_('Video Device') + ':', msg) from .qrreader import find_system_cameras system_cameras = find_system_cameras() for cam_desc, cam_path in system_cameras.items(): qr_combo.addItem(cam_desc, cam_path) index = qr_combo.findData(self.config.get("video_device")) qr_combo.setCurrentIndex(index) on_video_device = lambda x: self.config.set_key( "video_device", qr_combo.itemData(x), True) qr_combo.currentIndexChanged.connect(on_video_device) gui_widgets.append((qr_label, qr_combo)) colortheme_combo = QComboBox() colortheme_combo.addItem(_('Light'), 'default') colortheme_combo.addItem(_('Dark'), 'dark') index = colortheme_combo.findData( self.config.get('qt_gui_color_theme', 'default')) colortheme_combo.setCurrentIndex(index) colortheme_label = QLabel(_('Color theme') + ':') def on_colortheme(x): self.config.set_key('qt_gui_color_theme', colortheme_combo.itemData(x), True) #self.window.gui_object.reload_app_stylesheet() self.need_restart = True colortheme_combo.currentIndexChanged.connect(on_colortheme) gui_widgets.append((colortheme_label, colortheme_combo)) updatecheck_cb = QCheckBox( _("Automatically check for software updates")) updatecheck_cb.setChecked(bool(self.config.get('check_updates', False))) def on_set_updatecheck(v): self.config.set_key('check_updates', v == Qt.Checked, save=True) updatecheck_cb.stateChanged.connect(on_set_updatecheck) gui_widgets.append((updatecheck_cb, None)) filelogging_cb = QCheckBox(_("Write logs to file")) filelogging_cb.setChecked(bool(self.config.get('log_to_file', False))) def on_set_filelogging(v): self.config.set_key('log_to_file', v == Qt.Checked, save=True) self.need_restart = True filelogging_cb.stateChanged.connect(on_set_filelogging) filelogging_cb.setToolTip( _('Debug logs can be persisted to disk. These are useful for troubleshooting.' )) gui_widgets.append((filelogging_cb, None)) preview_cb = QCheckBox(_('Advanced preview')) preview_cb.setChecked(bool(self.config.get('advanced_preview', False))) preview_cb.setToolTip( _("Open advanced transaction preview dialog when 'Pay' is clicked." )) def on_preview(x): self.config.set_key('advanced_preview', x == Qt.Checked) preview_cb.stateChanged.connect(on_preview) tx_widgets.append((preview_cb, None)) usechange_cb = QCheckBox(_('Use change addresses')) usechange_cb.setChecked(self.window.wallet.use_change) if not self.config.is_modifiable('use_change'): usechange_cb.setEnabled(False) def on_usechange(x): usechange_result = x == Qt.Checked if self.window.wallet.use_change != usechange_result: self.window.wallet.use_change = usechange_result self.window.wallet.db.put('use_change', self.window.wallet.use_change) multiple_cb.setEnabled(self.window.wallet.use_change) usechange_cb.stateChanged.connect(on_usechange) usechange_cb.setToolTip( _('Using change addresses makes it more difficult for other people to track your transactions.' )) tx_widgets.append((usechange_cb, None)) def on_multiple(x): multiple = x == Qt.Checked if self.wallet.multiple_change != multiple: self.wallet.multiple_change = multiple self.wallet.db.put('multiple_change', multiple) multiple_change = self.wallet.multiple_change multiple_cb = QCheckBox(_('Use multiple change addresses')) multiple_cb.setEnabled(self.wallet.use_change) multiple_cb.setToolTip('\n'.join([ _('In some cases, use up to 3 change addresses in order to break ' 'up large coin amounts and obfuscate the recipient address.'), _('This may result in higher transactions fees.') ])) multiple_cb.setChecked(multiple_change) multiple_cb.stateChanged.connect(on_multiple) tx_widgets.append((multiple_cb, None)) def fmt_docs(key, klass): lines = [ln.lstrip(" ") for ln in klass.__doc__.split("\n")] return '\n'.join([key, "", " ".join(lines)]) choosers = sorted(coinchooser.COIN_CHOOSERS.keys()) if len(choosers) > 1: chooser_name = coinchooser.get_name(self.config) msg = _( 'Choose coin (UTXO) selection method. The following are available:\n\n' ) msg += '\n\n'.join( fmt_docs(*item) for item in coinchooser.COIN_CHOOSERS.items()) chooser_label = HelpLabel(_('Coin selection') + ':', msg) chooser_combo = QComboBox() chooser_combo.addItems(choosers) i = choosers.index(chooser_name) if chooser_name in choosers else 0 chooser_combo.setCurrentIndex(i) def on_chooser(x): chooser_name = choosers[chooser_combo.currentIndex()] self.config.set_key('coin_chooser', chooser_name) chooser_combo.currentIndexChanged.connect(on_chooser) tx_widgets.append((chooser_label, chooser_combo)) def on_unconf(x): self.config.set_key('confirmed_only', bool(x)) conf_only = bool(self.config.get('confirmed_only', False)) unconf_cb = QCheckBox(_('Spend only confirmed coins')) unconf_cb.setToolTip(_('Spend only confirmed inputs.')) unconf_cb.setChecked(conf_only) unconf_cb.stateChanged.connect(on_unconf) tx_widgets.append((unconf_cb, None)) def on_outrounding(x): self.config.set_key('coin_chooser_output_rounding', bool(x)) enable_outrounding = bool( self.config.get('coin_chooser_output_rounding', True)) outrounding_cb = QCheckBox(_('Enable output value rounding')) outrounding_cb.setToolTip( _('Set the value of the change output so that it has similar precision to the other outputs.' ) + '\n' + _('This might improve your privacy somewhat.') + '\n' + _('If enabled, at most 100 satoshis might be lost due to this, per transaction.' )) outrounding_cb.setChecked(enable_outrounding) outrounding_cb.stateChanged.connect(on_outrounding) tx_widgets.append((outrounding_cb, None)) block_explorers = sorted(util.block_explorer_info().keys()) BLOCK_EX_CUSTOM_ITEM = _("Custom URL") if BLOCK_EX_CUSTOM_ITEM in block_explorers: # malicious translation? block_explorers.remove(BLOCK_EX_CUSTOM_ITEM) block_explorers.append(BLOCK_EX_CUSTOM_ITEM) msg = _( 'Choose which online block explorer to use for functions that open a web browser' ) block_ex_label = HelpLabel(_('Online Block Explorer') + ':', msg) block_ex_combo = QComboBox() block_ex_custom_e = QLineEdit( str(self.config.get('block_explorer_custom') or '')) block_ex_combo.addItems(block_explorers) block_ex_combo.setCurrentIndex( block_ex_combo.findText( util.block_explorer(self.config) or BLOCK_EX_CUSTOM_ITEM)) def showhide_block_ex_custom_e(): block_ex_custom_e.setVisible( block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM) showhide_block_ex_custom_e() def on_be_combo(x): if block_ex_combo.currentText() == BLOCK_EX_CUSTOM_ITEM: on_be_edit() else: be_result = block_explorers[block_ex_combo.currentIndex()] self.config.set_key('block_explorer_custom', None, False) self.config.set_key('block_explorer', be_result, True) showhide_block_ex_custom_e() block_ex_combo.currentIndexChanged.connect(on_be_combo) def on_be_edit(): val = block_ex_custom_e.text() try: val = ast.literal_eval(val) # to also accept tuples except: pass self.config.set_key('block_explorer_custom', val) block_ex_custom_e.editingFinished.connect(on_be_edit) block_ex_hbox = QHBoxLayout() block_ex_hbox.setContentsMargins(0, 0, 0, 0) block_ex_hbox.setSpacing(0) block_ex_hbox.addWidget(block_ex_combo) block_ex_hbox.addWidget(block_ex_custom_e) block_ex_hbox_w = QWidget() block_ex_hbox_w.setLayout(block_ex_hbox) tx_widgets.append((block_ex_label, block_ex_hbox_w)) # Fiat Currency hist_checkbox = QCheckBox() hist_capgains_checkbox = QCheckBox() fiat_address_checkbox = QCheckBox() ccy_combo = QComboBox() ex_combo = QComboBox() def update_currencies(): if not self.window.fx: return currencies = sorted( self.fx.get_currencies(self.fx.get_history_config())) ccy_combo.clear() ccy_combo.addItems([_('None')] + currencies) if self.fx.is_enabled(): ccy_combo.setCurrentIndex( ccy_combo.findText(self.fx.get_currency())) def update_history_cb(): if not self.fx: return hist_checkbox.setChecked(self.fx.get_history_config()) hist_checkbox.setEnabled(self.fx.is_enabled()) def update_fiat_address_cb(): if not self.fx: return fiat_address_checkbox.setChecked(self.fx.get_fiat_address_config()) def update_history_capgains_cb(): if not self.fx: return hist_capgains_checkbox.setChecked( self.fx.get_history_capital_gains_config()) hist_capgains_checkbox.setEnabled(hist_checkbox.isChecked()) def update_exchanges(): if not self.fx: return b = self.fx.is_enabled() ex_combo.setEnabled(b) if b: h = self.fx.get_history_config() c = self.fx.get_currency() exchanges = self.fx.get_exchanges_by_ccy(c, h) else: exchanges = self.fx.get_exchanges_by_ccy('USD', False) ex_combo.blockSignals(True) ex_combo.clear() ex_combo.addItems(sorted(exchanges)) ex_combo.setCurrentIndex( ex_combo.findText(self.fx.config_exchange())) ex_combo.blockSignals(False) def on_currency(hh): if not self.fx: return b = bool(ccy_combo.currentIndex()) ccy = str(ccy_combo.currentText()) if b else None self.fx.set_enabled(b) if b and ccy != self.fx.ccy: self.fx.set_currency(ccy) update_history_cb() update_exchanges() self.window.update_fiat() def on_exchange(idx): exchange = str(ex_combo.currentText()) if self.fx and self.fx.is_enabled( ) and exchange and exchange != self.fx.exchange.name(): self.fx.set_exchange(exchange) def on_history(checked): if not self.fx: return self.fx.set_history_config(checked) update_exchanges() self.window.history_model.refresh('on_history') if self.fx.is_enabled() and checked: self.fx.trigger_update() update_history_capgains_cb() def on_history_capgains(checked): if not self.fx: return self.fx.set_history_capital_gains_config(checked) self.window.history_model.refresh('on_history_capgains') def on_fiat_address(checked): if not self.fx: return self.fx.set_fiat_address_config(checked) self.window.address_list.refresh_headers() self.window.address_list.update() update_currencies() update_history_cb() update_history_capgains_cb() update_fiat_address_cb() update_exchanges() ccy_combo.currentIndexChanged.connect(on_currency) hist_checkbox.stateChanged.connect(on_history) hist_capgains_checkbox.stateChanged.connect(on_history_capgains) fiat_address_checkbox.stateChanged.connect(on_fiat_address) ex_combo.currentIndexChanged.connect(on_exchange) fiat_widgets = [] fiat_widgets.append((QLabel(_('Fiat currency')), ccy_combo)) fiat_widgets.append((QLabel(_('Source')), ex_combo)) fiat_widgets.append((QLabel(_('Show history rates')), hist_checkbox)) fiat_widgets.append((QLabel(_('Show capital gains in history')), hist_capgains_checkbox)) fiat_widgets.append((QLabel(_('Show Fiat balance for addresses')), fiat_address_checkbox)) tabs_info = [ (gui_widgets, _('General')), (tx_widgets, _('Transactions')), (lightning_widgets, _('Lightning')), (fiat_widgets, _('Fiat')), (oa_widgets, _('OpenAlias')), ] for widgets, name in tabs_info: tab = QWidget() tab_vbox = QVBoxLayout(tab) grid = QGridLayout() for a, b in widgets: i = grid.rowCount() if b: if a: grid.addWidget(a, i, 0) grid.addWidget(b, i, 1) else: grid.addWidget(a, i, 0, 1, 2) tab_vbox.addLayout(grid) tab_vbox.addStretch(1) tabs.addTab(tab, name) vbox.addWidget(tabs) vbox.addStretch(1) vbox.addLayout(Buttons(CloseButton(self))) self.setLayout(vbox)
class HistoryList(MyTreeView, AcceptFileDragDrop): filter_columns = [ HistoryColumns.STATUS, HistoryColumns.DESCRIPTION, HistoryColumns.AMOUNT, HistoryColumns.TXID ] def tx_item_from_proxy_row(self, proxy_row): hm_idx = self.model().mapToSource(self.model().index(proxy_row, 0)) return hm_idx.internalPointer().get_data() def should_hide(self, proxy_row): if self.start_timestamp and self.end_timestamp: tx_item = self.tx_item_from_proxy_row(proxy_row) date = tx_item['date'] if date: in_interval = self.start_timestamp <= date <= self.end_timestamp if not in_interval: return True return False def __init__(self, parent, model: HistoryModel): super().__init__(parent, self.create_menu, stretch_column=HistoryColumns.DESCRIPTION) self.config = parent.config self.hm = model self.proxy = HistorySortModel(self) self.proxy.setSourceModel(model) self.setModel(self.proxy) AcceptFileDragDrop.__init__(self, ".txn") self.setSortingEnabled(True) self.start_timestamp = None self.end_timestamp = None self.years = [] self.create_toolbar_buttons() self.wallet = self.parent.wallet # type: Abstract_Wallet self.sortByColumn(HistoryColumns.STATUS, Qt.AscendingOrder) self.editable_columns |= {HistoryColumns.FIAT_VALUE} self.setRootIsDecorated(True) self.header().setStretchLastSection(False) for col in HistoryColumns: sm = QHeaderView.Stretch if col == self.stretch_column else QHeaderView.ResizeToContents self.header().setSectionResizeMode(col, sm) def update(self): self.hm.refresh('HistoryList.update()') def format_date(self, d): return str(datetime.date(d.year, d.month, d.day)) if d else _('None') def on_combo(self, x): s = self.period_combo.itemText(x) x = s == _('Custom') self.start_button.setEnabled(x) self.end_button.setEnabled(x) if s == _('All'): self.start_timestamp = None self.end_timestamp = None self.start_button.setText("-") self.end_button.setText("-") else: try: year = int(s) except: return self.start_timestamp = start_date = datetime.datetime(year, 1, 1) self.end_timestamp = end_date = datetime.datetime(year + 1, 1, 1) self.start_button.setText( _('From') + ' ' + self.format_date(start_date)) self.end_button.setText(_('To') + ' ' + self.format_date(end_date)) self.hide_rows() def create_toolbar_buttons(self): self.period_combo = QComboBox() self.start_button = QPushButton('-') self.start_button.pressed.connect(self.select_start_date) self.start_button.setEnabled(False) self.end_button = QPushButton('-') self.end_button.pressed.connect(self.select_end_date) self.end_button.setEnabled(False) self.period_combo.addItems([_('All'), _('Custom')]) self.period_combo.activated.connect(self.on_combo) def get_toolbar_buttons(self): return self.period_combo, self.start_button, self.end_button def on_hide_toolbar(self): self.start_timestamp = None self.end_timestamp = None self.hide_rows() def save_toolbar_state(self, state, config): config.set_key('show_toolbar_history', state) def select_start_date(self): self.start_timestamp = self.select_date(self.start_button) self.hide_rows() def select_end_date(self): self.end_timestamp = self.select_date(self.end_button) self.hide_rows() def select_date(self, button): d = WindowModalDialog(self, _("Select date")) d.setMinimumSize(600, 150) d.date = None vbox = QVBoxLayout() def on_date(date): d.date = date cal = QCalendarWidget() cal.setGridVisible(True) cal.clicked[QDate].connect(on_date) vbox.addWidget(cal) vbox.addLayout(Buttons(OkButton(d), CancelButton(d))) d.setLayout(vbox) if d.exec_(): if d.date is None: return None date = d.date.toPyDate() button.setText(self.format_date(date)) return datetime.datetime(date.year, date.month, date.day) def show_summary(self): fx = self.parent.fx show_fiat = fx and fx.is_enabled() and fx.get_history_config() if not show_fiat: self.parent.show_message( _("Enable fiat exchange rate with history.")) return h = self.wallet.get_detailed_history(fx=fx) summary = h['summary'] if not summary: self.parent.show_message(_("Nothing to summarize.")) return start = summary['begin'] end = summary['end'] flow = summary['flow'] start_date = start.get('date') end_date = end.get('date') format_amount = lambda x: self.parent.format_amount( x.value) + ' ' + self.parent.base_unit() format_fiat = lambda x: str(x) + ' ' + self.parent.fx.ccy d = WindowModalDialog(self, _("Summary")) d.setMinimumSize(600, 150) vbox = QVBoxLayout() msg = messages.to_rtf(messages.MSG_CAPITAL_GAINS) vbox.addWidget(WWLabel(msg)) grid = QGridLayout() grid.addWidget(QLabel(_("Begin")), 0, 1) grid.addWidget(QLabel(_("End")), 0, 2) # grid.addWidget(QLabel(_("Date")), 1, 0) grid.addWidget(QLabel(self.format_date(start_date)), 1, 1) grid.addWidget(QLabel(self.format_date(end_date)), 1, 2) # grid.addWidget(QLabel(_("BTC balance")), 2, 0) grid.addWidget(QLabel(format_amount(start['BTC_balance'])), 2, 1) grid.addWidget(QLabel(format_amount(end['BTC_balance'])), 2, 2) # grid.addWidget(QLabel(_("BTC Fiat price")), 3, 0) grid.addWidget(QLabel(format_fiat(start.get('BTC_fiat_price'))), 3, 1) grid.addWidget(QLabel(format_fiat(end.get('BTC_fiat_price'))), 3, 2) # grid.addWidget(QLabel(_("Fiat balance")), 4, 0) grid.addWidget(QLabel(format_fiat(start.get('fiat_balance'))), 4, 1) grid.addWidget(QLabel(format_fiat(end.get('fiat_balance'))), 4, 2) # grid.addWidget(QLabel(_("Acquisition price")), 5, 0) grid.addWidget(QLabel(format_fiat(start.get('acquisition_price', ''))), 5, 1) grid.addWidget(QLabel(format_fiat(end.get('acquisition_price', ''))), 5, 2) # grid.addWidget(QLabel(_("Unrealized capital gains")), 6, 0) grid.addWidget(QLabel(format_fiat(start.get('unrealized_gains', ''))), 6, 1) grid.addWidget(QLabel(format_fiat(end.get('unrealized_gains', ''))), 6, 2) # grid2 = QGridLayout() grid2.addWidget(QLabel(_("BTC incoming")), 0, 0) grid2.addWidget(QLabel(format_amount(flow['BTC_incoming'])), 0, 1) grid2.addWidget(QLabel(_("Fiat incoming")), 1, 0) grid2.addWidget(QLabel(format_fiat(flow.get('fiat_incoming'))), 1, 1) grid2.addWidget(QLabel(_("BTC outgoing")), 2, 0) grid2.addWidget(QLabel(format_amount(flow['BTC_outgoing'])), 2, 1) grid2.addWidget(QLabel(_("Fiat outgoing")), 3, 0) grid2.addWidget(QLabel(format_fiat(flow.get('fiat_outgoing'))), 3, 1) # grid2.addWidget(QLabel(_("Realized capital gains")), 4, 0) grid2.addWidget( QLabel(format_fiat(flow.get('realized_capital_gains'))), 4, 1) vbox.addLayout(grid) vbox.addWidget(QLabel(_('Cash flow'))) vbox.addLayout(grid2) vbox.addLayout(Buttons(CloseButton(d))) d.setLayout(vbox) d.exec_() def plot_history_dialog(self): if plot_history is None: self.parent.show_message( _("Can't plot history.") + '\n' + _("Perhaps some dependencies are missing...") + " (matplotlib?)") return try: plt = plot_history(list(self.hm.transactions.values())) plt.show() except NothingToPlotException as e: self.parent.show_message(str(e)) def on_edited(self, index, user_role, text): index = self.model().mapToSource(index) tx_item = index.internalPointer().get_data() column = index.column() key = get_item_key(tx_item) if column == HistoryColumns.DESCRIPTION: if self.wallet.set_label(key, text): #changed self.hm.update_label(index) self.parent.update_completions() elif column == HistoryColumns.FIAT_VALUE: self.wallet.set_fiat_value(key, self.parent.fx.ccy, text, self.parent.fx, tx_item['value'].value) value = tx_item['value'].value if value is not None: self.hm.update_fiat(index) else: assert False def mouseDoubleClickEvent(self, event: QMouseEvent): idx = self.indexAt(event.pos()) if not idx.isValid(): return tx_item = self.tx_item_from_proxy_row(idx.row()) if self.hm.flags(self.model().mapToSource(idx)) & Qt.ItemIsEditable: super().mouseDoubleClickEvent(event) else: if tx_item.get('lightning'): if tx_item['type'] == 'payment': self.parent.show_lightning_transaction(tx_item) return tx_hash = tx_item['txid'] tx = self.wallet.db.get_transaction(tx_hash) if not tx: return self.show_transaction(tx_item, tx) def show_transaction(self, tx_item, tx): tx_hash = tx_item['txid'] label = self.wallet.get_label_for_txid( tx_hash ) or None # prefer 'None' if not defined (force tx dialog to hide Description field if missing) self.parent.show_transaction(tx, tx_desc=label) def add_copy_menu(self, menu, idx): cc = menu.addMenu(_("Copy")) for column in HistoryColumns: if self.isColumnHidden(column): continue column_title = self.hm.headerData(column, Qt.Horizontal, Qt.DisplayRole) idx2 = idx.sibling(idx.row(), column) column_data = (self.hm.data(idx2, Qt.DisplayRole).value() or '').strip() cc.addAction(column_title, lambda text=column_data, title=column_title: self. place_text_on_clipboard(text, title=title)) return cc def create_menu(self, position: QPoint): org_idx: QModelIndex = self.indexAt(position) idx = self.proxy.mapToSource(org_idx) if not idx.isValid(): # can happen e.g. before list is populated for the first time return tx_item = idx.internalPointer().get_data() if tx_item.get('lightning') and tx_item['type'] == 'payment': menu = QMenu() menu.addAction( _("View Payment"), lambda: self.parent.show_lightning_transaction(tx_item)) cc = self.add_copy_menu(menu, idx) cc.addAction( _("Payment Hash"), lambda: self.place_text_on_clipboard(tx_item['payment_hash'], title="Payment Hash")) cc.addAction( _("Preimage"), lambda: self.place_text_on_clipboard(tx_item['preimage'], title="Preimage")) key = tx_item['payment_hash'] log = self.wallet.lnworker.logs.get(key) if log: menu.addAction( _("View log"), lambda: self.parent.invoice_list.show_log(key, log)) menu.exec_(self.viewport().mapToGlobal(position)) return tx_hash = tx_item['txid'] if tx_item.get('lightning'): tx = self.wallet.lnworker.lnwatcher.db.get_transaction(tx_hash) else: tx = self.wallet.db.get_transaction(tx_hash) if not tx: return tx_URL = block_explorer_URL(self.config, 'tx', tx_hash) tx_details = self.wallet.get_tx_info(tx) is_unconfirmed = tx_details.tx_mined_status.height <= 0 menu = QMenu() if tx_details.can_remove: menu.addAction(_("Remove"), lambda: self.remove_local_tx(tx_hash)) cc = self.add_copy_menu(menu, idx) cc.addAction( _("Transaction ID"), lambda: self.place_text_on_clipboard(tx_hash, title="TXID")) for c in self.editable_columns: if self.isColumnHidden(c): continue label = self.hm.headerData(c, Qt.Horizontal, Qt.DisplayRole) # TODO use siblingAtColumn when min Qt version is >=5.11 persistent = QPersistentModelIndex( org_idx.sibling(org_idx.row(), c)) menu.addAction(_("Edit {}").format(label), lambda p=persistent: self.edit(QModelIndex(p))) menu.addAction(_("View Transaction"), lambda: self.show_transaction(tx_item, tx)) channel_id = tx_item.get('channel_id') if channel_id: menu.addAction( _("View Channel"), lambda: self.parent.show_channel(bytes.fromhex(channel_id))) if is_unconfirmed and tx: if tx_details.can_bump: menu.addAction(_("Increase fee"), lambda: self.parent.bump_fee_dialog(tx)) else: if tx_details.can_cpfp: menu.addAction(_("Child pays for parent"), lambda: self.parent.cpfp_dialog(tx)) if tx_details.can_dscancel: menu.addAction(_("Cancel (double-spend)"), lambda: self.parent.dscancel_dialog(tx)) invoices = self.wallet.get_relevant_invoices_for_tx(tx) if len(invoices) == 1: menu.addAction( _("View invoice"), lambda inv=invoices[0]: self.parent.show_onchain_invoice(inv)) elif len(invoices) > 1: menu_invs = menu.addMenu(_("Related invoices")) for inv in invoices: menu_invs.addAction( _("View invoice"), lambda inv=inv: self.parent.show_onchain_invoice(inv)) if tx_URL: menu.addAction(_("View on block explorer"), lambda: webopen(tx_URL)) menu.exec_(self.viewport().mapToGlobal(position)) def remove_local_tx(self, tx_hash: str): num_child_txs = len(self.wallet.get_depending_transactions(tx_hash)) question = _("Are you sure you want to remove this transaction?") if num_child_txs > 0: question = (_( "Are you sure you want to remove this transaction and {} child transactions?" ).format(num_child_txs)) if not self.parent.question(msg=question, title=_("Please confirm")): return self.wallet.remove_transaction(tx_hash) self.wallet.save_db() # need to update at least: history_list, utxo_list, address_list self.parent.need_update.set() def onFileAdded(self, fn): try: with open(fn) as f: tx = self.parent.tx_from_text(f.read()) except IOError as e: self.parent.show_error(e) return if not tx: return self.parent.save_transaction_into_wallet(tx) def export_history_dialog(self): d = WindowModalDialog(self, _('Export History')) d.setMinimumSize(400, 200) vbox = QVBoxLayout(d) defaultname = os.path.expanduser('~/electrum-history.csv') select_msg = _('Select file to export your wallet transactions to') hbox, filename_e, csv_button = filename_field(self, self.config, defaultname, select_msg) vbox.addLayout(hbox) vbox.addStretch(1) hbox = Buttons(CancelButton(d), OkButton(d, _('Export'))) vbox.addLayout(hbox) #run_hook('export_history_dialog', self, hbox) self.update() if not d.exec_(): return filename = filename_e.text() if not filename: return try: self.do_export_history(filename, csv_button.isChecked()) except (IOError, os.error) as reason: export_error_label = _( "Electrum was unable to produce a transaction export.") self.parent.show_critical(export_error_label + "\n" + str(reason), title=_("Unable to export history")) return self.parent.show_message( _("Your wallet history has been successfully exported.")) def do_export_history(self, file_name, is_csv): hist = self.wallet.get_detailed_history(fx=self.parent.fx) txns = hist['transactions'] lines = [] if is_csv: for item in txns: lines.append([ item['txid'], item.get('label', ''), item['confirmations'], item['bc_value'], item.get('fiat_value', ''), item.get('fee', ''), item.get('fiat_fee', ''), item['date'] ]) with open(file_name, "w+", encoding='utf-8') as f: if is_csv: import csv transaction = csv.writer(f, lineterminator='\n') transaction.writerow([ "transaction_hash", "label", "confirmations", "value", "fiat_value", "fee", "fiat_fee", "timestamp" ]) for line in lines: transaction.writerow(line) else: from electrum.util import json_encode f.write(json_encode(txns)) def get_text_and_userrole_from_coordinate(self, row, col): idx = self.model().mapToSource(self.model().index(row, col)) tx_item = idx.internalPointer().get_data() return self.hm.data(idx, Qt.DisplayRole).value(), get_item_key(tx_item)
class Window(QDialog): def __init__(self): super().__init__() self.title = "PyQt5 Window" self.top = 100 self.left = 100 self.width = 400 self.height = 150 self.lang = "java19" self.setWindowTitle(self.title) self.setFixedSize(self.width, self.height) self.create_layout() vbox_layout = QVBoxLayout() vbox_layout.addWidget(self.group_box) self.setLayout(vbox_layout) self.show() def create_layout(self): vbox_layout = QVBoxLayout() hbox_layout = QHBoxLayout() btn_source = QPushButton("Choose Source", self) btn_source.setMinimumHeight(28) btn_source.clicked.connect(self.click_source_btn) hbox_layout.addWidget(btn_source) btn_destination = QPushButton("Choose Destination", self) btn_destination.setMinimumHeight(28) btn_destination.clicked.connect(self.click_destination_btn) hbox_layout.addWidget(btn_destination) btn_start = QPushButton("Start", self) btn_start.setMinimumHeight(28) btn_start.clicked.connect(self.click_start_btn) hbox_layout.addWidget(btn_start) vbox_layout.addLayout(hbox_layout) self.lang_cb = QComboBox() self.lang_cb.addItems( "java19,java17,java15,java15dm,java12,java11,python3,c/c++,c#-1.2,char,text,scheme" .split(",")) self.lang_cb.currentIndexChanged.connect( self.selection_changed_lang_gb) vbox_layout.addWidget(self.lang_cb) self.group_box = QGroupBox("JPlag Wrapper") self.group_box.setLayout(vbox_layout) def click_source_btn(self): dlg = QFileDialog() dlg.setFileMode(QFileDialog.DirectoryOnly) if dlg.exec_() == QFileDialog.Accepted: self.source_dir = dlg.selectedFiles()[0] logging.info("Source dir: '%s'", dlg.selectedFiles()) print(dlg.selectedFiles()) def click_destination_btn(self): dlg = QFileDialog() dlg.setFileMode(QFileDialog.DirectoryOnly) if dlg.exec_() == QFileDialog.Accepted: self.destination_dir = dlg.selectedFiles()[0] logging.info("Destination dir: '%s'", dlg.selectedFiles()) print(dlg.selectedFiles()) def click_start_btn(self): logging.info("JPlag started with source: '%s' and destination: '%s'", self.source_dir, self.destination_dir) print("Started with source: {} and destination: {}".format( self.source_dir, self.destination_dir)) jplag_process = subprocess.run( f"java -jar ./jplag.jar -l {self.lang} -s '{self.source_dir}' -r '{self.destination_dir}'", shell=True, stdout=subprocess.PIPE) with open("jplag_output.txt", "w") as jplag_output_fd: jplag_output_fd.write(jplag_process.stdout.decode()) logging.info("JPlag completed.") print("JPlag completed.") def selection_changed_lang_gb(self, i): logging.info("Selection changed to %s", self.lang_cb.currentText()) print("Selection changed to", self.lang_cb.currentText()) self.lang = self.lang_cb.currentText()
class WidgetGallery(QDialog): def __init__(self, parent=None): super(WidgetGallery, self).__init__(parent) QApplication.setStyle(QStyleFactory.create('Fusion')) QApplication.setPalette(QApplication.style().standardPalette()) self.tabGroupboxes = [] self.savePath = "" self.logMessages = "" self.setDarkMode() self.createSeasonsGroupBox() self.createExportGroupBox() self.createLogGroupBox() self.createSchemaTabWidget() self.createRequestsGroupBox() self.createProgressBar() self.initiateLogWatcher() mainLayout = QGridLayout() mainLayout.addWidget(self.schemaGroupBox, 0, 0, 3, 1) mainLayout.addWidget(self.seasonsGroupBox, 0, 1, 1, 1) mainLayout.addWidget(self.exportGroupBox, 1, 1, 1, 1) mainLayout.addWidget(self.requestsGroupBox, 2, 1, 1, 1) mainLayout.addWidget(self.logGroupBox, 3, 0, 1, 2) mainLayout.addWidget(self.progressBar, 4, 0, 1, 2) mainLayout.setRowStretch(1, 1) mainLayout.setRowStretch(2, 1) mainLayout.setColumnStretch(0, 1) mainLayout.setColumnStretch(1, 1) self.setLayout(mainLayout) self.setWindowTitle("MLB Data Fetch") def setDarkMode(self): palette = QPalette() palette.setColor(QPalette.Window, QColor(53, 53, 53)) palette.setColor(QPalette.WindowText, Qt.white) palette.setColor(QPalette.Base, QColor(25, 25, 25)) palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) palette.setColor(QPalette.ToolTipBase, Qt.white) palette.setColor(QPalette.ToolTipText, Qt.white) palette.setColor(QPalette.Text, Qt.white) palette.setColor(QPalette.Button, QColor(53, 53, 53)) palette.setColor(QPalette.ButtonText, Qt.white) palette.setColor(QPalette.BrightText, Qt.red) palette.setColor(QPalette.Link, QColor(42, 130, 218)) palette.setColor(QPalette.Highlight, QColor(42, 130, 218)) palette.setColor(QPalette.HighlightedText, Qt.black) app.setPalette(palette) def chooseFilePath(self): self.savePath = str( QFileDialog.getExistingDirectory(self, "Select Directory")) self.savePathLabel.setText(self.savePath) def validateSettings(self): error = "" if int(self.seasonsBeginComboBox.currentText()) > int( self.seasonsEndComboBox.currentText()): error += "Invalid seasons range.\n" if self.savePath == "": error += "No save directory chosen.\n" if error != "": msgbox = QMessageBox() msgbox.setFixedWidth(800) msgbox.setWindowTitle("Error") msgbox.setIcon(QMessageBox.Critical) msgbox.setText(error) msgbox.exec_() return False else: return True def fetchData(self): tables = [] for groupbox in self.tabGroupboxes: if groupbox.isChecked(): table = groupbox.objectName() cols = [] checkboxes = groupbox.findChildren(QWidget) for checkbox in checkboxes: if checkbox.isChecked(): cols.append(checkbox.objectName()) tables.append({"tableName": table, "cols": cols}) seasons = [] for i in range(int(self.seasonsBeginComboBox.currentText()), int(self.seasonsEndComboBox.currentText()) + 1): seasons.append(i) minSec = self.minSpinBox.value() maxSec = self.maxSpinBox.value() csv = True if csv: for table in tables: # Team and Venue are not based on season, so just get this data once if table["tableName"] == "Team": fetch.export_team_data(table["cols"], self.savePath) self.logMessages += "Team data written to " + self.savePath + "/Team.csv\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "Venue": fetch.export_venue_data(table["cols"], self.savePath) self.logMessages += "Venue data written to " + self.savePath + "/Venue.csv\n" sleep(randint(minSec, maxSec)) for season in seasons: for table in tables: if table["tableName"] == "Player": fetch.export_player_data(season, table["cols"], self.savePath) self.logMessages += "Player data written to " + self.savePath + "/Player" + str( season) + ".csv\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "Schedule": fetch.export_schedule_data(season, table["cols"], self.savePath) self.logMessages += "Schedule data written to " + self.savePath + "/Schedule" + str( season) + ".csv\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "Game": fetch.export_game_data(season, table["cols"], self.savePath) self.logMessages += "Game data written to " + self.savePath + "/Game" + str( season) + ".csv\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "MlbBoxscoreBatting": fetch.export_boxscore_data(season, table["cols"], minSec, maxSec, self.savePath) self.logMessages += "Boxscore data written to " + self.savePath + "/MlbBoxscoreBatting" + str( season) + ".csv\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "MlbBoxscorePitching": fetch.export_boxscore_pitching_data( season, table["cols"], minSec, maxSec, self.savePath) self.logMessages += "Boxscore data written to " + self.savePath + "/MlbBoxscorePitching" + str( season) + ".csv\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "PlayByPlay": fetch.export_pbp_data(season, table["cols"], minSec, maxSec, self.savePath) self.logMessages += "PlayByPlay data written to " + self.savePath + "/PlayByPlay" + str( season) + ".csv\n" sleep(randint(minSec, maxSec)) else: for table in tables: # Team and Venue are not based on season, so just get this data once if table["tableName"] == "Team": fetch.export_team_data(table["cols"], self.savePath) self.logMessages += "Team data written to " + self.savePath + "/Team.xls\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "Venue": fetch.export_venue_data(table["cols"], self.savePath) self.logMessages += "Venue data written to " + self.savePath + "/Venue.xls\n" sleep(randint(minSec, maxSec)) for season in seasons: for table in tables: if table["tableName"] == "Player": fetch.export_player_data(season, table["cols"], self.savePath) self.logMessages += "Player data written to " + self.savePath + "/Player" + str( season) + ".xls\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "Schedule": fetch.export_schedule_data(season, table["cols"], self.savePath) self.logMessages += "Schedule data written to " + self.savePath + "/Schedule" + str( season) + ".xls\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "Game": fetch.export_game_data(season, table["cols"], self.savePath) self.logMessages += "Game data written to " + self.savePath + "/Game" + str( season) + ".xls\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "MlbBoxscoreBatting": fetch.export_boxscore_data(season, table["cols"], minSec, maxSec, self.savePath) self.logMessages += "MlbBoxscoreBatting data written to " + self.savePath + "/MlbBoxscoreBatting" + str( season) + ".xls\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "MlbBoxscorePitching": fetch.export_boxscore_pitching_data( season, table["cols"], minSec, maxSec, self.savePath) self.logMessages += "MlbBoxscorePitching data written to " + self.savePath + "/MlbBoxscoreBatting" + str( season) + ".xls\n" sleep(randint(minSec, maxSec)) if table["tableName"] == "PlayByPlay": fetch.export_pbp_data(season, table["cols"], minSec, maxSec, self.savePath) self.logMessages += "PlayByPlay data written to " + self.savePath + "/PlayByPlay" + str( season) + ".xls\n" sleep(randint(minSec, maxSec)) def goButtonClicked(self): validSettings = self.validateSettings() if validSettings: thread = Thread(target=self.fetchData, daemon=True) thread.start() def advanceProgressBar(self): curVal = self.progressBar.value() maxVal = self.progressBar.maximum() self.progressBar.setValue(curVal + (maxVal - curVal) / 100) def createSeasonsGroupBox(self): self.seasonsGroupBox = QGroupBox("Seasons") topLayout = QHBoxLayout() seasons = [ "2005", "2006", "2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019" ] self.seasonsBeginComboBox = QComboBox() self.seasonsBeginComboBox.addItems(seasons) self.seasonsEndComboBox = QComboBox() self.seasonsEndComboBox.addItems(seasons) seasonsLabel = QLabel("Range:") seasonsLabel.setGeometry(QRect(10, 10, 20, 20)) seasonsLabel.setBuddy(self.seasonsBeginComboBox) toLabel = QLabel("to") toLabel.setGeometry(QRect(70, 10, 20, 20)) toLabel.setBuddy(self.seasonsEndComboBox) topLayout.addWidget(seasonsLabel) topLayout.addWidget(self.seasonsBeginComboBox) topLayout.addWidget(toLabel) topLayout.addWidget(self.seasonsEndComboBox) topLayout.addStretch(1) seasonsLayout = QGridLayout() seasonsLayout.addLayout(topLayout, 0, 0, 1, 1) self.seasonsGroupBox.setLayout(seasonsLayout) def createExportGroupBox(self): self.exportGroupBox = QGroupBox("Export") pathButton = QPushButton("Choose file path") pathButton.clicked.connect(self.chooseFilePath) self.savePathLabel = QLabel("") radioButton1 = QRadioButton(".xls") radioButton2 = QRadioButton(".csv") radioButton1.setChecked(True) layout = QVBoxLayout() layout.addWidget(pathButton) layout.addWidget(self.savePathLabel) layout.addWidget(radioButton1) layout.addWidget(radioButton2) layout.addStretch(1) self.exportGroupBox.setLayout(layout) def createLogGroupBox(self): self.logGroupBox = QGroupBox("Log") self.logTextbox = QTextEdit() #self.logTextbox.setDisabled(True) self.logTextbox.setReadOnly(True) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.logTextbox) layout.addStretch(1) self.logGroupBox.setLayout(layout) def createSchemaTabWidget(self): self.schemaGroupBox = QGroupBox("Data") layout = QVBoxLayout() self.schemaTabWidget = QTabWidget() self.schemaTabWidget.setMinimumHeight(300) self.schemaTabWidget.setMinimumWidth(380) self.tabs = [ "Team", "Venue", "Player", "Schedule", "Game", "MlbBoxscoreBatting", "MlbBoxscorePitching", "PlayByPlay" ] self.props = [ [ "MlbTeamID", "TeamName", "MlbVenueID", "TeamAbbrev", "LocationName", "MlbLeagueID", "MlbDivisionID" ], ["MlbVenueID", "VenueName"], [ "MlbPlayerID", "Season", "FullName", "FirstName", "LastName", "BirthDate", "PlayerHeight", "PlayerWeight", "MlbTeamID", "Position", "DebutDate", "BatSide", "PitchHand" ], [ "MlbScheduleID", "MlbGameID", "GameDateTime", "GameDate", "GameTime", "AwayTeamID", "HomeTeamID", "MlbVenueID" ], [ "MlbGameID", "Season", "GameDateTime", "GameDate", "GameTime", "Status", "AwayTeamID", "AwayTeamScore", "AwayTeamRecordWins", "AwayTeamRecordLosses", "AwayTeamRecordPct", "HomeTeamID", "HomeTeamScore", "HomeTeamRecordWins", "HomeTeamRecordLosses", "HomeTeamRecordPct", "VenueID", "DayNight", "GamesInSeries", "SeriesGameNumber", "SeriesDescription" ], [ "MlbBoxscoreBattingID", "MlbPlayerID", "MlbGameID", "AwayTeamID", "HomeTeamID", "IsAway", "BattingOrder", "AB", "R", "H", "2B", "3B", "HR", "RBI", "BB", "IBB", "SO", "HBP", "SH", "SF", "GDP", "SB", "CS" ], [ "MlbBoxscorePitchingID", "MlbPlayerID", "MlbGameID", "AwayTeamID", "HomeTeamID", "IsAway", "StartedGame", "Win", "IP", "H", "R", "ER", "ERA", "SO", "HR", "BB", "HBP", "CompleteGame", "Shutout", "PitchCount" ], [ "PlayByPlayID", "GameID", "BatterID", "BatSide", "PitcherID", "PitchHand", "MenOnBase", "Event", "EventType", "IsScoringPlay", "AwayTeamScore", "HomeTeamScore", "AtBatIndex", "HalfInning", "Inning", "Outs" ] ] for i in range(len(self.tabs)): tab = QWidget() tabVbox = QVBoxLayout() tabVbox.setContentsMargins(5, 5, 5, 5) tabGroupbox = QGroupBox(self.tabs[i]) tabGroupbox.setObjectName(self.tabs[i]) tabGroupbox.setCheckable(True) tabGroupbox.setChecked(True) tabGroupbox.setContentsMargins(5, 5, 5, 5) self.tabGroupboxes.append(tabGroupbox) cols = self.props[i] x_offset = 0 y_multiplier = 0 for j in range(len(cols)): if j == 10: x_offset = 175 y_multiplier = 0 checkbox = QCheckBox(tabGroupbox) checkbox.setGeometry( QRect(20 + x_offset, 35 + (20 * y_multiplier), 150, 17)) checkbox.setObjectName(cols[j]) checkbox.setText(cols[j]) checkbox.setChecked(True) y_multiplier += 1 tabVbox.addWidget(tabGroupbox) tab.setLayout(tabVbox) self.schemaTabWidget.addTab(tab, self.tabs[i]) layout.addWidget(self.schemaTabWidget) self.schemaGroupBox.setLayout(layout) def createRequestsGroupBox(self): self.requestsGroupBox = QGroupBox("Make Requests") self.requestsGroupBox.setMinimumWidth(380) topLayout = QHBoxLayout() self.minSpinBox = QSpinBox() self.minSpinBox.setValue(5) self.maxSpinBox = QSpinBox() self.maxSpinBox.setValue(15) waitTimeLabel = QLabel("Wait") waitTimeLabel.setGeometry(QRect(10, 10, 20, 20)) waitTimeLabel.setBuddy(self.minSpinBox) toLabel = QLabel("to") toLabel.setGeometry(QRect(70, 10, 20, 20)) toLabel.setBuddy(self.maxSpinBox) secondsLabel = QLabel("seconds between requests.") secondsLabel.setGeometry(QRect(130, 10, 20, 20)) topLayout.addWidget(waitTimeLabel) topLayout.addWidget(self.minSpinBox) topLayout.addWidget(toLabel) topLayout.addWidget(self.maxSpinBox) topLayout.addWidget(secondsLabel) topLayout.addStretch(1) middleLayout = QHBoxLayout() estimatedTimeLabel = QLabel("Estimated run time:") middleLayout.addWidget(estimatedTimeLabel) middleLayout.addStretch(1) bottomLayout = QHBoxLayout() goButton = QPushButton("Go") goButton.setMinimumHeight(30) goButton.setMinimumWidth(300) goButton.clicked.connect(lambda: self.goButtonClicked()) bottomLayout.addWidget(goButton) requestsLayout = QGridLayout() requestsLayout.addLayout(topLayout, 0, 0, 1, 1) requestsLayout.addLayout(middleLayout, 1, 0, 1, 1) requestsLayout.addLayout(bottomLayout, 2, 0, 1, 1) self.requestsGroupBox.setLayout(requestsLayout) def lol(self): self.logTextbox.setText(self.logMessages) def createProgressBar(self): self.progressBar = QProgressBar() self.progressBar.setRange(0, 10000) self.progressBar.setValue(0) timer = QTimer(self) timer.timeout.connect(self.advanceProgressBar) timer.start(1000) def initiateLogWatcher(self): logTimer = QTimer(self) logTimer.timeout.connect(self.lol) logTimer.start(3000)
class BookManage(QGroupBox): def __init__(self): super().__init__() self.book_list = [] self.body = QVBoxLayout() self.table = None self.setTitleBar() self.setSearchBar() self.searchFunction() self.setLayout(self.body) self.initUI() def errorBox(self, mes: str): msgBox = QMessageBox( QMessageBox.Warning, "警告!", mes, QMessageBox.NoButton, self ) msgBox.addButton("确认", QMessageBox.AcceptRole) msgBox.exec_() # 标题栏 def setTitleBar(self): self.title = QLabel() self.title.setText('书籍信息管理') self.title.setFixedHeight(25) titleLayout = QHBoxLayout() titleLayout.addSpacing(50) titleLayout.addWidget(self.title) self.titleBar = QWidget() self.titleBar.setFixedSize(1000, 50) self.titleBar.setLayout(titleLayout) self.body.addWidget(self.titleBar) # 设置搜索框 def setSearchBar(self): self.selectBox = QComboBox() self.selectBox.addItems(['书号', '分类', '出版社', '作者', '书名']) self.selectBox.setFixedHeight(30) self.searchTitle = QLabel() self.searchTitle.setText('搜索书籍') self.searchInput = QLineEdit() self.searchInput.setText('') self.searchInput.setClearButtonEnabled(True) self.searchInput.setFixedSize(400, 40) self.searchButton = QToolButton() self.searchButton.setFixedSize(100, 40) self.searchButton.setText('搜索') self.searchButton.clicked.connect(self.searchFunction) self.addNewBookButton = QToolButton() self.addNewBookButton.setFixedSize(120, 40) self.addNewBookButton.setText('插入新书') self.addNewBookButton.clicked.connect(self.addNewBookFunction) searchLayout = QHBoxLayout() searchLayout.addStretch() searchLayout.addWidget(self.selectBox) searchLayout.addWidget(self.searchTitle) searchLayout.addWidget(self.searchInput) searchLayout.addWidget(self.searchButton) searchLayout.addWidget(self.addNewBookButton) searchLayout.addStretch() self.searchWidget = QWidget() self.searchWidget.setLayout(searchLayout) self.body.addWidget(self.searchWidget) # 搜索方法 def searchFunction(self): convert = {'书号': 'BID', '分类': 'CLASSIFICATION', '出版社': 'PRESS', '作者': 'AUTHOR', '书名': 'BNAME', '': 'BNAME'} self.book_list = database.search_book(self.searchInput.text(), convert[self.selectBox.currentText()]) if self.book_list == []: self.errorBox('未找到') if self.table is not None: self.table.deleteLater() self.setTable() # 设置表格 def setTable(self): self.table = QTableWidget(1, 9) self.table.setContentsMargins(10, 10, 10, 10) self.table.verticalHeader().setVisible(False) self.table.horizontalHeader().setVisible(False) self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.table.setFocusPolicy(Qt.NoFocus) self.table.setColumnWidth(0, 80) # self.table.setColumnWidth(1, 150) # self.table.setColumnWidth(2, 125) # self.table.setColumnWidth(3, 125) # self.table.setColumnWidth(4, 100) self.table.setColumnWidth(6, 80) self.table.setItem(0, 0, QTableWidgetItem('书号')) self.table.setItem(0, 1, QTableWidgetItem('书名')) self.table.setItem(0, 2, QTableWidgetItem('作者')) self.table.setItem(0, 3, QTableWidgetItem('出版日期')) self.table.setItem(0, 4, QTableWidgetItem('出版社')) self.table.setItem(0, 5, QTableWidgetItem('分类')) self.table.setItem(0, 6, QTableWidgetItem('位置')) self.table.setItem(0, 7, QTableWidgetItem('总数/剩余')) self.table.setItem(0, 8, QTableWidgetItem('操作')) for i in range(9): self.table.item(0, i).setTextAlignment(Qt.AlignCenter) self.table.item(0, i).setFont(QFont('微软雅黑', 15)) # 显示借阅详情 for i in self.book_list: self.insertRow(i) self.body.addWidget(self.table) # 插入行 def insertRow(self, val: list): itemBID = QTableWidgetItem(val[0]) itemBID.setTextAlignment(Qt.AlignCenter) itemNAME = QTableWidgetItem('《' + val[1] + '》') itemNAME.setTextAlignment(Qt.AlignCenter) itemAUTHOR = QTableWidgetItem(val[2]) itemAUTHOR.setTextAlignment(Qt.AlignCenter) itemDATE = QTableWidgetItem(val[3]) itemDATE.setTextAlignment(Qt.AlignCenter) itemPRESS = QTableWidgetItem(val[4]) itemPRESS.setTextAlignment(Qt.AlignCenter) itemPOSITION = QTableWidgetItem(val[5]) itemPOSITION.setTextAlignment(Qt.AlignCenter) itemSUM = QTableWidgetItem(str(val[6])+'/'+str(val[7])) itemSUM.setTextAlignment(Qt.AlignCenter) itemCLASSIFICATION = QTableWidgetItem(val[8]) itemCLASSIFICATION.setTextAlignment(Qt.AlignCenter) itemModify = QToolButton(self.table) itemModify.setFixedSize(50, 25) itemModify.setText('修改') itemModify.clicked.connect(lambda: self.updateBookFunction(val[0])) itemModify.setStyleSheet(''' *{ color: white; font-family: 微软雅黑; background: rgba(38, 175, 217, 1); border: 0; border-radius: 10px; } ''') itemDelete = QToolButton(self.table) itemDelete.setFixedSize(50, 25) itemDelete.setText('删除') itemDelete.clicked.connect(lambda: self.deleteBookFunction(val[0])) itemDelete.setStyleSheet(''' *{ color: white; font-family: 微软雅黑; background: rgba(222, 52, 65, 1); border: 0; border-radius: 10px; } ''') itemLayout = QHBoxLayout() itemLayout.setContentsMargins(0, 0, 0, 0) itemLayout.addWidget(itemModify) itemLayout.addWidget(itemDelete) itemWidget = QWidget() itemWidget.setLayout(itemLayout) self.table.insertRow(1) self.table.setItem(1, 0, itemBID) self.table.setItem(1, 1, itemNAME) self.table.setItem(1, 2, itemAUTHOR) self.table.setItem(1, 3, itemDATE) self.table.setItem(1, 4, itemPRESS) self.table.setItem(1, 5, itemCLASSIFICATION) self.table.setItem(1, 6, itemPOSITION) self.table.setItem(1, 7, itemSUM) self.table.setCellWidget(1, 8, itemWidget) def updateBookFunction(self, BID: str): book_info = database.get_book_info(BID) if book_info is None: return self.sum = book_info['SUM'] self.updateBookDialog = book_information.BookInfo(book_info) self.updateBookDialog.after_close.connect(self.updateBook) self.updateBookDialog.show() def updateBook(self, book_info: dict): change = self.sum - book_info['SUM'] # 书本减少的数量不能大于未借出的书本数 if change > book_info['NUM']: book_info['SUM'] = self.sum - book_info['NUM'] book_info['NUM'] = 0 else: book_info['NUM'] -= change ans = database.update_book(book_info) if ans: self.searchFunction() def addNewBookFunction(self): self.newBookDialog = book_information.BookInfo() self.newBookDialog.show() self.newBookDialog.after_close.connect(self.addNewBook) def addNewBook(self, book_info: dict): ans = database.new_book(book_info) if ans: self.searchFunction() def deleteBookFunction(self, BID: str): msgBox = QMessageBox(QMessageBox.Warning, "警告!", '您将会永久删除这本书以及相关信息!', QMessageBox.NoButton, self) msgBox.addButton("确认", QMessageBox.AcceptRole) msgBox.addButton("取消", QMessageBox.RejectRole) if msgBox.exec_() == QMessageBox.AcceptRole: ans = database.delete_book(BID) if ans: self.searchFunction() def initUI(self): self.setFixedSize(1100, 600) self.setStyleSheet(''' *{ background-color: white; border:0px; } ''') self.titleBar.setStyleSheet(''' QWidget { border:0; background-color: rgba(216, 216, 216, 1); border-radius: 20px; color: rgba(113, 118, 121, 1); } QLabel{ font-size: 25px; font-family: 微软雅黑; } ''') self.searchTitle.setStyleSheet(''' QLabel{ font-size:25px; color: black; font-family: 微软雅黑; } ''') self.searchInput.setStyleSheet(''' QLineEdit{ border: 1px solid rgba(201, 201, 201, 1); border-radius: 5px; color: rgba(120, 120, 120, 1) } ''') self.searchButton.setStyleSheet(''' QToolButton{ border-radius: 10px; background-color:rgba(135, 206, 235, 1); color: white; font-size: 25px; font-family: 微软雅黑; } ''') self.addNewBookButton.setStyleSheet(''' QToolButton{ border-radius: 10px; background-color:rgba(135, 206, 235, 1); color: white; font-size: 25px; font-family: 微软雅黑; } ''') self.selectBox.setStyleSheet(''' *{ border: 0px; } QComboBox{ border: 1px solid rgba(201, 201, 201, 1); } ''')
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 MyWindow(QMainWindow): def __init__(self, parent=None): super(MyWindow, self).__init__() self.setObjectName("MediathekQuery") self.root = QFileInfo(__file__).absolutePath() self.setAttribute(Qt.WA_DeleteOnClose) self.settings = QSettings('Axel Schneider', self.objectName()) self.viewer = QTableWidget() self.horizontalHeader = self.viewer.horizontalHeader() icon = self.root + "/icon.png" self.titleList = [] self.topicList = [] self.urlList = [] self.urlKleinList = [] self.beschreibungList = [] self.idList = [] self.chList = [] self.lengthList = [] self.results = "" self.myurl = "" self.fname = "" self.viewer.setSelectionBehavior(QAbstractItemView.SelectRows) self.viewer.SelectionMode(QAbstractItemView.SingleSelection) self.viewer.setSortingEnabled(False) self.viewer.verticalHeader().setStretchLastSection(False) self.viewer.horizontalHeader().setStretchLastSection(True) self.viewer.setColumnCount(7) self.viewer.setColumnWidth(0, 48) self.viewer.setColumnWidth(1, 130) self.viewer.setColumnWidth(2, 160) self.viewer.setColumnWidth(3, 60) self.viewer.hideColumn(4) self.viewer.hideColumn(5) self.viewer.setHorizontalHeaderLabels(["Sender", "Thema", "Titel", "Länge", "HD", "SD", "Beschreibung"]) self.viewer.verticalHeader().setVisible(True) self.viewer.horizontalHeader().setVisible(True) self.setStyleSheet(stylesheet(self)) self.viewer.selectionModel().selectionChanged.connect(self.getCellText) self.layout = QGridLayout() self.layout.addWidget(self.viewer,0, 0, 1, 7) self.findfield = QLineEdit() self.fAction = QAction(QIcon.fromTheme("edit-clear"), "", triggered = self.findfieldAction) self.findfield.addAction(self.fAction, 1) self.findfield.returnPressed.connect(self.myQuery) self.findfield.setFixedWidth(200) self.findfield.setPlaceholderText("suchen ...") self.findfield.setToolTip("ENTER to find") self.layout.addWidget(self.findfield,1, 0) self.chCombo = QComboBox() self.chCombo.setFixedWidth(80) self.chCombo.addItems(['ARD', 'ZDF', 'MDR', 'PHOENIX', 'RBB', 'BR', 'HR', 'SR', \ 'SWR', 'NDR', 'DW', 'WDR', 'ARTE', '3SAT', 'KIKA', 'ORF', 'SRF']) self.chCombo.addItem("alle") self.chCombo.setToolTip("Sender wählen") self.chCombo.currentIndexChanged.connect(self.myQuery) self.layout.addWidget(self.chCombo,1, 1) self.btnPlay = QPushButton("Play") self.btnPlay.setFixedWidth(80) self.btnPlay.setIcon(QIcon.fromTheme("media-playback-start")) self.layout.addWidget(self.btnPlay,1, 2) self.btnPlay.clicked.connect(self.playVideo) self.btnDownload = QPushButton("Download") self.btnDownload.setFixedWidth(100) self.btnDownload.setIcon(QIcon.fromTheme("download")) self.layout.addWidget(self.btnDownload,1, 3) self.btnDownload.clicked.connect(self.downloadVideo) self.chBox = QPushButton("SD") self.chBox.setToolTip("umschalten HD / SD") self.chBox.setStyleSheet("background: #729fcf;") self.chBox.setFixedWidth(44) self.chBox.clicked.connect(self.toggleQuality) self.layout.addWidget(self.chBox,1, 4) self.lbl = QLabel("Info") self.layout.addWidget(self.lbl,1, 5) self.chkbox = QCheckBox("nach Filmlänge sortieren") self.layout.addWidget(self.chkbox,1, 6) self.chkbox.setCheckState(0) self.chkbox.setToolTip("Standard-Sortierung ist nach Erscheinungsdatum") self.chkbox.stateChanged.connect(self.myQuery) self.myWidget = QWidget() self.myWidget.setLayout(self.layout) self.msg("Ready") self.setCentralWidget(self.myWidget) self.setWindowIcon(QIcon(icon)) self.setGeometry(20,20,600,450) self.setWindowTitle("Mediathek Suche") self.readSettings() self.msg("Ready") self.findfield.setFocus() self.player = MediathekPlayer.VideoPlayer('') self.player.hide() wildcards = "Wildcards: + Titel # Thema * Beschreibung\n '<xx Suchbegriff' kleiner als xx Minuten '>xx Suchbegriff' grösser als xx Minuten " help_label = QLabel(wildcards) help_label.setToolTip("ohne Wildcard werden alle Felder durchsucht") help_label.setStyleSheet("font-size: 8pt; color: #1a2334;") self.statusBar().addPermanentWidget(help_label) self.statusBar().showMessage("Ready") def toggleQuality(self): if self.chBox.text() == "SD": self.chBox.setText("HD") self.chBox.setStyleSheet("background: #8ae234;") self.getCellText() else: self.chBox.setText("SD") self.chBox.setStyleSheet("background: #729fcf;") self.getCellText() def myQuery(self): if not self.findfield.text() == "": self.viewer.setRowCount(0) self.viewer.clearContents() self.titleList = [] self.topicList = [] self.urlList = [] self.urlKleinList = [] self.beschreibungList = [] self.idList = [] self.chList = [] self.lengthList = [] channels = [self.chCombo.currentText()] if channels == ["alle"]: channels = ["ard", "zdf", "mdr", "phoenix", "rbb", "br", "hr", "sr", "swr", "ndr",\ "dw", "wdr", "arte", "3sat", "kika", "orf", "srf"] print("suche", self.findfield.text(), "in", ','.join(channels).upper()) if self.findfield.text().startswith("*"): ### nur Beschreibung for ch in channels: r = self.makeQueryBeschreibung(ch, self.findfield.text()[1:]) elif self.findfield.text().startswith("#"): ### nur Thema for ch in channels: r = self.makeQueryTopic(ch, self.findfield.text()[1:]) elif self.findfield.text().startswith("+"): ### nur Titel for ch in channels: r = self.makeQueryTitle(ch, self.findfield.text()[1:]) elif self.findfield.text().startswith(">"): ### Zeit grösser for ch in channels: r = self.makeQueryBigger(ch, self.findfield.text()) elif self.findfield.text().startswith("<"): ### Zeit kleiner for ch in channels: r = self.makeQuerySmaller(ch, self.findfield.text()) else: ### alle Felder for ch in channels: r = self.makeQuery(ch, self.findfield.text()) for b in range(len(self.titleList)): self.idList.append(str(b)) self.viewer.setSortingEnabled(False) for x in range(len(self.titleList)): self.viewer.insertRow(x) self.viewer.setItem(x, 0, QTableWidgetItem(self.chList[x])) self.viewer.setItem(x, 1, QTableWidgetItem(self.topicList[x])) self.viewer.setItem(x, 2, QTableWidgetItem(self.titleList[x])) self.viewer.setItem(x, 3, QTableWidgetItem(self.lengthList[x])) self.viewer.setItem(x, 4, QTableWidgetItem(self.urlList[x])) self.viewer.setItem(x, 5, QTableWidgetItem(self.urlKleinList[x])) self.viewer.setItem(x, 6, QTableWidgetItem(self.beschreibungList[x])) for x in range(len(self.titleList)): self.viewer.resizeRowToContents(x) def makeQuery(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } if self.chkbox.checkState() == 2: data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} else: data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") def makeQueryBeschreibung(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \ "queries":[{"fields":["description"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") def makeQueryTopic(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \ "queries":[{"fields":["topic"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") def makeQueryTitle(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"desc", \ "queries":[{"fields":["title"], "query":"" + myquery + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) self.lengthList.append(length) else: self.lengthList.append("") ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") ####################################################################### def makeQueryBigger(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } if self.chkbox.checkState() == 2: data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \ "queries":[{"fields":["duration"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} else: data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) mydur = myquery[1:].partition(" ")[0] hour = time.strftime('%H', time.gmtime(l)) minute = time.strftime('%M', time.gmtime(l)) dur = int(hour) * 60 + int(minute) if dur > int(mydur) - 1: self.lengthList.append(length) ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") ####################################################################### def makeQuerySmaller(self, channel, myquery): headers = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0', 'Accept': '*/*', 'Accept-Language': 'de-DE,en;q=0.5', 'Content-Type': 'text/plain;charset=UTF-8', 'Connection': 'keep-alive', } if self.chkbox.checkState() == 2: data = {"future":"true", "size":"500", "sortBy":"duration", "sortOrder":"desc", \ "queries":[{"fields":["duration"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} else: data = {"future":"true", "size":"500", "sortBy":"timestamp", "sortOrder":"asc", \ "queries":[{"fields":["title", "topic", "description"], "query":"" + myquery[1:].partition(" ")[2] + ""},{"fields":["channel"], "query":"" + channel + ""}]} response = requests.post('https://mediathekviewweb.de/api/query', headers=headers, json=data) response_json = response.json() count = int(response_json['result']['queryInfo']['resultCount']) for x in range(count): topic = response_json['result']['results'][x]['topic'] title = response_json['result']['results'][x]['title'] url = response_json['result']['results'][x]['url_video'] url_klein = response_json['result']['results'][x]['url_video_low'] beschreibung = response_json['result']['results'][x]['description'] l = response_json['result']['results'][x]['duration'] if not l == "": length = time.strftime('%H:%M:%S', time.gmtime(l)) mydur = myquery[1:].partition(" ")[0] hour = time.strftime('%H', time.gmtime(l)) minute = time.strftime('%M', time.gmtime(l)) dur = int(hour) * 60 + int(minute) if dur < int(mydur): self.lengthList.append(length) ch = response_json['result']['results'][x]['channel'] if not ch == "": self.chList.append(ch) else: self.chList.append("") if not title == "": self.titleList.append(title) else: self.titleList.append("") if not topic == "": self.topicList.append(topic) else: self.topicList.append("") if not url == "": self.urlList.append(url) else: self.urlList.append("") if not url_klein == "": self.urlKleinList.append(url_klein) else: self.urlKleinList.append("") if not beschreibung == "": self.beschreibungList.append(beschreibung) else: self.beschreibungList.append("") print(count, "Beiträge gefunden") self.lbl.setText(f"{count} Beiträge gefunden") ####################################################################### def findfieldAction(self): self.findfield.setText("") def downloadVideo(self): if not self.url == "": self.downloader = Downloader.Downloader() self.downloader.setWindowTitle("Downloader") self.downloader.url = self.url item = self.viewer.selectedIndexes()[2] if not item == "": filename = str(item.data()) self.downloader.fname = filename + self.url[-4:] self.downloader.fname = self.downloader.fname.replace(' (', '_').replace(') ', '_')\ .replace(')', '_').replace('/', '_') if '_.' in self.downloader.fname: self.downloader.fname = self.downloader.fname.replace('_.', '.') self.downloader.lbl.setText("speichern als: " + self.downloader.homepath + self.downloader.fname) self.downloader.move(self.x() + 2, self.y() + 28) self.downloader.show() else: print("keine URL") self.msg("keine URL") def getCellText(self): if self.viewer.selectionModel().hasSelection(): row = self.selectedRow() if not self.chBox.text() == "SD": item = self.urlList[row] else: item = self.urlKleinList[row] if not item == "": name = item self.url = str(item) QApplication.clipboard().setText(self.url) print(self.url) infotext = f"{self.chList[row]}: {self.topicList[row]} - {self.titleList[row]} \ ({self.chBox.text()}) Dauer: {self.lengthList[row]}" self.msg(infotext) self.fname = str(self.viewer.selectedIndexes()[1].data()) def playVideo(self): if self.viewer.selectionModel().hasSelection(): row = self.selectedRow() if not self.chBox.text() == "SD": item = item = self.urlList[row] print("play HD") else: item = self.urlKleinList[row] print("play SD") if not item == "": self.url = item if not self.url == "": print("url =", self.url) self.player.show() self.player.playMyURL(self.url) else: print("keine URL vorhanden") self.msg("keine URL vorhanden") else: print("keine URL vorhanden") else: print("keine URL vorhanden") def selectedRow(self): if self.viewer.selectionModel().hasSelection(): row = self.viewer.selectionModel().selectedIndexes()[0].row() return int(row) def closeEvent(self, e): self.writeSettings() self.player.close() e.accept() def readSettings(self): print("lese Fensterposition") if self.settings.contains('geometry'): self.setGeometry(self.settings.value('geometry')) def writeSettings(self): print("Fensterposition gespeichert") self.settings.setValue('geometry', self.geometry()) def msg(self, message): self.statusBar().showMessage(message, 0)
class DyStockHistDaysDataSourceConfigDlg(QDialog): tradeDaysMode = OrderedDict\ ([ ('Wind和TuShare相互验证(默认)', 'Verify'), ('若冲突,则以Wind为主', 'Wind'), ('若冲突,则以TuShare为主', 'TuShare'), ]) def __init__(self, parent=None): super().__init__(parent) self._read() self._initUi() def _initUi(self): self.setWindowTitle('配置-股票历史日线数据源') # 控件 label = QLabel('股票历史日线数据源') self._windCheckBox = QCheckBox('Wind') self._windCheckBox.clicked.connect(self._windCheckBoxClicked) self._tuShareCheckBox = QCheckBox('TuShare') self._tuShareCheckBox.clicked.connect(self._tuShareCheckBoxClicked) self._tuShareProCheckBox = QCheckBox('TuSharePro') tuShareProTokenLabel = QLabel('TuSharePro token') self._tuShareProTokenLineEdit = QLineEdit() description = """默认使用Wind 只选Wind:更新交易日数据,股票代码表和股票历史日线数据到Wind对应的数据库 只选TuShare:更新交易日数据,股票代码表和股票历史日线数据到TuShare对应的数据库 选两个:更新交易日数据,股票代码表和股票历史日线数据到Wind对应的数据库,并同时做两个源的数据验证 交易日数据,股票代码表和股票历史日线数据的载入也是基于上面选择的数据库 """ textEdit = QTextEdit() textEdit.setPlainText(description) textEdit.setReadOnly(True) cancelPushButton = QPushButton('Cancel') okPushButton = QPushButton('OK') cancelPushButton.clicked.connect(self._cancel) okPushButton.clicked.connect(self._ok) self._tradeDaysComboBox = QComboBox() descriptionTradeDays = "Wind有时交易日数据可能出错,所以选Wind时,总是跟TuShare做验证,由用户选择该如何做。" tradeDaysTextEdit = QTextEdit() tradeDaysTextEdit.setPlainText(descriptionTradeDays) tradeDaysTextEdit.setReadOnly(True) self._tuShareDaysIntervalLineEdit = QLineEdit() # TuShare日线数据每次下载间隔时间(秒) self._tuShareProDaysIntervalLineEdit = QLineEdit() # TuSharePro日线数据每次下载间隔时间(秒) # 布局 grid = QGridLayout() grid.setSpacing(10) grid.addWidget(label, 0, 0) grid.addWidget(self._windCheckBox, 1, 0) grid.addWidget(self._tuShareCheckBox, 2, 0) grid.addWidget(self._tuShareProCheckBox, 3, 0) grid.addWidget(tuShareProTokenLabel, 4, 0) grid.addWidget(self._tuShareProTokenLineEdit, 5, 0) grid.addWidget(textEdit, 6, 0) grid.addWidget(QLabel(" "), 7, 0) grid.addWidget(QLabel("交易日数据模式"), 8, 0) grid.addWidget(self._tradeDaysComboBox, 9, 0) grid.addWidget(tradeDaysTextEdit, 10, 0) grid.addWidget(QLabel(" "), 11, 0) grid.addWidget(QLabel("TuShare日线数据下载间隔时间(秒)"), 12, 0) grid.addWidget(self._tuShareDaysIntervalLineEdit, 13, 0) grid.addWidget(QLabel("TuSharePro日线数据下载间隔时间(秒)"), 14, 0) grid.addWidget(self._tuShareProDaysIntervalLineEdit, 15, 0) grid.addWidget(okPushButton, 0, 1) grid.addWidget(cancelPushButton, 1, 1) self.setLayout(grid) # set data source to UI if self._data.get('Wind'): self._windCheckBox.setChecked(True) if sys.platform != 'win32': # Wind only supported at Windows. self._windCheckBox.setEnabled(False) self._windCheckBox.setChecked(False) enableTuSharePro = False if self._data.get('TuShare'): self._tuShareCheckBox.setChecked(True) enableTuSharePro = True self._tuShareProCheckBox.setEnabled(enableTuSharePro) # set tushare pro enableTushareProToken = False if self._tuShareProData.get('TuSharePro'): self._tuShareProCheckBox.setChecked(True) enableTushareProToken = True if self._tuShareProData.get('Token'): self._tuShareProTokenLineEdit.setText(self._tuShareProData.get('Token')) # set according to days source checkbox self._tradeDaysComboBox.addItems(list(self.tradeDaysMode)) self._enableTradeDaysComboBox() for k, v in self.tradeDaysMode.items(): if v == self._tradeDaysModeData["tradeDaysMode"]: self._tradeDaysComboBox.setCurrentText(k) break # tushare days downloading interval self._tuShareDaysIntervalLineEdit.setText(str(self._tuShareDaysIntervalData['interval'])) # tusharepro days downloading interval self._tuShareProDaysIntervalLineEdit.setText(str(self._tuShareProDaysIntervalData['interval'])) self.resize(QApplication.desktop().size().width()//2, QApplication.desktop().size().height()//4*3) def _read(self): # data source file = DyStockConfig.getStockHistDaysDataSourceFileName() try: with open(file) as f: self._data = json.load(f) except: self._data = DyStockConfig.getDefaultHistDaysDataSource() # tushare pro file = DyStockConfig.getStockHistDaysTuShareProFileName() try: with open(file) as f: self._tuShareProData = json.load(f) except: self._tuShareProData = DyStockConfig.getDefaultHistDaysTuSharePro() # trade days mode file = DyStockConfig.getStockTradeDaysModeFileName() try: with open(file) as f: self._tradeDaysModeData = json.load(f) except: self._tradeDaysModeData = DyStockConfig.defaultTradeDaysMode # interval of tushare days downloading file = DyStockConfig.getStockTuShareDaysIntervalFileName() try: with open(file) as f: self._tuShareDaysIntervalData = json.load(f) except: self._tuShareDaysIntervalData = DyStockConfig.defaultTuShareDaysInterval # interval of tusharepro days downloading file = DyStockConfig.getStockTuShareProDaysIntervalFileName() try: with open(file) as f: self._tuShareProDaysIntervalData = json.load(f) except: self._tuShareProDaysIntervalData = DyStockConfig.defaultTuShareProDaysInterval def _ok(self): # data source data = {'Wind': False, 'TuShare': False} if self._windCheckBox.isChecked(): data['Wind'] = True if self._tuShareCheckBox.isChecked(): data['TuShare'] = True # config to variables DyStockConfig.configStockHistDaysDataSource(data) # save config file = DyStockConfig.getStockHistDaysDataSourceFileName() with open(file, 'w') as f: f.write(json.dumps(data, indent=4)) # tushare pro data = {'TuSharePro': False, 'Token': None} if self._tuShareProCheckBox.isChecked(): data['TuSharePro'] = True data['Token'] = self._tuShareProTokenLineEdit.text() DyStockConfig.configStockHistDaysTuSharePro(data) file = DyStockConfig.getStockHistDaysTuShareProFileName() with open(file, 'w') as f: f.write(json.dumps(data, indent=4)) # trade days mode data = {} data["tradeDaysMode"] = self.tradeDaysMode[self._tradeDaysComboBox.currentText()] DyStockConfig.configStockTradeDaysMode(data) file = DyStockConfig.getStockTradeDaysModeFileName() with open(file, 'w') as f: f.write(json.dumps(data, indent=4)) # tushare days downloading interval data = {} text = self._tuShareDaysIntervalLineEdit.text() try: data["interval"] = int(text) except: try: data["interval"] = float(text) except: data = DyStockConfig.defaultTuShareDaysInterval DyStockConfig.configStockTuShareDaysInterval(data) file = DyStockConfig.getStockTuShareDaysIntervalFileName() with open(file, 'w') as f: f.write(json.dumps(data, indent=4)) # tusharepro days downloading interval data = {} text = self._tuShareProDaysIntervalLineEdit.text() try: data["interval"] = int(text) except: try: data["interval"] = float(text) except: data = DyStockConfig.defaultTuShareProDaysInterval DyStockConfig.configStockTuShareProDaysInterval(data) file = DyStockConfig.getStockTuShareProDaysIntervalFileName() with open(file, 'w') as f: f.write(json.dumps(data, indent=4)) self.accept() def _cancel(self): self.reject() def _enableTradeDaysComboBox(self): if self._windCheckBox.isChecked(): self._tradeDaysComboBox.setEnabled(True) else: self._tradeDaysComboBox.setEnabled(False) def _checkBoxClicked(self): if not self._windCheckBox.isChecked() and not self._tuShareCheckBox.isChecked(): if sys.platform == 'win32': self._windCheckBox.setChecked(True) else: self._tuShareCheckBox.setChecked(True) self._enableTradeDaysComboBox() def _windCheckBoxClicked(self): self._checkBoxClicked() def _tuShareCheckBoxClicked(self): self._checkBoxClicked() enable = self._tuShareCheckBox.isChecked() self._tuShareProCheckBox.setEnabled(enable)
class EditForm(QDialog): def __init__(self): super(EditForm, self).__init__() self.initUI(self) def initUI(self, EditForm): layout = QGridLayout(self) self.title_label = QLabel("Title:") self.title_line_edit = QLineEdit() self.rating_label = QLabel("Rating:") self.rating_slider = QSlider(Qt.Horizontal) self.rating_slider.setMinimum(0) self.rating_slider.setMaximum(5) self.rating_slider.setValue(0) self.rating_slider.setTickPosition(QSlider.TicksBelow) self.rating_slider.setTickInterval(5) self.review_label = QLabel("Review:") self.review_text_edit = QTextEdit() self.status_label = QLabel("Status:") self.status_combo_box = QComboBox() self.status_combo_box.addItems(["Read", "Currently Reading", "Want Тo Read"]) self.edit_button = QPushButton("Edit book") layout.addWidget(self.title_label, 0, 0) layout.addWidget(self.title_line_edit, 0, 1) layout.addWidget(self.rating_label, 1, 0) layout.addWidget(self.rating_slider, 1, 1) layout.addWidget(self.review_label, 2, 0) layout.addWidget(self.review_text_edit, 2, 1) layout.addWidget(self.status_label, 3, 0) layout.addWidget(self.status_combo_box, 3, 1) layout.addWidget(self.edit_button, 4, 0, 1, 2, Qt.AlignCenter) self.setLayout(layout) self.edit_button.clicked.connect(self.edit_button_click) self.layout().setSizeConstraint(QLayout.SetFixedSize) self.setWindowTitle("Edit Book") self.setWindowIcon(QIcon(QPixmap('../images/edit.png'))) def edit_button_click(self): title = self.title_line_edit.text() rating = self.rating_slider.value() review = self.review_text_edit.toPlainText() status = self.status_combo_box.currentText() if select_by_title(string.capwords(title)) == []: QMessageBox(QMessageBox.Critical, "Error", "There is no such book in the library!").exec_() else: if update_entry(string.capwords(title), rating, review, status): QMessageBox(QMessageBox.Information, "Updated book info", "You updated the info about this book!").exec_() else: QMessageBox(QMessageBox.Information, "Information", "The book was NOT edited! Try again.").exec_()