def on_actItem_Polygon_triggered(self): # 添加一个梯形 item = QGraphicsPolygonItem() points = QPolygonF() points.append(QPointF(-40, -40)) points.append(QPointF(40, -40)) points.append(QPointF(100, 40)) points.append(QPointF(-100, 40)) item.setPolygon(points) item.setPos(-50 + (QtCore.qrand() % 100), -50 + (QtCore.qrand() % 100)) item.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable) item.setBrush(QBrush(Qt.green)) self.view.frontZ = self.view.frontZ + 1 item.setZValue(self.view.frontZ) self.view.seqNum = self.view.seqNum + 1 item.setData(self.view.ItemId, self.view.seqNum) # //自定义数据,ItemId键 item.setData(self.view.ItemDesciption, "梯形") self.scene.addItem(item) self.scene.clearSelection() item.setSelected(True)
def on_qAction16_triggered(self): item = QGraphicsPolygonItem() points = [ QPointF(-40, -40), QPointF(40, -40), QPointF(100, 40), QPointF(-100, 40) ] item.setPolygon(QPolygonF(points)) item.setBrush(QBrush(Qt.green)) self.__setItemProperties(item, "梯形")
class RPolygon(QObject): def __init__(self, points, color, line_width): self._points = [QPointF(p[0], p[1]) for p in points] self._pos = self._points[0] super().__init__() # The underlying QGraphicsPolygonItem self.polygon = QGraphicsPolygonItem() self.polygon.setPolygon(QPolygonF(self._points)) self.polygon.setBrush(QtGui.QBrush(color)) pen = QPen() pen.setWidthF(line_width) self.polygon.setPen(pen) self._visible = 1 def x(self): return self._pos.x() def y(self): return self._pos.y() def points(self): return self._points # The following functions are for animation support @pyqtProperty(QPointF) def pos(self): return self._pos @pos.setter def pos(self, value): delta_x = value.x() - self._pos.x() delta_y = value.y() - self._pos.y() self._points = [ QPointF(p.x() + delta_x, p.y() + delta_y) for p in self._points ] self.polygon.setPolygon(QPolygonF(self._points)) self._pos = value @pyqtProperty(int) def visible(self): return self._visible @visible.setter def visible(self, value): if (value > 0): self.polygon.show() else: self.polygon.hide() self._visible = value
def create_ray_model(self, gscene, start_surf=1): tfrms = self.seq_model.compute_global_coords(start_surf) rayset = self.seq_model.trace_boundary_rays() start_offset = 0.1 * gscene.sceneRect().width() if abs(tfrms[0][1][2]) > start_offset: tfrms[0] = self.seq_model.shift_start_of_rayset( rayset, start_offset) pen = QPen() pen.setCosmetic(True) for rays in rayset: poly1 = [] for i, r in enumerate(rays[3][0][0:]): rot, trns = tfrms[i] p = rot.dot(r[0]) + trns # print(i, r[0], rot, trns, p) poly1.append(QPointF(p[2], -p[1])) poly2 = [] for i, r in enumerate(rays[4][0][0:]): rot, trns = tfrms[i] p = rot.dot(r[0]) + trns # print(i, r[0], rot, trns, p) poly2.append(QPointF(p[2], -p[1])) poly2.reverse() poly1.extend(poly2) polygon = QPolygonF() for p in poly1: polygon.append(p) gpoly = QGraphicsPolygonItem() gpoly.setPolygon(polygon) gpoly.setBrush(QColor(254, 197, 254, 64)) # magenta, 25% gpoly.setPen(pen) gscene.addItem(gpoly)
def create_element_model(self, gscene): clut = rgbt.RGBTable(filename='gui/red_blue64.csv', data_range=[10.0, 100.]) ele_model = ele.ElementModel() ele_model.elements_from_sequence(self.seq_model) pen = QPen() pen.setCosmetic(True) for e in ele_model.elements: poly = e.shape() polygon = QPolygonF() for p in poly: polygon.append(QPointF(p[0], p[1])) gpoly = QGraphicsPolygonItem() gpoly.setPolygon(polygon) # set element color based on V-number gc = float(e.medium.glass_code()) vnbr = round(100.0 * (gc - int(gc)), 3) ergb = clut.get_color(vnbr) gpoly.setBrush(QColor(*ergb)) gpoly.setPen(pen) t = e.tfrm[1] gpoly.setPos(QPointF(t[2], -t[1])) gscene.addItem(gpoly)
def on_actItem_Triangle_triggered(self): item=QGraphicsPolygonItem() points=[QPointF(0,-40), QPointF(60,40), QPointF(-60,40)] item.setPolygon(QPolygonF(points)) item.setBrush(QBrush(Qt.magenta)) #设置填充颜色 self.__setItemProperties(item,"三角形")
class GraphicLine(QGraphicsLineItem): """ This class is a graphic line with an arrow which connects two blocks in the scene. Attributes ---------- origin : QGraphicsRectItem Origin rect of the line. destination : QGraphicsRectItem Destination rect of the line. scene : QGraphicsScene Current drawing scene. brush : QBrush Brush to draw the arrow. pen : QPen Pen to draw the arrow. arrow_head : QGraphicsPolygonItem Final arrow of the line. arrow_size : int Size of the head of the arrow. dim_label : QGraphicsTextItem Text showing the dimensions of the edge. is_valid : bool Flag monitoring whether the connection is consistent. Methods ---------- gen_endpoints(QRectF, QRectF) Returns the shortest connection between the two rects. draw_arrow() Draws the polygon for the arrow. set_valid(bool) Assign validity for this line. update_dims(tuple) Update the line dimensions. update_pos(QRectF) Update the line position given the new rect position. remove_self() Delete this line. """ def __init__(self, origin: QGraphicsRectItem, destination: QGraphicsRectItem, scene): super(GraphicLine, self).__init__() self.origin = origin self.destination = destination self.scene = scene # This flag confirms a legal connection self.is_valid = True # Get the four sides of the rects destination_lines = u.get_sides_of( self.destination.sceneBoundingRect()) origin_lines = u.get_sides_of(self.origin.sceneBoundingRect()) # Get the shortest edge between the two blocks self.setLine(self.gen_endpoints(origin_lines, destination_lines)) self.brush = QBrush(QColor(style.GREY_0)) self.pen = QPen(QColor(style.GREY_0)) self.pen.setWidth(4) self.pen.setCapStyle(Qt.RoundCap) self.pen.setJoinStyle(Qt.RoundJoin) self.setPen(self.pen) # Dimensions labels self.dim_label = QGraphicsTextItem() self.dim_label.setZValue(6) self.scene.addItem(self.dim_label) # Arrow head self.arrow_head = QGraphicsPolygonItem() self.arrow_head.setPen(self.pen) self.arrow_head.setBrush(self.brush) self.arrow_size = 15.0 self.draw_arrow() @staticmethod def gen_endpoints(origin_sides: dict, destination_sides: dict) -> QLineF: """ This method finds the shortest path between two rectangles. Parameters ---------- origin_sides : dict The dictionary {side_label: side_size} of the starting rect. destination_sides : dict The dictionary {side_label: side_size} of the ending rect. Returns ---------- QLineF The shortest line. """ # Init the line with the maximum possible value shortest_line = QLineF(-sys.maxsize / 2, -sys.maxsize / 2, sys.maxsize / 2, sys.maxsize / 2) for o_side, origin_side in origin_sides.items(): o_mid_x, o_mid_y = u.get_midpoint(o_side, origin_side) for d_side, destination_side in destination_sides.items(): d_mid_x, d_mid_y = u.get_midpoint(d_side, destination_side) # Update line line = QLineF(o_mid_x, o_mid_y, d_mid_x, d_mid_y) if line.length() < shortest_line.length(): shortest_line = line return shortest_line def draw_arrow(self) -> None: """ This method draws an arrow at the end of the line. """ polygon_arrow_head = QPolygonF() # Compute the arrow angle angle = math.acos(self.line().dx() / self.line().length()) angle = ((math.pi * 2) - angle) # Compute the direction where the arrow points (1 up, -1 down) arrow_direction = 1 if math.asin(self.line().dy() / self.line().length()) < 0: arrow_direction = -1 # First point of the arrow tail arrow_p1 = self.line().p2() - arrow_direction * QPointF( arrow_direction * math.sin(angle + math.pi / 2.5) * self.arrow_size, math.cos(angle + math.pi / 2.5) * self.arrow_size) # Second point of the arrow tail arrow_p2 = self.line().p2() - arrow_direction * QPointF( arrow_direction * math.sin(angle + math.pi - math.pi / 2.5) * self.arrow_size, math.cos(angle + math.pi - math.pi / 2.5) * self.arrow_size) # Third point is the line end polygon_arrow_head.append(self.line().p2()) polygon_arrow_head.append(arrow_p2) polygon_arrow_head.append(arrow_p1) # Add the arrow to the scene self.arrow_head.setZValue(1) self.arrow_head.setParentItem(self) self.arrow_head.setPolygon(polygon_arrow_head) def set_valid(self, valid: bool) -> None: """ This method changes the arrow style: if the connection is not valid the arrow becomes red, otherwise it remains grey with dimensions displayed. Parameters ---------- valid : bool New value for the legality flag. """ if valid: self.is_valid = True self.pen.setColor(QColor(style.GREY_0)) self.brush.setColor(QColor(style.GREY_0)) self.dim_label.setVisible(False) else: self.is_valid = False self.pen.setColor(QColor(style.RED_2)) self.brush.setColor(QColor(style.RED_2)) if self.scene.is_dim_visible: self.dim_label.setVisible(True) def update_dims(self, dims: tuple) -> None: """ This method updates the input & output dimensions. Parameters ---------- dims : tuple The new dimensions to update. """ self.dim_label.setHtml("<div style = 'background-color: " + style.RED_2 + "; color: white; font-family: consolas;'>" + str(dims) + "</div>") self.dim_label.setPos(self.line().center()) def update_pos(self, new_target: QRectF): """ This method updates the line as it origin or its destination has changed location. Parameters ---------- new_target : QRectF """ if new_target == self.destination: self.destination = new_target elif new_target == self.origin: self.origin = new_target # Get the four sides of the rects destination_lines = u.get_sides_of( self.destination.sceneBoundingRect()) origin_lines = u.get_sides_of(self.origin.sceneBoundingRect()) # Get the shortest edge between the two blocks self.setLine(self.gen_endpoints(origin_lines, destination_lines)) self.draw_arrow() self.dim_label.setPos(self.line().center()) def remove_self(self) -> None: """ The line is removed from the scene along with origin and destination pointers. """ self.scene.removeItem(self) self.scene.edges.remove(self) self.scene.removeItem(self.dim_label) self.origin = None self.destination = None
class TransitionGraphicsItem(QGraphicsObject): # constant values SQUARE_SIDE = 10 ARROW_SIZE = 12 PEN_NORMAL_WIDTH = 1 PEN_FOCUS_WIDTH = 3 posChanged = pyqtSignal('QGraphicsItem') def __init__(self, data): super(QGraphicsObject, self).__init__() self.transitionData = data self.originLine = None self.destinationLine = None self.arrow = None self.textGraphics = None self.middleHandle = None self.graphicsOrigin = self.transitionData.origin.getGraphicsItem() self.graphicsDestination = self.transitionData.destination.getGraphicsItem() # connect position changed event self.graphicsOrigin.posChanged.connect(self.statePosChanged) self.graphicsDestination.posChanged.connect(self.statePosChanged) self.midPointX = (self.graphicsDestination.scenePos().x() + self.graphicsOrigin.scenePos().x()) / 2.0 self.midPointY = (self.graphicsDestination.scenePos().y() + self.graphicsOrigin.scenePos().y()) / 2.0 self.createOriginLine() self.createDestinationLine() self.createArrow() self.createMiddleHandle() self.createIdTextBox() def statePosChanged(self, state): if self.graphicsOrigin == state: self.createOriginLine() elif self.graphicsDestination == state: self.createDestinationLine() self.createArrow() def createOriginLine(self): if self.originLine == None: self.originLine = QGraphicsLineItem(self.midPointX, self.midPointY, self.graphicsOrigin.scenePos().x(), self.graphicsOrigin.scenePos().y(), self) else: self.originLine.setLine(QLineF(self.midPointX, self.midPointY, self.graphicsOrigin.scenePos().x(), self.graphicsOrigin.scenePos().y())) myLine = self.originLine.line() myLine.setLength(myLine.length() - StateGraphicsItem.NODE_WIDTH / 2) self.originLine.setLine(myLine) def createDestinationLine(self): if self.destinationLine == None: self.destinationLine = QGraphicsLineItem(self.midPointX, self.midPointY, self.graphicsDestination.scenePos().x(), self.graphicsDestination.scenePos().y(), self) else: self.destinationLine.setLine(QLineF(self.midPointX, self.midPointY, self.graphicsDestination.scenePos().x(), self.graphicsDestination.scenePos().y())) myLine = self.destinationLine.line() myLine.setLength(myLine.length() - StateGraphicsItem.NODE_WIDTH / 2) self.destinationLine.setLine(myLine) def createArrow(self): # add an arrow to destination line myLine = self.destinationLine.line() myLine.setLength(myLine.length() - TransitionGraphicsItem.ARROW_SIZE) rotatePoint = myLine.p2() - self.destinationLine.line().p2() rightPointX = rotatePoint.x() * math.cos(math.pi / 6) - rotatePoint.y() * math.sin(math.pi / 6) rightPointY = rotatePoint.x() * math.sin(math.pi / 6) + rotatePoint.y() * math.cos(math.pi / 6) rightPoint = QPointF(rightPointX + self.destinationLine.line().x2(), rightPointY + self.destinationLine.line().y2()) leftPointX = rotatePoint.x() * math.cos(-math.pi / 6) - rotatePoint.y() * math.sin(-math.pi / 6) leftPointY = rotatePoint.x() * math.sin(-math.pi / 6) + rotatePoint.y() * math.cos(-math.pi / 6) leftPoint = QPointF(leftPointX + self.destinationLine.line().x2(), leftPointY + self.destinationLine.line().y2()) polygon = QPolygonF() polygon << rightPoint << leftPoint << self.destinationLine.line().p2() << rightPoint if self.arrow == None: self.arrow = QGraphicsPolygonItem(polygon, self) else: self.arrow.setPolygon(polygon) brush = QBrush(Qt.SolidPattern) brush.setColor(Qt.black) self.arrow.setBrush(brush) def createMiddleHandle(self): # create middle handle if self.middleHandle == None: self.middleHandle = RectHandleGraphicsItem(TransitionGraphicsItem.SQUARE_SIDE, self) self.middleHandle.setFlag(QGraphicsItem.ItemIsMovable) self.middleHandle.setPos(self.midPointX, self.midPointY) def createIdTextBox(self): if self.textGraphics == None: self.textGraphics = IdTextBoxGraphicsItem(self.transitionData.name, self) self.textGraphics.textChanged.connect(self.nameChanged) else: self.textGraphics.setPlainText(self.transitionData.name) textWidth = self.textGraphics.boundingRect().width() self.textGraphics.setPos(self.midPointX - textWidth / 2, self.midPointY + TransitionGraphicsItem.SQUARE_SIDE - (TransitionGraphicsItem.SQUARE_SIDE / 2) + 5) def updateMiddlePoints(self, newPosition): self.midPointX = newPosition.x() self.midPointY = newPosition.y() self.createOriginLine() self.createDestinationLine() self.createArrow() self.createIdTextBox() self.posChanged.emit(self) def nameChanged(self, name): self.transitionData.name = name self.createIdTextBox() def boundingRect(self): if self.middleHandle != None: return self.middleHandle.boundingRect() else: return None def disableInteraction(self): if self.middleHandle is not None: self.middleHandle.setFlag(QGraphicsItem.ItemIsMovable, False) self.middleHandle.disableInteraction()
class NozzlePreviewWidget(QWidget): def __init__(self): super().__init__() self.ui = Ui_NozzlePreview() self.ui.setupUi(self) self.brush = QBrush() self.brush.setStyle(1) self.scene = QGraphicsScene(self) self.upper = QGraphicsPolygonItem() self.lower = QGraphicsPolygonItem() self.upper.setBrush(self.brush) self.lower.setBrush(self.brush) self.scene.addItem(self.upper) self.scene.addItem(self.lower) self.ui.tabCrossSection.setScene(self.scene) self.ui.tabWidget.currentChanged.connect(self.rescale) def loadNozzle(self, nozzle): geomAlerts = nozzle.getGeometryErrors() self.ui.tabAlerts.clear() for err in geomAlerts: self.ui.tabAlerts.addItem(err.description) self.upper.setPolygon(QPolygonF([])) self.lower.setPolygon(QPolygonF([])) for alert in geomAlerts: if alert.level == motorlib.simResult.SimAlertLevel.ERROR: return convAngle = radians(nozzle.props['convAngle'].getValue()) throatLen = nozzle.props['throatLength'].getValue() throatRad = nozzle.props['throat'].getValue() / 2 divAngle = radians(nozzle.props['divAngle'].getValue()) exitRad = nozzle.props['exit'].getValue() / 2 outerRad = 1.25 * exitRad if QApplication.instance() and QApplication.instance( ).fileManager: # Check if the app exists and has a fm motor = QApplication.instance().fileManager.getCurrentMotor() if len(motor.grains) > 0: outerRad = motor.grains[0].getProperty('diameter') / 2 scale = 100 / nozzle.props['exit'].getValue() radDiff = exitRad - throatRad if divAngle != 0: divLen = radDiff / tan(divAngle) else: divLen = 0 if convAngle != 0: convLen = (outerRad - throatRad) / tan(convAngle) else: convLen = 0 upperPoints = [ [throatLen, throatRad], [0, throatRad], [-divLen, exitRad], [-divLen, outerRad], [throatLen + convLen, outerRad], ] lower = QPolygonF( [QPointF(p[0] * scale, p[1] * scale) for p in upperPoints]) upper = QPolygonF( [QPointF(p[0] * scale, -p[1] * scale) for p in upperPoints]) self.upper.setPolygon(upper) self.lower.setPolygon(lower) self.rescale() def rescale(self): self.scene.setSceneRect(self.scene.itemsBoundingRect()) self.ui.tabCrossSection.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
class EdgeItem(GraphItem): _qt_pen_styles = { 'dashed': Qt.DashLine, 'dotted': Qt.DotLine, 'solid': Qt.SolidLine, } def __init__(self, highlight_level, spline, label_center, label, from_node, to_node, parent=None, penwidth=1, edge_color=None, style='solid'): super(EdgeItem, self).__init__(highlight_level, parent) self.from_node = from_node self.from_node.add_outgoing_edge(self) self.to_node = to_node self.to_node.add_incoming_edge(self) self._default_edge_color = self._COLOR_BLACK if edge_color is not None: self._default_edge_color = edge_color self._default_text_color = self._COLOR_BLACK self._default_color = self._COLOR_BLACK self._text_brush = QBrush(self._default_color) self._shape_brush = QBrush(self._default_color) if style in ['dashed', 'dotted']: self._shape_brush = QBrush(Qt.transparent) self._label_pen = QPen() self._label_pen.setColor(self._default_text_color) self._label_pen.setJoinStyle(Qt.RoundJoin) self._edge_pen = QPen(self._label_pen) self._edge_pen.setWidth(penwidth) self._edge_pen.setColor(self._default_edge_color) self._edge_pen.setStyle(self._qt_pen_styles.get(style, Qt.SolidLine)) self._sibling_edges = set() self._label = None if label is not None: self._label = QGraphicsSimpleTextItem(label) self._label.setFont(GraphItem._LABEL_FONT) label_rect = self._label.boundingRect() label_rect.moveCenter(label_center) self._label.setPos(label_rect.x(), label_rect.y()) self._label.hoverEnterEvent = self._handle_hoverEnterEvent self._label.hoverLeaveEvent = self._handle_hoverLeaveEvent self._label.setAcceptHoverEvents(True) # spline specification according to # http://www.graphviz.org/doc/info/attrs.html#k:splineType coordinates = spline.split(' ') # extract optional end_point end_point = None if (coordinates[0].startswith('e,')): parts = coordinates.pop(0)[2:].split(',') end_point = QPointF(float(parts[0]), -float(parts[1])) # extract optional start_point if (coordinates[0].startswith('s,')): parts = coordinates.pop(0).split(',') # first point parts = coordinates.pop(0).split(',') point = QPointF(float(parts[0]), -float(parts[1])) path = QPainterPath(point) while len(coordinates) > 2: # extract triple of points for a cubic spline parts = coordinates.pop(0).split(',') point1 = QPointF(float(parts[0]), -float(parts[1])) parts = coordinates.pop(0).split(',') point2 = QPointF(float(parts[0]), -float(parts[1])) parts = coordinates.pop(0).split(',') point3 = QPointF(float(parts[0]), -float(parts[1])) path.cubicTo(point1, point2, point3) self._arrow = None if end_point is not None: # draw arrow self._arrow = QGraphicsPolygonItem() polygon = QPolygonF() polygon.append(point3) offset = QPointF(end_point - point3) corner1 = QPointF(-offset.y(), offset.x()) * 0.35 corner2 = QPointF(offset.y(), -offset.x()) * 0.35 polygon.append(point3 + corner1) polygon.append(end_point) polygon.append(point3 + corner2) self._arrow.setPolygon(polygon) self._arrow.hoverEnterEvent = self._handle_hoverEnterEvent self._arrow.hoverLeaveEvent = self._handle_hoverLeaveEvent self._arrow.setAcceptHoverEvents(True) self._path = QGraphicsPathItem(parent) self._path.setPath(path) self.addToGroup(self._path) self.set_node_color() self.set_label_color() def add_to_scene(self, scene): scene.addItem(self) if self._label is not None: scene.addItem(self._label) if self._arrow is not None: scene.addItem(self._arrow) def setToolTip(self, tool_tip): super(EdgeItem, self).setToolTip(tool_tip) if self._label is not None: self._label.setToolTip(tool_tip) if self._arrow is not None: self._arrow.setToolTip(tool_tip) def add_sibling_edge(self, edge): self._sibling_edges.add(edge) def set_node_color(self, color=None): if color is None: self._label_pen.setColor(self._default_text_color) self._text_brush.setColor(self._default_color) if self._shape_brush.isOpaque(): self._shape_brush.setColor(self._default_edge_color) self._edge_pen.setColor(self._default_edge_color) else: self._label_pen.setColor(color) self._text_brush.setColor(color) if self._shape_brush.isOpaque(): self._shape_brush.setColor(color) self._edge_pen.setColor(color) self._path.setPen(self._edge_pen) if self._arrow is not None: self._arrow.setBrush(self._shape_brush) self._arrow.setPen(self._edge_pen) def set_label_color(self, color=None): if color is None: self._label_pen.setColor(self._default_text_color) else: self._label_pen.setColor(color) if self._label is not None: self._label.setBrush(self._text_brush) self._label.setPen(self._label_pen) def _handle_hoverEnterEvent(self, event): # hovered edge item in red self.set_node_color(self._COLOR_RED) self.set_label_color(self._COLOR_RED) if self._highlight_level > 1: if self.from_node != self.to_node: # from-node in blue self.from_node.set_node_color(self._COLOR_BLUE) # to-node in green self.to_node.set_node_color(self._COLOR_GREEN) else: # from-node/in-node in teal self.from_node.set_node_color(self._COLOR_TEAL) self.to_node.set_node_color(self._COLOR_TEAL) if self._highlight_level > 2: # sibling edges in orange for sibling_edge in self._sibling_edges: sibling_edge.set_node_color(self._COLOR_ORANGE) def _handle_hoverLeaveEvent(self, event): self.set_node_color() self.set_label_color() if self._highlight_level > 1: self.from_node.set_node_color() self.to_node.set_node_color() if self._highlight_level > 2: for sibling_edge in self._sibling_edges: sibling_edge.set_node_color()
class ASCGraphicsView(QGraphicsView): scale_signal = pyqtSignal('float', 'float') set_focus_point_signal = pyqtSignal('int', 'int', 'int') set_focus_point_percent_signal = pyqtSignal('float', 'float', 'float') move_focus_point_signal = pyqtSignal('int', 'int', 'int') # x, y, z, BRUSH_TYPE, BRUSH_SIZE, ERASE paint_anno_on_point_signal = pyqtSignal('int', 'int', 'int', 'int', 'int', 'bool', 'bool') def __init__(self, parent=None): super(ASCGraphicsView, self).__init__(parent) self.scene = QGraphicsScene(self) self.raw_img_item = QGraphicsPixmapItem() self.raw_img_item.setZValue(0) self.anno_img_item = QGraphicsPixmapItem() self.anno_img_item.setZValue(1) self.cross_bar_v_line_item = QGraphicsLineItem() self.cross_bar_h_line_item = QGraphicsLineItem() self.cross_bar_v_line_item.setZValue(100) self.cross_bar_h_line_item.setZValue(100) self.cross_bar_v_line_item.setPen( QPen(Qt.blue, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.cross_bar_h_line_item.setPen( QPen(Qt.blue, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.paint_brush_circle_item = QGraphicsEllipseItem() self.paint_brush_rect_item = QGraphicsPolygonItem() self.paint_brush_circle_item.setZValue(10) self.paint_brush_rect_item.setZValue(11) self.paint_brush_circle_item.setVisible(False) self.paint_brush_rect_item.setVisible(False) self.paint_brush_circle_item.setPen( QPen(Qt.red, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.paint_brush_rect_item.setPen( QPen(Qt.red, 0, Qt.DotLine, Qt.FlatCap, Qt.RoundJoin)) self.scene.addItem(self.raw_img_item) self.scene.addItem(self.anno_img_item) self.scene.addItem(self.cross_bar_v_line_item) self.scene.addItem(self.cross_bar_h_line_item) self.scene.addItem(self.paint_brush_circle_item) self.scene.addItem(self.paint_brush_rect_item) self.setScene(self.scene) self.setViewport(QOpenGLWidget()) self._last_button_press = Qt.NoButton self._last_pos_middle_button = None self._last_pos_right_button = None self._brush_stats = {'type': BRUSH_TYPE_NO_BRUSH, 'size': 5} self.setResizeAnchor(QGraphicsView.AnchorViewCenter) self.slice_scroll_bar = None self.image_size = None self.is_valid = False def clear(self): """before loading new image""" self._last_pos_middle_button = None self._last_pos_right_button = None self._last_button_press = Qt.NoButton self.raw_img_item.setPixmap(QPixmap()) self.anno_img_item.setPixmap(QPixmap()) self.paint_brush_circle_item.setVisible(False) self.paint_brush_rect_item.setVisible(False) self.image_size = None self.is_valid = False def init_view(self, image_size): """after loading new image""" self.is_valid = True self.image_size = image_size self.slice_scroll_bar = self.parent().findChild( QScrollBar, self.objectName()[0] + 'SliceScrollBar') trans_mat = item2scene_transform[self.objectName()[0]] self.raw_img_item.setTransform(trans_mat) self.anno_img_item.setTransform(trans_mat) self.cross_bar_v_line_item.setTransform(trans_mat) self.cross_bar_h_line_item.setTransform(trans_mat) self.paint_brush_rect_item.setTransform(trans_mat) self.paint_brush_circle_item.setTransform(trans_mat) self.fitInView(self.raw_img_item, Qt.KeepAspectRatio) self.paint_brush_circle_item.setVisible(False) self.paint_brush_rect_item.setVisible(False) @property def brush_stats(self): return self._brush_stats @brush_stats.setter def brush_stats(self, stats_tuple): b_type, size = stats_tuple if b_type in [ BRUSH_TYPE_NO_BRUSH, BRUSH_TYPE_CIRCLE_BRUSH, BRUSH_TYPE_RECT_BRUSH ]: self._brush_stats['type'] = b_type self._brush_stats['size'] = size if b_type != BRUSH_TYPE_NO_BRUSH: self.setMouseTracking(True) else: self.setMouseTracking(False) def update_brush_preview(self, x, y, out_of_sight=False): if not self.is_valid or self.brush_stats[ 'type'] == BRUSH_TYPE_NO_BRUSH or out_of_sight: self.paint_brush_rect_item.setVisible(False) self.paint_brush_circle_item.setVisible(False) return center = self.anno_img_item.mapFromScene(self.mapToScene(x, y)) start_x = self.raw_img_item.boundingRect().topLeft().x() start_y = self.raw_img_item.boundingRect().topLeft().y() end_x = self.raw_img_item.boundingRect().bottomRight().x() end_y = self.raw_img_item.boundingRect().bottomRight().y() center.setX(min(max(start_x, center.x()), end_x) + 0.5) center.setY(min(max(start_y, center.y()), end_y) + 0.5) top_left_x = int(center.x() - self.brush_stats['size'] / 2) top_left_y = int(center.y() - self.brush_stats['size'] / 2) rect = QRectF(top_left_x, top_left_y, self.brush_stats['size'], self.brush_stats['size']) if self.brush_stats['type'] == BRUSH_TYPE_CIRCLE_BRUSH: self.paint_brush_rect_item.setVisible(False) self.paint_brush_circle_item.setVisible(True) self.paint_brush_circle_item.setRect(rect) if self.brush_stats['type'] == BRUSH_TYPE_RECT_BRUSH: self.paint_brush_rect_item.setVisible(True) self.paint_brush_circle_item.setVisible(False) self.paint_brush_rect_item.setPolygon(QPolygonF(rect)) def anno_paint(self, x, y, erase=False, new_step=False): pos_on_item = self.raw_img_item.mapFromScene(self.mapToScene(x, y)) if self.objectName() == 'aGraphicsView': paint_point = [pos_on_item.y(), pos_on_item.x(), 999999] if self.objectName() == 'sGraphicsView': paint_point = [999999, pos_on_item.y(), pos_on_item.x()] if self.objectName() == 'cGraphicsView': paint_point = [pos_on_item.y(), 999999, pos_on_item.x()] self.paint_anno_on_point_signal.emit(math.floor(paint_point[0]), math.floor(paint_point[1]), math.floor(paint_point[2]), self.brush_stats['type'], self.brush_stats['size'], erase, new_step) @pyqtSlot('int') def on_slice_scroll_bar_changed(self, value): if not self.is_valid: return ratios = [-1, -1, -1] ratio = (value - self.slice_scroll_bar.minimum()) / \ (self.slice_scroll_bar.maximum() - self.slice_scroll_bar.minimum()) if self.objectName() == 'aGraphicsView': ratios[2] = ratio if self.objectName() == 'sGraphicsView': ratios[0] = ratio if self.objectName() == 'cGraphicsView': ratios[1] = ratio self.set_focus_point_percent_signal.emit(ratios[0], ratios[1], ratios[2]) @pyqtSlot('int', 'int') def set_brush_stats(self, b_type, size): self.brush_stats = [b_type, size] @pyqtSlot('int', 'int', 'int') def set_cross_bar(self, x, y, z): if self.objectName() == 'aGraphicsView': cross_bar_x = y cross_bar_y = x slice_bar_ratio = z / self.image_size[2] if self.objectName() == 'sGraphicsView': cross_bar_x = z cross_bar_y = y slice_bar_ratio = x / self.image_size[0] if self.objectName() == 'cGraphicsView': cross_bar_x = z cross_bar_y = x slice_bar_ratio = y / self.image_size[1] # cross line in voxel center cross_bar_x = cross_bar_x + 0.5 cross_bar_y = cross_bar_y + 0.5 start_x = self.raw_img_item.boundingRect().topLeft().x() start_y = self.raw_img_item.boundingRect().topLeft().y() end_x = self.raw_img_item.boundingRect().bottomRight().x() end_y = self.raw_img_item.boundingRect().bottomRight().y() self.cross_bar_v_line_item.setLine(cross_bar_x, start_y, cross_bar_x, end_y) self.cross_bar_h_line_item.setLine(start_x, cross_bar_y, end_x, cross_bar_y) slice_bar_value = round(slice_bar_ratio * (self.slice_scroll_bar.maximum() - self.slice_scroll_bar.minimum())) \ + self.slice_scroll_bar.minimum() self.slice_scroll_bar.setValue(slice_bar_value) def mousePressEvent(self, event: QtGui.QMouseEvent): self._last_button_press = event.button() if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH: if event.button() == Qt.LeftButton: item_coord_pos = self.raw_img_item.mapFromScene( self.mapToScene(event.pos())) if self.objectName() == 'aGraphicsView': new_focus_point = [ item_coord_pos.y(), item_coord_pos.x(), 999999 ] if self.objectName() == 'sGraphicsView': new_focus_point = [ 999999, item_coord_pos.y(), item_coord_pos.x() ] if self.objectName() == 'cGraphicsView': new_focus_point = [ item_coord_pos.y(), 999999, item_coord_pos.x() ] self.set_focus_point_signal.emit( math.floor(new_focus_point[0]), math.floor(new_focus_point[1]), math.floor(new_focus_point[2])) elif event.button() == Qt.MiddleButton: self._last_pos_middle_button = event.pos() self.setCursor(Qt.ClosedHandCursor) elif event.button() == Qt.RightButton: self._last_pos_right_button = event.pos() else: super(ASCGraphicsView, self).mousePressEvent(event) if self.brush_stats['type'] in [ BRUSH_TYPE_CIRCLE_BRUSH, BRUSH_TYPE_RECT_BRUSH ]: if event.button() == Qt.LeftButton: self.anno_paint(event.x(), event.y(), erase=False, new_step=True) elif event.button() == Qt.MiddleButton: self._last_pos_middle_button = event.pos() self.setCursor(Qt.ClosedHandCursor) elif event.button() == Qt.RightButton: self.anno_paint(event.x(), event.y(), erase=True, new_step=True) def mouseMoveEvent(self, event: QtGui.QMouseEvent): if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH: if self._last_button_press == Qt.LeftButton: item_coord_pos = self.raw_img_item.mapFromScene( self.mapToScene(event.pos())) if self.objectName() == 'aGraphicsView': new_focus_point = [ item_coord_pos.y(), item_coord_pos.x(), 999999 ] if self.objectName() == 'sGraphicsView': new_focus_point = [ 999999, item_coord_pos.y(), item_coord_pos.x() ] if self.objectName() == 'cGraphicsView': new_focus_point = [ item_coord_pos.y(), 999999, item_coord_pos.x() ] self.set_focus_point_signal.emit( math.floor(new_focus_point[0]), math.floor(new_focus_point[1]), math.floor(new_focus_point[2])) elif self._last_button_press == Qt.MiddleButton: delta_x = event.x() - self._last_pos_middle_button.x() delta_y = event.y() - self._last_pos_middle_button.y() self.horizontalScrollBar().setValue( self.horizontalScrollBar().value() - delta_x) self.verticalScrollBar().setValue( self.verticalScrollBar().value() - delta_y) self._last_pos_middle_button = event.pos() elif self._last_button_press == Qt.RightButton: delta = event.pos().y() - self._last_pos_right_button.y() scale = 1 - float(delta) / float(self.size().height()) self.scale_signal.emit(scale, scale) self._last_pos_right_button = event.pos() else: super(ASCGraphicsView, self).mouseMoveEvent(event) if self.brush_stats['type'] in [ BRUSH_TYPE_CIRCLE_BRUSH, BRUSH_TYPE_RECT_BRUSH ]: self.update_brush_preview(event.x(), event.y()) if self._last_button_press == Qt.LeftButton: self.anno_paint(event.x(), event.y(), erase=False, new_step=False) elif self._last_button_press == Qt.MiddleButton: delta_x = event.x() - self._last_pos_middle_button.x() delta_y = event.y() - self._last_pos_middle_button.y() self.horizontalScrollBar().setValue( self.horizontalScrollBar().value() - delta_x) self.verticalScrollBar().setValue( self.verticalScrollBar().value() - delta_y) self._last_pos_middle_button = event.pos() elif self._last_button_press == Qt.RightButton: self.anno_paint(event.x(), event.y(), erase=True, new_step=False) def mouseReleaseEvent(self, event: QtGui.QMouseEvent): self._last_button_press = Qt.NoButton if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH: if event.button() == Qt.MiddleButton: self.setCursor(Qt.ArrowCursor) if self.brush_stats['type'] in [ BRUSH_TYPE_CIRCLE_BRUSH, BRUSH_TYPE_RECT_BRUSH ]: if event.button() == Qt.LeftButton: pass elif event.button() == Qt.RightButton: pass else: super(ASCGraphicsView, self).mouseReleaseEvent(event) def wheelEvent(self, event: QtGui.QWheelEvent): # super(ASCGraphicsView, self).wheelEvent(event) if self.objectName() == 'aGraphicsView': if event.angleDelta().y() > 0: self.move_focus_point_signal.emit(0, 0, -1) elif event.angleDelta().y() < 0: self.move_focus_point_signal.emit(0, 0, 1) if self.objectName() == 'sGraphicsView': if event.angleDelta().y() > 0: self.move_focus_point_signal.emit(-1, 0, 0) elif event.angleDelta().y() < 0: self.move_focus_point_signal.emit(1, 0, 0) if self.objectName() == 'cGraphicsView': if event.angleDelta().y() > 0: self.move_focus_point_signal.emit(0, -1, 0) elif event.angleDelta().y() < 0: self.move_focus_point_signal.emit(0, 1, 0) def leaveEvent(self, event: QtCore.QEvent): self._last_button_press = Qt.NoButton if self.brush_stats['type'] == BRUSH_TYPE_NO_BRUSH: super(ASCGraphicsView, self).leaveEvent(event) else: self.update_brush_preview(0, 0, out_of_sight=True)
class TransitionGraphicsItem(QGraphicsObject): # constant values SQUARE_SIDE = 10 ARROW_SIZE = 12 PEN_NORMAL_WIDTH = 1 PEN_FOCUS_WIDTH = 3 posChanged = pyqtSignal('QGraphicsItem') def __init__(self, data): super(QGraphicsObject, self).__init__() self.transitionData = data self.originLine = None self.destinationLine = None self.arrow = None self.textGraphics = None self.middleHandle = None self.graphicsOrigin = self.transitionData.origin.getGraphicsItem() self.graphicsDestination = self.transitionData.destination.getGraphicsItem( ) # connect position changed event self.graphicsOrigin.posChanged.connect(self.statePosChanged) self.graphicsDestination.posChanged.connect(self.statePosChanged) self.midPointX = (self.graphicsDestination.scenePos().x() + self.graphicsOrigin.scenePos().x()) / 2.0 self.midPointY = (self.graphicsDestination.scenePos().y() + self.graphicsOrigin.scenePos().y()) / 2.0 self.createOriginLine() self.createDestinationLine() self.createArrow() self.createMiddleHandle() self.createIdTextBox() def statePosChanged(self, state): if self.graphicsOrigin == state: self.createOriginLine() elif self.graphicsDestination == state: self.createDestinationLine() self.createArrow() def createOriginLine(self): if self.originLine == None: self.originLine = QGraphicsLineItem( self.midPointX, self.midPointY, self.graphicsOrigin.scenePos().x(), self.graphicsOrigin.scenePos().y(), self) else: self.originLine.setLine( QLineF(self.midPointX, self.midPointY, self.graphicsOrigin.scenePos().x(), self.graphicsOrigin.scenePos().y())) myLine = self.originLine.line() myLine.setLength(myLine.length() - StateGraphicsItem.NODE_WIDTH / 2) self.originLine.setLine(myLine) def createDestinationLine(self): if self.destinationLine == None: self.destinationLine = QGraphicsLineItem( self.midPointX, self.midPointY, self.graphicsDestination.scenePos().x(), self.graphicsDestination.scenePos().y(), self) else: self.destinationLine.setLine( QLineF(self.midPointX, self.midPointY, self.graphicsDestination.scenePos().x(), self.graphicsDestination.scenePos().y())) myLine = self.destinationLine.line() myLine.setLength(myLine.length() - StateGraphicsItem.NODE_WIDTH / 2) self.destinationLine.setLine(myLine) def createArrow(self): # add an arrow to destination line myLine = self.destinationLine.line() myLine.setLength(myLine.length() - TransitionGraphicsItem.ARROW_SIZE) rotatePoint = myLine.p2() - self.destinationLine.line().p2() rightPointX = rotatePoint.x() * math.cos( math.pi / 6) - rotatePoint.y() * math.sin(math.pi / 6) rightPointY = rotatePoint.x() * math.sin( math.pi / 6) + rotatePoint.y() * math.cos(math.pi / 6) rightPoint = QPointF(rightPointX + self.destinationLine.line().x2(), rightPointY + self.destinationLine.line().y2()) leftPointX = rotatePoint.x() * math.cos( -math.pi / 6) - rotatePoint.y() * math.sin(-math.pi / 6) leftPointY = rotatePoint.x() * math.sin( -math.pi / 6) + rotatePoint.y() * math.cos(-math.pi / 6) leftPoint = QPointF(leftPointX + self.destinationLine.line().x2(), leftPointY + self.destinationLine.line().y2()) polygon = QPolygonF() polygon << rightPoint << leftPoint << self.destinationLine.line().p2( ) << rightPoint if self.arrow == None: self.arrow = QGraphicsPolygonItem(polygon, self) else: self.arrow.setPolygon(polygon) brush = QBrush(Qt.SolidPattern) brush.setColor(Qt.black) self.arrow.setBrush(brush) def createMiddleHandle(self): # create middle handle if self.middleHandle == None: self.middleHandle = RectHandleGraphicsItem( TransitionGraphicsItem.SQUARE_SIDE, self) self.middleHandle.setFlag(QGraphicsItem.ItemIsMovable) self.middleHandle.setPos(self.midPointX, self.midPointY) def createIdTextBox(self): if self.textGraphics == None: self.textGraphics = IdTextBoxGraphicsItem(self.transitionData.name, self) self.textGraphics.textChanged.connect(self.nameChanged) else: self.textGraphics.setPlainText(self.transitionData.name) textWidth = self.textGraphics.boundingRect().width() self.textGraphics.setPos( self.midPointX - textWidth / 2, self.midPointY + TransitionGraphicsItem.SQUARE_SIDE - (TransitionGraphicsItem.SQUARE_SIDE / 2) + 5) def updateMiddlePoints(self, newPosition): self.midPointX = newPosition.x() self.midPointY = newPosition.y() self.createOriginLine() self.createDestinationLine() self.createArrow() self.createIdTextBox() self.posChanged.emit(self) def nameChanged(self, name): self.transitionData.name = name self.createIdTextBox() def boundingRect(self): if self.middleHandle != None: return self.middleHandle.boundingRect() else: return None def disableInteraction(self): if self.middleHandle is not None: self.middleHandle.setFlag(QGraphicsItem.ItemIsMovable, False) self.middleHandle.disableInteraction()
def on_qAction15_triggered(self): item = QGraphicsPolygonItem() points = [QPointF(0, -40), QPointF(60, 40), QPointF(-60, 40)] item.setPolygon(QPolygonF(points)) item.setBrush(QBrush(Qt.magenta)) self.__setItemProperties(item, "三角形")