class PMGPasswordCtrl(BaseExtendedWidget): def __init__(self, layout_dir: str, title: str, initial_value: str): super().__init__(layout_dir) self.on_check_callback = None self.prefix = QLabel(text=title) entryLayout = QHBoxLayout() entryLayout.setContentsMargins(0, 0, 0, 0) self.ctrl = QLineEdit() self.ctrl.setEchoMode(QLineEdit.Password) self.ctrl.textChanged.connect(self.ontext) self.central_layout.addWidget(self.prefix) self.central_layout.addLayout(entryLayout) entryLayout.addWidget(self.ctrl) self.set_value(initial_value) def param_changed(self, event): pass def ontext(self, event): self.para_changed() def set_value(self, text: str): self.ctrl.clear() self.ctrl.setText(text) def get_value(self) -> str: return self.ctrl.text()
class ShellWidget(QWidget): run_shell = Signal(Bot, str) def __init__(self, bot, parent): super(ShellWidget, self).__init__(parent) self.bot = bot self.widget_layout = QVBoxLayout(self) self.setLayout(self.widget_layout) self.output_widget = QPlainTextEdit(self) self.output_widget.setReadOnly(True) self.highlighter = ShellHighlighter(self.output_widget.document()) self.widget_layout.addWidget(self.output_widget) self.input_widget = QLineEdit(self) self.widget_layout.addWidget(self.input_widget) self.send_button = QPushButton(self) self.send_button.setText("Send") self.send_button.clicked.connect(self.on_send_button_clicked) self.widget_layout.addWidget(self.send_button) @Slot() def on_send_button_clicked(self): text = self.input_widget.text() self.output_widget.appendPlainText("$: {}".format(text)) self.run_shell.emit(self.bot, text) self.input_widget.clear() @Slot(Bot, str) def append_shell(self, bot, message): if self.bot == bot: self.output_widget.appendPlainText(message)
class Console(FramelessWindow): message = Signal(dict) def __init__(self, parent=None): super(Console, self).__init__(parent) self.json_decode_warning = None self.widget = QWidget(self) self.console_layout = QVBoxLayout(self.widget) self.widget.setLayout(self.console_layout) self.output_label = QLabel(self.widget) self.output_label.setText("Output") self.output_edit = QTextEdit(self.widget) self.output_edit.setReadOnly(True) self.highlighter = Highlighter(self.output_edit.document()) self.output_edit.setStyleSheet("background-color: rgb(0, 0, 0);") self.output_edit.setTextColor(QColor(0, 255, 0)) self.output_edit.setFont(QFont(self.output_edit.currentFont().family(), 10)) self.input_label = QLabel(self.widget) self.input_label.setText("Command") self.input_edit = QLineEdit(self.widget) self.input_edit.setStyleSheet("background-color: rgb(0, 0, 0); color: rgb(0, 255, 0)") self.input_edit.setFont(QFont(self.output_edit.currentFont().family(), 10)) self.send_button = QPushButton(self.widget) self.send_button.setObjectName("send_button") self.send_button.setText("Send command") self.console_layout.addWidget(self.output_label) self.console_layout.addWidget(self.output_edit) self.console_layout.addWidget(self.input_label) self.console_layout.addWidget(self.input_edit) self.console_layout.addWidget(self.send_button) self.addContentWidget(self.widget) QMetaObject.connectSlotsByName(self) def on_send_button_clicked(self): mess = self.input_edit.text() try: mess = json.loads(mess) self.message.emit(mess) self.input_edit.clear() self.output_edit.append("$: {}".format(mess)) except json.JSONDecodeError as e: self.json_decode_warning = FramelessCriticalMessageBox(self) self.json_decode_warning.setText("Failed to convert string to JSON: {}".format(e)) self.json_decode_warning.setStandardButtons(QDialogButtonBox.Ok) self.json_decode_warning.button(QDialogButtonBox.Ok).clicked.connect(self.json_decode_warning.close) self.json_decode_warning.show() def write(self, resp: dict): if resp.get("event_type"): resp = "[{}]: {}".format(str(resp.get("event_type")).upper(), resp) else: resp = str(resp) self.output_edit.append(resp)
class PMGNumberCtrl(PMGBaseEntryCtrl): """ 用于输入数值。 """ def __init__(self, layout_dir: str, title: str, initial_value: int, unit: str = '', range: tuple = None): super().__init__(layout_dir=layout_dir) self.on_check_callback = None if range is None: range = (float('-inf'), float('inf')) if isinstance(initial_value, int) and isinstance(range[0], int) and isinstance(range[1], int): self.num_type = int else: self.num_type = float self.prefix = QLabel(text=title) entryLayout = QHBoxLayout() entryLayout.setContentsMargins(0, 0, 0, 0) self.ctrl = QLineEdit() self.ctrl.textChanged.connect(self.ontext) self.postfix = QLabel(text=unit) self.central_layout.addWidget(self.prefix) self.central_layout.addLayout(entryLayout) entryLayout.addWidget(self.ctrl) entryLayout.addWidget(self.postfix) self.min, self.max = range self.accury = initial_value self.set_value(initial_value) def ontext(self, event): if self.get_value() is None: self.set_ctrl_warning(True) else: self.set_ctrl_warning(False) self.para_changed() self.ctrl.update() if callable(self.on_check_callback): self.on_check_callback() self.signal_param_changed.emit(self.name) def set_value(self, n): self.ctrl.clear() self.ctrl.setText(str(n)) def get_value(self): text = self.ctrl.text() try: num = self.num_type(text) except ValueError: import traceback traceback.print_exc() return None if num < self.min or num > self.max: return None return num
class QtPluginDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.refresh_state = RefreshState.DONE self.already_installed = set() installer_type = "mamba" if running_as_constructor_app() else "pip" self.installer = Installer(installer=installer_type) self.setup_ui() self.installer.set_output_widget(self.stdout_text) self.installer.started.connect(self._on_installer_start) self.installer.finished.connect(self._on_installer_done) self.refresh() def _on_installer_start(self): self.cancel_all_btn.setVisible(True) self.working_indicator.show() self.process_error_indicator.hide() self.close_btn.setDisabled(True) def _on_installer_done(self, exit_code): self.working_indicator.hide() if exit_code: self.process_error_indicator.show() self.cancel_all_btn.setVisible(False) self.close_btn.setDisabled(False) self.refresh() def closeEvent(self, event): if self.close_btn.isEnabled(): super().closeEvent(event) event.ignore() def refresh(self): if self.refresh_state != RefreshState.DONE: self.refresh_state = RefreshState.OUTDATED return self.refresh_state = RefreshState.REFRESHING self.installed_list.clear() self.available_list.clear() # fetch installed from npe2 import PluginManager from ...plugins import plugin_manager plugin_manager.discover() # since they might not be loaded yet self.already_installed = set() def _add_to_installed(distname, enabled, npe_version=1): norm_name = normalized_name(distname or '') if distname: try: meta = metadata(distname) except PackageNotFoundError: self.refresh_state = RefreshState.OUTDATED return # a race condition has occurred and the package is uninstalled by another thread if len(meta) == 0: # will not add builtins. return self.already_installed.add(norm_name) else: meta = {} self.installed_list.addItem( PackageMetadata( metadata_version="1.0", name=norm_name, version=meta.get('version', ''), summary=meta.get('summary', ''), home_page=meta.get('url', ''), author=meta.get('author', ''), license=meta.get('license', ''), ), installed=True, enabled=enabled, npe_version=npe_version, ) pm2 = PluginManager.instance() for manifest in pm2.iter_manifests(): distname = normalized_name(manifest.name or '') if distname in self.already_installed or distname == 'napari': continue enabled = not pm2.is_disabled(manifest.name) _add_to_installed(distname, enabled, npe_version=2) for ( plugin_name, _mod_name, distname, ) in plugin_manager.iter_available(): # not showing these in the plugin dialog if plugin_name in ('napari_plugin_engine', ): continue if distname in self.already_installed: continue _add_to_installed(distname, not plugin_manager.is_blocked(plugin_name)) self.installed_label.setText( trans._( "Installed Plugins ({amount})", amount=len(self.already_installed), )) # fetch available plugins settings = get_settings() use_hub = (running_as_bundled_app() or running_as_constructor_app() or settings.plugins.plugin_api.name == "napari_hub") if use_hub: conda_forge = running_as_constructor_app() self.worker = create_worker(iter_hub_plugin_info, conda_forge=conda_forge) else: self.worker = create_worker(iter_napari_plugin_info) self.worker.yielded.connect(self._handle_yield) self.worker.finished.connect(self.working_indicator.hide) self.worker.finished.connect(self._update_count_in_label) self.worker.finished.connect(self._end_refresh) self.worker.start() def setup_ui(self): self.resize(1080, 640) vlay_1 = QVBoxLayout(self) self.h_splitter = QSplitter(self) vlay_1.addWidget(self.h_splitter) self.h_splitter.setOrientation(Qt.Horizontal) self.v_splitter = QSplitter(self.h_splitter) self.v_splitter.setOrientation(Qt.Vertical) self.v_splitter.setMinimumWidth(500) installed = QWidget(self.v_splitter) lay = QVBoxLayout(installed) lay.setContentsMargins(0, 2, 0, 2) self.installed_label = QLabel(trans._("Installed Plugins")) self.packages_filter = QLineEdit() self.packages_filter.setPlaceholderText(trans._("filter...")) self.packages_filter.setMaximumWidth(350) self.packages_filter.setClearButtonEnabled(True) mid_layout = QVBoxLayout() mid_layout.addWidget(self.packages_filter) mid_layout.addWidget(self.installed_label) lay.addLayout(mid_layout) self.installed_list = QPluginList(installed, self.installer) self.packages_filter.textChanged.connect(self.installed_list.filter) lay.addWidget(self.installed_list) uninstalled = QWidget(self.v_splitter) lay = QVBoxLayout(uninstalled) lay.setContentsMargins(0, 2, 0, 2) self.avail_label = QLabel(trans._("Available Plugins")) mid_layout = QHBoxLayout() mid_layout.addWidget(self.avail_label) mid_layout.addStretch() lay.addLayout(mid_layout) self.available_list = QPluginList(uninstalled, self.installer) self.packages_filter.textChanged.connect(self.available_list.filter) lay.addWidget(self.available_list) self.stdout_text = QTextEdit(self.v_splitter) self.stdout_text.setReadOnly(True) self.stdout_text.setObjectName("pip_install_status") self.stdout_text.hide() buttonBox = QHBoxLayout() self.working_indicator = QLabel(trans._("loading ..."), self) sp = self.working_indicator.sizePolicy() sp.setRetainSizeWhenHidden(True) self.working_indicator.setSizePolicy(sp) self.process_error_indicator = QLabel(self) self.process_error_indicator.setObjectName("error_label") self.process_error_indicator.hide() load_gif = str(Path(napari.resources.__file__).parent / "loading.gif") mov = QMovie(load_gif) mov.setScaledSize(QSize(18, 18)) self.working_indicator.setMovie(mov) mov.start() visibility_direct_entry = not running_as_constructor_app() self.direct_entry_edit = QLineEdit(self) self.direct_entry_edit.installEventFilter(self) self.direct_entry_edit.setPlaceholderText( trans._('install by name/url, or drop file...')) self.direct_entry_edit.setVisible(visibility_direct_entry) self.direct_entry_btn = QPushButton(trans._("Install"), self) self.direct_entry_btn.setVisible(visibility_direct_entry) self.direct_entry_btn.clicked.connect(self._install_packages) self.show_status_btn = QPushButton(trans._("Show Status"), self) self.show_status_btn.setFixedWidth(100) self.cancel_all_btn = QPushButton(trans._("cancel all actions"), self) self.cancel_all_btn.setObjectName("remove_button") self.cancel_all_btn.setVisible(False) self.cancel_all_btn.clicked.connect(lambda: self.installer.cancel()) self.close_btn = QPushButton(trans._("Close"), self) self.close_btn.clicked.connect(self.accept) self.close_btn.setObjectName("close_button") buttonBox.addWidget(self.show_status_btn) buttonBox.addWidget(self.working_indicator) buttonBox.addWidget(self.direct_entry_edit) buttonBox.addWidget(self.direct_entry_btn) if not visibility_direct_entry: buttonBox.addStretch() buttonBox.addWidget(self.process_error_indicator) buttonBox.addSpacing(20) buttonBox.addWidget(self.cancel_all_btn) buttonBox.addSpacing(20) buttonBox.addWidget(self.close_btn) buttonBox.setContentsMargins(0, 0, 4, 0) vlay_1.addLayout(buttonBox) self.show_status_btn.setCheckable(True) self.show_status_btn.setChecked(False) self.show_status_btn.toggled.connect(self._toggle_status) self.v_splitter.setStretchFactor(1, 2) self.h_splitter.setStretchFactor(0, 2) self.packages_filter.setFocus() def _update_count_in_label(self): count = self.available_list.count() self.avail_label.setText( trans._("Available Plugins ({count})", count=count)) def _end_refresh(self): refresh_state = self.refresh_state self.refresh_state = RefreshState.DONE if refresh_state == RefreshState.OUTDATED: self.refresh() def eventFilter(self, watched, event): if event.type() == QEvent.DragEnter: # we need to accept this event explicitly to be able # to receive QDropEvents! event.accept() if event.type() == QEvent.Drop: md = event.mimeData() if md.hasUrls(): files = [url.toLocalFile() for url in md.urls()] self.direct_entry_edit.setText(files[0]) return True return super().eventFilter(watched, event) def _toggle_status(self, show): if show: self.show_status_btn.setText(trans._("Hide Status")) self.stdout_text.show() else: self.show_status_btn.setText(trans._("Show Status")) self.stdout_text.hide() def _install_packages(self, packages: Sequence[str] = ()): if not packages: _packages = self.direct_entry_edit.text() if os.path.exists(_packages): packages = [_packages] else: packages = _packages.split() self.direct_entry_edit.clear() if packages: self.installer.install(packages) def _handle_yield(self, data: Tuple[PackageMetadata, bool]): project_info, is_available = data if project_info.name in self.already_installed: self.installed_list.tag_outdated(project_info, is_available) else: self.available_list.addItem(project_info) if not is_available: self.available_list.tag_unavailable(project_info) self.filter() def filter(self, text: str = None) -> None: """Filter by text or set current text as filter.""" if text is None: text = self.packages_filter.text() else: self.packages_filter.setText(text) self.installed_list.filter(text) self.available_list.filter(text)
class QtPluginDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.installer = Installer() self.setup_ui() self.installer.set_output_widget(self.stdout_text) self.installer.process.started.connect(self._on_installer_start) self.installer.process.finished.connect(self._on_installer_done) self.refresh() def _on_installer_start(self): self.show_status_btn.setChecked(True) self.working_indicator.show() self.process_error_indicator.hide() def _on_installer_done(self, exit_code, exit_status): self.working_indicator.hide() if exit_code: self.process_error_indicator.show() else: self.show_status_btn.setChecked(False) self.refresh() self.plugin_sorter.refresh() def refresh(self): self.installed_list.clear() self.available_list.clear() # fetch installed from ...plugins import plugin_manager plugin_manager.discover() # since they might not be loaded yet already_installed = set() for plugin_name, mod_name, distname in plugin_manager.iter_available(): # not showing these in the plugin dialog if plugin_name in ('napari_plugin_engine', ): continue if distname: already_installed.add(distname) meta = standard_metadata(distname) else: meta = {} self.installed_list.addItem( ProjectInfo( normalized_name(distname or ''), meta.get('version', ''), meta.get('url', ''), meta.get('summary', ''), meta.get('author', ''), meta.get('license', ''), ), plugin_name=plugin_name, enabled=plugin_name in plugin_manager.plugins, ) # self.v_splitter.setSizes([70 * self.installed_list.count(), 10, 10]) # fetch available plugins self.worker = create_worker(iter_napari_plugin_info) def _handle_yield(project_info): if project_info.name in already_installed: self.installed_list.tag_outdated(project_info) else: self.available_list.addItem(project_info) self.worker.yielded.connect(_handle_yield) self.worker.finished.connect(self.working_indicator.hide) self.worker.finished.connect(self._update_count_in_label) self.worker.start() def setup_ui(self): self.resize(1080, 640) vlay_1 = QVBoxLayout(self) self.h_splitter = QSplitter(self) vlay_1.addWidget(self.h_splitter) self.h_splitter.setOrientation(Qt.Horizontal) self.v_splitter = QSplitter(self.h_splitter) self.v_splitter.setOrientation(Qt.Vertical) self.v_splitter.setMinimumWidth(500) self.plugin_sorter = QtPluginSorter(parent=self.h_splitter) self.plugin_sorter.layout().setContentsMargins(2, 0, 0, 0) self.plugin_sorter.hide() installed = QWidget(self.v_splitter) lay = QVBoxLayout(installed) lay.setContentsMargins(0, 2, 0, 2) lay.addWidget(QLabel(trans._("Installed Plugins"))) self.installed_list = QPluginList(installed, self.installer) lay.addWidget(self.installed_list) uninstalled = QWidget(self.v_splitter) lay = QVBoxLayout(uninstalled) lay.setContentsMargins(0, 2, 0, 2) self.avail_label = QLabel(trans._("Available Plugins")) lay.addWidget(self.avail_label) self.available_list = QPluginList(uninstalled, self.installer) lay.addWidget(self.available_list) self.stdout_text = QTextEdit(self.v_splitter) self.stdout_text.setReadOnly(True) self.stdout_text.setObjectName("pip_install_status") self.stdout_text.hide() buttonBox = QHBoxLayout() self.working_indicator = QLabel(trans._("loading ..."), self) sp = self.working_indicator.sizePolicy() sp.setRetainSizeWhenHidden(True) self.working_indicator.setSizePolicy(sp) self.process_error_indicator = QLabel(self) self.process_error_indicator.setObjectName("error_label") self.process_error_indicator.hide() load_gif = str(Path(napari.resources.__file__).parent / "loading.gif") mov = QMovie(load_gif) mov.setScaledSize(QSize(18, 18)) self.working_indicator.setMovie(mov) mov.start() self.direct_entry_edit = QLineEdit(self) self.direct_entry_edit.installEventFilter(self) self.direct_entry_edit.setPlaceholderText( trans._('install by name/url, or drop file...')) self.direct_entry_btn = QPushButton(trans._("Install"), self) self.direct_entry_btn.clicked.connect(self._install_packages) self.show_status_btn = QPushButton(trans._("Show Status"), self) self.show_status_btn.setFixedWidth(100) self.show_sorter_btn = QPushButton(trans._("<< Show Sorter"), self) self.close_btn = QPushButton(trans._("Close"), self) self.close_btn.clicked.connect(self.reject) buttonBox.addWidget(self.show_status_btn) buttonBox.addWidget(self.working_indicator) buttonBox.addWidget(self.direct_entry_edit) buttonBox.addWidget(self.direct_entry_btn) buttonBox.addWidget(self.process_error_indicator) buttonBox.addSpacing(60) buttonBox.addWidget(self.show_sorter_btn) buttonBox.addWidget(self.close_btn) buttonBox.setContentsMargins(0, 0, 4, 0) vlay_1.addLayout(buttonBox) self.show_status_btn.setCheckable(True) self.show_status_btn.setChecked(False) self.show_status_btn.toggled.connect(self._toggle_status) self.show_sorter_btn.setCheckable(True) self.show_sorter_btn.setChecked(False) self.show_sorter_btn.toggled.connect(self._toggle_sorter) self.v_splitter.setStretchFactor(1, 2) self.h_splitter.setStretchFactor(0, 2) def _update_count_in_label(self): count = self.available_list.count() self.avail_label.setText( trans._("Available Plugins ({count})".format(count=count))) def eventFilter(self, watched, event): if event.type() == QEvent.DragEnter: # we need to accept this event explicitly to be able # to receive QDropEvents! event.accept() if event.type() == QEvent.Drop: md = event.mimeData() if md.hasUrls(): files = [url.toLocalFile() for url in md.urls()] self.direct_entry_edit.setText(files[0]) return True return super().eventFilter(watched, event) def _toggle_sorter(self, show): if show: self.show_sorter_btn.setText(trans._(">> Hide Sorter")) self.plugin_sorter.show() else: self.show_sorter_btn.setText(trans._("<< Show Sorter")) self.plugin_sorter.hide() def _toggle_status(self, show): if show: self.show_status_btn.setText(trans._("Hide Status")) self.stdout_text.show() else: self.show_status_btn.setText(trans._("Show Status")) self.stdout_text.hide() def _install_packages(self, packages: Sequence[str] = ()): if not packages: _packages = self.direct_entry_edit.text() if os.path.exists(_packages): packages = [_packages] else: packages = _packages.split() self.direct_entry_edit.clear() if packages: self.installer.install(packages)
class ZhuNoteForm(QWidget): def __init__(self, path=None): QWidget.__init__(self) self.initUI(path) def initUI(self, path): pathLabel = QLabel('Path') filenameLabel = QLabel('Filename') timeLabel = QLabel('Time') titleLabel = QLabel('Title') keywordLabel = QLabel('Keyword') figureLabel = QLabel('Figure') htmlLabel = QLabel('HTML') bodyLabel = QLabel('Body') self.pathEdit = QLineEdit(path) self.pathEdit.setReadOnly(True) self.filenameEdit = QLineEdit() self.timeEdit = QLineEdit() self.titleEdit = QLineEdit() self.keywordEdit = QLineEdit() self.figureEdit = QLineEdit() self.htmlEdit = QLineEdit() self.bodyEdit = QTextEdit() # If more than one keyword, delimit with comma. # Same for figure and html filenames. #btnSave = QPushButton('Save') #btnSave.setToolTip('Save script to file') #btnSave.clicked.connect(self.saveFile) # Replace save button with keyboard shortcut # Save move hand from keyboard to mouse. grid = QGridLayout() grid.setSpacing(5) row = 0 grid.addWidget(pathLabel, row, 0) grid.addWidget(self.pathEdit, row, 1) row += 1 grid.addWidget(filenameLabel, row, 0) grid.addWidget(self.filenameEdit, row, 1) row += 1 grid.addWidget(figureLabel, row, 0) grid.addWidget(self.figureEdit, row, 1) row += 1 grid.addWidget(htmlLabel, row, 0) grid.addWidget(self.htmlEdit, row, 1) row += 1 grid.addWidget(timeLabel, row, 0) grid.addWidget(self.timeEdit, row, 1) row += 1 grid.addWidget(titleLabel, row, 0) grid.addWidget(self.titleEdit, row, 1) row += 1 grid.addWidget(keywordLabel, row, 0) grid.addWidget(self.keywordEdit, row, 1) row += 1 grid.addWidget(bodyLabel, row, 0) grid.addWidget(self.bodyEdit, row, 1, 6, 1) #grid.addWidget(btnSave, 11, 1) self.actOpen = QAction('Open', self) self.actOpen.setShortcut('Ctrl+O') self.actOpen.triggered.connect(self.openFile) self.filenameEdit.addAction(self.actOpen) self.actSave = QAction('Save', self) self.actSave.setShortcut('Ctrl+S') self.actSave.triggered.connect(self.saveFile) self.bodyEdit.addAction(self.actSave) self.setLayout(grid) #self.setGeometry(300, 300, 600, 400) self.setWindowTitle('Form - ZhuNote') #self.show() def setFont(self, font): #font = self.bodyEdit.font() # current font #font = QFont() # default font self.pathEdit.setFont(font) self.filenameEdit.setFont(font) self.timeEdit.setFont(font) self.titleEdit.setFont(font) self.keywordEdit.setFont(font) self.figureEdit.setFont(font) self.htmlEdit.setFont(font) self.bodyEdit.setFont(font) def clear(self): self.filenameEdit.clear() self.timeEdit.clear() self.titleEdit.clear() self.keywordEdit.clear() self.figureEdit.clear() self.htmlEdit.clear() self.bodyEdit.clear() def viewDict(self, dictNote): self.filenameEdit.setText(dictNote['Filename']) self.timeEdit.setText(dictNote['Time']) self.titleEdit.setText(dictNote['Title']) self.keywordEdit.setText(dictNote['Keyword']) self.figureEdit.setText(dictNote['Figure']) self.htmlEdit.setText(dictNote['HTML']) self.bodyEdit.setText(dictNote['Body']) def openFile(self): path = self.pathEdit.text() fn = self.filenameEdit.text() ffn = os.path.join(path, fn) with open(ffn, 'rb') as f: dictNote = pickle.load(f) self.viewDict(dictNote) def saveFile(self): #fn = timeStr + '.txt' # Use title as filename to overwrite existing note file. base = self.titleEdit.text().replace(' ', '_') txtfn = base + '.txt' pklfn = base + '.pkl' path = self.pathEdit.text() timeStr = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') self.filenameEdit.setText(pklfn) self.timeEdit.setText(timeStr) textSum = '' text = 'Filename: ' + txtfn + '\n' textSum += text text = 'Time: ' + timeStr + '\n' textSum += text text = 'Title: ' + self.titleEdit.text() + '\n' textSum += text text = 'Keyword: ' + self.keywordEdit.text() + '\n' textSum += text text = 'Figure: ' + self.figureEdit.text() + '\n' textSum += text text = 'HTML: ' + self.htmlEdit.text() + '\n' textSum += text text = 'Body: ' + self.bodyEdit.toPlainText() + '\n' textSum += text dictNote = {} dictNote['Filename'] = pklfn dictNote['Time'] = timeStr dictNote['Title'] = self.titleEdit.text() dictNote['Keyword'] = self.keywordEdit.text() dictNote['Figure'] = self.figureEdit.text() dictNote['HTML'] = self.htmlEdit.text() dictNote['Body'] = self.bodyEdit.toPlainText() txtffn = os.path.join(path, txtfn) pklffn = os.path.join(path, pklfn) # Check if file exist if os.path.isfile(txtffn): choice = QMessageBox.question( self, 'Warning', "File exists. Do you want overwrite?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if choice == QMessageBox.Yes: self.writeFile(textSum, txtffn, dictNote, pklffn) else: print("Change title and re-save.") return 1 else: self.writeFile(textSum, txtffn, dictNote, pklffn) return 0 @staticmethod def writeFile(textSum, txtfn, dictNote, pklfn): """ input are full filename (with absolute path) """ with open(txtfn, 'w', encoding='utf-8') as f: f.write(textSum) with open(pklfn, 'wb') as f: pickle.dump(dictNote, f, -1)
class Classifier(QWidget): def __init__(self, viewer, metadata_levels, initial_classes, *args, **kwargs): super(Classifier,self).__init__(*args,**kwargs) self.viewer = viewer # open image if not already open if len(self.viewer.layers)<1: msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("No image open, please select an image in the following dialog.") msg.exec() self.viewer.window.qt_viewer._open_files_dialog() if len(self.viewer.layers)<1: # still no image open raise ValueError("Could not find image layers.") # get image shape self.shape = self.viewer.layers[0].shape # check metadata levels if not metadata_levels: self.metadata_levels = [f'dim_{dim}' for dim in range(len(self.shape[:-2]))] elif len(metadata_levels)!=len(self.shape[:-2]): metadata_levels_warning = NapariNotification((f'Number of metadata_levels ({len(metadata_levels)}) does not match ' f'number of leading image dimensions ({len(self.shape[:-2])}); will use default metadata_levels.'), severity='warning') metadata_levels_warning.show() self.metadata_levels = [f'dim_{dim}' for dim in range(len(self.shape[:-2]))] else: self.metadata_levels = metadata_levels # load metadata self.load_metadata() # initialize widget layout = QHBoxLayout() ## io panel save_button = QPushButton('Save...',self) save_button.clicked.connect(self.save_results) io_panel = QWidget() io_layout = QVBoxLayout() io_layout.addWidget(save_button) io_panel.setLayout(io_layout) layout.addWidget(io_panel) ## class panel classes_panel = QGroupBox('classes') classes_panel.setMinimumWidth(CLASS_PANEL_MINIMUM_WIDTH) ### layout for adding classes add_classes_layout = QHBoxLayout() add_class_button = QPushButton('Add class',self) add_class_button.clicked.connect(self.click_add_class) self.new_class_text = QLineEdit(self) self.new_class_text.setAlignment(Qt.AlignLeft) add_classes_layout.addWidget(add_class_button) add_classes_layout.addWidget(self.new_class_text) ### layout for class buttons self.class_button_layout = QGridLayout() ### add sub layouts to class panel classes_layout = QVBoxLayout() classes_layout.addLayout(add_classes_layout) classes_layout.addLayout(self.class_button_layout) classes_panel.setLayout(classes_layout) layout.addWidget(classes_panel) ## set widget layout layout.setAlignment(Qt.AlignTop) layout.setSpacing(4) self.setLayout(layout) self.setMaximumHeight(GUI_MAXIMUM_HEIGHT) self.setMaximumWidth(GUI_MAXIMUM_WIDTH) # initialize classes self.classes = [] if initial_classes is not None: for initial_class in initial_classes: self.add_class(initial_class) def load_metadata(self): # msg = QMessageBox() # msg.setIcon(QMessageBox.Information) # msg.setText(("Use the following dialog to choose a metadata table to open, " # "otherwise click 'cancel' to use an automatically generated table.")) # msg.exec() # filename = QFileDialog.getOpenFileName(self,'Open metadata table',DEFAULT_PATH,'Metadata table (*.csv *.hdf)') self.df_metadata = None # if filename[0]: # ext = filename[0].split('.')[-1] # if ext == 'csv': # self.df_metadata = pd.read_csv(filename[0]) # elif ext == 'hdf': # self.df_metadata = pd.read_hdf(filename[0]) # else: # print(f'filetype {ext} not recognized, creating default metadata table') if self.df_metadata is None: from itertools import product self.df_metadata = pd.DataFrame([{level:idx for level,idx in zip(self.metadata_levels,indices)} for indices in product(*(range(dim) for dim in self.shape[:-2]))] ) if 'annotated_class' not in self.df_metadata.columns: self.df_metadata = self.df_metadata.assign(annotated_class=None) self.df_metadata = self.df_metadata.set_index(self.metadata_levels) def click_add_class(self): self.add_class(self.new_class_text.text()) self.new_class_text.clear() def add_class(self,new_class): self.classes.append(new_class) if len(self.classes)<10: # shortcut key binding available self.viewer.bind_key(key=str(len(self.classes)), func=partial(self.classify_frame,chosen_class=self.classes[-1]), overwrite=True) new_class_button = QPushButton('{class_name} [{num}]'.format( class_name=self.classes[-1], num=len(self.classes)), self) else: # shortcut key binding not available many_classes_notification = NapariNotification( ('Shortcut key bindings not available with the 10th or further class'), severity='info') many_classes_notification.show() new_class_button = QPushButton(self.classes[-1],self) new_class_button.clicked.connect(partial(self.classify_frame,key_press=None,chosen_class=self.classes[-1])) self.class_button_layout.addWidget(new_class_button, ((len(self.classes)-1)%MAXIMUM_CLASS_BUTTONS_PER_COLUMN), int((len(self.classes)-1)/MAXIMUM_CLASS_BUTTONS_PER_COLUMN) ) def classify_frame(self,key_press,chosen_class): # TODO: create an annotation status bar that reports class of current slice coords = self.viewer.layers[0].coordinates[:-2] coords_string = ', '.join([f'{level}={val}' for level,val in zip(self.metadata_levels,coords)]) if self.df_metadata.loc[(coords),('annotated_class')] is not None: previous_class = self.df_metadata.loc[(coords),('annotated_class')] if previous_class != chosen_class: overwrite_notification = NapariNotification((f'{coords_string} previously annotated as ' f'`{previous_class}`, overwriting annotation as `{chosen_class}`'), severity='info') overwrite_notification.show() else: annotate_notification = NapariNotification((f'Annotating {coords_string} as `{chosen_class}`'), severity='info') annotate_notification.show() self.df_metadata.loc[(coords),('annotated_class')] = chosen_class if tuple(np.array(self.shape[:-2])-1)==coords: # last slice pass else: if coords[-1]<(self.shape[-3]-1): self.viewer.dims._increment_dims_right(axis=(-3)) else: self.viewer.dims.set_current_step(axis=(-3),value=0) self.viewer.dims._increment_dims_right(axis=(-4)) def save_results(self): filename = QFileDialog.getSaveFileName(self, 'Export classification data', os.path.join(DEFAULT_PATH, self.viewer.layers[0].name+'.classified.csv'), 'Classification files (*.csv *.hdf)') if filename[0]: ext = filename[0].split('.')[-1] if ext == 'csv': self.df_metadata.to_csv(filename[0]) elif ext == 'hdf': self.df_metadata.to_hdf(filename[0],'x',mode='w') else: print(f'filetype {ext} not recognized, cannot save') else: print('no file selected, did not save')
class PayloadWindow(FramelessWindow): get_build_options = Signal() start_build = Signal(str, str, list) stop_build = Signal() def __init__(self, parent): super(PayloadWindow, self).__init__(parent) self.logger = logging.getLogger(self.__class__.__name__) self.setContentsMargins(11, 11, 11, 11) self.progress_windows = [] self.content_widget = QWidget(self) self.addContentWidget(self.content_widget) self.widget_layout = QFormLayout(self.content_widget) self.content_widget.setLayout(self.widget_layout) self.spinner = WaitingSpinner(self, modality=Qt.WindowModal, roundness=70.0, fade=70.0, radius=15.0, lines=6, line_length=25.0, line_width=4.0, speed=1.0) self.build_name_label = QLabel("Name", self.content_widget) self.build_name_edit = QLineEdit(self.content_widget) self.widget_layout.addRow(self.build_name_label, self.build_name_edit) self.icon_label = QLabel("Icon", self.content_widget) self.icon_combobox = QComboBox(self.content_widget) self.widget_layout.addRow(self.icon_label, self.icon_combobox) self.generators_label = QLabel("Generators", self.content_widget) self.generators_list = QListWidget(self.content_widget) self.widget_layout.addRow(self.generators_label, self.generators_list) self.build_button = QPushButton("Build", self.content_widget) self.build_button.clicked.connect(self.on_build_button_clicked) self.widget_layout.addWidget(self.build_button) self.menu = QMenu(self) self.menu.setTitle("Payload") self.reload_action = QAction(self.menu) self.reload_action.setText("Reload options") self.reload_action.triggered.connect(self.setupUi) self.menu.addAction(self.reload_action) self.addMenu(self.menu) @Slot() def setupUi(self): self.spinner.start() self.get_build_options.emit() @Slot(dict) def process_build_message(self, message): if self.isVisible(): event = message.get("event") if event == "options": options = message.get("options") self.set_options(options.get("generators"), options.get("icons")) elif event == "started": self.set_started(message.get("generator_name")) elif event == "stopped": self.set_stopped() elif event == "progress": self.set_progress(message.get("generator_name"), message.get("progress")) elif event == "error": self.set_error(message.get("error")) elif event == "generator_finished": self.set_generator_finished(message.get("generator_name"), message.get("exit_code")) elif event == "build_finished": self.set_build_finished() @Slot(str, str) def set_progress(self, generator_name, progress): for win in self.progress_windows: if win.generator() == generator_name: win.appendProgress(progress) @Slot(str) def set_started(self, generator_name): win = ProgressWindow(self, generator_name) win.show() self.progress_windows.append(win) self.logger.info("Generator {} started!".format(generator_name)) self.reload_action.setEnabled(False) self.spinner.start() @Slot(str, int) def set_generator_finished(self, generator_name, exit_code): self.logger.info("Generator {} finished with exit code {}.".format( generator_name, exit_code)) @Slot(list, list) def set_options(self, generators, icons): self.build_name_edit.clear() self.generators_list.clear() self.icon_combobox.clear() for generator in generators: item = QListWidgetItem(generator, self.generators_list) item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsUserCheckable) item.setCheckState(Qt.Checked) self.generators_list.addItem(item) for icon in icons: name = icon.get("name") pix = QPixmap() pix.loadFromData(base64.b64decode(icon.get("ico"))) ico = QIcon() ico.addPixmap(pix) self.icon_combobox.addItem(ico, name) self.spinner.stop() @Slot() def set_stopped(self): self.on_build_finished() self.build_button.setText("Build") self.stopped_messagebox = FramelessInformationMessageBox(self) self.stopped_messagebox.setText( "Build process has been stopped successfully.") self.stopped_messagebox.setStandardButtons(QDialogButtonBox.Ok) self.stopped_messagebox.button(QDialogButtonBox.Ok).clicked.connect( self.stopped_messagebox.close) self.stopped_messagebox.show() @Slot(str) def set_error(self, error): self.on_build_finished() self.build_button.setText("Build") self.error_messagebox = FramelessCriticalMessageBox(self) self.error_messagebox.setText(error) self.error_messagebox.setStandardButtons(QDialogButtonBox.Ok) self.error_messagebox.button(QDialogButtonBox.Ok).clicked.connect( self.error_messagebox.close) self.error_messagebox.show() @Slot() def set_build_finished(self): self.on_build_finished() self.build_button.setText("Build") self.build_finished_messagebox = FramelessInformationMessageBox(self) self.build_finished_messagebox.setText( "Build process has been finished.") self.build_finished_messagebox.setStandardButtons(QDialogButtonBox.Ok) self.build_finished_messagebox.button( QDialogButtonBox.Ok).clicked.connect( self.build_finished_messagebox.close) self.build_finished_messagebox.show() @Slot() def on_build_button_clicked(self): if self.build_button.text() == "Build": generators = [] for i in range(self.generators_list.count()): item = self.generators_list.item(i) if item.checkState() == Qt.Checked: generators.append(item.text()) self.start_build.emit(self.build_name_edit.text(), self.icon_combobox.currentText(), generators) self.build_button.setText("Stop") else: self.stop_build_messagebox = FramelessQuestionMessageBox(self) self.stop_build_messagebox.setText( "Do you want to stop build process?") self.stop_build_messagebox.setStandardButtons( QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.stop_build_messagebox.button( QDialogButtonBox.Cancel).clicked.connect( self.stop_build_messagebox.close) self.stop_build_messagebox.button( QDialogButtonBox.Ok).clicked.connect(self.stop_build.emit) self.stop_build_messagebox.button( QDialogButtonBox.Ok).clicked.connect( self.stop_build_messagebox.close) self.stop_build_messagebox.show() @Slot() def on_build_finished(self): self.reload_action.setEnabled(True) self.spinner.stop() @Slot() def close(self) -> bool: for win in self.progress_windows: win.close() return super().close()
class PMGColorCtrl(BaseExtendedWidget): def __init__(self, layout_dir: str, title: str, initial_value: str): super().__init__(layout_dir) self.on_check_callback = None self.prefix = QLabel(text=title) entryLayout = QHBoxLayout() self.ctrl = QLineEdit() self.ctrl.textChanged.connect(self.ontext) self.color_button = QPushButton() self.color_button.clicked.connect(self.oncolor) self.central_layout.addWidget(self.prefix) self.central_layout.addLayout(entryLayout) entryLayout.addWidget(self.ctrl) entryLayout.addWidget(self.color_button) self.set_value(initial_value) def ontext(self, event): if self.get_value() is None: self.color_button.setStyleSheet("background-color:#ff0000;") self.ctrl.setStyleSheet("background-color:#ff0000;") else: self.ctrl.setStyleSheet('background-color:#ffffff;') self.color_button.setStyleSheet( "background-color:%s;" % self.colorTup2Str(self.get_value())) self.para_changed() self.ctrl.update() if callable(self.on_check_callback): self.on_check_callback() def oncolor(self, event): color = QColorDialog.getColor(initial=QColor(*self.get_value())) self.set_value(self.colorStr2Tup(color.name())) if callable(self.on_check_callback): self.on_check_callback() def set_value(self, color: Tuple = None): if color is None: color = (255, 255, 255) strcolor = self.colorTup2Str(color) self.color_button.setStyleSheet('background-color:%s;' % strcolor) self.ctrl.clear() self.ctrl.setText(strcolor) def get_value(self): rgb = self.ctrl.text().strip() if len(rgb) != 7 or rgb[0] != '#': return None try: int(rgb[1:], 16) except: import traceback traceback.print_exc() return None return self.colorStr2Tup(rgb) def colorStr2Tup(self, value: str) -> tuple: # pos或者wh的输入都是tuple def convert(c): v = ord(c) if (48 <= v <= 57): return v - 48 else: return v - 87 # 返回a的值。 value = value.lower() c0 = convert(value[1]) c1 = convert(value[2]) c2 = convert(value[3]) c3 = convert(value[4]) c4 = convert(value[5]) c5 = convert(value[6]) a1 = c0 * 16 + c1 a2 = c2 * 16 + c3 a3 = c4 * 16 + c5 return (a1, a2, a3) def colorTup2Str(self, value: tuple) -> str: if value is None: return None strcolor = '#' for i in value: strcolor += hex(int(i))[-2:].replace('x', '0') return strcolor
class OptionSelectorMainWindow(QtWidgets.QWidget): optionType = ["CALL", "PUT", "C&P"] optionPropertiesList = [ 'code', 'last_price', 'option_type', 'strike_time', 'option_strike_price', 'option_open_interest', 'volume', 'option_delta', 'option_gamma', 'option_vega' ] def __init__(self, optionSelectorEngine, eventEngine, mainWindow=None, parent=None): try: super(OptionSelectorMainWindow, self).__init__(parent) self.optionSelectorEngine = optionSelectorEngine self.eventEngine = eventEngine self.mainWindow = mainWindow self.optionSelectorEngine.start() self.initUi() self.registerEvent() self.forUT() except: traceback.print_exc() def initUi(self): try: self.setWindowTitle(u"期权选择器") self.setMinimumWidth(1200) self.setMinimumHeight(800) labelStockCode = QLabel(u"代码") labelStockPrice = QLabel(u"价格(非实时)") labelSTDTimes = QLabel(u"标准差倍数") labelSTDValue = QLabel(u"标准差") labelSTDDays = QLabel(u"计算天数") lableStartDate = QLabel(u"开始日期") labelEndDate = QLabel(u"结束日期") labelType = QLabel(u"类型") labelStrikePrice = QLabel(u"行权价范围") self.lineStockCode = QLineEdit() self.lineStockPrice = QLineEdit() self.lineStockPrice.setEnabled(False) self.lineSTDTimes = QLineEdit() self.lineSTDValue = QLineEdit() self.lineSTDValue.setEnabled(False) self.lineSTDDays = QLineEdit() self.lineStartDate = QLineEdit() self.lineEndDate = QLineEdit() self.comboxType = QComboBox() self.comboxType.addItems(self.optionType) self.lineLowStrikePrice = QLineEdit() self.lineHighStrikePrice = QLineEdit() btQry = QPushButton(u"查询") btSort = QPushButton(u"排序开关") glayout = QGridLayout() glayout.addWidget(labelStockCode, 0, 0) glayout.addWidget(labelStockPrice, 0, 1) glayout.addWidget(labelSTDTimes, 0, 2) glayout.addWidget(labelSTDValue, 0, 3) glayout.addWidget(labelSTDDays, 0, 4) glayout.addWidget(self.lineStockCode, 1, 0) glayout.addWidget(self.lineStockPrice, 1, 1) glayout.addWidget(self.lineSTDTimes, 1, 2) glayout.addWidget(self.lineSTDValue, 1, 3) glayout.addWidget(self.lineSTDDays, 1, 4) self.lineStockCode.setMaximumWidth(150) self.lineStockPrice.setMaximumWidth(150) self.lineSTDTimes.setMaximumWidth(80) self.lineSTDValue.setMaximumWidth(150) self.lineSTDDays.setMaximumWidth(80) glayout.addWidget(lableStartDate, 2, 0) glayout.addWidget(labelEndDate, 2, 1) glayout.addWidget(labelType, 2, 2) glayout.addWidget(labelStrikePrice, 2, 3) glayout.addWidget(self.lineStartDate, 3, 0) glayout.addWidget(self.lineEndDate, 3, 1) glayout.addWidget(self.comboxType, 3, 2) glayout.addWidget(self.lineLowStrikePrice, 3, 3) glayout.addWidget(self.lineHighStrikePrice, 3, 4) self.lineStartDate.setMaximumWidth(150) self.lineEndDate.setMaximumWidth(150) self.lineLowStrikePrice.setMaximumWidth(150) self.lineHighStrikePrice.setMaximumWidth(150) glayout.addWidget(btQry, 4, 0) glayout.addWidget(btSort, 4, 1) vbox = QVBoxLayout() # 策略状态组件 self.optionSelectorMonitorWidget = OptionSelectorMonitor(self.optionSelectorEngine, self.eventEngine, \ self.mainWindow) groupBoxStraMonitor = GroupBoxWithSinglWidget( self.optionSelectorMonitorWidget, u"期权信息") vbox.addLayout(glayout) vbox.addWidget(groupBoxStraMonitor) self.setLayout(vbox) btQry.clicked.connect(self.qryOptionList) btSort.clicked.connect(self.switchSort) self.lineStockCode.returnPressed.connect(self.pressPriceReturn) self.optionSelectorMonitorWidget.itemDoubleClicked.connect( self.passOptionSelectorDataToMainWindow) except: traceback.print_exc() def pressPriceReturn(self): self.qryStockPrice() # self.updateDefaultOptionStrikePrice() def cleanPriceRetrun(self): self.lineSTDValue.clear() self.lineLowStrikePrice.clear() self.lineHighStrikePrice.clear() self.lineStockPrice.clear() def qryStockPrice(self): try: self.cleanPriceRetrun() code = self.lineStockCode.text() df = self.optionSelectorEngine.qryMarketSnapshot(code) # 设置当前价格 if len(df) > 0: price = df['last_price'][0] self.lineStockPrice.setText(str(price)) # 记录昨收价 preClosePrice = df['prev_close_price'][0] else: # error return # 计算估计近日来的标准差 numOfDays = self.lineSTDDays.text() try: numOfDays = int(numOfDays) except: raise Exception(u"计算天数输入错误 %s" % numOfDays) std = self.optionSelectorEngine.calSTD(code, numOfDays) if std >= 0: # 设置行权价范围 times = self.lineSTDTimes.text() try: times = round(float(times), 3) except: self.writeLog(u"方差倍数设置不正确") return lowPrice = (preClosePrice * (1 - std * times)) highPrice = (preClosePrice * (1 + std * times)) lowPrice = round(lowPrice, 3) highPrice = round(highPrice, 3) self.lineSTDValue.setText(str(round(std, 4))) self.lineLowStrikePrice.setText(str(lowPrice)) self.lineHighStrikePrice.setText(str(highPrice)) else: # 无法计算波动范围 self.writeLog(u"无法计算标准差 %s %s" % (code, numOfDays)) except: traceback.print_exc() def updateDefaultOptionStrikePrice(self): try: # 默认区间是 0.9 - 1.1 倍股价 priceStr = self.lineStockPrice.text() price = float(priceStr) lowPrice = int(price * 0.9) highPrice = int(price * 1.1) self.lineLowStrikePrice.setText(str(lowPrice)) self.lineHighStrikePrice.setText(str(highPrice)) except: pass def passOptionSelectorDataToMainWindow(self, cell): try: optionSelectorData = cell.data self.mainWindow.accpetOptionData(optionSelectorData, "OptionSprites") except: traceback.print_exc() def switchSort(self): self.optionSelectorMonitorWidget.switchSort() def qryOptionList(self): try: # 先查询最新股票价格 # self.qryStockPrice() stockCode = self.lineStockCode.text() startDate = self.lineStartDate.text() endDate = self.lineEndDate.text() optLowPriceStr = self.lineLowStrikePrice.text() optHighPriceStr = self.lineHighStrikePrice.text() # 检查code,startDate, endDate, lowPrice, highPrice # Todo try: optLowPrice = 0 optLowPrice = round(float(optLowPriceStr), 3) except: pass try: optHighPrice = 0 optHighPrice = round(float(optHighPriceStr), 3) except: pass optType = self.comboxType.currentText() self.optionSelectorEngine.qryOptionList(stockCode, startDate, endDate, optLowPrice, optHighPrice, optType) self.updateDisplay() except: traceback.print_exc() def updateDisplay(self): try: stockCode = self.lineStockCode.text() df1 = self.optionSelectorEngine.getOptionDF(stockCode) # 查询返回有满足条件的option if len(df1) > 0: optionDF = df1[self.optionPropertiesList] optionDF = optionDF.sort_values( ["option_strike_price", "strike_time"], ascending=False) # 清除原来数据 self.optionSelectorMonitorWidget.setRowCount(0) self.optionSelectorMonitorWidget.clearContents() # 更新符合条件的数据 for index, row in optionDF.iterrows(): data = VtOptionSelectorData() data.code = row['code'] data.last_price = row['last_price'] data.option_type = row['option_type'] data.strike_time = row['strike_time'] data.option_strike_price = row['option_strike_price'] data.option_open_interest = row['option_open_interest'] data.volume = row['volume'] data.option_delta = row['option_delta'] data.option_gamma = row['option_gamma'] data.option_vega = row['option_vega'] self.optionSelectorMonitorWidget.updateData(data) except: traceback.print_exc() def registerEvent(self): pass def forUT(self): self.lineStockCode.setText("US.AAPL") dtToday = datetime.today() dtStr = dtToday.strftime("%Y-%m-%d") dtEnd = dtToday + timedelta(days=45) dtEndStr = dtEnd.strftime("%Y-%m-%d") self.lineStartDate.setText(dtStr) self.lineEndDate.setText(dtEndStr) self.lineLowStrikePrice.setText("160") self.lineHighStrikePrice.setText("190") self.lineSTDTimes.setText("1.0") self.lineSTDDays.setText("30") def writeLog(self, content): try: log = VtLogData() log.logContent = content log.gatewayName = 'OPTION_SELECTOR_MAIN_WINDOW' event = Event(type_=EVENT_LOG) event.dict_['data'] = log self.eventEngine.put(event) except: traceback.print_exc()
class D0(QGroupBox): def __init__(self, parent=None): self._parent = parent super().__init__(parent) self.setTitle("Define d₀") layout = QVBoxLayout() self.d0_grid_switch = QComboBox() self.d0_grid_switch.addItems(["Constant", "Field"]) self.d0_grid_switch.currentTextChanged.connect(self.set_case) layout.addWidget(self.d0_grid_switch) self.d0_box = QWidget() d0_box_layout = QHBoxLayout() d0_box_layout.addWidget(QLabel("d₀")) validator = QDoubleValidator() validator.setBottom(0) self.d0 = QLineEdit() self.d0.setValidator(validator) self.d0.editingFinished.connect(self.update_d0) d0_box_layout.addWidget(self.d0) d0_box_layout.addWidget(QLabel("Δd₀")) self.d0e = QLineEdit() self.d0e.setValidator(validator) self.d0e.editingFinished.connect(self.update_d0) d0_box_layout.addWidget(self.d0e) self.d0_box.setLayout(d0_box_layout) layout.addWidget(self.d0_box) load_save = QWidget() load_save_layout = QHBoxLayout() self.load_grid = QPushButton("Load d₀ Grid") self.load_grid.clicked.connect(self.load_d0_field) load_save_layout.addWidget(self.load_grid) self.save_grid = QPushButton("Save d₀ Grid") self.save_grid.clicked.connect(self.save_d0_field) load_save_layout.addWidget(self.save_grid) load_save.setLayout(load_save_layout) layout.addWidget(load_save) self.d0_grid = QTableWidget() self.d0_grid.setColumnCount(5) self.d0_grid.setColumnWidth(0, 60) self.d0_grid.setColumnWidth(1, 60) self.d0_grid.setColumnWidth(2, 60) self.d0_grid.setColumnWidth(3, 60) self.d0_grid.verticalHeader().setVisible(False) self.d0_grid.horizontalHeader().setStretchLastSection(True) self.d0_grid.setHorizontalHeaderLabels(['vx', 'vy', 'vz', "d₀", "Δd₀"]) spinBoxDelegate = SpinBoxDelegate() self.d0_grid.setItemDelegateForColumn(3, spinBoxDelegate) self.d0_grid.setItemDelegateForColumn(4, spinBoxDelegate) layout.addWidget(self.d0_grid) self.setLayout(layout) self.set_case('Constant') def set_case(self, case): if case == "Constant": self.d0_box.setEnabled(True) self.load_grid.setEnabled(False) self.save_grid.setEnabled(False) self.d0_grid.setEnabled(False) else: self.d0_box.setEnabled(False) self.load_grid.setEnabled(True) self.save_grid.setEnabled(True) self.d0_grid.setEnabled(True) def update_d0(self): self._parent.update_plot() def set_d0(self, d0, d0e): if d0 is None: self.d0.clear() self.d0e.clear() else: self.d0.setText(str(d0)) self.d0e.setText(str(d0e)) def set_d0_field(self, x, y, z, d0, d0e): if x is None: self.d0_grid.clearContents() else: self.d0_grid.setRowCount(len(x)) for n in range(len(x)): x_item = QTableWidgetItem(f'{x[n]: 7.2f}') x_item.setFlags(x_item.flags() ^ Qt.ItemIsEditable) y_item = QTableWidgetItem(f'{y[n]: 7.2f}') y_item.setFlags(y_item.flags() ^ Qt.ItemIsEditable) z_item = QTableWidgetItem(f'{z[n]: 7.2f}') z_item.setFlags(z_item.flags() ^ Qt.ItemIsEditable) d0_item = QTableWidgetItem() d0_item.setData(Qt.EditRole, float(d0[n])) d0e_item = QTableWidgetItem() d0e_item.setData(Qt.EditRole, float(d0e[n])) self.d0_grid.setItem(n, 0, QTableWidgetItem(x_item)) self.d0_grid.setItem(n, 1, QTableWidgetItem(y_item)) self.d0_grid.setItem(n, 2, QTableWidgetItem(z_item)) self.d0_grid.setItem(n, 3, QTableWidgetItem(d0_item)) self.d0_grid.setItem(n, 4, QTableWidgetItem(d0e_item)) def get_d0_field(self): if self.d0_grid.rowCount() == 0: return None else: x = [ float(self.d0_grid.item(row, 0).text()) for row in range(self.d0_grid.rowCount()) ] y = [ float(self.d0_grid.item(row, 1).text()) for row in range(self.d0_grid.rowCount()) ] z = [ float(self.d0_grid.item(row, 2).text()) for row in range(self.d0_grid.rowCount()) ] d0 = [ float(self.d0_grid.item(row, 3).text()) for row in range(self.d0_grid.rowCount()) ] d0e = [ float(self.d0_grid.item(row, 4).text()) for row in range(self.d0_grid.rowCount()) ] return (d0, d0e, x, y, z) def save_d0_field(self): filename, _ = QFileDialog.getSaveFileName( self, "Save d0 Grid", "", "CSV (*.csv);;All Files (*)") if filename: d0, d0e, x, y, z = self.get_d0_field() np.savetxt(filename, np.array([x, y, z, d0, d0e]).T, fmt=['%.4g', '%.4g', '%.4g', '%.9g', '%.9g'], header="vx, vy, vz, d0, d0_error", delimiter=',') def load_d0_field(self): filename, _ = QFileDialog.getOpenFileName( self, "Load d0 Grid", "", "CSV (*.csv);;All Files (*)") if filename: x, y, z, d0, d0e = np.loadtxt(filename, delimiter=',', unpack=True) self.set_d0_field(x, y, z, d0, d0e) def get_d0(self): if self.d0_grid_switch.currentText() == "Constant": try: return (float(self.d0.text()), float(self.d0e.text())) except ValueError: return None else: return self.get_d0_field()