From 7c00da4f2a493c2918979b89d74b828225484e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Thu, 27 Aug 2020 10:40:29 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E4=BB=BF?= =?UTF-8?q?=E7=85=A7ribbon=E7=9A=84=E5=8A=9F=E8=83=BD=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E6=96=87=E6=9C=AC=E7=BC=96=E8=BE=91=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/ui/base/widgets/codeeditwidget.py | 264 ++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 pyminer/ui/base/widgets/codeeditwidget.py diff --git a/pyminer/ui/base/widgets/codeeditwidget.py b/pyminer/ui/base/widgets/codeeditwidget.py new file mode 100644 index 00000000..07d8da07 --- /dev/null +++ b/pyminer/ui/base/widgets/codeeditwidget.py @@ -0,0 +1,264 @@ +#coding:utf-8 +# 来源和出处见注释。 +# 带有自动补全、代码高亮的代码编辑器。 +from PyQt5 import QtWidgets +from PyQt5.QtCore import * +from PyQt5.Qsci import * +from PyQt5.QtWidgets import * +from PyQt5.QtGui import * +import re +import keyword +import os +'''感谢https://blog.csdn.net/xiaoyangyang20/article/details/68923133?fps=1&locationNum=4 +,https://blog.csdn.net/tgbus18990140382/article/details/26136661 +,https://qscintilla.com +。''' + +class highlight(QsciLexerPython): + def __init__(self,parent): + QsciLexerPython.__init__(self,parent) + font = QFont() + font.setFamily('Courier') + font.setPointSize(12) + font.setFixedPitch(True) + self.setFont(font) + self.setColor(QColor(0, 0, 0)) + self.setPaper(QColor(255, 255, 255)) + self.setColor(QColor("#00FF00"), QsciLexerPython.ClassName) + self.setColor(QColor("#B0171F"), QsciLexerPython.Keyword) + self.setColor(QColor("#00FF00"), QsciLexerPython.Comment) + self.setColor(QColor("#FF00FF"), QsciLexerPython.Number) + self.setColor(QColor("#0000FF"), QsciLexerPython.DoubleQuotedString) + self.setColor(QColor("#0000FF"), QsciLexerPython.SingleQuotedString) + self.setColor(QColor("#288B22"), QsciLexerPython.TripleSingleQuotedString) + self.setColor(QColor("#288B22"), QsciLexerPython.TripleDoubleQuotedString) + self.setColor(QColor("#0000FF"), QsciLexerPython.FunctionMethodName) + self.setColor(QColor("#191970"), QsciLexerPython.Operator) + self.setColor(QColor("#000000"), QsciLexerPython.Identifier) + self.setColor(QColor("#00FF00"), QsciLexerPython.CommentBlock) + self.setColor(QColor("#0000FF"), QsciLexerPython.UnclosedString) + self.setColor(QColor("#FFFF00"), QsciLexerPython.HighlightedIdentifier) + self.setColor(QColor("#FF8000"), QsciLexerPython.Decorator) + self.setFont(QFont('Courier',12,weight=QFont.Bold),5) + self.setFont(QFont('Courier',12,italic=True),QsciLexerPython.Comment) + +class MainWindow(QMainWindow): + def __init__(self,parent=None,title='未命名',filenamearg=None): + super(MainWindow,self).__init__(parent) + self.setGeometry(100,100,1000,700) + self.setWindowTitle(title) + font=QFont() + font.setFamily('Courier') + font.setPointSize(12) + font.setFixedPitch(True) + self.setFont(font) + self.editor=QsciScintilla() + self.editor.setFont(font) + self.setCentralWidget(self.editor) + self.editor.setUtf8(True) + self.editor.setMarginsFont(font) + self.editor.setMarginWidth(0,len(str(len(self.editor.text().split('\n'))))*20) + self.editor.setMarginLineNumbers(0,True) + + self.editor.setEdgeMode(QsciScintilla.EdgeLine) + self.editor.setEdgeColumn(80) + self.editor.setEdgeColor(QColor(0,0,0)) + + self.editor.setBraceMatching(QsciScintilla.StrictBraceMatch) + + self.editor.setIndentationsUseTabs(True) + self.editor.setIndentationWidth(4) + self.editor.setTabIndents(True) + self.editor.setAutoIndent(True) + self.editor.setBackspaceUnindents(True) + self.editor.setTabWidth(4) + + self.editor.setCaretLineVisible(True) + self.editor.setCaretLineBackgroundColor(QColor('#FFFFCD')) + + self.editor.setIndentationGuides(True) + + self.editor.setFolding(QsciScintilla.PlainFoldStyle) + self.editor.setMarginWidth(2,12) + + self.editor.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPEN) + self.editor.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDER) + self.editor.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPENMID) + self.editor.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDEREND) + + self.editor.setMarkerBackgroundColor(QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEREND) + self.editor.setMarkerForegroundColor(QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEREND) + self.editor.setMarkerBackgroundColor(QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID) + self.editor.setMarkerForegroundColor(QColor("#272727"),QsciScintilla.SC_MARKNUM_FOLDEROPENMID) + self.editor.setAutoCompletionSource(QsciScintilla.AcsAll) + self.editor.setAutoCompletionCaseSensitivity(True) + self.editor.setAutoCompletionReplaceWord(False) + self.editor.setAutoCompletionThreshold(1) + self.editor.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit) + self.lexer=highlight(self.editor) + self.editor.setLexer(self.lexer) + self.mod=False + self.__api = QsciAPIs(self.lexer) + autocompletions = keyword.kwlist+["abs", "all", "any", "basestring", "bool", + "callable", "chr", "classmethod", "cmp", "compile", + "complex", "delattr", "dict", "dir", "divmod", + "enumerate", "eval", "execfile", "exit", "file", + "filter", "float", "frozenset", "getattr", "globals", + "hasattr", "hex", "id", "int", "isinstance", + "issubclass", "iter", "len", "list", "locals", "map", + "max", "min", "object", "oct", "open", "ord", "pow", + "property", "range", "reduce", "repr", "reversed", + "round", "set", "setattr", "slice", "sorted", + "staticmethod", "str", "sum", "super", "tuple", "type", + "vars", "zip",'print'] + for ac in autocompletions: + self.__api.add(ac) + self.__api.prepare() + self.editor.autoCompleteFromAll() + if filenamearg: + obj=open(filenamearg,'r+',encoding='utf-8') + try: + self.editor.setText(obj.read()) + except: + QMessageBox.warning(self,'警告','无法打开此文件!',QMessageBox.Ok) + self.editor.document().clear() + self.statusbar = QtWidgets.QStatusBar(self) + self.setStatusBar(self.statusbar) + fileNewAction = self.createAction("新建",self.newfile, + 'Ctrl+N', "filenew", "创建Python文件") + fileOpenAction = self.createAction("打开", self.fileopen, + 'Ctrl+O', "fileopen", + "打开Python文件") + self.fileSaveAction = self.createAction("保存", self.save, + 'Ctrl+S', "filesave", "保存Python文件") + self.fileSaveAsAction = self.createAction("另存为", + self.saveas,None, + "用新名字保存文件") + fileQuitAction = self.createAction("退出", self.close, + "Ctrl+Q", "filequit", "退出") + self.editCopyAction = self.createAction("撤销", + self.editor.undo,'Ctrl+Z', "editcopy", + "撤销") + self.editCutAction = self.createAction("重做", self.editor.redo, + 'Ctrl+Alt+Z', "editcut", + "重做") + self.findAction = self.createAction("查找", + self.findtext, 'Ctrl+F', "editcopy", + "查找") + self.replaceAction = self.createAction("替换", None, + 'Ctrl+R', "editcut", + "替换") + self.runAction = self.createAction('运行',self.run,'Ctrl+B','','运行程序') + fileMenu = self.menuBar().addMenu("文件") + self.addActions(fileMenu, (fileNewAction, fileOpenAction, + self.fileSaveAction, self.fileSaveAsAction, None, + fileQuitAction)) + editMenu = self.menuBar().addMenu("编辑") + self.addActions(editMenu, (self.editCopyAction, + self.editCutAction, None,self.findAction,self.replaceAction)) + runMenu=self.menuBar().addMenu('运行') + self.addActions(runMenu,(self.runAction,)) + self.name='' + self.editor.textChanged.connect(self.changed) + self.filename=filenamearg + def run(self): + if self.windowTitle()=='未命名': + self.askforsave() + print(self.windowTitle()) + os.system('call python '+self.windowTitle()) + def changed(self): + self.mod=True + self.editor.setMarginWidth(0, len(str(len(self.editor.text().split('\n')))) * 20) + def createAction(self, text, slot=None, shortcut=None, icon=None, + tip=None, checkable=False, signal="triggered()"): + action = QAction(text, self) + if icon is not None: + action.setIcon(QIcon(":/{0}.png".format(icon))) + if shortcut is not None: + action.setShortcut(shortcut) + if tip is not None: + action.setToolTip(tip) + action.setStatusTip(tip) + if slot is not None: + action.triggered.connect(slot) + if checkable: + action.setCheckable(True) + return action + + def addActions(self, target, actions): + for action in actions: + if action is None: + target.addSeparator() + else: + target.addAction(action) + def askforsave(self): + if self.mod: + r=QMessageBox.question(self,'询问','是否要保存?',QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel) + if r==QMessageBox.Cancel: + return False + elif r==QMessageBox.Yes: + return self.save() + return True + def save(self): + if not self.name: + return self.saveas() + self.mod=False + self.setWindowTitle(self.name) + obj=open(self.name,'w',encoding='utf-8') + obj.truncate() + obj.close() + obj = open(self.name, 'r+', encoding='utf-8') + try: + obj.write(self.editor.text()) + except: + obj.write('An error has occcured when trying to save this file.') + obj.close() + def saveas(self): + filename,_buff=QFileDialog.getSaveFileName(self,'另存为','./','Python文件 (*.py)') + if filename: + self.name=filename + return self.save() + return False + def newfile(self): + if self.mod: + if not self.askforsave(): + return -1 + self.editor.clear() + self.mod=False + self.name='' + self.setWindowTitle('未命名') + def fileopen(self): + if self.mod: + if not self.askforsave(): + return -1 + filename, _buff = QFileDialog.getOpenFileName(self, '另存为', './', 'Python文件 (*.py)') + if filename: + self.name = filename + obj=open(self.name,'r+',encoding='utf-8') + try: + self.editor.setText(obj.read()) + except Exception as e: + self.editor.setText("Can't read this file!Error:"+str(e)) + obj.close() + self.setWindowTitle(self.name) + self.mod=False + def closeEvent(self, event): + if not self.askforsave(): + event.ignore() + event.accept() + def findtext(self): + pass + +def main(): + import sys + from os import path + app = QApplication(sys.argv) + fname = '未命名' + if len(sys.argv) > 1: + if path.isfile(sys.argv[1]): + fname = sys.argv[1] + form = MainWindow(None,fname,fname if fname!='未命名' else None) + form.show() + app.exec_() + +main() \ No newline at end of file -- Gitee From 0653ee1dd5d9e45699ec39a4f39a723e936f5688 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Thu, 27 Aug 2020 21:01:11 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E5=81=9A=E5=A5=BD=E4=BA=86dockedwidget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/PyMiner.iml | 2 +- .idea/misc.xml | 2 +- pyminer/pmappmodern.py | 131 ++ pyminer/ui/base/mainForm.ui | 7 +- pyminer/ui/base/mainFormmodern.ui | 1465 +++++++++++++++++ pyminer/ui/base/widgets/codeeditwidget.py | 823 ++++++--- .../ui/base/widgets/menu_tool_stat_bars.py | 162 +- 7 files changed, 2350 insertions(+), 242 deletions(-) create mode 100644 pyminer/pmappmodern.py create mode 100644 pyminer/ui/base/mainFormmodern.ui diff --git a/.idea/PyMiner.iml b/.idea/PyMiner.iml index 8e47e33a..db3ae9e5 100644 --- a/.idea/PyMiner.iml +++ b/.idea/PyMiner.iml @@ -2,7 +2,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index d1e22ecb..a30b03ef 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py new file mode 100644 index 00000000..48c573f2 --- /dev/null +++ b/pyminer/pmappmodern.py @@ -0,0 +1,131 @@ +import os +import sys +from PyQt5.QtCore import pyqtSignal,Qt +# from PyQt5.QtGui import Q +from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QListWidget, QTextEdit, QPushButton, QApplication, \ + QWidget, QToolBar, QAction, QVBoxLayout, QMenu + + +class MyDockWidget(QDockWidget): + def dockLocationChanged(self, area: Qt.DockWidgetArea) -> None: + print(area) + +from pyminer.ui.base.widgets.menu_tool_stat_bars import PMModernToolbar + + +class PushButtonPane(QWidget): + def __init__(self): + super().__init__() + layout =QVBoxLayout() + layout.setContentsMargins(0,0,0,0) + + for i in range(2): + b=QPushButton('aa') + b.setStyleSheet('QPushButton{border-width:0px;padding:2px 2px;width:50px;height:30px;}') + m = QMenu('File') + b.setMenu(m) + layout.addWidget( b) + # layout.addWidget(ToolBarPushButton('aa')) + # layout.addWidget(ToolBarPushButton('aa')) + self.setLayout(layout) + +class MainWindow(QMainWindow): + def __init__(self, parent=None): + from pyminer.ui.base.widgets.resources import icon_New + super(MainWindow, self).__init__(parent) + + # self.toolbox = MyDockWidget('tools', self) + # self.addDockWidget(Qt.TopDockWidgetArea,self.toolbox) + # self.toolbox.setObjectName('tools') + # self.toolbox.setWidget(PMModernToolbar()) + # self.toolbox.setMaximumHeight(120) + t=QToolBar() + a=QAction(self) + self.addToolBar(t) + a.setIcon(icon_New) + t.addAction(a) + t.addWidget(PushButtonPane()) + t.setFixedHeight(60) + t.setStyleSheet('QToolButton{height:60px;width:60px;}') + # self.toolbox.setFeatures(QDockWidget.NoDockWidgetFeatures) + # self.toolbox.DockWidgetClosable + + # 创建QDockWidget窗口(标题,自身窗口) + self.items = MyDockWidget('Dockable', self) + self.items.setObjectName('1') + self.items2 = QDockWidget('Dockable', self) + self.items2.setObjectName('2') + self.items3 = QDockWidget('Dockable', self) + self.items3.setObjectName('3') + self.items4 = QDockWidget('Dockable', self) + self.items4.setObjectName('4') + + # 实例化列表窗口,添加几个条目 + self.listWidget = QListWidget() + self.listWidget.addItem('Item1') + self.listWidget.addItem('Item2') + self.listWidget.addItem('Item3') + self.listWidget.addItem('Item4') + + # 在窗口区域设置QWidget,添加列表控件 + self.items.setWidget(self.listWidget) + self.items2.setWidget(QTextEdit()) + self.items3.setWidget(QTextEdit()) + # self.items4.setWidget(QTextEdit()) + + # 设置dock窗口是否可以浮动,True,运行浮动在外面,自动与主界面脱离,False,默认浮动主窗口内,可以手动脱离 + self.items.setFloating(False) + self.items2.setFloating(False) + self.items3.setFloating(False) + # self.items4.setFloating(False) + # 设置QTextEdit为中央小控件 + b = QPushButton('此为中央控件,点击保存布局') + b.clicked.connect(self.save_layout) + self.setCentralWidget(b) + # 将窗口放置在中央小控件的右侧 + self.addDockWidget(Qt.RightDockWidgetArea, self.items) + self.addDockWidget(Qt.LeftDockWidgetArea, self.items2) + self.addDockWidget(Qt.RightDockWidgetArea, self.items3) + self.addDockWidget(Qt.LeftDockWidgetArea, self.items4) + + ld = self.items2.layoutDirection() + fl = self.items.isFloating() + + + # print(s) + print(ld, fl) + print(self.items.features()) + # print(self.items4.layoutDirection()) + # print(self.items.layoutDirection(), self.items4.layoutDirection()) + self.setWindowTitle('Dock 例子') + # self.add_widget_on_dock('hahahahaha',QPushButton('ttttttttttt')) + # self.load_layout() + + def add_widget_on_dock(self,dock_name:str,widget:QWidget): + dw = QDockWidget() + dw.setObjectName(dock_name) + dw.setWidget(widget) + self.addDockWidget(Qt.LeftDockWidgetArea,dw) + + def save_layout(self): + p = '/home/hzy/Desktop/qtlayout.ini' + with open(p, 'wb') as f: + s = self.saveState() + f.write(s) + + def load_layout(self): + p = '/home/hzy/Desktop/qtlayout.ini' + if os.path.exists(p): + with open(p, 'rb') as f: + s = f.read() + self.restoreState(s) + + def on_boot_finished(self): + pass + + +if __name__ == '__main__': + app = QApplication(sys.argv) + demo = MainWindow() + demo.show() + sys.exit(app.exec_()) diff --git a/pyminer/ui/base/mainForm.ui b/pyminer/ui/base/mainForm.ui index efdb6ab7..01899ecc 100644 --- a/pyminer/ui/base/mainForm.ui +++ b/pyminer/ui/base/mainForm.ui @@ -167,7 +167,7 @@ - 0 + 3 @@ -496,6 +496,11 @@ 输出 + + + 编辑器 + + diff --git a/pyminer/ui/base/mainFormmodern.ui b/pyminer/ui/base/mainFormmodern.ui new file mode 100644 index 00000000..6d3f53af --- /dev/null +++ b/pyminer/ui/base/mainFormmodern.ui @@ -0,0 +1,1465 @@ + + + MainWindow + + + + 0 + 0 + 1366 + 768 + + + + + 1024 + 768 + + + + + Microsoft YaHei UI + + + + Patata + + + + + + + Qt::Horizontal + + + + + 300 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + Qt::CustomContextMenu + + + + 工作区间 + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + 文件 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + true + + + true + + + false + + + true + + + true + + + true + + + false + + + false + + + false + + + true + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 3 + + + + 数据 + + + + + + + + + false + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 19 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + 27 + + + + + 28 + + + + + 29 + + + + + 30 + + + + + C1 + + + + + C2 + + + + + C3 + + + + + C4 + + + + + C5 + + + + + C6 + + + + + C7 + + + + + C8 + + + + + C9 + + + + + C10 + + + + + C11 + + + + + C12 + + + + + C13 + + + + + C14 + + + + + C15 + + + + + C16 + + + + + C17 + + + + + C18 + + + + + C19 + + + + + C20 + + + + + C21 + + + + + C22 + + + + + C23 + + + + + C24 + + + + + C25 + + + + + C26 + + + + + C27 + + + + + C28 + + + + + C29 + + + + + C30 + + + + + + + + + 流程 + + + + + 输出 + + + + + 编辑器 + + + + + + QTabWidget::South + + + 1 + + + + 日志 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 16777215 + 16777215 + + + + true + + + + + + + + 控制台 + + + + + + + + + + + + + + 280 + 0 + + + + + 280 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + + + + + 标准工具栏 + + + TopToolBarArea + + + false + + + + + + 分析工具栏 + + + Qt::RightToLeft + + + RightToolBarArea + + + false + + + + + + Microsoft YaHei UI + + + + false + + + background-color: rgb(240, 240, 240); + + + + + + 0 + 0 + 1366 + 23 + + + + + + true + + + 4 + + + + + + + + + + + + + :/pyqt/source/images/dbviewtables.png:/pyqt/source/images/dbviewtables.png + + + 数据 + + + 查看数据窗口 + + + + + + :/pyqt/source/images/lc_autosum.png:/pyqt/source/images/lc_autosum.png + + + 统计 + + + 统计 + + + + + + :/pyqt/source/images/lc_drawchart.png:/pyqt/source/images/lc_drawchart.png + + + 可视化 + + + 可视化 + + + + + + :/pyqt/source/images/lc_statisticsmenu.png:/pyqt/source/images/lc_statisticsmenu.png + + + 模型 + + + 模型 + + + + + + :/pyqt/source/images/New.png:/pyqt/source/images/New.png + + + 新建(&N) + + + + Microsoft YaHei UI + + + + Ctrl+N + + + + + + :/pyqt/source/images/folder.png:/pyqt/source/images/folder.png + + + 打开(&O) + + + + Microsoft YaHei UI + + + + Ctrl+O + + + + + + :/pyqt/source/images/input.png:/pyqt/source/images/input.png + + + 导入(&I) + + + + Microsoft YaHei UI + + + + Ctrl+I + + + + + + :/pyqt/source/images/Save.png:/pyqt/source/images/Save.png + + + 保存(&S) + + + Ctrl+S + + + + + 另存为 + + + + + + :/pyqt/source/images/wb-setting-normal.png:/pyqt/source/images/wb-setting-normal.png + + + 设置(&X) + + + + Microsoft YaHei UI + + + + Alt+M + + + + + + :/pyqt/source/images/Delete.png:/pyqt/source/images/Delete.png + + + 退出(&Q) + + + Alt+Q + + + + + + :/pyqt/source/images/Cut.png:/pyqt/source/images/Cut.png + + + 剪切(&X) + + + + + + :/pyqt/source/images/Copy.png:/pyqt/source/images/Copy.png + + + 复制(&C) + + + + + + :/pyqt/source/images/Paste.png:/pyqt/source/images/Paste.png + + + 粘贴(P) + + + + + true + + + true + + + 工具栏 + + + + + true + + + true + + + 状态栏 + + + + + 转置 + + + Ctrl+T + + + + + + :/pyqt/source/images/lc_formfilternavigator.png:/pyqt/source/images/lc_formfilternavigator.png + + + 筛选 + + + + Microsoft YaHei UI + + + + Alt+F + + + + + + :/pyqt/source/images/mergedocuments.png:/pyqt/source/images/mergedocuments.png + + + 纵向合并 + + + + + + :/pyqt/source/images/lc_mergecells.png:/pyqt/source/images/lc_mergecells.png + + + 横向合并 + + + + + 描述统计 + + + + Microsoft YaHei UI + + + + + + 数据分布 + + + + + 缺失值 + + + + + 异常值 + + + + + 相关 + + + + Microsoft YaHei UI + + + + + + 回归 + + + + + 分类 + + + + + 降维 + + + + + 非参数检验 + + + + + 时间序列预测 + + + + + 生存分析 + + + + + 折线图 + + + + Microsoft YaHei UI + + + + Alt+L + + + + + 直方图 + + + Alt+H + + + + + 散点图 + + + Alt+S + + + + + 盒型图 + + + Alt+B + + + + + 条形图 + + + + Microsoft YaHei UI + + + + Alt+P + + + + + 决策树 + + + Alt+T + + + + + ROC曲线 + + + Alt+R + + + + + WOE&&IV + + + Alt+W + + + + + 评分卡 + + + Alt+S + + + + + KS值 + + + Alt+K + + + + + + :/pyqt/source/images/hlinettp.png:/pyqt/source/images/hlinettp.png + + + 官方网站 + + + + Microsoft YaHei UI + + + + + + 检查更新 + + + + Microsoft YaHei UI + + + + + + + :/pyqt/source/images/hlinettp.png:/pyqt/source/images/hlinettp.png + + + 帮助文档 + + + + Microsoft YaHei UI + + + + + + 关于 + + + + Microsoft YaHei UI + + + + + + 删除行 + + + + + 删除列 + + + + + 拆分列 + + + + + 重新编码 + + + + + 唯一值 + + + + + 数据角色 + + + + Microsoft YaHei UI + + + + + + + :/pyqt/source/images/dbqueryedit.png:/pyqt/source/images/dbqueryedit.png + + + 从数据库导入 + + + + Microsoft YaHei UI + + + + + + + :/pyqt/source/images/infobox.png:/pyqt/source/images/infobox.png + + + 快速退出 + + + Alt+Shift+Q + + + + + + :/pyqt/source/images/lc_dbreportedit.png:/pyqt/source/images/lc_dbreportedit.png + + + 评估 + + + 评估 + + + + + + :/pyqt/source/images/lc_dataarearefresh.png:/pyqt/source/images/lc_dataarearefresh.png + + + 测试 + + + 测试 + + + + + + :/pyqt/source/images/lc_save.png:/pyqt/source/images/lc_save.png + + + 导出数据集 + + + 导出数据集 + + + + + + :/pyqt/source/images/lc_dbqueryrename.png:/pyqt/source/images/lc_dbqueryrename.png + + + 重命名 + + + 重命名数据集 + + + + + 行筛选 + + + + + + :/pyqt/source/images/lc_dia.png:/pyqt/source/images/lc_dia.png + + + 结果 + + + + + + :/pyqt/source/images/lc_dbsortingandgrouping.png:/pyqt/source/images/lc_dbsortingandgrouping.png + + + 排序 + + + + + + :/pyqt/source/images/lc_insertplugin.png:/pyqt/source/images/lc_insertplugin.png + + + Python包管理工具 + + + Python包管理工具 + + + + + + :/pyqt/source/images/jupyter.png:/pyqt/source/images/jupyter.png + + + jupyter_notebook + + + + + Windows + + + + + Fusion + + + + + QDarkStyle + + + + + + :/pyqt/source/images/python.png:/pyqt/source/images/python.png + + + ipython + + + + + 直方图 + + + + Microsoft YaHei UI + + + + + + WindowsVista + + + + + + :/pyqt/source/images/lc_arrowshapes.right-arrow-callout.png:/pyqt/source/images/lc_arrowshapes.right-arrow-callout.png + + + 隐藏侧边栏 + + + 隐藏侧边栏 + + + + + true + + + true + + + 工作区间 + + + + + true + + + true + + + 任务列表 + + + + + true + + + true + + + 工具窗口 + + + + + 最小化到托盘 + + + + + 信息提示 + + + + + 成功消息 + + + + + 警告消息 + + + + + 错误消息 + + + + + + ConsoleWidget + QWidget +
pyminer.ui.base.widgets.consolewidget
+ 1 +
+ + PMToolBarTop + QToolBar +
pyminer.ui.base.widgets.menu_tool_stat_bars.h
+
+ + PMToolBarRight + QToolBar +
pyminer.ui.base.widgets.menu_tool_stat_bars.h
+
+ + PMTableWidget + QTableWidget +
pyminer.ui.base.widgets.tablewidget
+
+ + PMFlowWidget + QWidget +
pyminer.ui.base.widgets.flowwidget.h
+ 1 +
+ + PMPageData + QWidget +
pyminer.ui.base.widgets.controlpanel.h
+ 1 +
+ + PMPageStats + QWidget +
pyminer.ui.base.widgets.controlpanel.h
+ 1 +
+ + PMPagePlot + QWidget +
pyminer.ui.base.widgets.controlpanel.h
+ 1 +
+ + PMPageModel + QWidget +
pyminer.ui.base.widgets.controlpanel.h
+ 1 +
+ + PMPage + QWidget +
pyminer.ui.base.widgets.controlpanel.h
+ 1 +
+ + PMMenuBar + QMenuBar +
pyminer.ui.base.widgets.menu_tool_stat_bars.h
+
+ + PMFilesTreeview + QTreeView +
pyminer.ui.base.widgets.treeviews.h
+
+ + PMDatasetsTreeview + QTreeWidget +
pyminer.ui.base.widgets.treeviews.h
+
+ + PMReportWidget + QWidget +
pyminer.ui.base.widgets.reportwidget.h
+ 1 +
+
+ + + + + + action_quit + triggered() + MainWindow + close() + + + -1 + -1 + + + 399 + 299 + + + + +
diff --git a/pyminer/ui/base/widgets/codeeditwidget.py b/pyminer/ui/base/widgets/codeeditwidget.py index 07d8da07..90d2349d 100644 --- a/pyminer/ui/base/widgets/codeeditwidget.py +++ b/pyminer/ui/base/widgets/codeeditwidget.py @@ -1,174 +1,497 @@ -#coding:utf-8 -# 来源和出处见注释。 -# 带有自动补全、代码高亮的代码编辑器。 -from PyQt5 import QtWidgets -from PyQt5.QtCore import * -from PyQt5.Qsci import * -from PyQt5.QtWidgets import * -from PyQt5.QtGui import * -import re -import keyword +#!/usr/bin/env python3 +''' +来源: +https://blog.csdn.net/xiaoyangyang20/article/details/68923133 +''' import os -'''感谢https://blog.csdn.net/xiaoyangyang20/article/details/68923133?fps=1&locationNum=4 -,https://blog.csdn.net/tgbus18990140382/article/details/26136661 -,https://qscintilla.com -。''' - -class highlight(QsciLexerPython): - def __init__(self,parent): - QsciLexerPython.__init__(self,parent) - font = QFont() - font.setFamily('Courier') - font.setPointSize(12) - font.setFixedPitch(True) - self.setFont(font) - self.setColor(QColor(0, 0, 0)) - self.setPaper(QColor(255, 255, 255)) - self.setColor(QColor("#00FF00"), QsciLexerPython.ClassName) - self.setColor(QColor("#B0171F"), QsciLexerPython.Keyword) - self.setColor(QColor("#00FF00"), QsciLexerPython.Comment) - self.setColor(QColor("#FF00FF"), QsciLexerPython.Number) - self.setColor(QColor("#0000FF"), QsciLexerPython.DoubleQuotedString) - self.setColor(QColor("#0000FF"), QsciLexerPython.SingleQuotedString) - self.setColor(QColor("#288B22"), QsciLexerPython.TripleSingleQuotedString) - self.setColor(QColor("#288B22"), QsciLexerPython.TripleDoubleQuotedString) - self.setColor(QColor("#0000FF"), QsciLexerPython.FunctionMethodName) - self.setColor(QColor("#191970"), QsciLexerPython.Operator) - self.setColor(QColor("#000000"), QsciLexerPython.Identifier) - self.setColor(QColor("#00FF00"), QsciLexerPython.CommentBlock) - self.setColor(QColor("#0000FF"), QsciLexerPython.UnclosedString) - self.setColor(QColor("#FFFF00"), QsciLexerPython.HighlightedIdentifier) - self.setColor(QColor("#FF8000"), QsciLexerPython.Decorator) - self.setFont(QFont('Courier',12,weight=QFont.Bold),5) - self.setFont(QFont('Courier',12,italic=True),QsciLexerPython.Comment) - +import sys + +sys.path.append('/media/hzy/程序/novalide/forgitcommit/pyminer/pyminer') + +from PyQt5.QtCore import QEvent, QFile, QFileInfo, QIODevice, QRegExp, QTextStream, Qt +from PyQt5.QtWidgets import QAction, QApplication, QFileDialog, QMainWindow, QMessageBox, QTextEdit, QTabWidget, \ + QVBoxLayout,QMessageBox +from PyQt5.QtGui import QFont, QIcon, QColor, QKeySequence, QSyntaxHighlighter, QTextCharFormat, QTextCursor, QCursor, \ + QKeyEvent + +# import pyqtresource_rc + + +__version__ = "1.1.0" + + +class PythonHighlighter(QSyntaxHighlighter): + Rules = [] + Formats = {} + + def __init__(self, parent=None): + super(PythonHighlighter, self).__init__(parent) + + self.initializeFormats() + + KEYWORDS = ["and", "as", "assert", "break", "class", + "continue", "def", "del", "elif", "else", "except", + "exec", "finally", "for", "from", "global", "if", + "import", "in", "is", "lambda", "not", "or", "pass", + "print", "raise", "return", "try", "while", "with", + "yield"] + BUILTINS = ["abs", "all", "any", "basestring", "bool", + "callable", "chr", "classmethod", "cmp", "compile", + "complex", "delattr", "dict", "dir", "divmod", + "enumerate", "eval", "execfile", "exit", "file", + "filter", "float", "frozenset", "getattr", "globals", + "hasattr", "hex", "id", "int", "isinstance", + "issubclass", "iter", "len", "list", "locals", "map", + "max", "min", "object", "oct", "open", "ord", "pow", + "property", "range", "reduce", "repr", "reversed", + "round", "set", "setattr", "slice", "sorted", + "staticmethod", "str", "sum", "super", "tuple", "type", + "vars", "zip"] + CONSTANTS = ["False", "True", "None", "NotImplemented", + "Ellipsis"] + + PythonHighlighter.Rules.append((QRegExp( + "|".join([r"\b%s\b" % keyword for keyword in KEYWORDS])), + "keyword")) + PythonHighlighter.Rules.append((QRegExp( + "|".join([r"\b%s\b" % builtin for builtin in BUILTINS])), + "builtin")) + PythonHighlighter.Rules.append((QRegExp( + "|".join([r"\b%s\b" % constant + for constant in CONSTANTS])), "constant")) + PythonHighlighter.Rules.append((QRegExp( + r"\b[+-]?[0-9]+[lL]?\b" + r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b" + r"|\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b"), + "number")) + PythonHighlighter.Rules.append((QRegExp( + r"\bPyQt4\b|\bQt?[A-Z][a-z]\w+\b"), "pyqt")) + PythonHighlighter.Rules.append((QRegExp(r"\b@\w+\b"), + "decorator")) + stringRe = QRegExp(r"""(?:'[^']*'|"[^"]*")""") + stringRe.setMinimal(True) + PythonHighlighter.Rules.append((stringRe, "string")) + self.stringRe = QRegExp(r"""(:?"["]".*"["]"|'''.*''')""") + self.stringRe.setMinimal(True) + PythonHighlighter.Rules.append((self.stringRe, "string")) + self.tripleSingleRe = QRegExp(r"""'''(?!")""") + self.tripleDoubleRe = QRegExp(r'''"""(?!')''') + + @staticmethod + def initializeFormats(): + baseFormat = QTextCharFormat() + baseFormat.setFontFamily("courier") + baseFormat.setFontPointSize(12) + for name, color in (("normal", Qt.black), + ("keyword", Qt.darkBlue), ("builtin", Qt.darkRed), + ("constant", Qt.darkGreen), + ("decorator", Qt.darkBlue), ("comment", Qt.darkGreen), + ("string", Qt.darkYellow), ("number", Qt.darkMagenta), + ("error", Qt.darkRed), ("pyqt", Qt.darkCyan)): + format = QTextCharFormat(baseFormat) + format.setForeground(QColor(color)) + if name in ("keyword", "decorator"): + format.setFontWeight(QFont.Bold) + if name == "comment": + format.setFontItalic(True) + PythonHighlighter.Formats[name] = format + + def highlightBlock(self, text): + NORMAL, TRIPLESINGLE, TRIPLEDOUBLE, ERROR = range(4) + + textLength = len(text) + prevState = self.previousBlockState() + + self.setFormat(0, textLength, + PythonHighlighter.Formats["normal"]) + + if text.startswith("Traceback") or text.startswith("Error: "): + self.setCurrentBlockState(ERROR) + self.setFormat(0, textLength, + PythonHighlighter.Formats["error"]) + return + if (prevState == ERROR and + not (text.startswith(sys.ps1) or text.startswith("#"))): + self.setCurrentBlockState(ERROR) + self.setFormat(0, textLength, + PythonHighlighter.Formats["error"]) + return + + for regex, format in PythonHighlighter.Rules: + i = regex.indexIn(text) + while i >= 0: + length = regex.matchedLength() + self.setFormat(i, length, + PythonHighlighter.Formats[format]) + i = regex.indexIn(text, i + length) + + # Slow but good quality highlighting for comments. For more + # speed, comment this out and add the following to __init__: + # PythonHighlighter.Rules.append((QRegExp(r"#.*"), "comment")) + if not text: + pass + elif text[0] == "#": + self.setFormat(0, len(text), + PythonHighlighter.Formats["comment"]) + else: + stack = [] + for i, c in enumerate(text): + if c in ('"', "'"): + if stack and stack[-1] == c: + stack.pop() + else: + stack.append(c) + elif c == "#" and len(stack) == 0: + self.setFormat(i, len(text), + PythonHighlighter.Formats["comment"]) + break + + self.setCurrentBlockState(NORMAL) + + if self.stringRe.indexIn(text) != -1: + return + # This is fooled by triple quotes inside single quoted strings + for i, state in ((self.tripleSingleRe.indexIn(text), + TRIPLESINGLE), + (self.tripleDoubleRe.indexIn(text), + TRIPLEDOUBLE)): + if self.previousBlockState() == state: + if i == -1: + i = text.length() + self.setCurrentBlockState(state) + self.setFormat(0, i + 3, + PythonHighlighter.Formats["string"]) + elif i > -1: + self.setCurrentBlockState(state) + self.setFormat(i, text.length(), + PythonHighlighter.Formats["string"]) + + def rehighlight(self): + QApplication.setOverrideCursor(QCursor( + Qt.WaitCursor)) + QSyntaxHighlighter.rehighlight(self) + QApplication.restoreOverrideCursor() + + +class PMCodeEdit(QTextEdit): + + def __init__(self, parent=None): + super(PMCodeEdit, self).__init__(parent) + self.doc_tab_widget = parent + self.filename = '*' + self.path = '' + self.modified = True + + # self.selectionChanged.connect(self.updateUi) + # self.document().modificationChanged.connect(self.on_text_changed) + # QApplication.clipboard().dataChanged.connect(self.updateUi) + self.highlighter = PythonHighlighter(self.document()) + self.setText('aaaaaaaaaaaaaa\ndaaaaaaaaaaaa') + self.setTabChangesFocus(False) + # self.change + self.textChanged.connect(self.on_text_changed) + # self.textChanged.conn/ect(lambda :print('text changed!!')) + + def on_text_changed(self): + print('text changed',self.modified) + if self.modified==True: + return + else: + self.modified=True + self.updateUi() + + def updateUi(self): + self.doc_tab_widget.refresh() + self.doc_tab_widget.is_all_files_saved() + # self.fileSaveAction.setEnabled(self.document().isModified()) + # enable = not self.editor.document().isEmpty() + # self.fileSaveAsAction.setEnabled(enable) + # self.editIndentAction.setEnabled(enable) + # self.editUnindentAction.setEnabled(enable) + # enable = self.editor.textCursor().hasSelection() + # self.editCopyAction.setEnabled(enable) + # self.editCutAction.setEnabled(enable) + # self.editPasteAction.setEnabled(self.editor.canPaste()) + return + + def keyPressEvent(self, event: QKeyEvent) -> None: + # print(event.modifiers() == Qt.ShiftModifier, event.key() == Qt.Key_Tab, event.key() == Qt.Key_CapsLock, + # event.key() == Qt.Key_Backtab) + if event.key() == Qt.Key_Tab: + self.on_tab() + return + if event.key() == Qt.Key_Backtab: + self.on_back_tab() + return + if event.key() == Qt.Key_S and event.modifiers() == Qt.ControlModifier: + self.save() + return + super().keyPressEvent(event) + + # def textChanged(self) -> None: + # self.modified = True + # print(self.modified, 'aaaaaaaaaaaaaaa') + + def on_back_tab(self): + # print('shift+tab(backtab)') + cursor = self.textCursor() + if cursor.hasSelection(): + # print('has selection') + self.editUnindent() + + else: + cursor = self.textCursor() + cursor.clearSelection() + + cursor.movePosition(QTextCursor.StartOfBlock) + + for i in range(4): + cursor.movePosition(QTextCursor.NextCharacter, + QTextCursor.KeepAnchor, 1) + if not cursor.selectedText().endswith(' '): + cursor.movePosition(QTextCursor.PreviousCharacter, + QTextCursor.KeepAnchor, 1) + break + # print('cursor.selected',cursor.selectedText()) + cursor.removeSelectedText() + + def on_tab(self): + cursor = self.textCursor() + if cursor.hasSelection(): + # print('has selection') + self.editIndent() + return + # return True + else: + cursor = self.textCursor() + cursor.insertText(" ") + + def editIndent(self): + cursor = self.textCursor() + cursor.beginEditBlock() + if cursor.hasSelection(): + start = pos = cursor.anchor() + start_line = self.document().findBlock(start) + end = cursor.position() + + if start > end: + start, end = end, start + pos = start + cursor.clearSelection() + + cursor.setPosition(end) + cursor.movePosition(QTextCursor.StartOfLine) + end = cursor.position() + # print(end) + cursor.setPosition(start) + cursor.movePosition(QTextCursor.StartOfLine) + start = cursor.position() + + cursor.setPosition(end) + while pos >= start: + # print(pos, start) + cursor.insertText(" ") + + cursor.movePosition(QTextCursor.Up) + cursor.movePosition(QTextCursor.StartOfLine) + lastPos = pos + pos = cursor.position() + if lastPos == pos: + break + + print('end loop', pos, start) + cursor.setPosition(start) + cursor.movePosition(QTextCursor.NextCharacter, + QTextCursor.KeepAnchor, end - start) + cursor.endEditBlock() + return True + + def editUnindent(self): + cursor = self.textCursor() + cursor.beginEditBlock() + if cursor.hasSelection(): + start = pos = cursor.anchor() + end = cursor.position() + if start > end: + start, end = end, start + pos = start + cursor.clearSelection() + cursor.setPosition(start) + cursor.movePosition(QTextCursor.StartOfLine) + start = cursor.position() + cursor.setPosition(end) + cursor.movePosition(QTextCursor.StartOfLine) + end = cursor.position() + print(start, end) + while pos >= start: + # print('a',start,pos) + cursor.movePosition(QTextCursor.NextCharacter, + QTextCursor.KeepAnchor, 4) + if cursor.selectedText() == " ": + cursor.removeSelectedText() + cursor.movePosition(QTextCursor.Up) + cursor.movePosition(QTextCursor.StartOfLine) + lastpos = pos + pos = cursor.position() + if pos == lastpos: + break + cursor.setPosition(start) + cursor.movePosition(QTextCursor.NextCharacter, + QTextCursor.KeepAnchor, end - start) + + cursor.endEditBlock() + + def save(self): + print(self.toPlainText()) + if not os.path.isfile(self.path): + print(os.getcwd()) + path = QFileDialog.getSaveFileName(self, "选择保存的文件", '/home/hzy/Desktop', filter='*.py')[0] + print('path', path) + if not path: # 说明对话框被关闭,未选择文件,则直接返回。 + return + if not path.endswith('.py'): + path += '.py' + self.path = path + self.filename = os.path.basename(path) + + with open(self.path, 'w') as f: + f.write(self.toPlainText()) + self.modified=False + self.updateUi() + + def on_close_request(self): + if self.modified==True: + answer =QMessageBox.question(self,'保存文件','%s有未保存的更改,是否要保存?'%self.filename,QMessageBox.Yes|QMessageBox.No,QMessageBox.Yes) + if answer==QMessageBox.No: + return + else: + self.save() + +class PMCodeEditTabWidget(QTabWidget): + def __init__(self): + super().__init__() + self.editor_tabs = [PMCodeEdit(self), PMCodeEdit(self), PMCodeEdit(self)] + for tab in self.editor_tabs: + self.addTab(tab, tab.filename) + self.is_all_files_saved() + + self.setTabsClosable(True) + self.tabCloseRequested.connect(self.on_tab_close_request) + def on_tab_close_request(self,close_index:int): + tab_to_close = self.widget(close_index) + tab_to_close.deleteLater() + tab_to_close.on_close_request() + self.removeTab(close_index) + + def keyPressEvent(self, a0: QKeyEvent) -> None: + return + + def is_all_files_saved(self): + for tab_id in range(self.count()): + modified = self.widget(tab_id).modified + print(modified) + print(self.widget(0), self.count()) + # cursor.movePosition(QTextCursor.NextCharacter, + # QTextCursor.KeepAnchor, 1) + def refresh(self): + for tab_id in range(self.count()): + modified = self.widget(tab_id).modified + filename = self.widget(tab_id).filename + if not modified: + self.setTabText(tab_id,filename) + else: + if filename!='*': + self.setTabText(tab_id, filename+' *') + print(self.widget(0), self.count()) + + +# from pyminer.ui.base.widgets.menu_tool_stat_bars import PMModernToolbar + + class MainWindow(QMainWindow): - def __init__(self,parent=None,title='未命名',filenamearg=None): - super(MainWindow,self).__init__(parent) - self.setGeometry(100,100,1000,700) - self.setWindowTitle(title) - font=QFont() - font.setFamily('Courier') - font.setPointSize(12) - font.setFixedPitch(True) - self.setFont(font) - self.editor=QsciScintilla() - self.editor.setFont(font) - self.setCentralWidget(self.editor) - self.editor.setUtf8(True) - self.editor.setMarginsFont(font) - self.editor.setMarginWidth(0,len(str(len(self.editor.text().split('\n'))))*20) - self.editor.setMarginLineNumbers(0,True) - - self.editor.setEdgeMode(QsciScintilla.EdgeLine) - self.editor.setEdgeColumn(80) - self.editor.setEdgeColor(QColor(0,0,0)) - - self.editor.setBraceMatching(QsciScintilla.StrictBraceMatch) - - self.editor.setIndentationsUseTabs(True) - self.editor.setIndentationWidth(4) - self.editor.setTabIndents(True) - self.editor.setAutoIndent(True) - self.editor.setBackspaceUnindents(True) - self.editor.setTabWidth(4) - - self.editor.setCaretLineVisible(True) - self.editor.setCaretLineBackgroundColor(QColor('#FFFFCD')) - - self.editor.setIndentationGuides(True) - - self.editor.setFolding(QsciScintilla.PlainFoldStyle) - self.editor.setMarginWidth(2,12) - - self.editor.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPEN) - self.editor.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDER) - self.editor.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPENMID) - self.editor.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDEREND) - - self.editor.setMarkerBackgroundColor(QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEREND) - self.editor.setMarkerForegroundColor(QColor("#272727"), QsciScintilla.SC_MARKNUM_FOLDEREND) - self.editor.setMarkerBackgroundColor(QColor("#FFFFFF"), QsciScintilla.SC_MARKNUM_FOLDEROPENMID) - self.editor.setMarkerForegroundColor(QColor("#272727"),QsciScintilla.SC_MARKNUM_FOLDEROPENMID) - self.editor.setAutoCompletionSource(QsciScintilla.AcsAll) - self.editor.setAutoCompletionCaseSensitivity(True) - self.editor.setAutoCompletionReplaceWord(False) - self.editor.setAutoCompletionThreshold(1) - self.editor.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit) - self.lexer=highlight(self.editor) - self.editor.setLexer(self.lexer) - self.mod=False - self.__api = QsciAPIs(self.lexer) - autocompletions = keyword.kwlist+["abs", "all", "any", "basestring", "bool", - "callable", "chr", "classmethod", "cmp", "compile", - "complex", "delattr", "dict", "dir", "divmod", - "enumerate", "eval", "execfile", "exit", "file", - "filter", "float", "frozenset", "getattr", "globals", - "hasattr", "hex", "id", "int", "isinstance", - "issubclass", "iter", "len", "list", "locals", "map", - "max", "min", "object", "oct", "open", "ord", "pow", - "property", "range", "reduce", "repr", "reversed", - "round", "set", "setattr", "slice", "sorted", - "staticmethod", "str", "sum", "super", "tuple", "type", - "vars", "zip",'print'] - for ac in autocompletions: - self.__api.add(ac) - self.__api.prepare() - self.editor.autoCompleteFromAll() - if filenamearg: - obj=open(filenamearg,'r+',encoding='utf-8') - try: - self.editor.setText(obj.read()) - except: - QMessageBox.warning(self,'警告','无法打开此文件!',QMessageBox.Ok) - self.editor.document().clear() - self.statusbar = QtWidgets.QStatusBar(self) - self.setStatusBar(self.statusbar) - fileNewAction = self.createAction("新建",self.newfile, - 'Ctrl+N', "filenew", "创建Python文件") - fileOpenAction = self.createAction("打开", self.fileopen, - 'Ctrl+O', "fileopen", - "打开Python文件") - self.fileSaveAction = self.createAction("保存", self.save, - 'Ctrl+S', "filesave", "保存Python文件") - self.fileSaveAsAction = self.createAction("另存为", - self.saveas,None, - "用新名字保存文件") - fileQuitAction = self.createAction("退出", self.close, - "Ctrl+Q", "filequit", "退出") - self.editCopyAction = self.createAction("撤销", - self.editor.undo,'Ctrl+Z', "editcopy", - "撤销") - self.editCutAction = self.createAction("重做", self.editor.redo, - 'Ctrl+Alt+Z', "editcut", - "重做") - self.findAction = self.createAction("查找", - self.findtext, 'Ctrl+F', "editcopy", - "查找") - self.replaceAction = self.createAction("替换", None, - 'Ctrl+R', "editcut", - "替换") - self.runAction = self.createAction('运行',self.run,'Ctrl+B','','运行程序') - fileMenu = self.menuBar().addMenu("文件") - self.addActions(fileMenu, (fileNewAction, fileOpenAction, - self.fileSaveAction, self.fileSaveAsAction, None, - fileQuitAction)) - editMenu = self.menuBar().addMenu("编辑") - self.addActions(editMenu, (self.editCopyAction, - self.editCutAction, None,self.findAction,self.replaceAction)) - runMenu=self.menuBar().addMenu('运行') - self.addActions(runMenu,(self.runAction,)) - self.name='' - self.editor.textChanged.connect(self.changed) - self.filename=filenamearg - def run(self): - if self.windowTitle()=='未命名': - self.askforsave() - print(self.windowTitle()) - os.system('call python '+self.windowTitle()) - def changed(self): - self.mod=True - self.editor.setMarginWidth(0, len(str(len(self.editor.text().split('\n')))) * 20) + + def __init__(self, filename=None, parent=None): + super(MainWindow, self).__init__(parent) + + self.setCentralWidget(PMCodeEditTabWidget()) # PMCodeEditTabWidget()) + # font = QFont("Courier", 11) + # font.setFixedPitch(True) + # self.editor = TextEdit() + # self.editor.setFont(font) + # self.highlighter = PythonHighlighter(self.editor.document()) + # self.setCentralWidget(self.editor) + # + # status = self.statusBar() + # status.setSizeGripEnabled(False) + # status.showMessage("Ready", 5000) + # + # fileNewAction = self.createAction("&New...", self.fileNew, + # QKeySequence.New, "filenew", "Create a Python file") + # fileOpenAction = self.createAction("&Open...", self.fileOpen, + # QKeySequence.Open, "fileopen", + # "Open an existing Python file") + # self.fileSaveAction = self.createAction("&Save", self.fileSave, + # QKeySequence.Save, "filesave", "Save the file") + # self.fileSaveAsAction = self.createAction("Save &As...", + # self.fileSaveAs, icon="filesaveas", + # tip="Save the file using a new name") + # fileQuitAction = self.createAction("&Quit", self.close, + # "Ctrl+Q", "filequit", "Close the application") + # self.editCopyAction = self.createAction("&Copy", + # self.editor.copy, QKeySequence.Copy, "editcopy", + # "Copy text to the clipboard") + # self.editCutAction = self.createAction("Cu&t", self.editor.cut, + # QKeySequence.Cut, "editcut", + # "Cut text to the clipboard") + # self.editPasteAction = self.createAction("&Paste", + # self.editor.paste, QKeySequence.Paste, "editpaste", + # "Paste in the clipboard's text") + # self.editIndentAction = self.createAction("&Indent", + # self.editIndent, "Ctrl+]", "editindent", + # "Indent the current line or selection") + # self.editUnindentAction = self.createAction("&Unindent", + # self.editUnindent, "Ctrl+[", "editunindent", + # "Unindent the current line or selection") + # + # fileMenu = self.menuBar().addMenu("&File") + # self.addActions(fileMenu, (fileNewAction, fileOpenAction, + # self.fileSaveAction, self.fileSaveAsAction, None, + # fileQuitAction)) + # editMenu = self.menuBar().addMenu("&Edit") + # self.addActions(editMenu, (self.editCopyAction, + # self.editCutAction, self.editPasteAction, None, + # self.editIndentAction, self.editUnindentAction)) + # fileToolbar = self.addToolBar("File") + # fileToolbar.setObjectName("FileToolBar") + # self.addActions(fileToolbar, (fileNewAction, fileOpenAction, + # self.fileSaveAction)) + # editToolbar = self.addToolBar("Edit") + # editToolbar.setObjectName("EditToolBar") + # self.addActions(editToolbar, (self.editCopyAction, + # self.editCutAction, self.editPasteAction, None, + # self.editIndentAction, self.editUnindentAction)) + # + # + # + # self.resize(800, 600) + # self.setWindowTitle("Python Editor") + # self.filename = filename + # if self.filename is not None: + # self.loadFile() + # self.updateUi() + + def updateUi(self, arg=None): + self.fileSaveAction.setEnabled( + self.editor.document().isModified()) + enable = not self.editor.document().isEmpty() + self.fileSaveAsAction.setEnabled(enable) + self.editIndentAction.setEnabled(enable) + self.editUnindentAction.setEnabled(enable) + enable = self.editor.textCursor().hasSelection() + self.editCopyAction.setEnabled(enable) + self.editCutAction.setEnabled(enable) + self.editPasteAction.setEnabled(self.editor.canPaste()) + def createAction(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) @@ -184,81 +507,115 @@ class MainWindow(QMainWindow): if checkable: action.setCheckable(True) return action - + def addActions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) - def askforsave(self): - if self.mod: - r=QMessageBox.question(self,'询问','是否要保存?',QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel) - if r==QMessageBox.Cancel: + + def closeEvent(self, event): + if not self.okToContinue(): + event.ignore() + + def okToContinue(self): + if self.editor.document().isModified(): + reply = QMessageBox.question(self, + "Python Editor - Unsaved Changes", + "Save unsaved changes?", + QMessageBox.Yes | QMessageBox.No | + QMessageBox.Cancel) + if reply == QMessageBox.Cancel: return False - elif r==QMessageBox.Yes: - return self.save() - return True - def save(self): - if not self.name: - return self.saveas() - self.mod=False - self.setWindowTitle(self.name) - obj=open(self.name,'w',encoding='utf-8') - obj.truncate() - obj.close() - obj = open(self.name, 'r+', encoding='utf-8') + elif reply == QMessageBox.Yes: + return self.fileSave() + return True + + def fileNew(self): + if not self.okToContinue(): + return + document = self.editor.document() + document.clear() + document.setModified(False) + self.filename = None + self.setWindowTitle("Python Editor - Unnamed") + self.updateUi() + + def fileOpen(self): + if not self.okToContinue(): + return + dir = (os.path.dirname(self.filename) + if self.filename is not None else ".") + fname = str(QFileDialog.getOpenFileName(self, + "Python Editor - Choose File", dir, + "Python files (*.py *.pyw)")[0]) + if fname: + self.filename = fname + self.loadFile() + + def loadFile(self): + fh = None + try: + fh = QFile(self.filename) + if not fh.open(QIODevice.ReadOnly): + raise IOError(str(fh.errorString())) + stream = QTextStream(fh) + stream.setCodec("UTF-8") + self.editor.setPlainText(stream.readAll()) + self.editor.document().setModified(False) + except EnvironmentError as e: + QMessageBox.warning(self, "Python Editor -- Load Error", + "Failed to load {0}: {1}".format(self.filename, e)) + finally: + if fh is not None: + fh.close() + self.setWindowTitle("Python Editor - {0}".format( + QFileInfo(self.filename).fileName())) + + def fileSave(self): + if self.filename is None: + return self.fileSaveAs() + fh = None try: - obj.write(self.editor.text()) - except: - obj.write('An error has occcured when trying to save this file.') - obj.close() - def saveas(self): - filename,_buff=QFileDialog.getSaveFileName(self,'另存为','./','Python文件 (*.py)') + fh = QFile(self.filename) + if not fh.open(QIODevice.WriteOnly): + raise IOError(str(fh.errorString())) + stream = QTextStream(fh) + stream.setCodec("UTF-8") + stream << self.editor.toPlainText() + self.editor.document().setModified(False) + except EnvironmentError as e: + QMessageBox.warning(self, "Python Editor -- Save Error", + "Failed to save {0}: {1}".format(self.filename, e)) + return False + finally: + if fh is not None: + fh.close() + return True + + def fileSaveAs(self): + filename = self.filename if self.filename is not None else "." + filename, filetype = QFileDialog.getSaveFileName(self, + "Python Editor -- Save File As", filename, + "Python files (*.py *.pyw)") if filename: - self.name=filename - return self.save() + self.filename = filename + self.setWindowTitle("Python Editor - {0}".format( + QFileInfo(self.filename).fileName())) + return self.fileSave() return False - def newfile(self): - if self.mod: - if not self.askforsave(): - return -1 - self.editor.clear() - self.mod=False - self.name='' - self.setWindowTitle('未命名') - def fileopen(self): - if self.mod: - if not self.askforsave(): - return -1 - filename, _buff = QFileDialog.getOpenFileName(self, '另存为', './', 'Python文件 (*.py)') - if filename: - self.name = filename - obj=open(self.name,'r+',encoding='utf-8') - try: - self.editor.setText(obj.read()) - except Exception as e: - self.editor.setText("Can't read this file!Error:"+str(e)) - obj.close() - self.setWindowTitle(self.name) - self.mod=False - def closeEvent(self, event): - if not self.askforsave(): - event.ignore() - event.accept() - def findtext(self): - pass - -def main(): - import sys - from os import path + + +if __name__ == '__main__': + app = QApplication(sys.argv) - fname = '未命名' + print(4465) + app.setWindowIcon(QIcon(":/icon.png")) + fname = None + if len(sys.argv) > 1: - if path.isfile(sys.argv[1]): - fname = sys.argv[1] - form = MainWindow(None,fname,fname if fname!='未命名' else None) + fname = sys.argv[1] + form = MainWindow(fname) form.show() app.exec_() - -main() \ No newline at end of file diff --git a/pyminer/ui/base/widgets/menu_tool_stat_bars.py b/pyminer/ui/base/widgets/menu_tool_stat_bars.py index a53c3fd3..2ca277c5 100644 --- a/pyminer/ui/base/widgets/menu_tool_stat_bars.py +++ b/pyminer/ui/base/widgets/menu_tool_stat_bars.py @@ -1,6 +1,12 @@ -from PyQt5.QtWidgets import QMenuBar, QMenu, QMainWindow, QAction, QToolBar, QStatusBar -from PyQt5.QtGui import QFont -from PyQt5.QtCore import QRect, QCoreApplication, Qt +import os +import sys + +from PyQt5.QtWidgets import QMenuBar, QMenu, QMainWindow, QAction, QToolBar, QStatusBar, QWidget, QApplication, \ + QGridLayout, QPushButton, QSizePolicy, QTabWidget, QSpacerItem, QHBoxLayout, QVBoxLayout, QToolButton, QSplitter, \ + QLabel +from PyQt5.QtGui import QFont, QIcon, QPixmap +from PyQt5.QtCore import QRect, QCoreApplication, Qt, QSize +from pyminer.features.preprocess.PMToolButton import PMToolButton def init_actions(app): @@ -278,6 +284,128 @@ def init_actions(app): app.action_error.setObjectName("action_error") +class PMModernToolbar(QTabWidget): + def __init__(self): + super().__init__() + tab1 = PMToolbarTabHome('主页') + self.addTab(tab1, tab1.tab_name) + tab = PMModernToolbarTab('绘图') + self.addTab(tab, tab.tab_name) + tab = PMModernToolbarTab('APP') + self.addTab(tab, tab.tab_name) + self.setContentsMargins(0, 0, 0, 0) + # self.setFixedHeight(105) + # self.setMaximumHeight(120) + self.setStyleSheet("QTabWidget::pane{border-width: 0px;background-color:#ffffff}" + "QTabBar::tab{border-width: 0px;width:60px;font-size:14px;background-color:#618Bd5;height:30px;}") + # "QTabBar::tab:selected{background-color:#618Bd5;font-size:14px;border-bottom:2px solid #618BE5;}" + # "QTabBar::tab:hover{color:#918Bf5;font-size:14px;border-bottom:2px solid #618BE5;}") + + +class PMModernToolbarTab(QWidget): + def __init__(self, tab_name: str): + super().__init__() + self.tab_name = tab_name + + self.grid_layout = QGridLayout() + self.grid_layout.setContentsMargins(0, 0, 0, 0) + self.grid_layout.setAlignment(Qt.AlignTop | Qt.AlignBottom) + self.grid_layout.setSpacing(0) + layout = QHBoxLayout() + layout.addLayout(self.grid_layout) + layout.addItem(QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)) + layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(layout) + self.setContentsMargins(0, 0, 0, 0) + + def add_action(self, from_row: int, from_column: int, row_span: int, column_span: int, icon_path: str = ''): + if os.path.isfile(icon_path): + b = PMToolButton(text='hahaha', icon=QIcon(icon_path)) + else: + b = PMToolButton(text='hahaha') + b.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) + b.setFixedHeight(30 * row_span) + b.setFixedWidth(30 * column_span) + self.grid_layout.addWidget(b, from_row, from_column, row_span, column_span, + alignment=Qt.AlignTop | Qt.AlignBottom) + + +class PMToolbarTabHome(PMModernToolbarTab): + def __init__(self, tab_name: str): + from pyminer.ui.base.widgets.resources import icon_python, icon_lc_save, icon_New + super().__init__(tab_name) + + icon_open = QIcon() + icon_open.addPixmap( + QPixmap(":/pyqt/source/images/folder.png").scaled(60, 60, Qt.IgnoreAspectRatio, Qt.SmoothTransformation), + QIcon.Normal, QIcon.Off) + + icon_load_data = QIcon( + '/media/hzy/程序/novalide/forgitcommit/pyminer/pyminer/pyminer/ui' + '/source/images/dbqueryedit.png') + self.current_col = 0 + + self.add_default_sized_action(2, icon=icon_New, text='新建\n脚本') + self.add_default_sized_action(2, icon=icon_New, text='新建\n数据') + self.add_splitter(self.current_col) + self.add_default_sized_action(1, text='打开') + self.add_default_sized_action(2, text='导入\n数据', icon=icon_load_data) + self.add_default_sized_action(2, text='保存\n工作区') + self.add_default_sized_action(2, text='插件') + self.add_default_sized_action(2, text='帮助') + self.add_three_stacked_actions(3, text=['分析代码', '运行并计时', '清除命令'], icons=[icon_load_data, icon_open, icon_New]) + + def add_action(self, from_row: int, from_column: int, row_span: int = 3, column_span: int = 2, text: str = '', + icon: QIcon = None, text_under_icon=True): + if text_under_icon: + b = QToolButton() + b.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) + b.setStyleSheet('QToolButton{background-color:white;border:1px;padding:2px 2px} ' + 'QToolButton:hover{background-color:#ededed}' + ) + else: + b = QPushButton() + b.setStyleSheet('QPushButton{background-color:white;border:1px;padding:2px 2px;text-align:left;} ' + 'QPushButton:hover{background-color:#ededed}' + ) + if icon is not None: + b.setIcon(icon) + b.setText(text) + + b.setFixedHeight(25 * row_span) + b.setFixedWidth(30 * column_span) + self.grid_layout.addWidget(b, from_row, from_column, row_span, column_span, + alignment=Qt.AlignTop | Qt.AlignBottom) + d = min(row_span, column_span) + + # b.setIconSize(QSize(30 * d, 30 * d)) + # spacer = QSpacerItem(20,20,QSizePolicy.Expanding,QSizePolicy.Minimum) + # self.grid_layout.addWidget(spacer,2,2) + + def add_default_sized_action(self, col_span, text: str = '', icon: QIcon = None): + self.add_action(0, self.current_col, row_span=3, column_span=col_span, text=text, icon=icon) + self.current_col += col_span + + def add_three_stacked_actions(self, col_span, text=None, icons=None): + if text is None: + text = ['', '', ''] + if icons is None: + icons = [None, None, None] + for i in range(3): + self.add_action(i, self.current_col, row_span=1, column_span=col_span, text=text[i], icon=icons[i], + text_under_icon=False) + # self.add_action(0, self.current_col, row_span=1, column_span=col_span,text=text,icon=icon) + # self.add_action(0, self.current_col, row_span=1, column_span=col_span,text=text,icon=icon) + + def add_splitter(self, xpos): + l = QLabel() + l.setFixedWidth(1) + l.setFixedHeight(75) + # l.setSizePolicy(QSizePolicy.Fixed,QSizePolicy.Expanding) + l.setStyleSheet('QLabel{margin:3px;background-color:#cccccc;border-radius:0px;border:0px}') + self.grid_layout.addWidget(l, 0, xpos, 3, 1) + self.current_col += 1 + + class PMMenuBar(QMenuBar): def __init__(self, main_window: QMainWindow): super().__init__() @@ -322,7 +450,7 @@ class PMMenuBar(QMenuBar): init_actions(self.main_window) self.translate() - def bind_events(self,app): + def bind_events(self, app): self.menu_file.addAction(app.action_menu_new) self.menu_file.addAction(app.action_menu_open) self.menu_file.addSeparator() @@ -508,7 +636,7 @@ class PMToolBarTop(QToolBar): app = self.main_window self.setObjectName("toolBar_left") - def bind_events(self,app): + def bind_events(self, app): self.addAction(app.action_menu_new) self.addAction(app.action_menu_open) self.addSeparator() @@ -536,7 +664,8 @@ class PMToolBarRight(QToolBar): def __init__(self, parent): super().__init__(parent) self.main_window = parent - def bind_events(self,app): + + def bind_events(self, app): _translate = QCoreApplication.translate self.setLayoutDirection(Qt.RightToLeft) self.setObjectName("toolBar_right") @@ -557,3 +686,24 @@ class PMStatusBar(QStatusBar): self.setAutoFillBackground(False) self.setStyleSheet("background-color: rgb(240, 240, 240);") self.setObjectName("statusBar") + + +if __name__ == '__main__': + class TestWidget(QWidget): + def __init__(self): + super().__init__() + layout = QVBoxLayout() + self.setLayout(layout) + layout.addWidget(PMModernToolbar()) + layout.addWidget(QPushButton()) + + + app = QApplication(sys.argv) + + fname = None + + if len(sys.argv) > 1: + fname = sys.argv[1] + form = TestWidget() + form.show() + app.exec_() -- Gitee From 9a7770a026acfb501c2dbc1b45de2469afeb8679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Fri, 28 Aug 2020 00:53:15 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E5=88=B6=E4=BD=9C=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/pmapp.py | 1 + pyminer/pmappmodern.py | 186 +++++++++++++++--- pyminer/ui/base/widgets/codeeditwidget.py | 4 +- .../ui/base/widgets/menu_tool_stat_bars.py | 8 +- 4 files changed, 165 insertions(+), 34 deletions(-) diff --git a/pyminer/pmapp.py b/pyminer/pmapp.py index 0d1bc783..04db4483 100644 --- a/pyminer/pmapp.py +++ b/pyminer/pmapp.py @@ -198,6 +198,7 @@ class MyMainForm(QMainWindow, Ui_MainWindow): self.toolBar_right.bind_events(self) self.toolBar_left.bind_events(self) self.menubar.bind_events(self) + self.menubar.translate() self.__file_path_choose = "" # 将原有的数据存储工具注释掉。方便之后查阅。 diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py index 48c573f2..c100dfd9 100644 --- a/pyminer/pmappmodern.py +++ b/pyminer/pmappmodern.py @@ -1,52 +1,174 @@ import os import sys -from PyQt5.QtCore import pyqtSignal,Qt +import time + +from PyQt5.QtCore import pyqtSignal, Qt,QTimer,QThread # from PyQt5.QtGui import Q +from PyQt5.QtGui import QIcon, QPixmap, QFont from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QListWidget, QTextEdit, QPushButton, QApplication, \ - QWidget, QToolBar, QAction, QVBoxLayout, QMenu - + QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QToolButton, QMenuBar +from typing import List +import threading class MyDockWidget(QDockWidget): def dockLocationChanged(self, area: Qt.DockWidgetArea) -> None: print(area) + from pyminer.ui.base.widgets.menu_tool_stat_bars import PMModernToolbar +def create_icon(icon_path: str = ":/pyqt/source/images/New.png"): + icon = QIcon() + icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off) + return icon + + class PushButtonPane(QWidget): def __init__(self): super().__init__() - layout =QVBoxLayout() - layout.setContentsMargins(0,0,0,0) - - for i in range(2): - b=QPushButton('aa') - b.setStyleSheet('QPushButton{border-width:0px;padding:2px 2px;width:50px;height:30px;}') - m = QMenu('File') - b.setMenu(m) - layout.addWidget( b) - # layout.addWidget(ToolBarPushButton('aa')) - # layout.addWidget(ToolBarPushButton('aa')) - self.setLayout(layout) + self.layout = QVBoxLayout() + self.layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(self.layout) + + def add_buttons(self, button_num: int = 2, text: list = None, icon_path: list = None, + menu: list = None) -> List[QPushButton]: + if text is None: + text = [''] * button_num + if icon_path == None: + icon_path = [None] * button_num + if menu == None: + menu = [None] * button_num + if len(text) != button_num or len(icon_path) != button_num or len(menu) != button_num: + raise Exception('text,icon和menu参数都必须为长为2的可迭代对象。') + if button_num == 2: + height = 30 + font_size = 12 + else: + height = 25 + font_size = 12 + btn_list = [] + for i in range(button_num): + b = self.add_button(text=text[i], icon=create_icon(icon_path[i]), menu=menu[i], height=height, + font_size=font_size) + btn_list.append(b) + return btn_list + + def add_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None, height: int = 30, + font_size: int = 14) -> QPushButton: + b = QPushButton() + b.setText(text) + if icon is not None: + b.setIcon(icon) + if menu is not None: + b.setMenu(menu) + b.setStyleSheet( + 'QPushButton{border:0px;font-size:%dpx;padding:2px 2px;width:80px;height:%dpx;text-align:left;}' % ( + font_size, height) + \ + 'QPushButton:hover{background-color:#ededed;}') + self.layout.addWidget(b) + return b + + +# class PMToolButton(QToolButton): +# def __init__(self): +# super().__init__() +# +class TopToolBar(QToolBar): + def __init__(self): + super().__init__() + self.addWidget(QPushButton('主页')) + + +# 继承QThread +class Runthread(QThread): + # 通过类成员对象定义信号对象 + _signal = pyqtSignal(str) + + def __init__(self): + super(Runthread, self).__init__() + + def __del__(self): + self.wait() + + def run(self): + # for i in range(100): + # time.sleep(0.2) + self._signal.emit('') # 注意这里与_signal = pyqtSignal(str)中的类型相同 + +class PMToolBar(QToolBar): + def __init__(self): + super().__init__() + self.setFixedHeight(80) + + self.add_tool_button('新建\n脚本', create_icon(":/pyqt/source/images/lc_newdoc.png")) + self.add_tool_button('新建', create_icon(":/pyqt/source/images/New.png")) + self.add_tool_button('打开', create_icon(":/pyqt/source/images/lc_open.png")) + pp = PushButtonPane() + pp.add_buttons(2, ['查找文件', '文件比较'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png"]) + self.addWidget(pp) + + self.addSeparator() + + self.add_tool_button('导入\n数据', create_icon(":/pyqt/source/images/lc_dataimport.png")) + self.add_tool_button('保存\n工作区', create_icon(":/pyqt/source/images/lc_save.png")) + + pp = PushButtonPane() + pp.add_buttons(3, ['新建变量', '打开变量', '清除工作区'], + [":/pyqt/source/images/lc_dbnewform.png", ":/pyqt/source/images/lc_open.png", + ":/pyqt/source/images/lc_dbclearquery.png"]) + self.addWidget(pp) + + # timer = QTimer() + # timer.singleShot(1000,self.thread_action) + + self.th = Runthread() + self.th._signal.connect(self.thread_action) + self.th.start() + # th =threading.Thread(target=self.thread_action) + # th.setDaemon(True) + # th.start() + # self.startTimer(1000,) + + def thread_action(self): + time.sleep(2) + self.add_tool_button('设置', create_icon(':/pyqt/source/images/lc_config.png')) + self.add_tool_button('帮助', create_icon(':/pyqt/source/images/lc_helpindex.png')) + + def add_tool_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None): + tb = QToolButton() + tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) + tb.setText(text) + tb.setStyleSheet('QToolButton{height:60px;width:50px;border:0px;}QToolButton::hover{background-color:#ededed;}') + if QIcon is not None: + tb.setIcon(icon) + self.addWidget(tb) + return tb + class MainWindow(QMainWindow): def __init__(self, parent=None): from pyminer.ui.base.widgets.resources import icon_New super(MainWindow, self).__init__(parent) - # self.toolbox = MyDockWidget('tools', self) - # self.addDockWidget(Qt.TopDockWidgetArea,self.toolbox) - # self.toolbox.setObjectName('tools') - # self.toolbox.setWidget(PMModernToolbar()) - # self.toolbox.setMaximumHeight(120) - t=QToolBar() - a=QAction(self) + + t = PMToolBar() + t.setObjectName('toolbar') + # t2 = PMToolBar() + tt = TopToolBar() + tt.setFloatable(False) + tt.setLayoutDirection(Qt.LeftToRight) + tt.setMovable(False) + self.addToolBar(tt) + # t.hide() + # t.setLayoutDirection(Qt.Top) + self.addToolBarBreak(Qt.TopToolBarArea) self.addToolBar(t) - a.setIcon(icon_New) - t.addAction(a) + t.setMovable(False) + # t.add_tool_button('haha', create_icon(":/pyqt/source/images/New.png")) t.addWidget(PushButtonPane()) - t.setFixedHeight(60) - t.setStyleSheet('QToolButton{height:60px;width:60px;}') + # self.toolbox.setFeatures(QDockWidget.NoDockWidgetFeatures) # self.toolbox.DockWidgetClosable @@ -91,7 +213,6 @@ class MainWindow(QMainWindow): ld = self.items2.layoutDirection() fl = self.items.isFloating() - # print(s) print(ld, fl) print(self.items.features()) @@ -101,11 +222,18 @@ class MainWindow(QMainWindow): # self.add_widget_on_dock('hahahahaha',QPushButton('ttttttttttt')) # self.load_layout() - def add_widget_on_dock(self,dock_name:str,widget:QWidget): + + def action_menu_new(self): + print('new') + + def action_menu_open(self): + print('open!') + + def add_widget_on_dock(self, dock_name: str, widget: QWidget): dw = QDockWidget() dw.setObjectName(dock_name) dw.setWidget(widget) - self.addDockWidget(Qt.LeftDockWidgetArea,dw) + self.addDockWidget(Qt.LeftDockWidgetArea, dw) def save_layout(self): p = '/home/hzy/Desktop/qtlayout.ini' diff --git a/pyminer/ui/base/widgets/codeeditwidget.py b/pyminer/ui/base/widgets/codeeditwidget.py index 90d2349d..2a4e6dc5 100644 --- a/pyminer/ui/base/widgets/codeeditwidget.py +++ b/pyminer/ui/base/widgets/codeeditwidget.py @@ -433,7 +433,7 @@ class MainWindow(QMainWindow): # self.fileSaveAction = self.createAction("&Save", self.fileSave, # QKeySequence.Save, "filesave", "Save the file") # self.fileSaveAsAction = self.createAction("Save &As...", - # self.fileSaveAs, icon="filesaveas", + # self.fileSaveAs, icon_path="filesaveas", # tip="Save the file using a new name") # fileQuitAction = self.createAction("&Quit", self.close, # "Ctrl+Q", "filequit", "Close the application") @@ -611,7 +611,7 @@ if __name__ == '__main__': app = QApplication(sys.argv) print(4465) - app.setWindowIcon(QIcon(":/icon.png")) + app.setWindowIcon(QIcon(":/icon_path.png")) fname = None if len(sys.argv) > 1: diff --git a/pyminer/ui/base/widgets/menu_tool_stat_bars.py b/pyminer/ui/base/widgets/menu_tool_stat_bars.py index 2ca277c5..49cd1c56 100644 --- a/pyminer/ui/base/widgets/menu_tool_stat_bars.py +++ b/pyminer/ui/base/widgets/menu_tool_stat_bars.py @@ -223,10 +223,11 @@ def init_actions(app): app.action_dataset_rename.setObjectName("action_dataset_rename") app.action_menu_data_row_filter = QAction(app) app.action_menu_data_row_filter.setObjectName("action_menu_data_row_filter") - app.action_menu_result = QAction(app) + app.action_menu_result = QAction(app) app.action_menu_result.setIcon(icon_lc_dia) app.action_menu_result.setObjectName("action_menu_result") + app.action_menu_sort = QAction(app) app.action_menu_sort.setIcon(icon_lc_dbsortingandgrouping) @@ -393,8 +394,8 @@ class PMToolbarTabHome(PMModernToolbarTab): for i in range(3): self.add_action(i, self.current_col, row_span=1, column_span=col_span, text=text[i], icon=icons[i], text_under_icon=False) - # self.add_action(0, self.current_col, row_span=1, column_span=col_span,text=text,icon=icon) - # self.add_action(0, self.current_col, row_span=1, column_span=col_span,text=text,icon=icon) + # self.add_action(0, self.current_col, row_span=1, column_span=col_span,text=text,icon_path=icon_path) + # self.add_action(0, self.current_col, row_span=1, column_span=col_span,text=text,icon_path=icon_path) def add_splitter(self, xpos): l = QLabel() @@ -412,6 +413,7 @@ class PMMenuBar(QMenuBar): self.main_window = main_window self.setGeometry(QRect(0, 0, 1366, 23)) self.setObjectName("menubar") + self.menu_file = QMenu(self) font = QFont() font.setFamily("Microsoft YaHei UI") -- Gitee From 91a228ab90e6df96c53cb34ea691c4e7c28ecf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Fri, 28 Aug 2020 09:26:30 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E6=9E=84=E5=BB=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/pmappmodern.py | 156 ++++++++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 49 deletions(-) diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py index c100dfd9..8538c716 100644 --- a/pyminer/pmappmodern.py +++ b/pyminer/pmappmodern.py @@ -2,7 +2,7 @@ import os import sys import time -from PyQt5.QtCore import pyqtSignal, Qt,QTimer,QThread +from PyQt5.QtCore import pyqtSignal, Qt, QTimer, QThread # from PyQt5.QtGui import Q from PyQt5.QtGui import QIcon, QPixmap, QFont from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QListWidget, QTextEdit, QPushButton, QApplication, \ @@ -10,6 +10,7 @@ from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QListWidget, from typing import List import threading + class MyDockWidget(QDockWidget): def dockLocationChanged(self, area: Qt.DockWidgetArea) -> None: print(area) @@ -70,14 +71,23 @@ class PushButtonPane(QWidget): return b -# class PMToolButton(QToolButton): -# def __init__(self): -# super().__init__() -# class TopToolBar(QToolBar): def __init__(self): super().__init__() - self.addWidget(QPushButton('主页')) + + def add_button(self, name: str, text: str): + b = QPushButton(text) + b.setObjectName(name) + + self.addWidget(b) + + def get_button(self, name: str): + return self.findChild(QPushButton, name) + + # self.addWidget() + + # self.addWidget(QPushButton('主页')) + # self.addWidget(QPushButton('主页')) # 继承QThread @@ -96,10 +106,28 @@ class Runthread(QThread): # time.sleep(0.2) self._signal.emit('') # 注意这里与_signal = pyqtSignal(str)中的类型相同 + class PMToolBar(QToolBar): + tab_button: QPushButton = None + + def __init__(self): + super().__init__() + self.setFixedHeight(90) + + def add_tool_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None): + tb = QToolButton() + tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) + tb.setText(text) + tb.setStyleSheet('QToolButton{height:60px;width:50px;border:0px;}QToolButton::hover{background-color:#ededed;}') + if QIcon is not None: + tb.setIcon(icon) + self.addWidget(tb) + return tb + + +class PMToolBarHome(PMToolBar): def __init__(self): super().__init__() - self.setFixedHeight(80) self.add_tool_button('新建\n脚本', create_icon(":/pyqt/source/images/lc_newdoc.png")) self.add_tool_button('新建', create_icon(":/pyqt/source/images/New.png")) @@ -119,55 +147,87 @@ class PMToolBar(QToolBar): [":/pyqt/source/images/lc_dbnewform.png", ":/pyqt/source/images/lc_open.png", ":/pyqt/source/images/lc_dbclearquery.png"]) self.addWidget(pp) - - # timer = QTimer() - # timer.singleShot(1000,self.thread_action) - - self.th = Runthread() - self.th._signal.connect(self.thread_action) - self.th.start() - # th =threading.Thread(target=self.thread_action) - # th.setDaemon(True) - # th.start() - # self.startTimer(1000,) - - def thread_action(self): - time.sleep(2) + self.addSeparator() self.add_tool_button('设置', create_icon(':/pyqt/source/images/lc_config.png')) self.add_tool_button('帮助', create_icon(':/pyqt/source/images/lc_helpindex.png')) - def add_tool_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None): - tb = QToolButton() - tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) - tb.setText(text) - tb.setStyleSheet('QToolButton{height:60px;width:50px;border:0px;}QToolButton::hover{background-color:#ededed;}') - if QIcon is not None: - tb.setIcon(icon) - self.addWidget(tb) - return tb +class PMToolBarEditor(PMToolBar): + def __init__(self): + super().__init__() + self.add_tool_button('新建\n脚本', create_icon(':/pyqt/source/images/lc_newdoc.png')) + self.add_tool_button('打开\n脚本', create_icon(':/pyqt/source/images/lc_open.png')) + self.add_tool_button('打开\n脚本', create_icon(':/pyqt/source/images/lc_save.png')) + pp = PushButtonPane() + pp.add_buttons(3, ['查找文件', '剪贴板', '打印'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png", + ':/pyqt/source/images/lc_print.png']) + self.addWidget(pp) + self.addSeparator() + pp = PushButtonPane() + pp.add_buttons(3, ['查找', '替换', '跳转到行'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png", + ':/pyqt/source/images/lc_print.png']) + pp = PushButtonPane() + pp.add_buttons(2, ['批量注释', '缩进'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png"]) + self.addWidget(pp) + pp = PushButtonPane() + pp.add_buttons(2, ['取消注释', '减少缩进'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png"]) + self.addWidget(pp) + self.addSeparator() + self.add_tool_button('运行', create_icon(':/pyqt/source/images/run_exc.png')) -class MainWindow(QMainWindow): - def __init__(self, parent=None): - from pyminer.ui.base.widgets.resources import icon_New - super(MainWindow, self).__init__(parent) +class BaseMainWindow(QMainWindow): + toolbars = {} - t = PMToolBar() - t.setObjectName('toolbar') - # t2 = PMToolBar() + def init_toolbar(self): tt = TopToolBar() tt.setFloatable(False) tt.setLayoutDirection(Qt.LeftToRight) tt.setMovable(False) + tt.setObjectName('tab_bar_for_tool_bar') + self.addToolBar(tt) - # t.hide() - # t.setLayoutDirection(Qt.Top) + self.top_toolbar_tab = tt + + self.add_toolbar('toolbar_home', PMToolBarHome(), text='主页') + self.add_toolbar('toolbar_plot', PMToolBar(), text='绘图') + self.add_toolbar('toolbar_editor', PMToolBarEditor(), text='编辑器') + + self.switch_toolbar('toolbar_home') + + def switch_toolbar(self, name: str): + for k in self.toolbars.keys(): + if k == name: + self.toolbars[k].show() + self.toolbars[k].tab_button.setStyleSheet('QPushButton{color:#444444;background-color:#ffffff;border:0px;width:100px;}') + else: + self.toolbars[k].hide() + self.toolbars[k].tab_button.setStyleSheet('QPushButton{color:#efefef;background-color:#1234ee;border:0px;width:100px;}') + + def add_toolbar(self, name: str, toolbar: QToolBar, text: str = 'untitled toolbar'): + b = QPushButton(text) + self.top_toolbar_tab.addWidget(b) + toolbar.tab_button = b + b.clicked.connect(lambda: self.switch_toolbar(name)) + self.addToolBarBreak(Qt.TopToolBarArea) - self.addToolBar(t) - t.setMovable(False) - # t.add_tool_button('haha', create_icon(":/pyqt/source/images/New.png")) - t.addWidget(PushButtonPane()) + self.addToolBar(toolbar) + toolbar.setObjectName(name) + self.toolbars[name] = toolbar + toolbar.setMovable(False) + toolbar.setFloatable(False) + toolbar.addWidget(PushButtonPane()) + + +class MainWindow(BaseMainWindow): + def __init__(self, parent=None): + from pyminer.ui.base.widgets.resources import icon_New + super(MainWindow, self).__init__(parent) + self.init_toolbar() # self.toolbox.setFeatures(QDockWidget.NoDockWidgetFeatures) # self.toolbox.DockWidgetClosable @@ -213,15 +273,10 @@ class MainWindow(QMainWindow): ld = self.items2.layoutDirection() fl = self.items.isFloating() - # print(s) print(ld, fl) print(self.items.features()) - # print(self.items4.layoutDirection()) - # print(self.items.layoutDirection(), self.items4.layoutDirection()) self.setWindowTitle('Dock 例子') - # self.add_widget_on_dock('hahahahaha',QPushButton('ttttttttttt')) - # self.load_layout() - + self.load_layout() def action_menu_new(self): print('new') @@ -251,6 +306,9 @@ class MainWindow(QMainWindow): def on_boot_finished(self): pass + def get_toolbar_list(self): + pass + if __name__ == '__main__': app = QApplication(sys.argv) -- Gitee From 2521ab121d9c8986dc0a76511a68e042255bbcaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Fri, 28 Aug 2020 20:52:10 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=8F=92?= =?UTF-8?q?=E5=85=A5=E8=8F=9C=E5=8D=95=E7=9A=84=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/pmapp.py | 3 + pyminer/pmappmodern.py | 207 ++++++++++------------ pyminer/ui/base/widgets/codeeditwidget.py | 145 +++++++++++++-- pyminer/ui/base/widgets/consolewidget.py | 2 + pyminer/ui/base/widgets/controlpanel.py | 3 + pyminer/ui/base/widgets/treeviews.py | 2 +- 6 files changed, 239 insertions(+), 123 deletions(-) diff --git a/pyminer/pmapp.py b/pyminer/pmapp.py index 04db4483..4e51d185 100644 --- a/pyminer/pmapp.py +++ b/pyminer/pmapp.py @@ -188,12 +188,15 @@ class MyMainForm(QMainWindow, Ui_MainWindow): super().__init__(parent) self.setupUi(self) self.center() + self.page_data.setup_ui() + self.console_widget.setup_ui() self.page_data.bind_events(self) self.page_access.bind_events(self) self.page_model.bind_events(self) self.page_plot.bind_events(self) self.page_stats.bind_events(self) + init_actions(self) self.toolBar_right.bind_events(self) self.toolBar_left.bind_events(self) diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py index 8538c716..dba5aec6 100644 --- a/pyminer/pmappmodern.py +++ b/pyminer/pmappmodern.py @@ -1,22 +1,32 @@ +''' +任务:写出显示浮动窗口数量的部件(下拉式菜单等),点击之后,可以进行浮动窗口显示或者隐藏。 +''' import os import sys import time from PyQt5.QtCore import pyqtSignal, Qt, QTimer, QThread # from PyQt5.QtGui import Q -from PyQt5.QtGui import QIcon, QPixmap, QFont -from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QListWidget, QTextEdit, QPushButton, QApplication, \ - QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QToolButton, QMenuBar -from typing import List -import threading +from PyQt5.QtGui import QIcon, QPixmap, QFont, QCloseEvent +from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow,QPushButton, QApplication, \ + QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QToolButton +from typing import List, Dict, Callable class MyDockWidget(QDockWidget): - def dockLocationChanged(self, area: Qt.DockWidgetArea) -> None: - print(area) + def __init__(self, text='', parent: QMainWindow = None): + super().__init__(text, parent) + self.parent = parent + print(self.titleBarWidget()) + def closeEvent(self, e): + print('close') + d1 = self.parent.dock_widgets + print(d1) + self.parent.dock_widgets.pop(self.objectName()) + d2 = self.parent.dock_widgets + print(d2) -from pyminer.ui.base.widgets.menu_tool_stat_bars import PMModernToolbar def create_icon(icon_path: str = ":/pyqt/source/images/New.png"): @@ -84,11 +94,6 @@ class TopToolBar(QToolBar): def get_button(self, name: str): return self.findChild(QPushButton, name) - # self.addWidget() - - # self.addWidget(QPushButton('主页')) - # self.addWidget(QPushButton('主页')) - # 继承QThread class Runthread(QThread): @@ -109,6 +114,7 @@ class Runthread(QThread): class PMToolBar(QToolBar): tab_button: QPushButton = None + widget_dic = {} def __init__(self): super().__init__() @@ -152,36 +158,9 @@ class PMToolBarHome(PMToolBar): self.add_tool_button('帮助', create_icon(':/pyqt/source/images/lc_helpindex.png')) -class PMToolBarEditor(PMToolBar): - def __init__(self): - super().__init__() - self.add_tool_button('新建\n脚本', create_icon(':/pyqt/source/images/lc_newdoc.png')) - self.add_tool_button('打开\n脚本', create_icon(':/pyqt/source/images/lc_open.png')) - self.add_tool_button('打开\n脚本', create_icon(':/pyqt/source/images/lc_save.png')) - pp = PushButtonPane() - pp.add_buttons(3, ['查找文件', '剪贴板', '打印'], - [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png", - ':/pyqt/source/images/lc_print.png']) - self.addWidget(pp) - self.addSeparator() - pp = PushButtonPane() - pp.add_buttons(3, ['查找', '替换', '跳转到行'], - [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png", - ':/pyqt/source/images/lc_print.png']) - pp = PushButtonPane() - pp.add_buttons(2, ['批量注释', '缩进'], - [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png"]) - self.addWidget(pp) - pp = PushButtonPane() - pp.add_buttons(2, ['取消注释', '减少缩进'], - [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png"]) - self.addWidget(pp) - self.addSeparator() - self.add_tool_button('运行', create_icon(':/pyqt/source/images/run_exc.png')) - - class BaseMainWindow(QMainWindow): - toolbars = {} + toolbars: Dict[str, QToolBar] = {} + dock_widgets: Dict[str, MyDockWidget] = {} def init_toolbar(self): tt = TopToolBar() @@ -195,7 +174,7 @@ class BaseMainWindow(QMainWindow): self.add_toolbar('toolbar_home', PMToolBarHome(), text='主页') self.add_toolbar('toolbar_plot', PMToolBar(), text='绘图') - self.add_toolbar('toolbar_editor', PMToolBarEditor(), text='编辑器') + # self.add_toolbar('toolbar_editor', PMToolBarEditor(), text='编辑器') self.switch_toolbar('toolbar_home') @@ -203,12 +182,15 @@ class BaseMainWindow(QMainWindow): for k in self.toolbars.keys(): if k == name: self.toolbars[k].show() - self.toolbars[k].tab_button.setStyleSheet('QPushButton{color:#444444;background-color:#ffffff;border:0px;width:100px;}') + self.toolbars[k].tab_button.setStyleSheet( + 'QPushButton{color:#444444;background-color:#ffffff;border:0px;width:100px;}') else: self.toolbars[k].hide() - self.toolbars[k].tab_button.setStyleSheet('QPushButton{color:#efefef;background-color:#1234ee;border:0px;width:100px;}') + self.toolbars[k].tab_button.setStyleSheet( + 'QPushButton{color:#efefef;background-color:#1234ee;border:0px;width:100px;}') def add_toolbar(self, name: str, toolbar: QToolBar, text: str = 'untitled toolbar'): + b = QPushButton(text) self.top_toolbar_tab.addWidget(b) toolbar.tab_button = b @@ -222,61 +204,47 @@ class BaseMainWindow(QMainWindow): toolbar.setFloatable(False) toolbar.addWidget(PushButtonPane()) + def save_layout(self): + p = '/home/hzy/Desktop/qtlayout.ini' + with open(p, 'wb') as f: + s = self.saveState() + f.write(s) + + def load_layout(self): + p = '/home/hzy/Desktop/qtlayout.ini' + if os.path.exists(p): + with open(p, 'rb') as f: + s = f.read() + self.restoreState(s) + + +from pyminer.ui.base.widgets.treeviews import PMFilesTreeview +from pyminer.ui.base.widgets.consolewidget import ConsoleWidget +from pyminer.ui.base.widgets.controlpanel import PMPageData +from pyminer.ui.base.widgets.codeeditwidget import PMCodeEditTabWidget + class MainWindow(BaseMainWindow): + setupui_tasks: List[Callable] = [] + boot_timer: QTimer = None + def __init__(self, parent=None): from pyminer.ui.base.widgets.resources import icon_New super(MainWindow, self).__init__(parent) + import pyminer.pmutil + pyminer.pmutil._main_window = self self.init_toolbar() - # self.toolbox.setFeatures(QDockWidget.NoDockWidgetFeatures) - # self.toolbox.DockWidgetClosable - - # 创建QDockWidget窗口(标题,自身窗口) - self.items = MyDockWidget('Dockable', self) - self.items.setObjectName('1') - self.items2 = QDockWidget('Dockable', self) - self.items2.setObjectName('2') - self.items3 = QDockWidget('Dockable', self) - self.items3.setObjectName('3') - self.items4 = QDockWidget('Dockable', self) - self.items4.setObjectName('4') - - # 实例化列表窗口,添加几个条目 - self.listWidget = QListWidget() - self.listWidget.addItem('Item1') - self.listWidget.addItem('Item2') - self.listWidget.addItem('Item3') - self.listWidget.addItem('Item4') - - # 在窗口区域设置QWidget,添加列表控件 - self.items.setWidget(self.listWidget) - self.items2.setWidget(QTextEdit()) - self.items3.setWidget(QTextEdit()) - # self.items4.setWidget(QTextEdit()) - - # 设置dock窗口是否可以浮动,True,运行浮动在外面,自动与主界面脱离,False,默认浮动主窗口内,可以手动脱离 - self.items.setFloating(False) - self.items2.setFloating(False) - self.items3.setFloating(False) - # self.items4.setFloating(False) - # 设置QTextEdit为中央小控件 - b = QPushButton('此为中央控件,点击保存布局') - b.clicked.connect(self.save_layout) - self.setCentralWidget(b) - # 将窗口放置在中央小控件的右侧 - self.addDockWidget(Qt.RightDockWidgetArea, self.items) - self.addDockWidget(Qt.LeftDockWidgetArea, self.items2) - self.addDockWidget(Qt.RightDockWidgetArea, self.items3) - self.addDockWidget(Qt.LeftDockWidgetArea, self.items4) - - ld = self.items2.layoutDirection() - fl = self.items.isFloating() - - print(ld, fl) - print(self.items.features()) + self.setDockNestingEnabled(True) self.setWindowTitle('Dock 例子') - self.load_layout() + self.add_widget_on_dock('tree_widget', PMFilesTreeview(self)) + self.add_widget_on_dock('console_widget', ConsoleWidget(self)) + self.add_widget_on_dock('control_panel', PMPageData()) + self.add_widget_on_dock('editor_panel', PMCodeEditTabWidget()) + + self.switch_toolbar('toolbar_home') + self.show() + self.on_boot_finished() def action_menu_new(self): print('new') @@ -284,34 +252,55 @@ class MainWindow(BaseMainWindow): def action_menu_open(self): print('open!') - def add_widget_on_dock(self, dock_name: str, widget: QWidget): - dw = QDockWidget() + def add_widget_on_dock(self, dock_name: str, widget: QWidget, text: str = ''): + dw = MyDockWidget(text=text, parent=self) dw.setObjectName(dock_name) dw.setWidget(widget) - self.addDockWidget(Qt.LeftDockWidgetArea, dw) - - def save_layout(self): - p = '/home/hzy/Desktop/qtlayout.ini' - with open(p, 'wb') as f: - s = self.saveState() - f.write(s) + if hasattr(widget, 'load_actions'): + widget.load_actions() + if hasattr(widget, 'setup_ui'): + if hasattr(widget, 'show_directly'): + if widget.show_directly: + widget.setup_ui() + else: + self.setupui_tasks.append(widget.setup_ui) + else: + self.setupui_tasks.append(widget.setup_ui) + if len(list(self.dock_widgets.keys())) % 2 == 0: - def load_layout(self): - p = '/home/hzy/Desktop/qtlayout.ini' - if os.path.exists(p): - with open(p, 'rb') as f: - s = f.read() - self.restoreState(s) + self.addDockWidget(Qt.LeftDockWidgetArea, dw) + else: + self.addDockWidget(Qt.RightDockWidgetArea, dw) + if dock_name not in self.dock_widgets.keys(): + self.dock_widgets[dock_name] = dw + else: + raise Exception('docked widget name: \'%s\' is already used!' % dock_name) def on_boot_finished(self): - pass + + self.boot_timer = QTimer() + self.boot_timer.start(50) + self.boot_timer.timeout.connect(self.on_boot_timer_timeout) + + def on_boot_timer_timeout(self): + if len(self.setupui_tasks) > 0: + task = self.setupui_tasks.pop(0) + print('start:', task) + task() + else: + self.boot_timer.stop() + print('boot ended!') def get_toolbar_list(self): pass + def closeEvent(self, a0: QCloseEvent) -> None: + self.save_layout() + super().closeEvent(a0) + if __name__ == '__main__': app = QApplication(sys.argv) demo = MainWindow() - demo.show() + sys.exit(app.exec_()) diff --git a/pyminer/ui/base/widgets/codeeditwidget.py b/pyminer/ui/base/widgets/codeeditwidget.py index 2a4e6dc5..75c9a964 100644 --- a/pyminer/ui/base/widgets/codeeditwidget.py +++ b/pyminer/ui/base/widgets/codeeditwidget.py @@ -5,20 +5,88 @@ https://blog.csdn.net/xiaoyangyang20/article/details/68923133 ''' import os import sys +from typing import List sys.path.append('/media/hzy/程序/novalide/forgitcommit/pyminer/pyminer') from PyQt5.QtCore import QEvent, QFile, QFileInfo, QIODevice, QRegExp, QTextStream, Qt from PyQt5.QtWidgets import QAction, QApplication, QFileDialog, QMainWindow, QMessageBox, QTextEdit, QTabWidget, \ - QVBoxLayout,QMessageBox + QVBoxLayout, QMessageBox, QWidget, QPushButton, QMenu, QToolBar, QToolButton from PyQt5.QtGui import QFont, QIcon, QColor, QKeySequence, QSyntaxHighlighter, QTextCharFormat, QTextCursor, QCursor, \ - QKeyEvent + QKeyEvent, QPixmap # import pyqtresource_rc __version__ = "1.1.0" +def create_icon(icon_path: str = ":/pyqt/source/images/New.png"): + icon = QIcon() + icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off) + return icon + +class PushButtonPane(QWidget): + def __init__(self): + super().__init__() + self.layout = QVBoxLayout() + self.layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(self.layout) + + def add_buttons(self, button_num: int = 2, text: list = None, icon_path: list = None, + menu: list = None) -> List[QPushButton]: + if text is None: + text = [''] * button_num + if icon_path == None: + icon_path = [None] * button_num + if menu == None: + menu = [None] * button_num + if len(text) != button_num or len(icon_path) != button_num or len(menu) != button_num: + raise Exception('text,icon和menu参数都必须为长为2的可迭代对象。') + if button_num == 2: + height = 30 + font_size = 12 + else: + height = 25 + font_size = 12 + btn_list = [] + for i in range(button_num): + b = self.add_button(text=text[i], icon=create_icon(icon_path[i]), menu=menu[i], height=height, + font_size=font_size) + btn_list.append(b) + return btn_list + + def add_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None, height: int = 30, + font_size: int = 14) -> QPushButton: + b = QPushButton() + b.setText(text) + if icon is not None: + b.setIcon(icon) + if menu is not None: + b.setMenu(menu) + b.setStyleSheet( + 'QPushButton{border:0px;font-size:%dpx;padding:2px 2px;width:80px;height:%dpx;text-align:left;}' % ( + font_size, height) + \ + 'QPushButton:hover{background-color:#ededed;}') + self.layout.addWidget(b) + return b + +class PMToolBar(QToolBar): + tab_button: QPushButton = None + widget_dic = {} + + def __init__(self): + super().__init__() + self.setFixedHeight(90) + + def add_tool_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None): + tb = QToolButton() + tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) + tb.setText(text) + tb.setStyleSheet('QToolButton{height:60px;width:50px;border:0px;}QToolButton::hover{background-color:#ededed;}') + if QIcon is not None: + tb.setIcon(icon) + self.addWidget(tb) + return tb class PythonHighlighter(QSyntaxHighlighter): Rules = [] @@ -193,11 +261,11 @@ class PMCodeEdit(QTextEdit): # self.textChanged.conn/ect(lambda :print('text changed!!')) def on_text_changed(self): - print('text changed',self.modified) - if self.modified==True: + print('text changed', self.modified) + if self.modified == True: return else: - self.modified=True + self.modified = True self.updateUi() def updateUi(self): @@ -356,20 +424,69 @@ class PMCodeEdit(QTextEdit): with open(self.path, 'w') as f: f.write(self.toPlainText()) - self.modified=False + self.modified = False self.updateUi() def on_close_request(self): - if self.modified==True: - answer =QMessageBox.question(self,'保存文件','%s有未保存的更改,是否要保存?'%self.filename,QMessageBox.Yes|QMessageBox.No,QMessageBox.Yes) - if answer==QMessageBox.No: + if self.modified == True: + answer = QMessageBox.question(self, '保存文件', '%s有未保存的更改,是否要保存?' % self.filename, + QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) + if answer == QMessageBox.No: return else: self.save() + class PMCodeEditTabWidget(QTabWidget): def __init__(self): super().__init__() + self.show_directly = True + + def init_toolbar(self): + ''' + 新建一个toolbar并且插入到主界面中。 + Returns: + + ''' + toolbar = PMToolBar() + toolbar.add_tool_button('新建\n脚本', create_icon(':/pyqt/source/images/lc_newdoc.png')) + toolbar.add_tool_button('打开\n脚本', create_icon(':/pyqt/source/images/lc_open.png')) + toolbar.add_tool_button('打开\n脚本', create_icon(':/pyqt/source/images/lc_save.png')) + pp = PushButtonPane() + pp.add_buttons(3, ['查找文件', '剪贴板', '打印'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png", + ':/pyqt/source/images/lc_print.png']) + toolbar.addWidget(pp) + toolbar.addSeparator() + + pp = PushButtonPane() + buttons=pp.add_buttons(3, ['查找', '替换', '跳转到行'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png", + ':/pyqt/source/images/lc_print.png']) + buttons[0].clicked.connect(lambda :print('查找!')) + buttons[1].clicked.connect(lambda :print('替换!')) + buttons[2].clicked.connect(lambda :print('跳转!')) + toolbar.addWidget(pp) + + pp = PushButtonPane() + pp.add_buttons(2, ['批量注释', '缩进'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png"]) + toolbar.addWidget(pp) + pp = PushButtonPane() + pp.add_buttons(2, ['取消注释', '减少缩进'], + [":/pyqt/source/images/lc_searchdialog.png", ":/pyqt/source/images/lc_pickthrough.png"]) + toolbar.addWidget(pp) + toolbar.addSeparator() + toolbar.add_tool_button('运行', create_icon(':/pyqt/source/images/run_exc.png')) + self.toolbar = toolbar + + + def setup_ui(self): + self.init_toolbar() + + from pyminer.pmutil import get_main_window + mw = get_main_window() + mw.add_toolbar('toolbar_editor', self.toolbar, text='编辑器') self.editor_tabs = [PMCodeEdit(self), PMCodeEdit(self), PMCodeEdit(self)] for tab in self.editor_tabs: self.addTab(tab, tab.filename) @@ -377,7 +494,8 @@ class PMCodeEditTabWidget(QTabWidget): self.setTabsClosable(True) self.tabCloseRequested.connect(self.on_tab_close_request) - def on_tab_close_request(self,close_index:int): + + def on_tab_close_request(self, close_index: int): tab_to_close = self.widget(close_index) tab_to_close.deleteLater() tab_to_close.on_close_request() @@ -393,15 +511,16 @@ class PMCodeEditTabWidget(QTabWidget): print(self.widget(0), self.count()) # cursor.movePosition(QTextCursor.NextCharacter, # QTextCursor.KeepAnchor, 1) + def refresh(self): for tab_id in range(self.count()): modified = self.widget(tab_id).modified filename = self.widget(tab_id).filename if not modified: - self.setTabText(tab_id,filename) + self.setTabText(tab_id, filename) else: - if filename!='*': - self.setTabText(tab_id, filename+' *') + if filename != '*': + self.setTabText(tab_id, filename + ' *') print(self.widget(0), self.count()) diff --git a/pyminer/ui/base/widgets/consolewidget.py b/pyminer/ui/base/widgets/consolewidget.py index 1c1a19cd..29f0b0b7 100644 --- a/pyminer/ui/base/widgets/consolewidget.py +++ b/pyminer/ui/base/widgets/consolewidget.py @@ -48,6 +48,8 @@ class ConsoleWidget(RichJupyterWidget): def __init__(self, *args, **kwargs): super(ConsoleWidget, self).__init__(*args, **kwargs) + + def setup_ui(self): self.kernel_manager = None self.kernel_client = None # initialize by thread diff --git a/pyminer/ui/base/widgets/controlpanel.py b/pyminer/ui/base/widgets/controlpanel.py index 70b4c57a..ef9caa4f 100644 --- a/pyminer/ui/base/widgets/controlpanel.py +++ b/pyminer/ui/base/widgets/controlpanel.py @@ -13,6 +13,8 @@ class ControlPanel(): class PMPageData(QWidget): def __init__(self): super().__init__() + + def setup_ui(self): from .resources import icon_lc_connectorcurve, icon_transition_random, icon_formfilternavigator, \ icon_data_provider, icon_lc_togglemergecells, icon_lc_datadatapilotrun, icon_delete_columns, \ icon_mergedocuments, icon_lc_accepttrackedchange, \ @@ -509,6 +511,7 @@ class PMPagePlot(QWidget): self.btn_plot_radar_4.setObjectName("btn_plot_radar_4") self.gridLayout_3.addWidget(self.btn_plot_radar_4, 3, 1, 1, 1) self.translate() + def translate(self): _translate = QCoreApplication.translate self.btn_plot_box.setText(_translate("MainWindow", "盒形图")) diff --git a/pyminer/ui/base/widgets/treeviews.py b/pyminer/ui/base/widgets/treeviews.py index 4460053a..3505028d 100644 --- a/pyminer/ui/base/widgets/treeviews.py +++ b/pyminer/ui/base/widgets/treeviews.py @@ -41,7 +41,7 @@ class PMFilesTreeview(QTreeView): # 文件管理器 # my_dir = QDir.rootPath() - my_dir = os.path.dirname(get_root_dir()) + my_dir = os.path.dirname('')#get_root_dir()) self.model = RewriteQFileSystemModel() self.model.setRootPath(my_dir) # self.setRootIndex(self.model.index(QDir.homePath())) -- Gitee From 513ae1cec881dcdc4af9175145ef57a935b91486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Fri, 28 Aug 2020 21:27:26 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E6=95=B4=E7=90=86=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/pmappmodern.py | 194 ++---------------- .../generalwidgets/buttons/__init__.py | 1 + .../generalwidgets/buttons/pmpushbuttons.py | 52 +++++ .../generalwidgets/sourcemgr/__init__.py | 1 + .../generalwidgets/sourcemgr/iconutils.py | 7 + .../generalwidgets/threads/__init__.py | 0 .../generalwidgets/toolbars/__init__.py | 1 + .../generalwidgets/toolbars/toolbar.py | 35 ++++ .../widgets/generalwidgets/window/__init__.py | 2 + .../generalwidgets/window/pmdockwidget.py | 26 +++ .../generalwidgets/window/pmmainwindow.py | 78 +++++++ 11 files changed, 222 insertions(+), 175 deletions(-) create mode 100644 pyminer/ui/base/widgets/generalwidgets/buttons/__init__.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/buttons/pmpushbuttons.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/sourcemgr/__init__.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/sourcemgr/iconutils.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/threads/__init__.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/window/__init__.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py index dba5aec6..4073e087 100644 --- a/pyminer/pmappmodern.py +++ b/pyminer/pmappmodern.py @@ -6,93 +6,20 @@ import sys import time from PyQt5.QtCore import pyqtSignal, Qt, QTimer, QThread -# from PyQt5.QtGui import Q from PyQt5.QtGui import QIcon, QPixmap, QFont, QCloseEvent -from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow,QPushButton, QApplication, \ - QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QToolButton +from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QPushButton, QApplication, \ + QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QToolButton, QMessageBox from typing import List, Dict, Callable +from pyminer.ui.base.widgets.generalwidgets.sourcemgr import create_icon +from pyminer.ui.base.widgets.generalwidgets.buttons import PushButtonPane +from pyminer.ui.base.widgets.generalwidgets.window import PMDockWidget, BaseMainWindow +from pyminer.ui.base.widgets.generalwidgets.toolbars import PMToolBar -class MyDockWidget(QDockWidget): - def __init__(self, text='', parent: QMainWindow = None): - super().__init__(text, parent) - self.parent = parent - print(self.titleBarWidget()) - - def closeEvent(self, e): - print('close') - d1 = self.parent.dock_widgets - print(d1) - self.parent.dock_widgets.pop(self.objectName()) - d2 = self.parent.dock_widgets - print(d2) - - - -def create_icon(icon_path: str = ":/pyqt/source/images/New.png"): - icon = QIcon() - icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off) - return icon - - -class PushButtonPane(QWidget): - def __init__(self): - super().__init__() - self.layout = QVBoxLayout() - self.layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(self.layout) - - def add_buttons(self, button_num: int = 2, text: list = None, icon_path: list = None, - menu: list = None) -> List[QPushButton]: - if text is None: - text = [''] * button_num - if icon_path == None: - icon_path = [None] * button_num - if menu == None: - menu = [None] * button_num - if len(text) != button_num or len(icon_path) != button_num or len(menu) != button_num: - raise Exception('text,icon和menu参数都必须为长为2的可迭代对象。') - if button_num == 2: - height = 30 - font_size = 12 - else: - height = 25 - font_size = 12 - btn_list = [] - for i in range(button_num): - b = self.add_button(text=text[i], icon=create_icon(icon_path[i]), menu=menu[i], height=height, - font_size=font_size) - btn_list.append(b) - return btn_list - - def add_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None, height: int = 30, - font_size: int = 14) -> QPushButton: - b = QPushButton() - b.setText(text) - if icon is not None: - b.setIcon(icon) - if menu is not None: - b.setMenu(menu) - b.setStyleSheet( - 'QPushButton{border:0px;font-size:%dpx;padding:2px 2px;width:80px;height:%dpx;text-align:left;}' % ( - font_size, height) + \ - 'QPushButton:hover{background-color:#ededed;}') - self.layout.addWidget(b) - return b - - -class TopToolBar(QToolBar): - def __init__(self): - super().__init__() - - def add_button(self, name: str, text: str): - b = QPushButton(text) - b.setObjectName(name) - - self.addWidget(b) - - def get_button(self, name: str): - return self.findChild(QPushButton, name) +from pyminer.ui.base.widgets.treeviews import PMFilesTreeview +from pyminer.ui.base.widgets.consolewidget import ConsoleWidget +from pyminer.ui.base.widgets.controlpanel import PMPageData +from pyminer.ui.base.widgets.codeeditwidget import PMCodeEditTabWidget # 继承QThread @@ -112,25 +39,6 @@ class Runthread(QThread): self._signal.emit('') # 注意这里与_signal = pyqtSignal(str)中的类型相同 -class PMToolBar(QToolBar): - tab_button: QPushButton = None - widget_dic = {} - - def __init__(self): - super().__init__() - self.setFixedHeight(90) - - def add_tool_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None): - tb = QToolButton() - tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) - tb.setText(text) - tb.setStyleSheet('QToolButton{height:60px;width:50px;border:0px;}QToolButton::hover{background-color:#ededed;}') - if QIcon is not None: - tb.setIcon(icon) - self.addWidget(tb) - return tb - - class PMToolBarHome(PMToolBar): def __init__(self): super().__init__() @@ -158,89 +66,25 @@ class PMToolBarHome(PMToolBar): self.add_tool_button('帮助', create_icon(':/pyqt/source/images/lc_helpindex.png')) -class BaseMainWindow(QMainWindow): - toolbars: Dict[str, QToolBar] = {} - dock_widgets: Dict[str, MyDockWidget] = {} - - def init_toolbar(self): - tt = TopToolBar() - tt.setFloatable(False) - tt.setLayoutDirection(Qt.LeftToRight) - tt.setMovable(False) - tt.setObjectName('tab_bar_for_tool_bar') - - self.addToolBar(tt) - self.top_toolbar_tab = tt - - self.add_toolbar('toolbar_home', PMToolBarHome(), text='主页') - self.add_toolbar('toolbar_plot', PMToolBar(), text='绘图') - # self.add_toolbar('toolbar_editor', PMToolBarEditor(), text='编辑器') - - self.switch_toolbar('toolbar_home') - - def switch_toolbar(self, name: str): - for k in self.toolbars.keys(): - if k == name: - self.toolbars[k].show() - self.toolbars[k].tab_button.setStyleSheet( - 'QPushButton{color:#444444;background-color:#ffffff;border:0px;width:100px;}') - else: - self.toolbars[k].hide() - self.toolbars[k].tab_button.setStyleSheet( - 'QPushButton{color:#efefef;background-color:#1234ee;border:0px;width:100px;}') - - def add_toolbar(self, name: str, toolbar: QToolBar, text: str = 'untitled toolbar'): - - b = QPushButton(text) - self.top_toolbar_tab.addWidget(b) - toolbar.tab_button = b - b.clicked.connect(lambda: self.switch_toolbar(name)) - - self.addToolBarBreak(Qt.TopToolBarArea) - self.addToolBar(toolbar) - toolbar.setObjectName(name) - self.toolbars[name] = toolbar - toolbar.setMovable(False) - toolbar.setFloatable(False) - toolbar.addWidget(PushButtonPane()) - - def save_layout(self): - p = '/home/hzy/Desktop/qtlayout.ini' - with open(p, 'wb') as f: - s = self.saveState() - f.write(s) - - def load_layout(self): - p = '/home/hzy/Desktop/qtlayout.ini' - if os.path.exists(p): - with open(p, 'rb') as f: - s = f.read() - self.restoreState(s) - - -from pyminer.ui.base.widgets.treeviews import PMFilesTreeview -from pyminer.ui.base.widgets.consolewidget import ConsoleWidget -from pyminer.ui.base.widgets.controlpanel import PMPageData -from pyminer.ui.base.widgets.codeeditwidget import PMCodeEditTabWidget - - class MainWindow(BaseMainWindow): setupui_tasks: List[Callable] = [] boot_timer: QTimer = None def __init__(self, parent=None): - from pyminer.ui.base.widgets.resources import icon_New super(MainWindow, self).__init__(parent) import pyminer.pmutil pyminer.pmutil._main_window = self - self.init_toolbar() + self.init_toolbar_tab() + + self.add_toolbar('toolbar_home', PMToolBarHome(), text='主页') + self.switch_toolbar('toolbar_home') self.setDockNestingEnabled(True) self.setWindowTitle('Dock 例子') - self.add_widget_on_dock('tree_widget', PMFilesTreeview(self)) - self.add_widget_on_dock('console_widget', ConsoleWidget(self)) - self.add_widget_on_dock('control_panel', PMPageData()) - self.add_widget_on_dock('editor_panel', PMCodeEditTabWidget()) + self.add_widget_on_dock('tree_widget', PMFilesTreeview(self),text='文件浏览器') + self.add_widget_on_dock('console_widget', ConsoleWidget(self),text='控制台') + self.add_widget_on_dock('control_panel', PMPageData(),text='控制面板') + self.add_widget_on_dock('editor_panel', PMCodeEditTabWidget(),text='编辑器面板') self.switch_toolbar('toolbar_home') self.show() @@ -253,7 +97,7 @@ class MainWindow(BaseMainWindow): print('open!') def add_widget_on_dock(self, dock_name: str, widget: QWidget, text: str = ''): - dw = MyDockWidget(text=text, parent=self) + dw = PMDockWidget(text=text, parent=self) dw.setObjectName(dock_name) dw.setWidget(widget) if hasattr(widget, 'load_actions'): diff --git a/pyminer/ui/base/widgets/generalwidgets/buttons/__init__.py b/pyminer/ui/base/widgets/generalwidgets/buttons/__init__.py new file mode 100644 index 00000000..70baa606 --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/buttons/__init__.py @@ -0,0 +1 @@ +from .pmpushbuttons import PushButtonPane \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/buttons/pmpushbuttons.py b/pyminer/ui/base/widgets/generalwidgets/buttons/pmpushbuttons.py new file mode 100644 index 00000000..dad22088 --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/buttons/pmpushbuttons.py @@ -0,0 +1,52 @@ +from typing import List + +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QMenu + +from pyminer.ui.base.widgets.generalwidgets.sourcemgr import create_icon + + +class PushButtonPane(QWidget): + def __init__(self): + super().__init__() + self.layout = QVBoxLayout() + self.layout.setContentsMargins(0, 0, 0, 0) + self.setLayout(self.layout) + + def add_buttons(self, button_num: int = 2, text: list = None, icon_path: list = None, + menu: list = None) -> List[QPushButton]: + if text is None: + text = [''] * button_num + if icon_path == None: + icon_path = [None] * button_num + if menu == None: + menu = [None] * button_num + if len(text) != button_num or len(icon_path) != button_num or len(menu) != button_num: + raise Exception('text,icon和menu参数都必须为长为2的可迭代对象。') + if button_num == 2: + height = 30 + font_size = 12 + else: + height = 25 + font_size = 12 + btn_list = [] + for i in range(button_num): + b = self.add_button(text=text[i], icon=create_icon(icon_path[i]), menu=menu[i], height=height, + font_size=font_size) + btn_list.append(b) + return btn_list + + def add_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None, height: int = 30, + font_size: int = 14) -> QPushButton: + b = QPushButton() + b.setText(text) + if icon is not None: + b.setIcon(icon) + if menu is not None: + b.setMenu(menu) + b.setStyleSheet( + 'QPushButton{border:0px;font-size:%dpx;padding:2px 2px;width:80px;height:%dpx;text-align:left;}' % ( + font_size, height) + \ + 'QPushButton:hover{background-color:#ededed;}') + self.layout.addWidget(b) + return b \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/sourcemgr/__init__.py b/pyminer/ui/base/widgets/generalwidgets/sourcemgr/__init__.py new file mode 100644 index 00000000..16adf940 --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/sourcemgr/__init__.py @@ -0,0 +1 @@ +from .iconutils import create_icon \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/sourcemgr/iconutils.py b/pyminer/ui/base/widgets/generalwidgets/sourcemgr/iconutils.py new file mode 100644 index 00000000..ec7cc906 --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/sourcemgr/iconutils.py @@ -0,0 +1,7 @@ +from PyQt5.QtGui import QIcon, QPixmap + + +def create_icon(icon_path: str = ":/pyqt/source/images/New.png"): + icon = QIcon() + icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off) + return icon \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/threads/__init__.py b/pyminer/ui/base/widgets/generalwidgets/threads/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py b/pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py new file mode 100644 index 00000000..a9546de2 --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py @@ -0,0 +1 @@ +from .toolbar import TopToolBar,PMToolBar \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py b/pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py new file mode 100644 index 00000000..667aa19f --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py @@ -0,0 +1,35 @@ +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import QToolBar, QPushButton, QMenu, QToolButton + + +class TopToolBar(QToolBar): + def __init__(self): + super().__init__() + + def add_button(self, name: str, text: str): + b = QPushButton(text) + b.setObjectName(name) + + self.addWidget(b) + + def get_button(self, name: str): + return self.findChild(QPushButton, name) + +class PMToolBar(QToolBar): + tab_button: QPushButton = None + widget_dic = {} + + def __init__(self): + super().__init__() + self.setFixedHeight(90) + + def add_tool_button(self, text: str = '', icon: QIcon = None, menu: QMenu = None): + tb = QToolButton() + tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) + tb.setText(text) + tb.setStyleSheet('QToolButton{height:60px;width:50px;border:0px;}QToolButton::hover{background-color:#ededed;}') + if QIcon is not None: + tb.setIcon(icon) + self.addWidget(tb) + return tb \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/window/__init__.py b/pyminer/ui/base/widgets/generalwidgets/window/__init__.py new file mode 100644 index 00000000..e5a02d4e --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/window/__init__.py @@ -0,0 +1,2 @@ +from .pmdockwidget import PMDockWidget +from .pmmainwindow import BaseMainWindow \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py b/pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py new file mode 100644 index 00000000..f62d1ba8 --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py @@ -0,0 +1,26 @@ +from PyQt5.QtGui import QCloseEvent +from PyQt5.QtWidgets import QDockWidget, QMainWindow + + +from pyminer.pmutil import get_main_window +class PMDockWidget(QDockWidget): + def __init__(self, text='', parent: QMainWindow = None): + super().__init__(text, parent) + self.parent = parent + print(self.titleBarWidget()) + + def closeEvent(self, event: QCloseEvent): + + print('close') + self.hide() + event.accept() + + dock_widgets = get_main_window().dock_widgets + for k in dock_widgets.keys(): + print(k,dock_widgets[k].isVisible()) + + # d1 = self.parent.dock_widgets + # print(d1) + # # self.parent.dock_widgets.pop(self.objectName()) + # d2 = self.parent.dock_widgets + # print(d2) \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py b/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py new file mode 100644 index 00000000..cdc6102c --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py @@ -0,0 +1,78 @@ +import os +from typing import Dict + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QCloseEvent +from PyQt5.QtWidgets import QMainWindow, QToolBar, QPushButton, QMessageBox + +# from pyminer.pmappmodern import TopToolBar, PMToolBarHome +from pyminer.ui.base.widgets.generalwidgets.toolbars import TopToolBar +from pyminer.ui.base.widgets.codeeditwidget import PMToolBar +from pyminer.ui.base.widgets.generalwidgets.buttons import PushButtonPane +from pyminer.ui.base.widgets.generalwidgets.window import PMDockWidget + + +class BaseMainWindow(QMainWindow): + toolbars: Dict[str, QToolBar] = {} + dock_widgets: Dict[str, PMDockWidget] = {} + + def init_toolbar_tab(self): + tt = TopToolBar() + tt.setFloatable(False) + tt.setLayoutDirection(Qt.LeftToRight) + tt.setMovable(False) + tt.setObjectName('tab_bar_for_tool_bar') + + self.addToolBar(tt) + self.top_toolbar_tab = tt + + + + def switch_toolbar(self, name: str): + for k in self.toolbars.keys(): + if k == name: + self.toolbars[k].show() + self.toolbars[k].tab_button.setStyleSheet( + 'QPushButton{color:#444444;background-color:#ffffff;border:0px;width:100px;}') + else: + self.toolbars[k].hide() + self.toolbars[k].tab_button.setStyleSheet( + 'QPushButton{color:#efefef;background-color:#1234ee;border:0px;width:100px;}') + + def add_toolbar(self, name: str, toolbar: QToolBar, text: str = 'untitled toolbar'): + + b = QPushButton(text) + self.top_toolbar_tab.addWidget(b) + toolbar.tab_button = b + b.clicked.connect(lambda: self.switch_toolbar(name)) + + self.addToolBarBreak(Qt.TopToolBarArea) + self.addToolBar(toolbar) + toolbar.setObjectName(name) + self.toolbars[name] = toolbar + toolbar.setMovable(False) + toolbar.setFloatable(False) + toolbar.addWidget(PushButtonPane()) + + def save_layout(self): + p = '/home/hzy/Desktop/qtlayout.ini' + with open(p, 'wb') as f: + s = self.saveState() + f.write(s) + + def load_layout(self): + p = '/home/hzy/Desktop/qtlayout.ini' + if os.path.exists(p): + with open(p, 'rb') as f: + s = f.read() + self.restoreState(s) + + def closeEvent(self, event: QCloseEvent) -> None: + + reply = QMessageBox.question(self, '注意', '确认退出吗?', QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel) + # 添加按钮,可用中文 + if reply == QMessageBox.Ok: + event.accept() + # os.system(r"taskkill /F /IM pyminer.exe") # 结束进程 + else: + event.ignore() \ No newline at end of file -- Gitee From b03bf28e03881e292a49658b08e38bc478f7f63f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Sat, 29 Aug 2020 00:18:55 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E5=86=99=E5=A5=BD=E4=BA=86=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=A0=8F=E5=88=87=E6=8D=A2=E7=9A=84=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/config/qtlayout.ini | Bin 0 -> 516 bytes pyminer/pmappmodern.py | 74 +++++++++-------- pyminer/pmutil.py | 7 +- .../generalwidgets/toolbars/__init__.py | 2 +- .../generalwidgets/toolbars/toolbar.py | 14 +++- .../generalwidgets/window/pmdockwidget.py | 18 ++-- .../generalwidgets/window/pmmainwindow.py | 77 ++++++++++++++++-- pyminer/ui/base/widgets/tablewidget.py | 4 +- 8 files changed, 136 insertions(+), 60 deletions(-) create mode 100644 pyminer/config/qtlayout.ini diff --git a/pyminer/config/qtlayout.ini b/pyminer/config/qtlayout.ini new file mode 100644 index 0000000000000000000000000000000000000000..fbf8acbfaa0c72a726d5975b0537b48bcf4ecf6c GIT binary patch literal 516 zcmaKoOA5k35JYRD3l}1;L`3&q#7npdQR4^v5d*GNyn)B`2%?c#HIsov!3jOnNvdC0 z4}ct8Z$_X5Fm0x{OmD%9TL&o;#C$>=vBC@s=BcFI%!ub0d7gW1gbCJGy+?#Cv$b*B z;O4bF`OVy`o%)z!$BF}YM=13x7&v=I#^gajQ^CK3r>K%y+r0uN^TLIw*pXvSZd%@Y zmquqCFQq#9QkyH4Cz3Bx^W?I_)R`z63K^;~baS#XBukeOG9t^I7i{%#p6nlq3qQ*2 c@{q1IB(aAqS-L^|uc-f1RGv+IH@$210YTegDgXcg literal 0 HcmV?d00001 diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py index 4073e087..3b7a4736 100644 --- a/pyminer/pmappmodern.py +++ b/pyminer/pmappmodern.py @@ -14,12 +14,15 @@ from typing import List, Dict, Callable from pyminer.ui.base.widgets.generalwidgets.sourcemgr import create_icon from pyminer.ui.base.widgets.generalwidgets.buttons import PushButtonPane from pyminer.ui.base.widgets.generalwidgets.window import PMDockWidget, BaseMainWindow -from pyminer.ui.base.widgets.generalwidgets.toolbars import PMToolBar +from pyminer.ui.base.widgets.generalwidgets.toolbars import PMToolBar, ActionWithMessage from pyminer.ui.base.widgets.treeviews import PMFilesTreeview from pyminer.ui.base.widgets.consolewidget import ConsoleWidget from pyminer.ui.base.widgets.controlpanel import PMPageData from pyminer.ui.base.widgets.codeeditwidget import PMCodeEditTabWidget +from pyminer.ui.base.widgets.tablewidget import PMTableWidget + +from pyminer.pmutil import get_main_window,get_root_dir # 继承QThread @@ -57,14 +60,37 @@ class PMToolBarHome(PMToolBar): self.add_tool_button('保存\n工作区', create_icon(":/pyqt/source/images/lc_save.png")) pp = PushButtonPane() - pp.add_buttons(3, ['新建变量', '打开变量', '清除工作区'], - [":/pyqt/source/images/lc_dbnewform.png", ":/pyqt/source/images/lc_open.png", - ":/pyqt/source/images/lc_dbclearquery.png"]) + b = pp.add_buttons(3, ['新建变量', '打开变量', '清除工作区'], + [":/pyqt/source/images/lc_dbnewform.png", ":/pyqt/source/images/lc_open.png", + ":/pyqt/source/images/lc_dbclearquery.png"]) self.addWidget(pp) self.addSeparator() self.add_tool_button('设置', create_icon(':/pyqt/source/images/lc_config.png')) self.add_tool_button('帮助', create_icon(':/pyqt/source/images/lc_helpindex.png')) + self.view_menu = QMenu() + self.view_menu.addMenu('erere') + a = ActionWithMessage(text='aaaaaa', parent=self.view_menu) + a.message = 'tree_widget' + a.setCheckable(True) + self.view_menu.addAction(a) + self.view_menu.triggered.connect(self.process_events) + + pp = PushButtonPane() + buttons = pp.add_buttons(2, ['视图', '']) + self.addWidget(pp) + buttons[0].setMenu(self.view_menu) + self.view_config_button = buttons[0] + + def process_events(self, e: ActionWithMessage): + print(e.text()) + print(e.isChecked()) + main_window = get_main_window() + dws = main_window.dock_widgets + if e.message in dws.keys(): + dws[e.message].setVisible(e.isChecked()) + + class MainWindow(BaseMainWindow): setupui_tasks: List[Callable] = [] @@ -74,6 +100,9 @@ class MainWindow(BaseMainWindow): super(MainWindow, self).__init__(parent) import pyminer.pmutil pyminer.pmutil._main_window = self + root_dir = os.path.dirname(__file__) + pyminer.pmutil._root_dir = root_dir + print(get_root_dir()) self.init_toolbar_tab() self.add_toolbar('toolbar_home', PMToolBarHome(), text='主页') @@ -81,11 +110,12 @@ class MainWindow(BaseMainWindow): self.setDockNestingEnabled(True) self.setWindowTitle('Dock 例子') - self.add_widget_on_dock('tree_widget', PMFilesTreeview(self),text='文件浏览器') - self.add_widget_on_dock('console_widget', ConsoleWidget(self),text='控制台') - self.add_widget_on_dock('control_panel', PMPageData(),text='控制面板') - self.add_widget_on_dock('editor_panel', PMCodeEditTabWidget(),text='编辑器面板') - + self.add_widget_on_dock('tree_widget', PMFilesTreeview(self), text='文件浏览器') + self.add_widget_on_dock('console_widget', ConsoleWidget(self), text='控制台') + self.add_widget_on_dock('control_panel', PMPageData(), text='控制面板') + self.add_widget_on_dock('editor_panel', PMCodeEditTabWidget(), text='编辑器面板') + self.add_widget_on_dock('table_panel', PMTableWidget(self), text='数据表格') + self.load_layout() self.switch_toolbar('toolbar_home') self.show() self.on_boot_finished() @@ -96,32 +126,8 @@ class MainWindow(BaseMainWindow): def action_menu_open(self): print('open!') - def add_widget_on_dock(self, dock_name: str, widget: QWidget, text: str = ''): - dw = PMDockWidget(text=text, parent=self) - dw.setObjectName(dock_name) - dw.setWidget(widget) - if hasattr(widget, 'load_actions'): - widget.load_actions() - if hasattr(widget, 'setup_ui'): - if hasattr(widget, 'show_directly'): - if widget.show_directly: - widget.setup_ui() - else: - self.setupui_tasks.append(widget.setup_ui) - else: - self.setupui_tasks.append(widget.setup_ui) - if len(list(self.dock_widgets.keys())) % 2 == 0: - - self.addDockWidget(Qt.LeftDockWidgetArea, dw) - else: - self.addDockWidget(Qt.RightDockWidgetArea, dw) - if dock_name not in self.dock_widgets.keys(): - self.dock_widgets[dock_name] = dw - else: - raise Exception('docked widget name: \'%s\' is already used!' % dock_name) - def on_boot_finished(self): - + super().on_boot_finished() self.boot_timer = QTimer() self.boot_timer.start(50) self.boot_timer.timeout.connect(self.on_boot_timer_timeout) diff --git a/pyminer/pmutil.py b/pyminer/pmutil.py index 96a92ba2..a4dc6d7a 100644 --- a/pyminer/pmutil.py +++ b/pyminer/pmutil.py @@ -5,6 +5,10 @@ import os import sys from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow +from typing import TYPE_CHECKING +if TYPE_CHECKING: + import pyminer.pmappmodern + _application = None _root_dir = None _main_window = None @@ -30,11 +34,10 @@ def get_application() -> QApplication: return _application -def get_main_window() -> QMainWindow: +def get_main_window() -> 'pyminer.pmappmodern.MainWindow': ''' 获取主窗口或者主控件。 Returns: - ''' assert _main_window is not None return _main_window diff --git a/pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py b/pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py index a9546de2..f990e99a 100644 --- a/pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py +++ b/pyminer/ui/base/widgets/generalwidgets/toolbars/__init__.py @@ -1 +1 @@ -from .toolbar import TopToolBar,PMToolBar \ No newline at end of file +from .toolbar import TopToolBar,PMToolBar,ActionWithMessage \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py b/pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py index 667aa19f..9b523e64 100644 --- a/pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py +++ b/pyminer/ui/base/widgets/generalwidgets/toolbars/toolbar.py @@ -1,8 +1,16 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon -from PyQt5.QtWidgets import QToolBar, QPushButton, QMenu, QToolButton +from PyQt5.QtWidgets import QToolBar, QPushButton, QMenu, QToolButton, QAction,QWidget +class ActionWithMessage(QAction): + def __init__(self,text:str='',icon:QIcon=None,parent:QWidget=None,message:str = ''): + super().__init__(parent) + self.setText(text) + if icon is not None: + self.setIcon(icon) + self.message=message + class TopToolBar(QToolBar): def __init__(self): super().__init__() @@ -29,7 +37,9 @@ class PMToolBar(QToolBar): tb.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) tb.setText(text) tb.setStyleSheet('QToolButton{height:60px;width:50px;border:0px;}QToolButton::hover{background-color:#ededed;}') - if QIcon is not None: + if icon is not None: tb.setIcon(icon) + if menu is not None: + tb.setMenu(menu) self.addWidget(tb) return tb \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py b/pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py index f62d1ba8..3fc95647 100644 --- a/pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py +++ b/pyminer/ui/base/widgets/generalwidgets/window/pmdockwidget.py @@ -1,8 +1,10 @@ from PyQt5.QtGui import QCloseEvent from PyQt5.QtWidgets import QDockWidget, QMainWindow - from pyminer.pmutil import get_main_window + + + class PMDockWidget(QDockWidget): def __init__(self, text='', parent: QMainWindow = None): super().__init__(text, parent) @@ -10,17 +12,11 @@ class PMDockWidget(QDockWidget): print(self.titleBarWidget()) def closeEvent(self, event: QCloseEvent): - print('close') self.hide() event.accept() - dock_widgets = get_main_window().dock_widgets - for k in dock_widgets.keys(): - print(k,dock_widgets[k].isVisible()) - - # d1 = self.parent.dock_widgets - # print(d1) - # # self.parent.dock_widgets.pop(self.objectName()) - # d2 = self.parent.dock_widgets - # print(d2) \ No newline at end of file + # dock_widgets = get_main_window().dock_widgets + # for k in dock_widgets.keys(): + # print(k, dock_widgets[k].isVisible()) + get_main_window().refresh_view_configs() diff --git a/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py b/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py index cdc6102c..793eee4f 100644 --- a/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py +++ b/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py @@ -1,15 +1,22 @@ +''' +这里定义了MainWindow的基类。 +基类主要包含带选项卡工具栏的管理功能,以及浮动窗口的管理功能 +添加浮动窗口时,默认‘关闭’事件就是隐藏。如果是彻底的关闭,需要进行重写。 +每次界面关闭时,布局会被存入文件pyminer/config/qtlayout.ini之中。再次启动时,若这个文件存在,就会加载,反之不会加载。 +''' import os from typing import Dict from PyQt5.QtCore import Qt from PyQt5.QtGui import QCloseEvent -from PyQt5.QtWidgets import QMainWindow, QToolBar, QPushButton, QMessageBox +from PyQt5.QtWidgets import QMainWindow, QToolBar, QPushButton, QMessageBox, QWidget, QMenu # from pyminer.pmappmodern import TopToolBar, PMToolBarHome -from pyminer.ui.base.widgets.generalwidgets.toolbars import TopToolBar +from pyminer.ui.base.widgets.generalwidgets.toolbars import TopToolBar, ActionWithMessage from pyminer.ui.base.widgets.codeeditwidget import PMToolBar from pyminer.ui.base.widgets.generalwidgets.buttons import PushButtonPane from pyminer.ui.base.widgets.generalwidgets.window import PMDockWidget +from pyminer.pmutil import get_root_dir class BaseMainWindow(QMainWindow): @@ -26,8 +33,6 @@ class BaseMainWindow(QMainWindow): self.addToolBar(tt) self.top_toolbar_tab = tt - - def switch_toolbar(self, name: str): for k in self.toolbars.keys(): if k == name: @@ -55,13 +60,14 @@ class BaseMainWindow(QMainWindow): toolbar.addWidget(PushButtonPane()) def save_layout(self): - p = '/home/hzy/Desktop/qtlayout.ini' + + p = os.path.join(get_root_dir(), 'config','qtlayout.ini') with open(p, 'wb') as f: s = self.saveState() f.write(s) def load_layout(self): - p = '/home/hzy/Desktop/qtlayout.ini' + p = os.path.join(get_root_dir(),'config', 'qtlayout.ini') if os.path.exists(p): with open(p, 'rb') as f: s = f.read() @@ -70,9 +76,62 @@ class BaseMainWindow(QMainWindow): def closeEvent(self, event: QCloseEvent) -> None: reply = QMessageBox.question(self, '注意', '确认退出吗?', QMessageBox.Ok | QMessageBox.Cancel, QMessageBox.Cancel) - # 添加按钮,可用中文 if reply == QMessageBox.Ok: event.accept() - # os.system(r"taskkill /F /IM pyminer.exe") # 结束进程 else: - event.ignore() \ No newline at end of file + event.ignore() + + def add_widget_on_dock(self, dock_name: str, widget: QWidget, text: str = ''): + dw = PMDockWidget(text=text, parent=self) + dw.text = text + dw.setObjectName(dock_name) + dw.setWidget(widget) + if hasattr(widget, 'load_actions'): + widget.load_actions() + if hasattr(widget, 'setup_ui'): + if hasattr(widget, 'show_directly'): + if widget.show_directly: + widget.setup_ui() + else: + self.setupui_tasks.append(widget.setup_ui) + else: + self.setupui_tasks.append(widget.setup_ui) + if len(list(self.dock_widgets.keys())) % 2 == 0: + + self.addDockWidget(Qt.LeftDockWidgetArea, dw) + else: + self.addDockWidget(Qt.RightDockWidgetArea, dw) + if dock_name not in self.dock_widgets.keys(): + self.dock_widgets[dock_name] = dw + else: + raise Exception('docked widget name: \'%s\' is already used!' % dock_name) + + home_toolbar = self.toolbars.get('toolbar_home') + + menu = QMenu() + menu.triggered.connect(home_toolbar.process_events) + for k in self.dock_widgets.keys(): + a = ActionWithMessage(text=self.dock_widgets[k].text, parent=home_toolbar, message=k) + + a.setCheckable(True) + + menu.addAction(a) + + home_toolbar.view_config_button.setMenu(menu) + + def refresh_view_configs(self): + home_toolbar = self.toolbars.get('toolbar_home') + menu = QMenu() + menu.triggered.connect(home_toolbar.process_events) + for k in self.dock_widgets.keys(): + a = ActionWithMessage(text=self.dock_widgets[k].text, parent=home_toolbar, message=k) + + a.setCheckable(True) + a.setChecked(self.dock_widgets[k].widget().isVisible()) + + menu.addAction(a) + + home_toolbar.view_config_button.setMenu(menu) + + def on_boot_finished(self): + self.refresh_view_configs() diff --git a/pyminer/ui/base/widgets/tablewidget.py b/pyminer/ui/base/widgets/tablewidget.py index df00688a..8df95d53 100644 --- a/pyminer/ui/base/widgets/tablewidget.py +++ b/pyminer/ui/base/widgets/tablewidget.py @@ -5,7 +5,7 @@ from PyQt5.QtCore import QCoreApplication class PMTableWidget(QTableWidget): - def __init__(self,parent): + def __init__(self, parent): super().__init__(parent) self.setStyleSheet("") @@ -13,6 +13,8 @@ class PMTableWidget(QTableWidget): self.setObjectName("tableWidget_dataset") self.setColumnCount(30) self.setRowCount(30) + + def setup_ui(self): item = QTableWidgetItem() self.setVerticalHeaderItem(0, item) item = QTableWidgetItem() -- Gitee From f5543ee9ad78d4503f35a8fcff96c9b604fed5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Sat, 29 Aug 2020 13:54:58 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E5=B0=9D=E8=AF=95=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86=E5=99=A8=EF=BC=8C=E4=BD=86?= =?UTF-8?q?=E6=98=AF=E9=81=87=E5=88=B0=E4=BA=86=E6=97=A0=E6=B3=95=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8A=A0=E8=BD=BD=E6=8F=92=E4=BB=B6=E7=9A=84=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/config/qtlayout.ini | Bin 516 -> 489 bytes .../extensions/extensions_manager/manager.py | 14 ++-- pyminer/pmapp.py | 4 +- pyminer/pmappmodern.py | 61 +++++++++++++++--- pyminer/pmutil.py | 4 +- pyminer/ui/base/widgets/controlpanel.py | 1 + .../generalwidgets/containers/PMTab.py | 9 +++ .../generalwidgets/containers/__init__.py | 1 + 8 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py create mode 100644 pyminer/ui/base/widgets/generalwidgets/containers/__init__.py diff --git a/pyminer/config/qtlayout.ini b/pyminer/config/qtlayout.ini index fbf8acbfaa0c72a726d5975b0537b48bcf4ecf6c..5f631787d941a874268c50bea12ba2fc92956238 100644 GIT binary patch delta 130 zcmZo+dC5FMgu9)Afoa7bCI$uu=85u3Tnte_Rusek|NkdmQ|2rIN_v3sM0X_xrbA#U ys5Fqx2t)|&Oq1Cd75Er{S{U8}aUIxt(a`Xcme=GlpyZ_ delta 156 zcmaFK+`=+Jgj;}tfoZ}YCI%oiQC^9S(G|#wnpm!+z)%8`0r43A|Njr98G+~plIrIw znjkd{bucx5fQ%nN1w0@OR4w}pqzlLZ8ttvj3o-_14kI6kF>$AY7-J)lR|}M`huQ#A KIbpIQ;|T!$lqR|W diff --git a/pyminer/features/extensions/extensions_manager/manager.py b/pyminer/features/extensions/extensions_manager/manager.py index c5194d56..e68c42ba 100644 --- a/pyminer/features/extensions/extensions_manager/manager.py +++ b/pyminer/features/extensions/extensions_manager/manager.py @@ -5,7 +5,9 @@ import json import json.decoder import zipfile import importlib -#from pyminer.features.extensions.extensionlib import env +from pyminer.pmutil import get_main_window + +# from pyminer.features.extensions.extensionlib import env BASEDIR = os.path.dirname(os.path.dirname( @@ -15,8 +17,8 @@ BASEDIR = os.path.dirname(os.path.dirname( def _log(text): '''日志输出text''' # 放在函数体中防止循环引用,接下来的也是 - from pyminer.pmapp import MyMainForm - MyMainForm.instance.slot_flush_console('info', 'Extension') + # from pyminer.pmapp import MyMainForm + get_main_window().slot_flush_console('info', 'Extension') def _assert_(boolean, text): @@ -25,10 +27,10 @@ def _assert_(boolean, text): text:str 若bool为false,以异常级输出text ''' - from pyminer.pmapp import MyMainForm + if not boolean: - MyMainForm.instance.slot_flush_console( - 'error', 'Extension', 'Error:'+str(text)) + get_main_window().slot_flush_console( + 'error', 'Extension', 'Error:' + str(text)) class ExtensionInfo: diff --git a/pyminer/pmapp.py b/pyminer/pmapp.py index 1783dfe3..d232b013 100644 --- a/pyminer/pmapp.py +++ b/pyminer/pmapp.py @@ -194,8 +194,10 @@ class CustomRect(QGraphicsObject): painter.drawRoundedRect(self.boundingRect(), 10, 10) # 绘制函数 painter.end() +from pyminer.pmappmodern import MainWindow +MyMainForm = MainWindow -class MyMainForm(QMainWindow, Ui_MainWindow): +class MayMainForm(QMainWindow, Ui_MainWindow): """ 主窗体 """ diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py index 913348ec..f2fc811a 100644 --- a/pyminer/pmappmodern.py +++ b/pyminer/pmappmodern.py @@ -2,16 +2,20 @@ √任务:写出显示浮动窗口数量的部件(下拉式菜单等),点击之后,可以进行浮动窗口显示或者隐藏。 参考单例模式修改MainWindow,保证mainwindow可用。 ''' +import datetime +import getpass import os import sys +import threading import time from PyQt5.QtCore import pyqtSignal, Qt, QTimer, QThread from PyQt5.QtGui import QIcon, QPixmap, QFont, QCloseEvent from PyQt5.QtWidgets import QHBoxLayout, QDockWidget, QMainWindow, QPushButton, QApplication, \ - QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QToolButton, QMessageBox + QWidget, QToolBar, QAction, QVBoxLayout, QMenu, QToolButton, QMessageBox, QStackedWidget, QTabWidget from typing import List, Dict, Callable +from pyminer.ui.base.widgets.generalwidgets.containers import PMTabWidget from pyminer.ui.base.widgets.generalwidgets.sourcemgr import create_icon from pyminer.ui.base.widgets.generalwidgets.buttons import PushButtonPane from pyminer.ui.base.widgets.generalwidgets.window import PMDockWidget, BaseMainWindow @@ -19,11 +23,12 @@ from pyminer.ui.base.widgets.generalwidgets.toolbars import PMToolBar, ActionWit from pyminer.ui.base.widgets.treeviews import PMFilesTreeview from pyminer.ui.base.widgets.consolewidget import ConsoleWidget -from pyminer.ui.base.widgets.controlpanel import PMPageData +from pyminer.ui.base.widgets.controlpanel import PMPageData, PMPageExt from pyminer.ui.base.widgets.codeeditwidget import PMCodeEditTabWidget from pyminer.ui.base.widgets.tablewidget import PMTableWidget -from pyminer.pmutil import get_main_window,get_root_dir +from pyminer.features.extensions.extensions_manager.manager import extensions_manager +from pyminer.pmutil import get_main_window, get_root_dir # 继承QThread @@ -92,18 +97,24 @@ class PMToolBarHome(PMToolBar): dws[e.message].setVisible(e.isChecked()) - class MainWindow(BaseMainWindow): setupui_tasks: List[Callable] = [] boot_timer: QTimer = None + @classmethod + def __new__(cls, *args): + instance = super().__new__(cls) + cls.instance = instance + return instance + def __init__(self, parent=None): - super(MainWindow, self).__init__(parent) + super().__init__(parent) + import pyminer.pmutil pyminer.pmutil._main_window = self root_dir = os.path.dirname(__file__) pyminer.pmutil._root_dir = root_dir - print(get_root_dir()) + # print(get_root_dir()) self.init_toolbar_tab() self.add_toolbar('toolbar_home', PMToolBarHome(), text='主页') @@ -113,7 +124,18 @@ class MainWindow(BaseMainWindow): self.setWindowTitle('Dock 例子') self.add_widget_on_dock('tree_widget', PMFilesTreeview(self), text='文件浏览器') self.add_widget_on_dock('console_widget', ConsoleWidget(self), text='控制台') - self.add_widget_on_dock('control_panel', PMPageData(), text='控制面板') + + stacked_widget = PMTabWidget() + stacked_widget.addTab(PMPageData(), '数据') + stacked_widget.addTab(PMPageExt(self), '插件') + + self.extensions_manager = extensions_manager + self.extensions_manager.load_setting() + self.extensions_manager.load() + + # stacked_widget.addWidget() + + self.add_widget_on_dock('control_panel', stacked_widget, text='控制面板') self.add_widget_on_dock('editor_panel', PMCodeEditTabWidget(), text='编辑器面板') self.add_widget_on_dock('table_panel', PMTableWidget(self), text='数据表格') self.load_layout() @@ -149,9 +171,32 @@ class MainWindow(BaseMainWindow): self.save_layout() super().closeEvent(a0) + def slot_flush_console(self, level, module, content): + """ + 刷新主窗体执行情况日志 + :return: + level:文本,warnning error info + module:业务模块名称,例如 数据获取,数据处理,数据探索,统计,模型,可视化,评估 + """ + 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 + "" + print(html) + return + console = self.textEdit_console # 由于代码重构,这里出现了不同。 + # [!TODO]应当创建方法,一次性的完成这个工作。 + console.moveCursor(QTextCursor.End) + console.append(html) + if __name__ == '__main__': app = QApplication(sys.argv) demo = MainWindow() - + id(demo) + # b=MainWindow() + # id(b) sys.exit(app.exec_()) diff --git a/pyminer/pmutil.py b/pyminer/pmutil.py index a4dc6d7a..c709e79b 100644 --- a/pyminer/pmutil.py +++ b/pyminer/pmutil.py @@ -11,7 +11,7 @@ if TYPE_CHECKING: _application = None _root_dir = None -_main_window = None +_main_window:'pyminer.pmappmodern.MainWindow' = None def get_root_dir() -> str: @@ -39,7 +39,6 @@ def get_main_window() -> 'pyminer.pmappmodern.MainWindow': 获取主窗口或者主控件。 Returns: ''' - assert _main_window is not None return _main_window @@ -52,6 +51,7 @@ def test_widget_run(widget_type): Returns:None ''' + _root_dir = os.path.dirname(os.path.abspath(__file__)) app = QApplication(sys.argv) diff --git a/pyminer/ui/base/widgets/controlpanel.py b/pyminer/ui/base/widgets/controlpanel.py index 58e49232..0d7bb985 100644 --- a/pyminer/ui/base/widgets/controlpanel.py +++ b/pyminer/ui/base/widgets/controlpanel.py @@ -851,6 +851,7 @@ class PMPageExt(QWidget): filter='所有文件(*.*);;zip文件(*.zip)', initialFilter='zip文件(*.zip)' ) + print(path,_) self.ext_manager.install(path) # 刷新扩展列表 self.init_extensions() diff --git a/pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py b/pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py new file mode 100644 index 00000000..fe45ede7 --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py @@ -0,0 +1,9 @@ +from PyQt5.QtWidgets import QTabWidget + + +class PMTabWidget(QTabWidget): + def setup_ui(self): + for tab_id in range(self.count()):# 遍历所有的tab + w=self.widget(tab_id) + if hasattr(w,'setup_ui'): + self.widget(tab_id).setup_ui() \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/containers/__init__.py b/pyminer/ui/base/widgets/generalwidgets/containers/__init__.py new file mode 100644 index 00000000..7a972cba --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/containers/__init__.py @@ -0,0 +1 @@ +from .PMTab import PMTabWidget \ No newline at end of file -- Gitee From 132412f13c4c6381aecb886450c4507ef6989a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Sat, 29 Aug 2020 15:44:45 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E5=86=99=E4=BA=86=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E7=9A=84=E4=B8=80=E4=BA=9B=E8=AF=B4=E6=98=8E=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/pmappmodern.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/pyminer/pmappmodern.py b/pyminer/pmappmodern.py index f2fc811a..dc6a27d1 100644 --- a/pyminer/pmappmodern.py +++ b/pyminer/pmappmodern.py @@ -1,6 +1,25 @@ ''' √任务:写出显示浮动窗口数量的部件(下拉式菜单等),点击之后,可以进行浮动窗口显示或者隐藏。 -参考单例模式修改MainWindow,保证mainwindow可用。 + +任务:将主界面中所有功能都迁移到目前的界面中去。 + +主界面由一系列PMDockWidget组成,每一个DockWidget可以获取主界面。 +1、注册工具栏的方法 +主界面的工具栏使用的是PMToolBar这个类,继承自QToolBar,结构为1+n。最顶端的选项卡样控件实为QToolBar,可以依靠其按钮的点击来进行工具栏的切换。 +切换工具栏时,其他工具栏隐藏,只有按钮对应的工具栏可以显示。详见switch_toolbar方法。 +主窗口add_tool_bar()方法,可以将QToolBar或者继承它的控件添加到主窗口。 +当需要在已有的工具栏上添加按钮的时候,比方说要获取主页对应的工具栏,那么就使用 MainWindow.toolbars.get('toolbar_home')进行获取就可以了。 + +获取工具栏后,调用add_tool_button()添加一个按钮,或者调用add_tool_buttons()添加多个竖排的按钮。这两个函数的返回值分别为QPushButton +和List[QPushButton] + +如果需要菜单效果,可以自己写一个菜单,然后添加到按钮之上。 +2、添加dockwidget的方法 +MainWindow.add_widget_on_dock()方法可以用来将任意控件添加到dock,而且下次加载之时布局会被保存。 + +为了加快软件启动速度,widget可以定义方法setup_ui(也可以没有)。当加载时,首先执行控件的__init__,并且将setup_ui压入任务栈之中,等到主 +界面显示出来之后再用定时器调用执行控件的setup_ui方法。对于核心控件可以定义show_directly=True,保证立即执行setup_ui方法。或者干脆不写 +setup_ui方法,而是将启动方法放在__init__之中。 ''' import datetime import getpass -- Gitee From 832f364f23373fbc7abce4bfe35241b87adc68df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Sat, 29 Aug 2020 19:12:31 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BA=86=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E9=9D=A2=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/config/qtlayout.ini | Bin 489 -> 748 bytes pyminer/pmappmodern.py | 67 +++++++++++++----- pyminer/ui/base/widgets/controlpanel.py | 13 ++-- .../generalwidgets/containers/PMTab.py | 23 ++++-- .../generalwidgets/containers/__init__.py | 3 +- .../generalwidgets/containers/pmscrollarea.py | 13 ++++ .../generalwidgets/window/pmmainwindow.py | 13 ++-- 7 files changed, 97 insertions(+), 35 deletions(-) create mode 100644 pyminer/ui/base/widgets/generalwidgets/containers/pmscrollarea.py diff --git a/pyminer/config/qtlayout.ini b/pyminer/config/qtlayout.ini index 5f631787d941a874268c50bea12ba2fc92956238..f8e234d88fd83048a8d533dbba8518c754dadf53 100644 GIT binary patch literal 748 zcmaKpF;2r!5JblgMQRF^!qAX{f)WlwOJf=008&Dt*nw0~aSJZMeK$#S4lGv&Og9(AXIZa9|_sgk%1QB{>|PswKd z&Q!PtM1y?*nS)O?C40|#WQO-P!-~ddMBhR7@PlmRve@KDfEEzuzzgUm>|1m~2lGVx zJ{Xf|s5y1l;C3UZzM$~g2zI))42Y2gQhFm^*OKf_kYsN%U1@}<-BR$UmeQkUfQS;| zv%jjJTx}nYiF4X4nx^4;Leqq4JbS_V(|GGz%;8zqt^3qXxVDsaj(}-c(@h@xyn*yL zDwZsJb#&Rg_M}7D1%pm%6H<)G!e~SKctnqCjdiBo0bF<*lHR(wA-M%QR{kF-`2}iQ KZ2sDb(CQn;PMhxl delta 167 zcmaFE`jUBq2x~h71JjC$l8TNDKu`k2QDFT4|Nq}Wh7?0GLq0}m`V+7mrhY84Inw-w4$P2ROEfCj%wQXQj Z5o1gTD%%PaiUJ7%X&_))F" else: html = "" + msg + "" - print(html) - return - console = self.textEdit_console # 由于代码重构,这里出现了不同。 + + + console = self.log_output_console # 由于代码重构,这里出现了不同。 # [!TODO]应当创建方法,一次性的完成这个工作。 console.moveCursor(QTextCursor.End) console.append(html) @@ -215,6 +247,7 @@ class MainWindow(BaseMainWindow): if __name__ == '__main__': app = QApplication(sys.argv) demo = MainWindow() + # demo.setMaximumHeight(700) id(demo) # b=MainWindow() # id(b) diff --git a/pyminer/ui/base/widgets/controlpanel.py b/pyminer/ui/base/widgets/controlpanel.py index 0d7bb985..06ebc734 100644 --- a/pyminer/ui/base/widgets/controlpanel.py +++ b/pyminer/ui/base/widgets/controlpanel.py @@ -2,13 +2,13 @@ import os import webbrowser # 也就是widget_right -from PyQt5.QtWidgets import QWidget, QGridLayout, QSpacerItem, QSizePolicy, QMainWindow, QListWidget, QListWidgetItem, QHBoxLayout, QLabel, QPushButton, QFileDialog, QVBoxLayout, QMenu +from PyQt5.QtWidgets import QWidget, QGridLayout, QSpacerItem, QSizePolicy, QMainWindow, QListWidget, QListWidgetItem, \ + QHBoxLayout, QLabel, QPushButton, QFileDialog, QVBoxLayout, QMenu, QScrollArea from PyQt5.QtGui import QIcon, QPixmap, QCursor from PyQt5.QtCore import QSize, Qt, QCoreApplication, QSize from pyminer.features.preprocess.PMToolButton import PMToolButton - from pyminer.pmutil import get_root_dir from pyminer.features.extensions.extensions_manager.manager import extensions_manager @@ -17,11 +17,13 @@ class ControlPanel(): pass + class PMPageData(QWidget): def __init__(self): super().__init__() def setup_ui(self): + # self.setMaximumHeight(300) from .resources import icon_lc_connectorcurve, icon_transition_random, icon_formfilternavigator, \ icon_data_provider, icon_lc_togglemergecells, icon_lc_datadatapilotrun, icon_delete_columns, \ icon_mergedocuments, icon_lc_accepttrackedchange, \ @@ -838,6 +840,7 @@ class PMPageExt(QWidget): main_window:主窗口 ''' super().__init__() + self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.main_window = main_window self.ext_manager = extensions_manager self.init_ui() @@ -851,7 +854,7 @@ class PMPageExt(QWidget): filter='所有文件(*.*);;zip文件(*.zip)', initialFilter='zip文件(*.zip)' ) - print(path,_) + print(path, _) self.ext_manager.install(path) # 刷新扩展列表 self.init_extensions() @@ -860,7 +863,7 @@ class PMPageExt(QWidget): self.ext_list.clear() # 先清空 for ext in self.ext_manager.extensions: item = QListWidgetItem(self.ext_list, 0) - item.setSizeHint(QSize(self.ext_list.width()-20, 50)) + item.setSizeHint(QSize(self.ext_list.width() - 20, 50)) w = ExtInfoWidget(self, ext, self.ext_manager) self.ext_list.addItem(item) self.ext_list.setItemWidget(item, w) @@ -872,7 +875,7 @@ class PMPageExt(QWidget): # 扩展列表 self.ext_list = QListWidget(self) self.init_extensions() - self.ext_list.setMinimumHeight(self.height()) + # self.ext_list.setMinimumHeight(self.height()) self.ext_list.show() self.layout.addWidget(self.ext_list) diff --git a/pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py b/pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py index fe45ede7..9357ee1c 100644 --- a/pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py +++ b/pyminer/ui/base/widgets/generalwidgets/containers/PMTab.py @@ -1,9 +1,22 @@ -from PyQt5.QtWidgets import QTabWidget +from PyQt5.QtWidgets import QTabWidget, QWidget, QScrollArea class PMTabWidget(QTabWidget): def setup_ui(self): - for tab_id in range(self.count()):# 遍历所有的tab - w=self.widget(tab_id) - if hasattr(w,'setup_ui'): - self.widget(tab_id).setup_ui() \ No newline at end of file + for tab_id in range(self.count()): # 遍历所有的tab + w = self.widget(tab_id) + if hasattr(w, 'setup_ui'): + self.widget(tab_id).setup_ui() + + def addScrolledAreaTab(self, widget: QWidget, a1: str) -> int: + ''' + 添加使用QScrollArea包裹的Tab。 + :param widget: + :param a1: + :return: + ''' + from pyminer.ui.base.widgets.generalwidgets.containers import PMScrollArea + scroll = PMScrollArea() + scroll.setWidget(widget) + + super().addTab(scroll, a1) diff --git a/pyminer/ui/base/widgets/generalwidgets/containers/__init__.py b/pyminer/ui/base/widgets/generalwidgets/containers/__init__.py index 7a972cba..6aabb372 100644 --- a/pyminer/ui/base/widgets/generalwidgets/containers/__init__.py +++ b/pyminer/ui/base/widgets/generalwidgets/containers/__init__.py @@ -1 +1,2 @@ -from .PMTab import PMTabWidget \ No newline at end of file +from .PMTab import PMTabWidget +from .pmscrollarea import PMScrollArea \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/containers/pmscrollarea.py b/pyminer/ui/base/widgets/generalwidgets/containers/pmscrollarea.py new file mode 100644 index 00000000..f60f00be --- /dev/null +++ b/pyminer/ui/base/widgets/generalwidgets/containers/pmscrollarea.py @@ -0,0 +1,13 @@ +from PyQt5.QtWidgets import QScrollArea +from PyQt5.QtCore import Qt + +class PMScrollArea(QScrollArea): + def __init__(self): + super().__init__() + self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) + self.setWidgetResizable(True) + + def setup_ui(self): + if hasattr(self.widget(),'setup_ui'): + self.widget().setup_ui() + # self.page_data.setup_ui() \ No newline at end of file diff --git a/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py b/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py index 793eee4f..ee691c92 100644 --- a/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py +++ b/pyminer/ui/base/widgets/generalwidgets/window/pmmainwindow.py @@ -22,6 +22,8 @@ from pyminer.pmutil import get_root_dir class BaseMainWindow(QMainWindow): toolbars: Dict[str, QToolBar] = {} dock_widgets: Dict[str, PMDockWidget] = {} + dock_places = {'left': Qt.LeftDockWidgetArea, 'right': Qt.RightDockWidgetArea, 'top': Qt.TopDockWidgetArea, + 'bottom': Qt.BottomDockWidgetArea} def init_toolbar_tab(self): tt = TopToolBar() @@ -61,13 +63,13 @@ class BaseMainWindow(QMainWindow): def save_layout(self): - p = os.path.join(get_root_dir(), 'config','qtlayout.ini') + p = os.path.join(get_root_dir(), 'config', 'qtlayout.ini') with open(p, 'wb') as f: s = self.saveState() f.write(s) def load_layout(self): - p = os.path.join(get_root_dir(),'config', 'qtlayout.ini') + p = os.path.join(get_root_dir(), 'config', 'qtlayout.ini') if os.path.exists(p): with open(p, 'rb') as f: s = f.read() @@ -81,7 +83,7 @@ class BaseMainWindow(QMainWindow): else: event.ignore() - def add_widget_on_dock(self, dock_name: str, widget: QWidget, text: str = ''): + def add_widget_on_dock(self, dock_name: str, widget: QWidget, text: str = '', side='left'): dw = PMDockWidget(text=text, parent=self) dw.text = text dw.setObjectName(dock_name) @@ -96,11 +98,8 @@ class BaseMainWindow(QMainWindow): self.setupui_tasks.append(widget.setup_ui) else: self.setupui_tasks.append(widget.setup_ui) - if len(list(self.dock_widgets.keys())) % 2 == 0: - self.addDockWidget(Qt.LeftDockWidgetArea, dw) - else: - self.addDockWidget(Qt.RightDockWidgetArea, dw) + self.addDockWidget(self.dock_places[side], dw) if dock_name not in self.dock_widgets.keys(): self.dock_widgets[dock_name] = dw else: -- Gitee From e57cbc80b78e3337f7529ec0dda5cfc2d27ad092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BE=AF=E5=B1=95=E6=84=8F?= <1295752786@qq.com> Date: Sat, 29 Aug 2020 19:40:30 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=90=8E=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyminer/config/qtlayout.ini | Bin 748 -> 748 bytes pyminer/pmapp.py | 5 +---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pyminer/config/qtlayout.ini b/pyminer/config/qtlayout.ini index f8e234d88fd83048a8d533dbba8518c754dadf53..2529f682a1cceb64df69df634a722d6e50658cb0 100644 GIT binary patch delta 12 TcmaFE`i6DFB1VRdi#?eDBJBjV delta 12 TcmaFE`i6DFB1XoIi#?eDBJu>b diff --git a/pyminer/pmapp.py b/pyminer/pmapp.py index d232b013..b5b0afce 100644 --- a/pyminer/pmapp.py +++ b/pyminer/pmapp.py @@ -194,10 +194,7 @@ class CustomRect(QGraphicsObject): painter.drawRoundedRect(self.boundingRect(), 10, 10) # 绘制函数 painter.end() -from pyminer.pmappmodern import MainWindow -MyMainForm = MainWindow - -class MayMainForm(QMainWindow, Ui_MainWindow): +class MyMainForm(QMainWindow, Ui_MainWindow): """ 主窗体 """ -- Gitee