From 74d119d7c5b6268f33d5e8c7cf3c0a2ab379635a Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Tue, 20 Apr 2021 17:26:39 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E7=94=A8=20qsettings=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E4=BA=86=E6=9B=B4=E6=96=B0=E7=9A=84=E8=AE=BE=E7=BD=AE=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app2.py | 45 +++- configuration/config.ini | 8 + features/io/settings.py | 4 +- features/main_window/base.py | 66 +++--- features/ui/ui_option.py | 124 +++++------ features/ui/ui_option.ui | 119 +++++----- features/util/update.py | 12 +- load_modules.py | 9 +- packages/code_editor/codeeditor/tabwidget.py | 8 +- packages/qt_vditor/client.py | 11 +- packages/qt_vditor/examples/sample.md | 7 + pmgwidgets/utilities/platform/fileutils.py | 9 +- pmlocalserver/server.py | 4 +- utils/__init__.py | 114 +++++----- utils/path.py | 73 ++++++- utils/settings/__init__.py | 1 + utils/settings/settings.py | 217 +++++++++++++++++++ 17 files changed, 560 insertions(+), 271 deletions(-) create mode 100644 configuration/config.ini create mode 100644 packages/qt_vditor/examples/sample.md create mode 100644 utils/settings/__init__.py create mode 100644 utils/settings/settings.py diff --git a/app2.py b/app2.py index 226e3271..862d0d93 100644 --- a/app2.py +++ b/app2.py @@ -65,7 +65,7 @@ os.environ['FORCE_QT_API'] = "1" from typing import List, Callable, Tuple, ClassVar from PySide2.QtCore import Signal, QTimer, Qt, QCoreApplication from PySide2.QtGui import QCloseEvent, QTextCursor, QResizeEvent, QMoveEvent, QFont, QIcon, QPixmap -from PySide2.QtWidgets import QApplication, QMessageBox, QSplashScreen, QStatusBar +from PySide2.QtWidgets import QApplication, QMessageBox, QSplashScreen, QStatusBar, QDialog, QVBoxLayout, QProgressBar import pmgwidgets pmgwidgets.in_unit_test = lambda: False @@ -76,7 +76,7 @@ from features.main_window import base from features.io.settings import Settings from features.io.settings import load_theme from features.interpretermanager.interpretermanager import InterpreterManagerWidget -from features.util.update import perform_update, UpdateTipClient +from features.util.update import UpdateTipClient from features.feedback import FeedbackClient from features.ui.widgets.controlpanel import PMPageExt from features.ui.pmwidgets import BaseMainWindow @@ -140,9 +140,8 @@ class MainWindow(BaseMainWindow): def __init__(self, parent=None): super().__init__(parent) - - t00 = time.time() settings = Settings() + t00 = time.time() self.main_option_form = base.OptionForm() self.project_wizard: base.ProjectWizardForm = None self.settings_changed_signal.connect(self.on_settings_changed) @@ -191,7 +190,8 @@ class MainWindow(BaseMainWindow): dw.setMaximumWidth(400) # 设置主题 ,组件都加载后再设置主题,否则可能有些组件不生效 - load_theme(settings['theme']) + settings = utils.get_settings_from_file("config.ini") + load_theme(settings.value("MAIN/THEME")) self.show() self.load_layout() @@ -200,7 +200,7 @@ class MainWindow(BaseMainWindow): self.on_main_window_shown() self.start_pmlocalserver() # 只要在插件加载完成之后启动就行,目前放在最后 - self.update_tip_client = UpdateTipClient() # 启动程序,检查更新,弹窗提醒 + self.update_tip_client = UpdateTipClient(True) # 启动程序,检查更新,弹窗提醒 t01 = time.time() logging.debug('Time Elapsed for loading main window contents: %f' % (t01 - t00)) @@ -219,7 +219,6 @@ class MainWindow(BaseMainWindow): a0.accept() self.delete_temporary_dock_windows() self.save_layout() # TODO:PySide2上存储布局有问题。 - Settings.get_instance().save() self.close_signal.emit() self.extensions_manager.stop() for k in self.dock_widgets.keys(): @@ -282,7 +281,12 @@ class MainWindow(BaseMainWindow): self.window_geometry_changed_signal.emit() def on_settings_changed(self): - load_theme(Settings.get_instance()['theme']) + """ + 当设置项发生改变时,加载这些设置项。 + Returns: + + """ + load_theme(utils.get_settings_from_file("config.ini").value("MAIN/THEME")) def delayed_call(self, time_ms: int, callback: Callable) -> None: """ @@ -368,7 +372,25 @@ class MainWindow(BaseMainWindow): """ 打开'检查更新'页面 """ - perform_update() + # perform_update() + dlg = QDialog() + dlg.setLayout(QVBoxLayout()) + proc = QProgressBar() + dlg.layout().addWidget(proc) + dlg.setWindowTitle("请稍等,正在进行更新检查") + proc.setRange(0, 0) + + def close(b): + if b: + dlg.close() + else: + dlg.close() + QMessageBox.information(self, "更新提示", "已经是最新版,无需更新!") + + self.update_tip_client = UpdateTipClient(False) + self.update_tip_client.thread.exist_update.connect(close) + + dlg.exec_() def main_install_update(self): closed = self.close() @@ -479,8 +501,9 @@ def main(test_function: Callable[[MainWindow], None] = None): splash.finish(window) if test_function is None: - # 展示快速启动窗口 - window.first_form_display() + # 展示快速启动窗口。只有在设置为True的情况下才显示起始页。 + if utils.get_settings_item_from_file("config.ini", "MAIN/SHOW_START_PAGE"): + window.first_form_display() else: test_function(window) logging.info('boot time elapsed:%f s' % (t1 - t0)) diff --git a/configuration/config.ini b/configuration/config.ini new file mode 100644 index 00000000..207edccc --- /dev/null +++ b/configuration/config.ini @@ -0,0 +1,8 @@ +[MAIN] +THEME = Fusion +LANGUAGE = zh_CN +PATH_OUTPUT = +PATH_WORKDIR = +INTERPRETER = d:/pyminer/python.exe +SHOW_START_PAGE = True +CHECK_UPDATE = True diff --git a/features/io/settings.py b/features/io/settings.py index 30b6c6d3..58eaf48b 100644 --- a/features/io/settings.py +++ b/features/io/settings.py @@ -1,4 +1,5 @@ """ +TODO:DEPRECATED。这个文件将被废弃! settings.py负责设置文件的输入输出。 Settings继承字典类,另外写了存储函数。 还有其他设置的函数 @@ -40,6 +41,7 @@ import platform from typing import Dict from PySide2.QtWidgets import QApplication + import qdarkstyle import utils @@ -49,7 +51,7 @@ logger = logging.getLogger(__name__) def get_pyminer_data_path() -> str: path = os.path.join(os.path.expanduser('~'), '.pyminer') if not os.path.exists(path): - os.mkdir(path) + os.makedirs(path) return path diff --git a/features/main_window/base.py b/features/main_window/base.py index 57d2f341..1a48a628 100644 --- a/features/main_window/base.py +++ b/features/main_window/base.py @@ -1,31 +1,27 @@ import os import sys -import time -import subprocess import webbrowser -from typing import Tuple, List +from typing import List -import qdarkstyle -from PySide2.QtCore import QPoint, QRectF -from PySide2.QtGui import QMouseEvent, QPainter, QLinearGradient -from PySide2.QtGui import QCloseEvent +from PySide2.QtCore import QPoint from PySide2.QtCore import Signal, Qt, QUrl, QPropertyAnimation -from PySide2.QtWidgets import QApplication, QListWidgetItem, QWizard, QHeaderView, QMessageBox +from PySide2.QtGui import QCloseEvent +from PySide2.QtGui import QMouseEvent from PySide2.QtWebEngineWidgets import * +from PySide2.QtWidgets import QListWidgetItem, QWizard, QMessageBox from PySide2.QtWidgets import QWidget, QDesktopWidget, QFileDialog, QApplication, QDialog -from pmgwidgets import PMGPanel -from features.ui.ui_option import Ui_Form as Option_Ui_Form -from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form +import utils +from features.extensions.extensionlib.extension_lib import extension_lib +from features.io.settings import Settings from features.ui.ui_aboutme import Ui_Form as About_Ui_Form -from features.ui.ui_project_wizard import Ui_Wizard as Project_Ui_Form +from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form from features.ui.ui_first_form import Ui_Form as first_Ui_Form -import utils +from features.ui.ui_option import Ui_Form as Option_Ui_Form +from features.ui.ui_project_wizard import Ui_Wizard as Project_Ui_Form +from pmgwidgets import PMGPanel from utils import get_main_window -from features.io.settings import Settings -from features.extensions.extensionlib.extension_lib import extension_lib - class OptionForm(QDialog, Option_Ui_Form): """ @@ -53,21 +49,12 @@ class OptionForm(QDialog, Option_Ui_Form): self.pushButton_cancel.clicked.connect(self.close) self.pushButton_ok.clicked.connect(self.close) self.pushButton_help.clicked.connect(self.get_help) - self.get_check_update() - - def get_check_update(self): - """是否启动检查更新""" - check_update = Settings.get_instance().get('check_update') - if check_update is None: - self.checkBox.setChecked(True) # 默认检查更新 - else: - self.checkBox.setChecked(check_update) def setup_ui(self): self.comboBox_9.setEnabled(False) self.comboBox_8.setEnabled(False) - self.checkBox_2.setEnabled(False) - self.checkBox_minitray.setEnabled(False) + # self.checkbox_show_startpage.setEnabled(False) + # self.checkBox_minitray.setEnabled(False) def add_settings_panel(self, text: str, settings_content: List): settings_widget = PMGPanel(views=settings_content) @@ -132,22 +119,31 @@ class OptionForm(QDialog, Option_Ui_Form): 从而每次重新显示的时候都可以刷新数据。 :return: """ - settings = Settings.get_instance() - if settings.get('theme') is not None: + settings = utils.get_settings_from_file("config.ini") + print(settings.value('MAIN/PATH_WORKDIR')) + if settings.value('MAIN/THEME') is not None: for i in range(self.comboBox_theme.count()): - if self.comboBox_theme.itemText(i) == settings['theme']: + if self.comboBox_theme.itemText(i) == settings.value('MAIN/THEME'): self.comboBox_theme.setCurrentIndex(i) - self.lineEdit_worksapce.setText(settings['work_dir']) + self.lineEdit_worksapce.setText(settings.value("MAIN/PATH_WORKDIR")) + self.lineEdit_output.setText(settings.value("MAIN/PATH_OUTPUT")) + + check_update = utils.get_settings_item_from_file("config.ini", "MAIN/CHECK_UPDATE") + show_start_page = utils.get_settings_item_from_file("config.ini", "MAIN/SHOW_START_PAGE") + self.check_box_check_upd_on_startup.setChecked(check_update) + self.checkbox_show_startpage.setChecked(show_start_page) + def refresh_settings(self): """ 窗口关闭时,调用此方法,刷新主界面设置项。 :return: """ - settings = Settings.get_instance() - settings['work_dir'] = self.lineEdit_worksapce.text() - settings['theme'] = self.comboBox_theme.currentText() - settings['check_update'] = self.checkBox.isChecked() # 设置是否检查更新 + utils.write_settings_item_to_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText()) + utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", self.lineEdit_worksapce.text()) + utils.write_settings_item_to_file("config.ini", "MAIN/PATH_OUTPUT", self.lineEdit_output.text()) + utils.write_settings_item_to_file("config.ini", "MAIN/CHECK_UPDATE", self.check_box_check_upd_on_startup.isChecked()) + utils.write_settings_item_to_file("config.ini", "MAIN/SHOW_START_PAGE", self.checkbox_show_startpage.isChecked()) get_main_window().on_settings_changed() self.signal_settings_changed.emit() diff --git a/features/ui/ui_option.py b/features/ui/ui_option.py index 38cf32e7..13fc3958 100644 --- a/features/ui/ui_option.py +++ b/features/ui/ui_option.py @@ -46,50 +46,24 @@ class Ui_Form(object): self.verticalLayout_8.setObjectName(u"verticalLayout_8") self.formLayout_2 = QFormLayout() self.formLayout_2.setObjectName(u"formLayout_2") - self.label = QLabel(self.tabBase) - self.label.setObjectName(u"label") - - self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.label) - - self.label_15 = QLabel(self.tabBase) - self.label_15.setObjectName(u"label_15") - - self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_15) - - self.checkBox = QCheckBox(self.tabBase) - self.checkBox.setObjectName(u"checkBox") - self.checkBox.setChecked(True) - - self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.checkBox) - - self.checkBox_2 = QCheckBox(self.tabBase) - self.checkBox_2.setObjectName(u"checkBox_2") - - self.formLayout_2.setWidget(7, QFormLayout.LabelRole, self.checkBox_2) - - self.label_16 = QLabel(self.tabBase) - self.label_16.setObjectName(u"label_16") - - self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.label_16) - - self.comboBox_9 = QComboBox(self.tabBase) - self.comboBox_9.addItem("") - self.comboBox_9.addItem("") - self.comboBox_9.setObjectName(u"comboBox_9") + self.label_theme = QLabel(self.tabBase) + self.label_theme.setObjectName(u"label_theme") - self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.comboBox_9) + self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_theme) - self.label_11 = QLabel(self.tabBase) - self.label_11.setObjectName(u"label_11") + self.comboBox_theme = QComboBox(self.tabBase) + self.comboBox_theme.addItem("") + self.comboBox_theme.addItem("") + self.comboBox_theme.addItem("") + self.comboBox_theme.addItem("") + self.comboBox_theme.setObjectName(u"comboBox_theme") - self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.label_11) + self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.comboBox_theme) - self.comboBox_8 = QComboBox(self.tabBase) - self.comboBox_8.addItem("") - self.comboBox_8.addItem("") - self.comboBox_8.setObjectName(u"comboBox_8") + self.label = QLabel(self.tabBase) + self.label.setObjectName(u"label") - self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.comboBox_8) + self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.label) self.horizontalLayout_14 = QHBoxLayout() self.horizontalLayout_14.setObjectName(u"horizontalLayout_14") @@ -106,6 +80,11 @@ class Ui_Form(object): self.formLayout_2.setLayout(1, QFormLayout.FieldRole, self.horizontalLayout_14) + self.label_15 = QLabel(self.tabBase) + self.label_15.setObjectName(u"label_15") + + self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_15) + self.horizontalLayout_15 = QHBoxLayout() self.horizontalLayout_15.setObjectName(u"horizontalLayout_15") self.lineEdit_output = QLineEdit(self.tabBase) @@ -121,25 +100,41 @@ class Ui_Form(object): self.formLayout_2.setLayout(2, QFormLayout.FieldRole, self.horizontalLayout_15) - self.label_theme = QLabel(self.tabBase) - self.label_theme.setObjectName(u"label_theme") + self.label_16 = QLabel(self.tabBase) + self.label_16.setObjectName(u"label_16") - self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.label_theme) + self.formLayout_2.setWidget(3, QFormLayout.LabelRole, self.label_16) - self.comboBox_theme = QComboBox(self.tabBase) - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.addItem("") - self.comboBox_theme.setObjectName(u"comboBox_theme") + self.comboBox_9 = QComboBox(self.tabBase) + self.comboBox_9.addItem("") + self.comboBox_9.addItem("") + self.comboBox_9.setObjectName(u"comboBox_9") - self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.comboBox_theme) + self.formLayout_2.setWidget(3, QFormLayout.FieldRole, self.comboBox_9) - self.checkBox_minitray = QCheckBox(self.tabBase) - self.checkBox_minitray.setObjectName(u"checkBox_minitray") - self.checkBox_minitray.setChecked(True) + self.label_11 = QLabel(self.tabBase) + self.label_11.setObjectName(u"label_11") - self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.checkBox_minitray) + self.formLayout_2.setWidget(4, QFormLayout.LabelRole, self.label_11) + + self.comboBox_8 = QComboBox(self.tabBase) + self.comboBox_8.addItem("") + self.comboBox_8.addItem("") + self.comboBox_8.setObjectName(u"comboBox_8") + + self.formLayout_2.setWidget(4, QFormLayout.FieldRole, self.comboBox_8) + + self.check_box_check_upd_on_startup = QCheckBox(self.tabBase) + self.check_box_check_upd_on_startup.setObjectName(u"check_box_check_upd_on_startup") + self.check_box_check_upd_on_startup.setChecked(True) + + self.formLayout_2.setWidget(5, QFormLayout.LabelRole, self.check_box_check_upd_on_startup) + + self.checkbox_show_startpage = QCheckBox(self.tabBase) + self.checkbox_show_startpage.setObjectName(u"checkbox_show_startpage") + self.checkbox_show_startpage.setChecked(True) + + self.formLayout_2.setWidget(6, QFormLayout.LabelRole, self.checkbox_show_startpage) self.verticalLayout_8.addLayout(self.formLayout_2) @@ -354,7 +349,7 @@ class Ui_Form(object): self.retranslateUi(Form) - self.stackedWidget.setCurrentIndex(2) + self.stackedWidget.setCurrentIndex(0) self.tabWidget.setCurrentIndex(0) @@ -374,10 +369,16 @@ class Ui_Form(object): ___qlistwidgetitem2.setText(QCoreApplication.translate("Form", u"\u683c\u5f0f\u5316", None)); self.listWidget.setSortingEnabled(__sortingEnabled) + self.label_theme.setText(QCoreApplication.translate("Form", u"UI Theme", None)) + self.comboBox_theme.setItemText(0, QCoreApplication.translate("Form", u"Fusion", None)) + self.comboBox_theme.setItemText(1, QCoreApplication.translate("Form", u"Qdarkstyle", None)) + self.comboBox_theme.setItemText(2, QCoreApplication.translate("Form", u"windowsvista", None)) + self.comboBox_theme.setItemText(3, QCoreApplication.translate("Form", u"Windows", None)) + self.label.setText(QCoreApplication.translate("Form", u"Work Directory", None)) + self.toolButton_workspace.setText(QCoreApplication.translate("Form", u"...", None)) self.label_15.setText(QCoreApplication.translate("Form", u"Output Directory", None)) - self.checkBox.setText(QCoreApplication.translate("Form", u"Check upd on startup", None)) - self.checkBox_2.setText(QCoreApplication.translate("Form", u"Start with system", None)) + self.toolButton_output.setText(QCoreApplication.translate("Form", u"...", None)) self.label_16.setText(QCoreApplication.translate("Form", u"UI Language", None)) self.comboBox_9.setItemText(0, QCoreApplication.translate("Form", u"\u7b80\u4f53\u4e2d\u6587", None)) self.comboBox_9.setItemText(1, QCoreApplication.translate("Form", u"English", None)) @@ -386,15 +387,8 @@ class Ui_Form(object): self.comboBox_8.setItemText(0, QCoreApplication.translate("Form", u"utf-8", None)) self.comboBox_8.setItemText(1, QCoreApplication.translate("Form", u"gb2312", None)) - self.toolButton_workspace.setText(QCoreApplication.translate("Form", u"...", None)) - self.toolButton_output.setText(QCoreApplication.translate("Form", u"...", None)) - self.label_theme.setText(QCoreApplication.translate("Form", u"UI Theme", None)) - self.comboBox_theme.setItemText(0, QCoreApplication.translate("Form", u"Fusion", None)) - self.comboBox_theme.setItemText(1, QCoreApplication.translate("Form", u"Qdarkstyle", None)) - self.comboBox_theme.setItemText(2, QCoreApplication.translate("Form", u"windowsvista", None)) - self.comboBox_theme.setItemText(3, QCoreApplication.translate("Form", u"Windows", None)) - - self.checkBox_minitray.setText(QCoreApplication.translate("Form", u"Minimize to tray", None)) + self.check_box_check_upd_on_startup.setText(QCoreApplication.translate("Form", u"Check upd on startup", None)) + self.checkbox_show_startpage.setText(QCoreApplication.translate("Form", u"\u663e\u793a\u8d77\u59cb\u9875\u9762", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabBase), QCoreApplication.translate("Form", u"Basic", None)) self.checkBox_3.setText(QCoreApplication.translate("Form", u"Interlaced coloring", None)) self.label_10.setText(QCoreApplication.translate("Form", u"Table Header Background:", None)) diff --git a/features/ui/ui_option.ui b/features/ui/ui_option.ui index addaebe8..645ab651 100644 --- a/features/ui/ui_option.ui +++ b/features/ui/ui_option.ui @@ -44,7 +44,7 @@ - 2 + 0 @@ -75,79 +75,44 @@ - - - - Work Directory - - - - - - - Output Directory - - - - - - - Check upd on startup - - - true - - - - - - - Start with system - - - - - + + - UI Language + UI Theme - - + + - 简体中文 + Fusion - English + Qdarkstyle - - - - - - Encoding - - - - - - utf-8 + windowsvista - gb2312 + Windows + + + + Work Directory + + + @@ -162,6 +127,13 @@ + + + + Output Directory + + + @@ -176,41 +148,62 @@ - - + + - UI Theme + UI Language - - + + - Fusion + 简体中文 - Qdarkstyle + English + + + + + + Encoding + + + + + - windowsvista + utf-8 - Windows + gb2312 + + + + Check upd on startup + + + true + + + - + - Minimize to tray + 显示起始页面 true diff --git a/features/util/update.py b/features/util/update.py index 9c30689d..22aad5c8 100644 --- a/features/util/update.py +++ b/features/util/update.py @@ -11,7 +11,7 @@ from PySide2.QtCore import Qt, QThread, Signal from PySide2.QtWidgets import QProgressBar, QVBoxLayout, QLabel, QApplication, QDesktopWidget, QDialog, QHBoxLayout, \ QPushButton, QTableWidgetItem, QHeaderView, QTableView -from features.io.settings import Settings +import utils from features.util.check_update_ui import Ui_Dialog from features.util.make_update import should_be_recorded @@ -184,7 +184,6 @@ class UpdateClientThread(BaseUpdateThread): return if response.status_code == 200: local_path = self.root.joinpath(item) - # local_path = Path('D:/temp/temp').joinpath(item) if not local_path.parent.is_dir(): os.makedirs(local_path.parent) with open(local_path, 'wb') as f: @@ -208,23 +207,23 @@ class UpdateClientThread(BaseUpdateThread): class UpdateTipClient(Ui_Dialog): - def __init__(self): + def __init__(self, startup: bool): self.dialog = QDialog() self.setupUi(self.dialog) self.url = MD5_JSON_URL self.update_files_list = [] self.delete_files_list = [] self.root = Path(__file__).parent.parent.parent.parent - self.is_start_thread() + self.is_start_thread(startup) - def is_start_thread(self): + def is_start_thread(self, startup: bool): """ 根据根目录下是否存在.git目录,判断是否处于开发状态,开发状态不检查更新 根据设置界面检查更新checkbox是否为True,决定是否启动检查更新 """ if self.root.joinpath('.git').is_dir(): return - if Settings.get_instance().get('check_update'): + if not (startup and (not utils.get_settings_item_from_file("config.ini", "MAIN/CHECK_UPDATE"))): self.thread = UpdateTipThread(url=self.url) self.thread.update_files_list.connect(self.set_update_files_list) self.thread.delete_files_list.connect(self.set_delete_files_list) @@ -283,7 +282,6 @@ class UpdateTipClient(Ui_Dialog): def set_exist_update(self, flag): """ 存在更新则启动界面 - TODO:暂时不要启动这样的更新界面了。要更新的话,手动更新.因为现在设置项还没有做好。 """ if flag: self.init_gui() diff --git a/load_modules.py b/load_modules.py index 01602d0e..14542a2d 100644 --- a/load_modules.py +++ b/load_modules.py @@ -1,8 +1,11 @@ +import logging +import os + from PySide2.QtCore import QTranslator, QSettings from PySide2.QtGui import QFontDatabase from PySide2.QtWidgets import QApplication -from utils import * +from utils import get_root_dir, get_config_file_dir logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) @@ -18,14 +21,12 @@ def load_translator(app: QApplication): app.translator = QTranslator() app.translator2 = QTranslator() - settings = QSettings(os.path.join(get_root_dir(), "config.ini"), QSettings.IniFormat) + settings = QSettings(get_config_file_dir("config.ini"), QSettings.IniFormat) language = settings.value("MAIN/LANGUAGE") logger.debug("获取设置项MAIN/LANGUAGE: %s" % language) - print(get_root_dir()) path_lang = os.path.join(get_root_dir(), 'languages', '{}'.format(language), '{}.qm'.format(language)) logger.debug("翻译文件的路径:%s" % path_lang) - if os.path.isfile(path_lang): app.translator.load(path_lang) app.installTranslator(app.translator) diff --git a/packages/code_editor/codeeditor/tabwidget.py b/packages/code_editor/codeeditor/tabwidget.py index ea32224e..afe5f295 100644 --- a/packages/code_editor/codeeditor/tabwidget.py +++ b/packages/code_editor/codeeditor/tabwidget.py @@ -976,11 +976,9 @@ if __name__ == '__main__': w.setMinimumHeight(600) w.setup_ui() code_editor_root_directory = os.path.dirname(__file__) - # w.slot_new_script( - # '/home/hzy/Desktop/create_dataset.py') # os.path.join(code_editor_root_directory, 'tests', 'test_file.py')) w.slot_new_script(r'C:/Users/12957/documents/developing/Python/pyminer_workdir/app_designer.py') w.currentWidget().goto_line(5) - # w.on_work_dir_changed(r'C:\Users\12957\AppData') - # w.slot_new_script(r'c:/users/12957/desktop/test.md') - # w.on_work_dir_changed('c:/users/12957/desktop') + # w.on_work_dir_changed(r'') + # w.slot_new_script(r'') + # w.on_work_dir_changed('') sys.exit(app.exec_()) diff --git a/packages/qt_vditor/client.py b/packages/qt_vditor/client.py index 74dde821..2031bd97 100644 --- a/packages/qt_vditor/client.py +++ b/packages/qt_vditor/client.py @@ -1,11 +1,12 @@ +import json import os -from PySide2 import QtWidgets, QtCore -from PySide2.QtWebEngineWidgets import QWebEngineView -import sys import re +import sys import time + import requests -import json +from PySide2 import QtWidgets, QtCore +from PySide2.QtWebEngineWidgets import QWebEngineView class Window(QtWidgets.QDialog): @@ -80,6 +81,6 @@ class Window(QtWidgets.QDialog): if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) win = Window(url='http://127.0.0.1:5000/qt_vditor') - win.load_file(file_path='D:/pyminer/pyminer2/extensions/packages/pmagg/sample/sample_code.md') + win.load_file(file_path=os.path.join(os.path.dirname(__file__), "examples", "sample.md")) win.show() app.exec_() diff --git a/packages/qt_vditor/examples/sample.md b/packages/qt_vditor/examples/sample.md new file mode 100644 index 00000000..da6e237a --- /dev/null +++ b/packages/qt_vditor/examples/sample.md @@ -0,0 +1,7 @@ +# 这是一个Markdown文件的一级标题 +## 这是一个Markdown文件的二级标题 +```python +def func(): + print("Hello Vditor!") +func() +``` \ No newline at end of file diff --git a/pmgwidgets/utilities/platform/fileutils.py b/pmgwidgets/utilities/platform/fileutils.py index 757a5645..f681e9dd 100644 --- a/pmgwidgets/utilities/platform/fileutils.py +++ b/pmgwidgets/utilities/platform/fileutils.py @@ -1,4 +1,5 @@ import os + import chardet @@ -129,9 +130,5 @@ def copy_paste(source_path: str, target_path: str): if __name__ == '__main__': - # move_to_trash('C:/Users/12957/Desktop/1.jpg') - create_file_if_not_exist(r'c:/users/12957/Desktop/rwrweew/ddddd/ggwewe/aaaaaa/as.a') - create_file_if_not_exist(r'c:/users/12957/Desktop/rwrweew/ddddd/ggwewe/aaaaaa/aa.s') - print(get_parent_path(r'c:/users/12957/desktop', 2)) - print(load_json( - r'/pyminer2/extensions/packages/code_editor/customized/settings.json')) + print(get_parent_path(os.path.dirname(__file__), 2)) + print(load_json(r'/pyminer2/extensions/packages/code_editor/customized/settings.json')) diff --git a/pmlocalserver/server.py b/pmlocalserver/server.py index 9d86addd..e9370246 100644 --- a/pmlocalserver/server.py +++ b/pmlocalserver/server.py @@ -1,7 +1,7 @@ -from flask import Flask +import threading +from flask import Flask from flask_cors import CORS -import threading server = Flask(__name__, static_folder='static', static_url_path='/static') CORS(server, supports_credentials=True) # 解决跨域 diff --git a/utils/__init__.py b/utils/__init__.py index fcb4d50b..e03a1832 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -3,17 +3,10 @@ # # 通用工具,可以在全局进行调用。 -import os -import datetime -import logging import webbrowser +from typing import TYPE_CHECKING -from .path import ( - get_root_dir, - get_user_dir, - get_desktop_dir, - get_documents_dir, -) +from .debug import * from .environ import ( get_python_version, get_python_modules_directory, @@ -21,6 +14,17 @@ from .environ import ( getScriptsPath, getDesignerPath ) +from .io import * +from .path import ( + get_root_dir, + get_user_dir, + get_desktop_dir, + get_documents_dir, + get_pyminer_data_dir, + get_user_config_dir, + get_default_config_dir, + get_config_file_dir +) from .platform import ( is_windows_platform, is_mac_platform, @@ -28,13 +32,9 @@ from .platform import ( is_kde_desktop, is_gnome_desktop ) - -from .io import * -from .debug import * +from .settings import * from .ui import * -from typing import TYPE_CHECKING - if TYPE_CHECKING: import pmgui version = 'v2.1.0 Beta' @@ -81,46 +81,46 @@ def open_url(url): webbrowser.open_new_tab(url) -def unzip_file(zip_src: str, dst_dir: str): - """ - 解压文件 - Args: - zip_src: - dst_dir: - - Returns: - - """ - r = zipfile.is_zipfile(zip_src) - if r: - fz = zipfile.ZipFile(zip_src, 'r') - for file in fz.namelist(): - fz.extract(file, dst_dir) - else: - print('This is not zip') - - -def make_zip(src_path, zip_dist_path, root='', rules=None): - """ - 创建zip包 - Args: - src_path: - zip_dist_path: - root: - rules: - - Returns: - - """ - if rules is None: - rules = [] - z = zipfile.ZipFile(zip_dist_path, 'w', zipfile.ZIP_DEFLATED) - for dirpath, dirnames, filenames in os.walk(src_path): - relpath = os.path.relpath(dirpath, src_path) - if is_neglect_path(relpath, rules): - continue - fpath = os.path.relpath(dirpath, src_path) - for filename in filenames: - filepath = os.path.join(dirpath, filename) - z.write(filepath, os.path.join(root, fpath, filename)) - z.close() +# def unzip_file(zip_src: str, dst_dir: str): +# """ +# 解压文件 +# Args: +# zip_src: +# dst_dir: +# +# Returns: +# +# """ +# r = zipfile.is_zipfile(zip_src) +# if r: +# fz = zipfile.ZipFile(zip_src, 'r') +# for file in fz.namelist(): +# fz.extract(file, dst_dir) +# else: +# print('This is not zip') +# +# +# def make_zip(src_path, zip_dist_path, root='', rules=None): +# """ +# 创建zip包 +# Args: +# src_path: +# zip_dist_path: +# root: +# rules: +# +# Returns: +# +# """ +# if rules is None: +# rules = [] +# z = zipfile.ZipFile(zip_dist_path, 'w', zipfile.ZIP_DEFLATED) +# for dirpath, dirnames, filenames in os.walk(src_path): +# relpath = os.path.relpath(dirpath, src_path) +# if is_neglect_path(relpath, rules): +# continue +# fpath = os.path.relpath(dirpath, src_path) +# for filename in filenames: +# filepath = os.path.join(dirpath, filename) +# z.write(filepath, os.path.join(root, fpath, filename)) +# z.close() diff --git a/utils/path.py b/utils/path.py index dd93c327..fc36a962 100644 --- a/utils/path.py +++ b/utils/path.py @@ -3,9 +3,12 @@ # Get application path information # 获取应用路径信息 import os -import sys +import shutil + from PySide2.QtCore import QStandardPaths +from .settings import SETTINGS_FILES + def get_root_dir() -> str: """ @@ -121,21 +124,71 @@ def get_path_generic_cache() -> str: return path -def get_path_generic_config() -> str: - path = QStandardPaths.writableLocation(QStandardPaths.GenericConfigLocation) +# def get_path_generic_config() -> str: +# path = QStandardPaths.writableLocation(QStandardPaths.GenericConfigLocation) +# return path + + +# def get_path_app_data() -> str: +# path = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation) +# return path + + +# def get_path_app_config() -> str: +# path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation) +# return path + + +def get_path_app_local_data() -> str: + path = QStandardPaths.writableLocation(QStandardPaths.AppLocalDataLocation) return path -def get_path_app_data() -> str: - path = QStandardPaths.writableLocation(QStandardPaths.AppDataLocation) +def get_pyminer_data_dir() -> str: + """ + 获取PyMiner的数据文件存储位置,一般为.pyminer文件夹。 + Returns: + + """ + path = os.path.join(os.path.expanduser('~'), '.pyminer') + if not os.path.exists(path): + os.makedirs(path) return path -def get_path_app_config() -> str: - path = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation) +def get_default_config_dir() -> str: + """ + 获取PyMiner默认设置的位置。软件第一次运行时,从这里获取设置,并且将设置拷贝到用户目录下面。。 + Returns: + + """ + return os.path.join(get_root_dir(), "configuration") + + +def get_user_config_dir() -> str: + """ + 获取用户的设置目录。 .pyminer/pyminer_config + Returns: + + """ + path = os.path.join(get_pyminer_data_dir(), "pyminer_config") + if not os.path.exists(path): + os.makedirs(path) return path -def get_path_app_local_data() -> str: - path = QStandardPaths.writableLocation(QStandardPaths.AppLocalDataLocation) - return path \ No newline at end of file +def get_config_file_dir(filename: str) -> str: + """ + 获取设置文件的路径 + Args: + filename: + + Returns: + + """ + assert filename in SETTINGS_FILES + user_cfg_file_path = os.path.join(get_user_config_dir(), filename) + if not os.path.exists(user_cfg_file_path): + default_cfg_file_path = os.path.join(get_default_config_dir(), filename) + shutil.copy(default_cfg_file_path, user_cfg_file_path) + return user_cfg_file_path diff --git a/utils/settings/__init__.py b/utils/settings/__init__.py new file mode 100644 index 00000000..c70020d5 --- /dev/null +++ b/utils/settings/__init__.py @@ -0,0 +1 @@ +from .settings import * \ No newline at end of file diff --git a/utils/settings/settings.py b/utils/settings/settings.py new file mode 100644 index 00000000..6a56a907 --- /dev/null +++ b/utils/settings/settings.py @@ -0,0 +1,217 @@ +import ast +import json +import os +import shutil +import sys +from typing import Any + +from PySide2.QtCore import QSettings, QTranslator +from PySide2.QtGui import QFont +from PySide2.QtWidgets import QWidget, QMessageBox, QApplication, QFileDialog, QStyleFactory + +# from features.ui.base.Preferences import Ui_Form + +Ui_Form = object + +SETTINGS_FILES = {"config.ini"} + + +def get_settings_from_file(file_name: str) -> QSettings: + """ + 从文件中获取设置 + Args: + file_name: + + Returns: + + """ + from ..path import get_config_file_dir + return QSettings(get_config_file_dir(file_name), QSettings.IniFormat) + + +def get_settings_item_from_file(file_name: str, item: str) -> Any: + """ + 从文件中获取设置。如果用户目录下没有,就去默认目录下面寻找。 + 这样可以解决软件更新时引入的问题。 + 对于true、false型变量,都会认为是字符串型。 + 0,1,2,3等,会被认为是数值型。 + 对于 + Args: + file_name: + item: + + Returns: + + """ + assert file_name in SETTINGS_FILES + from ..path import get_user_config_dir, get_default_config_dir + user_cfg_file_path = os.path.join(get_user_config_dir(), file_name) + default_cfg_file_path = os.path.join(get_default_config_dir(), file_name) + if not os.path.exists(user_cfg_file_path): + shutil.copy(default_cfg_file_path, user_cfg_file_path) + val = QSettings(user_cfg_file_path, QSettings.IniFormat).value(item) + if val is None: + val = QSettings(default_cfg_file_path, QSettings.IniFormat).value(item) + assert val is not None, (default_cfg_file_path, item) + try: + val = ast.literal_eval(val) + except: + pass + return val + + +def write_settings_item_to_file(file_name: str, item: str, value: Any): + """ + 带有类型转换地写入 + + Args: + file_name: + item: + value: + + Returns: + + """ + assert file_name in SETTINGS_FILES + from ..path import get_config_file_dir + + value_str = "" + if isinstance(value,str): + value_str = value + elif isinstance(value, (list, dict, set)): + value_str = json.dumps(value) + else: + value_str = str(value) + QSettings(os.path.join(get_config_file_dir(file_name)), QSettings.IniFormat).setValue(item, value_str) + + +class Preferences(QWidget, Ui_Form): + def __init__(self): + super(Preferences, self).__init__() + self.setupUi(self) + + self.pushButton_ok.clicked.connect(self.save_settings) + self.toolButton_workspace.clicked.connect(self.change_workspace_path) + self.toolButton_output.clicked.connect(self.change_output_path) + self.comboBox_language.currentIndexChanged.connect(self.change_lang) + self.comboBox_theme.currentIndexChanged.connect(self.change_theme) + + # load settings + self.settings = QSettings("config.ini", QSettings.IniFormat) + self.theme = self.settings.value("MAIN/THEME") + self.language = self.settings.value("MAIN/LANGUAGE") + self.path_workspace = self.settings.value("MAIN/PATH_WORKDIR") + self.path_output = self.settings.value("MAIN/PATH_OUTPUT") + self.path_interpreter = self.settings.value("MAIN/INTERPRETER") + self.if_display_startpage = self.settings.value("MAIN/STARTPAGE") + + self.comboBox_theme.setCurrentText(self.theme) + self.lineEdit_worksapce.setText(self.path_workspace) + self.lineEdit_output.setText(self.path_output) + + # 设置语言 + if self.language == "zh_CN": + self.comboBox_language.setCurrentText("简体中文") + elif self.language == "en": + self.comboBox_language.setCurrentText("English") + + # 设置显示快速启动页 + if self.if_display_startpage == "True": + self.checkBox_startpage.setChecked(True) + else: + self.checkBox_startpage.setChecked(False) + + # 设置解释器路径 + if self.path_interpreter: + print(self.path_interpreter) + else: + self.path_interpreter = sys.executable + print(self.path_interpreter) + + # 设置工作目录 + if self.path_workspace: + self.lineEdit_worksapce.setText(self.path_workspace) + else: + self.path_workspace = os.path.join(get_documents_dir(), 'PyMiner Workspace') + self.lineEdit_worksapce.setText(self.path_workspace) + + # 设置输出目录 + if self.path_output: + self.lineEdit_output.setText(self.path_workspace) + else: + self.path_output = os.path.join(get_documents_dir(), 'PyMiner Workspace', 'output') + self.lineEdit_output.setText(self.path_output) + + def change_fontsize(self): + font = QFont() + font.setPointSize(int(self.spinBox.value())) + self.plainTextEdit.setFont(font) + + def save_settings(self): + + self.theme = self.comboBox_theme.currentText() + self.path_workspace = self.lineEdit_worksapce.text() + self.path_output = self.lineEdit_output.text() + self.interpreter = "d:/pyminer/python.exe" + + # 保存 语言设置 + + if self.comboBox_language.currentText() == "简体中文": + self.language = "zh_CN" + else: + self.language = "en" + + # 保存 是否显示‘快速启动页’ + if self.checkBox_startpage.isChecked(): + self.if_display_startpage = "True" + else: + self.if_display_startpage = "False" + + self.settings.setValue("MAIN/THEME", self.theme) + self.settings.setValue("MAIN/LANGUAGE", self.language) + self.settings.setValue("MAIN/PATH_WORKSPACE", self.path_workspace) + self.settings.setValue("MAIN/PATH_OUTPUT", self.path_output) + self.settings.setValue("MAIN/INTERPRETER", self.interpreter) + self.settings.setValue("MAIN/STARTPAGE", self.if_display_startpage) + + # if self.comboBox.currentText()=='简体中文': + # self.language ='zh_CN' + # else: + # self.language = 'English' + # self.settings.setValue("General/Language", self.language) + QMessageBox.information(self, "提示", "设置内容已保存,重启后生效!") + + def change_workspace_path(self): + dir_path = QFileDialog.getExistingDirectory(self, "Select a directory as workspace", os.path.expanduser('~')) + self.lineEdit_worksapce.setText(dir_path) + + def change_output_path(self): + dir_path = QFileDialog.getExistingDirectory(self, "Select a directory as output location", + os.path.expanduser('~')) + self.lineEdit_output.setText(dir_path) + + def change_lang(self): + if self.comboBox.currentText() == 'English': + trans = QTranslator() + trans.load('English.qm') + app.installTranslator(trans) + self.retranslateUi(self) + + else: + trans = QTranslator() + trans.load('zh_CN.qm') + app.installTranslator(trans) + self.retranslateUi(self) + + def change_theme(self): + if self.comboBox_theme.currentText() == "Fusion": + QApplication.setStyle(QStyleFactory.create("Fusion")) + else: + QApplication.setStyle(QStyleFactory.create("windowsvista")) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + form = Preferences() + form.show() + sys.exit(app.exec_()) -- Gitee From 15dab71d7e5e0819583a55185bfda5b2bc541be7 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Tue, 20 Apr 2021 18:24:12 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E9=A1=B9=E8=AF=BB=E5=8F=96=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复最新版Matplotlib中PMAgg DivergingNorm被废止的问题 更新了matplotlib的版本号。后面要求更新 --- app2.py | 6 +- configuration/config.ini | 10 ++ features/feedback.py | 30 +++--- features/main_window/base.py | 26 ++++- features/ui/ui_aboutme.py | 27 +++-- features/ui/ui_aboutme.ui | 17 ++-- packages/pmagg/ui/linestyles.py | 2 +- requirements.txt | 2 +- requirements_linux.txt | 2 +- requirements_mac.txt | 2 +- run_before_commit.py | 2 +- utils/__init__.py | 4 +- utils/settings/settings.py | 169 ++++---------------------------- 13 files changed, 97 insertions(+), 202 deletions(-) diff --git a/app2.py b/app2.py index 862d0d93..0b4c722c 100644 --- a/app2.py +++ b/app2.py @@ -153,7 +153,7 @@ class MainWindow(BaseMainWindow): self.resize(1920, 1080) # 设置主窗体标题 - self.setWindowTitle('PyMiner ' + utils.version) + self.setWindowTitle('PyMiner ' + utils.get_settings_item_from_file("config.ini", "INFO/VERSION", "default")) # 设置状态栏 self.statusBar = QStatusBar() @@ -372,13 +372,13 @@ class MainWindow(BaseMainWindow): """ 打开'检查更新'页面 """ - # perform_update() dlg = QDialog() dlg.setLayout(QVBoxLayout()) proc = QProgressBar() dlg.layout().addWidget(proc) dlg.setWindowTitle("请稍等,正在进行更新检查") - proc.setRange(0, 0) + dlg.setFixedWidth(500) + proc.setRange(0, 0) # 设置进度条忙 def close(b): if b: diff --git a/configuration/config.ini b/configuration/config.ini index 207edccc..9d3f49d8 100644 --- a/configuration/config.ini +++ b/configuration/config.ini @@ -6,3 +6,13 @@ PATH_WORKDIR = INTERPRETER = d:/pyminer/python.exe SHOW_START_PAGE = True CHECK_UPDATE = True + +[RUN] +EXTERNAL_INTERPRETERS = "{}" +CURRENT_INTERPRETER = + +[INFO] +VERSION = v2.1.4 Beta +WEBSITE = http://www.pyminer.com +AUTHOR = PyMiner Development Team +MAIL = team@py2cn.com diff --git a/features/feedback.py b/features/feedback.py index 1fe390dc..f4a8a035 100644 --- a/features/feedback.py +++ b/features/feedback.py @@ -4,41 +4,45 @@ # @Email : 2195932461@qq.com # @File : feedback.py # @Software: PyCharm -from PySide2.QtWidgets import QDialog,QTextEdit,QLabel,QVBoxLayout,QApplication,QPushButton,QMessageBox +import requests +from PySide2.QtWidgets import QDialog, QTextEdit, QLabel, QVBoxLayout, QApplication, QPushButton, QMessageBox + from features.settings import Setting -import requests,json + class FeedbackClient(QDialog): def __init__(self): super().__init__() - self.vbox=QVBoxLayout() + self.vbox = QVBoxLayout() self.setLayout(self.vbox) - self.text_edit=QTextEdit() + self.text_edit = QTextEdit() self.setWindowTitle(self.tr('Feedback')) - self.label=QLabel(self.tr('You can give feedback through issue on suggestions or problems encountered in use! (<200 words)')) - self.confirm_button=QPushButton(self.tr('confirm')) + self.label = QLabel( + self.tr('You can give feedback through issue on suggestions or problems encountered in use! (<200 words)')) + self.confirm_button = QPushButton(self.tr('confirm')) self.confirm_button.setFixedWidth(75) self.confirm_button.clicked.connect(self.post) self.vbox.addWidget(self.label) self.vbox.addWidget(self.text_edit) self.vbox.addWidget(self.confirm_button) setting = Setting() - self.version=setting.get_system_version() + self.version = setting.get_system_version() self.exec_() def post(self): - text=self.text_edit.toPlainText() - version=self.version + text = self.text_edit.toPlainText() + version = self.version url = 'http://www.pyminer.com/api/v1/feedback/' data = {'core': version, 'feedback': text} r = requests.post(url, data) - if r.status_code==201: - QMessageBox.about(self,self.tr('result'),self.tr('Submitted successfully!')) + if r.status_code == 201: + QMessageBox.about(self, self.tr('result'), self.tr('Submitted successfully!')) else: QMessageBox.warning(self, self.tr('result'), r.text, QMessageBox.Yes) if __name__ == '__main__': import sys - app=QApplication(sys.argv) - FeedbackClient() \ No newline at end of file + + app = QApplication(sys.argv) + FeedbackClient() diff --git a/features/main_window/base.py b/features/main_window/base.py index 1a48a628..602ef9f0 100644 --- a/features/main_window/base.py +++ b/features/main_window/base.py @@ -133,7 +133,6 @@ class OptionForm(QDialog, Option_Ui_Form): self.check_box_check_upd_on_startup.setChecked(check_update) self.checkbox_show_startpage.setChecked(show_start_page) - def refresh_settings(self): """ 窗口关闭时,调用此方法,刷新主界面设置项。 @@ -142,8 +141,10 @@ class OptionForm(QDialog, Option_Ui_Form): utils.write_settings_item_to_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText()) utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", self.lineEdit_worksapce.text()) utils.write_settings_item_to_file("config.ini", "MAIN/PATH_OUTPUT", self.lineEdit_output.text()) - utils.write_settings_item_to_file("config.ini", "MAIN/CHECK_UPDATE", self.check_box_check_upd_on_startup.isChecked()) - utils.write_settings_item_to_file("config.ini", "MAIN/SHOW_START_PAGE", self.checkbox_show_startpage.isChecked()) + utils.write_settings_item_to_file("config.ini", "MAIN/CHECK_UPDATE", + self.check_box_check_upd_on_startup.isChecked()) + utils.write_settings_item_to_file("config.ini", "MAIN/SHOW_START_PAGE", + self.checkbox_show_startpage.isChecked()) get_main_window().on_settings_changed() self.signal_settings_changed.emit() @@ -206,10 +207,28 @@ class AppstoreForm(QWidget, appStore_Ui_Form): class AboutForm(QWidget, About_Ui_Form): + """ + 关于 弹出框 + + """ + def __init__(self): super(AboutForm, self).__init__() self.setupUi(self) self.center() + AUTHOR = utils.get_settings_item_from_file("config.ini", "INFO/AUTHOR", "default") + MAIL = utils.get_settings_item_from_file("config.ini", "INFO/MAIL", "default") + self.textedit_about.setMarkdown("""# PyMiner +PyMiner 是一款基于Python的开源、跨平台数据分析环境。它以方便Python初学者为己任,在Python的知识理论和工作实践之间搭建桥梁,竭诚为初学者服务。 +- PyMiner开箱即用,大大减少配置解释器环境的繁琐性。不仅提供了编程运行的功能,还能够以交互式的形式进行常见的数据分析操作,减少代码编写和文档查阅的时间。 +- PyMiner通过加载各种插件实现不同的需求,开发者可以通过编写插件,将PyMiner扩展的更强大、更趁手,甚至创建一番自己的商用程序。 +- PyMiner提供面向新手的快速入门教程,教程正由开发团队编写中。 +- 我们诚挚希望与Python培训或教育机构/个人合作,让我们的产品帮助到更多学习Python的人。 + +作者:{AUTHOR} + +邮箱:{MAIL} +""".format(AUTHOR=AUTHOR, MAIL=MAIL)) self.main_about_display() @@ -236,6 +255,7 @@ class AboutForm(QWidget, About_Ui_Form): system_info = '系统信息: ' + platform.platform() + ' ' + platform.architecture()[0] cpu_info = 'CPU信息: ' + platform.processor() self.feedback.setPlainText(python_info + '\n' + system_info + '\n' + cpu_info) + self.label_version_show.setText(utils.get_settings_item_from_file("config.ini", "INFO/VERSION", "default")) class ProjectWizardForm(QWizard, Project_Ui_Form): diff --git a/features/ui/ui_aboutme.py b/features/ui/ui_aboutme.py index df648fe9..878455db 100644 --- a/features/ui/ui_aboutme.py +++ b/features/ui/ui_aboutme.py @@ -47,6 +47,7 @@ class Ui_Form(object): font1.setFamily(u"Microsoft YaHei UI") font1.setPointSize(24) font1.setBold(True) + font1.setWeight(75) self.label.setFont(font1) self.label.setScaledContents(True) self.label.setAlignment(Qt.AlignCenter) @@ -62,12 +63,12 @@ class Ui_Form(object): self.horizontalLayout.addWidget(self.label_2) - self.label_6 = QLabel(Form) - self.label_6.setObjectName(u"label_6") - self.label_6.setFont(font2) - self.label_6.setAlignment(Qt.AlignBottom|Qt.AlignHCenter) + self.label_version_show = QLabel(Form) + self.label_version_show.setObjectName(u"label_version_show") + self.label_version_show.setFont(font2) + self.label_version_show.setAlignment(Qt.AlignBottom|Qt.AlignHCenter) - self.horizontalLayout.addWidget(self.label_6) + self.horizontalLayout.addWidget(self.label_version_show) self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) @@ -88,12 +89,12 @@ class Ui_Form(object): self.verticalLayout_2.setSpacing(0) self.verticalLayout_2.setObjectName(u"verticalLayout_2") self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) - self.plainTextEdit = QPlainTextEdit(self.tab) - self.plainTextEdit.setObjectName(u"plainTextEdit") - self.plainTextEdit.setFont(font3) - self.plainTextEdit.setFrameShape(QFrame.NoFrame) + self.textedit_about = QTextEdit(self.tab) + self.textedit_about.setObjectName(u"textedit_about") + self.textedit_about.setFont(font3) + self.textedit_about.setFrameShape(QFrame.NoFrame) - self.verticalLayout_2.addWidget(self.plainTextEdit) + self.verticalLayout_2.addWidget(self.textedit_about) self.tabWidget.addTab(self.tab, "") self.tab_2 = QWidget() @@ -163,11 +164,7 @@ class Ui_Form(object): self.label_3.setText("") self.label.setText(QCoreApplication.translate("Form", u"PyMiner", None)) self.label_2.setText(QCoreApplication.translate("Form", u"Version:", None)) - self.label_6.setText(QCoreApplication.translate("Form", u"v2.0 Beta", None)) - self.plainTextEdit.setPlainText(QCoreApplication.translate("Form", u"PyMiner is a mathematical tool based on Python. It provides solutions to various of problems by loading different plugins. \n" -"\n" -"Author\uff1aPyMiner Development Team\n" -"E-Mail\uff1ateam@py2cn.com", None)) + self.label_version_show.setText(QCoreApplication.translate("Form", u"v2.0 Beta", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QCoreApplication.translate("Form", u"About", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("Form", u"System", None)) self.plainTextEdit_2.setPlainText(QCoreApplication.translate("Form", u"\u4faf\u5c55\u610f\n" diff --git a/features/ui/ui_aboutme.ui b/features/ui/ui_aboutme.ui index d5ff0507..747bd4a4 100644 --- a/features/ui/ui_aboutme.ui +++ b/features/ui/ui_aboutme.ui @@ -64,7 +64,7 @@ - :/logo/icons/logo.png + :/logo/icons/logo.png true @@ -77,6 +77,7 @@ Microsoft YaHei UI 24 + 75 true @@ -107,7 +108,7 @@ - + 黑体 @@ -168,7 +169,7 @@ 0 - + 黑体 @@ -178,12 +179,6 @@ QFrame::NoFrame - - PyMiner is a mathematical tool based on Python. It provides solutions to various of problems by loading different plugins. - -Author:PyMiner Development Team -E-Mail:team@py2cn.com - @@ -282,7 +277,7 @@ houxinluo - :/images/images/weixin.png + :/images/images/weixin.png true @@ -295,7 +290,7 @@ houxinluo - :/images/images/zhifubao.png + :/images/images/zhifubao.png true diff --git a/packages/pmagg/ui/linestyles.py b/packages/pmagg/ui/linestyles.py index 9689a82f..f59b5dc3 100644 --- a/packages/pmagg/ui/linestyles.py +++ b/packages/pmagg/ui/linestyles.py @@ -3,7 +3,7 @@ # @Author : 别着急慢慢来 # @FileName: linestyles.py # matplotlib中的常见颜色 -from matplotlib.colors import LogNorm, NoNorm, BoundaryNorm, DivergingNorm, PowerNorm, SymLogNorm, TwoSlopeNorm, \ +from matplotlib.colors import LogNorm, NoNorm, BoundaryNorm, PowerNorm, SymLogNorm, TwoSlopeNorm, \ Normalize languages = ['en', 'zh_CN'] diff --git a/requirements.txt b/requirements.txt index 6f0eae7e..cf5d9a0d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ jdcal>=1.4.1 joblib>=0.16.0 kiwisolver>=1.2.0 numpy==1.19.3 -matplotlib>=3.3.1 +matplotlib>=3.4.1 openpyxl>=3.0.4 xlrd>=1.2.0 pandas>=1.1.1 diff --git a/requirements_linux.txt b/requirements_linux.txt index 0ebaca10..aa3b7350 100644 --- a/requirements_linux.txt +++ b/requirements_linux.txt @@ -6,7 +6,7 @@ helpdev>=0.7.1 jdcal>=1.4.1 joblib>=0.16.0 kiwisolver>=1.2.0 -matplotlib>=3.3.1 +matplotlib>=3.4.1 numpy==1.19.1 openpyxl>=3.0.4 pandas>=1.1.1 diff --git a/requirements_mac.txt b/requirements_mac.txt index fa5b0d70..9c625abe 100644 --- a/requirements_mac.txt +++ b/requirements_mac.txt @@ -5,7 +5,7 @@ helpdev>=0.7.1 jdcal>=1.4.1 joblib>=0.16.0 kiwisolver>=1.2.0 -matplotlib>=3.3.1 +matplotlib>=3.4.1 numpy==1.19.1 openpyxl>=3.0.4 pandas>=1.1.1 diff --git a/run_before_commit.py b/run_before_commit.py index 16b7e903..855bf193 100644 --- a/run_before_commit.py +++ b/run_before_commit.py @@ -9,4 +9,4 @@ import sys from utils import get_root_dir os.system(f"{sys.executable} {os.path.join(get_root_dir(), 'features', 'util', 'make_update.py')}") -print("已经运行完成,现在可以提交了。") +print("已经运行完成。现在还需要进行一次更新测试,确认已是最新版本,便可以提交到主分支了。") diff --git a/utils/__init__.py b/utils/__init__.py index e03a1832..47fefc0f 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -4,7 +4,6 @@ # 通用工具,可以在全局进行调用。 import webbrowser -from typing import TYPE_CHECKING from .debug import * from .environ import ( @@ -37,7 +36,7 @@ from .ui import * if TYPE_CHECKING: import pmgui -version = 'v2.1.0 Beta' +# version = 'v2.1.0 Beta' 这里原有version ,但是考虑到这些信息写在静态文件中较好,所以就写在了文件中。 _application = None _root_dir = None @@ -80,7 +79,6 @@ def open_url(url): except Exception as e: webbrowser.open_new_tab(url) - # def unzip_file(zip_src: str, dst_dir: str): # """ # 解压文件 diff --git a/utils/settings/settings.py b/utils/settings/settings.py index 6a56a907..ceb1a2a1 100644 --- a/utils/settings/settings.py +++ b/utils/settings/settings.py @@ -1,13 +1,9 @@ import ast -import json import os import shutil -import sys from typing import Any -from PySide2.QtCore import QSettings, QTranslator -from PySide2.QtGui import QFont -from PySide2.QtWidgets import QWidget, QMessageBox, QApplication, QFileDialog, QStyleFactory +from PySide2.QtCore import QSettings # from features.ui.base.Preferences import Ui_Form @@ -29,28 +25,31 @@ def get_settings_from_file(file_name: str) -> QSettings: return QSettings(get_config_file_dir(file_name), QSettings.IniFormat) -def get_settings_item_from_file(file_name: str, item: str) -> Any: +def get_settings_item_from_file(file_name: str, item: str, mode="user") -> Any: """ 从文件中获取设置。如果用户目录下没有,就去默认目录下面寻找。 这样可以解决软件更新时引入的问题。 - 对于true、false型变量,都会认为是字符串型。 - 0,1,2,3等,会被认为是数值型。 - 对于 + 在此时会调用ast.literal_eval函数进行数据类型转换。 Args: file_name: item: + mode: 两种选项,有user和default。 Returns: """ + assert mode in {"user", "default"} assert file_name in SETTINGS_FILES - from ..path import get_user_config_dir, get_default_config_dir + from utils.path import get_user_config_dir, get_default_config_dir user_cfg_file_path = os.path.join(get_user_config_dir(), file_name) default_cfg_file_path = os.path.join(get_default_config_dir(), file_name) - if not os.path.exists(user_cfg_file_path): - shutil.copy(default_cfg_file_path, user_cfg_file_path) - val = QSettings(user_cfg_file_path, QSettings.IniFormat).value(item) - if val is None: + if mode == "user": + if not os.path.exists(user_cfg_file_path): + shutil.copy(default_cfg_file_path, user_cfg_file_path) + val = QSettings(user_cfg_file_path, QSettings.IniFormat).value(item) + if val is None: + val = QSettings(default_cfg_file_path, QSettings.IniFormat).value(item) + else: val = QSettings(default_cfg_file_path, QSettings.IniFormat).value(item) assert val is not None, (default_cfg_file_path, item) try: @@ -62,7 +61,9 @@ def get_settings_item_from_file(file_name: str, item: str) -> Any: def write_settings_item_to_file(file_name: str, item: str, value: Any): """ - 带有类型转换地写入 + 带有类型转换地写入。 + 一般的,设置类型只能是 + int,float,str以及由他们repr之后组成的结果。 Args: file_name: @@ -73,145 +74,15 @@ def write_settings_item_to_file(file_name: str, item: str, value: Any): """ assert file_name in SETTINGS_FILES - from ..path import get_config_file_dir + from utils.path import get_config_file_dir value_str = "" - if isinstance(value,str): + if isinstance(value, str): value_str = value - elif isinstance(value, (list, dict, set)): - value_str = json.dumps(value) else: - value_str = str(value) + value_str = repr(value) QSettings(os.path.join(get_config_file_dir(file_name)), QSettings.IniFormat).setValue(item, value_str) -class Preferences(QWidget, Ui_Form): - def __init__(self): - super(Preferences, self).__init__() - self.setupUi(self) - - self.pushButton_ok.clicked.connect(self.save_settings) - self.toolButton_workspace.clicked.connect(self.change_workspace_path) - self.toolButton_output.clicked.connect(self.change_output_path) - self.comboBox_language.currentIndexChanged.connect(self.change_lang) - self.comboBox_theme.currentIndexChanged.connect(self.change_theme) - - # load settings - self.settings = QSettings("config.ini", QSettings.IniFormat) - self.theme = self.settings.value("MAIN/THEME") - self.language = self.settings.value("MAIN/LANGUAGE") - self.path_workspace = self.settings.value("MAIN/PATH_WORKDIR") - self.path_output = self.settings.value("MAIN/PATH_OUTPUT") - self.path_interpreter = self.settings.value("MAIN/INTERPRETER") - self.if_display_startpage = self.settings.value("MAIN/STARTPAGE") - - self.comboBox_theme.setCurrentText(self.theme) - self.lineEdit_worksapce.setText(self.path_workspace) - self.lineEdit_output.setText(self.path_output) - - # 设置语言 - if self.language == "zh_CN": - self.comboBox_language.setCurrentText("简体中文") - elif self.language == "en": - self.comboBox_language.setCurrentText("English") - - # 设置显示快速启动页 - if self.if_display_startpage == "True": - self.checkBox_startpage.setChecked(True) - else: - self.checkBox_startpage.setChecked(False) - - # 设置解释器路径 - if self.path_interpreter: - print(self.path_interpreter) - else: - self.path_interpreter = sys.executable - print(self.path_interpreter) - - # 设置工作目录 - if self.path_workspace: - self.lineEdit_worksapce.setText(self.path_workspace) - else: - self.path_workspace = os.path.join(get_documents_dir(), 'PyMiner Workspace') - self.lineEdit_worksapce.setText(self.path_workspace) - - # 设置输出目录 - if self.path_output: - self.lineEdit_output.setText(self.path_workspace) - else: - self.path_output = os.path.join(get_documents_dir(), 'PyMiner Workspace', 'output') - self.lineEdit_output.setText(self.path_output) - - def change_fontsize(self): - font = QFont() - font.setPointSize(int(self.spinBox.value())) - self.plainTextEdit.setFont(font) - - def save_settings(self): - - self.theme = self.comboBox_theme.currentText() - self.path_workspace = self.lineEdit_worksapce.text() - self.path_output = self.lineEdit_output.text() - self.interpreter = "d:/pyminer/python.exe" - - # 保存 语言设置 - - if self.comboBox_language.currentText() == "简体中文": - self.language = "zh_CN" - else: - self.language = "en" - - # 保存 是否显示‘快速启动页’ - if self.checkBox_startpage.isChecked(): - self.if_display_startpage = "True" - else: - self.if_display_startpage = "False" - - self.settings.setValue("MAIN/THEME", self.theme) - self.settings.setValue("MAIN/LANGUAGE", self.language) - self.settings.setValue("MAIN/PATH_WORKSPACE", self.path_workspace) - self.settings.setValue("MAIN/PATH_OUTPUT", self.path_output) - self.settings.setValue("MAIN/INTERPRETER", self.interpreter) - self.settings.setValue("MAIN/STARTPAGE", self.if_display_startpage) - - # if self.comboBox.currentText()=='简体中文': - # self.language ='zh_CN' - # else: - # self.language = 'English' - # self.settings.setValue("General/Language", self.language) - QMessageBox.information(self, "提示", "设置内容已保存,重启后生效!") - - def change_workspace_path(self): - dir_path = QFileDialog.getExistingDirectory(self, "Select a directory as workspace", os.path.expanduser('~')) - self.lineEdit_worksapce.setText(dir_path) - - def change_output_path(self): - dir_path = QFileDialog.getExistingDirectory(self, "Select a directory as output location", - os.path.expanduser('~')) - self.lineEdit_output.setText(dir_path) - - def change_lang(self): - if self.comboBox.currentText() == 'English': - trans = QTranslator() - trans.load('English.qm') - app.installTranslator(trans) - self.retranslateUi(self) - - else: - trans = QTranslator() - trans.load('zh_CN.qm') - app.installTranslator(trans) - self.retranslateUi(self) - - def change_theme(self): - if self.comboBox_theme.currentText() == "Fusion": - QApplication.setStyle(QStyleFactory.create("Fusion")) - else: - QApplication.setStyle(QStyleFactory.create("windowsvista")) - - if __name__ == '__main__': - app = QApplication(sys.argv) - form = Preferences() - form.show() - sys.exit(app.exec_()) + print(get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS")) -- Gitee From 43df2db9e779949e8b9f86379bbd7553e800e6cf Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Tue, 20 Apr 2021 21:36:23 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E9=A2=84=E7=95=99=E4=BA=86=E8=A7=A3?= =?UTF-8?q?=E9=87=8A=E5=99=A8=E6=9B=B4=E6=8D=A2=E5=85=B6=E4=BB=96=E8=A7=A3?= =?UTF-8?q?=E9=87=8A=E5=99=A8=E7=9A=84=E6=8E=A5=E5=8F=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pmgwidgets/widgets/basic/others/console.py | 28 +++++++++++++++++++--- run_before_commit.py | 10 ++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/pmgwidgets/widgets/basic/others/console.py b/pmgwidgets/widgets/basic/others/console.py index 8cb374e4..90f96258 100644 --- a/pmgwidgets/widgets/basic/others/console.py +++ b/pmgwidgets/widgets/basic/others/console.py @@ -40,8 +40,30 @@ class ConsoleInitThread(QObject): def run(self): self.mutex.lock() - kernel_manager = QtKernelManager(kernel_name='python3') - kernel_manager.start_kernel() + + class NewKernelManager(QtKernelManager): + def start_kernel(self, path: str, **kw): + """Starts a kernel on this host in a separate process. + + If random ports (port=0) are being used, this method must be called + before the channels are created. + + Parameters + ---------- + `**kw` : optional + keyword arguments that are passed down to build the kernel_cmd + and launching the kernel (e.g. Popen kwargs). + """ + kernel_cmd, kw = self.pre_start_kernel(**kw) + kernel_cmd[0] = path + print("kernel_cmd", kernel_cmd) + # launch the kernel subprocess + self.log.debug("Starting kernel: %s", kernel_cmd) + self.kernel = self._launch_kernel(kernel_cmd, **kw) + self.post_start_kernel(**kw) + + kernel_manager = NewKernelManager(kernel_name='python3') + kernel_manager.start_kernel(path=sys.executable) # 指定使用哪一个Python的解释器。 kernel_client = kernel_manager.client() kernel_client.start_channels() @@ -311,7 +333,7 @@ if __name__ == '__main__': cgitb.enable(format='text') app = QApplication([]) - os.environ['IPYTHON_AS_PYMINER_NODE'] = '1' + # os.environ['IPYTHON_AS_PYMINER_NODE'] = '1' PMGIpythonConsole.install_translator() w = PMGIpythonConsole() w.show() diff --git a/run_before_commit.py b/run_before_commit.py index 855bf193..7440b2e1 100644 --- a/run_before_commit.py +++ b/run_before_commit.py @@ -1,6 +1,16 @@ """ 这个文件需要在提交之前运行,从而正确的生成更新包。 +在更新之后,需要检查: +1、最新的版本启动后,是否还会提示要更新。如果是,那么说明可能文件存在错误,或者并未正确执行此文件。 +2、最新打包的版本,其中是否因为某些包的更新而发生错误。典型例子就是Matplotlib升级成3.4.1版本之后,废止了旧的某个类,导致PMAgg不能运行。 + +还有一些问题: +是否需要发布大版本更新的提示?比如,当版本更新中包含pip包版本升级的时候,是否需要提示用户? +如何处理用户升级解释器中包的问题?是否要提示,默认解释器不得安装requirements.txt中已有的包? + +是否需要支持切换解释器的工作空间? + """ import os -- Gitee From e6fbed6dc8875b447e0f87831ffe829c8c7ed6c0 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Wed, 21 Apr 2021 09:24:23 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A7=A3=E9=87=8A?= =?UTF-8?q?=E5=99=A8=E6=97=A0=E6=B3=95=E8=BF=9E=E6=8E=A5=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ipython_console/README.md | 0 packages/ipython_console/initialize.py | 65 ++++++++++++------- packages/ipython_console/ipythonqtconsole.py | 4 +- .../requirements_ipython_node.txt | 4 ++ pmgwidgets/widgets/basic/others/console.py | 37 ++++------- pyminer_comm/base/datadesc.py | 26 +++++--- 6 files changed, 79 insertions(+), 57 deletions(-) create mode 100644 packages/ipython_console/README.md create mode 100644 packages/ipython_console/requirements_ipython_node.txt diff --git a/packages/ipython_console/README.md b/packages/ipython_console/README.md new file mode 100644 index 00000000..e69de29b diff --git a/packages/ipython_console/initialize.py b/packages/ipython_console/initialize.py index fd1f9dd3..700d646b 100644 --- a/packages/ipython_console/initialize.py +++ b/packages/ipython_console/initialize.py @@ -7,23 +7,30 @@ import types import typing -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import scipy.integrate -import scipy.stats - -__packages = [np, plt, pd, scipy.integrate, scipy.stats] -from IPython.core.magic import register_line_cell_magic -from core import * from pyminer_comm import modify_settings, set_data_desc_dic from pyminer_comm.base import dict_to_b64, b64_to_dict, dict_to_pickle, pickle_to_dict, DataDesc, is_big_variable, \ NoPreviewError +try: + import matplotlib.pyplot as plt + import numpy as np + import pandas as pd + import scipy.integrate + import scipy.stats + from core import * + + __packages = [np, plt, pd, scipy.integrate, scipy.stats] +except Exception as e: + import traceback + + traceback.print_exc() + if typing.TYPE_CHECKING: from IPython.core.interactiveshell import InteractiveShell from IPython.core.getipython import get_ipython +from IPython.core.magic import register_line_cell_magic + __ip: 'InteractiveShell' = get_ipython() __ip.builtin_vars = [__k for __k in globals().keys()] # 内置保留变量,不可删除或者清空。 @@ -51,31 +58,43 @@ def __init_server(): server = Flask('ipython_data_server') __ip = get_ipython() __ip.shms = {} + log.debug("started server!") def get_preview(var: typing.Any): if is_big_variable(var): - if isinstance(var, pd.DataFrame): - if var.shape[0] > DataDesc.max_pandas_rows: - return var.iloc[:DataDesc.max_pandas_rows, :] - else: - return var + if isinstance(var, (int, float, complex)): + return var + if isinstance(var, (list, tuple)): + return var[:DataDesc.max_len] elif isinstance(var, str): if len(var) > DataDesc.max_str_len: return var[:DataDesc.max_str_len] else: return var - elif isinstance(var, (list, tuple)): - return var[:DataDesc.max_len] - elif isinstance(var, np.ndarray): - if is_big_variable(var): - return NoPreviewError( - 'Big numpy.ndarray with shape: %s, dtype:%s, memory usage: %s MB, cannot be viewed.' - % (repr(var.shape), repr(var.dtype), repr(var.nbytes / 1024 / 1024))) - else: - return var + try: + if isinstance(var, pd.DataFrame): + if var.shape[0] > DataDesc.max_pandas_rows: + return var.iloc[:DataDesc.max_pandas_rows, :] + else: + return var + + if isinstance(var, np.ndarray): + if is_big_variable(var): + return NoPreviewError( + 'Big numpy.ndarray with shape: %s, dtype:%s, memory usage: %s MB, cannot be viewed.' + % (repr(var.shape), repr(var.dtype), repr(var.nbytes / 1024 / 1024))) + else: + return var + + except Exception as e: + return e + + else: return NoPreviewError('Big Variable typed %s cannot be viewed.' % (type(var))) # 无法产生预览视图。 + else: + return repr(var) def write_log(arg): if os.path.exists(r'c:\users\hzy\Desktop\log.txt'): diff --git a/packages/ipython_console/ipythonqtconsole.py b/packages/ipython_console/ipythonqtconsole.py index 3ea9eec9..bc453f68 100644 --- a/packages/ipython_console/ipythonqtconsole.py +++ b/packages/ipython_console/ipythonqtconsole.py @@ -12,8 +12,9 @@ import os from typing import Tuple import time from pmgwidgets import PMDockObject, get_ipython_console_class, in_unit_test +from pmgwidgets.widgets.basic.others.console import PMGIpythonConsole from PySide2.QtWidgets import QApplication -PMGIpythonConsole = get_ipython_console_class() +# PMGIpythonConsole = get_ipython_console_class() if QApplication.instance() is not None: PMGIpythonConsole.install_translator() @@ -61,7 +62,6 @@ class ConsoleWidget(PMGIpythonConsole, PMDockObject): pwd = pwd.replace('\\', '\\\\') from utils import get_root_dir cmd = 'import sys;sys.path.append(r\'%s\')' % get_root_dir() - print(cmd) self.execute_command(cmd, True, '') cdcmd = 'import os;os.chdir(\'%s\')' % pwd # 启动时切换到当前工作路径。 self.execute_command(cdcmd, True, '') diff --git a/packages/ipython_console/requirements_ipython_node.txt b/packages/ipython_console/requirements_ipython_node.txt new file mode 100644 index 00000000..92f07469 --- /dev/null +++ b/packages/ipython_console/requirements_ipython_node.txt @@ -0,0 +1,4 @@ +cloudpickle +Flask +ipykernel +ipython diff --git a/pmgwidgets/widgets/basic/others/console.py b/pmgwidgets/widgets/basic/others/console.py index 90f96258..831ea38e 100644 --- a/pmgwidgets/widgets/basic/others/console.py +++ b/pmgwidgets/widgets/basic/others/console.py @@ -8,8 +8,9 @@ Created on 2020/8/24 @file: console.py @description: Console Widget """ - +import logging import os +import sys from typing import Tuple, Dict, Callable from PySide2.QtCore import QObject, Signal, QThread, QWaitCondition, QMutex, QPoint, QCoreApplication, QTranslator, \ @@ -29,6 +30,10 @@ default_dark_style_sheet = default_dark_style_template % dict( bgcolor='#19232d', fgcolor='white', select="#ccc") default_dark_syntax_style = 'monokai' # 'default' +logging.basicConfig(stream=sys.stderr) +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + class ConsoleInitThread(QObject): initialized = Signal(object, object) @@ -40,30 +45,13 @@ class ConsoleInitThread(QObject): def run(self): self.mutex.lock() + kernel_manager = QtKernelManager(kernel_name="python3") + logger.debug("installed kernel start method") - class NewKernelManager(QtKernelManager): - def start_kernel(self, path: str, **kw): - """Starts a kernel on this host in a separate process. - - If random ports (port=0) are being used, this method must be called - before the channels are created. - - Parameters - ---------- - `**kw` : optional - keyword arguments that are passed down to build the kernel_cmd - and launching the kernel (e.g. Popen kwargs). - """ - kernel_cmd, kw = self.pre_start_kernel(**kw) - kernel_cmd[0] = path - print("kernel_cmd", kernel_cmd) - # launch the kernel subprocess - self.log.debug("Starting kernel: %s", kernel_cmd) - self.kernel = self._launch_kernel(kernel_cmd, **kw) - self.post_start_kernel(**kw) - - kernel_manager = NewKernelManager(kernel_name='python3') - kernel_manager.start_kernel(path=sys.executable) # 指定使用哪一个Python的解释器。 + # kernel_manager.kernel_spec.argv[0] = r"C:\Users\12957\AppData\Local\Programs\Python\Python38\python.exe" + kernel_manager.kernel_spec.argv[0] = sys.executable + # 这一步的目的是,指明要连接到的解释器。 + kernel_manager.start_kernel() kernel_client = kernel_manager.client() kernel_client.start_channels() @@ -138,6 +126,7 @@ class PMGIpythonConsole(RichJupyterWidget): self.init_thread.finished.connect(self.init_thread.deleteLater) self.init_thread.started.connect(self.console_object.run) self.init_thread.start() + logger.debug("setup--ui") cursor: QTextCursor = self._prompt_cursor cursor.movePosition(QTextCursor.End) diff --git a/pyminer_comm/base/datadesc.py b/pyminer_comm/base/datadesc.py index 19cdf996..7faa7753 100644 --- a/pyminer_comm/base/datadesc.py +++ b/pyminer_comm/base/datadesc.py @@ -33,24 +33,34 @@ class NoPreviewError(Exception): def is_big_variable(var): - import pandas as pd - import numpy as np + """ + 判断是否为大型变量。 + 对于较大的变量,需要采用预览模式。 + Args: + var: + + Returns: + """ if isinstance(var, (int, bool, float)): return sys.getsizeof(var) > DataDesc.threshold_pandas - if isinstance(var, str): + elif isinstance(var, str): return len(var) > DataDesc.max_str_len - elif isinstance(var, (pd.DataFrame, pd.Series)): + elif isinstance(var, dict): + return len(list(var.keys())) > DataDesc.max_len + elif isinstance(var, (list, tuple)): + return len(var) > DataDesc.max_len + + import pandas as pd + import numpy as np + if isinstance(var, (pd.DataFrame, pd.Series)): if isinstance(var, pd.DataFrame): return int(var.memory_usage().sum()) - DataDesc.threshold_pandas > 0 else: return var.memory_usage() - DataDesc.threshold_pandas > 0 elif isinstance(var, np.ndarray): return var.nbytes > DataDesc.threshold_numpy - elif isinstance(var, dict): - return len(list(var.keys())) > DataDesc.max_len - elif isinstance(var, (list, tuple)): - return len(var) > DataDesc.max_len + else: return False -- Gitee From ff0e19bb3e48942826293fbda318728fafba86c3 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Wed, 21 Apr 2021 11:06:37 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E5=BC=BA=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=B7=A5=E5=85=B7=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8F=8C=E7=A7=AF=E5=88=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/ipython_console/README.md | 4 + packages/ipython_console/ipythonqtconsole.py | 4 +- packages/ipython_console/lexersplit.py | 69 ------ packages/pm_calc/fastui/dblquad.py | 210 ++++++++++++++++++ pmgwidgets/widgets/composited/fastui.py | 5 +- .../widgets/extended/entries/funcctrl.py | 101 +++++++++ .../extended/others/multitypeparaminput.py | 2 +- requirements.txt | 1 + 8 files changed, 321 insertions(+), 75 deletions(-) delete mode 100644 packages/ipython_console/lexersplit.py create mode 100644 packages/pm_calc/fastui/dblquad.py create mode 100644 pmgwidgets/widgets/extended/entries/funcctrl.py diff --git a/packages/ipython_console/README.md b/packages/ipython_console/README.md index e69de29b..561b0588 100644 --- a/packages/ipython_console/README.md +++ b/packages/ipython_console/README.md @@ -0,0 +1,4 @@ +- requirements_ipython_node.txt:一个IPython作为连接到外部的IPython节点,至少需要装的包。 +这些包看起来不少,但是每个都比较小,即使用国外镜像源也很快。 + +- \ No newline at end of file diff --git a/packages/ipython_console/ipythonqtconsole.py b/packages/ipython_console/ipythonqtconsole.py index bc453f68..46e3302d 100644 --- a/packages/ipython_console/ipythonqtconsole.py +++ b/packages/ipython_console/ipythonqtconsole.py @@ -10,11 +10,9 @@ Created on 2020/8/24 """ import os from typing import Tuple -import time -from pmgwidgets import PMDockObject, get_ipython_console_class, in_unit_test +from pmgwidgets import PMDockObject, in_unit_test from pmgwidgets.widgets.basic.others.console import PMGIpythonConsole from PySide2.QtWidgets import QApplication -# PMGIpythonConsole = get_ipython_console_class() if QApplication.instance() is not None: PMGIpythonConsole.install_translator() diff --git a/packages/ipython_console/lexersplit.py b/packages/ipython_console/lexersplit.py deleted file mode 100644 index 7ee30f30..00000000 --- a/packages/ipython_console/lexersplit.py +++ /dev/null @@ -1,69 +0,0 @@ -import ast -import typing - - -class NodeVisitor(ast.NodeVisitor): - def visit_Name(self, node: ast.Name) -> typing.Any: - print(node) - - -class NodeTransformer(ast.NodeTransformer): - # def visit_Str(self, tree_node): - # return ast.Str('String: ' + tree_node.s) - def __init__(self): - super(NodeTransformer, self).__init__() - self.identifier_list = [] - self.str_list = [] - - def visit_Name(self, node: ast.Name): - """ - - Args: - node: - - Returns: - - """ - self.identifier_list.append(node.id) - - def visit_Str(self, node: ast.Str) -> typing.Any: - """ - - Args: - node: - - Returns: - - """ - self.str_list.append(node.s) - - def show_identifiers_might_changed(self, code) -> list: - """ - - Args: - code: - - Returns: - - """ - self.identifier_list = [] - self.str_list = [] - self.visit(ast.parse(code)) - return [s for s in list(set(self.identifier_list + self.str_list)) if s.isidentifier()] - - -if __name__ == '__main__': - s = ''' - class A: - def aaa(): - b=123 - print(b) - fruits = ['grapes', 'mango'] - name = 'peter' - for fruit in fruits: - print('{} likes {}'.format(name, fruit)) - ''' - - # NodeTransformer().visit(tree_node) - print(NodeTransformer().show_identifiers_might_changed(s)) - # NodeVisitor().visit(tree_node) diff --git a/packages/pm_calc/fastui/dblquad.py b/packages/pm_calc/fastui/dblquad.py new file mode 100644 index 00000000..853c7391 --- /dev/null +++ b/packages/pm_calc/fastui/dblquad.py @@ -0,0 +1,210 @@ +import ast +from typing import Any, List, Tuple + +from PySide2.QtWidgets import QApplication + +from pmgwidgets import FunctionGUIDialog + + +class CodeVisitor(ast.NodeVisitor): + def __init__(self): + super(CodeVisitor, self).__init__() + self.preserved = {"pi", "e"} + self.called = set() + self.func_args = set() + self._names = set() + + def visit_Name(self, node: ast.Name) -> Any: + self._names.add(node.id) + + def visit_Call(self, node: ast.Call) -> Any: + self.generic_visit(node) + self.called.add(node.func.id) + + def get_result(self) -> Tuple[List[str], List[str]]: + """ + + Returns: 定义的名称,以及调用的ID名称。 + + """ + names = self._names.copy() + names.difference_update(self.preserved) + names.difference_update(self.called) + return list(names), list(self.called) + + +class Function(): + def __init__(self, s): + self.name = s + + def __repr__(self): + return self.name + + +def convert_to_lambda(code): + print(code) + original_code = code + code = code.replace("np.", "") + cv = CodeVisitor() + cv.visit(ast.parse(code)) + args_list, funcs = cv.get_result() + args = '' + for a in args_list: + args += a + "," + args = args.strip(", ") + + ret = "lambda {ARGS}: {FCN}".format(ARGS=args, FCN=original_code) + return Function(ret) + + +dic = { + "title": "数据透视", + "func_name": "scipy.integrate.dblquad", + "with_object": False, + "args": [ + { + "name": "func", + "title": "被积函数", + "optional": False, + "ctrl": { + "type": "multitype_ctrl", + "title": "选择被积函数", + "init": "x*y", + "types": + [{ + "type_title": "输入表达式", + "ctrls": [ + ("line_ctrl", "", '输入表达式并自动转换为函数', "np.sin(2*np.pi*x)"), + ], + "on_ok": lambda data: convert_to_lambda(data[""]) + }, { + "type_title": "输入函数", + "ctrls": [ + ("line_ctrl", "", '输入函数代码', "lambda x: np.sin(2*np.pi*x)"), + ], + "on_ok": lambda data: Function(data[""]) + }, { + "type_title": "选择变量", + "ctrls": [ + ("vars_combo_ctrl", "variable", "选择变量", ""), + ], + }] + } + }, + { + "name": "hfun", + "title": "内层函数上界", + "optional": False, + "ctrl": { + "type": "multitype_ctrl", + "title": "内层函数上界", + "init": "np.sin(2*np.pi*x)", + "types": + [{ + "type_title": "输入表达式", + "ctrls": [ + ("line_ctrl", "", '输入表达式并自动转换为函数', "np.sin(2*np.pi*x)"), + ], + "on_ok": lambda data: convert_to_lambda(data[""]) + }, { + "type_title": "输入函数", + "ctrls": [ + ("line_ctrl", "", '输入函数代码', "lambda x: np.sin(2*np.pi*x)"), + ], + "on_ok": lambda data: Function(data[""]) + }, { + "type_title": "选择变量", + "ctrls": [ + ("vars_combo_ctrl", "variable", "选择变量", ""), + ], + }] + } + }, + { + "name": "gfun", + "title": "内层函数下界", + "optional": False, + "ctrl": { + "type": "multitype_ctrl", + "title": "内层函数下界", + "init": "lambda x:0", + "types": + [{ + "type_title": "输入表达式", + "ctrls": [ + ("line_ctrl", "", '输入表达式并自动转换为函数', "np.sin(2*np.pi*x)"), + ], + "on_ok": lambda data: convert_to_lambda(data[""]) + }, { + "type_title": "输入函数", + "ctrls": [ + ("line_ctrl", "", '输入函数代码', "lambda x:0"), + ], + "on_ok": lambda data: Function(data[""]) + }, { + "type_title": "选择变量", + "ctrls": [ + ("vars_combo_ctrl", "variable", "选择变量", ""), + ], + }] + } + }, + { + "name": "a", + "title": "积分下限", + "optional": False, + "ctrl": { + "type": "multitype_ctrl", + "title": "积分下限", + "init": 0, + "types": + [{ + "type_title": "输入下界", + "ctrls": [ + ("number_ctrl", "", '输入下界', 0), + ], + }, { + "type_title": "选择变量", + "ctrls": [ + ("vars_combo_ctrl", "variable", "选择变量", ""), + ], + }] + } + }, + { + "name": "b", + "title": "积分上限", + "optional": False, + "ctrl": { + "type": "multitype_ctrl", + "title": "积分上限", + "init": 1, + "types": + [{ + "type_title": "输入数值", + "ctrls": [ + ("number_ctrl", "", '输入数值', 1), + ] + }, { + "type_title": "选择变量", + "ctrls": [ + ("vars_combo_ctrl", "variable", "选择变量", ""), + ], + }] + } + }, + ] + +} + + +class PivotDialog(FunctionGUIDialog): + def __init__(self): + FunctionGUIDialog.__init__(self, dic) + + +if __name__ == '__main__': + app = QApplication([]) + md = PivotDialog() + md.show() + app.exec_() diff --git a/pmgwidgets/widgets/composited/fastui.py b/pmgwidgets/widgets/composited/fastui.py index 6d2df6b0..6f3a80a7 100644 --- a/pmgwidgets/widgets/composited/fastui.py +++ b/pmgwidgets/widgets/composited/fastui.py @@ -241,15 +241,16 @@ class FunctionGUIDialog(DFOperationDialog): if arg["optional"]: optional_names.append(arg["name"]) views.append(("check_ctrl", arg["name"] + "#enable", "", True)) + arg["ctrl"]["name"] = arg["name"] views.append(arg["ctrl"]) self.panel.set_items(views) - for op_name in optional_names: self.panel.set_as_controller(op_name + "#enable", [op_name], True, ) def get_value_code(self) -> str: values = self.panel.get_value_with_filter() # 只获取使能并且可见的控件的值 + print(values,self.panel.widgets_dic) values = {k: v for k, v in values.items() if k.isidentifier()} varname = self.combo_box.currentText() args_str = '' @@ -261,7 +262,7 @@ class FunctionGUIDialog(DFOperationDialog): code = '{var_name}.{method_name}({args})'.format(var_name=varname, method_name=self.func_name, args=args_str) - + print(code,values) return code diff --git a/pmgwidgets/widgets/extended/entries/funcctrl.py b/pmgwidgets/widgets/extended/entries/funcctrl.py new file mode 100644 index 00000000..a3820c22 --- /dev/null +++ b/pmgwidgets/widgets/extended/entries/funcctrl.py @@ -0,0 +1,101 @@ +import ast +import astunparse +from typing import Any, Tuple, List + +from PySide2.QtWidgets import QLineEdit, QLabel, QHBoxLayout, QPushButton, QMessageBox + +from pmgwidgets.widgets.extended.base.baseextendedwidget import BaseExtendedWidget + + +class CodeVisitor(ast.NodeVisitor): + def __init__(self): + super(CodeVisitor, self).__init__() + self.preserved = {"pi", "e"} + self.called = set() + self.func_args = set() + self._names = set() + + def visit_Name(self, node: ast.Name) -> Any: + self._names.add(node.id) + + + def visit_Call(self, node: ast.Call) -> Any: + self.generic_visit(node) + self.called.add(node.func.id) + + def get_result(self) -> Tuple[List[str], List[str]]: + """ + + Returns: 定义的名称,以及调用的ID名称。 + + """ + names = self._names.copy() + names.difference_update(self.preserved) + names.difference_update(self.called) + return list(names), list(self.called) + + +# n = ast.parse("x*cos(v,sin(2*pi*x))") +# print(CodeVisitor().visit(n)) +# print(cv := CodeVisitor()) +# cv.visit(n) +# print(cv.get_result()) +# # # print(ast.get_source_segment("x*cos(v,sin(2*pi*x))",n)) +# # print(ast.dump(n)) +# # print(astunparse.unparse(n)) + + +class PMGFuncCtrl(BaseExtendedWidget): + """ + + 输入:一个有效的函数表达式。 + 其中,里面的变量名会自动进行检测。 + + """ + + def __init__(self, layout_dir: str, title: str, initial_value: str): + super().__init__(layout_dir) + self.allowed_chars = set(' ,[](){}:1234567890.+-*/') + self.on_check_callback = None + self.prefix = QLabel(text=title) + self.type = type + entryLayout = QHBoxLayout() + self.ctrl = QLineEdit() + self.central_layout.addWidget(self.prefix) + self.central_layout.addLayout(entryLayout) + entryLayout.addWidget(self.ctrl) + self.set_value(initial_value) + + def get_code(self) -> str: + text = self.ctrl.text() + if self.type == 'safe': + for char in text: + if char not in self.allowed_chars: + return None + return text + + def set_value(self, obj: Any): + try: + self.ctrl.setText(repr(obj)) + except: + import traceback + traceback.print_exc() + + def get_value(self) -> object: + if self.get_code() is not None: + try: + return eval(self.ctrl.text()) + except: + import traceback + traceback.print_exc() + return None + else: + return None + + def on_eval_test(self): + """ + 点击计算按钮,弹出对话框显示计算结果。 + :return: + """ + val = self.get_value() + QMessageBox.information(self, self.tr('Result'), repr(val), QMessageBox.Ok) diff --git a/pmgwidgets/widgets/extended/others/multitypeparaminput.py b/pmgwidgets/widgets/extended/others/multitypeparaminput.py index fb60d0cf..65f20666 100644 --- a/pmgwidgets/widgets/extended/others/multitypeparaminput.py +++ b/pmgwidgets/widgets/extended/others/multitypeparaminput.py @@ -35,7 +35,7 @@ class PMGMultiTypeCtrl(BaseExtendedWidget): index = self.get_type_index() self.sub_panel.set_items([self.ctrls[index]["ctrls"]]) - print(self.get_value()) + # print(self.get_value()) # self.setFixedSize(0) def on_param_changed(self, event): diff --git a/requirements.txt b/requirements.txt index cf5d9a0d..45dd7f37 100644 --- a/requirements.txt +++ b/requirements.txt @@ -57,5 +57,6 @@ cx_Oracle>=8.1.0 pyminer_comm>=0.7.1 ipyparams pathspec +codegen -- Gitee From 3d5c97b516662a0a213b4b3a5b3b60af361aa3a4 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Sun, 25 Apr 2021 13:22:37 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=90=8E=E6=95=B4?= =?UTF-8?q?=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- features/main_window/base.py | 31 +++++++++++-------------------- features/ui/ui_option.py | 2 +- features/ui/ui_option.ui | 2 +- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/features/main_window/base.py b/features/main_window/base.py index c4383a23..a4fc2207 100644 --- a/features/main_window/base.py +++ b/features/main_window/base.py @@ -1,12 +1,12 @@ +import base64 +import json +import logging import os import sys import time import webbrowser - -import base64 -import json -from typing import Tuple, List - +from multiprocessing import shared_memory +from typing import List from PySide2.QtCore import QPoint from PySide2.QtCore import Signal, Qt, QUrl, QPropertyAnimation @@ -16,27 +16,20 @@ from PySide2.QtWebEngineWidgets import * from PySide2.QtWidgets import QListWidgetItem, QWizard, QMessageBox from PySide2.QtWidgets import QWidget, QDesktopWidget, QFileDialog, QApplication, QDialog -from pmgwidgets import PMGPanel - import utils from features.extensions.extensionlib.extension_lib import extension_lib from features.io.settings import Settings from features.ui.ui_aboutme import Ui_Form as About_Ui_Form from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form from features.ui.ui_first_form import Ui_Form as first_Ui_Form +from features.ui.ui_login import Ui_Form as login_Ui_Form +from features.ui.ui_logined import Ui_Form as logined_Ui_Form from features.ui.ui_option import Ui_Form as Option_Ui_Form from features.ui.ui_project_wizard import Ui_Wizard as Project_Ui_Form from pmgwidgets import PMGPanel -from utils import get_main_window - -from features.ui.ui_login import Ui_Form as login_Ui_Form -from features.ui.ui_logined import Ui_Form as logined_Ui_Form -import utils from utils import get_main_window, http_client -from features.io.settings import Settings -from features.extensions.extensionlib.extension_lib import extension_lib -from multiprocessing import shared_memory +logger = logging.getLogger(__name__) class OptionForm(QDialog, Option_Ui_Form): @@ -115,10 +108,7 @@ class OptionForm(QDialog, Option_Ui_Form): load_theme(style) Settings.get_instance()['theme'] = self.comboBox_theme.currentText() - # print(Settings.get_instance()['theme']) get_main_window().settings_changed_signal.emit() - # get_main_window().on_settings_changed() - # self.signal_settings_changed.emit() def slot_change_workspace(self): directory = QFileDialog.getExistingDirectory(self, "选择工作路径位置", directory=Settings.get_instance()['work_dir']) @@ -136,7 +126,7 @@ class OptionForm(QDialog, Option_Ui_Form): :return: """ settings = utils.get_settings_from_file("config.ini") - print(settings.value('MAIN/PATH_WORKDIR')) + logger.debug("PATH/WORKDIR", settings.value('MAIN/PATH_WORKDIR')) if settings.value('MAIN/THEME') is not None: for i in range(self.comboBox_theme.count()): if self.comboBox_theme.itemText(i) == settings.value('MAIN/THEME'): @@ -629,6 +619,7 @@ class LoginForm(QDialog, login_Ui_Form): """ 登录窗口 """ + def __init__(self, parent=None): super(LoginForm, self).__init__(parent) self.setupUi(self) @@ -706,7 +697,7 @@ class LoginedForm(QDialog, logined_Ui_Form): shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token buff = shared_memo.buf for i in range(0, len(buff)): - buff[i:i+1] = "\x00".encode() + buff[i:i + 1] = "\x00".encode() time.sleep(0.5) self.close() diff --git a/features/ui/ui_option.py b/features/ui/ui_option.py index 13fc3958..7340b217 100644 --- a/features/ui/ui_option.py +++ b/features/ui/ui_option.py @@ -435,7 +435,7 @@ class Ui_Form(object): self.label_8.setText(QCoreApplication.translate("Form", u"\u8d27\u5e01\u7b26\u53f7\u4f4d\u4e8e:", None)) self.pushButton_help.setText(QCoreApplication.translate("Form", u"Help", None)) - self.pushButton_ok.setText(QCoreApplication.translate("Form", u"Ok", None)) + self.pushButton_ok.setText(QCoreApplication.translate("Form", u"OK", None)) self.pushButton_cancel.setText(QCoreApplication.translate("Form", u"Cancel", None)) # retranslateUi diff --git a/features/ui/ui_option.ui b/features/ui/ui_option.ui index 645ab651..f9394124 100644 --- a/features/ui/ui_option.ui +++ b/features/ui/ui_option.ui @@ -562,7 +562,7 @@ p, li { white-space: pre-wrap; } - Ok + OK -- Gitee From ae478f2d06638fe5d8b968c0b80d73897bf13f17 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Sun, 25 Apr 2021 14:42:38 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E4=BD=BF=E7=94=A8QSettings=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=EF=BC=8C=E4=BD=86=E6=98=AF=E7=9B=AE=E5=89=8D=E8=BF=98?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E5=81=9A=E5=92=8C=E4=B9=8B=E5=89=8D=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=E9=80=82=E9=85=8D=E5=B7=A5=E4=BD=9C=EF=BC=8C?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD=E6=9A=82?= =?UTF-8?q?=E6=97=B6=E6=B2=A1=E6=9C=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app2.py | 9 +- configuration/config.ini | 3 +- .../extensions/extensionlib/extension_lib.py | 61 +- .../extensions/extensionlib/extensionlib.md | 1 - .../interpretermanager/interpretermanager.py | 57 +- features/io/encoding.py | 12 +- features/io/settings.py | 134 +-- features/main_window/base.py | 12 +- features/ui/pmwidgets/pmmainwindow.py | 27 +- .../applications_toolbar.py | 4 +- packages/applications_toolbar/dev_tools.py | 10 +- packages/code_editor/codeeditor/tabwidget.py | 28 +- packages/code_editor/main.py | 12 +- packages/dataio/export.py | 2 +- packages/dataio/sample.py | 2 +- packages/file_tree/main.py | 12 +- packages/ipython_console/ipythonqtconsole.py | 4 +- packages/ipython_console/main.py | 8 +- packages/socket_server/server_by_socket.py | 10 +- pmgui.py | 761 +++++++++--------- resources/qss/Fusion.qss | 20 +- resources/qss/standard.qss | 36 +- resources/qss/windowsvista.qss | 2 +- utils/__init__.py | 14 +- utils/settings/settings.py | 2 +- 25 files changed, 644 insertions(+), 599 deletions(-) diff --git a/app2.py b/app2.py index 593dc93c..902f4197 100644 --- a/app2.py +++ b/app2.py @@ -39,10 +39,6 @@ def exception_handler(i: 'Tuple[ClassVar[BaseException], BaseException]'): reinstall_requirements_with_gui() - # dlg = ExceptionHandlerDialog(i[1]) - # - # dlg.exec_() - def on_exception(e): from check_dependency import ExceptionHandlerDialog @@ -74,7 +70,6 @@ from pmgwidgets import PMGToolBar from features.extensions.extensions_manager.manager import extensions_manager from features.main_window import base -from features.io.settings import Settings from features.io.settings import load_theme from features.interpretermanager.interpretermanager import InterpreterManagerWidget from features.util.update import UpdateTipClient @@ -141,7 +136,7 @@ class MainWindow(BaseMainWindow): def __init__(self, parent=None): super().__init__(parent) - settings = Settings() + # settings = Settings() t00 = time.time() self.main_option_form = base.OptionForm() self.project_wizard: base.ProjectWizardForm = None @@ -333,7 +328,7 @@ class MainWindow(BaseMainWindow): self.widgets_ready_signal.emit() t1 = time.time() logging.info('Layout ready time elapsed:%f' % (t1 - t0)) - self.set_dock_titlebar_visible(Settings.get_instance()['dock_titlebar_visible']) + self.set_dock_titlebar_visible(utils.get_settings_item_from_file("config.ini", "MAIN/DOCK_TITLEBAR_VISIBLE")) self.bind_events() self.events_ready_signal.emit() t2 = time.time() diff --git a/configuration/config.ini b/configuration/config.ini index 9d3f49d8..22e5135e 100644 --- a/configuration/config.ini +++ b/configuration/config.ini @@ -6,9 +6,10 @@ PATH_WORKDIR = INTERPRETER = d:/pyminer/python.exe SHOW_START_PAGE = True CHECK_UPDATE = True +DOCK_TITLEBAR_VISIBLE = False [RUN] -EXTERNAL_INTERPRETERS = "{}" +EXTERNAL_INTERPRETERS = "[]" CURRENT_INTERPRETER = [INFO] diff --git a/features/extensions/extensionlib/extension_lib.py b/features/extensions/extensionlib/extension_lib.py index ef22b7f6..60b96ed6 100644 --- a/features/extensions/extensionlib/extension_lib.py +++ b/features/extensions/extensionlib/extension_lib.py @@ -1,10 +1,12 @@ import inspect import os -from typing import TYPE_CHECKING, Callable, Dict, List, Tuple, Union, Optional, Any -from PySide2.QtCore import QRect, Signal, QTranslator, QLocale -from PySide2.QtWidgets import QWidget, QApplication, QDialog -from features.workspace.data_adapter import UniversalAdapter +from typing import TYPE_CHECKING, Callable, Dict, List, Tuple, Optional, Any + +from PySide2.QtCore import QRect, Signal +from PySide2.QtWidgets import QWidget, QDialog + import utils +from features.workspace.data_adapter import UniversalAdapter if TYPE_CHECKING: from pmgwidgets import PMGToolBar @@ -18,8 +20,6 @@ def wrapper(): from utils import get_main_window from features.ui import pmwidgets from features.extensions.extensionlib import baseext - from features.ui.common.pmlocale import pmlocale - from features.io.settings import Settings from features.io.exceptions import PMExceptions from pyminer_comm.base import DataDesc @@ -260,42 +260,32 @@ def wrapper(): return utils.get_root_dir() @staticmethod - def _(text): + def get_settings_item_from_file(file: str, item: str, mode: str = "user"): """ - + 从设置文件中获取设置项 Args: - text: - - Returns: - - """ - return pmlocale.translate(text) - - @staticmethod - def get_settings() -> Dict[str, str]: - """ + file: + item: + mode: Returns: """ - return Settings.get_instance() + return utils.get_settings_item_from_file(file, item, mode) @staticmethod - def update_settings(settings_to_modify: Dict[str, str]) -> None: + def write_settings_item_to_file(file: str, item: str, value: Any): """ - 修改设置 + 将配置项写入设置文件中 Args: - settings_to_modify: + file: + item: + value: Returns: """ - settings = Settings.get_instance() - for k, v in settings_to_modify.items(): - if k in settings.keys(): - Settings.get_instance()[k] = v - else: - raise ValueError('Key {0} not in Settings!' % k) + utils.write_settings_item_to_file(file, item, value) get_main_window().settings_changed_signal.emit() @staticmethod @@ -309,7 +299,7 @@ def wrapper(): Returns: """ - Settings.get_instance()['work_dir'] = work_dir + utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", work_dir) get_main_window().settings_changed_signal.emit() @staticmethod @@ -321,7 +311,18 @@ def wrapper(): """ - return Settings.get_instance()['work_dir'] + dir = utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR") + if (not isinstance(dir, str)) or (not os.path.exists(dir)): + dir = os.path.join(os.path.expanduser("~"), "Desktop") + return dir + @staticmethod + def get_theme() -> str: + """ + 获取主题 + Returns: + + """ + return utils.get_settings_item_from_file("config.ini", "MAIN/THEME") @staticmethod def run_python_file(file_path: str, interpreter_path: str): diff --git a/features/extensions/extensionlib/extensionlib.md b/features/extensions/extensionlib/extensionlib.md index 093cc62a..5e5bf1e8 100644 --- a/features/extensions/extensionlib/extensionlib.md +++ b/features/extensions/extensionlib/extensionlib.md @@ -210,7 +210,6 @@ def get_settings() -> Dict[str, str]: Returns: """ -return Settings.get_instance() ### 设置当前工作路径 @staticmethod diff --git a/features/interpretermanager/interpretermanager.py b/features/interpretermanager/interpretermanager.py index 73d1d4f6..3861306d 100644 --- a/features/interpretermanager/interpretermanager.py +++ b/features/interpretermanager/interpretermanager.py @@ -7,13 +7,14 @@ settings['interpreters'] = """ import os import sys -from typing import Dict +from typing import Dict, List -from PySide2.QtWidgets import QTableWidget, QPushButton, QHBoxLayout, QVBoxLayout, QApplication, QWidget, QDialog, \ +from PySide2.QtWidgets import QPushButton, QHBoxLayout, QVBoxLayout, QWidget, QDialog, \ QListWidget, QMessageBox, QSpacerItem, QSizePolicy -from features.io.settings import Settings +import utils from pmgwidgets import PMGPanelDialog +from utils import get_settings_item_from_file class Interpreter(): @@ -35,6 +36,38 @@ def get_interpreter_version(interpreter_path: str) -> str: return version +def get_all_external_interpreters() -> List[Dict]: + """ + 获取所有的外部解释器 + Returns: + + """ + return utils.get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS") + + +def modify_interpreter_config(mode, info: Dict = None, index: int = -1): + """ + + Args: + info: 一个存储解释器信息的字典 + mode: "add","delete","modify" + + Returns: + + """ + + external_interpreters = utils.get_settings_item_from_file("config.ini", "RUN/EXTERNAL_INTERPRETERS") + if mode == "add": + external_interpreters.append(info) + elif mode == "modify": + external_interpreters[index] = info + elif mode == "delete": + external_interpreters.pop(index) + else: + raise NotImplementedError(mode) + utils.write_settings_item_to_file("config.ini", "RUN/EXTERNAL_INTERPRETERS", external_interpreters) + + class InterpreterManagerWidget(QWidget): def __init__(self, parent=None): super(InterpreterManagerWidget, self).__init__(parent) @@ -83,13 +116,15 @@ class InterpreterManagerWidget(QWidget): if ret == QDialog.Accepted: res = dlg.get_value() d = {'name': res['name'], 'path': res['path'], 'version': get_interpreter_version(res['path'])} - Settings.get_instance()['external_interpreters'].append(d) + modify_interpreter_config("add", d) self.show_interpreters() def edit(self): current_index = self.interpreters_list_show.currentRow() list_index = current_index - 1 # 第一个是默认解释器,所以要减去1 - current_interpreter = Settings.get_instance()['external_interpreters'][list_index] + + external_interpreters = get_all_external_interpreters() + current_interpreter = external_interpreters[list_index] views = [ ('line_ctrl', 'name', self.tr('Name'), current_interpreter['name']), @@ -103,7 +138,7 @@ class InterpreterManagerWidget(QWidget): if ret == QDialog.Accepted: res = dlg.get_value() d = {'name': res['name'], 'path': res['path'], 'version': get_interpreter_version(res['path'])} - Settings.get_instance()['external_interpreters'][list_index] = d + modify_interpreter_config("modify", d, list_index) self.show_interpreters() def manage_packages(self): @@ -126,19 +161,18 @@ class InterpreterManagerWidget(QWidget): return True def remove(self): - Settings.get_instance()['external_interpreters'].pop( - self.interpreters_list_show.currentRow() - 1) # 第一个是默认解释器,所以要减去1 + modify_interpreter_config("delete", index=self.interpreters_list_show.currentRow() - 1) self.show_interpreters() def show_interpreters(self): self.interpreters_list_show.clear() self.interpreters_list_show.addItem(self.tr('BuiltIn (3.8.5)')) - for interpreter in Settings.get_instance()['external_interpreters']: + ext_interpreters = get_all_external_interpreters() + for interpreter in ext_interpreters: name = interpreter['name'] version = interpreter['version'] text = name + ' (%s)' % version self.interpreters_list_show.addItem(text) - pass def on_list_current_item_changed(self): """ @@ -158,11 +192,10 @@ class InterpreterManagerWidget(QWidget): return else: list_index = current_index - 1 - return Settings.get_instance()['external_interpreters'][list_index] + return get_all_external_interpreters()[list_index] if __name__ == '__main__': - s = Settings() from PySide2.QtWidgets import QApplication app = QApplication([]) diff --git a/features/io/encoding.py b/features/io/encoding.py index f36c01dc..caac3288 100644 --- a/features/io/encoding.py +++ b/features/io/encoding.py @@ -1,16 +1,20 @@ import os + from PySide2.QtWidgets import QDialog, QPushButton, QVBoxLayout, QHBoxLayout, QTextBrowser, QMessageBox + from pmgwidgets import PMGPanel +import utils from utils import file_encoding_convert -from features.io.settings import Settings class EncodingConversionWidget(QDialog): def __init__(self, parent=None): super(EncodingConversionWidget, self).__init__(parent=parent) views = [ - ('file_ctrl', 'input_file', '读取文件名', '', '', Settings.get_instance()['work_dir']), - ('file_ctrl', 'output_file', '输出为文件', '', '', Settings.get_instance()['work_dir'],'save'), + ('file_ctrl', 'input_file', '读取文件名', '', '', + utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR")), + ('file_ctrl', 'output_file', '输出为文件', '', '', + utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR"), 'save'), [ ('combo_ctrl', 'input_encoding', '读取编码方式', 'UTF8', ['UTF8', 'GBK', 'ASCII']), ('combo_ctrl', 'output_encoding', '输出编码方式', 'UTF8', ['UTF8', 'GBK', 'ASCII']) @@ -32,7 +36,6 @@ class EncodingConversionWidget(QDialog): self.button_preview.clicked.connect(self.preview) self.button_convert.clicked.connect(self.convert) - # self.button_preview.clicked.connect(self.preview) def preview(self): info = self.panel.get_value() @@ -55,7 +58,6 @@ class EncodingConversionWidget(QDialog): if __name__ == '__main__': - s = Settings() from PySide2.QtWidgets import QApplication app = QApplication([]) diff --git a/features/io/settings.py b/features/io/settings.py index 58eaf48b..60556216 100644 --- a/features/io/settings.py +++ b/features/io/settings.py @@ -98,73 +98,73 @@ def load_theme(style: str): # app.setStyle("Windows") -class Settings(dict): - """ - 单例! - """ - - @classmethod - def __new__(cls, *args): - if not hasattr(cls, 'instance'): - instance = super().__new__(cls) - cls.instance = instance - return cls.instance - - def __init__(self): - super(Settings, self).__init__() - self.check_pyminer_settings_dir() - self.update(self.load()) - - def check_pyminer_settings_dir(self): - self.data_path = get_pyminer_data_path() - path = os.path.join(self.data_path, 'pyminer_config') - self.settings_path = path - if not os.path.exists(path): - os.mkdir(path) - - @staticmethod - def get_instance() -> 'Settings': - return Settings.instance - - def load(self) -> Dict[str, str]: - """ - 加载设置项。 - default_settings是默认设置项 - :return: - """ - with open(os.path.join(utils.get_root_dir(), 'configuration', 'default_settings.json'), 'r') as f: - default_settings = json.load(f) - if platform.system().lower() == 'windows': - default_settings['work_dir'] = os.path.expanduser('~') - else: - default_settings['work_dir'] = os.environ['HOME'] - if not os.path.exists(default_settings['work_dir']): - os.mkdir(default_settings['work_dir']) - - try: - with open(os.path.join(self.settings_path, 'pyminer_settings.json'), 'r') as f: - settings = json.load(f) - except BaseException: - settings = {} - - pmsettings = default_settings - pmsettings.update(settings) - if not os.path.exists(pmsettings['work_dir']): - pmsettings['work_dir'] = os.path.expanduser('~') - return pmsettings - - def save(self): - """ - 保存 - :return: - """ - import json - try: - config_file = os.path.join(self.settings_path, 'pyminer_settings.json') - with open(config_file, 'w') as f: - json.dump(self, f, indent=4) - except FileNotFoundError as e: - logging.warning(e) +# class Settings(dict): +# """ +# 单例! +# """ +# +# @classmethod +# def __new__(cls, *args): +# if not hasattr(cls, 'instance'): +# instance = super().__new__(cls) +# cls.instance = instance +# return cls.instance +# +# def __init__(self): +# super(Settings, self).__init__() +# self.check_pyminer_settings_dir() +# self.update(self.load()) +# +# def check_pyminer_settings_dir(self): +# self.data_path = get_pyminer_data_path() +# path = os.path.join(self.data_path, 'pyminer_config') +# self.settings_path = path +# if not os.path.exists(path): +# os.mkdir(path) +# +# @staticmethod +# def get_instance() -> 'Settings': +# return Settings.instance +# +# def load(self) -> Dict[str, str]: +# """ +# 加载设置项。 +# default_settings是默认设置项 +# :return: +# """ +# with open(os.path.join(utils.get_root_dir(), 'configuration', 'default_settings.json'), 'r') as f: +# default_settings = json.load(f) +# if platform.system().lower() == 'windows': +# default_settings['work_dir'] = os.path.expanduser('~') +# else: +# default_settings['work_dir'] = os.environ['HOME'] +# if not os.path.exists(default_settings['work_dir']): +# os.mkdir(default_settings['work_dir']) +# +# try: +# with open(os.path.join(self.settings_path, 'pyminer_settings.json'), 'r') as f: +# settings = json.load(f) +# except BaseException: +# settings = {} +# +# pmsettings = default_settings +# pmsettings.update(settings) +# if not os.path.exists(pmsettings['work_dir']): +# pmsettings['work_dir'] = os.path.expanduser('~') +# return pmsettings +# +# def save(self): +# """ +# 保存 +# :return: +# """ +# import json +# try: +# config_file = os.path.join(self.settings_path, 'pyminer_settings.json') +# with open(config_file, 'w') as f: +# json.dump(self, f, indent=4) +# except FileNotFoundError as e: +# logging.warning(e) if __name__ == '__main__': diff --git a/features/main_window/base.py b/features/main_window/base.py index a4fc2207..6c276d01 100644 --- a/features/main_window/base.py +++ b/features/main_window/base.py @@ -18,7 +18,6 @@ from PySide2.QtWidgets import QWidget, QDesktopWidget, QFileDialog, QApplication import utils from features.extensions.extensionlib.extension_lib import extension_lib -from features.io.settings import Settings from features.ui.ui_aboutme import Ui_Form as About_Ui_Form from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form from features.ui.ui_first_form import Ui_Form as first_Ui_Form @@ -106,12 +105,17 @@ class OptionForm(QDialog, Option_Ui_Form): """ from features.io.settings import load_theme load_theme(style) - - Settings.get_instance()['theme'] = self.comboBox_theme.currentText() + utils.write_settings_item_to_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText()) get_main_window().settings_changed_signal.emit() def slot_change_workspace(self): - directory = QFileDialog.getExistingDirectory(self, "选择工作路径位置", directory=Settings.get_instance()['work_dir']) + """ + 改变工作路径时的回调 + Returns: + + """ + work_dir = utils.get_settings_item_from_file("config.ini", "MAIN/THEME", self.comboBox_theme.currentText()) + directory = QFileDialog.getExistingDirectory(self, "选择工作路径位置", directory=work_dir) if not directory == '': self.lineEdit_worksapce.setText(directory) diff --git a/features/ui/pmwidgets/pmmainwindow.py b/features/ui/pmwidgets/pmmainwindow.py index 0c2060b1..f7438501 100644 --- a/features/ui/pmwidgets/pmmainwindow.py +++ b/features/ui/pmwidgets/pmmainwindow.py @@ -20,15 +20,15 @@ import chardet from PySide2.QtCore import Qt from PySide2.QtWidgets import QMainWindow, QToolBar, QPushButton, QWidget, QMenu, QDialog -from pmgwidgets import TopToolBarRight -from features.io.settings import Settings -from features.ui.common.pmlocale import pmlocale import utils +from features.ui.common.pmlocale import pmlocale +from pmgwidgets import TopToolBarRight if TYPE_CHECKING: from app2 import PMToolBarHome from features.ui.pmwidgets.dockwidget import PMDockWidget from pmgwidgets import ActionWithMessage +logger = logging.getLogger(__name__) class BaseMainWindow(QMainWindow): @@ -63,7 +63,7 @@ class BaseMainWindow(QMainWindow): else: for k, w in self.dock_widgets.items(): w.setTitleBarWidget(QWidget()) - Settings.get_instance()['dock_titlebar_visible'] = show + utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", show) @staticmethod def get_stylesheet(style_sheet_name: str = 'standard'): @@ -82,9 +82,9 @@ class BaseMainWindow(QMainWindow): enc = chardet.detect(b) if enc.get('encoding') is not None: s = b.decode(enc['encoding']) - style_sheet = s.replace( - 'MAIN_THEME', Settings.get_instance()['main_theme']).replace( - 'MARGIN_THEME', Settings.get_instance()['margin_theme']) + style_sheet = s + else: + logger.fatal("加载样式表%s失败!" % style_sheet_name) return style_sheet def init_toolbar_tab(self): @@ -175,7 +175,13 @@ class BaseMainWindow(QMainWindow): self.refresh_toolbar_hide_button_status() def save_layout(self): - layout_path = os.path.join(Settings.get_instance().settings_path, 'layout.ini') + """ + 当关闭程序时保存布局 + Returns: + + """ + cfg_dir = utils.get_user_config_dir() + layout_path = os.path.join(cfg_dir, 'layout.ini') try: with open(layout_path, 'wb') as f: s = b'' # self.saveState() @@ -184,7 +190,7 @@ class BaseMainWindow(QMainWindow): logging.warning("file not found:" + layout_path) def load_layout(self): - p = os.path.join(Settings.get_instance().settings_path, 'layout.ini') + # p = os.path.join(Settings.get_instance().settings_path, 'layout.ini') # if os.path.exists(p): # with open(p, 'rb') as f: @@ -310,7 +316,8 @@ class BaseMainWindow(QMainWindow): parent=home_toolbar, message='lock_layout') a.setCheckable(True) - a.setChecked(not Settings.get_instance()['dock_titlebar_visible']) + dock_title_visible = utils.get_settings_item_from_file("config.ini", "MAIN/DOCK_TITLEBAR_VISIBLE") + a.setChecked(not dock_title_visible) menu.addAction(a) home_toolbar.get_control_widget('view_config').setMenu(menu) self._view_config_menu = menu diff --git a/packages/applications_toolbar/applications_toolbar.py b/packages/applications_toolbar/applications_toolbar.py index 76cafa0a..2ef583f5 100644 --- a/packages/applications_toolbar/applications_toolbar.py +++ b/packages/applications_toolbar/applications_toolbar.py @@ -269,7 +269,7 @@ class PMApplicationsToolBar(PMGToolBar): Returns: """ - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + work_dir = self.extension_lib.Program.get_work_dir() app_paths = APPManager.get_instance().get_app_paths() path_index = 1 if len(app_paths) > 1 else 0 dlg = PMGPanelDialog(parent=self, views=[]) @@ -299,7 +299,7 @@ class PMApplicationsToolBar(PMGToolBar): Returns: """ - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + work_dir = self.extension_lib.Program.get_work_dir() dev_path = QFileDialog.getExistingDirectory(self, self.tr('Select Packup App Developing Folder'), directory=work_dir) diff --git a/packages/applications_toolbar/dev_tools.py b/packages/applications_toolbar/dev_tools.py index 77023881..c4f82c85 100644 --- a/packages/applications_toolbar/dev_tools.py +++ b/packages/applications_toolbar/dev_tools.py @@ -53,7 +53,7 @@ class DevelopTools(QObject): def open_designer(self): import subprocess - self.workdir = self.extension_lib.Program.get_settings()['work_dir'] + self.workdir = self.extension_lib.Program.get_work_dir() if self.check_installed(self.designer_path): subprocess.Popen(self.designer_path, cwd=self.workdir) @@ -136,7 +136,7 @@ class DevelopTools(QObject): """ ret = self.show_covered_message('.ui', '.py') if ret == QMessageBox.Ok: - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + work_dir = self.extension_lib.Program.get_work_dir() ui_files = self.list_files(work_dir, '.ui') for ui_file_path in ui_files: try: @@ -156,7 +156,7 @@ class DevelopTools(QObject): Returns: """ - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + work_dir = self.extension_lib.Program.get_work_dir() pro_path = '' for name in os.listdir(work_dir): if name.endswith('.pro'): @@ -211,7 +211,7 @@ class DevelopTools(QObject): Returns: """ - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + work_dir = self.extension_lib.Program.get_work_dir() ret = self.show_covered_message(self.tr('.py files in working directory with tr() or translate() functions'), '.ts') if ret == QMessageBox.Ok: @@ -257,7 +257,7 @@ class DevelopTools(QObject): """ ret = self.show_covered_message('.qrc', '*_rc.py') if ret == QMessageBox.Ok: - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + work_dir = self.extension_lib.Program.get_work_dir() qrcs = self.list_files(work_dir, '.qrc') for qrc_path in qrcs: try: diff --git a/packages/code_editor/codeeditor/tabwidget.py b/packages/code_editor/codeeditor/tabwidget.py index afe5f295..fa0bbcc7 100644 --- a/packages/code_editor/codeeditor/tabwidget.py +++ b/packages/code_editor/codeeditor/tabwidget.py @@ -21,26 +21,26 @@ translated into English by those websites. __version__ = '0.1' +import sys +import cgitb import logging import os -import sys import re import time from contextlib import redirect_stdout from io import StringIO from queue import Queue -from typing import TYPE_CHECKING, List -import pmgwidgets -from PySide2.QtCore import QDir, QLocale, QObject, Signal, QThread, QTemporaryFile, QTimer +from typing import List +from typing import TYPE_CHECKING, Dict, Union, Tuple, Optional, Any + +from PySide2.QtCore import QDir, QObject, Signal, QThread, QTemporaryFile, QTimer from PySide2.QtGui import QCloseEvent from PySide2.QtWidgets import QTabWidget, QFileDialog, QMessageBox, QApplication, QSizePolicy, QWidget, QComboBox - -from packages.code_editor.codeeditor.qtpyeditor import PythonHighlighter - # TODO to remove (use extensionlib) from flake8.main.application import Application -from typing import TYPE_CHECKING, Dict, Union, Tuple, Optional, Any +import pmgwidgets +from packages.code_editor.codeeditor.qtpyeditor import PythonHighlighter from pmgwidgets import PMDockObject, in_unit_test, PMGFileSystemWatchdog, UndoManager if TYPE_CHECKING or in_unit_test(): @@ -742,7 +742,8 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject): # 打开文件 self.extension_lib.UI.get_toolbar_widget('code_editor_toolbar', 'button_open_script').clicked.connect( self.slot_open_script) - interpreters = self.extension_lib.Program.get_settings()['external_interpreters'] + interpreters = self.extension_lib.Program.get_settings_item_from_file("config.ini", + "RUN/EXTERNAL_INTERPRETERS") interpreter_names = [self.tr('Builtin (3.8.5)')] + [d['name'] for d in interpreters] combo_box: QComboBox = self.extension_lib.UI.get_toolbar_widget('code_editor_toolbar', 'combobox_interpreter') @@ -821,7 +822,7 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject): Returns: """ - interpreters = self.extension_lib.Program.get_settings()['external_interpreters'] + interpreters = self.extension_lib.Program.get_settings_item_from_file("config.ini", 'RUN/EXTERNAL_INTERPRETERS') combo.clear() combo.addItem(self.tr('Builtin (%s)' % sys.version.split()[0])) for interpreter in interpreters: @@ -838,9 +839,8 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject): elif interpreter_index == 0: self._current_executable = sys.executable else: - print(self.extension_lib.Program.get_settings()['external_interpreters'], interpreter_index) self._current_executable = \ - self.extension_lib.Program.get_settings()['external_interpreters'][interpreter_index - 1]['path'] + self.extension_lib.Program.get_settings_item_from_file("config.ini", 'RUN/EXTERNAL_INTERPRETERS')[interpreter_index - 1]['path'] def on_tab_switched(self, index: int) -> None: for i in range(self.count()): @@ -955,9 +955,7 @@ class PMCodeEditTabWidget(QTabWidget, PMDockObject): if __name__ == '__main__': - import sys - import cgitb - import logging + cgitb.enable(format='text') logging.basicConfig(level=logging.INFO) diff --git a/packages/code_editor/main.py b/packages/code_editor/main.py index 7c1bd8fd..d5e1fb5f 100644 --- a/packages/code_editor/main.py +++ b/packages/code_editor/main.py @@ -1,7 +1,6 @@ -import sys import os -import time -from typing import Dict, Union, Any +import sys +from typing import Dict, Union from PySide2.QtCore import QLocale, QTranslator from PySide2.QtWidgets import QApplication @@ -71,15 +70,14 @@ class Extension(BaseExtension): Deal with events that settings changed. :return: """ - theme = self.extension_lib.Program.get_settings()['theme'] - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + theme = self.extension_lib.Program.get_theme() + work_dir = self.extension_lib.Program.get_work_dir() if theme != self.editor_widget._color_scheme: if theme.lower() in ('fusion', 'windows', 'windowsvista'): self.editor_widget.set_color_scheme('light') else: self.editor_widget.set_color_scheme('dark') - - work_dir = self.extension_lib.Program.get_settings()['work_dir'] + print(work_dir) self.editor_widget.on_work_dir_changed(work_dir) def bind_event(self): diff --git a/packages/dataio/export.py b/packages/dataio/export.py index c8c2c0d0..568e2669 100644 --- a/packages/dataio/export.py +++ b/packages/dataio/export.py @@ -16,7 +16,7 @@ class ExportDialog(QDialog): super(ExportDialog, self).__init__(parent=None) self.normal = False if initial_path == '' and not in_unit_test(): - initial_path = self.extension_lib.Program.get_settings()['work_dir'] + initial_path = self.extension_lib.Program.get_work_dir() self.setLayout(QVBoxLayout()) self.initial_var_name = initial_var_name self.initial_path = initial_path diff --git a/packages/dataio/sample.py b/packages/dataio/sample.py index 30f0c790..4f207de6 100644 --- a/packages/dataio/sample.py +++ b/packages/dataio/sample.py @@ -237,7 +237,7 @@ class ImportDialog(QDialog): def get_work_dir(self) -> str: """获取工作路径""" - return self.extension_lib.Program.get_settings()['work_dir'] + return self.extension_lib.Program.get_work_dir() def center(self): """将窗口置于中心""" diff --git a/packages/file_tree/main.py b/packages/file_tree/main.py index d86e7bdc..697259db 100644 --- a/packages/file_tree/main.py +++ b/packages/file_tree/main.py @@ -1,11 +1,11 @@ import os from typing import Callable -from PySide2.QtWidgets import QApplication from PySide2.QtCore import QLocale, QTranslator +from PySide2.QtWidgets import QApplication -from .file_tree import PMFilesTree from features.extensions.extensionlib import BaseExtension, BaseInterface +from .file_tree import PMFilesTree file_name = os.path.join(os.path.dirname(__file__), 'translations', 'qt_%s.qm' % QLocale.system().name()) app = QApplication.instance() @@ -23,9 +23,11 @@ class Extension(BaseExtension): files_tree: 'PMFilesTree' = self.widgets['PMFilesTree'] files_tree.extension_lib = self.extension_lib self.interface.file_widget = files_tree - settings = self.extension_lib.Program.get_settings() - self.extension_lib.Signal.get_settings_changed_signal().connect( # 当主界面设置改变信号发出时,改变工作路径。 - lambda: files_tree.change_current_path(settings['work_dir'])) + def on_settings_changed(): + work_dir = self.extension_lib.Program.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR") + files_tree.change_current_path(work_dir) + + self.extension_lib.Signal.get_settings_changed_signal().connect(on_settings_changed) # 当主界面设置改变信号发出时,改变工作路径。 class Interface(BaseInterface): diff --git a/packages/ipython_console/ipythonqtconsole.py b/packages/ipython_console/ipythonqtconsole.py index 46e3302d..e10b1683 100644 --- a/packages/ipython_console/ipythonqtconsole.py +++ b/packages/ipython_console/ipythonqtconsole.py @@ -37,7 +37,7 @@ class ConsoleWidget(PMGIpythonConsole, PMDockObject): def setup_ui(self): super().setup_ui() if not in_unit_test(): - style = self.lib.Program.get_settings()['theme'] + style = self.lib.Program.get_theme() self.change_ui_theme(style) def connect_to_datamanager(self, data_manager): @@ -56,7 +56,7 @@ class ConsoleWidget(PMGIpythonConsole, PMDockObject): if in_unit_test(): pwd = os.path.dirname(__file__) else: - pwd = self.extension_lib.Program.get_settings()['work_dir'] + pwd = self.extension_lib.Program.get_work_dir() pwd = pwd.replace('\\', '\\\\') from utils import get_root_dir cmd = 'import sys;sys.path.append(r\'%s\')' % get_root_dir() diff --git a/packages/ipython_console/main.py b/packages/ipython_console/main.py index c730eaae..1492208d 100644 --- a/packages/ipython_console/main.py +++ b/packages/ipython_console/main.py @@ -37,16 +37,16 @@ class Extension(BaseExtension): self.interface.widget = self.console self.extension_lib.Signal.get_settings_changed_signal().connect(self.on_settings_changed) self.extension_lib.Signal.get_events_ready_signal().connect(self.on_settings_changed) - self._work_dir = self.extension_lib.Program.get_settings()['work_dir'] + self._work_dir = self.extension_lib.Program.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR") def on_settings_changed(self): """ 如果设置项发生改变,重新加载主题文件。 TODO:倘若ipython发生改变之后,工作路径如何跟着改变? """ - settings = self.extension_lib.Program.get_settings() - self.console.change_ui_theme(settings['theme']) - work_dir = settings['work_dir'] + theme = self.extension_lib.Program.get_theme() + self.console.change_ui_theme(theme) + work_dir = self.extension_lib.Program.get_work_dir() if not os.path.samefile(work_dir, self._work_dir): # samefile函数:既可判断是否为同一文件,也可判断是否为同一文件夹 self.command = self.interface.run_command("get_ipython().chdir(\'%s\')" % work_dir.replace('\\', '\\\\'), hidden=False) diff --git a/packages/socket_server/server_by_socket.py b/packages/socket_server/server_by_socket.py index 03895aa8..65e801b1 100644 --- a/packages/socket_server/server_by_socket.py +++ b/packages/socket_server/server_by_socket.py @@ -56,7 +56,8 @@ def get_settings(): :return: """ global message_queue - return json.dumps(extension_lib.Program.get_settings()) + return "['Warning this method was deprecated']" + # return json.dumps(extension_lib.Program.get_settings()) @app.route('/get_stylesheet') @@ -196,10 +197,9 @@ class PMGServer(QObject): :param settings :return: """ - for param_name, param_val in settings.items(): - if param_name not in self.extension_lib.Program.get_settings().keys(): - raise ValueError('Parameter name \'%s\' not in settings!' % param_name) - self.extension_lib.Program.update_settings(settings) + logger.warning("目前服务器on_settings_changed方法无效!") + raise DeprecationWarning + # self.extension_lib.Program.update_settings(settings) def on_interface_called(self, interface_name: str, method_name: str, kwargs: Dict, res_queue: queue.Queue): interface = self.extension_lib.get_interface(interface_name) diff --git a/pmgui.py b/pmgui.py index 52f2bddc..f83fc3bd 100644 --- a/pmgui.py +++ b/pmgui.py @@ -1,33 +1,26 @@ import datetime import getpass +import logging import os import time +from multiprocessing import shared_memory +from typing import List, Callable -from PySide2.QtWidgets import QTextEdit -from pmgwidgets import PMGToolBar, ActionWithMessage, PMDockObject, create_icon - -from typing import List, Callable, Tuple, ClassVar - -from PySide2.QtCore import Signal, QTimer, Qt, QTranslator, QLocale, QSize, QCoreApplication -from PySide2.QtGui import QCloseEvent, QTextCursor, QResizeEvent, QFontDatabase, QMoveEvent, QFont, QIcon, QPixmap -from PySide2.QtWidgets import QApplication, QTextEdit, QMessageBox, QToolBar, QSplashScreen, QStatusBar, QTextBrowser, \ - QDialog, QVBoxLayout, QLabel, QHBoxLayout, QPushButton -from utils import get_main_window, get_application +from PySide2.QtCore import Signal, QTimer, Qt, QSize +from PySide2.QtGui import QCloseEvent, QTextCursor, QResizeEvent, QMoveEvent +from PySide2.QtWidgets import QTextEdit, QMessageBox, QStatusBar -from pmgwidgets import PMGToolBar, ActionWithMessage, PMDockObject, create_icon +import utils from features.extensions.extensions_manager.manager import extensions_manager -from features.main_window import base -from features.io.settings import Settings -from features.io.settings import load_theme -from features.interpretermanager.interpretermanager import InterpreterManagerWidget -from features.util.update import perform_update, UpdateTipClient from features.feedback import FeedbackClient -from features.ui.widgets.controlpanel import PMPageExt +from features.interpretermanager.interpretermanager import InterpreterManagerWidget +from features.io.settings import load_theme +from features.main_window import base from features.ui.pmwidgets import BaseMainWindow -from multiprocessing import shared_memory -import utils -import logging - +from features.ui.widgets.controlpanel import PMPageExt +from features.util.update import perform_update, UpdateTipClient +from pmgwidgets import PMGToolBar, ActionWithMessage, PMDockObject, create_icon +from utils import get_main_window, get_application def updateSplashMsg(ext_load_status: dict): @@ -40,6 +33,7 @@ def updateSplashMsg(ext_load_status: dict): except TypeError: return + class PMToolBarHome(PMGToolBar): """ 定义菜单工具栏按钮。 @@ -175,361 +169,372 @@ class PMToolBarHome(PMGToolBar): class LogOutputConsole(QTextEdit, PMDockObject): pass -class MainWindow(BaseMainWindow): - setupui_tasks: List[Callable] = [] - boot_timer: QTimer = None - close_signal = Signal() - window_geometry_changed_signal = Signal() - - layouts_ready_signal = Signal() - widgets_ready_signal = Signal() - events_ready_signal = Signal() - - settings_changed_signal = Signal() - - @classmethod - def __new__(cls, *args): - if not hasattr(cls, 'instance'): - instance = super().__new__(cls) - cls.instance = instance - return cls.instance - - def __init__(self, parent=None): - super().__init__(parent) - - t00 = time.time() - settings = Settings() - self.main_option_form = base.OptionForm() - self.project_wizard: base.ProjectWizardForm = None - self.settings_changed_signal.connect(self.on_settings_changed) - self.main_option_form.add_page(self.tr('Interpreter'), InterpreterManagerWidget()) - - utils._main_window = self - - # 主窗体默认大小 - self.resize(1920, 1080) - self.setIconSize(QSize(40, 40)) - # 设置状态栏 - self.statusBar = QStatusBar() - version = utils.get_python_version() - self.statusBar.showMessage(version, 0) - self.setStatusBar(self.statusBar) - - root_dir = os.path.dirname(__file__) - utils._root_dir = root_dir - - self.init_toolbar_tab() - tb_home = PMToolBarHome() - self.add_toolbar('toolbar_home', tb_home, text=tb_home.get_toolbar_text()) - self.setDockNestingEnabled(True) - self.setWindowTitle('PyMiner') - - self.log_output_console = LogOutputConsole(self) - - self.add_widget_on_dock( - 'log_output_console', - self.log_output_console, - text=self.tr('Logs'), - side='right') - - # 初始化日志 - self.slot_flush_console('info', 'system', self.tr('Welcome to PyMiner')) - - self.extensions_manager = extensions_manager - self.extensions_manager.load_from_extension_folder(updateSplashMsg) - - self.ext_manager_widget = PMPageExt(self) - dw = self.add_widget_on_dock( - 'extension_panel', - self.ext_manager_widget, - text=self.tr('Plugs'), - side='left') - dw.setMaximumWidth(400) - - load_theme(settings['theme']) # 组件都加载后再设置主题,否则可能有些组件不生效 - self.show() - self.load_layout() - self.switch_toolbar('toolbar_home') # 启动完成时,将工具栏切换到‘主页’ - - self.on_main_window_shown() - # self.first_form_display() - - self.start_pmlocalserver() # 只要在插件加载完成之后启动就行,目前放在最后 - self.update_tip_client = UpdateTipClient() # 启动程序,检查更新,弹窗提醒 - - t01 = time.time() - logging.debug('Time Elapsed for loading main window contents: %f' % (t01 - t00)) - - def start_pmlocalserver(self): - """ - 启动本地flask服务器pmlocalserver - Returns:None - - """ - server.server_thread.start() - - def clear_workspace(self): - from features.extensions.extensionlib.extension_lib import extension_lib - extension_lib.get_interface('ipython_console').run_command('Clearing_Variables_ =\'Clear All\'', - hint_text=self.tr('Start Clear...'), hidden=False) - extension_lib.get_interface('ipython_console').run_command('get_ipython().clear_all()', - hint_text=self.tr('Clear all variables'), - hidden=False) - - def add_toolbar(self, name: str, toolbar: PMGToolBar, - text: str = 'untitled toolbar'): - """ - 添加一个工具栏。 - """ - if toolbar.insert_after() == '': - b = self.top_toolbar_tab.add_button(name, text) - else: - b = self.top_toolbar_tab.insert_button(name, text, toolbar.insert_after()) - toolbar.tab_button = b - b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name)) - - if hasattr(self, 'toolbar_path'): - self.insertToolBar(self.toolbar_path, toolbar) - self.insertToolBarBreak(self.toolbar_path) - else: - self.addToolBarBreak(Qt.TopToolBarArea) - self.addToolBar(toolbar) - toolbar.setObjectName(name) - self.toolbars[name] = toolbar - toolbar.setMovable(False) - toolbar.setFloatable(False) - - if self._current_toolbar_name != '': - self.refresh_toolbar_appearance() - - # def insert_toolbar(self, name: str, toolbar: QToolBar, text: str, insert_after: str): - # """ - # 插入一个工具栏。 - # """ - # b = self.top_toolbar_tab.add_button(text) - # toolbar.tab_button = b - # b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name)) - # - # if hasattr(self, 'toolbar_path'): - # self.insertToolBar(self.toolbar_path, toolbar) - # self.insertToolBarBreak(self.toolbar_path) - # else: - # self.addToolBarBreak(Qt.TopToolBarArea) - # self.addToolBar(toolbar) - # toolbar.setObjectName(name) - # self.toolbars[name] = toolbar - # toolbar.setMovable(False) - # toolbar.setFloatable(False) - # - # if self._current_toolbar_name != '': - # self.refresh_toolbar_appearance() - - def moveEvent(self, a0: 'QMoveEvent') -> None: - self.window_geometry_changed_signal.emit() - - def resizeEvent(self, a0: QResizeEvent) -> None: - """ - 窗口大小调节,或者位置改变的信号。 - Window size adjustment, or a signal of a change in position. - """ - self.size_restriction_acquire() - super().resizeEvent(a0) - self.delayed_call(500, self.size_restriction_release) - self.window_geometry_changed_signal.emit() - - def on_settings_changed(self): - load_theme(Settings.get_instance()['theme']) - - def delayed_call(self, time_ms: int, callback: Callable) -> None: - """ - 封装了QTimer.SingleShot - :param time_ms: - :param callback: - :return: - """ - timer = QTimer() - timer.singleShot(time_ms, callback) - - def size_restriction_acquire(self) -> None: - """ - 设置插件尺寸的最大值。 - 控件需要指定get_split_portion_hint才可以。 - :return: - """ - for k in self.dock_widgets.keys(): - dw = self.dock_widgets[k] - horizontal_portion_hint = dw.widget().get_split_portion_hint()[0] - if horizontal_portion_hint is not None: - dw.setMaximumWidth(int(self.width() * horizontal_portion_hint)) - dw.setMinimumWidth(int(self.width() * horizontal_portion_hint)) - - def size_restriction_release(self): - for w_name in self.dock_widgets.keys(): - self.dock_widgets[w_name].setMaximumWidth(100000) - self.dock_widgets[w_name].setMaximumHeight(100000) - self.dock_widgets[w_name].setMinimumHeight(0) - self.dock_widgets[w_name].setMinimumWidth(0) - - def on_main_window_shown(self): - """ - 在界面显示后触发的事件。 - Returns: None - """ - t0 = time.time() - super().on_main_window_shown() - - self.layouts_ready_signal.emit() - for task in self.setupui_tasks: - task() - self.widgets_ready_signal.emit() - t1 = time.time() - logging.info('Layout ready time elapsed:%f' % (t1 - t0)) - self.set_dock_titlebar_visible(Settings.get_instance()['dock_titlebar_visible']) - self.bind_events() - self.events_ready_signal.emit() - t2 = time.time() - logging.info('Events ready, time elapsed:%f' % (t2 - t1)) - - def first_form_display(self): - """ - 显示"快速操作"窗口 - Displays the "Quick Action" window - """ - self.main_first_form = base.FirstForm(parent=self) - self.main_first_form.show() - - def login_form_display(self): - """ - 显示"登录"窗口 - Displays the "Quick Action" window - """ - shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token - buff = shared_memo.buf - token = bytes(buff[:199]).decode().replace("\x00", "") - if token != "": - self.main_login_form = base.LoginedForm(parent=self) - self.main_login_form.exec_() - else: - self.main_login_form = base.LoginForm(parent=self) - self.main_login_form.exec_() - - def main_appstore_dispaly(self): - """ - 显示"应用商店"窗口 - Displays the "App Store" window - """ - self.appstore = MarketplaceForm() - self.appstore.show() - - def main_option_display(self): - """ - 显示"选项"窗口 - """ - if self.main_option_form is None: - self.main_option_form = base.OptionForm() - self.main_option_form.exec_() - - def main_help_display(self): - """ - 打开帮助页面 - """ - utils.open_url("https://gitee.com/py2cn/pyminer/wikis") - - def main_check_update_display(self): - """ - 打开'检查更新'页面 - """ - perform_update() - - def main_install_update(self): - closed = self.close() - if closed: - from pmgwidgets import run_python_file_in_terminal - path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'update', 'update.py') - run_python_file_in_terminal(path + ' -i') - - def main_feedback_display(self): - """ - 打开'反馈'页面 - """ - FeedbackClient() - # reply = QMessageBox.information(self, self.tr('Feedback'), self.tr( - # 'You can give feedback through issue on suggestions or problems encountered in use'), - # QMessageBox.Yes | QMessageBox.No, - # QMessageBox.Yes) - # if reply == QMessageBox.Yes: - # utils.open_url("https://gitee.com/py2cn/pyminer/issues") - - def main_homesite_display(self): - """ - 打开官方网站页面 - """ - utils.open_url("http://www.pyminer.com") - - def main_markdown_display(self): - print("TODO 添加markdown编辑器代码") - - def main_new_script_display(self): - from features.extensions.extensionlib.extension_lib import extension_lib - extension_lib.get_interface('code_editor').open_script('') - - def main_community_display(self): - """ - 打开帮助页面 - """ - utils.open_url("https://www.kuxai.com/") - - def main_project_wizard_display(self): - """ - 打开新建项目向导 - """ - self.wizard = project_wizard = base.ProjectWizardForm(parent=self) - project_wizard.exec_() - - def main_about_display(self): - """ - 打开关于页面,并将当前操作系统信息写入页面 - """ - self.about_me = base.AboutForm() - self.about_me.show() - - def closeEvent(self, a0: QCloseEvent) -> None: - """ - 主窗体退出时的事件,包括弹框提示等。Mac 上测试点击无法退出,修改为QMessageBox.Warning - """ - reply = QMessageBox(QMessageBox.Warning, self.tr('Close'), self.tr('Are you sure close?')) - reply.addButton(self.tr('OK'), QMessageBox.ActionRole) - reply.addButton(self.tr('Cancel'), QMessageBox.RejectRole) - if reply.exec_() == QMessageBox.RejectRole: - a0.ignore() - return - else: - a0.accept() - self.delete_temporary_dock_windows() - self.save_layout() # TODO:PySide2上存储布局有问题。 - Settings.get_instance().save() - self.close_signal.emit() - self.extensions_manager.stop() - for k in self.dock_widgets.keys(): - self.dock_widgets[k].widget().closeEvent(a0) - super().closeEvent(a0) - - def slot_flush_console(self, level: str, module, content): - """刷新主窗体执行情况日志 - - Args: - level: 报错级别,包括 ``info`` , ``warnning`` , ``error`` 。 - module: 业务模块名称,例如 数据获取,数据处理,数据探索,统计,模型,可视化,评估 - content: 具体显示的内容 - """ - create_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 日志记录时间 - user = getpass.getuser() - msg = create_time + ' ' + user + ' ' + level.upper() + ' [' + module + ']' + ':' + content - if level == "error": - html = "" + msg + "" - else: - html = "" + msg + "" - console = self.log_output_console # 由于代码重构,这里出现了不同。 - console.moveCursor(QTextCursor.End) - console.append(html) +# class MainWindow(BaseMainWindow): +# setupui_tasks: List[Callable] = [] +# boot_timer: QTimer = None +# close_signal = Signal() +# window_geometry_changed_signal = Signal() +# +# layouts_ready_signal = Signal() +# widgets_ready_signal = Signal() +# events_ready_signal = Signal() +# +# settings_changed_signal = Signal() +# +# @classmethod +# def __new__(cls, *args): +# if not hasattr(cls, 'instance'): +# instance = super().__new__(cls) +# cls.instance = instance +# return cls.instance +# +# def __init__(self, parent=None): +# super().__init__(parent) +# +# t00 = time.time() +# settings = Settings() +# self.main_option_form = base.OptionForm() +# self.project_wizard: base.ProjectWizardForm = None +# self.settings_changed_signal.connect(self.on_settings_changed) +# self.main_option_form.add_page(self.tr('Interpreter'), InterpreterManagerWidget()) +# +# utils._main_window = self +# +# # 主窗体默认大小 +# self.resize(1920, 1080) +# self.setIconSize(QSize(40, 40)) +# # 设置状态栏 +# self.statusBar = QStatusBar() +# version = utils.get_python_version() +# self.statusBar.showMessage(version, 0) +# self.setStatusBar(self.statusBar) +# +# root_dir = os.path.dirname(__file__) +# utils._root_dir = root_dir +# +# self.init_toolbar_tab() +# tb_home = PMToolBarHome() +# self.add_toolbar('toolbar_home', tb_home, text=tb_home.get_toolbar_text()) +# self.setDockNestingEnabled(True) +# self.setWindowTitle('PyMiner') +# +# self.log_output_console = LogOutputConsole(self) +# +# self.add_widget_on_dock( +# 'log_output_console', +# self.log_output_console, +# text=self.tr('Logs'), +# side='right') +# +# # 初始化日志 +# self.slot_flush_console('info', 'system', self.tr('Welcome to PyMiner')) +# +# self.extensions_manager = extensions_manager +# self.extensions_manager.load_from_extension_folder(updateSplashMsg) +# +# self.ext_manager_widget = PMPageExt(self) +# dw = self.add_widget_on_dock( +# 'extension_panel', +# self.ext_manager_widget, +# text=self.tr('Plugs'), +# side='left') +# dw.setMaximumWidth(400) +# +# load_theme(settings['theme']) # 组件都加载后再设置主题,否则可能有些组件不生效 +# self.show() +# self.load_layout() +# self.switch_toolbar('toolbar_home') # 启动完成时,将工具栏切换到‘主页’ +# +# self.on_main_window_shown() +# # self.first_form_display() +# +# self.start_pmlocalserver() # 只要在插件加载完成之后启动就行,目前放在最后 +# self.update_tip_client = UpdateTipClient() # 启动程序,检查更新,弹窗提醒 +# +# t01 = time.time() +# logging.debug('Time Elapsed for loading main window contents: %f' % (t01 - t00)) +# +# def start_pmlocalserver(self): +# """ +# 启动本地flask服务器pmlocalserver +# Returns:None +# +# """ +# server.server_thread.start() +# +# def clear_workspace(self): +# from features.extensions.extensionlib.extension_lib import extension_lib +# extension_lib.get_interface('ipython_console').run_command('Clearing_Variables_ =\'Clear All\'', +# hint_text=self.tr('Start Clear...'), hidden=False) +# extension_lib.get_interface('ipython_console').run_command('get_ipython().clear_all()', +# hint_text=self.tr('Clear all variables'), +# hidden=False) +# +# def add_toolbar(self, name: str, toolbar: PMGToolBar, +# text: str = 'untitled toolbar'): +# """ +# 添加一个工具栏。 +# """ +# if toolbar.insert_after() == '': +# b = self.top_toolbar_tab.add_button(name, text) +# else: +# b = self.top_toolbar_tab.insert_button(name, text, toolbar.insert_after()) +# toolbar.tab_button = b +# b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name)) +# +# if hasattr(self, 'toolbar_path'): +# self.insertToolBar(self.toolbar_path, toolbar) +# self.insertToolBarBreak(self.toolbar_path) +# else: +# self.addToolBarBreak(Qt.TopToolBarArea) +# self.addToolBar(toolbar) +# toolbar.setObjectName(name) +# self.toolbars[name] = toolbar +# toolbar.setMovable(False) +# toolbar.setFloatable(False) +# +# if self._current_toolbar_name != '': +# self.refresh_toolbar_appearance() +# +# # def insert_toolbar(self, name: str, toolbar: QToolBar, text: str, insert_after: str): +# # """ +# # 插入一个工具栏。 +# # """ +# # b = self.top_toolbar_tab.add_button(text) +# # toolbar.tab_button = b +# # b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name)) +# # +# # if hasattr(self, 'toolbar_path'): +# # self.insertToolBar(self.toolbar_path, toolbar) +# # self.insertToolBarBreak(self.toolbar_path) +# # else: +# # self.addToolBarBreak(Qt.TopToolBarArea) +# # self.addToolBar(toolbar) +# # toolbar.setObjectName(name) +# # self.toolbars[name] = toolbar +# # toolbar.setMovable(False) +# # toolbar.setFloatable(False) +# # +# # if self._current_toolbar_name != '': +# # self.refresh_toolbar_appearance() +# +# def moveEvent(self, a0: 'QMoveEvent') -> None: +# self.window_geometry_changed_signal.emit() +# +# def resizeEvent(self, a0: QResizeEvent) -> None: +# """ +# 窗口大小调节,或者位置改变的信号。 +# Window size adjustment, or a signal of a change in position. +# """ +# self.size_restriction_acquire() +# super().resizeEvent(a0) +# self.delayed_call(500, self.size_restriction_release) +# self.window_geometry_changed_signal.emit() +# +# def on_settings_changed(self): +# """ +# 当设置项发生改变时调用 +# Returns: +# +# """ +# load_theme(utils.get_settings_item_from_file("config.ini", "MAIN/THEME")) +# +# def delayed_call(self, time_ms: int, callback: Callable) -> None: +# """ +# 封装了QTimer.SingleShot +# +# Args: +# time_ms: +# callback: +# +# Returns: +# +# """ +# timer = QTimer() +# timer.singleShot(time_ms, callback) +# +# def size_restriction_acquire(self) -> None: +# """ +# 设置插件尺寸的最大值。 +# 控件需要指定get_split_portion_hint才可以。 +# :return: +# """ +# for k in self.dock_widgets.keys(): +# dw = self.dock_widgets[k] +# horizontal_portion_hint = dw.widget().get_split_portion_hint()[0] +# if horizontal_portion_hint is not None: +# dw.setMaximumWidth(int(self.width() * horizontal_portion_hint)) +# dw.setMinimumWidth(int(self.width() * horizontal_portion_hint)) +# +# def size_restriction_release(self): +# for w_name in self.dock_widgets.keys(): +# self.dock_widgets[w_name].setMaximumWidth(100000) +# self.dock_widgets[w_name].setMaximumHeight(100000) +# self.dock_widgets[w_name].setMinimumHeight(0) +# self.dock_widgets[w_name].setMinimumWidth(0) +# +# def on_main_window_shown(self): +# """ +# 在界面显示后触发的事件。 +# Returns: None +# """ +# t0 = time.time() +# super().on_main_window_shown() +# +# self.layouts_ready_signal.emit() +# for task in self.setupui_tasks: +# task() +# self.widgets_ready_signal.emit() +# t1 = time.time() +# logging.info('Layout ready time elapsed:%f' % (t1 - t0)) +# +# self.set_dock_titlebar_visible(Settings.get_instance()['dock_titlebar_visible']) +# self.bind_events() +# self.events_ready_signal.emit() +# t2 = time.time() +# logging.info('Events ready, time elapsed:%f' % (t2 - t1)) +# +# def first_form_display(self): +# """ +# 显示"快速操作"窗口 +# Displays the "Quick Action" window +# """ +# self.main_first_form = base.FirstForm(parent=self) +# self.main_first_form.show() +# +# def login_form_display(self): +# """ +# 显示"登录"窗口 +# Displays the "Quick Action" window +# """ +# shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token +# buff = shared_memo.buf +# token = bytes(buff[:199]).decode().replace("\x00", "") +# if token != "": +# self.main_login_form = base.LoginedForm(parent=self) +# self.main_login_form.exec_() +# else: +# self.main_login_form = base.LoginForm(parent=self) +# self.main_login_form.exec_() +# +# def main_appstore_dispaly(self): +# """ +# 显示"应用商店"窗口 +# Displays the "App Store" window +# """ +# self.appstore = MarketplaceForm() +# self.appstore.show() +# +# def main_option_display(self): +# """ +# 显示"选项"窗口 +# """ +# if self.main_option_form is None: +# self.main_option_form = base.OptionForm() +# self.main_option_form.exec_() +# +# def main_help_display(self): +# """ +# 打开帮助页面 +# """ +# utils.open_url("https://gitee.com/py2cn/pyminer/wikis") +# +# def main_check_update_display(self): +# """ +# 打开'检查更新'页面 +# """ +# perform_update() +# +# def main_install_update(self): +# closed = self.close() +# if closed: +# from pmgwidgets import run_python_file_in_terminal +# path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'update', 'update.py') +# run_python_file_in_terminal(path + ' -i') +# +# def main_feedback_display(self): +# """ +# 打开'反馈'页面 +# """ +# FeedbackClient() +# # reply = QMessageBox.information(self, self.tr('Feedback'), self.tr( +# # 'You can give feedback through issue on suggestions or problems encountered in use'), +# # QMessageBox.Yes | QMessageBox.No, +# # QMessageBox.Yes) +# # if reply == QMessageBox.Yes: +# # utils.open_url("https://gitee.com/py2cn/pyminer/issues") +# +# def main_homesite_display(self): +# """ +# 打开官方网站页面 +# """ +# utils.open_url("http://www.pyminer.com") +# +# def main_markdown_display(self): +# print("TODO 添加markdown编辑器代码") +# +# def main_new_script_display(self): +# from features.extensions.extensionlib.extension_lib import extension_lib +# extension_lib.get_interface('code_editor').open_script('') +# +# def main_community_display(self): +# """ +# 打开帮助页面 +# """ +# utils.open_url("https://www.kuxai.com/") +# +# def main_project_wizard_display(self): +# """ +# 打开新建项目向导 +# """ +# self.wizard = project_wizard = base.ProjectWizardForm(parent=self) +# project_wizard.exec_() +# +# def main_about_display(self): +# """ +# 打开关于页面,并将当前操作系统信息写入页面 +# """ +# self.about_me = base.AboutForm() +# self.about_me.show() +# +# def closeEvent(self, a0: QCloseEvent) -> None: +# """ +# 主窗体退出时的事件,包括弹框提示等。Mac 上测试点击无法退出,修改为QMessageBox.Warning +# """ +# reply = QMessageBox(QMessageBox.Warning, self.tr('Close'), self.tr('Are you sure close?')) +# reply.addButton(self.tr('OK'), QMessageBox.ActionRole) +# reply.addButton(self.tr('Cancel'), QMessageBox.RejectRole) +# if reply.exec_() == QMessageBox.RejectRole: +# a0.ignore() +# return +# else: +# a0.accept() +# self.delete_temporary_dock_windows() +# self.save_layout() # TODO:PySide2上存储布局有问题。 +# Settings.get_instance().save() +# self.close_signal.emit() +# self.extensions_manager.stop() +# for k in self.dock_widgets.keys(): +# self.dock_widgets[k].widget().closeEvent(a0) +# super().closeEvent(a0) +# +# def slot_flush_console(self, level: str, module, content): +# """刷新主窗体执行情况日志 +# +# Args: +# level: 报错级别,包括 ``info`` , ``warnning`` , ``error`` 。 +# module: 业务模块名称,例如 数据获取,数据处理,数据探索,统计,模型,可视化,评估 +# content: 具体显示的内容 +# """ +# create_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 日志记录时间 +# user = getpass.getuser() +# msg = create_time + ' ' + user + ' ' + level.upper() + ' [' + module + ']' + ':' + content +# if level == "error": +# html = "" + msg + "" +# else: +# html = "" + msg + "" +# +# console = self.log_output_console # 由于代码重构,这里出现了不同。 +# console.moveCursor(QTextCursor.End) +# console.append(html) diff --git a/resources/qss/Fusion.qss b/resources/qss/Fusion.qss index f4d798d8..9b4ebb6c 100644 --- a/resources/qss/Fusion.qss +++ b/resources/qss/Fusion.qss @@ -15,10 +15,10 @@ QDockWidget::title{ } QPushButton{ - background-color: MAIN_THEME; + background-color: #F7F7F7; } QPushButton:hover{ - background-color:MARGIN_THEME; + background-color:#DADADA; } QPushButton#pmtopToolbarButton[stat="unselected"]:hover{ @@ -29,7 +29,7 @@ QPushButton#pmtopToolbarButton[stat="selected"]{ margin: 5px 5px -5px 5px; min-width: 120px; border-radius:5px; - background-color: MAIN_THEME; + background-color: #F7F7F7; } QPushButton#pmtopToolbarButton[stat="unselected"]{ padding: 5px 0px 10px 0px; @@ -66,10 +66,10 @@ QToolButton{ border-radius:5px; } QToolButton:hover{ - background-color:MARGIN_THEME; + background-color:#DADADA; } QToolButton::checked{ - background-color:MARGIN_THEME; + background-color:#DADADA; } QToolButton#hidebutton { max-width: 15px; @@ -110,14 +110,14 @@ QToolButton#stacked_tool_button::menu-indicator:image{ /*以下几行设定的是滚动条的横竖向功能*/ QScrollBar::vertical { - background: MARGIN_THEME; + background: #DADADA; border: -0px solid grey; margin: 0px 0px 0px 0px; width: 10px; border-radius:5px; } QScrollBar::horizontal { - background: MARGIN_THEME; + background: #DADADA; border: -0px solid grey; margin: 0px 0px 0px 0px; height:10px; @@ -127,17 +127,17 @@ QScrollBar::horizontal { QScrollBar::handle:vertical{ border-radius:3px; min-height:30px; -background:MARGIN_THEME; +background:#DADADA; } QScrollBar::handle:horizontal{ border-radius:3px; min-width:30px; -background:MARGIN_THEME; +background:#DADADA; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { - background: MAIN_THEME; + background: #F7F7F7; border:0px; } diff --git a/resources/qss/standard.qss b/resources/qss/standard.qss index b2e7ad2a..cb948716 100644 --- a/resources/qss/standard.qss +++ b/resources/qss/standard.qss @@ -5,20 +5,20 @@ github链接: https://github.com/PyQt5/PyQt/blob/master/QScrollArea/Data/style.qss 文件加载时,将会自动替换MAIN_THEME和MARGIN_THEME为相应的颜色。 */ -QMainWindow{background-color:MAIN_THEME;} -QDialog{background-color:MAIN_THEME;} +QMainWindow{background-color:#F7F7F7;} +QDialog{background-color:#F7F7F7;} QAbstractScrollArea{ - border:1px solid MARGIN_THEME; + border:1px solid #DADADA; } TopToolBar { - border-bottom: 1px solid MARGIN_THEME; - border-top: 1px solid MARGIN_THEME; + border-bottom: 1px solid #DADADA; + border-top: 1px solid #DADADA; } TopToolBarRight { - border-bottom: 1px solid MARGIN_THEME; - border-top: 1px solid MARGIN_THEME; + border-bottom: 1px solid #DADADA; + border-top: 1px solid #DADADA; } QDockWidget { @@ -49,12 +49,12 @@ QDockWidget::close-button:pressed, QDockWidget::float-button:pressed { } QPushButton{ - border:1px solid MARGIN_THEME; + border:1px solid #DADADA; border-radius:5px; height:20px; width:80px; } -QPushButton:hover{background-color:MARGIN_THEME;} +QPushButton:hover{background-color:#DADADA;} /*按钮停留态*/ QPushButton#pmtopToolbarButton[stat="selected"]{ /*背景颜色*/ @@ -62,7 +62,7 @@ QPushButton#pmtopToolbarButton[stat="selected"]{ padding:0px 0px 0px 0px; border:1px; border-radius:8px; - background-color:MARGIN_THEME; + background-color:#DADADA; } QPushButton#pmtopToolbarButton[stat="unselected"]{ @@ -71,7 +71,7 @@ QPushButton#pmtopToolbarButton[stat="unselected"]{ padding:0px 0px 0px 0px; border:1px; border-radius:8px; - background-color:MAIN_THEME; + background-color:#F7F7F7; } QPushButton#pmtopToolbarButton:hover{ @@ -86,7 +86,7 @@ QPushButton#pmtopToolbarButton:hover{ QPushButton:hover { /*背景颜色*/ - background-color:MARGIN_THEME; + background-color:#DADADA; } QToolBar{ height:100px; @@ -104,7 +104,7 @@ QToolButton{ QToolButton:hover { /*背景颜色*/ - background-color:MARGIN_THEME; + background-color:#DADADA; } /*toolbutton下三角居中靠下显示*/ QToolButton::menu-indicator:image{ @@ -115,14 +115,14 @@ QToolButton::menu-indicator:image{ QScrollBar::vertical { - background: MARGIN_THEME; + background: #DADADA; border: -0px solid grey; margin: 0px 0px 0px 0px; width: 10px; border-radius:5px; } QScrollBar::horizontal { - background: MARGIN_THEME; + background: #DADADA; margin: 0px 0px 0px 0px; height:10px; @@ -130,16 +130,16 @@ QScrollBar::horizontal { QScrollBar::handle:vertical{ border-radius:3px; -background:MARGIN_THEME; +background:#DADADA; } QScrollBar::handle:horizontal{ border-radius:3px; -background:MARGIN_THEME; +background:#DADADA; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { - background: MAIN_THEME; + background: #F7F7F7; border:0px; } QMessageBox QPushButton[text="OK"] { diff --git a/resources/qss/windowsvista.qss b/resources/qss/windowsvista.qss index 5c87512e..dc95f29a 100644 --- a/resources/qss/windowsvista.qss +++ b/resources/qss/windowsvista.qss @@ -53,7 +53,7 @@ QToolButton{ border-radius:5px; } QToolButton:hover{ - background-color:MARGIN_THEME; + background-color: #DADADA; } QToolButton#hidebutton { max-width: 15px; diff --git a/utils/__init__.py b/utils/__init__.py index 47fefc0f..e70f3f75 100644 --- a/utils/__init__.py +++ b/utils/__init__.py @@ -35,15 +35,16 @@ from .settings import * from .ui import * if TYPE_CHECKING: - import pmgui + import app2 + from PySide2.QtWidgets import QApplication # version = 'v2.1.0 Beta' 这里原有version ,但是考虑到这些信息写在静态文件中较好,所以就写在了文件中。 -_application = None +_application = Optional["QApplication"] _root_dir = None -_main_window: Optional["pmgui.MainWindow"] = None +_main_window: Optional["app2.MainWindow"] = None -def get_application() -> None: +def get_application() -> "QApplication": """ 获取QApplication Returns: @@ -53,7 +54,7 @@ def get_application() -> None: return _application -def get_main_window() -> Optional["pmgui.MainWindow"]: +def get_main_window() -> Optional["app2.MainWindow"]: """ 获取主窗口或者主控件。 Returns: @@ -66,8 +67,7 @@ def get_work_dir() -> 'str': 获取主窗口或者主控件。 Returns: """ - from features.io.settings import Settings - return Settings.get_instance()['work_dir'] + return get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR") def open_url(url): diff --git a/utils/settings/settings.py b/utils/settings/settings.py index ceb1a2a1..6ededd52 100644 --- a/utils/settings/settings.py +++ b/utils/settings/settings.py @@ -51,7 +51,7 @@ def get_settings_item_from_file(file_name: str, item: str, mode="user") -> Any: val = QSettings(default_cfg_file_path, QSettings.IniFormat).value(item) else: val = QSettings(default_cfg_file_path, QSettings.IniFormat).value(item) - assert val is not None, (default_cfg_file_path, item) + assert val is not None, (default_cfg_file_path, item, mode) try: val = ast.literal_eval(val) except: -- Gitee From d30b0ec9f5a08f61cc59e5d57e6998e3afe6cb97 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Sun, 25 Apr 2021 14:43:09 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E4=BD=BF=E7=94=A8QSettings=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=EF=BC=8C=E4=BD=86=E6=98=AF=E7=9B=AE=E5=89=8D=E8=BF=98?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E5=81=9A=E5=92=8C=E4=B9=8B=E5=89=8D=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E7=9A=84=E9=80=82=E9=85=8D=E5=B7=A5=E4=BD=9C=EF=BC=8C?= =?UTF-8?q?=E8=B7=AF=E5=BE=84=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD=E6=9A=82?= =?UTF-8?q?=E6=97=B6=E6=B2=A1=E6=9C=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pmgui.py | 392 +------------------------------------------------------ 1 file changed, 2 insertions(+), 390 deletions(-) diff --git a/pmgui.py b/pmgui.py index f83fc3bd..7e425da5 100644 --- a/pmgui.py +++ b/pmgui.py @@ -1,24 +1,6 @@ -import datetime -import getpass -import logging -import os -import time -from multiprocessing import shared_memory -from typing import List, Callable +from PySide2.QtCore import Qt +from PySide2.QtWidgets import QTextEdit -from PySide2.QtCore import Signal, QTimer, Qt, QSize -from PySide2.QtGui import QCloseEvent, QTextCursor, QResizeEvent, QMoveEvent -from PySide2.QtWidgets import QTextEdit, QMessageBox, QStatusBar - -import utils -from features.extensions.extensions_manager.manager import extensions_manager -from features.feedback import FeedbackClient -from features.interpretermanager.interpretermanager import InterpreterManagerWidget -from features.io.settings import load_theme -from features.main_window import base -from features.ui.pmwidgets import BaseMainWindow -from features.ui.widgets.controlpanel import PMPageExt -from features.util.update import perform_update, UpdateTipClient from pmgwidgets import PMGToolBar, ActionWithMessage, PMDockObject, create_icon from utils import get_main_window, get_application @@ -168,373 +150,3 @@ class PMToolBarHome(PMGToolBar): class LogOutputConsole(QTextEdit, PMDockObject): pass - - -# class MainWindow(BaseMainWindow): -# setupui_tasks: List[Callable] = [] -# boot_timer: QTimer = None -# close_signal = Signal() -# window_geometry_changed_signal = Signal() -# -# layouts_ready_signal = Signal() -# widgets_ready_signal = Signal() -# events_ready_signal = Signal() -# -# settings_changed_signal = Signal() -# -# @classmethod -# def __new__(cls, *args): -# if not hasattr(cls, 'instance'): -# instance = super().__new__(cls) -# cls.instance = instance -# return cls.instance -# -# def __init__(self, parent=None): -# super().__init__(parent) -# -# t00 = time.time() -# settings = Settings() -# self.main_option_form = base.OptionForm() -# self.project_wizard: base.ProjectWizardForm = None -# self.settings_changed_signal.connect(self.on_settings_changed) -# self.main_option_form.add_page(self.tr('Interpreter'), InterpreterManagerWidget()) -# -# utils._main_window = self -# -# # 主窗体默认大小 -# self.resize(1920, 1080) -# self.setIconSize(QSize(40, 40)) -# # 设置状态栏 -# self.statusBar = QStatusBar() -# version = utils.get_python_version() -# self.statusBar.showMessage(version, 0) -# self.setStatusBar(self.statusBar) -# -# root_dir = os.path.dirname(__file__) -# utils._root_dir = root_dir -# -# self.init_toolbar_tab() -# tb_home = PMToolBarHome() -# self.add_toolbar('toolbar_home', tb_home, text=tb_home.get_toolbar_text()) -# self.setDockNestingEnabled(True) -# self.setWindowTitle('PyMiner') -# -# self.log_output_console = LogOutputConsole(self) -# -# self.add_widget_on_dock( -# 'log_output_console', -# self.log_output_console, -# text=self.tr('Logs'), -# side='right') -# -# # 初始化日志 -# self.slot_flush_console('info', 'system', self.tr('Welcome to PyMiner')) -# -# self.extensions_manager = extensions_manager -# self.extensions_manager.load_from_extension_folder(updateSplashMsg) -# -# self.ext_manager_widget = PMPageExt(self) -# dw = self.add_widget_on_dock( -# 'extension_panel', -# self.ext_manager_widget, -# text=self.tr('Plugs'), -# side='left') -# dw.setMaximumWidth(400) -# -# load_theme(settings['theme']) # 组件都加载后再设置主题,否则可能有些组件不生效 -# self.show() -# self.load_layout() -# self.switch_toolbar('toolbar_home') # 启动完成时,将工具栏切换到‘主页’ -# -# self.on_main_window_shown() -# # self.first_form_display() -# -# self.start_pmlocalserver() # 只要在插件加载完成之后启动就行,目前放在最后 -# self.update_tip_client = UpdateTipClient() # 启动程序,检查更新,弹窗提醒 -# -# t01 = time.time() -# logging.debug('Time Elapsed for loading main window contents: %f' % (t01 - t00)) -# -# def start_pmlocalserver(self): -# """ -# 启动本地flask服务器pmlocalserver -# Returns:None -# -# """ -# server.server_thread.start() -# -# def clear_workspace(self): -# from features.extensions.extensionlib.extension_lib import extension_lib -# extension_lib.get_interface('ipython_console').run_command('Clearing_Variables_ =\'Clear All\'', -# hint_text=self.tr('Start Clear...'), hidden=False) -# extension_lib.get_interface('ipython_console').run_command('get_ipython().clear_all()', -# hint_text=self.tr('Clear all variables'), -# hidden=False) -# -# def add_toolbar(self, name: str, toolbar: PMGToolBar, -# text: str = 'untitled toolbar'): -# """ -# 添加一个工具栏。 -# """ -# if toolbar.insert_after() == '': -# b = self.top_toolbar_tab.add_button(name, text) -# else: -# b = self.top_toolbar_tab.insert_button(name, text, toolbar.insert_after()) -# toolbar.tab_button = b -# b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name)) -# -# if hasattr(self, 'toolbar_path'): -# self.insertToolBar(self.toolbar_path, toolbar) -# self.insertToolBarBreak(self.toolbar_path) -# else: -# self.addToolBarBreak(Qt.TopToolBarArea) -# self.addToolBar(toolbar) -# toolbar.setObjectName(name) -# self.toolbars[name] = toolbar -# toolbar.setMovable(False) -# toolbar.setFloatable(False) -# -# if self._current_toolbar_name != '': -# self.refresh_toolbar_appearance() -# -# # def insert_toolbar(self, name: str, toolbar: QToolBar, text: str, insert_after: str): -# # """ -# # 插入一个工具栏。 -# # """ -# # b = self.top_toolbar_tab.add_button(text) -# # toolbar.tab_button = b -# # b.clicked.connect(lambda: self.on_toolbar_switch_button_clicked(name)) -# # -# # if hasattr(self, 'toolbar_path'): -# # self.insertToolBar(self.toolbar_path, toolbar) -# # self.insertToolBarBreak(self.toolbar_path) -# # else: -# # self.addToolBarBreak(Qt.TopToolBarArea) -# # self.addToolBar(toolbar) -# # toolbar.setObjectName(name) -# # self.toolbars[name] = toolbar -# # toolbar.setMovable(False) -# # toolbar.setFloatable(False) -# # -# # if self._current_toolbar_name != '': -# # self.refresh_toolbar_appearance() -# -# def moveEvent(self, a0: 'QMoveEvent') -> None: -# self.window_geometry_changed_signal.emit() -# -# def resizeEvent(self, a0: QResizeEvent) -> None: -# """ -# 窗口大小调节,或者位置改变的信号。 -# Window size adjustment, or a signal of a change in position. -# """ -# self.size_restriction_acquire() -# super().resizeEvent(a0) -# self.delayed_call(500, self.size_restriction_release) -# self.window_geometry_changed_signal.emit() -# -# def on_settings_changed(self): -# """ -# 当设置项发生改变时调用 -# Returns: -# -# """ -# load_theme(utils.get_settings_item_from_file("config.ini", "MAIN/THEME")) -# -# def delayed_call(self, time_ms: int, callback: Callable) -> None: -# """ -# 封装了QTimer.SingleShot -# -# Args: -# time_ms: -# callback: -# -# Returns: -# -# """ -# timer = QTimer() -# timer.singleShot(time_ms, callback) -# -# def size_restriction_acquire(self) -> None: -# """ -# 设置插件尺寸的最大值。 -# 控件需要指定get_split_portion_hint才可以。 -# :return: -# """ -# for k in self.dock_widgets.keys(): -# dw = self.dock_widgets[k] -# horizontal_portion_hint = dw.widget().get_split_portion_hint()[0] -# if horizontal_portion_hint is not None: -# dw.setMaximumWidth(int(self.width() * horizontal_portion_hint)) -# dw.setMinimumWidth(int(self.width() * horizontal_portion_hint)) -# -# def size_restriction_release(self): -# for w_name in self.dock_widgets.keys(): -# self.dock_widgets[w_name].setMaximumWidth(100000) -# self.dock_widgets[w_name].setMaximumHeight(100000) -# self.dock_widgets[w_name].setMinimumHeight(0) -# self.dock_widgets[w_name].setMinimumWidth(0) -# -# def on_main_window_shown(self): -# """ -# 在界面显示后触发的事件。 -# Returns: None -# """ -# t0 = time.time() -# super().on_main_window_shown() -# -# self.layouts_ready_signal.emit() -# for task in self.setupui_tasks: -# task() -# self.widgets_ready_signal.emit() -# t1 = time.time() -# logging.info('Layout ready time elapsed:%f' % (t1 - t0)) -# -# self.set_dock_titlebar_visible(Settings.get_instance()['dock_titlebar_visible']) -# self.bind_events() -# self.events_ready_signal.emit() -# t2 = time.time() -# logging.info('Events ready, time elapsed:%f' % (t2 - t1)) -# -# def first_form_display(self): -# """ -# 显示"快速操作"窗口 -# Displays the "Quick Action" window -# """ -# self.main_first_form = base.FirstForm(parent=self) -# self.main_first_form.show() -# -# def login_form_display(self): -# """ -# 显示"登录"窗口 -# Displays the "Quick Action" window -# """ -# shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token -# buff = shared_memo.buf -# token = bytes(buff[:199]).decode().replace("\x00", "") -# if token != "": -# self.main_login_form = base.LoginedForm(parent=self) -# self.main_login_form.exec_() -# else: -# self.main_login_form = base.LoginForm(parent=self) -# self.main_login_form.exec_() -# -# def main_appstore_dispaly(self): -# """ -# 显示"应用商店"窗口 -# Displays the "App Store" window -# """ -# self.appstore = MarketplaceForm() -# self.appstore.show() -# -# def main_option_display(self): -# """ -# 显示"选项"窗口 -# """ -# if self.main_option_form is None: -# self.main_option_form = base.OptionForm() -# self.main_option_form.exec_() -# -# def main_help_display(self): -# """ -# 打开帮助页面 -# """ -# utils.open_url("https://gitee.com/py2cn/pyminer/wikis") -# -# def main_check_update_display(self): -# """ -# 打开'检查更新'页面 -# """ -# perform_update() -# -# def main_install_update(self): -# closed = self.close() -# if closed: -# from pmgwidgets import run_python_file_in_terminal -# path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'update', 'update.py') -# run_python_file_in_terminal(path + ' -i') -# -# def main_feedback_display(self): -# """ -# 打开'反馈'页面 -# """ -# FeedbackClient() -# # reply = QMessageBox.information(self, self.tr('Feedback'), self.tr( -# # 'You can give feedback through issue on suggestions or problems encountered in use'), -# # QMessageBox.Yes | QMessageBox.No, -# # QMessageBox.Yes) -# # if reply == QMessageBox.Yes: -# # utils.open_url("https://gitee.com/py2cn/pyminer/issues") -# -# def main_homesite_display(self): -# """ -# 打开官方网站页面 -# """ -# utils.open_url("http://www.pyminer.com") -# -# def main_markdown_display(self): -# print("TODO 添加markdown编辑器代码") -# -# def main_new_script_display(self): -# from features.extensions.extensionlib.extension_lib import extension_lib -# extension_lib.get_interface('code_editor').open_script('') -# -# def main_community_display(self): -# """ -# 打开帮助页面 -# """ -# utils.open_url("https://www.kuxai.com/") -# -# def main_project_wizard_display(self): -# """ -# 打开新建项目向导 -# """ -# self.wizard = project_wizard = base.ProjectWizardForm(parent=self) -# project_wizard.exec_() -# -# def main_about_display(self): -# """ -# 打开关于页面,并将当前操作系统信息写入页面 -# """ -# self.about_me = base.AboutForm() -# self.about_me.show() -# -# def closeEvent(self, a0: QCloseEvent) -> None: -# """ -# 主窗体退出时的事件,包括弹框提示等。Mac 上测试点击无法退出,修改为QMessageBox.Warning -# """ -# reply = QMessageBox(QMessageBox.Warning, self.tr('Close'), self.tr('Are you sure close?')) -# reply.addButton(self.tr('OK'), QMessageBox.ActionRole) -# reply.addButton(self.tr('Cancel'), QMessageBox.RejectRole) -# if reply.exec_() == QMessageBox.RejectRole: -# a0.ignore() -# return -# else: -# a0.accept() -# self.delete_temporary_dock_windows() -# self.save_layout() # TODO:PySide2上存储布局有问题。 -# Settings.get_instance().save() -# self.close_signal.emit() -# self.extensions_manager.stop() -# for k in self.dock_widgets.keys(): -# self.dock_widgets[k].widget().closeEvent(a0) -# super().closeEvent(a0) -# -# def slot_flush_console(self, level: str, module, content): -# """刷新主窗体执行情况日志 -# -# Args: -# level: 报错级别,包括 ``info`` , ``warnning`` , ``error`` 。 -# module: 业务模块名称,例如 数据获取,数据处理,数据探索,统计,模型,可视化,评估 -# content: 具体显示的内容 -# """ -# create_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 日志记录时间 -# user = getpass.getuser() -# msg = create_time + ' ' + user + ' ' + level.upper() + ' [' + module + ']' + ':' + content -# if level == "error": -# html = "" + msg + "" -# else: -# html = "" + msg + "" -# -# console = self.log_output_console # 由于代码重构,这里出现了不同。 -# console.moveCursor(QTextCursor.End) -# console.append(html) -- Gitee From e5b4a8b9a37dd6aa976dc5df560262e967e30128 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Sun, 25 Apr 2021 15:42:00 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extensions/extensionlib/extension_lib.py | 2 + packages/ipython_console/initialize.py | 51 +----------- packages/socket_server/server_by_socket.py | 81 +++++++++++-------- pyminer_comm/pyminer_client/pm_client.py | 2 +- 4 files changed, 53 insertions(+), 83 deletions(-) diff --git a/features/extensions/extensionlib/extension_lib.py b/features/extensions/extensionlib/extension_lib.py index 60b96ed6..90126d73 100644 --- a/features/extensions/extensionlib/extension_lib.py +++ b/features/extensions/extensionlib/extension_lib.py @@ -314,7 +314,9 @@ def wrapper(): dir = utils.get_settings_item_from_file("config.ini", "MAIN/PATH_WORKDIR") if (not isinstance(dir, str)) or (not os.path.exists(dir)): dir = os.path.join(os.path.expanduser("~"), "Desktop") + utils.write_settings_item_to_file("config.ini", "MAIN/PATH_WORKDIR", dir) return dir + @staticmethod def get_theme() -> str: """ diff --git a/packages/ipython_console/initialize.py b/packages/ipython_console/initialize.py index 700d646b..433382e4 100644 --- a/packages/ipython_console/initialize.py +++ b/packages/ipython_console/initialize.py @@ -380,59 +380,16 @@ def __cell_exec_func(raw_cell, store_history=False, silent=False, shell_futures= Returns: """ - import ast __ip = get_ipython() __cwd = os.getcwd() - class PyMinerIPyConsoleNodeTransformer(ast.NodeTransformer): - def __init__(self): - super(PyMinerIPyConsoleNodeTransformer, self).__init__() - self.identifier_list = [] - self.str_list = [] - - def visit_Name(self, node: ast.Name): - """ - - Args: - node: - - Returns: - - """ - self.identifier_list.append(node.id) - - def visit_Str(self, node: ast.Str): - """ - - Args: - node: - - Returns: - - """ - self.str_list.append(node.s) - - def show_identifiers_might_changed(self, code): - """ - - Args: - code: - - Returns: - - """ - self.identifier_list = [] - self.str_list = [] - self.visit(ast.parse(code)) - return [s for s in list(set(self.identifier_list + self.str_list)) if s.isidentifier()] - - s = get_ipython().original_run_cell_func(raw_cell, store_history=store_history, silent=silent, - shell_futures=shell_futures) + __ret = get_ipython().original_run_cell_func(raw_cell, store_history=store_history, silent=silent, + shell_futures=shell_futures) __ip.var_name_list = list(__ip.filter_vars(globals()).keys()) __ip.update_workspace() if __cwd != os.getcwd(): - modify_settings({'work_dir': os.getcwd()}) - return s + modify_settings({'MAIN/PATH_WORKDIR': os.getcwd()}) + return __ret def __chdir(path: str): diff --git a/packages/socket_server/server_by_socket.py b/packages/socket_server/server_by_socket.py index 65e801b1..9975e4f2 100644 --- a/packages/socket_server/server_by_socket.py +++ b/packages/socket_server/server_by_socket.py @@ -1,14 +1,13 @@ import json import logging +import queue import sys -import time -from typing import Dict, Any, List, Tuple +import threading +from typing import Dict, Any -import cloudpickle +from PySide2.QtCore import Signal, QObject, QThread from PySide2.QtWidgets import QApplication -from PySide2.QtCore import Signal, QTimer, QObject, QThread -import threading -import queue + from pyminer_comm.base import b64_to_dict, dict_to_b64, DataDesc, get_protocol logger = logging.getLogger(__name__) @@ -18,17 +17,10 @@ INTERFACE_CALLED = 3 from flask import Flask, request app = Flask(__name__) -worker: 'LoopWork' = None message_queue: queue.Queue = queue.Queue() extension_lib = None -@app.route('/get_data_desc') -def hello_world(): - global message_queue - return 'Hello World!' - - @app.route('/modify_settings') def modify_settings(): global message_queue @@ -57,17 +49,26 @@ def get_settings(): """ global message_queue return "['Warning this method was deprecated']" - # return json.dumps(extension_lib.Program.get_settings()) @app.route('/get_stylesheet') def get_stylesheet(): + """ + 获取QApplication的样式表 + Returns: + + """ assert QApplication.instance() is not None return QApplication.instance().styleSheet() @app.route('/set_data') def modify_data_descs(): + """ + 将工作空间中设置为data_desc型变量 + Returns: + + """ global message_queue try: datadesc_dict = b64_to_dict(request.args.get('msg')) @@ -84,6 +85,11 @@ def modify_data_descs(): @app.route('/interface_call') def run_command(): + """ + 运行命令,调用接口函数。 + Returns: + + """ global message_queue try: settings = request.args.get('msg') @@ -103,16 +109,6 @@ def run_command(): return "Failed!" -class LoopWork(QObject): - def __init__(self, server_obj: 'Flask'): - super().__init__() - self.server_obj = server_obj - self.threads = [] - - def work(self): - app.run(port=12306) - - class QueueWork(QObject): signal_queue_recv = Signal(object) @@ -150,10 +146,9 @@ class PMGServer(QObject): def __init__(self, parent=None): super().__init__(parent) - global worker self.queue_loop_thread = QThread() - self.queue_worker = QueueWork() + self.queue_worker = QueueWork() # 队列处理 self.queue_worker.moveToThread(self.queue_loop_thread) @@ -173,8 +168,11 @@ class PMGServer(QObject): def on_recv(self, msg: object): """ - :param msg: - :return: + Args: + msg: 收到的信息 + + Returns: + """ if msg[0] == DATA_CHANGED: self.signal_data_set.emit(msg[1]) @@ -182,8 +180,18 @@ class PMGServer(QObject): self.signal_settings_changed.emit(msg[1]) elif msg[0] == INTERFACE_CALLED: self.signal_interface_called.emit(msg[1]['interface'], msg[1]['method'], msg[1]['kwargs'], msg[2]) + else: + logger.error("received error:" + repr(object)) def on_data_set(self, data: Dict[str, Any]): + """ + 当数据设置时的回调 + Args: + data: + + Returns: + + """ names = self.extension_lib.Data.get_all_variable_names() for name in names: if name not in data.keys(): @@ -193,13 +201,16 @@ class PMGServer(QObject): def on_settings_changed(self, settings: Dict[str, Any]): """ - 改变设置 - :param settings - :return: + 改变设置时的回调 + Args: + settings: + + Returns: + """ - logger.warning("目前服务器on_settings_changed方法无效!") - raise DeprecationWarning - # self.extension_lib.Program.update_settings(settings) + for k, v in settings.items(): + self.extension_lib.Program.write_settings_item_to_file("config.ini", k, v) + self.extension_lib.Signal.get_settings_changed_signal().emit() def on_interface_called(self, interface_name: str, method_name: str, kwargs: Dict, res_queue: queue.Queue): interface = self.extension_lib.get_interface(interface_name) @@ -221,7 +232,7 @@ def run_server(port: int = None, ext_lib=None): extension_lib = ext_lib server = PMGServer() - server_thread = threading.Thread(target=app.run, kwargs={'port': 12306}) + server_thread = threading.Thread(target=app.run, kwargs={'port': port}) server_thread.setDaemon(True) server_thread.start() diff --git a/pyminer_comm/pyminer_client/pm_client.py b/pyminer_comm/pyminer_client/pm_client.py index 12c259dc..a16f941b 100644 --- a/pyminer_comm/pyminer_client/pm_client.py +++ b/pyminer_comm/pyminer_client/pm_client.py @@ -21,7 +21,7 @@ def modify_settings(items: Dict[str, Any]): """ assert isinstance(items, dict), items res = get('modify_settings', dict_to_b64(items, protocol=get_protocol()), 12306, ) - + return res def set_data_desc_dic(data: Dict[str, Any]) -> None: for k, v in data.items(): -- Gitee From 7e05adc4fae4947735cb40ea82782c462c02e585 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Sun, 25 Apr 2021 16:02:01 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/socket_server/main.py | 56 +++++++++++----------- packages/socket_server/server_by_socket.py | 47 +++++++++--------- pyminer_comm/base/network.py | 6 ++- 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/packages/socket_server/main.py b/packages/socket_server/main.py index 1915fb61..f20b1d22 100644 --- a/packages/socket_server/main.py +++ b/packages/socket_server/main.py @@ -1,11 +1,11 @@ import inspect import logging -from typing import Callable +from typing import Callable, Optional from flask import Flask from features.extensions.extensionlib import BaseExtension, BaseInterface -from .server_by_socket import run, app +from .server_by_socket import run, server logger = logging.getLogger(__name__) @@ -13,8 +13,8 @@ logger = logging.getLogger(__name__) class Extension(BaseExtension): def on_load(self): run(self.extension_lib) - self.interface.app = app - self.interface.extension_lib = self.extension_lib + # self.interface.app = server + # self.interface.extension_lib = self.extension_lib logger.debug(self.settings) @@ -22,27 +22,27 @@ class Interface(BaseInterface): extension_lib = None def __init__(self): - self.app: Flask = None - - def add_handler(self, rule, callback: Callable[[], str]): - """ - rule:比如‘/’ - - :param rule: - :param callback: - :return: - """ - if not isinstance(rule, str): - raise TypeError( - 'Rule argument should be str,but your argument was %s, type %s' % (repr(rule), str(type(rule)))) - if not len(list(inspect.signature(callback).parameters.keys())) == 0: - raise ValueError('Callback function should not have any arguments!') - try: - self.app.add_url_rule(rule, callback.__name__, callback) - except AssertionError as e: - if "overwriting an existing endpoint function" in repr(e): - desc = 'Problem happened when trying register function {func} with rule {rule}'.format( - func=callback, rule=rule) - logger.error(desc) - raise e - # self.extension_lib.Program.show_exception_occured_panel(e, solution='') + self.app: Optional[Flask] = None +# +# def add_handler(self, rule, callback: Callable[[], str]): +# """ +# rule:比如‘/’ +# +# :param rule: +# :param callback: +# :return: +# """ +# if not isinstance(rule, str): +# raise TypeError( +# 'Rule argument should be str,but your argument was %s, type %s' % (repr(rule), str(type(rule)))) +# if not len(list(inspect.signature(callback).parameters.keys())) == 0: +# raise ValueError('Callback function should not have any arguments!') +# try: +# self.app.add_url_rule(rule, callback.__name__, callback) +# except AssertionError as e: +# if "overwriting an existing endpoint function" in repr(e): +# desc = 'Problem happened when trying register function {func} with rule {rule}'.format( +# func=callback, rule=rule) +# logger.error(desc) +# raise e +# # self.extension_lib.Program.show_exception_occured_panel(e, solution='') diff --git a/packages/socket_server/server_by_socket.py b/packages/socket_server/server_by_socket.py index 9975e4f2..62bbf8cb 100644 --- a/packages/socket_server/server_by_socket.py +++ b/packages/socket_server/server_by_socket.py @@ -2,8 +2,7 @@ import json import logging import queue import sys -import threading -from typing import Dict, Any +from typing import Dict, Any, Optional from PySide2.QtCore import Signal, QObject, QThread from PySide2.QtWidgets import QApplication @@ -14,14 +13,17 @@ logger = logging.getLogger(__name__) DATA_CHANGED = 1 SETTINGS_CHANGED = 2 INTERFACE_CALLED = 3 -from flask import Flask, request +from flask import request -app = Flask(__name__) +from pmlocalserver.server import server as _server + +server = _server +pmg_server: Optional['PMGServer'] = None message_queue: queue.Queue = queue.Queue() extension_lib = None -@app.route('/modify_settings') +@server.route('/modify_settings') def modify_settings(): global message_queue try: @@ -35,13 +37,13 @@ def modify_settings(): return "Failed!" -@app.route('/get_python_version_info') +@server.route('/get_python_version_info') def get_python_version_info(): info = sys.version_info return json.dumps([info.major, info.minor, info.micro]) -@app.route('/get_settings') +@server.route('/get_settings') def get_settings(): """ 获取设置 @@ -51,7 +53,7 @@ def get_settings(): return "['Warning this method was deprecated']" -@app.route('/get_stylesheet') +@server.route('/get_stylesheet') def get_stylesheet(): """ 获取QApplication的样式表 @@ -62,7 +64,7 @@ def get_stylesheet(): return QApplication.instance().styleSheet() -@app.route('/set_data') +@server.route('/set_data') def modify_data_descs(): """ 将工作空间中设置为data_desc型变量 @@ -83,7 +85,7 @@ def modify_data_descs(): return json.dumps({'status': 'failed', 'error': str(e)}) -@app.route('/interface_call') +@server.route('/interface_call') def run_command(): """ 运行命令,调用接口函数。 @@ -124,6 +126,7 @@ class QueueWork(QObject): break try: item = message_queue.get(timeout=0.05) + self.signal_queue_recv.emit(item) except queue.Empty: pass @@ -227,22 +230,20 @@ class PMGServer(QObject): self.queue_loop_thread.wait(500) -def run_server(port: int = None, ext_lib=None): - global server, server_thread, extension_lib +def run_server(ext_lib=None): + global server, server_thread, extension_lib, pmg_server extension_lib = ext_lib - server = PMGServer() - - server_thread = threading.Thread(target=app.run, kwargs={'port': port}) - server_thread.setDaemon(True) - server_thread.start() - - return server + pmg_server = PMGServer() + return pmg_server + # server_thread = threading.Thread(target=server.run, kwargs={'port': port}) + # server_thread.setDaemon(True) + # server_thread.start() -def run(extension_lib) -> Flask: - server = run_server(12306, extension_lib) - server.set_extension_lib(extension_lib) - return server +def run(extension_lib) -> PMGServer: + s = run_server(extension_lib) + s.set_extension_lib(extension_lib) + return s if __name__ == "__main__": diff --git a/pyminer_comm/base/network.py b/pyminer_comm/base/network.py index e92d1cf0..8b9b5ab5 100644 --- a/pyminer_comm/base/network.py +++ b/pyminer_comm/base/network.py @@ -3,19 +3,21 @@ # @Author: Zhanyi Hou # @Email: 1295752786@qq.com # @File: base.py -import socket import logging +import socket logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) +PORT = 5000 + def get(method: str, msg: str, port=52346, _timeout: int = None, **kwargs) -> bytes: s = socket.socket() if _timeout is not None: s.settimeout(_timeout) try: - s.connect(('localhost', port)) + s.connect(('localhost', PORT)) except socket.timeout as e: s.close() logger.debug('Connection timeout') -- Gitee From 74d9181cb85159fb6cda976718d55b0252bd0227 Mon Sep 17 00:00:00 2001 From: hzy15610046011 <1295752786@qq.com> Date: Thu, 3 Jun 2021 09:27:29 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BA=86=E5=8E=9F?= =?UTF-8?q?=E6=9C=89=E7=9A=84=E8=AE=BE=E7=BD=AE=E6=96=87=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E5=8A=A0=E4=BA=86qsettings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ings.json => default_settings.json.unused} | 0 features/io/settings.py | 109 ------------------ 2 files changed, 109 deletions(-) rename configuration/{default_settings.json => default_settings.json.unused} (100%) diff --git a/configuration/default_settings.json b/configuration/default_settings.json.unused similarity index 100% rename from configuration/default_settings.json rename to configuration/default_settings.json.unused diff --git a/features/io/settings.py b/features/io/settings.py index 60556216..82188df7 100644 --- a/features/io/settings.py +++ b/features/io/settings.py @@ -1,38 +1,6 @@ """ TODO:DEPRECATED。这个文件将被废弃! -settings.py负责设置文件的输入输出。 -Settings继承字典类,另外写了存储函数。 -还有其他设置的函数 -设置文件: -~/.pyminer文件夹存储设置文件。 -~/.pyminer/pyminer_config存储全局界面的设置文件 -~/.pyminer/packages下存储插件的文件夹,插件的文件也放在下面。 -插件获取的方式: -extension_lib.Program.get_plugin_data_path(plugin_name) -比如: - -extension_lib.Program.get_plugin_data_path('code_editor') -返回的路径就是~/.pyminer/packages/code_editor文件夹。 - -其中的文件敬请插件开发者管理。建议不要向其中放太多数据,避免过多占用用户的磁盘空间。 -TODO:未来我们会增加一个插件读写设置的接口。可以将插件的文件放到里面。 -=============================== -方案1: -settings = Extension.create_default_settings() # 创建默认设置。 -settings = Extension.read_settings('settings.json') # settings值为一个字典,{'width':100,'height':161} -Extension.save_settings(settings,'settings.json') # 需要手动调用这个回调函数。 -=============================== -方案2: -创建一个默认的属性Extension.settings,与插件目录下的extsettings.json保持关联。 -启动时,插件加载之前调用: -ext = Extension() -ext.create_default_settings() # 创建默认设置 -ext.update_settings() # 从设置文件中读取设置并且更新设置 -ext.save_settings() # pyminer 关闭时自动调用 - -此时直接拿到settings就可以使用了。 -对于多进程插件,可以在启动的子进程中直接获取相关的设置路径。但一般的科学计算插件,是无需保存设置的。 """ import logging import os @@ -96,80 +64,3 @@ def load_theme(style: str): app.setStyleSheet(mw.get_stylesheet('Windows')) mw.setStyleSheet(mw.get_stylesheet('Windows')) # app.setStyle("Windows") - - -# class Settings(dict): -# """ -# 单例! -# """ -# -# @classmethod -# def __new__(cls, *args): -# if not hasattr(cls, 'instance'): -# instance = super().__new__(cls) -# cls.instance = instance -# return cls.instance -# -# def __init__(self): -# super(Settings, self).__init__() -# self.check_pyminer_settings_dir() -# self.update(self.load()) -# -# def check_pyminer_settings_dir(self): -# self.data_path = get_pyminer_data_path() -# path = os.path.join(self.data_path, 'pyminer_config') -# self.settings_path = path -# if not os.path.exists(path): -# os.mkdir(path) -# -# @staticmethod -# def get_instance() -> 'Settings': -# return Settings.instance -# -# def load(self) -> Dict[str, str]: -# """ -# 加载设置项。 -# default_settings是默认设置项 -# :return: -# """ -# with open(os.path.join(utils.get_root_dir(), 'configuration', 'default_settings.json'), 'r') as f: -# default_settings = json.load(f) -# if platform.system().lower() == 'windows': -# default_settings['work_dir'] = os.path.expanduser('~') -# else: -# default_settings['work_dir'] = os.environ['HOME'] -# if not os.path.exists(default_settings['work_dir']): -# os.mkdir(default_settings['work_dir']) -# -# try: -# with open(os.path.join(self.settings_path, 'pyminer_settings.json'), 'r') as f: -# settings = json.load(f) -# except BaseException: -# settings = {} -# -# pmsettings = default_settings -# pmsettings.update(settings) -# if not os.path.exists(pmsettings['work_dir']): -# pmsettings['work_dir'] = os.path.expanduser('~') -# return pmsettings -# -# def save(self): -# """ -# 保存 -# :return: -# """ -# import json -# try: -# config_file = os.path.join(self.settings_path, 'pyminer_settings.json') -# with open(config_file, 'w') as f: -# json.dump(self, f, indent=4) -# except FileNotFoundError as e: -# logging.warning(e) - - -if __name__ == '__main__': - s1 = Settings() - s2 = Settings() - s3 = Settings.instance - print(s3) - print(id(s1), id(s2), s1 is s2, id(s3)) -- Gitee