def paint(self, painter, option, widget): path = QPainterPath() path.addRoundedRect(self.rect, 5, 5) anchor = self.mapFromParent(self.chart.mapToPosition(self.anchor)) if not self.rect.contains(anchor): point1 = QPointF() point2 = QPointF() # establish the position of the anchor point in relation to m_rect above = anchor.y() <= self.rect.top() aboveCenter = anchor.y() > self.rect.top() and anchor.y( ) <= self.rect.center().y() belowCenter = anchor.y() > self.rect.center().y() and anchor.y( ) <= self.rect.bottom() below = anchor.y() > self.rect.bottom() onLeft = anchor.x() <= self.rect.left() leftOfCenter = anchor.x() > self.rect.left() and anchor.x( ) <= self.rect.center().x() rightOfCenter = anchor.x() > self.rect.center().x() and anchor.x( ) <= self.rect.right() onRight = anchor.x() > self.rect.right() # get the nearest m_rect corner x = (onRight + rightOfCenter) * self.rect.width() y = (below + belowCenter) * self.rect.height() cornerCase = (above and onLeft) or (above and onRight) or ( below and onLeft) or (below and onRight) vertical = qAbs(anchor.x() - x) > qAbs(anchor.y() - y) x1 = x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * ( not vertical) * (onLeft * 10 - onRight * 20) y1 = y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * ( above * 10 - below * 20) x2 = x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * ( not vertical) * (onLeft * 20 - onRight * 10) y2 = y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * ( above * 20 - below * 10) point1.setX(x1) point1.setY(y1) point2.setX(x2) point2.setY(y2) path.moveTo(point1) path.lineTo(anchor) path.lineTo(point2) path = path.simplified() painter.setBrush(QColor(255, 255, 255)) painter.drawPath(path) painter.drawText(self.text_rect, self.text)
def paint(self, painter, option, widget): path = QPainterPath() path.addRoundedRect(self._rect, 5, 5) anchor = self.mapFromParent(self._chart.mapToPosition(self._anchor)) if not self._rect.contains(anchor) and not self._anchor.isNull(): point1 = QPointF() point2 = QPointF() # establish the position of the anchor point in relation to _rect above = anchor.y() <= self._rect.top() aboveCenter = (anchor.y() > self._rect.top() and anchor.y() <= self._rect.center().y()) belowCenter = (anchor.y() > self._rect.center().y() and anchor.y() <= self._rect.bottom()) below = anchor.y() > self._rect.bottom() onLeft = anchor.x() <= self._rect.left() leftOfCenter = (anchor.x() > self._rect.left() and anchor.x() <= self._rect.center().x()) rightOfCenter = (anchor.x() > self._rect.center().x() and anchor.x() <= self._rect.right()) onRight = anchor.x() > self._rect.right() # get the nearest _rect corner. x = (onRight + rightOfCenter) * self._rect.width() y = (below + belowCenter) * self._rect.height() cornerCase = ((above and onLeft) or (above and onRight) or (below and onLeft) or (below and onRight)) vertical = abs(anchor.x() - x) > abs(anchor.y() - y) x1 = (x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * int(not vertical) * (onLeft * 10 - onRight * 20)) y1 = (y + aboveCenter * 10 - belowCenter * 20 + cornerCase * vertical * (above * 10 - below * 20)) point1.setX(x1) point1.setY(y1) x2 = (x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * int(not vertical) * (onLeft * 20 - onRight * 10)) y2 = (y + aboveCenter * 20 - belowCenter * 10 + cornerCase * vertical * (above * 20 - below * 10)) point2.setX(x2) point2.setY(y2) path.moveTo(point1) path.lineTo(anchor) path.lineTo(point2) path = path.simplified() painter.setBrush(QColor(255, 255, 255)) painter.drawPath(path) painter.drawText(self._textRect, self._text)
def draw_text(painter: QPainter, x: float, y: float, flags, text: str): # Originally from # https://stackoverflow.com/questions/24831484/how-to-align-qpainter-drawtext-around-a-point-not-a-rectangle size = 32767.0 corner = QPointF(x, y - size) if flags & Qt.AlignHCenter: corner.setX(corner.x() - size / 2.0) elif flags & Qt.AlignRight: corner.setX(corner.x() - size) if flags & Qt.AlignVCenter: corner.setY(corner.y() + size / 2.0) elif flags & Qt.AlignTop: corner.setY(corner.y() + size) else: flags |= Qt.AlignBottom rect = QRectF(corner.x(), corner.y(), size, size) painter.drawText(rect, int(flags), text)
def drawText(self, painter, flags, text, boundingRect=0): size = 32767.0 x, y = self.boundingRect().center() corner = QPointF(x, y - size) if flags & Qt.AlignHCenter: corner.setX(corner.x() - size / 2.0) elif flags & Qt.AlignRight: corner.setX(corner.x() - size) if flags & Qt.AlignVCenter: corner.setY(corner.y() + size / 2.0) elif flags & Qt.AlignTop: corner.setY(corner.y() + size) else: flags |= Qt.AlignBottom rect = QRectF(corner.x(), corner.y(), size, size) pen = painter.setPen(painter.brush().color().inverse()) painter.save() painter.drawText(rect, flags, text, boundingRect) painter.restore()
def paint(self, painter, option, widget): pen = QPen(Qt.black, 1) if self._hover: pen.setColor(Qt.blue) if self.isSelected(): pen.setColor(Qt.red) pen.setWidth(2) painter.setPen(pen) painter.drawEllipse(self.boundingRect()) if self.state_type == StateType.FINAL: painter.drawEllipse(self.boundingRect().adjusted(7, 7, -7, -7)) elif self.state_type == StateType.INITIAL: center = QPointF(self.boundingRect().center()) center.setX(center.x() - (self.boundingRect().height() * 0.3)) up = QPointF(self.boundingRect().topLeft()) up.setY(up.y() + (self.boundingRect().height() * 0.3)) down = QPointF(self.boundingRect().bottomLeft()) down.setY(down.y() - (self.boundingRect().height() * 0.3)) triangle = [center, up, down] painter.drawPolygon(triangle) painter.drawText(self.boundingRect(), Qt.AlignCenter, str(self.state_number))
class activeTriangle(QGraphicsPathItem): """ interactive bump triangle """ def __init__(self, x, y, bump, persistent=False, rect=None, parentItem=None): super().__init__(parent=parentItem) self.setAcceptHoverEvents(True) self.persistent = persistent self.rect = rect self.setPos(QPointF(x, y)) self.clicked = False # coordinates are relative to activeTriangle self.B, self.C, self.A = QPointF(0, 0), QPointF(50, 0), QPointF(25, -bump) self.setPen(QPen(QColor(255, 255, 255), 2)) self.update() def update(self): qpp = QPainterPath() trans = QPointF(-4, -4) # coordinates are relative to activeTriangle for p in [self.A, self.B, self.C]: qpp.addEllipse(p + trans, 4, 4) self.setPath(qpp) super().update() def mousePressEvent(self, e): self.clicked = True xt, yt = e.pos().x(), e.pos().y() p = QPointF(xt, yt) self.moving = None for p in [self.A, self.B, self.C]: if abs(xt - p.x()) + abs(yt - p.y()) < 15: self.moving = p break def mouseMoveEvent(self, e): if self.moving is None: return self.clicked = False xt, yt = e.pos().x(), e.pos().y() if self.moving is self.A: self.A.setY(yt) else: if self.moving is self.B: x1, x2 = xt, self.C.x() elif self.moving is self.C: x1, x2 = xt, self.B.x() self.A.setX((self.B.x() + self.C.x()) / 2) self.B.setX(min(x1, x2)) self.C.setX(max(x1, x2)) self.update() self.parentItem().updatePath() def mouseReleaseEvent(self, e): # get scene current spline sc = self.scene() # get parent spline activeSpline = self.parentItem() # sc.cubicItem # click event : remove point if self.clicked: if self.persistent: return activeSpline.fixedPoints.remove(self) sc.removeItem(self) return activeSpline.updateLUTXY() activeSpline.curveChanged.sig.emit() def hoverEnterEvent(self, *args, **kwargs): self.setPen(QPen(QColor(0, 255, 0), 2)) self.update() def hoverLeaveEvent(self, *args, **kwargs): self.setPen(QPen(QColor(255, 255, 255), 2)) self.update()
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None: painter.setRenderHints(QPainter.Antialiasing) node: NavModel.TreeNode = index.data(Qt.UserRole) # 定义变量存储区域 optionRect: QRect = option.rect x: int = optionRect.x() y: int = optionRect.y() width: int = optionRect.width() height: int = optionRect.height() fontSize: int = self.__nav.parentFontSize parent: bool = node.level == 1 # 父节点和子节点颜色分开设置 # 根据不同的状态设置不同的颜色 bgColor-主背景色 textColor-主文字颜色 tipBgColor-提示信息背景颜色 tipTextColor-提示信息文字颜色 if option.state & QStyle.State_Selected: bgColor = self.__nav.parentBgSelectedColor if parent else self.__nav.childBgSelectedColor textColor = self.__nav.parentTextSelectedColor if parent else self.__nav.childTextSelectedColor tipBgColor = self.__nav.parentTextSelectedColor if parent else self.__nav.childTextSelectedColor tipTextColor = self.__nav.parentBgSelectedColor if parent else self.__nav.childBgSelectedColor # iconColor = self.__nav.parentTextSelectedColor if parent else self.__nav.childTextSelectedColor elif option.state & QStyle.State_MouseOver: bgColor = self.__nav.parentBgHoverColor if parent else self.__nav.childBgHoverColor textColor = self.__nav.parentTextHoverColor if parent else self.__nav.childTextHoverColor tipBgColor = self.__nav.parentTextSelectedColor if parent else self.__nav.childTextSelectedColor tipTextColor = self.__nav.parentBgSelectedColor if parent else self.__nav.childBgSelectedColor # iconColor = self.__nav.parentTextHoverColor if parent else self.__nav.childTextHoverColor else: bgColor = self.__nav.parentBgNormalColor if parent else self.__nav.childBgNormalColor textColor = self.__nav.parentTextNormalColor if parent else self.__nav.childTextNormalColor tipBgColor = self.__nav.parentBgSelectedColor if parent else self.__nav.childBgSelectedColor tipTextColor = self.__nav.parentTextSelectedColor if parent else self.__nav.childTextSelectedColor # iconColor = self.__nav.parentTextNormalColor if parent else self.__nav.childTextNormalColor painter.fillRect(optionRect, bgColor) # 绘制背景 # 绘制线条,目前限定子节点绘制,如果需要父节点也绘制则取消parent判断即可 lineWidth: int = self.__nav.lineWidth if not parent and self.__nav.lineVisible and lineWidth > 0: if (option.state & QStyle.State_Selected) or ( option.state & QStyle.State_MouseOver): offset: float = lineWidth / 2 # 设置偏移量,不然上下部分会有点偏移 # 计算上下两个坐标点 pointTop = QPointF(x, y + offset) pointBottom = QPointF(x, height + y - offset) if not self.__nav.lineLeft: pointTop.setX(width) pointBottom.setX(width) # 设置线条颜色和宽度 painter.setPen(QPen(self.__nav.lineColor, lineWidth)) painter.drawLine(pointTop, pointBottom) # 绘制三角形,目前限定子节点绘制,如果需要父节点也绘制则取消parent判断即可 triangleWidth: int = self.__nav.triangleWidth if not parent and self.__nav.triangleVisible and triangleWidth > 0: if (option.state & QStyle.State_Selected) or ( option.state & QStyle.State_MouseOver): font: QFont = self.__iconFont font.setPixelSize(fontSize + triangleWidth) painter.setFont(font) painter.setPen(self.__nav.triangleColor) # 采用图形字体中的三角形绘制 if self.__nav.triangleLeft: painter.drawText(optionRect, Qt.AlignLeft | Qt.AlignVCenter, chr(0xf0da)) else: painter.drawText(optionRect, Qt.AlignRight | Qt.AlignVCenter, chr(0xf0d9)) # 绘制行分隔符 if self.__nav.separateVisible: if node.level == 1 or node.level == 2 and node.last: painter.setPen( QPen(self.__nav.separateColor, self.__nav.separateHeight)) painter.drawLine(QPointF(x, y + height), QPointF(x + width, y + height)) # 绘制文字,如果文字为空则不绘制 text: str = node.text if text != '': # 文字离左边的距离+字体大小 margin: int = self.__nav.parentMargin if node.level == 2: margin = self.__nav.childMargin fontSize = self.__nav.childFontSize # 计算文字区域 textRect: QRect = optionRect.__copy__() textRect.setWidth(width - margin) textRect.setX(x + margin) font: QFont = QFont() font.setPixelSize(fontSize) painter.setFont(font) painter.setPen(textColor) painter.drawText(textRect, Qt.AlignLeft | Qt.AlignVCenter, text) # 绘制提示信息,如果不需要显示提示信息或者提示信息为空则不绘制 tip: str = node.tip if self.__nav.tipVisible and tip != '': # 如果是数字则将超过999的数字显示成 999+ # 如果显示的提示信息长度过长则将多余显示成省略号. try: if int(tip) > 0: tip = "999+" if int(tip) > 999 else tip except ValueError: if len(tip) > 2: tip = tip[:2] + " ." # 计算绘制区域,半径取高度的四分之一 radius: int = height // 4 tipRect: QRect = optionRect.__copy__() tipRect.setHeight(radius * 2) tipRect.moveCenter(optionRect.center()) tipRect.setLeft(optionRect.right() - self.__nav.tipWidth - 5) tipRect.setRight(optionRect.right() - 5) # 设置字体大小 font: QFont = QFont() font.setPixelSize(fontSize - 2) painter.setFont(font) # 绘制提示文字的背景 painter.setPen(Qt.NoPen) painter.setBrush(tipBgColor) painter.drawRoundedRect(tipRect, radius, radius) # 绘制提示文字 painter.setPen(tipTextColor) painter.setBrush(Qt.NoBrush) painter.drawText(tipRect, Qt.AlignCenter, tip) # 计算绘制图标区域 iconRect: QRect = optionRect.__copy__() iconRect.setLeft(self.__nav.parentIconMargin if parent else self.__nav. childIconMargin) # 设置图形字体和画笔颜色 font: QFont = self.__iconFont font.setPixelSize(fontSize) painter.setFont(font) painter.setPen(textColor) # 绘制左侧图标,有图标则绘制图标,没有的话父窗体取 + - if node.icon != '': painter.drawText(iconRect, Qt.AlignLeft | Qt.AlignVCenter, node.icon) elif parent: if node.expand: painter.drawText(iconRect, Qt.AlignLeft | Qt.AlignVCenter, chr(0xf067)) else: painter.drawText(iconRect, Qt.AlignLeft | Qt.AlignVCenter, chr(0xf068)) # 绘制父节点右侧图标 iconRect.setRight(optionRect.width() - 10) if not (self.__nav.tipVisible and node.tip != '') and self.__nav.rightIconVisible and parent: if node.expand: painter.drawText(iconRect, Qt.AlignRight | Qt.AlignVCenter, chr(0xf054)) else: painter.drawText(iconRect, Qt.AlignRight | Qt.AlignVCenter, chr(0xf078))
def redraw(self): self.graphics_scene.clear() # draw screenshot self.graphics_scene.addPixmap(self.screenPixel) # prepare for drawing selected area rect = QRectF(self.selected_area) rect = rect.normalized() top_left_point = rect.topLeft() top_right_point = rect.topRight() bottom_left_point = rect.bottomLeft() bottom_right_point = rect.bottomRight() top_middle_point = (top_left_point + top_right_point) / 2 left_middle_point = (top_left_point + bottom_left_point) / 2 bottom_middle_point = (bottom_left_point + bottom_right_point) / 2 right_middle_point = (top_right_point + bottom_right_point) / 2 # draw the picture mask mask = QColor(0, 0, 0, 155) if self.selected_area == QRect(): self.graphics_scene.addRect(0, 0, self.screenPixel.width(), self.screenPixel.height(), QPen(Qt.NoPen), mask) else: self.graphics_scene.addRect(0, 0, self.screenPixel.width(), top_right_point.y(), QPen(Qt.NoPen), mask) self.graphics_scene.addRect(0, top_left_point.y(), top_left_point.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphics_scene.addRect( top_right_point.x(), top_right_point.y(), self.screenPixel.width() - top_right_point.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphics_scene.addRect( 0, bottom_left_point.y(), self.screenPixel.width(), self.screenPixel.height() - bottom_left_point.y(), QPen(Qt.NoPen), mask) # draw the toolBar if self.action != ACTION_SELECT: spacing = 5 # show the toolbar first, then move it to the correct position # because the width of it may be wrong if this is the first time it shows self.tooBar.show() dest = QPointF(rect.bottomRight() - QPointF(self.tooBar.width(), 0) - QPointF(spacing, -spacing)) if dest.x() < spacing: dest.setX(spacing) pen_set_bar_height = self.penSetBar.height( ) if self.penSetBar is not None else 0 if dest.y() + self.tooBar.height( ) + pen_set_bar_height >= self.height(): if rect.top() - self.tooBar.height( ) - pen_set_bar_height < spacing: dest.setY(rect.top() + spacing) else: dest.setY(rect.top() - self.tooBar.height() - pen_set_bar_height - spacing) self.tooBar.move(dest.toPoint()) if self.penSetBar is not None: self.penSetBar.show() self.penSetBar.move(dest.toPoint() + QPoint(0, self.tooBar.height() + spacing)) if self.action == ACTION_TEXT: self.penSetBar.showFontWidget() else: self.penSetBar.showPenWidget() else: self.tooBar.hide() if self.penSetBar is not None: self.penSetBar.hide() # draw the list for step in self.drawListResult: self.drawOneStep(step) if self.drawListProcess is not None: self.drawOneStep(self.drawListProcess) if self.action != ACTION_TEXT: self.drawListProcess = None if self.selected_area != QRect(): self.items_to_remove = [] # draw the selected rectangle pen = QPen(QColor(0, 255, 255), 2) self.items_to_remove.append(self.graphics_scene.addRect(rect, pen)) # draw the drag point radius = QPoint(3, 3) brush = QBrush(QColor(0, 255, 255)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(top_left_point - radius, top_left_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(top_middle_point - radius, top_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(top_right_point - radius, top_right_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(left_middle_point - radius, left_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(right_middle_point - radius, right_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(bottom_left_point - radius, bottom_left_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(bottom_middle_point - radius, bottom_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(bottom_right_point - radius, bottom_right_point + radius), pen, brush)) # draw the textedit if self.textPosition is not None: textSpacing = 50 position = QPoint() if self.textPosition.x() + self.textInput.width( ) >= self.screenPixel.width(): position.setX(self.textPosition.x() - self.textInput.width()) else: position.setX(self.textPosition.x()) if self.textRect is not None: if self.textPosition.y() + self.textInput.height( ) + self.textRect.height() >= self.screenPixel.height(): position.setY(self.textPosition.y() - self.textInput.height() - self.textRect.height()) else: position.setY(self.textPosition.y() + self.textRect.height()) else: if self.textPosition.y() + self.textInput.height( ) >= self.screenPixel.height(): position.setY(self.textPosition.y() - self.textInput.height()) else: position.setY(self.textPosition.y()) self.textInput.move(position) self.textInput.show() # self.textInput.getFocus() # draw the magnifier if self.action == ACTION_SELECT: self.drawMagnifier() if self.mousePressed: self.drawSizeInfo() if self.action == ACTION_MOVE_SELECTED: self.drawSizeInfo()