def generatePicture(self): ## pre-computing a QPicture object allows paint() to run much more quickly, ## rather than re-drawing the shapes every time. global last_pf self.picture = QtGui.QPicture() p = QtGui.QPainter(self.picture) w = 1.0/3 #(self.data[1][0] - self.data[0][0]) / 3. #last_pf = self.data[0][2] first = True for (t, open, close, min, max, pf) in self.data: if open > close: #p.setBrush(pg.mkBrush('g')) p.setPen(pg.mkPen('g')) elif open < close: #p.setBrush(pg.mkBrush('r')) p.setPen(pg.mkPen('r')) else: p.setPen(pg.mkPen('w')) if min < max: p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max)) p.drawRect(QtCore.QRectF(t-w, open, w*2, close-open)) p.setPen(pg.mkPen('y', width=1.5, style=QtCore.Qt.DashLine)) if not first: p.drawLine(QtCore.QPointF(t-1, last_pf), QtCore.QPointF(t, pf)) first = False last_pf = pf p.end()
def generate_picture(self, boundingRect): w = self.datasrc.period * self.candle_width w2 = w * 0.5 left,right = boundingRect.left(), boundingRect.right() p = self.painter p.begin(self.picture) rows = list(self.datasrc.bear_rows(5, left, right, yscale=self.ax.vb.yscale)) if self.draw_shadow: p.setPen(pg.mkPen(self.bear_color)) for t,open,close,high,low in rows: if high > low: p.drawLine(QtCore.QPointF(t, low), QtCore.QPointF(t, high)) if self.draw_body: p.setPen(pg.mkPen(self.bear_frame_color)) p.setBrush(pg.mkBrush(self.bear_body_color)) for t,open,close,high,low in rows: p.drawRect(QtCore.QRectF(t-w2, open, w, close-open)) rows = list(self.datasrc.bull_rows(5, left, right, yscale=self.ax.vb.yscale)) if self.draw_shadow: p.setPen(pg.mkPen(self.bull_color)) for t,open,close,high,low in rows: if high > low: p.drawLine(QtCore.QPointF(t, low), QtCore.QPointF(t, high)) if self.draw_body: p.setPen(pg.mkPen(self.bull_frame_color)) p.setBrush(pg.mkBrush(self.bull_body_color)) for t,open,close,high,low in rows: p.drawRect(QtCore.QRectF(t-w2, open, w, close-open)) p.end()
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) for bi in self.data: if bi.biType == 'up': p.setPen(pg.mkPen('r')) p.drawLine( QtCore.QPointF( chan.chanBars[bi.barIndex1].closeIndex, chan.lowBar[chan.chanBars[bi.barIndex1].closeIndex]), QtCore.QPointF( chan.chanBars[bi.barIndex2].closeIndex, chan.highBar[chan.chanBars[bi.barIndex2].closeIndex])) else: p.setPen(pg.mkPen('g')) p.drawLine( QtCore.QPointF( chan.chanBars[bi.barIndex1].closeIndex, chan.highBar[chan.chanBars[bi.barIndex1].closeIndex]), QtCore.QPointF( chan.chanBars[bi.barIndex2].closeIndex, chan.lowBar[chan.chanBars[bi.barIndex2].closeIndex])) p.end()
def generatePicture(self): self.picture = QtGui.QPicture() p = QtGui.QPainter(self.picture) p.setPen(pg.mkPen('w', width=1 / 2.)) for (t, v) in self.data: p.drawLine(QtCore.QPointF(t, v - 2), QtCore.QPointF(t, v + 2)) p.end()
def getPath(self): if self.path is None: if self.data is None or len(self.data) < 2: self.path = [QtGui.QPainterPath(), QtGui.QPainterPath()] else: redBars = QtGui.QPainterPath() greenBars = QtGui.QPainterPath() self.step = self.data[1][0] - self.data[0][0] w = self.step / 3.0 for data in self.data: if not np.isnan(data).any(): t, o, h, l, c = data if o > c: redBars.moveTo(QtCore.QPointF(t, l)) redBars.lineTo(QtCore.QPointF(t, h)) redBars.addRect( QtCore.QRectF(t - w, o, w * 2, c - o)) else: greenBars.moveTo(QtCore.QPointF(t, l)) greenBars.lineTo(QtCore.QPointF(t, h)) greenBars.addRect( QtCore.QRectF(t - w, o, w * 2, c - o)) self.path = [redBars, greenBars] return self.path
def _get_line_chart(self): """Return QPicture() with line chart by self._data""" picture = QtGui.QPicture() pen = QtGui.QPainter(picture) pen.setPen(pg.mkPen(self.border_color)) for ind in range(0, len(self._data) - 1): pen.drawLine(QtCore.QPointF(ind, self._data[ind][3]), QtCore.QPointF(ind + 1, self._data[ind + 1][3])) pen.end() return picture
def draw(self, data, width=1. / 3.): """draw(self, data, width=1./3.) -> None draw an item of boxplot Parameters ---------- data : tuple data has the following format: timestamp : int outliers : array-like lower whisker : float first quartile : float median : float third quartile : float upper whisker : float width : float (default : 1/3) width of an item of boxplot """ t_, out, low_w, q1, q2, q3, up_w = data[:] self.p.drawLine(QtCore.QPointF(t_, low_w), QtCore.QPointF(t_, up_w)) self.p.drawLine(QtCore.QPointF(t_ - width, low_w), QtCore.QPointF(t_ + width, low_w)) self.p.drawLine(QtCore.QPointF(t_ - width, up_w), QtCore.QPointF(t_ + width, up_w)) for out_ in out: self.p.drawEllipse(QtCore.QPointF(t_, out_), width, width) self.p.setBrush(pg.mkBrush("#000000")) self.p.drawRect(QtCore.QRectF(t_ - width, q1, width * 2, q3 - q1)) self.p.setBrush(pg.mkBrush("#FFFFFF")) self.p.drawLine(QtCore.QPointF(t_ - width, q2), QtCore.QPointF(t_ + width, q2))
def generatePicture(self): 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 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 createPoly(self, n, r, s, xx, yy, act): polygon = QtGui.QPolygonF() w = 360 / n # angle per step for i in range(n): # add the points of polygon t = w * i + s y = r * math.sin(math.radians(t)) x = r * math.cos(math.radians(t)) if i == 0: if act > 0: polygon.append(QtCore.QPointF(xx + x, 2 + (yy + y))) elif act < 0: polygon.append(QtCore.QPointF(xx + x, (yy + y) - 2)) else: polygon.append(QtCore.QPointF(xx + x, yy + y)) return polygon
def _calc_robot_polygon(self, x, y, theta): """ Prepare a QPolygonF representing the robot by a triangle, given a pose @return: a QPolygonF object. """ # angle coordinates translation theta = math.radians(theta) # 3 points around the gravity center (x, y) # all oriented following the theta angle x1 = (self.ROBOT_WIDTH_MM // 2) * math.cos(theta) y1 = (self.ROBOT_WIDTH_MM // 2) * math.sin(theta) x2 = (self.ROBOT_WIDTH_MM // 2) * math.cos(theta + 2.5 * (math.pi / 3.)) y2 = (self.ROBOT_WIDTH_MM // 2) * math.sin(theta + 2.5 * (math.pi / 3.)) x3 = (self.ROBOT_WIDTH_MM // 2) * math.cos(theta + 3.5 * (math.pi / 3.)) y3 = (self.ROBOT_WIDTH_MM // 2) * math.sin(theta + 3.5 * (math.pi / 3.)) points = [(x + x1, y + y1), (x + x2, y + y2), (x + x3, y + y3)] qpoints = [QtCore.QPointF(x, y) for (x, y) in points] qpoly = QtGui.QPolygonF(qpoints) return qpoly
def createCandlestick(self, isVolume, showTrendBars): if not self.isOHLC: return if isVolume and not self.hasVolume: return picture = self.candleStickPictures[isVolume][showTrendBars] if picture: return picture picture = QtGui.QPicture() p = QtGui.QPainter(picture) w = self.timeInterval / 3. for e in xrange(self.count()): t = self.plotTimes[e] open, high, low, close, volume = self.getOHLCV(e) upBar = close >= open if showTrendBars: upTrend = self.upTrend[e] color = 'cyan' if upTrend else 'red' else: color = OPEN_CLOSE_COLOR[upBar] color = color[0] p.setPen(pg.mkPen(color)) if showTrendBars and upTrend == upBar: p.setBrush(pg.mkBrush(color))# Solid body else: p.setBrush(pg.mkBrush('#000000'))# Make the body hollow if isVolume: y = 0. height = volume else: # Candlestick if low != high:# Weird long lines can happen on 5m Yahoo if the OHLC is all the same p.drawLine(QtCore.QPointF(t, low), QtCore.QPointF(t, high)) y = open height = close - open p.drawRect(QtCore.QRectF(t-w, y, w*2, height)) p.end() self.candleStickPictures[isVolume][showTrendBars] = picture return picture
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')) barWidth = (self.data[1][0] - self.data[0][0]) / 3. for (time, open, high, low, close) in self.data: p.drawLine(QtCore.QPointF(time, low), QtCore.QPointF(time, high)) if open > high: p.setBrush(pg.mkBrush('r')) else: p.setBrush(pg.mkBrush('g')) p.drawRect( QtCore.QRectF(time - barWidth, open, barWidth * 2, high - open)) p.end()
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.day2num(self.data[1][0]) - self.day2num(self.data[0][0])) / 3 ################################################################################ for (t, open, close, high, low, vol, code) in self.data: t = self.day2num(str(t)) p.drawLine(QtCore.QPointF(t, high), QtCore.QPointF(t, low)) if open > close: p.setBrush(pg.mkBrush('g')) else: p.setBrush(pg.mkBrush('r')) p.drawRect(QtCore.QRectF(t - w, open, w * 2, close - open)) p.end()
def setData(self, toclh): # toclh is a tuple of (time, open, close, min, max) self.data.append(toclh) p = QtGui.QPainter(self.picture) p.setPen(pg.mkPen('w')) w = 1. / 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() self.update()
def draw(self, data, width=1. / 3.): """draw(self, data, width=1./3.) -> None draw an item of candlestick Parameters ---------- width : float (default : 1/3) width of a candlestick """ t_, open_, high_, low_, close_ = data[:] self.p.drawLine(QtCore.QPointF(t_, low_), QtCore.QPointF(t_, high_)) if open_ > close_: self.p.setBrush(pg.mkBrush('r')) else: self.p.setBrush(pg.mkBrush('g')) self.p.drawRect( QtCore.QRectF(t_ - width, open_, width * 2, close_ - open_))
def generatePicture(self): self.picture = QtGui.QPicture() p = QtGui.QPainter(self.picture) p.setBrush(pg.mkBrush(None)) # Mouse center p.setPen(pg.mkPen('b')) for i in range(4): p.drawLine( QtCore.QPointF(0, 0), QtCore.QPointF(cos(i * pi / 2) * 30, sin(i * pi / 2) * 30)) # Emitters p.setPen(pg.mkPen('#ffd70080')) for x, y, rotation in self.configuration['emitters']: for i in [1, 0, -1]: diff = i * self.configuration['half_emission_angle'] angle = radians(rotation + diff) p.drawLine( QtCore.QPointF(x, y), QtCore.QPointF(x + sin(angle) * 400, y + cos(angle) * 400)) p.end()
def draw_picture(self, painter, headcolors): face_index = 0 for i, node_count in enumerate(self.nodes_per_face): polygon = QtGui.QPolygonF() for j in range(node_count): face_node = self.face_nodes[face_index + j] polygon.append( QtCore.QPointF(self.grid_x[face_node], self.grid_y[face_node])) face_index += node_count + 1 painter.setBrush(pg.mkBrush(headcolors[i])) painter.drawPolygon(polygon)
def _generate(self, p): w = .35 p.setPen(pg.mkPen(color=(155, 163, 157))) #rects = [(QtCore.QRectF(i-w, row.open, w*2, row.close-row.open), row.open-row.close ) for i, row in self.ohlc.iterrows()] for i, row in self.ohlc.iterrows(): p.drawLine(QtCore.QPointF(i, row.low), QtCore.QPointF(i, row.high)) candlestick_bar = QtCore.QRectF(i - w, row.open, w * 2, row.close - row.open) if row.close - row.open < 0: p.setBrush(pg.mkBrush('r')) else: p.setBrush(pg.mkBrush('g')) p.drawRect(candlestick_bar) return p
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)) self.path = pg.arrayToQPath(np.array([0, 1, 2, 1]), np.array([0, 0, 1, 1])) # self.path = self.generatePath([0, 1, 2, 1], [0, 0, 1, 1]) p2 = QtGui.QPainterPath(self.path) p.fillPath(p2, pg.mkBrush((100, 100, 100))) 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.drawPolygon(QtCore.) # p.drawLine(QtCore.QPointF(*pts[i][0]), QtCore.QPointF(*pts[i][1])) p.end()
def _get_candles_chart(self): """Return QPicture() with candlestick chart by self._data""" picture = QtGui.QPicture() pen = QtGui.QPainter(picture) pen.setPen(pg.mkPen(self.border_color, width=2)) width = 1 / 3. for ind, candle in enumerate(self._data): # Warning. if you paint line x -> y if x == y, then on pyqtgraph will paint white rectangle (bug?) if candle[1] != candle[2]: # paint shadow pen.drawLine(QtCore.QPointF(ind, candle[2]), QtCore.QPointF(ind, candle[1])) if candle[0] > candle[3]: pen.setBrush(pg.mkBrush(self.negative_color)) else: pen.setBrush(pg.mkBrush(self.positive_color)) # paint body pen.drawRect( QtCore.QRectF(ind - width, candle[0], width * 2, candle[3] - candle[0])) pen.end() return picture
def generatePicture(self): # 重畫或者最後一根K線 if int(len(self.pictures)) > 1: self.pictures.pop() w = 1.0 / 3.0 start = len(self.pictures) stop = self.data.shape[0] for (t, x) in self.data.loc[start:stop, ['open', 'high', 'low', 'close']].iterrows(): picture = QtGui.QPicture() p = QtGui.QPainter(picture) p.setPen(pg.mkPen('w')) p.drawLine(QtCore.QPointF(t, x.low), QtCore.QPointF(t, x.high)) if x.open > x.close: p.setBrush(pg.mkBrush('g')) elif x.open < x.close: p.setBrush(pg.mkBrush('r')) else: p.setBrush(pg.mkBrush('w')) p.drawRect(QtCore.QRectF(t - w, x.open, w * 2, x.close - x.open)) p.end() self.pictures.append(picture)
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')) # import ipdb;ipdb.set_trace() # w = (self.data[1][0] - self.data[0][0]) / 3. # # w = (self.data[1][0] - self.data[0][0]) # print self.data[1][0] , self.data[0][0] # print self.data[1] , self.data[0] for (t, open, close, low, high) in self.data: # p.drawLine(QtCore.QPointF(t, low), QtCore.QPointF(t, high)) p.drawLine(QtCore.QPointF(t, low), QtCore.QPointF(t, high)) 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.drawRect(QtCore.QRectF(t, open, 0.66, close - open)) p.end()
def _get_bar_chart(self): """Return QPicture() with bar chart by self._data""" picture = QtGui.QPicture() pen = QtGui.QPainter(picture) pen.setPen(pg.mkPen(self.border_color)) width = 1 / 3. for ind, candle in enumerate(self._data): if candle[0] > candle[3]: pen.setPen(pg.mkPen(self.negative_color, width=5)) else: pen.setPen(pg.mkPen(self.positive_color, width=5)) # Warning. if paint line x->y | x==y, then pyqtgraph will paint white rectangle (bug?) if candle[1] != candle[2]: pen.drawLine(QtCore.QPointF(ind, candle[2]), QtCore.QPointF(ind, candle[1])) pen.drawLine(QtCore.QPointF(ind - width, candle[0]), QtCore.QPointF(ind, candle[0])) pen.drawLine(QtCore.QPointF(ind, candle[3]), QtCore.QPointF(ind + width, candle[3])) pen.end() return picture
def resizeEvent(self, ev): ## Set the position of the label nudge = 5 br = self.label.boundingRect() p = QtCore.QPointF(0, 0) if self.orientation == 'left': p.setY(int(self.size().height() / 2 + br.width() / 2)) #p.setX(-nudge) p.setX(self.size().width() - self.neededSpace()) elif self.orientation == 'right': p.setY(int(self.size().height() / 2 + br.width() / 2)) #p.setX(int(self.size().width()-br.height()+nudge)) p.setX(self.labelPos()) elif self.orientation == 'top': #p.setY(-nudge) p.setY(self.size().height() - self.neededSpace()) p.setX(int(self.size().width() / 2. - br.width() / 2.)) elif self.orientation == 'bottom': p.setX(int(self.size().width() / 2. - br.width() / 2.)) p.setY(self.labelPos()) #p.setY(int(self.size().height()-br.height()+nudge)) #p.setY(self.label_y) self.label.setPos(p) self.picture = None if not hasattr(self, 'set_lmt_btns' ) or self.set_lmt_btns is None: ## already closed down return lower = self.set_lmt_btns[0] rect = self.mapRectFromItem(lower, lower.boundingRect()) rh = rect.height() y0 = 0 y1 = rh y2 = rh * 2 ym0 = self.size().height() - rh ym1 = ym0 - rh rw = rect.width() x0 = 0 x1 = rw x2 = rw * 2 xm0 = self.size().width() - rw xm1 = xm0 - rw if self.orientation == 'left': self.set_lmt_btns[0].setPos(0, ym0) self.set_lmt_btns[1].setPos(0, y0) self.aset_lmt_btns[0].setPos(0, ym1) self.aset_lmt_btns[1].setPos(0, y1) self.enable_auto_range_btn.setPos(0, y2) elif self.orientation == 'bottom': self.set_lmt_btns[0].setPos(x0, ym0) self.set_lmt_btns[1].setPos(xm0, ym0) self.aset_lmt_btns[0].setPos(x1, ym0) self.aset_lmt_btns[1].setPos(xm1, ym0) self.enable_auto_range_btn.setPos(x2, ym0) elif self.orientation == 'right': self.set_lmt_btns[0].setPos(xm0, ym0) self.set_lmt_btns[1].setPos(xm0, y0) self.aset_lmt_btns[0].setPos(xm0, ym1) self.aset_lmt_btns[1].setPos(xm0, y1) self.enable_auto_range_btn.setPos(xm0, y2) elif self.orientation == 'top': self.set_lmt_btns[0].setPos(x0, 0) self.set_lmt_btns[1].setPos(xm0, 0) self.aset_lmt_btns[0].setPos(x1, 0) self.aset_lmt_btns[1].setPos(xm1, 0) self.enable_auto_range_btn.setPos(x2, 0)
def setData(self, *args): """ Set the data to be drawn. Parameters ---------- x, y : np.ndarray, optional, default None 2D array containing the coordinates of the polygons z : np.ndarray 2D array containing the value which will be maped into the polygons colors. If x and y is None, the polygons will be displaced on a grid otherwise x and y will be used as polygons vertices coordinates as:: (x[i+1, j], y[i+1, j]) (x[i+1, j+1], y[i+1, j+1]) +---------+ | z[i, j] | +---------+ (x[i, j], y[i, j]) (x[i, j+1], y[i, j+1]) "ASCII from: <https://matplotlib.org/3.2.1/api/_as_gen/ matplotlib.pyplot.pcolormesh.html>". """ # Prepare data cd = self._prepareData(args) # Has the view bounds changed shapeChanged = False if self.qpicture is None: shapeChanged = True elif len(args) == 1: if args[0].shape[0] != self.x[:, 1][-1] or args[0].shape[ 1] != self.y[0][-1]: shapeChanged = True elif len(args) == 3: if np.any(self.x != args[0]) or np.any(self.y != args[1]): shapeChanged = True self.qpicture = QtGui.QPicture() p = QtGui.QPainter(self.qpicture) # We set the pen of all polygons once if self.edgecolors is None: p.setPen(fn.mkPen(QtGui.QColor(0, 0, 0, 0))) else: p.setPen(fn.mkPen(self.edgecolors)) if self.antialiasing: p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing) ## Prepare colormap # First we get the LookupTable pos = [i[0] for i in Gradients[self.cmap]['ticks']] color = [i[1] for i in Gradients[self.cmap]['ticks']] cmap = ColorMap(pos, color) lut = cmap.getLookupTable(0.0, 1.0, 256) # Second we associate each z value, that we normalize, to the lut vmin, vmax = self.z.min(), self.z.max() if self.levels is not None: vmin, vmax = self.levels vmin = max(vmin, self.z.min()) vmax = min(vmax, self.z.max()) norm = self.z - vmin norm_max = vmax - vmin norm = norm / norm_max norm = (norm * (len(lut) - 1)).astype(int) norm[norm < 0] = 0 norm[norm > 255] = 255 # Go through all the data and draw the polygons accordingly for xi in range(self.z.shape[0]): for yi in range(self.z.shape[1]): # Set the color of the polygon first c = lut[norm[xi][yi]] p.setBrush(fn.mkBrush(QtGui.QColor(c[0], c[1], c[2]))) polygon = QtGui.QPolygonF([ QtCore.QPointF(self.x[xi][yi], self.y[xi][yi]), QtCore.QPointF(self.x[xi + 1][yi], self.y[xi + 1][yi]), QtCore.QPointF(self.x[xi + 1][yi + 1], self.y[xi + 1][yi + 1]), QtCore.QPointF(self.x[xi][yi + 1], self.y[xi][yi + 1]) ]) # DrawConvexPlygon is faster p.drawConvexPolygon(polygon) p.end() self.update() self.prepareGeometryChange() if shapeChanged: self.informViewBoundsChanged()
def paint(self, p, *args): p.setPen(self.pen) p.drawLine(QtCore.QPointF(*self.points[0]), QtCore.QPointF(*self.points[1]))