对话框页面

在pyminer中自带一个对话框插件,点击之后,可以获取工作空间变量、向控制台注入命令并且显示。 这个插件是如何实现的呢?请让我们继续往下看。 对话框插件位置

源文件解析

它的源文件位置为(pyminer2/extensions/packages/extension_dialog_demo),如图所示: 输入图片说明

json编写

  1. {
  2. "name": "extension_dialog_demo",
  3. "display_name": "对话框插件demo",
  4. "version": "0.1",
  5. "description": "好多介绍",
  6. "icon": "python.jpg",
  7. "interface": {
  8. "file": "main.py",
  9. "interface": "Interface"
  10. },
  11. "widgets": [
  12. {
  13. "file": "main.py",
  14. "widget": "DemoToolButton",
  15. "position": "append_to_toolbar",
  16. "config": {
  17. "toolbar": "toolbar_home",
  18. "message": "no",
  19. "name": "demo_tool_button"
  20. }
  21. }
  22. ],
  23. "requirements": [
  24. ]
  25. }

在以上的json中,我们可以发现这几个信息:

  • 1、我们的对话框窗体类,并没有在json中体现出来。json中只注册了一个DemoToolButton。看名字的话,这像是一个工具栏按钮。 没错,就是这样的。对话框在唤出时动态生成,关闭之后就释放掉了。这样可以节省不少内存。

  • 2、我们需要改写的主要是”widgets”的”config”属性。其中比较重要的是: — toolbar参数。这个参数的可以说明将这个东西插入到哪个工具栏中。而toolbar_home的意思就是主页工具栏。目前只有主页工具栏,所以就插入主页中。 — message参数:用处不大。 — name参数:按钮控件的名称。

main.py文件解析

  1. """
  2. 作者:@吴宫幽径
  3. 说明:
  4. dialog无需写在json里面,直接调用主界面的控件就可以了。
  5. """
  6. from PyQt5.QtGui import QCloseEvent
  7. from PyQt5.QtCore import Qt
  8. from PyQt5.QtWidgets import QDialog, QHBoxLayout, QToolButton, QTextEdit, QSizePolicy
  9. from pyminer2.extensions.extensionlib import BaseExtension,BaseInterface
  10. class Extension(BaseExtension):
  11. def on_load(self):
  12. self.demo_tool_button = self.widgets['DemoToolButton']
  13. self.demo_tool_button.extension_lib = self.extension_lib
  14. print("对话框示例被加载")
  15. def on_install(self):
  16. print('被安装')
  17. def on_uninstall(self):
  18. print("被卸载")
  19. class Interface(BaseInterface):
  20. def hello(self):
  21. print("Hello,来自对话框示例")
  22. class DemoToolButton(QToolButton):
  23. def __init__(self, parent=None):
  24. super().__init__(parent)
  25. self.setText('显示\n插件示例\n的对话框')
  26. self.clicked.connect(self.show_dialog)
  27. def show_dialog(self):
  28. """
  29. 显示一个插件示例所弹出的对话框。
  30. """
  31. self.demo_tool_dialog = DemoToolDialog(self, ['执行python命令\'x=123\'', '获取数据x值\n', ])
  32. self.demo_tool_dialog.extension_lib = self.extension_lib
  33. self.demo_tool_dialog.show()
  34. class DemoToolDialog(QDialog):
  35. def __init__(self, parent, button_text: list):
  36. super().__init__(parent)
  37. layout = QHBoxLayout(self)
  38. self.text_edit = QTextEdit()
  39. self.text_edit.append('请先点击左侧按钮运行命令\'x=123\',然后点击右侧按钮获取变量空间中的x值。'
  40. '\n这条命令将以用户不可见的形式执行。\n')
  41. layout.addWidget(self.text_edit)
  42. b = QToolButton(self)
  43. b.setText(button_text[0])
  44. b.setSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)
  45. b.clicked.connect(self.run_shell_command)
  46. layout.addWidget(b)
  47. b = QToolButton(self)
  48. b.setText(button_text[1])
  49. b.clicked.connect(self.get_data)
  50. b.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
  51. layout.addWidget(b)
  52. self.setLayout(layout)
  53. def run_shell_command(self):
  54. console = self.extension_lib.get_interface('ipython_console')
  55. if console is None:
  56. raise Exception('dependency ipython console not found')
  57. console.run_command(command='x=123',hint_text='执行命令',hidden=False)
  58. self.text_edit.append('命令已执行,请查看工作空间。\n')
  59. self.extension_lib.UI.raise_dock_into_view('ipython_console')#调用命令,将控制台提升到窗口最上方。
  60. def get_data(self):
  61. try:
  62. var = self.extension_lib.get_var('x')
  63. except:
  64. self.text_edit.append('x变量不存在,请先点击左侧按钮对x赋值。\n')
  65. return
  66. self.text_edit.append('成功获取变量‘x’,值为' + repr(var) + '\n你可以在控制台中运行命令改变x的值,'
  67. '并且再次点击右侧按钮获取它,查看有无变化。\n')
  68. def closeEvent(self, a0: 'QCloseEvent') -> None:
  69. '''
  70. 保证插件的退出动作,不会影响到主界面的其他部位。
  71. '''
  72. a0.accept()
  73. self.deleteLater()
  74. if __name__ == '__main__':
  75. '''
  76. 这个测试只是用于调试界面,不能点击按钮
  77. '''
  78. from PyQt5.QtWidgets import QApplication
  79. import sys
  80. app = QApplication(sys.argv)
  81. form = DemoToolDialog(None,['aaa','dddddd'])
  82. form.show()
  83. 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、提升窗口

细心如你,可能注意到了以下语句:

  1. extension_lib.raise_dock_into_view(extension_lib.CONSOLE_WIDGET)

这个语句是什么意思呢?答案是将窗口提升到最上方。

PyMiner的主界面中,除了工具栏就是可停靠窗口(继承于QDockWidget)。可停靠窗口既可以单独停靠在主界面之上,又可以摞在一起,就像选项卡那样————但显而易见,它们和选项卡不同,因为选项卡控件的标签在上方,而可停靠窗口的标签在下方。

插件开发教程——对话框界面详解 - 图3

红圈是可停靠窗口的标签,绿圈是选项卡的标签。

当这些控件摞在一起的时候,就会出现一个问题————假如说控制台不在最上层,你在对话框中执行命令,那么要观察控制台中的变化,你还要点击一次控制台的标签。如果反复执行不同的命令,就要这样来回点来点去,烦煞我也。

为了解决这种令用户抓狂不已的问题,Pyminer引入了“提升窗口到可见”的功能。而这句代码的意思,就是将控制台窗口提升到最上方,使得其可见。

执行前后窗口截图如下:

执行前

输入图片说明

执行后

执行后

你可以将和控制台叠放在一起的其他窗口置于最上方,再次点击这个对话框的按钮运行命令,你会发现控制台自动蹦到了可见的位置。这就是这条命令的威力。

Note:执行python console命令的时候,不会显示命令的文字,但是可以看到行数在增加,这是正常现象。