示例#1
0
class TradingWidget(QtGui.QFrame):
    """简单交易组件"""
    signal = QtCore.pyqtSignal(type(Event()))

    directionList = [DIRECTION_LONG, DIRECTION_SHORT]

    offsetList = [
        OFFSET_OPEN, OFFSET_CLOSE, OFFSET_CLOSEYESTERDAY, OFFSET_CLOSETODAY
    ]

    priceTypeList = [
        PRICETYPE_LIMITPRICE, PRICETYPE_MARKETPRICE, PRICETYPE_FAK,
        PRICETYPE_FOK
    ]

    exchangeList = [
        EXCHANGE_NONE, EXCHANGE_CFFEX, EXCHANGE_SHFE, EXCHANGE_DCE,
        EXCHANGE_CZCE, EXCHANGE_SSE, EXCHANGE_SZSE, EXCHANGE_SGE,
        EXCHANGE_HKEX, EXCHANGE_HKFE, EXCHANGE_SMART, EXCHANGE_ICE,
        EXCHANGE_CME, EXCHANGE_NYMEX, EXCHANGE_GLOBEX, EXCHANGE_IDEALPRO
    ]

    currencyList = [CURRENCY_NONE, CURRENCY_CNY, CURRENCY_HKD, CURRENCY_USD]

    productClassList = [
        PRODUCT_NONE, PRODUCT_EQUITY, PRODUCT_FUTURES, PRODUCT_OPTION,
        PRODUCT_FOREX
    ]

    gatewayList = ['']

    #----------------------------------------------------------------------
    def __init__(self, mainEngine, eventEngine, parent=None):
        """Constructor"""
        super(TradingWidget, self).__init__(parent)
        self.mainEngine = mainEngine
        self.eventEngine = eventEngine

        self.symbol = ''

        # 添加交易接口
        self.gatewayList.extend(mainEngine.getAllGatewayNames())

        self.initUi()
        self.connectSignal()

    #----------------------------------------------------------------------
    def initUi(self):
        """初始化界面"""
        self.setWindowTitle(vtText.TRADING)
        self.setMaximumWidth(400)
        self.setFrameShape(self.Box)  # 设置边框
        self.setLineWidth(1)

        # 左边部分
        labelSymbol = QtGui.QLabel(vtText.CONTRACT_SYMBOL)
        labelName = QtGui.QLabel(vtText.CONTRACT_NAME)
        labelDirection = QtGui.QLabel(vtText.DIRECTION)
        labelOffset = QtGui.QLabel(vtText.OFFSET)
        labelPrice = QtGui.QLabel(vtText.PRICE)
        self.checkFixed = QtGui.QCheckBox(u'')  # 价格固定选择框
        labelVolume = QtGui.QLabel(vtText.VOLUME)
        labelPriceType = QtGui.QLabel(vtText.PRICE_TYPE)
        labelExchange = QtGui.QLabel(vtText.EXCHANGE)
        labelCurrency = QtGui.QLabel(vtText.CURRENCY)
        labelProductClass = QtGui.QLabel(vtText.PRODUCT_CLASS)
        labelGateway = QtGui.QLabel(vtText.GATEWAY)

        self.lineSymbol = QtGui.QLineEdit()
        self.lineName = QtGui.QLineEdit()

        self.comboDirection = QtGui.QComboBox()
        self.comboDirection.addItems(self.directionList)

        self.comboOffset = QtGui.QComboBox()
        self.comboOffset.addItems(self.offsetList)

        self.spinPrice = QtGui.QDoubleSpinBox()
        self.spinPrice.setDecimals(4)
        self.spinPrice.setMinimum(-10000)  # 原来是0,为支持套利,改为-10000
        self.spinPrice.setMaximum(100000)

        self.spinVolume = QtGui.QSpinBox()
        self.spinVolume.setMinimum(0)
        self.spinVolume.setMaximum(1000000)

        self.comboPriceType = QtGui.QComboBox()
        self.comboPriceType.addItems(self.priceTypeList)

        self.comboExchange = QtGui.QComboBox()
        self.comboExchange.addItems(self.exchangeList)

        self.comboCurrency = QtGui.QComboBox()
        self.comboCurrency.addItems(self.currencyList)

        self.comboProductClass = QtGui.QComboBox()
        self.comboProductClass.addItems(self.productClassList)

        self.comboGateway = QtGui.QComboBox()
        self.comboGateway.addItems(self.gatewayList)

        #self.lineOrder = QtGui.QLineEdit()

        gridleft = QtGui.QGridLayout()
        gridleft.addWidget(labelSymbol, 0, 0)
        gridleft.addWidget(labelName, 1, 0)
        gridleft.addWidget(labelDirection, 2, 0)
        gridleft.addWidget(labelOffset, 3, 0)
        gridleft.addWidget(labelPrice, 4, 0)
        gridleft.addWidget(labelVolume, 5, 0)
        gridleft.addWidget(labelPriceType, 6, 0)
        gridleft.addWidget(labelExchange, 7, 0)

        gridleft.addWidget(labelCurrency, 8, 0)
        gridleft.addWidget(labelProductClass, 9, 0)
        gridleft.addWidget(labelGateway, 10, 0)

        gridleft.addWidget(self.lineSymbol, 0, 1, 1, -1)
        gridleft.addWidget(self.lineName, 1, 1, 1, -1)
        gridleft.addWidget(self.comboDirection, 2, 1, 1, -1)
        gridleft.addWidget(self.comboOffset, 3, 1, 1, -1)
        gridleft.addWidget(self.checkFixed, 4, 1)
        gridleft.addWidget(self.spinPrice, 4, 2)
        gridleft.addWidget(self.spinVolume, 5, 1, 1, -1)
        gridleft.addWidget(self.comboPriceType, 6, 1, 1, -1)
        gridleft.addWidget(self.comboExchange, 7, 1, 1, -1)
        gridleft.addWidget(self.comboCurrency, 8, 1, 1, -1)
        gridleft.addWidget(self.comboProductClass, 9, 1, 1, -1)
        gridleft.addWidget(self.comboGateway, 10, 1, 1, -1)

        # 右边部分
        labelBid1 = QtGui.QLabel(vtText.BID_1)
        labelBid2 = QtGui.QLabel(vtText.BID_2)
        labelBid3 = QtGui.QLabel(vtText.BID_3)
        labelBid4 = QtGui.QLabel(vtText.BID_4)
        labelBid5 = QtGui.QLabel(vtText.BID_5)

        labelAsk1 = QtGui.QLabel(vtText.ASK_1)
        labelAsk2 = QtGui.QLabel(vtText.ASK_2)
        labelAsk3 = QtGui.QLabel(vtText.ASK_3)
        labelAsk4 = QtGui.QLabel(vtText.ASK_4)
        labelAsk5 = QtGui.QLabel(vtText.ASK_5)

        self.labelBidPrice1 = QtGui.QLabel()
        self.labelBidPrice2 = QtGui.QLabel()
        self.labelBidPrice3 = QtGui.QLabel()
        self.labelBidPrice4 = QtGui.QLabel()
        self.labelBidPrice5 = QtGui.QLabel()
        self.labelBidVolume1 = QtGui.QLabel()
        self.labelBidVolume2 = QtGui.QLabel()
        self.labelBidVolume3 = QtGui.QLabel()
        self.labelBidVolume4 = QtGui.QLabel()
        self.labelBidVolume5 = QtGui.QLabel()

        self.labelAskPrice1 = QtGui.QLabel()
        self.labelAskPrice2 = QtGui.QLabel()
        self.labelAskPrice3 = QtGui.QLabel()
        self.labelAskPrice4 = QtGui.QLabel()
        self.labelAskPrice5 = QtGui.QLabel()
        self.labelAskVolume1 = QtGui.QLabel()
        self.labelAskVolume2 = QtGui.QLabel()
        self.labelAskVolume3 = QtGui.QLabel()
        self.labelAskVolume4 = QtGui.QLabel()
        self.labelAskVolume5 = QtGui.QLabel()

        labelLast = QtGui.QLabel(vtText.LAST)
        self.labelLastPrice = QtGui.QLabel()
        self.labelReturn = QtGui.QLabel()

        self.labelLastPrice.setMinimumWidth(60)
        self.labelReturn.setMinimumWidth(60)

        gridRight = QtGui.QGridLayout()
        gridRight.addWidget(labelAsk5, 0, 0)
        gridRight.addWidget(labelAsk4, 1, 0)
        gridRight.addWidget(labelAsk3, 2, 0)
        gridRight.addWidget(labelAsk2, 3, 0)
        gridRight.addWidget(labelAsk1, 4, 0)
        gridRight.addWidget(labelLast, 5, 0)
        gridRight.addWidget(labelBid1, 6, 0)
        gridRight.addWidget(labelBid2, 7, 0)
        gridRight.addWidget(labelBid3, 8, 0)
        gridRight.addWidget(labelBid4, 9, 0)
        gridRight.addWidget(labelBid5, 10, 0)

        gridRight.addWidget(self.labelAskPrice5, 0, 1)
        gridRight.addWidget(self.labelAskPrice4, 1, 1)
        gridRight.addWidget(self.labelAskPrice3, 2, 1)
        gridRight.addWidget(self.labelAskPrice2, 3, 1)
        gridRight.addWidget(self.labelAskPrice1, 4, 1)
        gridRight.addWidget(self.labelLastPrice, 5, 1)
        gridRight.addWidget(self.labelBidPrice1, 6, 1)
        gridRight.addWidget(self.labelBidPrice2, 7, 1)
        gridRight.addWidget(self.labelBidPrice3, 8, 1)
        gridRight.addWidget(self.labelBidPrice4, 9, 1)
        gridRight.addWidget(self.labelBidPrice5, 10, 1)

        gridRight.addWidget(self.labelAskVolume5, 0, 2)
        gridRight.addWidget(self.labelAskVolume4, 1, 2)
        gridRight.addWidget(self.labelAskVolume3, 2, 2)
        gridRight.addWidget(self.labelAskVolume2, 3, 2)
        gridRight.addWidget(self.labelAskVolume1, 4, 2)
        gridRight.addWidget(self.labelReturn, 5, 2)
        gridRight.addWidget(self.labelBidVolume1, 6, 2)
        gridRight.addWidget(self.labelBidVolume2, 7, 2)
        gridRight.addWidget(self.labelBidVolume3, 8, 2)
        gridRight.addWidget(self.labelBidVolume4, 9, 2)
        gridRight.addWidget(self.labelBidVolume5, 10, 2)

        # 发单按钮
        buttonSendOrder = QtGui.QPushButton(vtText.SEND_ORDER)
        buttonCancelAll = QtGui.QPushButton(vtText.CANCEL_ALL)

        size = buttonSendOrder.sizeHint()
        buttonSendOrder.setMinimumHeight(size.height() * 2)  # 把按钮高度设为默认两倍
        buttonCancelAll.setMinimumHeight(size.height() * 2)

        # 整合布局
        hbox = QtGui.QHBoxLayout()
        hbox.addLayout(gridleft)
        hbox.addLayout(gridRight)

        vbox = QtGui.QVBoxLayout()
        vbox.addLayout(hbox)
        vbox.addWidget(buttonSendOrder)
        vbox.addWidget(buttonCancelAll)
        vbox.addStretch()

        self.setLayout(vbox)

        # 关联更新
        buttonSendOrder.clicked.connect(self.sendOrder)
        buttonCancelAll.clicked.connect(self.cancelAll)
        self.lineSymbol.returnPressed.connect(self.updateSymbol)

    #----------------------------------------------------------------------
    def updateSymbol(self):
        """合约变化"""
        # 读取组件数据
        symbol = str(self.lineSymbol.text())
        exchange = unicode(self.comboExchange.currentText())
        currency = unicode(self.comboCurrency.currentText())
        productClass = unicode(self.comboProductClass.currentText())
        gatewayName = unicode(self.comboGateway.currentText())

        # 查询合约
        if exchange:
            vtSymbol = '.'.join([symbol, exchange])
            contract = self.mainEngine.getContract(vtSymbol)
        else:
            vtSymbol = symbol
            contract = self.mainEngine.getContract(symbol)

        if contract:
            vtSymbol = contract.vtSymbol
            gatewayName = contract.gatewayName
            self.lineName.setText(contract.name)
            exchange = contract.exchange  # 保证有交易所代码

        # 清空价格数量
        self.spinPrice.setValue(0)
        self.spinVolume.setValue(0)

        # 清空行情显示
        self.labelBidPrice1.setText('')
        self.labelBidPrice2.setText('')
        self.labelBidPrice3.setText('')
        self.labelBidPrice4.setText('')
        self.labelBidPrice5.setText('')
        self.labelBidVolume1.setText('')
        self.labelBidVolume2.setText('')
        self.labelBidVolume3.setText('')
        self.labelBidVolume4.setText('')
        self.labelBidVolume5.setText('')
        self.labelAskPrice1.setText('')
        self.labelAskPrice2.setText('')
        self.labelAskPrice3.setText('')
        self.labelAskPrice4.setText('')
        self.labelAskPrice5.setText('')
        self.labelAskVolume1.setText('')
        self.labelAskVolume2.setText('')
        self.labelAskVolume3.setText('')
        self.labelAskVolume4.setText('')
        self.labelAskVolume5.setText('')
        self.labelLastPrice.setText('')
        self.labelReturn.setText('')

        # 重新注册事件监听
        self.eventEngine.unregister(EVENT_TICK + self.symbol, self.signal.emit)
        self.eventEngine.register(EVENT_TICK + vtSymbol, self.signal.emit)

        # 订阅合约
        req = VtSubscribeReq()
        req.symbol = symbol
        req.exchange = exchange
        req.currency = currency
        req.productClass = productClass

        # 默认跟随价
        self.checkFixed.setChecked(False)

        self.mainEngine.subscribe(req, gatewayName)

        # 更新组件当前交易的合约
        self.symbol = vtSymbol

    #----------------------------------------------------------------------
    def updateTick(self, event):
        """更新行情"""
        tick = event.dict_['data']

        if tick.vtSymbol == self.symbol:
            if not self.checkFixed.isChecked():
                self.spinPrice.setValue(tick.lastPrice)
            self.labelBidPrice1.setText(str(tick.bidPrice1))
            self.labelAskPrice1.setText(str(tick.askPrice1))
            self.labelBidVolume1.setText(str(tick.bidVolume1))
            self.labelAskVolume1.setText(str(tick.askVolume1))

            if tick.bidPrice2:
                self.labelBidPrice2.setText(str(tick.bidPrice2))
                self.labelBidPrice3.setText(str(tick.bidPrice3))
                self.labelBidPrice4.setText(str(tick.bidPrice4))
                self.labelBidPrice5.setText(str(tick.bidPrice5))

                self.labelAskPrice2.setText(str(tick.askPrice2))
                self.labelAskPrice3.setText(str(tick.askPrice3))
                self.labelAskPrice4.setText(str(tick.askPrice4))
                self.labelAskPrice5.setText(str(tick.askPrice5))

                self.labelBidVolume2.setText(str(tick.bidVolume2))
                self.labelBidVolume3.setText(str(tick.bidVolume3))
                self.labelBidVolume4.setText(str(tick.bidVolume4))
                self.labelBidVolume5.setText(str(tick.bidVolume5))

                self.labelAskVolume2.setText(str(tick.askVolume2))
                self.labelAskVolume3.setText(str(tick.askVolume3))
                self.labelAskVolume4.setText(str(tick.askVolume4))
                self.labelAskVolume5.setText(str(tick.askVolume5))

            self.labelLastPrice.setText(str(tick.lastPrice))

            if tick.preClosePrice:
                rt = (tick.lastPrice / tick.preClosePrice) - 1
                self.labelReturn.setText(('%.2f' % (rt * 100)) + '%')
            else:
                self.labelReturn.setText('')

    #----------------------------------------------------------------------
    def connectSignal(self):
        """连接Signal"""
        self.signal.connect(self.updateTick)

    #----------------------------------------------------------------------
    def sendOrder(self):
        """发单"""
        symbol = str(self.lineSymbol.text())
        exchange = unicode(self.comboExchange.currentText())
        currency = unicode(self.comboCurrency.currentText())
        productClass = unicode(self.comboProductClass.currentText())
        gatewayName = unicode(self.comboGateway.currentText())

        # 查询合约
        if exchange:
            vtSymbol = '.'.join([symbol, exchange])
            contract = self.mainEngine.getContract(vtSymbol)
        else:
            vtSymbol = symbol
            contract = self.mainEngine.getContract(symbol)

        if contract:
            if not gatewayName:
                gatewayName = contract.gatewayName
            exchange = contract.exchange  # 保证有交易所代码

        req = VtOrderReq()
        req.symbol = symbol
        req.exchange = exchange
        req.price = self.spinPrice.value()
        req.volume = self.spinVolume.value()
        req.direction = unicode(self.comboDirection.currentText())
        req.priceType = unicode(self.comboPriceType.currentText())
        req.offset = unicode(self.comboOffset.currentText())
        req.currency = currency
        req.productClass = productClass

        self.mainEngine.sendOrder(req, gatewayName)

    def canelOrder(self):
        """撤单"""
        orderRef = str(self.lineOrder.text())

        l = self.mainEngine.getAllWorkingOrders()
        for order in l:
            if order.orderID == orderRef:
                req = VtCancelOrderReq()
                req.symbol = order.symbol
                req.exchange = order.exchange
                req.frontID = order.frontID
                req.sessionID = order.sessionID
                req.orderID = order.orderID
                self.mainEngine.cancelOrder(req, order.gatewayName)

    # ----------------------------------------------------------------------
    def cancelAll(self):
        """一键撤销所有委托"""
        l = self.mainEngine.getAllWorkingOrders()
        for order in l:
            req = VtCancelOrderReq()
            req.symbol = order.symbol
            req.exchange = order.exchange
            req.frontID = order.frontID
            req.sessionID = order.sessionID
            req.orderID = order.orderID
            self.mainEngine.cancelOrder(req, order.gatewayName)

    #----------------------------------------------------------------------
    def closePosition(self, cell):
        """根据持仓信息自动填写交易组件"""
        # 读取持仓数据,cell是一个表格中的单元格对象
        pos = cell.data
        symbol = pos.symbol

        # 更新交易组件的显示合约
        self.lineSymbol.setText(symbol)
        self.updateSymbol()

        # 自动填写信息
        self.comboPriceType.setCurrentIndex(
            self.priceTypeList.index(PRICETYPE_LIMITPRICE))
        self.comboOffset.setCurrentIndex(self.offsetList.index(OFFSET_CLOSE))
        self.spinVolume.setValue(pos.position)

        if pos.direction == DIRECTION_LONG or pos.direction == DIRECTION_NET:
            self.comboDirection.setCurrentIndex(
                self.directionList.index(DIRECTION_SHORT))
        else:
            self.comboDirection.setCurrentIndex(
                self.directionList.index(DIRECTION_LONG))
示例#2
0
class StAlgoManager(QtWidgets.QTableWidget):
    """价差算法管理组件"""
    signalPos = QtCore.pyqtSignal(type(Event()))

    #----------------------------------------------------------------------
    def __init__(self, stEngine, parent=None):
        """Constructor"""
        super(StAlgoManager, self).__init__(parent)

        self.algoEngine = stEngine.algoEngine
        self.eventEngine = stEngine.eventEngine

        self.buttonActiveDict = {}  # spreadName: buttonActive
        self.posCellDict = {}  # spreadName: cell

        self.initUi()
        self.registerEvent()

    #----------------------------------------------------------------------
    def initUi(self):
        """初始化表格"""
        headers = [
            u'价差', u'算法', u'净持仓', 'BuyPrice', 'SellPrice', 'CoverPrice',
            'ShortPrice', u'委托上限', u'持仓上限', u'模式', u'状态'
        ]
        self.setColumnCount(len(headers))
        self.setHorizontalHeaderLabels(headers)

        try:
            self.horizontalHeader().setResizeMode(
                QtWidgets.QHeaderView.Stretch)
        except AttributeError:
            self.horizontalHeader().setSectionResizeMode(
                QtWidgets.QHeaderView.Stretch)

        self.verticalHeader().setVisible(False)
        self.setEditTriggers(self.NoEditTriggers)

    #----------------------------------------------------------------------
    def initCells(self):
        """初始化单元格"""
        algoEngine = self.algoEngine

        l = self.algoEngine.getAllAlgoParams()
        self.setRowCount(len(l))

        for row, d in enumerate(l):
            cellSpreadName = QtWidgets.QTableWidgetItem(d['spreadName'])
            cellAlgoName = QtWidgets.QTableWidgetItem(d['algoName'])
            cellNetPos = QtWidgets.QTableWidgetItem('0')
            spinBuyPrice = StBuyPriceSpinBox(algoEngine, d['spreadName'],
                                             d['buyPrice'])
            spinSellPrice = StSellPriceSpinBox(algoEngine, d['spreadName'],
                                               d['sellPrice'])
            spinShortPrice = StShortPriceSpinBox(algoEngine, d['spreadName'],
                                                 d['shortPrice'])
            spinCoverPrice = StCoverPriceSpinBox(algoEngine, d['spreadName'],
                                                 d['coverPrice'])
            spinMaxOrderSize = StMaxOrderSizeSpinBox(algoEngine,
                                                     d['spreadName'],
                                                     d['maxOrderSize'])
            spinMaxPosSize = StMaxPosSizeSpinBox(algoEngine, d['spreadName'],
                                                 d['maxPosSize'])
            comboMode = StModeComboBox(algoEngine, d['spreadName'], d['mode'])
            buttonActive = StActiveButton(algoEngine, d['spreadName'])

            self.setItem(row, 0, cellSpreadName)
            self.setItem(row, 1, cellAlgoName)
            self.setItem(row, 2, cellNetPos)
            self.setCellWidget(row, 3, spinBuyPrice)
            self.setCellWidget(row, 4, spinSellPrice)
            self.setCellWidget(row, 5, spinCoverPrice)
            self.setCellWidget(row, 6, spinShortPrice)
            self.setCellWidget(row, 7, spinMaxOrderSize)
            self.setCellWidget(row, 8, spinMaxPosSize)
            self.setCellWidget(row, 9, comboMode)
            self.setCellWidget(row, 10, buttonActive)

            buttonActive.signalActive.connect(spinBuyPrice.algoActiveChanged)
            buttonActive.signalActive.connect(spinSellPrice.algoActiveChanged)
            buttonActive.signalActive.connect(spinShortPrice.algoActiveChanged)
            buttonActive.signalActive.connect(spinCoverPrice.algoActiveChanged)
            buttonActive.signalActive.connect(
                spinMaxOrderSize.algoActiveChanged)
            buttonActive.signalActive.connect(spinMaxPosSize.algoActiveChanged)
            buttonActive.signalActive.connect(comboMode.algoActiveChanged)

            self.buttonActiveDict[d['spreadName']] = buttonActive
            self.posCellDict[d['spreadName']] = cellNetPos

    #----------------------------------------------------------------------
    def stopAll(self):
        """停止所有算法"""
        for button in self.buttonActiveDict.values():
            button.stop()

    #----------------------------------------------------------------------
    def processStPosEvent(self, event):
        """"""
        pos = event.dict_['data']
        cell = self.posCellDict[pos.name]
        cell.setText(str(pos.netPos))

    #----------------------------------------------------------------------
    def registerEvent(self):
        """"""
        self.signalPos.connect(self.processStPosEvent)

        self.eventEngine.register(EVENT_SPREADTRADING_POS, self.signalPos.emit)
示例#3
0
class BasicMonitor(QtGui.QTableWidget):
    """
    基础监控
    
    headerDict中的值对应的字典格式如下
    {'chinese': u'中文名', 'cellType': BasicCell}
    
    """
    signal = QtCore.pyqtSignal(type(Event()))

    #----------------------------------------------------------------------
    def __init__(self, mainEngine=None, eventEngine=None, parent=None):
        """Constructor"""
        super(BasicMonitor, self).__init__(parent)

        self.mainEngine = mainEngine
        self.eventEngine = eventEngine

        # 保存表头标签用
        self.headerDict = OrderedDict()  # 有序字典,key是英文名,value是对应的配置字典
        self.headerList = []  # 对应self.headerDict.keys()

        # 保存相关数据用
        self.dataDict = {}  # 字典,key是字段对应的数据,value是保存相关单元格的字典
        self.dataKey = ''  # 字典键对应的数据字段

        # 监控的事件类型
        self.eventType = ''

        # 字体
        self.font = None

        # 保存数据对象到单元格
        self.saveData = False

        # 默认不允许根据表头进行排序,需要的组件可以开启
        self.sorting = False

        # 初始化右键菜单
        self.initMenu()

    #----------------------------------------------------------------------
    def setHeaderDict(self, headerDict):
        """设置表头有序字典"""
        self.headerDict = headerDict
        self.headerList = headerDict.keys()

    #----------------------------------------------------------------------
    def setDataKey(self, dataKey):
        """设置数据字典的键"""
        self.dataKey = dataKey

    #----------------------------------------------------------------------
    def setEventType(self, eventType):
        """设置监控的事件类型"""
        self.eventType = eventType

    #----------------------------------------------------------------------
    def setFont(self, font):
        """设置字体"""
        self.font = font

    #----------------------------------------------------------------------
    def setSaveData(self, saveData):
        """设置是否要保存数据到单元格"""
        self.saveData = saveData

    #----------------------------------------------------------------------
    def initTable(self):
        """初始化表格"""
        # 设置表格的列数
        col = len(self.headerDict)
        self.setColumnCount(col)

        # 设置列表头
        labels = [d['chinese'] for d in self.headerDict.values()]
        self.setHorizontalHeaderLabels(labels)

        # 关闭左边的垂直表头
        self.verticalHeader().setVisible(False)

        # 设为不可编辑
        self.setEditTriggers(self.NoEditTriggers)

        # 设为行交替颜色
        self.setAlternatingRowColors(True)

        # 设置允许排序
        self.setSortingEnabled(self.sorting)

    #----------------------------------------------------------------------
    def registerEvent(self):
        """注册GUI更新相关的事件监听"""
        self.signal.connect(self.updateEvent)
        self.eventEngine.register(self.eventType, self.signal.emit)

    #----------------------------------------------------------------------
    def updateEvent(self, event):
        """收到事件更新"""
        data = event.dict_['data']
        self.updateData(data)

    #----------------------------------------------------------------------
    def updateData(self, data):
        """将数据更新到表格中"""
        # 如果允许了排序功能,则插入数据前必须关闭,否则插入新的数据会变乱
        if self.sorting:
            self.setSortingEnabled(False)

        # 如果设置了dataKey,则采用存量更新模式
        if self.dataKey:
            key = data.__getattribute__(self.dataKey)
            # 如果键在数据字典中不存在,则先插入新的一行,并创建对应单元格
            if key not in self.dataDict:
                self.insertRow(0)
                d = {}
                for n, header in enumerate(self.headerList):
                    content = safeUnicode(data.__getattribute__(header))
                    cellType = self.headerDict[header]['cellType']
                    cell = cellType(content, self.mainEngine)

                    if self.font:
                        cell.setFont(self.font)  # 如果设置了特殊字体,则进行单元格设置

                    if self.saveData:  # 如果设置了保存数据对象,则进行对象保存
                        cell.data = data

                    self.setItem(0, n, cell)
                    d[header] = cell
                self.dataDict[key] = d
            # 否则如果已经存在,则直接更新相关单元格
            else:
                d = self.dataDict[key]
                for header in self.headerList:
                    content = safeUnicode(data.__getattribute__(header))
                    cell = d[header]
                    cell.setContent(content)

                    if self.saveData:  # 如果设置了保存数据对象,则进行对象保存
                        cell.data = data
        # 否则采用增量更新模式
        else:
            self.insertRow(0)
            for n, header in enumerate(self.headerList):
                content = safeUnicode(data.__getattribute__(header))
                cellType = self.headerDict[header]['cellType']
                cell = cellType(content, self.mainEngine)

                if self.font:
                    cell.setFont(self.font)

                if self.saveData:
                    cell.data = data

                self.setItem(0, n, cell)

        # 调整列宽
        self.resizeColumns()

        # 重新打开排序
        if self.sorting:
            self.setSortingEnabled(True)

    #----------------------------------------------------------------------
    def resizeColumns(self):
        """调整各列的大小"""
        self.horizontalHeader().resizeSections(
            QtGui.QHeaderView.ResizeToContents)

    #----------------------------------------------------------------------
    def setSorting(self, sorting):
        """设置是否允许根据表头排序"""
        self.sorting = sorting

    #----------------------------------------------------------------------
    def saveToCsv(self, path=EMPTY_STRING):
        """保存表格内容到CSV文件"""

        # 获取想要保存的文件名
        if not path:
            # 先隐藏右键菜单
            self.menu.close()

            # 获取想要保存的文件名
            path = QtGui.QFileDialog.getSaveFileName(self, vtText.SAVE_DATA,
                                                     '', 'CSV(*.csv)')

        log = VtLogData()
        log.gatewayName = u'-'

        try:
            if not os.path.exists(path):
                with open(unicode(path), 'wb') as f:
                    writer = csv.writer(f)

                    # 保存标签
                    headers = [
                        header.encode('gbk') for header in self.headerList
                    ]
                    writer.writerow(headers)

                    # 保存每行内容
                    for row in range(self.rowCount()):
                        rowdata = []
                        for column in range(self.columnCount()):
                            item = self.item(row, column)
                            if item is not None:
                                rowdata.append(
                                    unicode(item.text()).encode('gbk'))
                            else:
                                rowdata.append('')
                        writer.writerow(rowdata)

                log.logContent = u'数据保存至:{0}'.format(path)

        except IOError:
            log.logContent = u'文件IO失败:{0}'.format(path)

            event1 = Event(type_=EVENT_LOG)
            event1.dict_['data'] = log
            self.eventEngine.put(event1)

    #----------------------------------------------------------------------
    def initMenu(self):
        """初始化右键菜单"""
        self.menu = QtGui.QMenu(self)

        saveAction = QtGui.QAction(vtText.SAVE_DATA, self)
        saveAction.triggered.connect(self.saveToCsv)

        self.menu.addAction(saveAction)

    #----------------------------------------------------------------------
    def contextMenuEvent(self, event):
        """右键点击事件"""
        self.menu.popup(QtGui.QCursor.pos())

    def clearData(self):
        """清空数据"""
        self.dataDict = {}
        self.setRowCount(0)