首页 > 解决方案 > 我的 Pyqt PlotWidget 中的 MousePressEvent - 模拟事件

问题描述

这是完整的代码库。我试图在图表中模拟鼠标点击,它是 self.graph,它是一个 plotwidget。我希望鼠标单击发生在 plotrunnable 类中,所以在我单击图形按钮后它会自动更新,并且在睡觉之前它会模拟对图形的单击以使其看起来像是自动更新

# Form implementation generated from reading ui file 'U:\Embedded Graphics View2.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets
import pyqtgraph as pg
import pyodbc as db
import pandas as pd
import time, os
from time import strptime as strptime
from time import mktime as mktime
from time import gmtime, strftime
from pyqtgraph import AxisItem
from datetime import datetime, timedelta
from numpy import ceil
import numpy as np
import sip
os.environ['TZ']='EST'


now=time.asctime(time.localtime())
start_time=time.time()
print('starting at '+now)

def time(date):
    if date == '':
        return None
    else:
        datetime = date
        pattern = '%Y%m%d %H:%M:%S'
        epoch = int(mktime(strptime(datetime, pattern))) 
        return epoch 



def connecttosql():
    host='{SQL Server}'
    server='SERVER'     ######### DEV - WILL CHANGE TO PRODUCTION WHEN DELIVERED
    database='DB'
    username='user'
    password='pass'

    try:
        cs= 'Driver=%s;Server=%s;Uid=%s;Pwd=%s;Database=%s;' % (host,server, username, password, database)
        global conn   #### THIS WILL BE USED ON THE QUERY
        conn= db.connect(cs)
        print ('Connected successfully to '+host+', '+server)

    except Exception as e:
        print ('Error: ' + str (e))

def testconnection():
    cursor=conn.cursor()
    try:
        cursor.execute("SELECT VERSION()")
        res=cursor.fetchone()
        print(res)
        ver=res[0]
        if ver in None:
            return False
        else:
            return True
    except:
        print ("ERROR IN CONNECTION")
        return False    

def closeconnection():
    conn.close
    print('CONNECTION WITH DATABASE HAS BEEN CLOSED')


def query(ticker,interval,ST,ET):
   # target='U:/py/sql csv/'+ticker+' - '+interval+'.csv'
    global conn
    table = 'BAR_BB'    ### hard code
    qry = f"SELECT * FROM {table} WHERE SY = {ticker} AND IL = {interval} AND ST >= {ST} AND ST <= {ET}"
    df=pd.read_sql(qry,conn)    ###### format will change

    df.set_index('ST',inplace=True)

   #df.to_csv(target,encoding='utf-8',index=False)

    st=df.index.tolist() 
    op=df['O'].tolist()
    hi=df['H'].tolist()
    lo=df['L'].tolist()
    cl=df['C'].tolist()
    bars=[]
    x=0

    for i in st:
        bar=[st[x],op[x],cl[x],lo[x],hi[x]]
        bars.append(bar)
        x=x+1
    data=bars
    return data






##Picture that goes in the UI
class CandlestickItem(pg.GraphicsObject):
    def __init__(self):
        pg.GraphicsObject.__init__(self)
        self.flagHasData = False

    @QtCore.pyqtSlot(list)
    def set_data(self, data):
        self.data = data 
        self.flagHasData = True
        self.generatePicture()
        self.informViewBoundsChanged()


    def generatePicture(self):
        ## pre-computing a QPicture object allows paint() to run much more quickly, 
        ## rather than re-drawing the shapes every time.
        self.picture = QtGui.QPicture()
        p = QtGui.QPainter(self.picture)
        p.setPen(pg.mkPen('w'))
        w = (self.data[1][0] - self.data[0][0]) / 3.
        for (t, open, close, min, max) in self.data:
            p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max))
            if open > close:
                p.setBrush(pg.mkBrush('r'))
            else:
                p.setBrush(pg.mkBrush('g'))
            p.drawRect(QtCore.QRectF(t-w, open, w*2, close-open))
        p.end()

    def paint(self, p, *args):
        p.drawPicture(0, 0, self.picture)

    def boundingRect(self):
        ## boundingRect _must_ indicate the entire area that will be drawn on
        ## or else we will get artifacts and possibly crashing.
        ## (in this case, QPicture does all the work of computing the bouning rect for us)
        return QtCore.QRectF(self.picture.boundingRect())


class DateAxisItem(AxisItem):
    """
    A tool that provides a date-time aware axis. It is implemented as an
    AxisItem that interpretes positions as unix timestamps (i.e. seconds
    since 1970).
    The labels and the tick positions are dynamically adjusted depending
    on the range.
    It provides a  :meth:`attachToPlotItem` method to add it to a given
    PlotItem
    """

    # Max width in pixels reserved for each label in axis
    _pxLabelWidth = 80

    def __init__(self, *args, **kwargs):
        AxisItem.__init__(self, *args, **kwargs)
        self._oldAxis = None

    def tickValues(self, minVal, maxVal, size):
        """
        Reimplemented from PlotItem to adjust to the range and to force
        the ticks at "round" positions in the context of time units instead of
        rounding in a decimal base
        """



        maxMajSteps = int(size/self._pxLabelWidth)

        dt1 = datetime.fromtimestamp(minVal) 
        dt2 = datetime.fromtimestamp(maxVal) 

        dx = maxVal - minVal
        majticks = []

        if dx > 63072001:  # 3600s*24*(365+366) = 2 years (count leap year)
            d = timedelta(days=366)
            for y in range(dt1.year + 1, dt2.year):
                dt = datetime(year=y, month=1, day=1)
                majticks.append(mktime(dt.timetuple()))

        elif dx > 5270400:  # 3600s*24*61 = 61 days
            d = timedelta(days=31)
            dt = dt1.replace(day=1, hour=0, minute=0,
                             second=0, microsecond=0) + d
            while dt < dt2:
                # make sure that we are on day 1 (even if always sum 31 days)
                dt = dt.replace(day=1)
                majticks.append(mktime(dt.timetuple()))
                dt += d

        elif dx > 172800:  # 3600s24*2 = 2 days
            d = timedelta(days=1)
            dt = dt1.replace(hour=0, minute=0, second=0, microsecond=0) + d
            while dt < dt2:
                majticks.append(mktime(dt.timetuple()))
                dt += d

        elif dx > 7200:  # 3600s*2 = 2hours
            d = timedelta(hours=1)
            dt = dt1.replace(minute=0, second=0, microsecond=0) + d
            while dt < dt2:
                majticks.append(mktime(dt.timetuple()))
                dt += d

        elif dx > 1200:  # 60s*20 = 20 minutes
            d = timedelta(minutes=10)
            dt = dt1.replace(minute=(dt1.minute // 10) * 10,
                             second=0, microsecond=0) + d
            while dt < dt2:
                majticks.append(mktime(dt.timetuple()))
                dt += d

        elif dx > 120:  # 60s*2 = 2 minutes
            d = timedelta(minutes=1)
            dt = dt1.replace(second=0, microsecond=0) + d
            while dt < dt2:
                majticks.append(mktime(dt.timetuple()))
                dt += d

        elif dx > 20:  # 20s
            d = timedelta(seconds=10)
            dt = dt1.replace(second=(dt1.second // 10) * 10, microsecond=0) + d
            while dt < dt2:
                majticks.append(mktime(dt.timetuple()))
                dt += d

        elif dx > 2:  # 2s
            d = timedelta(seconds=1)
            majticks = range(int(minVal), int(maxVal))

        else:  # <2s , use standard implementation from parent
            return AxisItem.tickValues(self, minVal, maxVal, size)

        L = len(majticks)
        if L > maxMajSteps:
            majticks = majticks[::int(ceil(float(L) / maxMajSteps))]

        return [(d.total_seconds(), majticks)]

    def tickStrings(self, values, scale, spacing):
        """Reimplemented from PlotItem to adjust to the range"""
        ret = []
        if not values:
            return []

        if spacing >= 31622400:  # 366 days
            fmt = "%Y"

        elif spacing >= 2678400:  # 31 days
            fmt = "%Y %b"

        elif spacing >= 86400:  # = 1 day
            fmt = "%b/%d"

        elif spacing >= 3600:  # 1 h
            fmt = "%b/%d-%Hh"

        elif spacing >= 60:  # 1 m
            fmt = "%H:%M"

        elif spacing >= 1:  # 1s
            fmt = "%H:%M:%S"

        else:
            # less than 2s (show microseconds)
            # fmt = '%S.%f"'
            fmt = '[+%fms]'  # explicitly relative to last second

        for x in values:
            try:
                t = datetime.fromtimestamp(x)
                ret.append(t.strftime(fmt))
            except ValueError:  # Windows can't handle dates before 1970
                ret.append('')

        return ret

    def attachToPlotItem(self, plotItem):
        """Add this axis to the given PlotItem
        :param plotItem: (PlotItem)
        """
        self.setParentItem(plotItem)
        viewBox = plotItem.getViewBox()
        self.linkToView(viewBox)
        self._oldAxis = plotItem.axes[self.orientation]['item']
        self._oldAxis.hide()
        plotItem.axes[self.orientation]['item'] = self
        pos = plotItem.axes[self.orientation]['pos']
        plotItem.layout.addItem(self, *pos)
        self.setZValue(-1000)

    def detachFromPlotItem(self):
        """Remove this axis from its attached PlotItem
        (not yet implemented)
        """
        raise NotImplementedError()  # TODO

class TimeAxisItem(pg.AxisItem):
    def tickStrings(self, values, scale, spacing):
        return [datetime.fromtimestamp(value) for value in values]


##UI SetUP
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1442, 1018)
        MainWindow.setAutoFillBackground(False)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.graphicsView = QtWidgets.QWidget(self.centralwidget)
        self.flagHasData = False
        self.graphicsView.setGeometry(QtCore.QRect(0, 0, 1201, 991))
        font = QtGui.QFont()
        font.setPointSize(18)
        self.graphicsView.setFont(font)
        brush = QtGui.QBrush(QtGui.QColor(0, 0, 0))
        brush.setStyle(QtCore.Qt.SolidPattern)

        self.graphicsView.setObjectName("graphicsView")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setEnabled(True)
        self.lineEdit.setGeometry(QtCore.QRect(1280, 20, 151, 21))
        font = QtGui.QFont()
        font.setPointSize(11)
        self.lineEdit.setFont(font)
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setGeometry(QtCore.QRect(1280, 80, 151, 20))
        font = QtGui.QFont()
        font.setPointSize(11)
        self.lineEdit_2.setFont(font)
        self.lineEdit_2.setText("")
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.lineEdit_3 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_3.setGeometry(QtCore.QRect(1280, 160, 151, 20))
        font = QtGui.QFont()
        font.setPointSize(11)
        self.lineEdit_3.setFont(font)
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.lineEdit_4 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_4.setGeometry(QtCore.QRect(1280, 230, 151, 20))
        font = QtGui.QFont()
        font.setPointSize(11)
        self.lineEdit_4.setFont(font)
        self.lineEdit_4.setObjectName("lineEdit_4")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(1280, 0, 91, 16))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(self.centralwidget)
        self.label_2.setGeometry(QtCore.QRect(1280, 60, 111, 16))
        self.label_2.setObjectName("label_2")
        self.label_3 = QtWidgets.QLabel(self.centralwidget)
        self.label_3.setGeometry(QtCore.QRect(1280, 120, 51, 16))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(self.centralwidget)
        self.label_4.setGeometry(QtCore.QRect(1280, 190, 101, 16))
        self.label_4.setObjectName("label_4")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(1280, 260, 75, 23))
        self.pushButton.setObjectName("pushButton")
        self.label_5 = QtWidgets.QLabel(self.centralwidget)
        self.label_5.setGeometry(QtCore.QRect(1280, 140, 170, 20))
        self.label_5.setObjectName("label_5")
        self.label_6 = QtWidgets.QLabel(self.centralwidget)
        self.label_6.setGeometry(QtCore.QRect(1280, 210, 170, 20))
        self.label_6.setObjectName("label_6")
        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(1360, 260, 75, 23))
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.pushButton.clicked.connect(self.btn_click)
        self.pushButton_2.clicked.connect(self.clear)

        self.main_layout = QtWidgets.QHBoxLayout()
        self.graphicsView.setLayout(self.main_layout)
        self.graph = None
        self.glayout = None
        self.data = []
        self.vb = None

        self.main_layout.addWidget(self.graph)
        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)


##renaming all the Labels and Window
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Graph Interface"))
        self.label.setText(_translate("MainWindow", "Ticker (Bloomberg)"))
        self.label_2.setText(_translate("MainWindow", "Interval (In Seconds)"))
        self.label_3.setText(_translate("MainWindow", "Start Time"))
        self.label_4.setText(_translate("MainWindow", "End Time (Optional)"))
        self.pushButton.setText(_translate("MainWindow", "Graph"))
        self.label_5.setText(_translate("MainWindow", "YYYYMMDD 00:00:00 (UTC)"))
        self.label_6.setText(_translate("MainWindow", "YYYYMMDD 00:00:00 (UTC)"))
        self.pushButton_2.setText(_translate("MainWindow", "Clear"))



    global mouse_click_event    
    def mouse_click_event(self):
        graph.clicked()



#Button Click function.        
    def btn_click(self):
        global ticker, interval, start_time, end_time, graph
        global DRAW_GRAPH
        connecttosql()
        self.data = [  ## fields are (time, open, close, min, max).
        (1., 10, 13, 5, 15),
        (2., 13, 17, 9, 20),
        (3., 17, 14, 11, 23),
        (4., 14, 15, 5, 19),
        (5., 15, 9, 8, 22),
        (6., 9, 15, 8, 16)]
        self.graph = pg.PlotWidget(name = 'Whatever', aixsItems = {'bottom' : TimeAxisItem(orientation = 'bottom')})
       # self.ticker = self.lineEdit.text()
        #self.interval = self.lineEdit_2.text()
        #self.start_time = time(self.lineEdit_3.text())
        #self.end_time = time(self.lineEdit_4.text())        
       # if self.end_time == None:
        #    self.end_time = time(strftime("%Y%m%d %H:%M:%S", gmtime()))
       # else:
       #     self.end_time = time((self.lineEdit_4.text()))
      #  self.ticker = "'{}'".format(self.ticker)
     #   self.interval = "'{}'".format(self.interval)
     #   ticker = self.ticker
     #   interval = self.interval
    #    start_time = self.start_time
    #    end_time = self.end_time


        self.glayout = pg.GraphicsLayout()
        self.vb = self.glayout.addViewBox()
        self.vb.enableAutoRange(axis='xy',enable = True)
        #self.data = query(self.ticker,self.interval,self.start_time,self.end_time)
        self.item = CandlestickItem()
        self.item.set_data(self.data)
        self.graph.addItem(self.item)

        self.axis1 = DateAxisItem(orientation = 'bottom')

        self.axis1.attachToPlotItem(self.graph.getPlotItem()) 
        self.graph.showGrid(y=True, alpha = 0.8)
        self.main_layout.addWidget(self.graph)



        runnable = PlotRunnable(self.item)
        QtCore.QThreadPool.globalInstance().start(runnable)




    def clear(self):
        self.parent = self.graph.parent()
        self.graph.setParent(None)
        self.graph.setParent(self.parent)



class PlotRunnable(QtCore.QRunnable):
    def __init__(self, it):
        QtCore.QRunnable.__init__(self)
        self.it = it

    def run(self):

        while True:
            data = self.it.data           
           # end_time = end_time = time(strftime("%Y%m%d %H:%M:%S", gmtime()))            
            rand =[  ## fields are (time, open, close, min, max).
                  (1., 10, 13, 5, 15),
                  (2., 13, 17, 9, 20),
                  (3., 17, 14, 11, 23),
                  (4., 14, 15, 5, 19),
                  (5., 15, 9, 8, 22),
                  (6., 9, 15, 8, 16),     
                  (7., 8, 16, 10, 17)]
            new_bar = rand[-1]            
            data.append(new_bar)
            QtCore.QMetaObject.invokeMethod(self.it, "set_data",
                                     QtCore.Qt.QueuedConnection,
                                     QtCore.Q_ARG(list, data))
            #put mouse click here

            print("ran")
            #interval = int("{}".format(interval))
            QtCore.QThread.msleep(1000)   



import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()


if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

标签: python-3.xqtpyqtpyqt5pyqtgraph

解决方案


推荐阅读