# encoding: UTF-8 import psutil import traceback from vnpy.trader.vtFunction import loadIconPath from vnpy.trader.vtGlobal import globalSetting from uiCryptoWidget import * ######################################################################## class MainWindow(QtWidgets.QMainWindow): """主窗口""" signalStatusBar = QtCore.Signal(type(Event())) #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine): """Constructor""" super(MainWindow, self).__init__() self.mainEngine = mainEngine self.eventEngine = eventEngine l = self.mainEngine.getAllGatewayDetails() self.gatewayNameList = [d['gatewayName'] for d in l] self.widgetDict = {} # 用来保存子窗口的字典 # 获取主引擎中的上层应用信息 self.appDetailList = self.mainEngine.getAllAppDetails() self.initUi() self.loadWindowSettings('custom') #---------------------------------------------------------------------- def initUi(self): """初始化界面""" self.setWindowTitle('VN Crypto') self.initCentral() self.initMenu() self.initStatusBar() #---------------------------------------------------------------------- def initCentral(self): """初始化中心区域""" widgetTradingW, dockTradingW = self.createDock(TradingWidget, vtText.TRADING, QtCore.Qt.RightDockWidgetArea) widgetMarketM, dockMarketM = self.createDock(MarketMonitor, vtText.MARKET_DATA, QtCore.Qt.LeftDockWidgetArea) widgetOrderM, dockOrderM = self.createDock(OrderMonitor, vtText.ORDER, QtCore.Qt.LeftDockWidgetArea) widgetWorkingOrderM, dockWorkingOrderM = self.createDock(WorkingOrderMonitor, vtText.WORKING_ORDER, QtCore.Qt.LeftDockWidgetArea) widgetTradeM, dockTradeM = self.createDock(TradeMonitor, vtText.TRADE, QtCore.Qt.LeftDockWidgetArea) widgetAccountM, dockAccountM = self.createDock(AccountMonitor, vtText.ACCOUNT, QtCore.Qt.RightDockWidgetArea) widgetPositionM, dockPositionM = self.createDock(PositionMonitor, vtText.POSITION, QtCore.Qt.RightDockWidgetArea) widgetLogM, dockLogM = self.createDock(LogMonitor, vtText.LOG, QtCore.Qt.RightDockWidgetArea) self.tabifyDockWidget(dockOrderM, dockWorkingOrderM) self.tabifyDockWidget(dockPositionM, dockAccountM) # 保存默认设置 self.saveWindowSettings('default') #---------------------------------------------------------------------- def initMenu(self): """初始化菜单""" # 创建菜单 menubar = self.menuBar() # 设计为只显示存在的接口 gatewayDetails = self.mainEngine.getAllGatewayDetails() sysMenu = menubar.addMenu(vtText.SYSTEM) for d in gatewayDetails: if d['gatewayType'] == GATEWAYTYPE_FUTURES: self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName']) sysMenu.addSeparator() for d in gatewayDetails: if d['gatewayType'] == GATEWAYTYPE_EQUITY: self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName']) sysMenu.addSeparator() for d in gatewayDetails: if d['gatewayType'] == GATEWAYTYPE_INTERNATIONAL: self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName']) sysMenu.addSeparator() for d in gatewayDetails: if d['gatewayType'] == GATEWAYTYPE_BTC: self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName']) sysMenu.addSeparator() for d in gatewayDetails: if d['gatewayType'] == GATEWAYTYPE_DATA: self.addConnectAction(sysMenu, d['gatewayName'], d['gatewayDisplayName']) sysMenu.addSeparator() sysMenu.addAction(self.createAction(vtText.CONNECT_DATABASE, self.mainEngine.dbConnect, loadIconPath('database.ico'))) sysMenu.addSeparator() sysMenu.addAction(self.createAction(vtText.EXIT, self.close, loadIconPath('exit.ico'))) # 功能应用 appMenu = menubar.addMenu(vtText.APPLICATION) for appDetail in self.appDetailList: # 如果没有应用界面,则不添加菜单按钮 if not appDetail['appWidget']: continue function = self.createOpenAppFunction(appDetail) action = self.createAction(appDetail['appDisplayName'], function, loadIconPath(appDetail['appIco'])) appMenu.addAction(action) # 帮助 helpMenu = menubar.addMenu(vtText.HELP) helpMenu.addAction(self.createAction(vtText.CONTRACT_SEARCH, self.openContract, loadIconPath('contract.ico'))) helpMenu.addAction(self.createAction(vtText.EDIT_SETTING, self.openSettingEditor, loadIconPath('editor.ico'))) helpMenu.addSeparator() helpMenu.addAction(self.createAction(vtText.RESTORE, self.restoreWindow, loadIconPath('restore.ico'))) helpMenu.addAction(self.createAction(vtText.ABOUT, self.openAbout, loadIconPath('about.ico'))) helpMenu.addSeparator() helpMenu.addAction(self.createAction(vtText.TEST, self.test, loadIconPath('test.ico'))) #---------------------------------------------------------------------- def initStatusBar(self): """初始化状态栏""" self.statusLabel = QtWidgets.QLabel() self.statusLabel.setAlignment(QtCore.Qt.AlignLeft) self.statusBar().addPermanentWidget(self.statusLabel) self.statusLabel.setText(self.getCpuMemory()) self.sbCount = 0 self.sbTrigger = 10 # 10秒刷新一次 self.signalStatusBar.connect(self.updateStatusBar) self.eventEngine.register(EVENT_TIMER, self.signalStatusBar.emit) #---------------------------------------------------------------------- def updateStatusBar(self, event): """在状态栏更新CPU和内存信息""" self.sbCount += 1 if self.sbCount == self.sbTrigger: self.sbCount = 0 self.statusLabel.setText(self.getCpuMemory()) #---------------------------------------------------------------------- def getCpuMemory(self): """获取CPU和内存状态信息""" cpuPercent = psutil.cpu_percent() memoryPercent = psutil.virtual_memory().percent return vtText.CPU_MEMORY_INFO.format(cpu=cpuPercent, memory=memoryPercent) #---------------------------------------------------------------------- def addConnectAction(self, menu, gatewayName, displayName=''): """增加连接功能""" if gatewayName not in self.gatewayNameList: return def connect(): self.mainEngine.connect(gatewayName) if not displayName: displayName = gatewayName actionName = vtText.CONNECT + displayName connectAction = self.createAction(actionName, connect, loadIconPath('connect.ico')) menu.addAction(connectAction) #---------------------------------------------------------------------- def createAction(self, actionName, function, iconPath=''): """创建操作功能""" action = QtWidgets.QAction(actionName, self) action.triggered.connect(function) if iconPath: icon = QtGui.QIcon(iconPath) action.setIcon(icon) return action #---------------------------------------------------------------------- def createOpenAppFunction(self, appDetail): """创建打开应用UI的函数""" def openAppFunction(): appName = appDetail['appName'] try: self.widgetDict[appName].show() except KeyError: appEngine = self.mainEngine.getApp(appName) self.widgetDict[appName] = appDetail['appWidget'](appEngine, self.eventEngine) self.widgetDict[appName].show() return openAppFunction #---------------------------------------------------------------------- def test(self): """测试按钮用的函数""" # 有需要使用手动触发的测试函数可以写在这里 pass #---------------------------------------------------------------------- def openAbout(self): """打开关于""" try: self.widgetDict['aboutW'].show() except KeyError: self.widgetDict['aboutW'] = AboutWidget(self) self.widgetDict['aboutW'].show() #---------------------------------------------------------------------- def openContract(self): """打开合约查询""" try: self.widgetDict['contractM'].show() except KeyError: self.widgetDict['contractM'] = ContractManager(self.mainEngine) self.widgetDict['contractM'].show() #---------------------------------------------------------------------- def openSettingEditor(self): """打开配置编辑""" try: self.widgetDict['settingEditor'].show() except KeyError: self.widgetDict['settingEditor'] = SettingEditor(self.mainEngine) self.widgetDict['settingEditor'].show() #---------------------------------------------------------------------- def closeEvent(self, event): """关闭事件""" reply = QtWidgets.QMessageBox.question(self, vtText.EXIT, vtText.CONFIRM_EXIT, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: for widget in self.widgetDict.values(): widget.close() self.saveWindowSettings('custom') self.mainEngine.exit() event.accept() else: event.ignore() #---------------------------------------------------------------------- def createDock(self, widgetClass, widgetName, widgetArea): """创建停靠组件""" widget = widgetClass(self.mainEngine, self.eventEngine) dock = QtWidgets.QDockWidget(widgetName) dock.setWidget(widget) dock.setObjectName(widgetName) dock.setFeatures(dock.DockWidgetFloatable|dock.DockWidgetMovable) self.addDockWidget(widgetArea, dock) return widget, dock #---------------------------------------------------------------------- def saveWindowSettings(self, settingName): """保存窗口设置""" settings = QtCore.QSettings('vn.trader', settingName) settings.setValue('state', self.saveState()) settings.setValue('geometry', self.saveGeometry()) #---------------------------------------------------------------------- def loadWindowSettings(self, settingName): """载入窗口设置""" settings = QtCore.QSettings('vn.trader', settingName) state = settings.value('state') geometry = settings.value('geometry') # 尚未初始化 if state is None: return # 老版PyQt elif isinstance(state, QtCore.QVariant): self.restoreState(state.toByteArray()) self.restoreGeometry(geometry.toByteArray()) # 新版PyQt elif isinstance(state, QtCore.QByteArray): self.restoreState(state) self.restoreGeometry(geometry) # 异常 else: content = u'载入窗口配置异常,请检查' self.mainEngine.writeLog(content) #---------------------------------------------------------------------- def restoreWindow(self): """还原默认窗口设置(还原停靠组件位置)""" self.loadWindowSettings('default') self.showMaximized() ######################################################################## class AboutWidget(QtWidgets.QDialog): """显示关于信息""" #---------------------------------------------------------------------- def __init__(self, parent=None): """Constructor""" super(AboutWidget, self).__init__(parent) self.initUi() #---------------------------------------------------------------------- def initUi(self): """""" self.setWindowTitle(vtText.ABOUT + 'VN Crypto') text = u""" Developed by Traders, for Traders. License:MIT Website:www.vnpy.org Github:www.github.com/vnpy/vnpy """ label = QtWidgets.QLabel() label.setText(text) label.setMinimumWidth(500) vbox = QtWidgets.QVBoxLayout() vbox.addWidget(label) self.setLayout(vbox)