コード例 #1
0
ファイル: passwordctrl.py プロジェクト: hzyrc6011/pmgwidgets
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()
コード例 #2
0
ファイル: BotShellWidget.py プロジェクト: desty2k/QtPyBotnet
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)
コード例 #3
0
ファイル: Window.py プロジェクト: desty2k/QtPyBotnet
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)
コード例 #4
0
ファイル: numctrl.py プロジェクト: hzyrc6011/pmgwidgets
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
コード例 #5
0
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)
コード例 #6
0
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)
コード例 #7
0
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)
コード例 #8
0
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')
コード例 #9
0
ファイル: Window.py プロジェクト: desty2k/QtPyBotnet
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()
コード例 #10
0
ファイル: colorctrl.py プロジェクト: hzyrc6011/pmgwidgets
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
コード例 #11
0
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()
コード例 #12
0
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()