对话框页面
在pyminer中自带一个对话框插件,点击之后,可以获取工作空间变量、向控制台注入命令并且显示。 这个插件是如何实现的呢?请让我们继续往下看。
源文件解析
它的源文件位置为(pyminer2/extensions/packages/extension_dialog_demo),如图所示:
json编写
{
"name": "extension_dialog_demo",
"display_name": "对话框插件demo",
"version": "0.1",
"description": "好多介绍",
"icon": "python.jpg",
"interface": {
"file": "main.py",
"interface": "Interface"
},
"widgets": [
{
"file": "main.py",
"widget": "DemoToolButton",
"position": "append_to_toolbar",
"config": {
"toolbar": "toolbar_home",
"message": "no",
"name": "demo_tool_button"
}
}
],
"requirements": [
]
}
在以上的json中,我们可以发现这几个信息:
1、我们的对话框窗体类,并没有在json中体现出来。json中只注册了一个DemoToolButton。看名字的话,这像是一个工具栏按钮。 没错,就是这样的。对话框在唤出时动态生成,关闭之后就释放掉了。这样可以节省不少内存。
2、我们需要改写的主要是”widgets”的”config”属性。其中比较重要的是: — toolbar参数。这个参数的可以说明将这个东西插入到哪个工具栏中。而toolbar_home的意思就是主页工具栏。目前只有主页工具栏,所以就插入主页中。 — message参数:用处不大。 — name参数:按钮控件的名称。
main.py文件解析
"""
作者:@吴宫幽径
说明:
dialog无需写在json里面,直接调用主界面的控件就可以了。
"""
from PyQt5.QtGui import QCloseEvent
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QToolButton, QTextEdit, QSizePolicy
from pyminer2.extensions.extensionlib import BaseExtension,BaseInterface
class Extension(BaseExtension):
def on_load(self):
self.demo_tool_button = self.widgets['DemoToolButton']
self.demo_tool_button.extension_lib = self.extension_lib
print("对话框示例被加载")
def on_install(self):
print('被安装')
def on_uninstall(self):
print("被卸载")
class Interface(BaseInterface):
def hello(self):
print("Hello,来自对话框示例")
class DemoToolButton(QToolButton):
def __init__(self, parent=None):
super().__init__(parent)
self.setText('显示\n插件示例\n的对话框')
self.clicked.connect(self.show_dialog)
def show_dialog(self):
"""
显示一个插件示例所弹出的对话框。
"""
self.demo_tool_dialog = DemoToolDialog(self, ['执行python命令\'x=123\'', '获取数据x值\n', ])
self.demo_tool_dialog.extension_lib = self.extension_lib
self.demo_tool_dialog.show()
class DemoToolDialog(QDialog):
def __init__(self, parent, button_text: list):
super().__init__(parent)
layout = QHBoxLayout(self)
self.text_edit = QTextEdit()
self.text_edit.append('请先点击左侧按钮运行命令\'x=123\',然后点击右侧按钮获取变量空间中的x值。'
'\n这条命令将以用户不可见的形式执行。\n')
layout.addWidget(self.text_edit)
b = QToolButton(self)
b.setText(button_text[0])
b.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
b.clicked.connect(self.run_shell_command)
layout.addWidget(b)
b = QToolButton(self)
b.setText(button_text[1])
b.clicked.connect(self.get_data)
b.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
layout.addWidget(b)
self.setLayout(layout)
def run_shell_command(self):
console = self.extension_lib.get_interface('ipython_console')
if console is None:
raise Exception('dependency ipython console not found')
console.run_command(command='x=123',hint_text='执行命令',hidden=False)
self.text_edit.append('命令已执行,请查看工作空间。\n')
self.extension_lib.UI.raise_dock_into_view('ipython_console')#调用命令,将控制台提升到窗口最上方。
def get_data(self):
try:
var = self.extension_lib.get_var('x')
except:
self.text_edit.append('x变量不存在,请先点击左侧按钮对x赋值。\n')
return
self.text_edit.append('成功获取变量‘x’,值为' + repr(var) + '\n你可以在控制台中运行命令改变x的值,'
'并且再次点击右侧按钮获取它,查看有无变化。\n')
def closeEvent(self, a0: 'QCloseEvent') -> None:
'''
保证插件的退出动作,不会影响到主界面的其他部位。
'''
a0.accept()
self.deleteLater()
if __name__ == '__main__':
'''
这个测试只是用于调试界面,不能点击按钮
'''
from PyQt5.QtWidgets import QApplication
import sys
app = QApplication(sys.argv)
form = DemoToolDialog(None,['aaa','dddddd'])
form.show()
sys.exit(app.exec_())
一共有四个类——Interface,Extension,DemoToolButton,DemoToolDialog。 Interface和Extension是基础教程中已经说明过的模板类,在这里不再赘述。
DemoToolButton
DemoToolButton是一个插入工具栏的按钮,在json中需要注册它的名称。
当点击的时候,调用show_dialog
方法,直接唤出DemoToolDialog对话框。
DemoToolDialog
这是一个对话框类。
说到对话框,你很可能想到的是弹出一条错误信息,只给你留一两个按钮的小窗体。但实际上对话框可以做的很大很大。
当然你可以发现,这个类与其他的对话框最大的不同就是,它调用了插件接口extension_lib,这个插件接口却依赖于主界面。如果主界面不启动,那么插件是不可能独立运行的,调试的确带来了一定的不便。但是,如果不调用extension_lib这个接口,插件的意义又何在呢?
因此,对开发者的建议是,可以先写好界面中不依赖pyminer主程序的部分。加上接口之后,就要插入到Pyminer主程序上面调试了。我们的主界面已经初步优化了启动速度,它的启动时间并不会太长,而且未来还将继续优化,从而为开发者提供更加快捷高效的开发体验。
回到对话框。尽管我不得不承认,这个对话框界面做的非常非常难看——但是它好歹体现了两种基本操作:在控制台中运行命令,以及获取工作空间的数据。
1、在控制台中运行命令。
extension_lib.run_command_in_console(‘x=123’,,hint=’执行命令’) 这一句代码可以运行命令。x=123。hint则是显示的提示文字。
2、获取工作空间的数据。
extension_lib.get_var(‘x’)。
这句代码的意思是获取工作空间的数据,数据的变量名为x。
当然,如果你问:“如果,我想在对话框中嵌入一个列表框,把工作区里面全部的变量名称都显示出来,点击某个变量的时候,就加载它到表格里/在绘图窗口中绘制出来/存储为文件/(…以下省略n种可能的操作),你说这样可以吗?”
答案当然是肯定的。不过,在这里篇幅所限,不能多说了。其余更多方法,请参阅插件接口的文档!
3、提升窗口
细心如你,可能注意到了以下语句:
extension_lib.raise_dock_into_view(extension_lib.CONSOLE_WIDGET)
这个语句是什么意思呢?答案是将窗口提升到最上方。
PyMiner的主界面中,除了工具栏就是可停靠窗口(继承于QDockWidget)。可停靠窗口既可以单独停靠在主界面之上,又可以摞在一起,就像选项卡那样————但显而易见,它们和选项卡不同,因为选项卡控件的标签在上方,而可停靠窗口的标签在下方。
红圈是可停靠窗口的标签,绿圈是选项卡的标签。
当这些控件摞在一起的时候,就会出现一个问题————假如说控制台不在最上层,你在对话框中执行命令,那么要观察控制台中的变化,你还要点击一次控制台的标签。如果反复执行不同的命令,就要这样来回点来点去,烦煞我也。
为了解决这种令用户抓狂不已的问题,Pyminer引入了“提升窗口到可见”的功能。而这句代码的意思,就是将控制台窗口提升到最上方,使得其可见。
执行前后窗口截图如下:
执行前
执行后
你可以将和控制台叠放在一起的其他窗口置于最上方,再次点击这个对话框的按钮运行命令,你会发现控制台自动蹦到了可见的位置。这就是这条命令的威力。
Note:执行python console命令的时候,不会显示命令的文字,但是可以看到行数在增加,这是正常现象。