vnpy源码阅读学习(3):学习vnpy的界面的实现
学习vnpy的界面的实现
通过简单的学习了PyQt5的一些代码以后,我们基本上可以理解PyQt的一些用法,下面让我们来先研究下vnpy的UI部分的代码。
首先回到上一节看到的run.py(/vnpy/example/trade/run.py)的关于UI部分的代码。
生成QApplication部分
qapp = create_qapp()
我们跟踪得到 create_qapp() 方法是写在 "/vnpy/trader/ui/init.py"上面的。
init.py主要是把一个文件夹变成一个包,方便包的引入和管理,方法写在__init__.py中可以会在引入的时候被直接调用,也就是说不需要在调用的时候通过xxx.method()的形式来调用。init.py详细解释
我们来看看这部分的代码
def excepthook(exctype, value, tb):
## 全局的一个异常处理的钩子,所有的异常都会被处理到这里来
def create_qapp(app_name: str = "VN Trader"):
sys.excepthook = excepthook
# 让窗体可以适应高分辨率屏幕
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
qapp = QtWidgets.QApplication([])
qapp.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
font = QtGui.QFont(SETTINGS["font.family"], SETTINGS["font.size"])
qapp.setFont(font)
icon = QtGui.QIcon(get_icon_path(__file__, "vnpy.ico"))
qapp.setWindowIcon(icon)
if "Windows" in platform.uname():
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
app_name
)
return qapp
class ExceptionDialog(QtWidgets.QDialog):
""""""
#这里是异常窗口的代码
上面的这部分代码就是简单的生成一个QApplication代码,并且指定了全局的异常发生以后弹出异常窗体。需要注意以下代码:
if "Windows" in platform.uname():
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
app_name
)
在Windows 7中,任务栏本身不适用于“应用程序Windows”,它适用于“应用程序用户模型”。例如,如果您运行了多个不同的应用程序实例,并且每个实例都有自己的图标,那么它们将全部分组到一个任务栏图标下。 Windows使用各种启发式方法来决定是否应该对不同的实例进行分组,在这种情况下,它决定将Pythonw.exe托管的所有内容分组到Pythonw.exe的图标下。 正确的解决方案是让Pythonw.exe告诉Windows它只是托管其他应用程序。也许未来的Python版本会这样做。或者,您可以添加一个注册表项来告诉Windows,Pythonw.exe本身只是一个主机而不是一个应用程序。有关AppUserModelIDs的信息,请参阅MSDN文档。 或者,您可以使用Python的Windows调用,明确告诉Windows此进程的正确AppUserModelID:
主窗体生成部分
让我们接着看看UI的主窗体生成部分的代码
main_window = MainWindow(main_engine, event_engine)
main_window.showMaximized()
MainWindows的代码位置在 /vnpy/vnpy/trader/ui/mainwindow.py
在__init__()
方法中就是对常见的self
的属性赋值,没什么稀奇的。我们直接看initUI()
部分的代码。
def init_ui(self):
self.setWindowTitle(self.window_title) #设置标题
self.init_dock()
self.init_toolbar()
self.init_menu()
self.load_window_setting("custom")
我们一个一个看看这部分的函数和功能。
init_dock
def init_dock(self):
""""""
self.trading_widget, trading_dock = self.create_dock(TradingWidget, "交易", QtCore.Qt.LeftDockWidgetArea)
tick_widget, tick_dock = self.create_dock(TickMonitor, "行情", QtCore.Qt.RightDockWidgetArea)
#中间省略掉N多调用create_dock的方法
self.tabifyDockWidget(active_dock, order_dock)
self.save_window_setting("default")
在init_dock
的方法中首先调用了create_dock
咱们来研究下create_dock
的方法。
def create_dock(
self, widget_class: QtWidgets.QWidget, name: str, area: int
):
widget = widget_class(self.main_engine, self.event_engine)
dock = QtWidgets.QDockWidget(name)
dock.setWidget(widget)
dock.setObjectName(name)
dock.setFeatures(dock.DockWidgetFloatable | dock.DockWidgetMovable)
self.addDockWidget(area, dock)
return widget, dock
我们基本上可以这样理解,就是实例化了一个自定义的Widget,然后放入docker中.
docker大概是这样的一个概念【浮动窗口】。
我搜索到了一篇详细的教程:PyQt5高级界面控件之QDockWidget(八)
为了联系docker我简单的写了一段代码:
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class DockDemo(QMainWindow):
def __init__(self):
super().__init__()
tradeWidget = TradeWidget()
self.trade_docker = QDockWidget('交易窗口', self)
self.trade_docker.setWidget(tradeWidget)
self.trade_docker.setFeatures(self.trade_docker.DockWidgetFloatable | self.trade_docker.DockWidgetMovable)
self.trade_docker.setObjectName("交易窗口")
self.trade_docker.setFloating(False)
self.addDockWidget(Qt.RightDockWidgetArea,self.trade_docker)
tickWidget = TickMonitorWidget()
self.tick_docker = QDockWidget('行情窗口', self)
self.tick_docker.setWidget(tickWidget)
self.tick_docker.setFloating(False)
self.addDockWidget(Qt.LeftDockWidgetArea, self.tick_docker)
self.show()
class TradeWidget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("这里是交易窗口")
button = QPushButton('交易按钮', self)
button.move(10, 20)
self.show()
class TickMonitorWidget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("这里是行情窗口")
button = QPushButton('行情', self)
button.move(10, 20)
self.show()
app = QApplication([])
dd = DockDemo()
exit(app.exec_())
init_toolbar
这个没什么好说的,就是初始化工具栏
init_menu()
这个方法是生成菜单,里面有一个有趣的方法把菜单和插槽连接起来
self.add_menu_action(
help_menu,
"查询合约",
"contract.ico",
partial(self.open_widget, ContractManager, "contract"),
)
def add_menu_action(
self,
menu: QtWidgets.QMenu,
action_name: str,
icon_name: str,
func: Callable,
):
""""""
icon = QtGui.QIcon(get_icon_path(__file__, icon_name))
action = QtWidgets.QAction(action_name, self)
action.triggered.connect(func)
action.setIcon(icon)
menu.addAction(action)
保存windows布局和恢复布局
def save_window_setting(self, name: str):
"""
Save current window size and state by trader path and setting name.
"""
settings = QtCore.QSettings(self.window_title, name)
settings.setValue("state", self.saveState())
settings.setValue("geometry", self.saveGeometry())
def load_window_setting(self, name: str):
"""
Load previous window size and state by trader path and setting name.
"""
settings = QtCore.QSettings(self.window_title, name)
state = settings.value("state")
geometry = settings.value("geometry")
if isinstance(state, QtCore.QByteArray):
self.restoreState(state)
self.restoreGeometry(geometry)
def restore_window_setting(self):
"""
Restore window to default setting.
"""
self.load_window_setting("default")
self.showMaximized()
打开一个定义的Wiget
def open_widget(self, widget_class: QtWidgets.QWidget, name: str):
"""
Open contract manager.
"""
widget = self.widgets.get(name, None)
if not widget:
widget = widget_class(self.main_engine, self.event_engine)
self.widgets[name] = widget
if isinstance(widget, QtWidgets.QDialog):
widget.exec_()
else:
widget.show()
这个简单,就是当菜单和工具栏调用打开一个功能窗口的时候,首先查找这个窗口是否在wigets方法里面。如果不的话,实例化,添加进去。然后打开.
需要注意的是,如果是widget直接调用show
,如果是dialog需要调用的是exec_()
方法
vnpy源码阅读学习(3):学习vnpy的界面的实现的更多相关文章
- vnpy源码阅读学习(1):准备工作
vnpy源码阅读学习 目标 通过阅读vnpy,学习量化交易系统的一些设计思路和理念. 通过阅读vnpy学习python项目开发的一些技巧和范式 通过vnpy的设计,可以用python复现一个小型简单的 ...
- vnpy源码阅读学习(5):关于MainEngine的代码阅读
关于MainEngine的代码阅读 在入口文件中,我们看到了除了窗体界面的产生,还有关于MainEngine和EventEngin部分.今天来学习下MainEngine的代码. 首先在run代码中,我 ...
- vnpy源码阅读学习(8):关于app
关于app 在入口程序中,我们看到了把 gateway,app, 各类的engine都添加到mainEngine中来.不难猜测gateway主要是处理跟外部的行情,接口各方面的代码,通过别人的文章也不 ...
- vnpy源码阅读学习(4):自己写一个类似vnpy的UI框架
自己写一个类似vnpy的界面框架 概述 通过之前3次对vnpy的界面代码的研究,我们去模仿做一个vn.py的大框架.巩固一下PyQt5的学习. 这部分的代码相对来说没有难度和深度,基本上就是把PyQt ...
- vnpy源码阅读学习(9)回到OptionMaster
回到OptionMaster 根据我们对APP调用的代码阅读,我们基本上知道了一个APP是如何被调用,那么我们回到OptionMaster学习下这个APP的实现. 看看结构 class OptionM ...
- vnpy源码阅读学习(2):学习PyQt5
PyQt5的学习 花费了一个下午把PyQt5大概的学习了下.找了一个教程 PyQt5教程 跟着挨着把上面的案例做了一遍,大概知道PyQt5是如何生成窗体,以及控件的.基本上做到如果有需求要实现,查查手 ...
- vnpy源码阅读学习(7):串在一起
串在一起 我们已经分析了UI.MainEngine.EventEngine.然后他们几个是如何发挥作用的呢?我总结了一张图: 我们来具体的看看UI部分是如何跟EventEngine穿插起来的 \exa ...
- Kubernetes 学习(九)Kubernetes 源码阅读之正式篇------核心组件之 Scheduler
0. 前言 继续上一篇博客阅读 Kubernetes 源码,参照<k8s 源码阅读>首先学习 Kubernetes 的一些核心组件,首先是 kube-scheduler 本文严重参考原文: ...
- 搭建 Spring 源码阅读环境
前言 有一个Spring源码阅读环境是学习Spring的基础.笔者借鉴了网上很多搭建环境的方法,也尝试了很多,接下来总结两种个人认为比较简便实用的方法.读者可根据自己的需要自行选择. 方法一:搭建基础 ...
随机推荐
- js最简单的对数字的排序
文章地址 https://www.cnblogs.com/sandraryan/ JS自己有sort可以用来排序,可以排string会转为ASCII比较,但是,ASCII对数字的排序不合理 < ...
- Python--day25--接口类
接口类,起规范作用
- Python--day46--用户管理设计方案介绍
1,基于用户权限管理: 2,基于角色的权限管理: 开始一个项目如果要100天的,可能70天都在设计,比如设计数据库表结构,最后30天才是写代码.设计是最难的,写代码是最简单的. 还有一个重要的一点,写 ...
- 高可用之nginx配置文件详解
#user nobody; worker_processes 1;##工作线程数,一般和cpu的核数相同:可通过ps -ef | nginx查看线程数 #配置错误日志位置 #error_log log ...
- 【ts】 VSCode自动编译TypeScript终端报错
一.点击终端--运行任务--选择tsc:监视 - tsconfig.json后,终端报出了如下错误:error TS5058: The specified path does not exist 在网 ...
- 2019-9-2-C#同步方法转异步
title author date CreateTime categories C#同步方法转异步 lindexi 2019-09-02 12:57:37 +0800 2018-2-13 17:23: ...
- win10 uwp 如何使用DataTemplate
这是数据模板,一般用在数组的绑定,显示数组中的元素. 假如我们有一个列表,列表里是书,包括书名.作者.还有出版,那么我们只有源信息,如何把它显示到我们的ListView,就需要DataTemplate ...
- router-link-active的作用
如上图所示,创建了3个路由跳转选项,css实现后的效果如下 ↓↓↓ 当我切换“电影” “影院” “我的” 三个路由选项时,文字由黑色变成红色 此时可用vue自带的 router-link-active ...
- Win7安装和配置Apache
一.版本介绍 首先,我们需要下载Apache2.4服务器:http://www.apachehaus.com/cgi-bin/download.plx#APACHE24VC14 关于现在那个版 ...
- redis 集群模式
redis cluster 介绍 自动将数据进行分片,每个 master 上放一部分数据 提供内置的高可用支持,部分 master 不可用时,还是可以继续工作的 在 redis cluster 架构下 ...