class Viewer(QGraphicsView): def __init__(self, gridsize_label, position_label, help_label): QGraphicsView.__init__(self) self.gridsize_label = gridsize_label self.position_label = position_label self.help_label = help_label # Create a QGraphicsScene which this view looks at self.scene = QGraphicsScene(self) self.scene.setSceneRect(QRectF()) self.setScene(self.scene) # Customize QGraphicsView self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setInteractive(False) self.scale(1, -1) # Flips around the Y axis # Use OpenGL http://ralsina.me/stories/BBS53.html # self.setViewport(QtOpenGL.QGLWidget()) self.rubberBand = QRubberBand(QRubberBand.Rectangle, self) self.pen = QPen(QtCore.Qt.black, 0) self.portpen = QPen(PORT_COLOR, 3) self.portpen.setCosmetic(True) # Makes constant width self.portfont = QtGui.QFont('Arial', pointSize=14) self.portfontcolor = PORT_COLOR self.subportpen = QPen(SUBPORT_COLOR, 3) self.subportpen.setCosmetic(True) # Makes constant width self.subportfont = QtGui.QFont('Arial', pointSize=14) self.subportfontcolor = SUBPORT_COLOR # Tracking ports # Various status variables self._mousePressed = None self._rb_origin = QPoint() self.zoom_factor_total = 1 # Grid variables self.gridpen = QPen(QtCore.Qt.black, 0) self.gridpen.setStyle(QtCore.Qt.DotLine) self.gridpen.setDashPattern([1, 4]) self.gridpen.setColor(QtGui.QColor(0, 0, 0, 125)) # self.gridpen = QPen(QtCore.Qt.black, 1) # self.gridpen.setCosmetic(True) # Makes constant width self.scene_polys = [] self.initialize() def add_polygons(self, polygons, color='#A8F22A', alpha=1): qcolor = QColor() qcolor.setNamedColor(color) qcolor.setAlphaF(alpha) for points in polygons: qpoly = QPolygonF([QPointF(p[0], p[1]) for p in points]) scene_poly = self.scene.addPolygon(qpoly) scene_poly.setBrush(qcolor) scene_poly.setPen(self.pen) self.scene_polys.append(scene_poly) # Update custom bounding box sr = scene_poly.sceneBoundingRect() if len(self.scene_polys) == 1: self.scene_xmin = sr.left() self.scene_xmax = sr.right() self.scene_ymin = sr.top() self.scene_ymax = sr.bottom() else: self.scene_xmin = min(self.scene_xmin, sr.left()) self.scene_xmax = max(self.scene_xmax, sr.right()) self.scene_ymin = min(self.scene_ymin, sr.top()) self.scene_ymax = max(self.scene_ymax, sr.bottom()) def reset_view(self): # The SceneRect controls how far you can pan, make it larger than # just the bounding box so middle-click panning works panning_rect = QRectF(self.scene_bounding_rect) panning_rect_center = panning_rect.center() panning_rect_size = max(panning_rect.width(), panning_rect.height()) * 3 panning_rect.setSize(QSizeF(panning_rect_size, panning_rect_size)) panning_rect.moveCenter(panning_rect_center) self.setSceneRect(panning_rect) self.fitInView(self.scene_bounding_rect, Qt.KeepAspectRatio) self.zoom_view(0.8) self.update_grid() def add_port(self, port, is_subport=False): if (port.width is None) or (port.width == 0): x, y = port.midpoint cs = 1 # cross size pn = QPointF(x, y + cs) ps = QPointF(x, y - cs) pe = QPointF(x + cs, y) pw = QPointF(x - cs, y) qline1 = self.scene.addLine(QLineF(pn, ps)) qline2 = self.scene.addLine(QLineF(pw, pe)) port_shapes = [qline1, qline2] else: point1, point2 = port.endpoints point1 = QPointF(point1[0], point1[1]) point2 = QPointF(point2[0], point2[1]) qline = self.scene.addLine(QLineF(point1, point2)) arrow_points = np.array([[0, 0], [10, 0], [6, 4], [6, 2], [0, 2] ]) / (40) * port.width arrow_qpoly = QPolygonF( [QPointF(p[0], p[1]) for p in arrow_points]) port_scene_poly = self.scene.addPolygon(arrow_qpoly) port_scene_poly.setRotation(port.orientation) port_scene_poly.moveBy(port.midpoint[0], port.midpoint[1]) port_shapes = [qline, port_scene_poly] qtext = self.scene.addText(str(port.name), self.portfont) port_items = port_shapes + [qtext] rad = port.orientation * np.pi / 180 x, y = port.endpoints[0] * 1 / 4 + port.endpoints[ 1] * 3 / 4 + np.array([np.cos(rad), np.sin(rad)]) * port.width / 8 # x,y = port.midpoint[0], port.midpoint[1] # x,y = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2 qtext.setPos(QPointF(x, y)) qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations) if not is_subport: [shape.setPen(self.portpen) for shape in port_shapes] qtext.setDefaultTextColor(self.portfontcolor) self.portitems += port_items else: [shape.setPen(self.subportpen) for shape in port_shapes] qtext.setDefaultTextColor(self.subportfontcolor) self.subportitems += port_items # self.portlabels.append(qtext) def add_aliases(self, aliases): for name, ref in aliases.items(): qtext = self.scene.addText(str(name), self.portfont) x, y = ref.center qtext.setPos(QPointF(x, y)) qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.aliasitems += [qtext] def set_port_visibility(self, visible=True): for item in self.portitems: item.setVisible(visible) self.ports_visible = visible def set_subport_visibility(self, visible=True): for item in self.subportitems: item.setVisible(visible) self.subports_visible = visible def set_alias_visibility(self, visible=True): for item in self.aliasitems: item.setVisible(visible) self.aliases_visible = visible def initialize(self): self.scene.clear() self.polygons = {} self.portitems = [] self.subportitems = [] self.aliasitems = [] self.aliases_visible = True self.ports_visible = True self.subports_visible = True self.mouse_position = [0, 0] self.grid_size_snapped = 0 self.setMouseTracking(True) self.scene_bounding_rect = None self.scene_polys = [] self.scene_xmin = 0 self.scene_xmax = 1 self.scene_ymin = 0 self.scene_ymax = 1 def finalize(self): self.scene_bounding_rect = QRectF( QPointF(self.scene_xmin, self.scene_ymin), QPointF(self.scene_xmax, self.scene_ymax)) # self.scene_center = [self.scene_bounding_rect.center().x(), self.scene_bounding_rect.center().y()] self.scene_size = [ self.scene_bounding_rect.width(), self.scene_bounding_rect.height() ] self.create_grid() self.update_grid() #============================================================================== # Grid creation #============================================================================== def update_grid(self): grid_pixels = 50 grid_snaps = [1, 2, 4] # Number of pixels in the viewer view_width, view_height = self.rect().width(), self.rect().height() # Rectangle of viewport in terms of scene coordinates r = self.mapToScene(self.rect()).boundingRect() width, height = r.width(), r.height() xmin, ymin, xmax, ymax = r.x(), r.y(), r.x() + width, r.y() + height grid_size = grid_pixels * (width / view_width) exponent = np.floor(np.log10(grid_size)) digits = round(grid_size / 10**(exponent), 2) digits_snapped = min(grid_snaps, key=lambda x: abs(x - digits)) grid_size_snapped = digits_snapped * 10**(exponent) # Starting coordinates for gridlines x = round((xmin - 2 * width) / grid_size_snapped) * grid_size_snapped y = round((ymin - 2 * height) / grid_size_snapped) * grid_size_snapped for gl in self.gridlinesx: gl.setLine(x, -1e10, x, 1e10) x += grid_size_snapped for gl in self.gridlinesy: gl.setLine(-1e10, y, 1e10, y) y += grid_size_snapped self.grid_size_snapped = grid_size_snapped self.update_gridsize_label() def update_gridsize_label(self): self.gridsize_label.setText('grid size = ' + str(self.grid_size_snapped)) self.gridsize_label.move(QPoint(5, self.height() - 25)) def update_mouse_position_label(self): self.position_label.setText( 'X = %0.4f / Y = %0.4f' % (self.mouse_position[0], self.mouse_position[1])) self.position_label.move(QPoint(self.width() - 250, self.height() - 25)) def update_help_label(self): self.help_label.setText('Press "?" key for help') self.help_label.move(QPoint(self.width() - 175, 0)) def create_grid(self): self.gridlinesx = [ self.scene.addLine(-10, -10, 10, 10, self.gridpen) for n in range(300) ] self.gridlinesy = [ self.scene.addLine(-10, -10, 10, 10, self.gridpen) for n in range(300) ] self.update_grid() #============================================================================== # Mousewheel zoom, taken from http://stackoverflow.com/a/29026916 #============================================================================== def wheelEvent(self, event): # Zoom Factor zoom_percentage = 1.4 # Set Anchors self.setTransformationAnchor(QGraphicsView.NoAnchor) self.setResizeAnchor(QGraphicsView.NoAnchor) # Save the scene pos oldPos = self.mapToScene(event.pos()) # Zoom mousewheel_rotation = event.angleDelta().y( ) # Typically = 120 on most mousewheels zoom_factor = zoom_percentage**(mousewheel_rotation / 120) zoom_factor = np.clip(zoom_factor, 0.5, 2.0) # Check to make sure we're not overzoomed min_width = 0.01 min_height = 0.01 window_width = self.rect().width() window_height = self.rect().height() scene_upper_left_corner = self.mapToScene(QPoint(0, 0)) scene_bottom_right_corner = self.mapToScene( QPoint(window_width, window_height)) scene_width = (scene_bottom_right_corner - scene_upper_left_corner).x() scene_height = (scene_upper_left_corner - scene_bottom_right_corner).y() max_width = self.scene_bounding_rect.width() * 3 max_height = self.scene_bounding_rect.height() * 3 if ((scene_width > max_width) and (scene_height > max_height)) and (zoom_factor < 1): pass elif ((scene_width < min_width) and (scene_height < min_height)) and (zoom_factor > 1): pass else: self.zoom_view(zoom_factor) # Get the new position and move scene to old position newPos = self.mapToScene(event.pos()) delta = newPos - oldPos self.translate(delta.x(), delta.y()) self.update_grid() def zoom_view(self, zoom_factor): old_center = self.mapToScene(self.rect().center()) self.scale(zoom_factor, zoom_factor) self.centerOn(old_center) self.zoom_factor_total *= zoom_factor def resizeEvent(self, event): super(QGraphicsView, self).resizeEvent(event) if self.scene_bounding_rect is not None: self.reset_view() self.update_gridsize_label() self.update_mouse_position_label() self.update_help_label() def mousePressEvent(self, event): super(QGraphicsView, self).mousePressEvent(event) #============================================================================== # Zoom to rectangle, from # https://wiki.python.org/moin/PyQt/Selecting%20a%20region%20of%20a%20widget #============================================================================== if event.button() == Qt.RightButton: self._mousePressed = Qt.RightButton self._rb_origin = QPoint(event.pos()) self.rubberBand.setGeometry(QRect(self._rb_origin, QSize())) self.rubberBand.show() #============================================================================== # Mouse panning, taken from # http://stackoverflow.com/a/15043279 #============================================================================== elif event.button() == Qt.MidButton: self._mousePressed = Qt.MidButton self._mousePressedPos = event.pos() self.setCursor(QtCore.Qt.ClosedHandCursor) self._dragPos = event.pos() def mouseMoveEvent(self, event): super(QGraphicsView, self).mouseMoveEvent(event) # # Useful debug # try: # self.debug_label.setText(str(itemsBoundingRect_nogrid().width())) # except: # print('Debug statement failed') # Update the X,Y label indicating where the mouse is on the geometry mouse_position = self.mapToScene(event.pos()) self.mouse_position = [mouse_position.x(), mouse_position.y()] self.update_mouse_position_label() if not self._rb_origin.isNull( ) and self._mousePressed == Qt.RightButton: self.rubberBand.setGeometry( QRect(self._rb_origin, event.pos()).normalized()) # Middle-click-to-pan if self._mousePressed == Qt.MidButton: newPos = event.pos() diff = newPos - self._dragPos self._dragPos = newPos self.horizontalScrollBar().setValue( self.horizontalScrollBar().value() - diff.x()) self.verticalScrollBar().setValue( self.verticalScrollBar().value() - diff.y()) # event.accept() def mouseReleaseEvent(self, event): if event.button() == Qt.RightButton: self.rubberBand.hide() rb_rect = QRect(self._rb_origin, event.pos()) rb_center = rb_rect.center() rb_size = rb_rect.size() if abs(rb_size.width()) > 3 and abs(rb_size.height()) > 3: viewport_size = self.viewport().geometry().size() zoom_factor_x = abs(viewport_size.width() / rb_size.width()) zoom_factor_y = abs(viewport_size.height() / rb_size.height()) new_center = self.mapToScene(rb_center) zoom_factor = min(zoom_factor_x, zoom_factor_y) self.zoom_view(zoom_factor) self.centerOn(new_center) self.update_grid() if event.button() == Qt.MidButton: self.setCursor(Qt.ArrowCursor) self._mousePressed = None self.update_grid() def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.reset_view() if event.key() == Qt.Key_F1: self.set_alias_visibility(not self.aliases_visible) if event.key() == Qt.Key_F2: self.set_port_visibility(not self.ports_visible) if event.key() == Qt.Key_F3: self.set_subport_visibility(not self.subports_visible) if event.key() == Qt.Key_Question: help_str = """ Mouse control: Mousewheel: Zoom in and out Right-click & drag: Zoom to rectangle Middle-click & drag: Pan Keyboard shortcuts: Esc: Reset view F1: Show/hide alias names F2: Show/hide ports F3: Show/hide subports (ports in underlying references) """ msg = QMessageBox.about(self, 'PHIDL Help', help_str) msg.raise_()
class Dashboard(QGraphicsView): # Parameters WINDOW_WIDTH = 800 WINDOW_HEIGHT = 480 INACTIVE_COLOR = QColor('#252525') OK_COLOR = Qt.green WARNING_COLOR = Qt.yellow DANGEROUS_COLOR = Qt.red TACHOMETER_GEARS_ARROW_COLOR = Qt.white TACHOMETER_GEARS_NUMBER_COLOR = Qt.black GEAR_NUMBER_COLOR = Qt.white TACHOMETER_SCALING = 100 ACCELEROMETER_MIN_ANGEL = 10 ACCELEROMETER_MAX_ANGEL = 350 # Constructor def __init__(self, initMode: DriveMode) -> None: # Init values self.mode = initMode self.tachometerEngineRpm = 0 # 0 - 9000 self.tachometerEngineLevel = DashboardLevel.inactive self.tachometerGearboxRpm = 0 # 0 - 9000 self.tachometerGearboxLevel = DashboardLevel.inactive self.tachometerGear1Rpm = 0 # 0 - 9000 self.tachometerGear2Rpm = 0 # 0 - 9000 self.tachometerGear3Rpm = 0 # 0 - 9000 self.tachometerGear4Rpm = 0 # 0 - 9000 self.tachometerGear5Rpm = 0 # 0 - 9000 self.accelerometerAngel = 0 # -180 - +180 self.accelerometerValue = 0.0 # 0.0 - 1.0 self.accelerometerLevel = DashboardLevel.inactive self.steeringWheelEncoderAngel = 0 # -7 - +7 self.steeringWheelEncoderLevel = DashboardLevel.inactive self.turnLeftIndicatorLevel = DashboardLevel.inactive self.turnRightIndicatorLevel = DashboardLevel.inactive self.oilWarningIndicatorLevel = DashboardLevel.inactive self.watterWarningIndicatorLevel = DashboardLevel.inactive self.gearNumberValue = 0 # 0 - 5 self.speedometerValue = 0 # 0 - 999 self.speedometerLevel = DashboardLevel.inactive self.stopwatchMills = 0 # 0 - 99 self.stopwatchSeconds = 0 # 0 - 59 self.stopwatchMinutes = 0 # 0 - 59 self.stopwatchHours = 0 # 0 - 9 self.stopwatchLevel = DashboardLevel.inactive self.oilManometerValue = 0.0 # 0.0 - 9.99 self.oilManometerLevel = DashboardLevel.inactive self.oilThermometerValue = 0 # 0 - 999 self.oilThermometerLevel = DashboardLevel.inactive self.watterThermometerValue = 0 # 0 - 999 self.watterThermometerLevel = DashboardLevel.inactive self.odometerValue = 0 # 0 - 9999 self.odometerLevel = DashboardLevel.inactive # Init UI super(Dashboard, self).__init__() viewport = QOpenGLWidget() viewportFormat = QSurfaceFormat() viewportFormat.setSwapInterval(0) # disable VSync viewportFormat.setSamples(2**8) viewportFormat.setDefaultFormat(viewportFormat) viewport.setFormat(viewportFormat) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setGeometry(0, 0, self.WINDOW_WIDTH, self.WINDOW_HEIGHT) self.setStyleSheet("border: 0px") self.setWindowTitle("Dashboard") self.setWindowFlags(Qt.FramelessWindowHint) self.scene = QGraphicsScene(0, 0, self.WINDOW_WIDTH, self.WINDOW_HEIGHT) self.setScene(self.scene) self.setViewport(viewport) self.setInteractive(False) self.levelPens = { DashboardLevel.inactive: QPen(self.INACTIVE_COLOR, 1, Qt.SolidLine), DashboardLevel.ok: QPen(self.OK_COLOR, 1, Qt.SolidLine), DashboardLevel.warning: QPen(self.WARNING_COLOR, 1, Qt.SolidLine), DashboardLevel.dangerous: QPen(self.DANGEROUS_COLOR, 1, Qt.SolidLine) } self.levelBrushes = { DashboardLevel.inactive: QBrush(self.INACTIVE_COLOR, Qt.SolidPattern), DashboardLevel.ok: QBrush(self.OK_COLOR, Qt.SolidPattern), DashboardLevel.warning: QBrush(self.WARNING_COLOR, Qt.SolidPattern), DashboardLevel.dangerous: QBrush(self.DANGEROUS_COLOR, Qt.SolidPattern) } # Helpers dirPath = os.path.dirname(os.path.abspath(__file__)) inactivePen = self.levelPens[DashboardLevel.inactive] inactiveBrush = self.levelBrushes[DashboardLevel.inactive] def buildPolygonItem(origin: QPointF, polygon: List[QPointF]): return self.scene.addPolygon( QPolygonF([ QPointF(p.x() + origin.x(), p.y() + origin.y()) for p in polygon ]), inactivePen, inactiveBrush) def makeNumberItems(origin: QPointF, polygon: Dict[str, List[QPointF]]): return {k: buildPolygonItem(origin, p) for k, p in polygon.items()} # Add background self.backgroundPixmaps = { DriveMode.race: QPixmap(os.path.join(dirPath, "background_race.png")).scaled( self.WINDOW_WIDTH, self.WINDOW_HEIGHT), DriveMode.street: QPixmap(os.path.join(dirPath, "background_street.png")).scaled( self.WINDOW_WIDTH, self.WINDOW_HEIGHT) } logging.debug( f"[Dashboard.__init__] Loaded: backgroundPixmaps = {self.backgroundPixmaps}, initMode = {initMode}" ) self.backgroundItem = QGraphicsPixmapItem() self.backgroundItem.setZValue(-1) self.scene.addItem(self.backgroundItem) # Add tachometer graphics self.tachometerEngineItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.TACHOMETER_ENGINE.items()} self.tachometerGearboxItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.TACHOMETER_GEARBOX.items()} self.tachometerGearsPens = { "A": QPen(self.TACHOMETER_GEARS_ARROW_COLOR, 1, Qt.SolidLine), "N": QPen(self.TACHOMETER_GEARS_NUMBER_COLOR, 1, Qt.SolidLine) } self.tachometerGearsBrushes = { "A": QBrush(self.TACHOMETER_GEARS_ARROW_COLOR, Qt.SolidPattern), "N": QBrush(self.TACHOMETER_GEARS_NUMBER_COLOR, Qt.SolidPattern) } def makeGearsTransforms(translate: QPointF, rotate: int): arrowTrans = QTransform() arrowTrans.translate(translate.x(), translate.y()) arrowTrans.rotate(rotate) numberTrans = QTransform() numberTrans.translate(translate.x(), translate.y()) return arrowTrans, numberTrans self.tachometerGearsTransforms = \ {k: makeGearsTransforms(p[0], p[1]) for k, p in PolygonsMapping.TACHOMETER_GEARS["T"].items()} def tachometerGearsItem(gearNumber: int): (arrowTrans, numberTrans) = self.tachometerGearsTransforms[0] arrowItem = self.scene.addPolygon( PolygonsMapping.TACHOMETER_GEARS["A"], inactivePen, inactiveBrush) arrowItem.setTransform(arrowTrans) numberItem = buildPolygonItem( PolygonsMapping.TACHOMETER_GEARS["N"]["O"], PolygonsMapping.TACHOMETER_GEARS["N"]["P"][gearNumber]) numberItem.setTransform(numberTrans) return arrowItem, numberItem self.tachometerGearsItems = { 1: tachometerGearsItem(1), 2: tachometerGearsItem(2), 3: tachometerGearsItem(3), 4: tachometerGearsItem(4), 5: tachometerGearsItem(5) } # Add accelerometer graphics def makeEllipse(points: Tuple[QPointF, QPointF]): return self.scene.addEllipse(points[0].x(), points[0].y(), points[1].x() - points[0].x(), points[1].y() - points[0].y(), inactivePen, inactiveBrush) self.accelerometerCenterItem = makeEllipse( PolygonsMapping.ACCELEROMETER["C"]) self.accelerometerSectorItem = makeEllipse( PolygonsMapping.ACCELEROMETER["S"]) self.accelerometerSectorItem.setStartAngle( int((270 - (self.ACCELEROMETER_MIN_ANGEL / 2))) * 16) self.accelerometerSectorItem.setSpanAngle( self.ACCELEROMETER_MIN_ANGEL * 16) # Add steering wheel encoder graphics self.steeringWheelEncoderItems = \ {k: self.scene.addPolygon(p, inactivePen, inactiveBrush) for k, p in PolygonsMapping.STEERING_WHEEL_ENCODER.items()} # Add turn indicator graphics def makeTurnIndicatorItem(initCoordinates: Dict[str, Any]): return buildPolygonItem(initCoordinates["C"], initCoordinates["P"]) self.turnIndicatorLeftItem = makeTurnIndicatorItem( PolygonsMapping.TURN_INDICATOR["L"]) self.turnIndicatorRightItem = makeTurnIndicatorItem( PolygonsMapping.TURN_INDICATOR["R"]) # Add warning indicators graphics def makeWarningIndicatorItems(initCoordinates: Dict[str, Any]): return [ buildPolygonItem(initCoordinates["C"], p) for p in initCoordinates["P"] ] self.oilWarningIndicatorItems = makeWarningIndicatorItems( PolygonsMapping.WARNING_INDICATORS["OIL"]) self.watterWarningIndicatorItems = makeWarningIndicatorItems( PolygonsMapping.WARNING_INDICATORS["WATTER"]) # Add gear number graphics self.gearNumberPen = QPen(self.GEAR_NUMBER_COLOR, 1, Qt.SolidLine) self.gearNumberBrush = QBrush(self.GEAR_NUMBER_COLOR, Qt.SolidPattern) self.gearNumberItems = makeNumberItems( PolygonsMapping.GEAR_NUMBER["C"], PolygonsMapping.GEAR_NUMBER["P"]) # Add speedometer graphics self.speedometer001Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[1], PolygonsMapping.SPEED_NUMBERS) self.speedometer010Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[10], PolygonsMapping.SPEED_NUMBERS) self.speedometer100Items = makeNumberItems( PolygonsMapping.SPEEDOMETER[100], PolygonsMapping.SPEED_NUMBERS) # Add stopwatch graphics self.stopwatchMS01Items = makeNumberItems( PolygonsMapping.STOPWATCH["MS01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchMS10Items = makeNumberItems( PolygonsMapping.STOPWATCH["MS10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchS01Items = makeNumberItems( PolygonsMapping.STOPWATCH["S01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchS10Items = makeNumberItems( PolygonsMapping.STOPWATCH["S10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchM01Items = makeNumberItems( PolygonsMapping.STOPWATCH["M01"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchM10Items = makeNumberItems( PolygonsMapping.STOPWATCH["M10"], PolygonsMapping.STANDARD_NUMBERS) self.stopwatchH01Items = makeNumberItems( PolygonsMapping.STOPWATCH["H01"], PolygonsMapping.STANDARD_NUMBERS) # Add oil manometer graphics self.oilManometer0d01Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[0.01], PolygonsMapping.STANDARD_NUMBERS) self.oilManometer0d10Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[0.1], PolygonsMapping.STANDARD_NUMBERS) self.oilManometer1d00Items = makeNumberItems( PolygonsMapping.OIL_MANOMETER[1], PolygonsMapping.STANDARD_NUMBERS) # Add oil thermometer graphics self.oilThermometer001Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.oilThermometer010Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.oilThermometer100Items = makeNumberItems( PolygonsMapping.OIL_THERMOMETER[100], PolygonsMapping.STANDARD_NUMBERS) # Add watter thermometer graphics self.watterThermometer001Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.watterThermometer010Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.watterThermometer100Items = makeNumberItems( PolygonsMapping.WATTER_THERMOMETER[100], PolygonsMapping.STANDARD_NUMBERS) # Add odometer graphics self.watterOdometer0001Items = makeNumberItems( PolygonsMapping.ODOMETER[1], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer0010Items = makeNumberItems( PolygonsMapping.ODOMETER[10], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer0100Items = makeNumberItems( PolygonsMapping.ODOMETER[100], PolygonsMapping.STANDARD_NUMBERS) self.watterOdometer1000Items = makeNumberItems( PolygonsMapping.ODOMETER[1000], PolygonsMapping.STANDARD_NUMBERS) # Initial rendering self.renderBackground() self.renderTachometerScale(self.tachometerEngineItems, self.tachometerEngineRpm, self.tachometerEngineLevel) self.renderTachometerScale(self.tachometerGearboxItems, self.tachometerGearboxRpm, self.tachometerGearboxLevel) self.renderAccelerometer() self.renderSteeringWheelEncoder() self.renderTurnLeftIndicator() self.renderTurnRightIndicator() self.renderOilWarningIndicator() self.renderWatterWarningIndicator() self.renderGearNumber() self.renderSpeedometer() self.renderStopwatch() self.renderOilManometer() self.renderOilThermometer() self.renderWatterThermometer() self.renderOdometer() # Helpers def renderNumberHelper(self, number: int, items: Dict[str, QStandardItem], level: DashboardLevel) -> None: def setLevel(p: QStandardItem, l: DashboardLevel): p.setPen(self.levelPens[l]) p.setBrush(self.levelBrushes[l]) if level != DashboardLevel.inactive: for s in PolygonsMapping.NUMBER_TO_SEGMENTS[number][0]: setLevel(items[s], level) for s in PolygonsMapping.NUMBER_TO_SEGMENTS[number][1]: setLevel(items[s], DashboardLevel.inactive) else: for _, p in items.items(): setLevel(p, DashboardLevel.inactive) def renderTripleNumberHelper(self, value: int, items001: Dict[str, QStandardItem], items010: Dict[str, QStandardItem], items100: Dict[str, QStandardItem], level: DashboardLevel) -> None: v001 = value % 10 v010 = (value % 100) // 10 v100 = value // 100 self.renderNumberHelper(v001, items001, level) self.renderNumberHelper( v010, items010, level if v010 > 0 or v100 > 0 else DashboardLevel.inactive) self.renderNumberHelper(v100, items100, level if v100 > 0 else DashboardLevel.inactive) # Rendering def renderBackground(self) -> None: logging.debug(f"[Dashboard.renderBackground] For mode = {self.mode}") # Render background pixmap self.backgroundItem.setPixmap(self.backgroundPixmaps[self.mode]) # Re-render all indicators self.renderTachometerScale(self.tachometerEngineItems, self.tachometerEngineRpm, self.tachometerEngineLevel) self.renderTachometerScale(self.tachometerGearboxItems, self.tachometerGearboxRpm, self.tachometerGearboxLevel) self.renderTachometerGear(1, self.tachometerGear1Rpm) self.renderTachometerGear(2, self.tachometerGear2Rpm) self.renderTachometerGear(3, self.tachometerGear3Rpm) self.renderTachometerGear(4, self.tachometerGear4Rpm) self.renderTachometerGear(5, self.tachometerGear5Rpm) self.renderAccelerometer() self.renderSteeringWheelEncoder() self.renderTurnLeftIndicator() self.renderTurnRightIndicator() self.renderOilWarningIndicator() self.renderWatterWarningIndicator() self.renderGearNumber() self.renderSpeedometer() self.renderStopwatch() self.renderOilManometer() self.renderOilThermometer() self.renderWatterThermometer() self.renderOdometer() def renderTachometerScale(self, items: Dict[int, QStandardItem], rpm: int, level: DashboardLevel) -> None: segment = round(rpm / self.TACHOMETER_SCALING) for k, p in items.items(): if k <= segment: p.setPen(self.levelPens[level]) p.setBrush(self.levelBrushes[level]) else: p.setPen(self.levelPens[DashboardLevel.inactive]) p.setBrush(self.levelBrushes[DashboardLevel.inactive]) def renderTachometerGear(self, gearNumber: int, rpm: int) -> None: (arrowItem, numberItem) = self.tachometerGearsItems[gearNumber] segment = ((rpm if rpm <= 8600 else 8600) // 200) * 2 (arrowTrans, numberTrans) = self.tachometerGearsTransforms[segment] arrowItem.setTransform(arrowTrans) arrowItem.setPen(self.tachometerGearsPens["A"]) arrowItem.setBrush(self.tachometerGearsBrushes["A"]) numberItem.setTransform(numberTrans) numberItem.setPen(self.tachometerGearsPens["N"]) numberItem.setBrush(self.tachometerGearsBrushes["N"]) def renderAccelerometer(self) -> None: newPen = self.levelPens[self.accelerometerLevel] newBrush = self.levelBrushes[self.accelerometerLevel] self.accelerometerCenterItem.setPen(newPen) self.accelerometerCenterItem.setBrush(newBrush) self.accelerometerSectorItem.setPen(newPen) self.accelerometerSectorItem.setBrush(newBrush) span = ((self.ACCELEROMETER_MAX_ANGEL - self.ACCELEROMETER_MIN_ANGEL) * self.accelerometerValue)\ + self.ACCELEROMETER_MIN_ANGEL startAngel = self.accelerometerAngel - (span / 2) correctedAngel = ((startAngel - 90) if startAngel >= 90 else (270 + startAngel)) self.accelerometerSectorItem.setStartAngle(int(correctedAngel) * 16) self.accelerometerSectorItem.setSpanAngle(int(span) * 16) def renderSteeringWheelEncoder(self) -> None: angel = self.steeringWheelEncoderAngel for k, p in self.steeringWheelEncoderItems.items(): if (angel == 0 and k == 0) or (abs(k) <= abs(angel) and k != 0 and (k * angel) > 0): p.setPen(self.levelPens[self.steeringWheelEncoderLevel]) p.setBrush(self.levelBrushes[self.steeringWheelEncoderLevel]) else: p.setPen(self.levelPens[DashboardLevel.inactive]) p.setBrush(self.levelBrushes[DashboardLevel.inactive]) def renderTurnLeftIndicator(self) -> None: self.turnIndicatorLeftItem.setPen( self.levelPens[self.turnLeftIndicatorLevel]) self.turnIndicatorLeftItem.setBrush( self.levelBrushes[self.turnLeftIndicatorLevel]) def renderTurnRightIndicator(self) -> None: self.turnIndicatorRightItem.setPen( self.levelPens[self.turnRightIndicatorLevel]) self.turnIndicatorRightItem.setBrush( self.levelBrushes[self.turnRightIndicatorLevel]) def renderOilWarningIndicator(self) -> None: for p in self.oilWarningIndicatorItems: p.setPen(self.levelPens[self.oilWarningIndicatorLevel]) p.setBrush(self.levelBrushes[self.oilWarningIndicatorLevel]) def renderWatterWarningIndicator(self) -> None: for p in self.watterWarningIndicatorItems: p.setPen(self.levelPens[self.watterWarningIndicatorLevel]) p.setBrush(self.levelBrushes[self.watterWarningIndicatorLevel]) def renderGearNumber(self) -> None: for s in PolygonsMapping.GEAR_NUMBER["M"][self.gearNumberValue][0]: segment = self.gearNumberItems[s] segment.setPen(self.gearNumberPen) segment.setBrush(self.gearNumberBrush) for s in PolygonsMapping.GEAR_NUMBER["M"][self.gearNumberValue][1]: segment = self.gearNumberItems[s] segment.setPen(self.levelPens[DashboardLevel.inactive]) segment.setBrush(self.levelBrushes[DashboardLevel.inactive]) def renderSpeedometer(self) -> None: self.renderTripleNumberHelper(self.speedometerValue, self.speedometer001Items, self.speedometer010Items, self.speedometer100Items, self.speedometerLevel) def renderStopwatch(self) -> None: self.renderNumberHelper(self.stopwatchMills % 10, self.stopwatchMS01Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchMills // 10, self.stopwatchMS10Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchSeconds % 10, self.stopwatchS01Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchSeconds // 10, self.stopwatchS10Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchMinutes % 10, self.stopwatchM01Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchMinutes // 10, self.stopwatchM10Items, self.stopwatchLevel) self.renderNumberHelper(self.stopwatchHours, self.stopwatchH01Items, self.stopwatchLevel) def renderOilManometer(self) -> None: intValue = int(self.oilManometerValue * 100) self.renderNumberHelper(intValue % 10, self.oilManometer0d01Items, self.oilManometerLevel) self.renderNumberHelper((intValue % 100) // 10, self.oilManometer0d10Items, self.oilManometerLevel) self.renderNumberHelper(intValue // 100, self.oilManometer1d00Items, self.oilManometerLevel) def renderOilThermometer(self) -> None: self.renderTripleNumberHelper(self.oilThermometerValue, self.oilThermometer001Items, self.oilThermometer010Items, self.oilThermometer100Items, self.oilThermometerLevel) def renderWatterThermometer(self) -> None: self.renderTripleNumberHelper(self.watterThermometerValue, self.watterThermometer001Items, self.watterThermometer010Items, self.watterThermometer100Items, self.watterThermometerLevel) def renderOdometer(self) -> None: v0001 = (self.odometerValue % 10) v0010 = (self.odometerValue % 100) // 10 v0100 = (self.odometerValue % 1000) // 100 v1000 = self.odometerValue // 1000 def level(isActive: bool): return self.odometerLevel if isActive > 0 else DashboardLevel.inactive self.renderNumberHelper(v0001, self.watterOdometer0001Items, self.odometerLevel) self.renderNumberHelper(v0010, self.watterOdometer0010Items, level(v0010 > 0 or v0100 > 0 or v1000 > 0)) self.renderNumberHelper(v0100, self.watterOdometer0100Items, level(v0100 > 0 or v1000 > 0)) self.renderNumberHelper(v1000, self.watterOdometer1000Items, level(v1000 > 0)) # Methods @pyqtSlot(DriveMode) def inMode(self, mode: DriveMode) -> None: logging.debug(f"[Dashboard.inMode] New mode = {mode}") # Store new state self.mode = mode # Redraw UI self.renderBackground() @pyqtSlot(int, DashboardLevel) def inTachometerEngine(self, rpm: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inTachometerEngine] New rpm = {rpm}, level = {level}") # Store new state self.tachometerEngineRpm = 0 if rpm < 0 else ( 9000 if rpm > 9000 else rpm) self.tachometerEngineLevel = level # Redraw UI self.renderTachometerScale(self.tachometerEngineItems, self.tachometerEngineRpm, self.tachometerEngineLevel) @pyqtSlot(int, DashboardLevel) def inTachometerGearbox(self, rpm: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inTachometerGearbox] New rpm = {rpm}, level = {level}" ) # Store new state self.tachometerGearboxRpm = 0 if rpm < 0 else ( 9000 if rpm > 9000 else rpm) self.tachometerGearboxLevel = level # Redraw UI self.renderTachometerScale(self.tachometerGearboxItems, self.tachometerGearboxRpm, self.tachometerGearboxLevel) @pyqtSlot(int, int, int, int, int) def inTachometerGears(self, rpm1: int, rpm2: int, rpm3: int, rpm4: int, rpm5: int) -> None: logging.debug( f"[Dashboard.inTachometerGears] New rpm1 = {rpm1}, rpm2 = {rpm2}, rpm3 = {rpm3}, " f"rpm4 = {rpm4}, rpm5 = {rpm5}") # Store new state self.tachometerGear1Rpm = 0 if rpm1 < 0 else ( 9000 if rpm1 > 9000 else rpm1) self.tachometerGear2Rpm = 0 if rpm2 < 0 else ( 9000 if rpm2 > 9000 else rpm2) self.tachometerGear3Rpm = 0 if rpm3 < 0 else ( 9000 if rpm3 > 9000 else rpm3) self.tachometerGear4Rpm = 0 if rpm4 < 0 else ( 9000 if rpm4 > 9000 else rpm4) self.tachometerGear5Rpm = 0 if rpm5 < 0 else ( 9000 if rpm5 > 9000 else rpm5) # Redraw UI self.renderTachometerGear(1, self.tachometerGear1Rpm) self.renderTachometerGear(2, self.tachometerGear2Rpm) self.renderTachometerGear(3, self.tachometerGear3Rpm) self.renderTachometerGear(4, self.tachometerGear4Rpm) self.renderTachometerGear(5, self.tachometerGear5Rpm) @pyqtSlot(int, float, DashboardLevel) def inAccelerometer(self, angel: int, value: float, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inAccelerometer] New angel = {angel}, value = {value}, level = {level}" ) # Store new state self.accelerometerAngel = -180 if angel < -180 else ( 180 if angel > 180 else angel) self.accelerometerValue = 0.0 if value < 0.0 else ( 1.0 if value > 1.0 else value) self.accelerometerLevel = level # Redraw UI self.renderAccelerometer() @pyqtSlot(int, DashboardLevel) def inSteeringWheelEncoder(self, angel: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inSteeringWheelEncoder] New angel = {angel}, level = {level}" ) # Store new state self.steeringWheelEncoderAngel = -7 if angel < -7 else ( 7 if angel > 7 else angel) self.steeringWheelEncoderLevel = level # Redraw UI self.renderSteeringWheelEncoder() @pyqtSlot(DashboardLevel) def inTurnLeftIndicator(self, level: DashboardLevel) -> None: logging.debug(f"[Dashboard.inTurnLeftIndicator] New level = {level}") # Store new state self.turnLeftIndicatorLevel = level # Redraw UI self.renderTurnLeftIndicator() @pyqtSlot(DashboardLevel) def inTurnRightIndicator(self, level: DashboardLevel) -> None: logging.debug(f"[Dashboard.inTurnRightIndicator] New level = {level}") # Store new state self.turnRightIndicatorLevel = level # Redraw UI self.renderTurnRightIndicator() @pyqtSlot(int) def inGearNumber(self, value: int) -> None: logging.debug(f"[Dashboard.inGearNumber] New value = {value}") # Store new state self.gearNumberValue = 0 if value < 0 else (5 if value > 5 else value) # Redraw UI self.renderGearNumber() @pyqtSlot(DashboardLevel) def inOilWarningIndicator(self, level: DashboardLevel) -> None: logging.debug(f"[Dashboard.inOilWarningIndicator] New level = {level}") # Store new state self.oilWarningIndicatorLevel = level # Redraw UI self.renderOilWarningIndicator() @pyqtSlot(DashboardLevel) def inWatterWarningIndicator(self, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inWatterWarningIndicator] New level = {level}") # Store new state self.watterWarningIndicatorLevel = level # Redraw UI self.renderWatterWarningIndicator() @pyqtSlot(int, DashboardLevel) def inSpeedometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inSpeedometer] New value = {value}, level = {level}") # Store new state self.speedometerValue = 0 if value < 0 else ( 999 if value > 999 else value) self.speedometerLevel = level # Redraw UI self.renderSpeedometer() @pyqtSlot(int, int, int, int, DashboardLevel) def inStopwatch(self, mills: int, seconds: int, minutes: int, hours: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inStopwatch] New mills = {mills}, seconds = {seconds}, minutes = {minutes}, " f"hours = {hours}, level = {level}") # Store new state self.stopwatchMills = 0 if mills < 0 else (99 if mills > 99 else mills) self.stopwatchSeconds = 0 if seconds < 0 else ( 59 if seconds > 59 else seconds) self.stopwatchMinutes = 0 if minutes < 0 else ( 59 if minutes > 59 else minutes) self.stopwatchHours = 0 if hours < 0 else (9 if hours > 9 else hours) self.stopwatchLevel = level # Redraw UI self.renderStopwatch() @pyqtSlot(float, DashboardLevel) def inOilManometer(self, value: float, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inOilManometer] New value = {value}, level = {level}") # Store new state self.oilManometerValue = 0.0 if value < 0.0 else ( 9.99 if value > 9.99 else value) self.oilManometerLevel = level # Redraw UI self.renderOilManometer() @pyqtSlot(int, DashboardLevel) def inOilThermometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inOilThermometer] New value = {value}, level = {level}" ) # Store new state self.oilThermometerValue = 0 if value < 0 else ( 999 if value > 999 else value) self.oilThermometerLevel = level # Redraw UI self.renderOilThermometer() @pyqtSlot(int, DashboardLevel) def inWatterThermometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inWatterThermometer] New value = {value}, level = {level}" ) # Store new state self.watterThermometerValue = 0 if value < 0 else ( 999 if value > 999 else value) self.watterThermometerLevel = level # Redraw UI self.renderWatterThermometer() @pyqtSlot(int, DashboardLevel) def inOdometer(self, value: int, level: DashboardLevel) -> None: logging.debug( f"[Dashboard.inOdometer] New value = {value}, level = {level}") # Store new state self.odometerValue = 0 if value < 0 else ( 9999 if value > 9999 else value) self.odometerLevel = level # Redraw UI self.renderOdometer()
class KineticsWidget(EditorWidgetBase): def __init__(self, *args): EditorWidgetBase.__init__(self, *args) self.setAcceptDrops(True) self.border = 10 self.sceneContainer = QGraphicsScene(self) self.sceneContainer.setSceneRect( self.sceneContainer.itemsBoundingRect()) self.sceneContainer.setBackgroundBrush(QtGui.QColor( 230, 220, 219, 120)) self.insertMenu = QMenu('&Insert') self._menus.append(self.insertMenu) self.insertMapper = QtCore.QSignalMapper(self) classlist = [ 'CubeMesh', 'CylMesh', 'Pool', 'Reac', 'Enz', 'MMenz', 'StimulusTable', 'Table' ] insertMapper, actions = self.getInsertActions(classlist) for action in actions: self.insertMenu.addAction(action) def getToolBars(self): if not hasattr(self, '_insertToolBar'): self._insertToolBar = QtGui.QToolBar('Insert') self._toolBars.append(self._insertToolBar) for action in self.insertMenu.actions(): button = MToolButton() button.setDefaultAction(action) self._insertToolBar.addWidget(button) return self._toolBars def sizeHint(self): return QtCore.QSize(800, 400) def updateModelView(self): #print "update model view",self.modelRoot if self.modelRoot == '/': m = moose.wildcardFind('/##[ISA=ChemCompt]') else: m = moose.wildcardFind(self.modelRoot + '/##[ISA=ChemCompt]') #print "111",self.modelRoot,m if not m: # when we want an empty GraphicView while creating new model, # then remove all the view and add an empty view if hasattr(self, 'view') and isinstance(self.view, QWidget): self.layout().removeWidget(self.view) self.view = GraphicalView(self.sceneContainer, self.border, self) self.layout().addWidget(self.view) else: # maxmium and minimum coordinates of the objects specified in kkit file. self.xmin = 0.0 self.xmax = 1.0 self.ymin = 0.0 self.ymax = 1.0 self.autoCordinatepos = {} self.sceneContainer.clear() # TODO: size will be dummy at this point, but I need the availiable size from the Gui self.size = QtCore.QSize(1024, 768) #self.size = QtCore.QSize(300,400) self.autocoordinates = False # pickled the color map file """ colormap_file = open( os.path.join(config.settings[config.KEY_COLORMAP_DIR], 'rainbow2.pkl'), 'rb') self.colorMap = pickle.load(colormap_file) colormap_file.close() # Compartment and its members are setup """ o, self.meshEntry, self.xmin, self.xmax, self.ymin, \ self.ymax, self.noPositionInfo = kkitOrdinateUtil.setupMeshObj(self.modelRoot) self.srcdesConnection = {} kkitOrdinateUtil.setupItem(self.modelRoot, self.srcdesConnection) if self.noPositionInfo: self.autocoordinates = True QMessageBox.warning(self, 'No coordinates found for the model', '\n Automatic layouting will be done') kkitOrdinateUtil.autoCoordinates(self.meshEntry, self.srcdesConnection) # Scale factor to translate the x -y position to fit the Qt graphicalScene, scene width. """ if self.xmax - self.xmin != 0: self.xratio = (self.size.width() - 10) / (self.xmax - self.xmin) else: self.xratio = self.size.width() - 10 if self.ymax - self.ymin: self.yratio = (self.size.height() - 10) / (self.ymax - self.ymin) else: self.yratio = (self.size.height() - 10) #A map b/w moose compartment key with QGraphicsObject self.qGraCompt = {} #A map between mooseId of all the mooseObject (except compartment) with QGraphicsObject self.mooseId_GObj = {} self.border = 5 self.arrowsize = 2 self.iconScale = 1 self.defaultComptsize = 5 self.itemignoreZooming = False self.lineItem_dict = {} self.object2line = defaultdict(list) # Compartment and its members are put on the qgraphicsscene self.mooseObjOntoscene() # All the moose Object are connected for visualization self.drawLine_arrow(itemignoreZooming=False) if hasattr(self, 'view') and isinstance(self.view, QWidget): self.layout().removeWidget(self.view) self.view = GraphicalView(self.sceneContainer, self.border, self) hLayout = QtGui.QGridLayout(self) self.setLayout(hLayout) hLayout.addWidget(self.view) #self.layout().addWidget(self.view) def mooseObjOntoscene(self): # All the compartments are put first on to the scene \ # Need to do: Check With upi if empty compartments exist for cmpt in sorted(self.meshEntry.keys()): self.createCompt(cmpt) self.qGraCompt[cmpt] for cmpt, memb in list(self.meshEntry.items()): for enzObj in memb.get('enzyme', []): enzinfo = enzObj.path + '/info' if enzObj.className == 'ZEnz': enzItem = EnzItem(enzObj, self.qGraCompt[cmpt]) else: enzItem = MMEnzItem(enzObj, self.qGraCompt[cmpt]) self.setupDisplay(enzinfo, enzItem, "enzyme") self.setupSlot(enzObj, enzItem) for cmpt, memb in list(self.meshEntry.items()): for poolObj in kkitOrdinateUtil.find_index(memb, 'pool'): poolinfo = poolObj.path + '/info' poolItem = PoolItem(poolObj, self.qGraCompt[cmpt]) self.setupDisplay(poolinfo, poolItem, "pool") self.setupSlot(poolObj, poolItem) for cplxObj in kkitOrdinateUtil.find_index(memb, 'cplx'): cplxinfo = (cplxObj[0].parent).path + '/info' cplxItem = CplxItem( cplxObj, self.mooseId_GObj[element(cplxObj[0]).parent.getId()]) self.setupDisplay(cplxinfo, cplxItem, "cplx") self.setupSlot(cplxObj, cplxItem) for reaObj in kkitOrdinateUtil.find_index(memb, 'reaction'): reainfo = reaObj.path + '/info' reaItem = ReacItem(reaObj, self.qGraCompt[cmpt]) self.setupDisplay(reainfo, reaItem, "reaction") self.setupSlot(reaObj, reaItem) for tabObj in kkitOrdinateUtil.find_index(memb, 'table'): tabinfo = tabObj.path + '/info' tabItem = PoolItem(tabObj, self.qGraCompt[cmpt]) self.setupDisplay(tabinfo, tabItem, "tab") self.setupSlot(tabObj, tabItem) # compartment's rectangle size is calculated depending on children for k, v in list(self.qGraCompt.items()): rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20)) v.setPen( QtGui.QPen(Qt.QColor(66, 66, 66, 100), 5, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin)) v.cmptEmitter.connect( v.cmptEmitter, QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"), self.positionChange) v.cmptEmitter.connect( v.cmptEmitter, QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"), self.objectEditSlot) def createCompt(self, key): self.new_Compt = ComptItem(self, 0, 0, 0, 0, key) self.qGraCompt[key] = self.new_Compt self.new_Compt.setRect(10, 10, 10, 10) self.sceneContainer.addItem(self.new_Compt) def setupDisplay(self, info, graphicalObj, objClass): xpos, ypos = self.positioninfo(info) # For Reaction and Complex object I have skipped the process to get the facecolor and background color as \ # we are not using these colors for displaying the object so just passing dummy color white if ((objClass == "reaction") or (objClass == "cplx")): textcolor, bgcolor = "white", "white" elif objClass == "tab": textcolor, bgcolor = getColor(info, self.colorMap) else: textcolor, bgcolor = getColor(info, self.colorMap) graphicalObj.setDisplayProperties(xpos, ypos, textcolor, bgcolor) def positioninfo(self, iteminfo): if self.noPositionInfo: try: # kkit does exist item's/info which up querying for parent.path gives the information of item's parent x, y = self.autoCordinatepos[(element(iteminfo).parent).path] except: # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\ # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\ # type of the object (rea,pool,enz,cplx,tab) which I have already done. parent, child = posixpath.split(iteminfo) x, y = self.autoCordinatepos[parent] ypos = (y - self.ymin) * self.yratio else: x = float(element(iteminfo).getField('x')) y = float(element(iteminfo).getField('y')) #Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \ #as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated ypos = -(y - self.ymin) * self.yratio xpos = (x - self.xmin) * self.xratio return (xpos, ypos) def setupSlot(self, mooseObj, qgraphicItem): self.mooseId_GObj[element(mooseObj).getId()] = qgraphicItem qgraphicItem.connect( qgraphicItem, QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"), self.positionChange) qgraphicItem.connect( qgraphicItem, QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"), self.objectEditSlot) def updateItemSlot(self, mooseObject): #This is overridden by derived classes to connect appropriate #slot for updating the display item. #In this case if the name is updated from the keyboard both in mooseobj and gui gets updation changedItem = '' for item in list(self.sceneContainer.items()): if isinstance(item, PoolItem): if mooseObject.getId() == element(item.mobj).getId(): item.updateSlot() #once the text is edited in editor, laydisplay gets updated in turn resize the length, positionChanged signal shd be emitted self.positionChange(mooseObject) def positionChange(self, mooseObject): #If the item position changes, the corresponding arrow's are calculated if isinstance(element(mooseObject), CubeMesh): for k, v in list(self.qGraCompt.items()): mesh = mooseObject.path + '/mesh[0]' if k.path == mesh: for rectChilditem in v.childItems(): self.updateArrow(rectChilditem) else: mobj = self.mooseId_GObj[mooseObject.getId()] self.updateArrow(mobj) for k, v in list(self.qGraCompt.items()): rectcompt = v.childrenBoundingRect() v.setRect(rectcompt.x() - 10, rectcompt.y() - 10, (rectcompt.width() + 20), (rectcompt.height() + 20)) def emitItemtoEditor(self, mooseObject): #self.emit(QtCore.SIGNAL("itemPressed(PyQt_PyObject)"),mooseObject) self.editObject.emit(mooseObject.path) def drawLine_arrow(self, itemignoreZooming=False): for inn, out in list(self.srcdesConnection.items()): # self.srcdesConnection is dictionary which contains key,value \ # key is Enzyme or Reaction and value [[list of substrate],[list of product]] (tuple) # key is FuncBase and value is [list of pool] (list) #src = self.mooseId_GObj[inn] if isinstance(out, tuple): if len(out[0]) == 0: print(inn.className + ':' + inn[0].name + " doesn't output message") else: src = self.mooseId_GObj[inn] for items in (items for items in out[0]): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src, des, items, itemignoreZooming) if len(out[1]) == 0: print(inn.className + ':' + inn[0].name + " doesn't output message") else: for items in (items for items in out[1]): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src, des, items, itemignoreZooming) elif isinstance(out, list): if len(out) == 0: print("Func pool doesn't have sumtotal") else: src = self.mooseId_GObj[element(inn).getId()] for items in (items for items in out): des = self.mooseId_GObj[element(items[0]).getId()] self.lineCord(src, des, items, itemignoreZooming) def lineCord(self, src, des, type_no, itemignoreZooming): endtype = type_no[1] line = 0 if (src == "") and (des == ""): print("Source or destination is missing or incorrect") return srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) while (type_no[2] > 1 and line <= (type_no[2] - 1)): srcdes_list = [src, des, endtype, line] arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale) self.drawLine(srcdes_list, arrow) line = line + 1 if type_no[2] > 5: print("Higher order reaction will not be displayed") def drawLine(self, srcdes_list, arrow): src = srcdes_list[0] des = srcdes_list[1] endtype = srcdes_list[2] line = srcdes_list[3] source = element( next((k for k, v in list(self.mooseId_GObj.items()) if v == src), None)) for l, v, o in self.object2line[src]: if v == des and o == line: l.setPolygon(arrow) arrowPen = l.pen() arrowPenWidth = self.arrowsize * self.iconScale arrowPen.setColor(l.pen().color()) arrowPen.setWidth(arrowPenWidth) l.setPen(arrowPen) return qgLineitem = self.sceneContainer.addPolygon(arrow) pen = QtGui.QPen(QtCore.Qt.green, 0, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin) pen.setWidth(self.arrowsize) #pen.setCosmetic(True) # Green is default color moose.ReacBase and derivatives - already set above if isinstance(source, EnzBase): if ((endtype == 's') or (endtype == 'p')): pen.setColor(QtCore.Qt.red) elif (endtype != 'cplx'): p1 = (next( (k for k, v in list(self.mooseId_GObj.items()) if v == src), None)) pinfo = p1.path + '/info' color, bgcolor = getColor(pinfo, self.colorMap) pen.setColor(color) elif isinstance(source, moose.PoolBase): pen.setColor(QtCore.Qt.blue) elif isinstance(source, moose.StimulusTable): pen.setColor(QtCore.Qt.yellow) self.lineItem_dict[qgLineitem] = srcdes_list self.object2line[src].append((qgLineitem, des, line)) self.object2line[des].append((qgLineitem, src, line)) qgLineitem.setPen(pen) def updateArrow(self, qGTextitem): #if there is no arrow to update then return if qGTextitem not in self.object2line: return listItem = self.object2line[qGTextitem] for ql, va, order in self.object2line[qGTextitem]: srcdes = [] srcdes = self.lineItem_dict[ql] # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz, # if yes then need to check if cplx is connected to any mooseObject, # so that when Enzyme is moved, cplx connected arrow to other mooseObject(poolItem) should also be updated if (type(srcdes[0]) == EnzItem): self.cplxUpdatearrow(srcdes[0]) elif (type(srcdes[1]) == EnzItem): self.cplxUpdatearrow(srcdes[1]) # For calcArrow(src,des,endtype,itemignoreZooming) is to be provided arrow = calcArrow(srcdes, self.itemignoreZooming, self.iconScale) ql.setPolygon(arrow) def cplxUpdatearrow(self, srcdes): # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz) #And cplxItem is passed for updatearrow #Note: Here at this point enzItem has just one child which is cplxItem and childItems returns, PyQt5.QtGui.QGraphicsEllipseItem,CplxItem #Assuming CplxItem is always[1], but still check if not[0], if something changes in structure one need to keep an eye. if (srcdes.childItems()[1], CplxItem): self.updateArrow(srcdes.childItems()[1]) else: self.updateArrow(srcdes.childItems()[0]) def keyPressEvent(self, event): # key1 = event.key() # key event does not distinguish between capital and non-capital letters key = event.text().toAscii().toHex() if key == '41': # 'A' fits the view to iconScale factor itemignoreZooming = False self.updateItemTransformationMode(itemignoreZooming) self.view.fitInView( self.sceneContainer.itemsBoundingRect().x() - 10, self.sceneContainer.itemsBoundingRect().y() - 10, self.sceneContainer.itemsBoundingRect().width() + 20, self.sceneContainer.itemsBoundingRect().height() + 20, Qt.Qt.IgnoreAspectRatio) self.drawLine_arrow(itemignoreZooming=False) elif (key == '2e'): # '.' key, lower case for '>' zooms in self.view.scale(1.1, 1.1) elif (key == '2c'): # ',' key, lower case for '<' zooms in self.view.scale(1 / 1.1, 1 / 1.1) elif (key == '3c'): # '<' key. zooms-in to iconScale factor self.iconScale *= 0.8 self.updateScale(self.iconScale) elif (key == '3e'): # '>' key. zooms-out to iconScale factor self.iconScale *= 1.25 self.updateScale(self.iconScale) elif (key == '61' ): # 'a' fits the view to initial value where iconscale=1 self.iconScale = 1 self.updateScale(self.iconScale) self.view.fitInView( self.sceneContainer.itemsBoundingRect().x() - 10, self.sceneContainer.itemsBoundingRect().y() - 10, self.sceneContainer.itemsBoundingRect().width() + 20, self.sceneContainer.itemsBoundingRect().height() + 20, Qt.Qt.IgnoreAspectRatio) def updateItemTransformationMode(self, on): for v in list(self.sceneContainer.items()): if (not isinstance(v, ComptItem)): #if ( isinstance(v, PoolItem) or isinstance(v, ReacItem) or isinstance(v, EnzItem) or isinstance(v, CplxItem) ): if isinstance(v, KineticsDisplayItem): v.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations, on) def updateScale(self, scale): for item in list(self.sceneContainer.items()): if isinstance(item, KineticsDisplayItem): item.refresh(scale) #iteminfo = item.mobj.path+'/info' #xpos,ypos = self.positioninfo(iteminfo) xpos = item.scenePos().x() ypos = item.scenePos().y() if isinstance(item, ReacItem) or isinstance( item, EnzItem) or isinstance(item, MMEnzItem): item.setGeometry(xpos, ypos, item.gobj.boundingRect().width(), item.gobj.boundingRect().height()) elif isinstance(item, CplxItem): item.setGeometry(item.gobj.boundingRect().width() / 2, item.gobj.boundingRect().height(), item.gobj.boundingRect().width(), item.gobj.boundingRect().height()) elif isinstance(item, PoolItem): item.setGeometry( xpos, ypos, item.gobj.boundingRect().width() + PoolItem.fontMetrics.width(' '), item.gobj.boundingRect().height()) item.bg.setRect( 0, 0, item.gobj.boundingRect().width() + PoolItem.fontMetrics.width(' '), item.gobj.boundingRect().height()) self.drawLine_arrow(itemignoreZooming=False) for k, v in list(self.qGraCompt.items()): rectcompt = v.childrenBoundingRect() comptPen = v.pen() comptWidth = self.defaultComptsize * self.iconScale comptPen.setWidth(comptWidth) v.setPen(comptPen) v.setRect(rectcompt.x() - comptWidth, rectcompt.y() - comptWidth, (rectcompt.width() + 2 * comptWidth), (rectcompt.height() + 2 * comptWidth))
class Screenshot(QGraphicsView): """ Main Class """ screen_shot_grabed = pyqtSignal(QImage) widget_closed = pyqtSignal() def __init__(self, flags=constant.DEFAULT, parent=None): """ flags: binary flags. see the flags in the constant.py """ super().__init__(parent) # Init self.penColorNow = QColor(PENCOLOR) self.penSizeNow = PENSIZE self.fontNow = QFont('Sans') self.clipboard = QApplication.clipboard() self.drawListResult = [ ] # draw list that sure to be drew, [action, coord] self.drawListProcess = None # the process to the result self.selectedArea = QRect( ) # a QRect instance which stands for the selected area self.selectedAreaRaw = QRect() self.mousePosition = MousePosition.OUTSIDE_AREA # mouse position self.screenPixel = None self.textRect = None self.mousePressed = False self.action = ACTION_SELECT self.mousePoint = self.cursor().pos() self.startX, self.startY = 0, 0 # the point where you start self.endX, self.endY = 0, 0 # the point where you end self.pointPath = QPainterPath( ) # the point mouse passes, used by draw free line self.itemsToRemove = [ ] # the items that should not draw on screenshot picture self.textPosition = None # result self.target_img = None # Init window self.getscreenshot() self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint) self.setMouseTracking(True) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setContentsMargins(0, 0, 0, 0) self.setStyleSheet("QGraphicsView { border-style: none; }") self.tooBar = MyToolBar(flags, self) self.tooBar.trigger.connect(self.changeAction) self.penSetBar = None if flags & constant.RECT or flags & constant.ELLIPSE or flags & constant.LINE or flags & constant.FREEPEN \ or flags & constant.ARROW or flags & constant.TEXT: self.penSetBar = PenSetWidget(self) self.penSetBar.penSizeTrigger.connect(self.changePenSize) self.penSetBar.penColorTrigger.connect(self.changePenColor) self.penSetBar.fontChangeTrigger.connect(self.changeFont) self.textInput = TextInput(self) self.textInput.inputChanged.connect(self.textChange) self.textInput.cancelPressed.connect(self.cancelInput) self.textInput.okPressed.connect(self.okInput) self.graphicsScene = QGraphicsScene(0, 0, self.screenPixel.width(), self.screenPixel.height()) self.show() self.setScene(self.graphicsScene) self.windowHandle().setScreen(QGuiApplication.screenAt(QCursor.pos())) self.scale = self.get_scale() # self.setFixedSize(self.screenPixel.width(), self.screenPixel.height()) self.setGeometry(QGuiApplication.screenAt(QCursor.pos()).geometry()) self.showFullScreen() self.redraw() QShortcut(QKeySequence('ctrl+s'), self).activated.connect(self.saveScreenshot) QShortcut(QKeySequence('esc'), self).activated.connect(self.close) @staticmethod def take_screenshot(flags): loop = QEventLoop() screen_shot = Screenshot(flags) screen_shot.show() screen_shot.widget_closed.connect(loop.quit) loop.exec() img = screen_shot.target_img return img def getscreenshot(self): screen = QGuiApplication.screenAt(QCursor.pos()) self.screenPixel = screen.grabWindow(0) def mousePressEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if event.button() != Qt.LeftButton: return if self.action is None: self.action = ACTION_SELECT self.startX, self.startY = event.x(), event.y() if self.action == ACTION_SELECT: if self.mousePosition == MousePosition.OUTSIDE_AREA: self.mousePressed = True self.selectedArea = QRect() self.selectedArea.setTopLeft(QPoint(event.x(), event.y())) self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.redraw() elif self.mousePosition == MousePosition.INSIDE_AREA: self.mousePressed = True else: pass elif self.action == ACTION_MOVE_SELECTED: if self.mousePosition == MousePosition.OUTSIDE_AREA: self.action = ACTION_SELECT self.selectedArea = QRect() self.selectedArea.setTopLeft(QPoint(event.x(), event.y())) self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.redraw() self.mousePressed = True elif self.action in DRAW_ACTION: self.mousePressed = True if self.action == ACTION_FREEPEN: self.pointPath = QPainterPath() self.pointPath.moveTo(QPoint(event.x(), event.y())) elif self.action == ACTION_TEXT: if self.textPosition is None: self.textPosition = QPoint(event.x(), event.y()) self.textRect = None self.redraw() def mouseMoveEvent(self, event: QMouseEvent): """ :type event: QMouseEvent :param event: :return: """ self.mousePoint = QPoint(event.globalPos().x(), event.globalPos().y()) if self.action is None: self.action = ACTION_SELECT if not self.mousePressed: point = QPoint(event.x(), event.y()) self.detectMousePosition(point) self.setCursorStyle() self.redraw() else: self.endX, self.endY = event.x(), event.y() # if self.mousePosition != OUTSIDE_AREA: # self.action = ACTION_MOVE_SELECTED if self.action == ACTION_SELECT: self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.redraw() elif self.action == ACTION_MOVE_SELECTED: self.selectedArea = QRect(self.selectedAreaRaw) if self.mousePosition == MousePosition.INSIDE_AREA: moveToX = event.x() - self.startX + self.selectedArea.left( ) moveToY = event.y() - self.startY + self.selectedArea.top() if 0 <= moveToX <= self.screenPixel.width( ) - 1 - self.selectedArea.width(): self.selectedArea.moveLeft(moveToX) if 0 <= moveToY <= self.screenPixel.height( ) - 1 - self.selectedArea.height(): self.selectedArea.moveTop(moveToY) self.selectedArea = self.selectedArea.normalized() self.selectedAreaRaw = QRect(self.selectedArea) self.startX, self.startY = event.x(), event.y() self.redraw() elif self.mousePosition == MousePosition.ON_THE_LEFT_SIDE: moveToX = event.x() - self.startX + self.selectedArea.left( ) if moveToX <= self.selectedArea.right(): self.selectedArea.setLeft(moveToX) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE: moveToX = event.x( ) - self.startX + self.selectedArea.right() self.selectedArea.setRight(moveToX) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_UP_SIDE: moveToY = event.y() - self.startY + self.selectedArea.top() self.selectedArea.setTop(moveToY) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_DOWN_SIDE: moveToY = event.y( ) - self.startY + self.selectedArea.bottom() self.selectedArea.setBottom(moveToY) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER: moveToX = event.x() - self.startX + self.selectedArea.left( ) moveToY = event.y() - self.startY + self.selectedArea.top() self.selectedArea.setTopLeft(QPoint(moveToX, moveToY)) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER: moveToX = event.x( ) - self.startX + self.selectedArea.right() moveToY = event.y( ) - self.startY + self.selectedArea.bottom() self.selectedArea.setBottomRight(QPoint(moveToX, moveToY)) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER: moveToX = event.x( ) - self.startX + self.selectedArea.right() moveToY = event.y() - self.startY + self.selectedArea.top() self.selectedArea.setTopRight(QPoint(moveToX, moveToY)) self.selectedArea = self.selectedArea.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER: moveToX = event.x() - self.startX + self.selectedArea.left( ) moveToY = event.y( ) - self.startY + self.selectedArea.bottom() self.selectedArea.setBottomLeft(QPoint(moveToX, moveToY)) self.redraw() else: pass elif self.action == ACTION_RECT: self.drawRect(self.startX, self.startY, event.x(), event.y(), False) self.redraw() pass elif self.action == ACTION_ELLIPSE: self.drawEllipse(self.startX, self.startY, event.x(), event.y(), False) self.redraw() elif self.action == ACTION_ARROW: self.drawArrow(self.startX, self.startY, event.x(), event.y(), False) self.redraw() elif self.action == ACTION_LINE: self.drawLine(self.startX, self.startY, event.x(), event.y(), False) self.redraw() elif self.action == ACTION_FREEPEN: y1, y2 = event.x(), event.y() rect = self.selectedArea.normalized() if y1 <= rect.left(): y1 = rect.left() elif y1 >= rect.right(): y1 = rect.right() if y2 <= rect.top(): y2 = rect.top() elif y2 >= rect.bottom(): y2 = rect.bottom() self.pointPath.lineTo(y1, y2) self.drawFreeLine(self.pointPath, False) self.redraw() def mouseReleaseEvent(self, event): """ :type event: QMouseEvent :param event: :return: """ if event.button() != Qt.LeftButton: return if self.mousePressed: self.mousePressed = False self.endX, self.endY = event.x(), event.y() if self.action == ACTION_SELECT: self.selectedArea.setBottomRight(QPoint(event.x(), event.y())) self.selectedAreaRaw = QRect(self.selectedArea) self.action = ACTION_MOVE_SELECTED self.redraw() elif self.action == ACTION_MOVE_SELECTED: self.selectedAreaRaw = QRect(self.selectedArea) self.redraw() # self.action = None elif self.action == ACTION_RECT: self.drawRect(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_ELLIPSE: self.drawEllipse(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_ARROW: self.drawArrow(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_LINE: self.drawLine(self.startX, self.startY, event.x(), event.y(), True) self.redraw() elif self.action == ACTION_FREEPEN: self.drawFreeLine(self.pointPath, True) self.redraw() def detectMousePosition(self, point): """ :type point: QPoint :param point: the mouse position you want to check :return: """ if self.selectedArea == QRect(): self.mousePosition = MousePosition.OUTSIDE_AREA return if self.selectedArea.left() - ERRORRANGE <= point.x( ) <= self.selectedArea.left() and (self.selectedArea.top() - ERRORRANGE <= point.y() <= self.selectedArea.top()): self.mousePosition = MousePosition.ON_THE_TOP_LEFT_CORNER elif self.selectedArea.right() <= point.x() <= self.selectedArea.right( ) + ERRORRANGE and (self.selectedArea.top() - ERRORRANGE <= point.y() <= self.selectedArea.top()): self.mousePosition = MousePosition.ON_THE_TOP_RIGHT_CORNER elif self.selectedArea.left() - ERRORRANGE <= point.x( ) <= self.selectedArea.left() and ( self.selectedArea.bottom() <= point.y() <= self.selectedArea.bottom() + ERRORRANGE): self.mousePosition = MousePosition.ON_THE_BOTTOM_LEFT_CORNER elif self.selectedArea.right() <= point.x() <= self.selectedArea.right( ) + ERRORRANGE and (self.selectedArea.bottom() <= point.y() <= self.selectedArea.bottom() + ERRORRANGE): self.mousePosition = MousePosition.ON_THE_BOTTOM_RIGHT_CORNER elif -ERRORRANGE <= point.x() - self.selectedArea.left() <= 0 and ( self.selectedArea.topLeft().y() < point.y() < self.selectedArea.bottomLeft().y()): self.mousePosition = MousePosition.ON_THE_LEFT_SIDE elif 0 <= point.x() - self.selectedArea.right() <= ERRORRANGE and ( self.selectedArea.topRight().y() < point.y() < self.selectedArea.bottomRight().y()): self.mousePosition = MousePosition.ON_THE_RIGHT_SIDE elif -ERRORRANGE <= point.y() - self.selectedArea.top() <= 0 and ( self.selectedArea.topLeft().x() < point.x() < self.selectedArea.topRight().x()): self.mousePosition = MousePosition.ON_THE_UP_SIDE elif 0 <= point.y() - self.selectedArea.bottom() <= ERRORRANGE and ( self.selectedArea.bottomLeft().x() < point.x() < self.selectedArea.bottomRight().x()): self.mousePosition = MousePosition.ON_THE_DOWN_SIDE elif not self.selectedArea.contains(point): self.mousePosition = MousePosition.OUTSIDE_AREA else: self.mousePosition = MousePosition.INSIDE_AREA def setCursorStyle(self): if self.action in DRAW_ACTION: self.setCursor(Qt.CrossCursor) return if self.mousePosition == MousePosition.ON_THE_LEFT_SIDE or \ self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE: self.setCursor(Qt.SizeHorCursor) elif self.mousePosition == MousePosition.ON_THE_UP_SIDE or \ self.mousePosition == MousePosition.ON_THE_DOWN_SIDE: self.setCursor(Qt.SizeVerCursor) elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER or \ self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER: self.setCursor(Qt.SizeFDiagCursor) elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER or \ self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER: self.setCursor(Qt.SizeBDiagCursor) elif self.mousePosition == MousePosition.OUTSIDE_AREA: self.setCursor(Qt.ArrowCursor) elif self.mousePosition == MousePosition.INSIDE_AREA: self.setCursor(Qt.OpenHandCursor) else: self.setCursor(Qt.ArrowCursor) pass def drawMagnifier(self): # First, calculate the magnifier position due to the mouse position watchAreaWidth = 16 watchAreaHeight = 16 watchAreaPixmap = QPixmap() cursor_pos = self.mousePoint watchArea = QRect( QPoint(cursor_pos.x() - watchAreaWidth / 2, cursor_pos.y() - watchAreaHeight / 2), QPoint(cursor_pos.x() + watchAreaWidth / 2, cursor_pos.y() + watchAreaHeight / 2)) if watchArea.left() < 0: watchArea.moveLeft(0) watchArea.moveRight(watchAreaWidth) if self.mousePoint.x() + watchAreaWidth / 2 >= self.screenPixel.width( ): watchArea.moveRight(self.screenPixel.width() - 1) watchArea.moveLeft(watchArea.right() - watchAreaWidth) if self.mousePoint.y() - watchAreaHeight / 2 < 0: watchArea.moveTop(0) watchArea.moveBottom(watchAreaHeight) if self.mousePoint.y( ) + watchAreaHeight / 2 >= self.screenPixel.height(): watchArea.moveBottom(self.screenPixel.height() - 1) watchArea.moveTop(watchArea.bottom() - watchAreaHeight) # tricks to solve the hidpi impact on QCursor.pos() watchArea.setTopLeft( QPoint(watchArea.topLeft().x() * self.scale, watchArea.topLeft().y() * self.scale)) watchArea.setBottomRight( QPoint(watchArea.bottomRight().x() * self.scale, watchArea.bottomRight().y() * self.scale)) watchAreaPixmap = self.screenPixel.copy(watchArea) # second, calculate the magnifier area magnifierAreaWidth = watchAreaWidth * 10 magnifierAreaHeight = watchAreaHeight * 10 fontAreaHeight = 40 cursorSize = 24 magnifierArea = QRectF( QPoint(QCursor.pos().x() + cursorSize, QCursor.pos().y() + cursorSize), QPoint(QCursor.pos().x() + cursorSize + magnifierAreaWidth, QCursor.pos().y() + cursorSize + magnifierAreaHeight)) if magnifierArea.right() >= self.screenPixel.width(): magnifierArea.moveLeft(QCursor.pos().x() - magnifierAreaWidth - cursorSize / 2) if magnifierArea.bottom() + fontAreaHeight >= self.screenPixel.height( ): magnifierArea.moveTop(QCursor.pos().y() - magnifierAreaHeight - cursorSize / 2 - fontAreaHeight) # third, draw the watch area to magnifier area watchAreaScaled = watchAreaPixmap.scaled( QSize(magnifierAreaWidth * self.scale, magnifierAreaHeight * self.scale)) magnifierPixmap = self.graphicsScene.addPixmap(watchAreaScaled) magnifierPixmap.setOffset(magnifierArea.topLeft()) # then draw lines and text self.graphicsScene.addRect(QRectF(magnifierArea), QPen(QColor(255, 255, 255), 2)) self.graphicsScene.addLine( QLineF(QPointF(magnifierArea.center().x(), magnifierArea.top()), QPointF(magnifierArea.center().x(), magnifierArea.bottom())), QPen(QColor(0, 255, 255), 2)) self.graphicsScene.addLine( QLineF(QPointF(magnifierArea.left(), magnifierArea.center().y()), QPointF(magnifierArea.right(), magnifierArea.center().y())), QPen(QColor(0, 255, 255), 2)) # get the rgb of mouse point pointRgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint)) # draw information self.graphicsScene.addRect( QRectF( magnifierArea.bottomLeft(), magnifierArea.bottomRight() + QPoint(0, fontAreaHeight + 30)), Qt.black, QBrush(Qt.black)) rgbInfo = self.graphicsScene.addSimpleText( ' Rgb: ({0}, {1}, {2})'.format(pointRgb.red(), pointRgb.green(), pointRgb.blue())) rgbInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 5)) rgbInfo.setPen(QPen(QColor(255, 255, 255), 2)) rect = self.selectedArea.normalized() sizeInfo = self.graphicsScene.addSimpleText(' Size: {0} x {1}'.format( rect.width() * self.scale, rect.height() * self.scale)) sizeInfo.setPos(magnifierArea.bottomLeft() + QPoint(0, 15) + QPoint(0, fontAreaHeight / 2)) sizeInfo.setPen(QPen(QColor(255, 255, 255), 2)) def get_scale(self): return self.devicePixelRatio() def saveScreenshot(self, clipboard=False, fileName='screenshot.png', picType='png'): fullWindow = QRect(0, 0, self.width() - 1, self.height() - 1) selected = QRect(self.selectedArea) if selected.left() < 0: selected.setLeft(0) if selected.right() >= self.width(): selected.setRight(self.width() - 1) if selected.top() < 0: selected.setTop(0) if selected.bottom() >= self.height(): selected.setBottom(self.height() - 1) source = (fullWindow & selected) source.setTopLeft( QPoint(source.topLeft().x() * self.scale, source.topLeft().y() * self.scale)) source.setBottomRight( QPoint(source.bottomRight().x() * self.scale, source.bottomRight().y() * self.scale)) image = self.screenPixel.copy(source) image.setDevicePixelRatio(1) if clipboard: QGuiApplication.clipboard().setImage(QImage(image), QClipboard.Clipboard) else: image.save(fileName, picType, 10) self.target_img = image self.screen_shot_grabed.emit(QImage(image)) def redraw(self): self.graphicsScene.clear() # draw screenshot self.graphicsScene.addPixmap(self.screenPixel) # prepare for drawing selected area rect = QRectF(self.selectedArea) rect = rect.normalized() topLeftPoint = rect.topLeft() topRightPoint = rect.topRight() bottomLeftPoint = rect.bottomLeft() bottomRightPoint = rect.bottomRight() topMiddlePoint = (topLeftPoint + topRightPoint) / 2 leftMiddlePoint = (topLeftPoint + bottomLeftPoint) / 2 bottomMiddlePoint = (bottomLeftPoint + bottomRightPoint) / 2 rightMiddlePoint = (topRightPoint + bottomRightPoint) / 2 # draw the picture mask mask = QColor(0, 0, 0, 155) if self.selectedArea == QRect(): self.graphicsScene.addRect(0, 0, self.screenPixel.width(), self.screenPixel.height(), QPen(Qt.NoPen), mask) else: self.graphicsScene.addRect(0, 0, self.screenPixel.width(), topRightPoint.y(), QPen(Qt.NoPen), mask) self.graphicsScene.addRect(0, topLeftPoint.y(), topLeftPoint.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphicsScene.addRect( topRightPoint.x(), topRightPoint.y(), self.screenPixel.width() - topRightPoint.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphicsScene.addRect( 0, bottomLeftPoint.y(), self.screenPixel.width(), self.screenPixel.height() - bottomLeftPoint.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.selectedArea != QRect(): self.itemsToRemove = [] # draw the selected rectangle pen = QPen(QColor(0, 255, 255), 2) self.itemsToRemove.append(self.graphicsScene.addRect(rect, pen)) # draw the drag point radius = QPoint(3, 3) brush = QBrush(QColor(0, 255, 255)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(topLeftPoint - radius, topLeftPoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(topMiddlePoint - radius, topMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(topRightPoint - radius, topRightPoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(leftMiddlePoint - radius, leftMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(rightMiddlePoint - radius, rightMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(bottomLeftPoint - radius, bottomLeftPoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(bottomMiddlePoint - radius, bottomMiddlePoint + radius), pen, brush)) self.itemsToRemove.append( self.graphicsScene.addEllipse( QRectF(bottomRightPoint - radius, bottomRightPoint + 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() # deal with every step in drawList def drawOneStep(self, step): """ :type step: tuple """ if step[0] == ACTION_RECT: self.graphicsScene.addRect( QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_ELLIPSE: self.graphicsScene.addEllipse( QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_ARROW: arrow = QPolygonF() linex = float(step[1] - step[3]) liney = float(step[2] - step[4]) line = sqrt(pow(linex, 2) + pow(liney, 2)) # in case to divided by 0 if line == 0: return sinAngel = liney / line cosAngel = linex / line # sideLength is the length of bottom side of the body of an arrow # arrowSize is the size of the head of an arrow, left and right # sides' size is arrowSize, and the bottom side's size is arrowSize / 2 sideLength = step[5].width() arrowSize = 8 bottomSize = arrowSize / 2 tmpPoint = QPointF(step[3] + arrowSize * sideLength * cosAngel, step[4] + arrowSize * sideLength * sinAngel) point1 = QPointF(step[1] + sideLength * sinAngel, step[2] - sideLength * cosAngel) point2 = QPointF(step[1] - sideLength * sinAngel, step[2] + sideLength * cosAngel) point3 = QPointF(tmpPoint.x() - sideLength * sinAngel, tmpPoint.y() + sideLength * cosAngel) point4 = QPointF(tmpPoint.x() - bottomSize * sideLength * sinAngel, tmpPoint.y() + bottomSize * sideLength * cosAngel) point5 = QPointF(step[3], step[4]) point6 = QPointF(tmpPoint.x() + bottomSize * sideLength * sinAngel, tmpPoint.y() - bottomSize * sideLength * cosAngel) point7 = QPointF(tmpPoint.x() + sideLength * sinAngel, tmpPoint.y() - sideLength * cosAngel) arrow.append(point1) arrow.append(point2) arrow.append(point3) arrow.append(point4) arrow.append(point5) arrow.append(point6) arrow.append(point7) arrow.append(point1) self.graphicsScene.addPolygon(arrow, step[5], step[6]) elif step[0] == ACTION_LINE: self.graphicsScene.addLine( QLineF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_FREEPEN: self.graphicsScene.addPath(step[1], step[2]) elif step[0] == ACTION_TEXT: textAdd = self.graphicsScene.addSimpleText(step[1], step[2]) textAdd.setPos(step[3]) textAdd.setBrush(QBrush(step[4])) self.textRect = textAdd.boundingRect() # draw the size information on the top left corner def drawSizeInfo(self): sizeInfoAreaWidth = 200 sizeInfoAreaHeight = 30 spacing = 5 rect = self.selectedArea.normalized() sizeInfoArea = QRect(rect.left(), rect.top() - spacing - sizeInfoAreaHeight, sizeInfoAreaWidth, sizeInfoAreaHeight) if sizeInfoArea.top() < 0: sizeInfoArea.moveTopLeft(rect.topLeft() + QPoint(spacing, spacing)) if sizeInfoArea.right() >= self.screenPixel.width(): sizeInfoArea.moveTopLeft(rect.topLeft() - QPoint(spacing, spacing) - QPoint(sizeInfoAreaWidth, 0)) if sizeInfoArea.left() < spacing: sizeInfoArea.moveLeft(spacing) if sizeInfoArea.top() < spacing: sizeInfoArea.moveTop(spacing) self.itemsToRemove.append( self.graphicsScene.addRect(QRectF(sizeInfoArea), Qt.white, QBrush(Qt.black))) sizeInfo = self.graphicsScene.addSimpleText(' {0} x {1}'.format( rect.width() * self.scale, rect.height() * self.scale)) sizeInfo.setPos(sizeInfoArea.topLeft() + QPoint(0, 2)) sizeInfo.setPen(QPen(QColor(255, 255, 255), 2)) self.itemsToRemove.append(sizeInfo) def drawRect(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized() resultRect = rect & tmpRect tmp = [ ACTION_RECT, resultRect.topLeft().x(), resultRect.topLeft().y(), resultRect.bottomRight().x(), resultRect.bottomRight().y(), QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawEllipse(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() tmpRect = QRect(QPoint(x1, x2), QPoint(y1, y2)).normalized() resultRect = rect & tmpRect tmp = [ ACTION_ELLIPSE, resultRect.topLeft().x(), resultRect.topLeft().y(), resultRect.bottomRight().x(), resultRect.bottomRight().y(), QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawArrow(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() if y1 <= rect.left(): y1 = rect.left() elif y1 >= rect.right(): y1 = rect.right() if y2 <= rect.top(): y2 = rect.top() elif y2 >= rect.bottom(): y2 = rect.bottom() tmp = [ ACTION_ARROW, x1, x2, y1, y2, QPen(QColor(self.penColorNow), int(self.penSizeNow)), QBrush(QColor(self.penColorNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawLine(self, x1, x2, y1, y2, result): rect = self.selectedArea.normalized() if y1 <= rect.left(): y1 = rect.left() elif y1 >= rect.right(): y1 = rect.right() if y2 <= rect.top(): y2 = rect.top() elif y2 >= rect.bottom(): y2 = rect.bottom() tmp = [ ACTION_LINE, x1, x2, y1, y2, QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def drawFreeLine(self, pointPath, result): tmp = [ ACTION_FREEPEN, QPainterPath(pointPath), QPen(QColor(self.penColorNow), int(self.penSizeNow)) ] if result: self.drawListResult.append(tmp) else: self.drawListProcess = tmp def textChange(self): if self.textPosition is None: return self.text = self.textInput.getText() self.drawListProcess = [ ACTION_TEXT, str(self.text), QFont(self.fontNow), QPoint(self.textPosition), QColor(self.penColorNow) ] self.redraw() def undoOperation(self): if len(self.drawListResult) == 0: self.action = ACTION_SELECT self.selectedArea = QRect() self.selectedAreaRaw = QRect() self.tooBar.hide() if self.penSetBar is not None: self.penSetBar.hide() else: self.drawListResult.pop() self.redraw() def saveOperation(self): filename = QFileDialog.getSaveFileName(self, 'Save file', './screenshot.png', '*.png;;*.jpg') if len(filename[0]) == 0: return else: self.saveScreenshot(False, filename[0], filename[1][2:]) self.close() def close(self): self.widget_closed.emit() super().close() self.tooBar.close() if self.penSetBar is not None: self.penSetBar.close() def saveToClipboard(self): QApplication.clipboard().setText('Test in save function') self.saveScreenshot(True) self.close() # slots def changeAction(self, nextAction): QApplication.clipboard().setText('Test in changeAction function') if nextAction == ACTION_UNDO: self.undoOperation() elif nextAction == ACTION_SAVE: self.saveOperation() elif nextAction == ACTION_CANCEL: self.close() elif nextAction == ACTION_SURE: self.saveToClipboard() else: self.action = nextAction self.setFocus() def changePenSize(self, nextPenSize): self.penSizeNow = nextPenSize def changePenColor(self, nextPenColor): self.penColorNow = nextPenColor def cancelInput(self): self.drawListProcess = None self.textPosition = None self.textRect = None self.textInput.hide() self.textInput.clearText() self.redraw() def okInput(self): self.text = self.textInput.getText() self.drawListResult.append([ ACTION_TEXT, str(self.text), QFont(self.fontNow), QPoint(self.textPosition), QColor(self.penColorNow) ]) self.textPosition = None self.textRect = None self.textInput.hide() self.textInput.clearText() self.redraw() def changeFont(self, font): self.fontNow = font
class MonitorGraphicsView(QGraphicsView, AllowDrop): monitorWin = None SIZE = (50.0, 50.0) FULLSPEED = 512 * 1024 # 512 in kb/s _progressText = None _speedsPolygon = None _speedsPen = None _speedsBrush = None def __init__(self, parent = None): super().__init__(parent) self.monitorWin = parent if self.monitorWin: self.monitorWin.sigTaskUpdating.connect(self.slotTaskUpdate) self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, self.SIZE[0], self.SIZE[1]) self.setScene(self.scene) self._speedsPen = QPen(Qt.white) gradient = QLinearGradient(0, 0, self.SIZE[0], self.SIZE[1]) gradient.setColorAt(0.0, Qt.darkGreen) gradient.setColorAt(1.0, Qt.yellow) self._speedsBrush = QBrush(gradient) # add elements to the scene self._speedsPolygon = self.scene.addPolygon(QPolygonF(), self._speedsPen, self._speedsBrush) self._progressText = self.scene.addText("") self._progressText.setPos(10, 0) self.setupDropSupport() def mousePressEvent(self, qMouseEvent): self.monitorWin.mousePressEvent(qMouseEvent) def mouseMoveEvent(self, qMouseEvent): self.monitorWin.mouseMoveEvent(qMouseEvent) def mouseReleaseEvent(self, qMouseEvent): self.monitorWin.mouseReleaseEvent(qMouseEvent) def _setSpeeds(self, speeds): polygon = QPolygonF() polygon.append(QPointF(0, self.SIZE[1])) # start the polygon nSamples = len(speeds) xPerSample = self.SIZE[0] / nSamples for i, speed in enumerate(speeds): y = self._translateSpeedToPosY(speed) polygon.append(QPointF(xPerSample * i, y)) polygon.append(QPointF(xPerSample * (i+1), y)) polygon.append(QPointF(*self.SIZE)) # close the polygon self._speedsPolygon.setPolygon(polygon) def _setProgress(self, process): # 10000 means 100% if process is None: self._progressText.setPlainText("") else: self._progressText.setPlainText("{:.1f}%".format(process / 100)) def _translateSpeedToPosY(self, speed): return self.SIZE[1] * (1.0 - speed / self.FULLSPEED) @pyqtSlot(dict) def slotTaskUpdate(self, task): if task: self._setProgress(task["progress"]) self._setSpeeds(task["speeds"]) else: self._setProgress(None) self._setSpeeds([0.0])
def paint(self, scene: QtWidgets.QGraphicsScene): poly = QtGui.QPolygonF(self.points) scene.addPolygon(poly, self.color, self.inner_color)
class TableViewWidget(QGraphicsView): g_table_view = None g_detect_size = 200 g_detect_text = "position" #g_detect_text = "quality" #g_detect_text = "none" g_rplidar_remanence = False g_rplidar_plot_life_ms = 1000 def __init__(self, parent = None, ihm_type='pc'): super(TableViewWidget, self).__init__(parent) if ihm_type=='pc': #self.setFixedSize(900,600) self.setFixedSize(960,660) elif ihm_type=='pc-mini': #self.setFixedSize(600,400) self.setFixedSize(640,440) else: #self.setFixedSize(225,150) self.setFixedSize(240,165) #self.setSceneRect(QRectF(0,-1500,2000,3000)) self.setSceneRect(QRectF(-100,-1600,2200,3200)) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._robots = {} self._waypoints = [] redium = QColor.fromCmykF(0,1,1,0.1) greenium = QColor.fromCmykF(0.7,0,0.9,0) blueium = QColor.fromCmykF(0.9,0.4,0,0) goldenium = QColor('white') yellow = QColor.fromCmykF(0,0.25,1,0) purple = QColor.fromCmykF(0.5,0.9,0,0.05) background = QColor(40,40,40) darker = QColor(20,20,20) # big_robot_poly = QPolygonF([ # QPointF(-135,-151), # QPointF(60,-151), # QPointF(170,-91), # QPointF(170,-45), # QPointF(111,-40), # QPointF(111,40), # QPointF(170,45), # QPointF(170,91), # QPointF(60,151), # QPointF(-135,151) # ]) little_robot_poly = QPolygonF([ QPointF( 50, 0), QPointF( 100, 85), QPointF( 65, 115), QPointF( -65, 115), QPointF(-100, 85), QPointF(-100, -85), QPointF( -65,-115), QPointF( 65,-115), QPointF( 100, -85) ]) #self._scene = QGraphicsScene(QRectF(0,-1500,2000,3000)) self._scene = QGraphicsScene(QRectF(-100,-1600,2200,3200)) # self._big_robot = self._scene.addPolygon(big_robot_poly, QPen(), QBrush(QColor('red'))) # self._big_robot.setZValue(1) #self._robots['little'] = Robot(self._scene) self._little_robot = self._scene.addPolygon(little_robot_poly, QPen(), QBrush(QColor('red'))) self._little_robot.setZValue(1) #self._friend_robot = self._scene.addEllipse(-100, -100, 200, 200, QPen(QBrush(QColor('black')),4), QBrush(QColor('green'))) self._friend_robot = self._scene.addEllipse(-100, -100, TableViewWidget.g_detect_size, TableViewWidget.g_detect_size, QPen(QBrush(QColor('black')),4), QBrush(QColor('white'))) self._friend_robot.setZValue(1) self._friend_robot.setPos(-1 * 1000, -1 * 1000) if os.name == 'nt': self._friend_robot_text = self._scene.addText("0123456", QFont("Calibri",80)); else: self._friend_robot_text = self._scene.addText("0123456", QFont("System",40)); self._friend_robot_text.setPos(-1 * 1000 - 60, -1 * 1000 - 40) self._friend_robot_text.setRotation(-90) self._friend_robot_text.setTransform(QTransform(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0)) self._friend_robot_text.setZValue(1) #self._adv1_robot = self._scene.addEllipse(-100, -100, 200, 200, QPen(QBrush(QColor('black')),4), QBrush(QColor('white'))) self._adv1_robot = self._scene.addEllipse(-100, -100, TableViewWidget.g_detect_size, TableViewWidget.g_detect_size, QPen(QBrush(QColor('black')),4), QBrush(QColor('white'))) self._adv1_robot.setZValue(1) self._adv1_robot.setPos(-1 * 1000, -1 * 1000) if os.name == 'nt': self._adv1_robot_text = self._scene.addText("0", QFont("Calibri",80)); else: self._adv1_robot_text = self._scene.addText("0", QFont("System",40)); self._adv1_robot_text.setPos(-1 * 1000 - 60, -1 * 1000 - 40) self._adv1_robot_text.setRotation(-90) self._adv1_robot_text.setTransform(QTransform(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0)) self._adv1_robot_text.setZValue(1) #self._adv2_robot = self._scene.addEllipse(-100, -100, 200, 200, QPen(QBrush(QColor('black')),4), QBrush(QColor('blue'))) self._adv2_robot = self._scene.addEllipse(-100, -100, TableViewWidget.g_detect_size, TableViewWidget.g_detect_size, QPen(QBrush(QColor('black')),4), QBrush(QColor('white'))) self._adv2_robot.setZValue(1) self._adv2_robot.setPos(-1 * 1000, -1 * 1000) if os.name == 'nt': self._adv2_robot_text = self._scene.addText("0", QFont("Calibri",80)); else: self._adv2_robot_text = self._scene.addText("0", QFont("System",40)); self._adv2_robot_text.setPos(-1 * 1000 - 60, -1 * 1000 - 40) self._adv2_robot_text.setRotation(-90) self._adv2_robot_text.setTransform(QTransform(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0)) self._adv2_robot_text.setZValue(1) self.setScene(self._scene) self.rotate(90) if ihm_type=='pc': self.scale(0.3, -0.3) elif ihm_type=='pc-mini': self.scale(0.2, -0.2) else: self.scale(0.075, -0.075) #self._scene.addRect(QRectF(0,-1500,2000,3000),QPen(), QBrush(background)) f=open("widgets/table_2020_600x400.png","rb") my_buff=f.read() test_img_pixmap2 = QPixmap() test_img_pixmap2.loadFromData(my_buff) #self.setPixmap(test_img_pixmap2) self._bg_img = QGraphicsPixmapItem(test_img_pixmap2) self._bg_img.setTransform(QTransform(1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.2)) self._bg_img.setRotation(-90) self._bg_img.setPos(0, -1500) self._scene.addItem(self._bg_img); # Scenario 2020 #Port principal "bleu" self._scene.addRect(QRectF(500,-1120,570,20),QPen(), QBrush(blueium)) self._scene.addRect(QRectF(500,-1500,30,400),QPen(), QBrush(greenium)) self._scene.addRect(QRectF(1070,-1500,30,400),QPen(), QBrush(redium)) #Port secondaire "bleu" self._scene.addRect(QRectF(1700,150,20,300),QPen(), QBrush(blueium)) self._scene.addRect(QRectF(1700,150,300,100),QPen(), QBrush(greenium)) self._scene.addRect(QRectF(1700,350,300,100),QPen(), QBrush(redium)) #Bouees cote "bleu" self._scene.addEllipse(QRectF(1200-35,-1200-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(1080-35,-1050-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(510-35,-1050-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(400-35,-1200-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(100-35,-830-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(400-35,-550-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(800-35,-400-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(1200-35,-230-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(1650-35,-435-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(1650-35,-165-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(1955-35,-495-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(1955-35,-105-35,70,70),QPen(), QBrush(greenium)) #Port principal "jaune" self._scene.addRect(QRectF(500,1100,570,20),QPen(), QBrush(yellow)) self._scene.addRect(QRectF(500,1100,30,400),QPen(), QBrush(redium)) self._scene.addRect(QRectF(1070,1100,30,400),QPen(), QBrush(greenium)) #Port secondaire "jaune" self._scene.addRect(QRectF(1700,-450,20,300),QPen(), QBrush(yellow)) self._scene.addRect(QRectF(1700,-450,300,100),QPen(), QBrush(greenium)) self._scene.addRect(QRectF(1700,-250,300,100),QPen(), QBrush(redium)) #Bouees cote "jaune" self._scene.addEllipse(QRectF(1200-35,1200-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(1080-35,1050-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(510-35,1050-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(400-35,1200-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(100-35,830-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(400-35,550-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(800-35,400-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(1200-35,230-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(1650-35,435-35,70,70),QPen(), QBrush(redium)) self._scene.addEllipse(QRectF(1650-35,165-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(1955-35,495-35,70,70),QPen(), QBrush(greenium)) self._scene.addEllipse(QRectF(1955-35,105-35,70,70),QPen(), QBrush(redium)) #dbg_plt_sz = 3 #self._scene.addEllipse(1000 - dbg_plt_sz, 0 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white'))) self._points = [] #self.setSceneRect(QRectF(0,-150,200,300)) self._traj_segm_l = [] self._debug_edit_mode = False self._debug_edit_point_l = [] # self._big_robot_x = 0 # self._big_robot_y = 0 self._little_robot_x = 0 self._little_robot_y = 0 self.last_plot_ts = 0 self.plot_graph_l = [] self._plot_items = [] TableViewWidget.g_table_view = self def set_strategy(self, strategy): greenium = QColor.fromCmykF(0.7,0,0.9,0) #greenium.setAlphaF(0.2) for id_, pos in strategy['strategy']['map']['waypoints'].items(): wp = self._scene.addEllipse(QRectF(pos[0]-10,pos[1]-10,20,20),QPen(), QBrush(greenium)) self._waypoints.append(wp) for id_, pose in strategy['strategy']['map']['poses'].items(): p = strategy['strategy']['map']['waypoints'][pose[0]] path = QPainterPath() cos_ = math.cos(pose[1] * math.pi / 180) sin_ = math.sin(pose[1] * math.pi / 180) l = 40 w = 20 path.moveTo(p[0] + l * cos_, p[1] + l * sin_) path.lineTo(p[0] -l * cos_ + w * sin_, p[1] - l * sin_ - w * cos_) path.lineTo(p[0] -l * cos_ - w * sin_, p[1] - l * sin_ + w * cos_) path.closeSubpath() itm = self._scene.addPath(path, QPen(), QBrush(greenium)) for id_, area in strategy['strategy']['map']['areas'].items(): path = QPainterPath() v = area['vertices'][0] path.moveTo(v[0], v[1]) for v in area['vertices'][1:]: path.lineTo(v[0], v[1]) path.closeSubpath() itm = self._scene.addPath(path, QPen(), QBrush(greenium)) self._waypoints.append(wp) def add_points(self, points): for p in points: pt = self._scene.addEllipse(p[0]-10, p[1]-10, 20, 20, QPen(), QBrush(QColor('grey'))) pt.setZValue(1) self._points.append((pt, p)) def sizeHint(self): return QSize(600,400) def set_client(self, client): self._client = client self._client.propulsion_telemetry.connect(self.update_telemetry) self._client.rplidar_plot.connect(self.update_plots) self._client.rplidar_robot_detection.connect(self.update_other_robots) def update_telemetry(self, telemetry): # self._big_robot.setPos(telemetry.x * 1000, telemetry.y * 1000) # self._big_robot.setRotation(telemetry.yaw * 180 / math.pi) # self._big_robot_x = telemetry.x * 1000 # self._big_robot_y = telemetry.y * 1000 self._little_robot.setPos(telemetry.pose.position.x * 1000, telemetry.pose.position.y * 1000) self._little_robot.setRotation(telemetry.pose.yaw * 180 / math.pi) self._little_robot_x = telemetry.pose.position.x * 1000 self._little_robot_y = telemetry.pose.position.y * 1000 def update_plots(self, my_plot): dbg_plt_sz = 1 for i in self._plot_items: self._scene.removeItem(i) self._plot_items = [] #self.last_plot_ts = my_plot.timestamp for pt in my_plot.points: itm = self._scene.addEllipse(pt.x * 1000 - dbg_plt_sz, pt.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('red')),4), QBrush(QColor('red'))) self._plot_items.append(itm) return my_plot_ellipse = self._scene.addEllipse(my_plot.x * 1000 - dbg_plt_sz, my_plot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('red')),4), QBrush(QColor('red'))) self.plot_graph_l.append((my_plot,my_plot_ellipse)) for rec in self.plot_graph_l: if (self.last_plot_ts-rec[0].timestamp>TableViewWidget.g_rplidar_plot_life_ms): rec_ellipse = rec[1] self._scene.removeItem(rec_ellipse) self.plot_graph_l.remove(rec) def update_other_robots(self, other_robot): dbg_plt_sz = 3 if (other_robot.id == 0): self._friend_robot.setPos(other_robot.x * 1000, other_robot.y * 1000) if (TableViewWidget.g_detect_text == "quality"): self._friend_robot_text.setPlainText("%d"%other_robot.samples) elif (TableViewWidget.g_detect_text == "position"): self._friend_robot_text.setPlainText("%d,%d"%(other_robot.x*1000,other_robot.y*1000)) else: self._friend_robot_text.setPlainText("") self._friend_robot_text.setPos(other_robot.x * 1000 - 60, other_robot.y * 1000 - 40) if TableViewWidget.g_rplidar_remanence: self._scene.addEllipse(other_robot.x * 1000 - dbg_plt_sz, other_robot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white'))) elif (other_robot.id == 1): self._adv1_robot.setPos(other_robot.x * 1000, other_robot.y * 1000) if (TableViewWidget.g_detect_text == "quality"): self._adv1_robot_text.setPlainText("%d"%other_robot.samples) elif (TableViewWidget.g_detect_text == "position"): self._adv1_robot_text.setPlainText("%d,%d"%(other_robot.x*1000,other_robot.y*1000)) else: self._adv1_robot_text.setPlainText("") self._adv1_robot_text.setPos(other_robot.x * 1000 - 60, other_robot.y * 1000 - 40) if TableViewWidget.g_rplidar_remanence: self._scene.addEllipse(other_robot.x * 1000 - dbg_plt_sz, other_robot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white'))) elif (other_robot.id == 2): self._adv2_robot.setPos(other_robot.x * 1000, other_robot.y * 1000) if (TableViewWidget.g_detect_text == "quality"): self._adv2_robot_text.setPlainText("%d"%other_robot.samples) elif (TableViewWidget.g_detect_text == "position"): self._adv2_robot_text.setPlainText("%d,%d"%(other_robot.x*1000,other_robot.y*1000)) else: self._adv2_robot_text.setPlainText("") self._adv2_robot_text.setPos(other_robot.x * 1000 - 60, other_robot.y * 1000 - 40) if TableViewWidget.g_rplidar_remanence: self._scene.addEllipse(other_robot.x * 1000 - dbg_plt_sz, other_robot.y * 1000 - dbg_plt_sz, 2*dbg_plt_sz, 2*dbg_plt_sz, QPen(QBrush(QColor('white')),4), QBrush(QColor('white'))) def debug_set_start(self, _new_x, _new_y): self.debug_start_x = _new_x self.debug_start_y = _new_y self.debug_cur_x = _new_x self.debug_cur_y = _new_y if self._debug_edit_mode: self._debug_edit_point_l.append((_new_x,_new_y)) def debug_line_to(self, _new_x, _new_y): my_segm = self._scene.addLine(self.debug_cur_x, self.debug_cur_y, _new_x, _new_y, QPen(QColor(255,255,255))); self._traj_segm_l.append(my_segm) self.debug_cur_x = _new_x self.debug_cur_y = _new_y def debug_clear_lines(self): for l in self._traj_segm_l: self._scene.removeItem(l) self._traj_segm_l = [] def debug_start_edit(self, _new_x, _new_y): self.debug_clear_lines() self._debug_edit_mode = True self.debug_start_x = _new_x self.debug_start_y = _new_y self.debug_cur_x = _new_x self.debug_cur_y = _new_y self._debug_edit_point_l = [(_new_x,_new_y)] def debug_start_edit_rel(self): self.debug_clear_lines() self._debug_edit_mode = True self.debug_start_x = self._little_robot_x self.debug_start_y = self._little_robot_y self.debug_cur_x = self._little_robot_x self.debug_cur_y = self._little_robot_y self._debug_edit_point_l = [(self._little_robot_x,self._little_robot_y)] def debug_stop_edit(self): self._debug_edit_mode = False return self._debug_edit_point_l def mousePressEvent(self, event): print ("pix:<{},{}>".format(event.x(),event.y())) #realY = 3000.0*(event.x()-450.0)/900.0 #realX = 2000.0*(event.y())/600.0 realY = 3200.0*(event.x()-480.0)/960.0 realX = 2200.0*(event.y()-30.0)/660.0 print ("real:<{},{}>".format(realX,realY)) if self._debug_edit_mode: self._debug_edit_point_l.append((realX,realY)) self.debug_line_to(realX, realY)
class Viewer(QGraphicsView): def __init__(self): QGraphicsView.__init__(self) self.setGeometry(QRect(100, 100, 800, 600)) self.setWindowTitle("PIHDL Graphics Window") # Create a QGraphicsScene which this view looks at self.scene = QGraphicsScene(self) self.scene.setSceneRect(QRectF()) self.setScene(self.scene) # Customize QGraphicsView self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setInteractive(False) self.scale(1, -1) # Flips around the Y axis # Use OpenGL http://ralsina.me/stories/BBS53.html # self.setViewport(QtOpenGL.QGLWidget()) self.rubberBand = QRubberBand(QRubberBand.Rectangle, self) self.pen = QPen(QtCore.Qt.black, 0) self.portpen = QPen(PORT_COLOR, 3) self.portpen.setCosmetic(True) # Makes constant width self.portfont = QtGui.QFont('Arial', pointSize=14) self.portfontcolor = PORT_COLOR self.subportpen = QPen(SUBPORT_COLOR, 3) self.subportpen.setCosmetic(True) # Makes constant width self.subportfont = QtGui.QFont('Arial', pointSize=14) self.subportfontcolor = SUBPORT_COLOR # Tracking ports # Various status variables self._mousePressed = None self._rb_origin = QPoint() self.zoom_factor_total = 1 # Grid variables self.gridpen = QPen(QtCore.Qt.black, 0) self.gridpen.setStyle(QtCore.Qt.DotLine) self.gridpen.setDashPattern([1, 4]) self.gridpen.setColor(QtGui.QColor(0, 0, 0, 125)) # self.gridpen = QPen(QtCore.Qt.black, 1) # self.gridpen.setCosmetic(True) # Makes constant width # self.gridlinesx = [self.scene.addLine(-10,-10,10,10, self.gridpen) for n in range(100)] # self.gridlinesy = [self.scene.addLine(-10,-10,10,10, self.gridpen) for n in range(100)] self.initialize() def itemsBoundingRect_nogrid(self): self.remove_grid() r = self.scene.itemsBoundingRect() self.create_grid() return r def add_polygons(self, polygons, color='#A8F22A', alpha=1): qcolor = QColor() qcolor.setNamedColor(color) qcolor.setAlphaF(alpha) for points in polygons: qpoly = QPolygonF([QPointF(p[0], p[1]) for p in points]) scene_poly = self.scene.addPolygon(qpoly) scene_poly.setBrush(qcolor) scene_poly.setPen(self.pen) sr = self.itemsBoundingRect_nogrid() ymax = sr.top() xmin = sr.left() width = sr.width() height = sr.height() self.scene.setSceneRect( QRectF(xmin - 2 * width, ymax - 2 * height, width * 5, height * 5)) def reset_view(self): self.fitInView(self.itemsBoundingRect_nogrid(), Qt.KeepAspectRatio) self.update_grid() def add_port(self, port, is_subport=False): if (port.width is None) or (port.width == 0): x, y = port.midpoint cs = 1 # cross size pn = QPointF(x, y + cs) ps = QPointF(x, y - cs) pe = QPointF(x + cs, y) pw = QPointF(x - cs, y) qline1 = self.scene.addLine(QLineF(pn, ps)) qline2 = self.scene.addLine(QLineF(pw, pe)) port_shapes = [qline1, qline2] else: point1, point2 = port.endpoints point1 = QPointF(point1[0], point1[1]) point2 = QPointF(point2[0], point2[1]) qline = self.scene.addLine(QLineF(point1, point2)) arrow_points = np.array([[0, 0], [10, 0], [6, 4], [6, 2], [0, 2] ]) / (40) * port.width arrow_qpoly = QPolygonF( [QPointF(p[0], p[1]) for p in arrow_points]) port_scene_poly = self.scene.addPolygon(arrow_qpoly) port_scene_poly.setRotation(port.orientation) port_scene_poly.moveBy(port.midpoint[0], port.midpoint[1]) port_shapes = [qline, port_scene_poly] qtext = self.scene.addText(str(port.name), self.portfont) port_items = port_shapes + [qtext] rad = port.orientation * np.pi / 180 x, y = port.endpoints[0] * 1 / 4 + port.endpoints[ 1] * 3 / 4 + np.array([np.cos(rad), np.sin(rad)]) * port.width / 8 # x,y = port.midpoint[0], port.midpoint[1] # x,y = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2 qtext.setPos(QPointF(x, y)) qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations) if not is_subport: [shape.setPen(self.portpen) for shape in port_shapes] qtext.setDefaultTextColor(self.portfontcolor) self.portitems += port_items else: [shape.setPen(self.subportpen) for shape in port_shapes] qtext.setDefaultTextColor(self.subportfontcolor) self.subportitems += port_items # self.portlabels.append(qtext) def add_aliases(self, aliases): for name, ref in aliases.items(): qtext = self.scene.addText(str(name), self.portfont) x, y = ref.center qtext.setPos(QPointF(x, y)) qtext.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.aliasitems += [qtext] # x,y = port.midpoint[0], port.midpoint[1] # x,y = x - qtext.boundingRect().width()/2, y - qtext.boundingRect().height()/2 def set_port_visibility(self, visible=True): for item in self.portitems: item.setVisible(visible) self.ports_visible = visible def set_subport_visibility(self, visible=True): for item in self.subportitems: item.setVisible(visible) self.subports_visible = visible def set_alias_visibility(self, visible=True): for item in self.aliasitems: item.setVisible(visible) self.aliases_visible = visible def initialize(self): self.scene.clear() self.polygons = {} self.portitems = [] self.subportitems = [] self.aliasitems = [] self.aliases_visible = True self.ports_visible = True self.subports_visible = True self.create_grid() self.update_grid() #============================================================================== # Grid creation #============================================================================== def update_grid(self): grid_pixels = 50 grid_snaps = [1, 2, 4] # Number of pixels in the viewer view_width, view_height = self.rect().width(), self.rect().height() # Rectangle of viewport in terms of scene coordinates r = self.mapToScene(self.rect()).boundingRect() width, height = r.width(), r.height() xmin, ymin, xmax, ymax = r.x(), r.y(), r.x() + width, r.y() + height grid_size = grid_pixels * (width / view_width) exponent = np.floor(np.log10(grid_size)) digits = round(grid_size / 10**(exponent), 2) digits_snapped = min(grid_snaps, key=lambda x: abs(x - digits)) grid_size_snapped = digits_snapped * 10**(exponent) # Starting coordinates for gridlines x = round((xmin - 2 * width) / grid_size_snapped) * grid_size_snapped y = round((ymin - 2 * height) / grid_size_snapped) * grid_size_snapped # print('\n xmin = %s, xmax = %s, ymin = %s, ymax = %s' % (xmin, xmax, ymin, ymax)) # print('Starting at x = %s' % x) # print('Starting at y = %s' % y) for gl in self.gridlinesx: gl.setLine(x, -1e10, x, 1e10) x += grid_size_snapped for gl in self.gridlinesy: gl.setLine(-1e10, y, 1e10, y) y += grid_size_snapped def create_grid(self): self.gridlinesx = [ self.scene.addLine(-10, -10, 10, 10, self.gridpen) for n in range(200) ] self.gridlinesy = [ self.scene.addLine(-10, -10, 10, 10, self.gridpen) for n in range(200) ] self.update_grid() def remove_grid(self): for gl in self.gridlinesx + self.gridlinesy: self.scene.removeItem(gl) self.gridlinesx == [] self.gridlinesy == [] #============================================================================== # Mousewheel zoom, taken from http://stackoverflow.com/a/29026916 #============================================================================== def wheelEvent(self, event): # Zoom Factor zoom_percentage = 1.4 # Set Anchors self.setTransformationAnchor(QGraphicsView.NoAnchor) self.setResizeAnchor(QGraphicsView.NoAnchor) # Save the scene pos oldPos = self.mapToScene(event.pos()) # Zoom mousewheel_rotation = event.angleDelta().y( ) # Typically = 120 on most mousewheels zoom_factor = zoom_percentage**(mousewheel_rotation / 120) zoom_factor = np.clip(zoom_factor, 0.5, 2.0) # Check to make sure we're not overzoomed actual_rect = self.mapToScene(self.rect()) bbox_size = actual_rect[0] - actual_rect[2] actual_width = abs(bbox_size.x()) actual_height = abs(bbox_size.y()) max_width = abs(self.scene.sceneRect().x() * 3) max_height = abs(self.scene.sceneRect().y() * 3) min_width = 1 min_height = 1 if ((actual_width > max_width) or (actual_height > max_height)) and (zoom_factor < 1): pass elif ((actual_width < min_width) or (actual_height < min_height)) and (zoom_factor > 1): pass else: self.zoom_view(zoom_factor) # Get the new position and move scene to old position newPos = self.mapToScene(event.pos()) delta = newPos - oldPos self.translate(delta.x(), delta.y()) self.update_grid() def zoom_view(self, zoom_factor): self.scale(zoom_factor, zoom_factor) self.zoom_factor_total *= zoom_factor def mousePressEvent(self, event): #============================================================================== # Zoom to rectangle, from # https://wiki.python.org/moin/PyQt/Selecting%20a%20region%20of%20a%20widget #============================================================================== if event.button() == Qt.RightButton: self._mousePressed = Qt.RightButton self._rb_origin = QPoint(event.pos()) self.rubberBand.setGeometry(QRect(self._rb_origin, QSize())) self.rubberBand.show() #============================================================================== # Mouse panning, taken from # http://stackoverflow.com/a/15043279 #============================================================================== elif event.button() == Qt.MidButton: self._mousePressed = Qt.MidButton self._mousePressedPos = event.pos() self.setCursor(QtCore.Qt.ClosedHandCursor) self._dragPos = event.pos() def mouseMoveEvent(self, event): if not self._rb_origin.isNull( ) and self._mousePressed == Qt.RightButton: self.rubberBand.setGeometry( QRect(self._rb_origin, event.pos()).normalized()) if self._mousePressed == Qt.MidButton: newPos = event.pos() diff = newPos - self._dragPos self._dragPos = newPos self.horizontalScrollBar().setValue( self.horizontalScrollBar().value() - diff.x()) self.verticalScrollBar().setValue( self.verticalScrollBar().value() - diff.y()) # event.accept() def mouseReleaseEvent(self, event): if event.button() == Qt.RightButton: self.rubberBand.hide() rb_rect = QRect(self._rb_origin, event.pos()) rb_center = rb_rect.center() rb_size = rb_rect.size() if abs(rb_size.width()) > 3 and abs(rb_size.height()) > 3: viewport_size = self.viewport().geometry().size() zoom_factor_x = abs(viewport_size.width() / rb_size.width()) zoom_factor_y = abs(viewport_size.height() / rb_size.height()) new_center = self.mapToScene(rb_center) zoom_factor = min(zoom_factor_x, zoom_factor_y) self.zoom_view(zoom_factor) self.centerOn(new_center) self.update_grid() if event.button() == Qt.MidButton: self.setCursor(Qt.ArrowCursor) self._mousePressed = None self.update_grid() def keyPressEvent(self, event): if event.key() == Qt.Key_Escape: self.reset_view() if event.key() == Qt.Key_F1: self.set_alias_visibility(not self.aliases_visible) if event.key() == Qt.Key_F2: self.set_port_visibility(not self.ports_visible) if event.key() == Qt.Key_F3: self.set_subport_visibility(not self.subports_visible)
def init_graphicsView(self): """ graphicsView 初始化 : 1、画出基站矩阵 2、画出角点位置,将角点按顺时针连接 """ global scene scene = QGraphicsScene() self.graphicsView.setScene(scene) anchor = np.zeros((4,3), dtype=float) # anchor_1.x = 3.75 # 单位:米 for i in range(4): anchor[i][0] = np.float(self.anchorTable.item(i,1).text()) * 100 # 取 anchorTable 其中 cell 的值 anchor[i][1] = np.float(self.anchorTable.item(i,2).text()) * 100 anchor[i][2] = np.float(self.anchorTable.item(i,3).text()) * 100 # -------- 画出基站的四个顶点 ---------# anchor_brush = QBrush(QColor.fromRgb(120, 50, 255)) for i in range(4): scene.addEllipse( anchor[i][0]-8, anchor[i][1]-8, 15, 15, brush=anchor_brush) origin_x = anchor[0][0] origin_y = anchor[0][1] axis_x = anchor[1][0] axis_y = anchor[2][1] # ------- 画出 基站区域 --------# scene.addLine(origin_x, origin_y, axis_x, anchor[1][1], pen=QPen(Qt.green)) scene.addLine(origin_x, origin_y, anchor[2][0], axis_y, pen=QPen(Qt.green)) # ------- 画出x, y 轴 ---------# scene.addLine(origin_x, origin_y, axis_x + 20, origin_y, pen=QPen(Qt.red, 4)) scene.addLine(origin_x, origin_y, origin_x, axis_y + 20, pen=QPen(Qt.red, 4)) triangle_0 = [ QPoint(origin_x - 10, axis_y+ 20), QPoint(origin_x, axis_y +30), QPoint(origin_x + 10 , axis_y+ 20) ] # Y轴顶上三角形 triangle_1 = [ QPoint(axis_x + 20, origin_y - 10), QPoint(axis_x + 30, origin_y), QPoint(axis_x + 20, origin_y + 10) ] # X轴顶上三角形 scene.addPolygon(QPolygonF(triangle_0), pen=QPen(Qt.red, 4), brush=QBrush(Qt.red, Qt.SolidPattern)) scene.addPolygon(QPolygonF(triangle_1), pen=QPen(Qt.red, 4), brush=QBrush(Qt.red, Qt.SolidPattern)) # ------ 再画出所有角点------- # row_count = self.vertexTable.rowCount() vertex = np.zeros((row_count,3), dtype=float) # print("row count: " + str(row_count)) for i in range(row_count): vertex[i][0] = np.float(self.vertexTable.item(i,1).text()) / 10 # 取 vertexrTable 其中 cell 的值 vertex[i][1] = np.float(self.vertexTable.item(i,2).text()) / 10 vertex[i][2] = np.float(self.vertexTable.item(i,3).text()) / 10 vertex_brush = QBrush(QColor.fromRgb(250, 244, 8)) # 红(250) 绿(244) 蓝(8) for i in range(row_count): scene.addEllipse( vertex[i][0]-4, vertex[i][1]-4, 8, 8, brush=vertex_brush) if i != row_count -1 : scene.addLine(vertex[i][0], vertex[i][1], vertex[i+1][0], vertex[i+1][1], pen=QPen(Qt.blue)) else: scene.addLine(vertex[i][0], vertex[i][1], vertex[0][0], vertex[0][1], pen=QPen(Qt.blue)) # 再画出砖块 global brick_width, brick_height brick_width = int(self.brick_width_textEdit.toPlainText()) / 10 # 砖长:300mm brick_height = int(self.brick_length_textEdit.toPlainText()) / 10 self.brick_gap = int(self.brick_gap_textEdit.toPlainText()) / 10 # 砖间隙:5mm global height_num, width_num height_num = np.int(axis_y/brick_height) width_num = np.int(axis_x/brick_width) return axis_x, axis_y # 返回长宽
class MyWin(QtWidgets.QMainWindow): osc_ip = "127.0.0.1" osc_port = 9023 osc_client = SimpleUDPClient(osc_ip, osc_port) # Create client streams = resolve_stream('name', 'EEG') # first resolve an EEG stream on the lab network print("looking for an EEG stream...") # create a new inlet to read from the stream inlet = StreamInlet(streams[0]) timer = QtCore.QTimer() plot_timer = QtCore.QTimer() active_channels = [ ] # array of "active" channels - used for averaged signal samp_rate = 500 # sampling rate n_points = 0 # number of obtained points buffer_size = 0.5 # seconds, size of buffer buffer_vals = np.zeros(int(buffer_size * samp_rate)) buffer_channels = [] for i in range(24): buffer_channels.append(np.zeros(int(buffer_size * samp_rate))) fdb = open("delta_band.csv", "w") ftb = open("theta_band.csv", "w") fab = open("alpha_band.csv", "w") fbb = open("beta_band.csv", "w") fgb = open("gamma_band.csv", "w") fhgb = open("hgamma_band.csv", "w") timestmp = 0 num_active_chan = 24 average_val = 0 # averaged value - used for relative power and attention estimation for i in range(24): active_channels.append(1) attention_estimation_points = 5 # number of points for attention estimation relpower_arrays_size = 20 # size of array for storing relative power values theta_relpower = [] beta_relpower = [] alpharelpow = 0 gammarelpow = 0 attention_val = 0 attention_source_ind = 0 # for average alpha_source_ind = 0 # for average attention_val_fromchannel = 0 alpha_val_fromchannel = 0 theta_relpower_fromchan = [] beta_relpower_fromchan = [] polygon = QPolygonF() #plotting variables size = 50 x_vec = np.linspace(0, 50, size + 1)[0:-1] y_vec = np.random.randn(len(x_vec)) line1 = [] # for motor imagery motor_imagery_out = 0 # positive values reflect left hand imagery, negative values right hand n_output_integrate = 8 # how many motor imagery classifier outputs to integrate pred_buffer = np.zeros(n_output_integrate + 1) motor_imagery_out_save = [] # for debugging # set filter coefficients sfreq = 500 # or user already existing variable that specifies the sampling rate b_bp, a_bp = butter(2, np.array([8, 30]) / sfreq * 2, 'bandpass') zi_previous_bp = [] for i in range(24): zi_previous_bp.append(lfilter_zi(b_bp, a_bp)) zi_previous_bp = np.array(zi_previous_bp) b_pred, a_pred = butter(2, np.array([0.15]) / (sfreq / (sfreq * buffer_size)) * 2, 'lowpass') # adapted to sampling rate of buffer zi_previous_pred = lfilter_zi(b_pred, a_pred) def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.setGeometry(500, 200, 900, 580) self.ui.pushButton.clicked.connect(self.startprocessing) self.ui.pushButton.setGeometry(QtCore.QRect(50, 510, 120, 28)) self.ui.pushButton_2.clicked.connect(self.ext) self.ui.pushButton_2.setGeometry(QtCore.QRect(740, 510, 70, 28)) self.ui.pushButton_3.clicked.connect( partial(self.update_allchans, True)) self.ui.pushButton_5.clicked.connect(self.drawturtle) self.ui.pushButton_5.setVisible(False) self.ui.pushButton_6.clicked.connect(self.startdrawstream) self.ui.pushButton_6.setText("Plot Average signal") self.ui.pushButton_6.setGeometry(QtCore.QRect(180, 510, 140, 28)) self.ui.pushButton_4.clicked.connect( partial(self.update_allchans, False)) self.ui.doubleSpinBox.setValue(self.buffer_size) self.ui.comboBox.currentIndexChanged.connect( self.on_attentionsource_box_changed) self.ui.comboBox_2.currentIndexChanged.connect( self.on_alphasource_box_changed) self.scene = QGraphicsScene(self) self.scene.setBackgroundBrush(QBrush(QColor(0, 0, 0, 255))) self.ui.graphicsView.setScene(self.scene) self.ui.graphicsView.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.ui.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.ui.graphicsView.setFrameStyle(0) self.back_brush = QBrush(Qt.gray) self.shape_brush = QBrush(Qt.darkGreen) self.pen = QPen(Qt.green) self.ui.graphicsView.setBackgroundBrush(self.back_brush) self.drawshapes() self.ui.checkBox.stateChanged.connect(self.update_activechannels) self.ui.checkBox_2.stateChanged.connect(self.update_activechannels) self.ui.checkBox_3.stateChanged.connect(self.update_activechannels) self.ui.checkBox_4.stateChanged.connect(self.update_activechannels) self.ui.checkBox_5.stateChanged.connect(self.update_activechannels) self.ui.checkBox_6.stateChanged.connect(self.update_activechannels) self.ui.checkBox_7.stateChanged.connect(self.update_activechannels) self.ui.checkBox_8.stateChanged.connect(self.update_activechannels) self.ui.checkBox_9.stateChanged.connect(self.update_activechannels) self.ui.checkBox_10.stateChanged.connect(self.update_activechannels) self.ui.checkBox_11.stateChanged.connect(self.update_activechannels) self.ui.checkBox_12.stateChanged.connect(self.update_activechannels) self.ui.checkBox_13.stateChanged.connect(self.update_activechannels) self.ui.checkBox_14.stateChanged.connect(self.update_activechannels) self.ui.checkBox_15.stateChanged.connect(self.update_activechannels) self.ui.checkBox_16.stateChanged.connect(self.update_activechannels) self.ui.checkBox_17.stateChanged.connect(self.update_activechannels) self.ui.checkBox_18.stateChanged.connect(self.update_activechannels) self.ui.checkBox_19.stateChanged.connect(self.update_activechannels) self.ui.checkBox_20.stateChanged.connect(self.update_activechannels) self.ui.checkBox_21.stateChanged.connect(self.update_activechannels) self.ui.checkBox_22.stateChanged.connect(self.update_activechannels) self.ui.checkBox_23.stateChanged.connect(self.update_activechannels) self.ui.checkBox_24.stateChanged.connect(self.update_activechannels) self.timer.timeout.connect(self.updatedata) self.plot_timer.timeout.connect(self.drawstream) def on_attentionsource_box_changed(self, value): self.attention_source_ind = value def on_alphasource_box_changed(self, value): self.alpha_source_ind = value def drawshapes(self): # self.scene.addEllipse(20,20,200,200,self.pen,self.shape_brush) self.scene.clear() self.polygon.clear() x = y = t = 0 npoints = int(self.attention_val * 10) + 3 radius = int(self.attention_val * 10) * 15 + 20 for i in range(npoints): t = 2 * math.pi * (float(i) / npoints + 0.5) x = 100 + math.cos(t) * radius y = 100 + math.sin(t) * radius self.polygon.append(QPointF(x, y)) self.scene.addPolygon( self.polygon, self.pen, QColor(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), int(100 + self.attention_val * 10))) def on_liveplot_close(self, event): self.plot_timer.stop() def live_plotter(self, x_vec, y1_data, line1, identifier='', pause_time=0.1): if line1 == []: # this is the call to matplotlib that allows dynamic plotting #plt.ion() fig = plt.figure(figsize=(9, 2)) fig.canvas.mpl_connect('close_event', self.on_liveplot_close) ax = fig.add_subplot(111) # create a variable for the line so we can later update it line1, = ax.plot(x_vec, y1_data, '-o', alpha=0.8) #update plot label/title plt.ylabel('Raw Value') plt.xticks([]) plt.title('{}'.format(identifier)) plt.show() # after the figure, axis, and line are created, we only need to update the y-data line1.set_ydata(y1_data) # adjust limits if new data goes beyond bounds #if np.min(y1_data)<=line1.axes.get_ylim()[0] or np.max(y1_data)>=line1.axes.get_ylim()[1]: plt.ylim([ np.min(y1_data) - np.std(y1_data), np.max(y1_data) + np.std(y1_data) ]) # this pauses the data so the figure/axis can catch up - the amount of pause can be altered above plt.pause(pause_time) # return line so we can update it again in the next iteration return line1 def startprocessing(self): self.timer.start(1) def startdrawstream(self): self.line1 = [] self.plot_timer.start(10) def drawstream(self): self.y_vec[-1] = self.average_val self.line1 = self.live_plotter(self.x_vec, self.y_vec, self.line1, "Average raw signal") self.y_vec = np.append(self.y_vec[1:], 0.0) def drawturtle(self): import turtle MINIMUM_BRANCH_LENGTH = 5 def build_tree(t, branch_length, shorten_by, angle): if branch_length > MINIMUM_BRANCH_LENGTH: t.speed(int(self.alpharelpow * 100) + 1) t.forward(branch_length) new_length = branch_length - shorten_by t.left(angle) build_tree(t, new_length, shorten_by, angle) t.right(angle * 2) build_tree(t, new_length, shorten_by, angle) t.left(angle) t.backward(branch_length) tree = turtle.Turtle() # tree.speed(100) tree.hideturtle() tree.setheading(90) tree.color('green') build_tree(tree, 50, 5, 30) turtle.mainloop() def update_allchans(self, flag): self.ui.checkBox.setChecked(flag) self.ui.checkBox_2.setChecked(flag) self.ui.checkBox_3.setChecked(flag) self.ui.checkBox_4.setChecked(flag) self.ui.checkBox_5.setChecked(flag) self.ui.checkBox_6.setChecked(flag) self.ui.checkBox_7.setChecked(flag) self.ui.checkBox_8.setChecked(flag) self.ui.checkBox_9.setChecked(flag) self.ui.checkBox_10.setChecked(flag) self.ui.checkBox_11.setChecked(flag) self.ui.checkBox_12.setChecked(flag) self.ui.checkBox_13.setChecked(flag) self.ui.checkBox_14.setChecked(flag) self.ui.checkBox_15.setChecked(flag) self.ui.checkBox_16.setChecked(flag) self.ui.checkBox_17.setChecked(flag) self.ui.checkBox_18.setChecked(flag) self.ui.checkBox_19.setChecked(flag) self.ui.checkBox_20.setChecked(flag) self.ui.checkBox_21.setChecked(flag) self.ui.checkBox_22.setChecked(flag) self.ui.checkBox_23.setChecked(flag) self.ui.checkBox_24.setChecked(flag) self.update_activechannels() def update_activechannels(self): self.active_channels[0] = self.ui.checkBox.isChecked() self.active_channels[1] = self.ui.checkBox_2.isChecked() self.active_channels[2] = self.ui.checkBox_3.isChecked() self.active_channels[3] = self.ui.checkBox_4.isChecked() self.active_channels[4] = self.ui.checkBox_5.isChecked() self.active_channels[5] = self.ui.checkBox_6.isChecked() self.active_channels[6] = self.ui.checkBox_7.isChecked() self.active_channels[7] = self.ui.checkBox_8.isChecked() self.active_channels[8] = self.ui.checkBox_9.isChecked() self.active_channels[9] = self.ui.checkBox_10.isChecked() self.active_channels[10] = self.ui.checkBox_11.isChecked() self.active_channels[11] = self.ui.checkBox_12.isChecked() self.active_channels[12] = self.ui.checkBox_13.isChecked() self.active_channels[13] = self.ui.checkBox_14.isChecked() self.active_channels[14] = self.ui.checkBox_15.isChecked() self.active_channels[15] = self.ui.checkBox_16.isChecked() self.active_channels[16] = self.ui.checkBox_17.isChecked() self.active_channels[17] = self.ui.checkBox_18.isChecked() self.active_channels[18] = self.ui.checkBox_19.isChecked() self.active_channels[19] = self.ui.checkBox_20.isChecked() self.active_channels[20] = self.ui.checkBox_21.isChecked() self.active_channels[21] = self.ui.checkBox_22.isChecked() self.active_channels[22] = self.ui.checkBox_23.isChecked() self.active_channels[23] = self.ui.checkBox_24.isChecked() self.num_active_chan = sum(self.active_channels) def bandpower(self, data, sf, band, window_sec=None, relative=False): """Compute the average power of the signal x in a specific frequency band. https://raphaelvallat.com/bandpower.html Parameters ---------- data : 1d-array Input signal in the time-domain. sf : float Sampling frequency of the data. band : list Lower and upper frequencies of the band of interest. window_sec : float Length of each window in seconds. If None, window_sec = (1 / min(band)) * 2 relative : boolean If True, return the relative power (= divided by the total power of the signal). If False (default), return the absolute power. Return ------ bp : float Absolute or relative band power. """ from scipy.signal import welch from scipy.integrate import simps band = np.asarray(band) low, high = band # Define window length if window_sec is not None: nperseg = window_sec * sf else: nperseg = (2 / low) * sf # Compute the modified periodogram (Welch) freqs, psd = welch(data, sf, nperseg=nperseg) # Frequency resolution freq_res = freqs[1] - freqs[0] # Find closest indices of band in frequency vector idx_band = np.logical_and(freqs >= low, freqs <= high) # Integral approximation of the spectrum using Simpson's rule. bp = simps(psd[idx_band], dx=freq_res) if relative and simps(psd, dx=freq_res) > 0: bp /= simps(psd, dx=freq_res) else: return 0 return bp def apply_csp_lda_online(self): # retrieve data signal_tmp = np.array(self.buffer_channels) # filter incoming signal (and use previous filter state) for i in range(24): signal_tmp[i, ], self.zi_previous_bp[i, ] = lfilter( self.b_bp, self.a_bp, signal_tmp[i, ], axis=-1, zi=self.zi_previous_bp[i, ]) # scale signal (depending on input; signal range should be around +-25 µV) signal_tmp = signal_tmp / 10**6 # bring data into right format signal_tmp = np.expand_dims( signal_tmp, 0 ) # dimensions for CSP: epochs x channels x samples (1,24,n_samples_integrate) # load CSP+LDA from training (pre-allocate this to class MyWin? self.csp = ...) csp = load('csp_stored.joblib') lda = load('lda_stored.joblib') # apply CSP filters + LDA fea_tmp = csp.transform(signal_tmp) pred_tmp = lda.decision_function(fea_tmp) # put in array for prediction values # pred_cont.append(list(pred_tmp)) # pred_cont = pred_cont[-n_output_integrate:] # only keep last values in buffer self.pred_buffer[:self.n_output_integrate] = self.pred_buffer[ -self.n_output_integrate:] # shift to the left by one self.pred_buffer[ self.n_output_integrate] = pred_tmp # add prediction of this loop # (actually, the buffer for the prediction output is not needed if we just low-pass filter but let´s keep it for now in case we switch to a moving average) # low-pass filter classifier outputs self.motor_imagery_out, self.zi_previous_pred = lfilter( self.b_pred, self.a_pred, pred_tmp, axis=-1, zi=self.zi_previous_pred) print(self.motor_imagery_out) self.osc_client.send_message("/motor_imagery", self.motor_imagery_out) self.motor_imagery_out_save.append( self.motor_imagery_out) # for debugging def update_freqbandspower_allchans(self): win_sec = self.buffer_size self.fdb.write("{0:4.1f}".format(self.timestmp) + ',') self.ftb.write("{0:4.1f}".format(self.timestmp) + ',') self.fab.write("{0:4.1f}".format(self.timestmp) + ',') self.fbb.write("{0:4.1f}".format(self.timestmp) + ',') self.fgb.write("{0:4.1f}".format(self.timestmp) + ',') self.fhgb.write("{0:4.1f}".format(self.timestmp) + ',') for i in range(24): db_rel = self.bandpower(self.buffer_channels[i], self.samp_rate, [0.5, 4], win_sec, True) tb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate, [4, 8], win_sec, True) ab_rel = self.bandpower(self.buffer_channels[i], self.samp_rate, [8, 12], win_sec, True) bb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate, [12, 27], win_sec, True) gb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate, [27, 60], win_sec, True) hgb_rel = self.bandpower(self.buffer_channels[i], self.samp_rate, [60, self.samp_rate / 2], win_sec, True) endch = ',' if (i == 23): endch = '' self.fdb.write("{0:4.3f}".format(db_rel) + endch) self.ftb.write("{0:4.3f}".format(tb_rel) + endch) self.fab.write("{0:4.3f}".format(ab_rel) + endch) self.fbb.write("{0:4.3f}".format(bb_rel) + endch) self.fgb.write("{0:4.3f}".format(gb_rel) + endch) self.fhgb.write("{0:4.3f}".format(hgb_rel) + endch) if i == self.alpha_source_ind - 1: self.alpha_val_fromchannel = ab_rel self.ui.progressBar_3.setValue( round(self.alpha_val_fromchannel * 100)) self.ui.lineEdit_32.setText( str(int(self.alpha_val_fromchannel * 100)) + "%") if i == self.attention_source_ind - 1: self.update_attention_fromchan(tb_rel, bb_rel) #print("{0:4.2f},{1:4.2f},{2:4.2f},{3:4.2f},{4:4.2f},{5:4.2f}".format(db_rel, tb_rel, ab_rel, bb_rel, gb_rel, hgb_rel)) self.fdb.write('\n') self.ftb.write('\n') self.fab.write('\n') self.fbb.write('\n') self.fgb.write('\n') self.fhgb.write('\n') self.fdb.flush() self.ftb.flush() self.fab.flush() self.fbb.flush() self.fgb.flush() self.fhgb.flush() def update_freqbandspower(self): if self.num_active_chan == 0: return win_sec = self.buffer_size db_rel = self.bandpower(self.buffer_vals, self.samp_rate, [0.5, 4], win_sec, True) tb_rel = self.bandpower(self.buffer_vals, self.samp_rate, [4, 8], win_sec, True) ab_rel = self.bandpower(self.buffer_vals, self.samp_rate, [8, 12], win_sec, True) bb_rel = self.bandpower(self.buffer_vals, self.samp_rate, [12, 27], win_sec, True) gb_rel = self.bandpower(self.buffer_vals, self.samp_rate, [27, 60], win_sec, True) hgb_rel = self.bandpower(self.buffer_vals, self.samp_rate, [60, self.samp_rate / 2], win_sec, True) sum_rel = db_rel + tb_rel + ab_rel + bb_rel + gb_rel + hgb_rel self.alpharelpow = ab_rel self.gammarelpow = gb_rel # print("{0:4.2f},{1:4.2f},{2:4.2f},{3:4.2f},{4:4.2f},{5:4.2f},{6:4.2f}".format(db_rel, tb_rel, ab_rel, bb_rel, # gb_rel, hgb_rel, sum_rel)) self.update_attention(tb_rel, bb_rel) self.ui.progressBar.setValue(round(db_rel * 100)) self.ui.lineEdit_30.setText(str(int(db_rel * 100)) + "%") self.ui.progressBar_2.setValue(round(tb_rel * 100)) self.ui.lineEdit_31.setText(str(int(tb_rel * 100)) + "%") if self.alpha_source_ind == 0: self.ui.progressBar_3.setValue(round(ab_rel * 100)) self.ui.lineEdit_32.setText(str(int(ab_rel * 100)) + "%") self.ui.progressBar_4.setValue(round(bb_rel * 100)) self.ui.lineEdit_33.setText(str(int(bb_rel * 100)) + "%") self.ui.progressBar_5.setValue(round(gb_rel * 100)) self.ui.lineEdit_34.setText(str(int(gb_rel * 100)) + "%") self.ui.progressBar_6.setValue(round(hgb_rel * 100)) self.ui.lineEdit_35.setText(str(int(hgb_rel * 100)) + "%") # self.buffer_vals = np.zeros(self.samp_rate) def update_rawchannels(self, sample, timestamp): self.ui.lineEdit.setText(str(round(sample[0]))) self.ui.lineEdit_2.setText(str(round(sample[1]))) self.ui.lineEdit_3.setText(str(round(sample[2]))) self.ui.lineEdit_4.setText(str(round(sample[3]))) self.ui.lineEdit_5.setText(str(round(sample[4]))) self.ui.lineEdit_6.setText(str(round(sample[5]))) self.ui.lineEdit_7.setText(str(round(sample[6]))) self.ui.lineEdit_8.setText(str(round(sample[7]))) self.ui.lineEdit_9.setText(str(round(sample[8]))) self.ui.lineEdit_10.setText(str(round(sample[9]))) self.ui.lineEdit_11.setText(str(round(sample[10]))) self.ui.lineEdit_12.setText(str(round(sample[11]))) self.ui.lineEdit_13.setText(str(round(sample[12]))) self.ui.lineEdit_14.setText(str(round(sample[13]))) self.ui.lineEdit_15.setText(str(round(sample[14]))) self.ui.lineEdit_16.setText(str(round(sample[15]))) self.ui.lineEdit_17.setText(str(round(sample[16]))) self.ui.lineEdit_18.setText(str(round(sample[17]))) self.ui.lineEdit_19.setText(str(round(sample[18]))) self.ui.lineEdit_20.setText(str(round(sample[19]))) self.ui.lineEdit_21.setText(str(round(sample[20]))) self.ui.lineEdit_22.setText(str(round(sample[21]))) self.ui.lineEdit_23.setText(str(round(sample[22]))) self.ui.lineEdit_24.setText(str(round(sample[23]))) self.ui.lineEdit_25.setText(str(round(sample[24]))) self.ui.lineEdit_26.setText(str(round(sample[25]))) self.ui.lineEdit_27.setText(str(round(sample[26]))) self.osc_client.send_message("/gyro/x", round(sample[24])) self.osc_client.send_message("/gyro/y", round(sample[25])) self.osc_client.send_message("/gyro/z", round(sample[26])) self.ui.lineEdit_28.setText(str(round(timestamp))) self.osc_client.send_message("/timestamp", round(timestamp)) def update_attention_fromchan(self, tb_rel, bb_rel): self.theta_relpower_fromchan.append(tb_rel) self.beta_relpower_fromchan.append(bb_rel) if len(self.theta_relpower_fromchan) == self.relpower_arrays_size: self.theta_relpower_fromchan.pop(0) self.beta_relpower_fromchan.pop(0) if len(self.theta_relpower_fromchan ) < self.attention_estimation_points: if bb_rel < 0.01: bb_rel = 0.01 self.attention_val_fromchannel = (1 - tb_rel / bb_rel) else: thetv = 0 betav = 0 for i in range(self.attention_estimation_points): thetv += self.theta_relpower_fromchan[ len(self.theta_relpower_fromchan) - i - 1] betav += self.beta_relpower_fromchan[ len(self.beta_relpower_fromchan) - i - 1] thetv /= self.attention_estimation_points betav /= self.attention_estimation_points self.attention_val_fromchannel = (1 - thetv / betav) if self.attention_val_fromchannel > 1: self.attention_val_fromchannel = 1 elif self.attention_val_fromchannel < 0: self.attention_val_fromchannel = 0 #print(self.attention_val_fromchannel) def update_attention(self, tb_rel, bb_rel): if self.num_active_chan == 0: return self.theta_relpower.append(tb_rel) self.beta_relpower.append(bb_rel) if len(self.theta_relpower) == self.relpower_arrays_size: self.theta_relpower.pop(0) self.beta_relpower.pop(0) if len(self.theta_relpower) < self.attention_estimation_points: if bb_rel < 0.01: bb_rel = 0.01 self.attention_val = (1 - tb_rel / bb_rel) else: thetv = 0 betav = 0 for i in range(self.attention_estimation_points): thetv += self.theta_relpower[len(self.theta_relpower) - i - 1] betav += self.beta_relpower[len(self.beta_relpower) - i - 1] thetv /= self.attention_estimation_points betav /= self.attention_estimation_points self.attention_val = (1 - thetv / betav) #print(self.attention_val) if self.attention_val > 1: self.attention_val = 1 elif self.attention_val < 0: self.attention_val = 0 if self.attention_source_ind == 0: self.ui.progressBar_7.setValue(round(self.attention_val * 100)) self.osc_client.send_message("/eeg/attention", int(self.attention_val * 100)) else: self.ui.progressBar_7.setValue( round(self.attention_val_fromchannel * 100)) self.osc_client.send_message( "/eeg/attention", int(self.attention_val_fromchannel * 100)) #print(int(self.attention_val * 100)) if self.alpha_source_ind == 0: self.osc_client.send_message("/eeg/alpha", int(self.alpharelpow * 100)) else: self.osc_client.send_message("/eeg/alpha", int(self.alpha_val_fromchannel * 100)) #print(int(self.alpharelpow * 100)) self.osc_client.send_message("/eeg/gamma", int(self.gammarelpow * 100)) def updatedata(self): sample, timestamp = self.inlet.pull_sample() self.timestmp = timestamp self.average_val = 0 for i in range(24): if self.active_channels[i] == 1: self.average_val += sample[i] self.buffer_channels[i][self.n_points] = sample[i] if self.num_active_chan > 0: self.average_val /= self.num_active_chan else: self.average_val = 0 self.buffer_vals[self.n_points] = self.average_val self.n_points += 1 self.osc_client.send_message("/eeg/raw", self.average_val) if self.n_points == self.buffer_size * self.samp_rate: self.update_rawchannels(sample, timestamp) self.update_freqbandspower() self.update_freqbandspower_allchans() self.apply_csp_lda_online() self.drawshapes() self.ui.lineEdit_29.setText(str(round(self.average_val))) self.n_points = 0 self.buffer_size = self.ui.doubleSpinBox.value() self.buffer_vals = np.zeros(int(self.buffer_size * self.samp_rate)) for i in range(24): self.buffer_channels[i] = np.zeros( int(self.buffer_size * self.samp_rate)) def ext(self): """ exit the application """ self.plot_timer.stop() self.timer.stop() self.fdb.close() self.ftb.close() self.fab.close() self.fbb.close() self.fgb.close() self.fhg.close() sys.exit()
class view(QGraphicsView): def __init__(self): super().__init__() self.title = "mainWindow" self.top = 0 self.left = 0 self.width = 1400 self.height = 800 self.scene = QGraphicsScene(0, 0, self.width, self.height) self.container_margin = 120 self.container_max_height = 0 self.rel_width = 70 * 2 self.rel_height = 40 * 2 self.r_atr_h = 30 self.r_atr_w = 80 self.r_atr_line = 50 self.rel_pen = QPen(Qt.black, 3, Qt.SolidLine) self.rel_Brush = QBrush(QColor(255, 204, 153), Qt.SolidPattern) self.level = 100 # self.setBackgroundBrush(QBrush(Qt.darkGray,Qt.CrossPattern)) self.InitWindow() def InitWindow(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.setScene(self.scene) self.setDragMode(QGraphicsView.ScrollHandDrag) self.setRenderHint(QPainter.Antialiasing) self.setRenderHint(QPainter.TextAntialiasing) def add_Ens(self, e_list): self.item_list = [] self.data = e_list for i in range(0, len(e_list)): self.item_list.append( ContainerItem(e_list[i], QPointF(500, 500), self.scene)) if self.item_list[-1].container_height > self.container_max_height: self.container_max_height = self.item_list[-1].container_height cur_x = self.item_list[0].attribute_width / 2 cur_y = self.container_max_height self.level = cur_y + self.item_list[0].entity_height + self.rel_height for j in range(0, len(self.item_list)): self.item_list[j].en_shape.setPos(cur_x, cur_y) cur_x += self.item_list[0].container_width + self.container_margin if (cur_x + self.item_list[0].container_width > self.scene.width()): self.width += self.item_list[0].container_width self.scene.setSceneRect(QRectF(0, 0, self.width, self.height)) # self.gen.widget().setGeometry(self.width-self.gen.widget().width(), self.height-self.gen.widget().height(), self.gen.widget().width(), self.gen.widget().height()) for k in range(0, len(e_list)): for n in range(0, len(e_list[k].relations)): if (self.get_index(e_list[k].relations[n].getTargetEntity( e_list[k])) >= k): start = self.item_list[k].en_shape.x( ) + self.item_list[k].entity_width self.add_relation(start, e_list[k].relations[n]) self.item_list[k].connect_relation( start, self.level, e_list[k].relations[n].p_type1) self.item_list[self.get_index( e_list[k].relations[n].getTargetEntity( e_list[k]))].connect_relation( start + self.rel_width, self.level, e_list[k].relations[n].p_type1) self.level += self.rel_height + 10 if (self.level + self.rel_height / 2 >= self.scene.height()): self.height = self.level + self.rel_height / 2 self.scene.setSceneRect( QRectF(0, 0, self.width, self.height)) def get_data(self): return self.data def add_relation(self, x, r): if (len(r.attrib_list) != 0): self.level += self.rel_height / 2 + self.r_atr_h * ( len(r.attrib_list) - 1) + self.r_atr_line Qpoints = [ QPointF(x, self.level), QPointF(x + self.rel_width / 2, self.level + self.rel_height / 2), QPointF(x + self.rel_width, self.level), QPointF(x + self.rel_width / 2, self.level - self.rel_height / 2) ] rel_shape = self.scene.addPolygon(QPolygonF(Qpoints), self.rel_pen, self.rel_Brush) rel_name = self.scene.addWidget(QLineEdit()) left_p = self.scene.addWidget(QLineEdit()) right_p = self.scene.addWidget(QLineEdit()) #rel_name.setParentItem(rel_shape) rel_name.setGeometry(QRectF(0, 0, self.rel_width / 2, 3)) left_p.setGeometry(QRectF(0, 0, 0, 0)) right_p.setGeometry(QRectF(0, 0, 0, 0)) left_p.widget().setFixedWidth(43) right_p.widget().setFixedWidth(43) rel_name.setPos(x + self.rel_width / 4, self.level - rel_name.widget().height() / 2) left_p.setPos(x - left_p.widget().width(), self.level - left_p.widget().height()) right_p.setPos(x + self.rel_width, self.level - right_p.widget().height()) rel_name.widget().setText(r.name) left_p.widget().setText(r.p_ratio1) right_p.widget().setText(r.p_ratio2) rel_name.widget().editingFinished.connect( partial(self.mod, "n", r, rel_name.widget())) left_p.widget().editingFinished.connect( partial(self.mod, "l", r, left_p.widget())) right_p.widget().editingFinished.connect( partial(self.mod, "r", r, right_p.widget())) atr_step = ((self.rel_width - 2 * right_p.widget().width() - 10) / (len(r.attrib_list) - 1)) if len(r.attrib_list) > 1 else 0 ten = (Qpoints[0].y() - Qpoints[3].y()) / (Qpoints[0].x() - Qpoints[3].x()) for i in range(len(r.attrib_list)): first_pt = QPointF( Qpoints[0].x() + i * atr_step + right_p.widget().width() + 10, self.get_y_line( Qpoints[0].x() + i * atr_step + right_p.widget().width() + 10, Qpoints[0], ten)) if (first_pt.x() > Qpoints[3].x()): first_pt.setY( self.get_y_line(first_pt.x(), Qpoints[3], -1 * ten)) atr_line = self.scene.addLine( first_pt.x(), first_pt.y(), first_pt.x(), Qpoints[3].y() - self.r_atr_line - i * self.r_atr_h) elip_pt = QPointF(first_pt.x() - self.r_atr_w / 2, atr_line.line().y2() - self.r_atr_h) atr_elipse = self.scene.addEllipse( QRectF(0, 0, self.r_atr_w, self.r_atr_h), self.rel_pen, self.rel_Brush) txt = [] txt.append(self.scene.addWidget(QLineEdit(r.attrib_list[i].name))) atr_elipse.setPos(elip_pt) txt[-1].setPos(elip_pt.x() + self.rel_width * 0.25, elip_pt.y() + self.r_atr_h * 0.125) txt[-1].widget().setFixedWidth(self.r_atr_w * 0.5) txt[-1].widget().setFixedHeight(self.r_atr_h * 0.75) txt[-1].widget().editingFinished.connect( partial(self.mod, "c", r, txt[-1].widget(), i)) def get_y_line(self, x, p1, ten): return (x - p1.x()) * ten + p1.y() def get_index(self, id): for i in range(0, len(self.item_list)): if (id == self.item_list[i].entity.id): return i def mod(self, type, r, w, child=-1): if type == "n": r.name = w.text() elif type == 'l': r.p_ratio1 = w.text() elif type == 'r': r.p_ratio2 = w.text() elif type == 'c': r.attrib_list[child].name = w.text()
class MainWindow(QWidget): def __init__(self): super().__init__() self.line_edit = QLineEdit() data = dict(json.load(open('description.json'))) self.conditions = dict( (key, data[key]) for key in data.keys()) # { состояние :{{переходы}, {координаты}, for key in self.conditions.keys( ): # флаг(конечное состояние), объекты на сцене, текст сигналов},...} self.conditions[key]["scene_items"] = [] self.conditions[key]["text"] = {} self.signals = {} # входные сигналы self.setGeometry(0, 0, 1000, 650) self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 1000, 570) self.view = QGraphicsView(self.scene, self) self.view.show() self.configure_scene() def configure_scene(self): self.add_jump() self.add_conditions() self.add_signals() self.line_edit.setGeometry(50, 500, 800, 50) self.line_edit.textChanged.connect(self.slot) self.scene.addWidget(self.line_edit) def slot(self): # слот при изменения machine = Machine.Machine(self.line_edit.text()) current_condition = machine.start() machine = Machine.Machine(self.line_edit.text()[:-1]) prev_condition = machine.start() for key in self.conditions.keys(): self.change_color_of_circle(key, QColor(192, 192, 192)) for k in self.conditions[key]["text"]: self.conditions[key]["text"][k].setDefaultTextColor( QColor(0, 0, 0)) if current_condition[0]: self.change_color_of_circle(current_condition[1], QColor(50, 205, 50)) if current_condition[1] in self.conditions[ prev_condition[1]]["text"].keys(): self.conditions[prev_condition[1]]["text"][ current_condition[1]].setDefaultTextColor( QColor(50, 205, 50)) else: self.change_color_of_circle(current_condition[1], QColor(255, 50, 50)) def change_color_of_circle(self, cond, color): for item in self.conditions[cond]["scene_items"]: item.setBrush(color) def add_conditions(self): # добавляет состояния автомата for key in self.conditions.keys(): x = int(self.conditions[key]["coord"]['x']) y = int(self.conditions[key]["coord"]['y']) r = int(self.conditions[key]["coord"]['r']) self.paint_circle(x, y, r, key) for item in self.conditions['s0'][ "scene_items"]: # закрашиваем начальное состояние item.setBrush(QColor(50, 205, 50)) def paint_circle(self, x, y, r, name): # добавляет круг на сцену ell = QGraphicsEllipseItem( x - r // 2, y - r // 2, r, r) # поправка смещения(в qt x,y - правый левый угол) ell.setBrush(QColor(192, 192, 192)) self.scene.addItem(ell) self.conditions[name]["scene_items"].append(ell) if self.conditions[name]["is_final"] == 'yes': ell = QGraphicsEllipseItem(x - r // 2 + r // 10, y - r // 2 + r // 10, r - r // 5, r - r // 5) ell.setBrush(QColor(192, 192, 192)) self.scene.addItem(ell) self.conditions[name]["scene_items"].append(ell) text_item = QGraphicsTextItem(name) text_item.moveBy(x - 11, y - 12) self.scene.addItem(text_item) def add_jump(self): # добавляет переходы for key in self.conditions.keys(): # цикл по всем состояниям exist_jumps = [] r1 = int(self.conditions[key]["coord"]['r']) x1 = int(self.conditions[key]["coord"]['x']) y1 = int(self.conditions[key]["coord"]['y']) for state in self.conditions[key]["jump"].values( ): # цикл по всем переходам из текущего состояния r2 = int(self.conditions[state]["coord"]['r']) x2 = int(self.conditions[state]["coord"]['x']) y2 = int(self.conditions[state]["coord"]['y']) if key == state and state not in exist_jumps: self.add_arc(x1, y1, r1) exist_jumps.append(state) elif state not in exist_jumps: self.add_arrow(x1, y1, x2, y2, r2) exist_jumps.append(state) if self.conditions[key][ "is_final"] == 'start': # начальное состояние self.add_arrow(x1, y1 - 1.5 * r1, x1, y1, r1) def add_arrow(self, x1, y1, x2, y2, r): # добавляет стрелки [(x1,y1) ---> (x2,y2) polygon = QPolygonF() polygon.append(QPoint(x1, y1)) arrow_length = 30 + r // 2 # длина стрелки ostr = 0.1 # острота стрелки x = x2 - x1 y = y2 - y1 angle = math.atan2(y, x) new__x2 = x2 - r / 2 * math.cos(angle) # координаты с учетом радиуса new__y2 = y2 - r / 2 * math.sin(angle) polygon.append(QPoint(new__x2, new__y2)) arrow__x = x2 - arrow_length * math.cos(angle - ostr) arrow__y = y2 - arrow_length * math.sin(angle - ostr) polygon.append(QPoint(arrow__x, arrow__y)) arrow__x = x2 - arrow_length * math.cos(angle + ostr) arrow__y = y2 - arrow_length * math.sin(angle + ostr) polygon.append(QPoint(arrow__x, arrow__y)) polygon.append(QPoint(new__x2, new__y2)) self.scene.addPolygon(polygon, QPen(), QBrush(Qt.black)) def add_triangle(self, x, y, l): polygon = QPolygonF() polygon.append(QPoint(x, y)) polygon.append(QPoint(x + l // 2, y - l)) polygon.append(QPoint(x - l // 2, y - l)) polygon.append(QPoint(x, y)) self.scene.addPolygon(polygon, QPen(), QBrush(Qt.black)) def add_arc(self, x, y, r): # x,y - центр окружности, к которой строится дуга ell = QGraphicsEllipseItem(x - r // 4, y - r / 1.1, r - r // 2, r + r // 2) ell.setStartAngle(0) ell.setSpanAngle(2900) self.scene.addItem(ell) self.add_triangle(x - r // 4.4, y - r // 2.28, r // 4) def add_signals( self): # добавление сигналов для перехода в другое состояние for cond in self.conditions.keys(): text = {} for key in self.conditions[cond]["jump"].keys(): if self.conditions[cond]["jump"][key] not in text.keys( ): # если нет ключа - добавляем запись text[self.conditions[cond]["jump"][key]] = key + ',' else: # если ключ есть - перезаписываем строку text[self.conditions[cond]["jump"][key]] += key + ',' for k in text.keys(): if k == cond: # переход в это же состояние x = int(self.conditions[cond]["coord"]["x"]) y = int(self.conditions[cond]["coord"]["y"]) r = int(self.conditions[cond]["coord"]["r"]) self.add_text(cond, k, text[k][:-1], x + r // 5, y - r) else: x1 = int(self.conditions[cond]["coord"]["x"]) y1 = int(self.conditions[cond]["coord"]["y"]) x2 = int(self.conditions[k]["coord"]["x"]) y2 = int(self.conditions[k]["coord"]["y"]) self.add_text(cond, k, text[k][:-1], (x1 + x2) // 2, (y1 + y2) // 2 - 30) # добавляет текст на сцену и в conditions сохраняет объекты этого текста def add_text(self, key, cond, text, x, y): # key - к какому состоянию привязать текст не сцене text_item = QGraphicsTextItem(text) # cond куда произойдет переход text_item.moveBy(x, y) f = QFont("Times", 15) text_item.setFont(f) self.scene.addItem(text_item) self.conditions[key]["text"][cond] = text_item
class MonitorGraphicsView(QGraphicsView, AllowDrop): monitorWin = None SIZE = (50.0, 50.0) FULLSPEED = 512 * 1024 # 512 in kb/s _progressText = None _speedsPolygon = None _speedsPen = None _speedsBrush = None def __init__(self, parent=None): super().__init__(parent) self.monitorWin = parent if self.monitorWin: self.monitorWin.sigTaskUpdating.connect(self.slotTaskUpdate) self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, self.SIZE[0], self.SIZE[1]) self.setScene(self.scene) self._speedsPen = QPen(Qt.white) gradient = QLinearGradient(0, 0, self.SIZE[0], self.SIZE[1]) gradient.setColorAt(0.0, Qt.darkGreen) gradient.setColorAt(1.0, Qt.yellow) self._speedsBrush = QBrush(gradient) # add elements to the scene self._speedsPolygon = self.scene.addPolygon(QPolygonF(), self._speedsPen, self._speedsBrush) self._progressText = self.scene.addText("") self._progressText.setPos(10, 0) self.setupDropSupport() def mousePressEvent(self, qMouseEvent): self.monitorWin.mousePressEvent(qMouseEvent) def mouseMoveEvent(self, qMouseEvent): self.monitorWin.mouseMoveEvent(qMouseEvent) def mouseReleaseEvent(self, qMouseEvent): self.monitorWin.mouseReleaseEvent(qMouseEvent) def _setSpeeds(self, speeds): polygon = QPolygonF() polygon.append(QPointF(0, self.SIZE[1])) # start the polygon nSamples = len(speeds) xPerSample = self.SIZE[0] / nSamples for i, speed in enumerate(speeds): y = self._translateSpeedToPosY(speed) polygon.append(QPointF(xPerSample * i, y)) polygon.append(QPointF(xPerSample * (i + 1), y)) polygon.append(QPointF(*self.SIZE)) # close the polygon self._speedsPolygon.setPolygon(polygon) def _setProgress(self, process): # 10000 means 100% if process is None: self._progressText.setPlainText("") else: self._progressText.setPlainText("{:.1f}%".format(process / 100)) def _translateSpeedToPosY(self, speed): return self.SIZE[1] * (1.0 - speed / self.FULLSPEED) @pyqtSlot(dict) def slotTaskUpdate(self, task): if task: self._setProgress(task["progress"]) self._setSpeeds(task["speeds"]) else: self._setProgress(None) self._setSpeeds([0.0])
class Paint(QGraphicsView): ''' La clase Paint recive dos parámetros en el constructor una imagen y el nombre de dicha imágen ''' def __init__(self, img=None, img_name=None): ''' Esta clase hereda atributos y métodos de la clase QgraphicsView La clase QgraphicsView permite añadir una escena y en dicha escena se pueden hacer los dibujos. ''' QGraphicsView.__init__(self) self.setSceneRect( QRectF(self.viewport().rect()) ) #El Tamaño de la escena va a tener el tamaño de la pantalla original que es Dialogo self.scene = QGraphicsScene() #Creamos un objeto tipo QgraphicsScene self.isObject = None #Esta variable inicialmente nula, permite controlar las opciones de que dibujo queremos realizar self.startX = None #Al momento de dibujar, esta variable guarda las cordenadas en x del primer clic self.startY = None #Al momento de dibujar, esta variable guarda las cordenadas en y del primer clic self.pointPolygon = None #Es una tubla de puntos del poligono en x e y self.arrayPolygon = [ ] #Es una lista con cada una de las tuplas de las coordenadas del poligono self.puntosX = [] #Es una lista que guarda solo los puntos de x self.puntosY = [] #Es una lista que guarda solo los puntos de y self.img_name = img_name self.pixi = img.scaled( 638, 478) #Reescalamos la imágen al tamaño de nuestra pantalla self.scene.addPixmap(self.pixi) #añadimos la imágen a la escena self.setScene(self.scene) #enviamso la escena al GraphicsVie ''' Esta función nos permite seleccionar que tipo de dibujo queremos hacer ''' def paintObject(self, e): if self.isObject != None: object = self.isObject if object == 1: #Line pen = QPen(Qt.red) self.scene.addItem( self.scene.addLine(self.startX, self.startY, e.x(), e.y(), pen)) self.setScene(self.scene) elif object == 2: #Rect ''' Solo podemos dibujar un rectangulo para hacer un solo recorte, por eso cada vez que dibujemos uno preguntamos si ya hay algún rectangulo en la escena, si es así lo borramos ''' for self.item in self.scene.items(): x = isinstance(self.item, QGraphicsRectItem) if x: self.scene.removeItem(self.item) pen = QPen(Qt.red) brush = QBrush() self.scene.addItem( self.scene.addRect(self.startX, self.startY, e.x() - self.startX, e.y() - self.startY, pen, brush)) self.region = ( self.startX, self.startY, e.x(), e.y() ) #éste es el rectangulo que obtendremos al recortar self.img = Image.open( self.img_name) #Abrimos la misma imágen que ya teniamos self.img_resized = self.img.resize( (638, 478) ) #La redimensionamos, si no hacemos esto, al momento de recortar, no se obtendra la imagen requerida self.img_recortada = self.img_resized.crop( self.region) #Hacemos el recorte self.setScene(self.scene) #Enviamos el rectangulo a la escena elif object == 3: #Ellipse pen = QPen(Qt.red) brush = QBrush() self.scene.addItem( self.scene.addEllipse(self.startX, self.startY, e.x() - self.startX, e.y() - self.startY, pen, brush)) self.setScene(self.scene) def paintPolygon(self, e): if self.isObject != None: object = self.isObject if object == 4: #Polygon self.pointPolygon = QPointF(e.x(), e.y()) self.puntosX.append(e.x()) self.puntosY.append(e.y()) self.arrayPolygon.append(self.pointPolygon) pen = QPen(Qt.green) brush = QBrush(Qt.green, Qt.Dense4Pattern) self.scene.addItem( self.scene.addPolygon(QPolygonF(self.arrayPolygon), pen, brush)) self.setScene(self.scene) ''' Esta funcion captura el evento de clickear ''' def mousePressEvent(self, event): e = QPointF(self.mapToScene(event.pos())) self.startX = e.x() self.startY = e.y() ''' Esta función actualiza las coordenadas en x e y ''' def mouseReleaseEvent(self, event): e = QPointF(self.mapToScene(event.pos())) self.paintObject(e) self.paintPolygon(e) ''' Esta función captura el evento de movimiento del mouse ''' def mouseMoveEvent(self, event): e = QPointF(self.mapToScene(event.pos()))
def __init__(self, state, device): super().__init__() self.state = state self.invalidated = False self.cnt = 0 self.acc_values = (0, 0, 0, 0, 0, 0, 0) self.network = QNetworkAccessManager() view = QGraphicsView() view.setRenderHint(QPainter.Antialiasing) scene = QGraphicsScene() scene.addPixmap(QPixmap("chair.png").scaledToWidth(150)) pen = QPen(QColor.fromRgb(0x28, 0x30, 0x39), 3) self.sonic = scene.addRect(QRectF(65, 20, 20, 10), pen, QBrush(Qt.white)) self.lback = scene.addEllipse(QRectF(30, 50, 20, 20), pen, QBrush(Qt.white)) self.rback = scene.addEllipse(QRectF(100, 50, 20, 20), pen, QBrush(Qt.white)) self.lhip = scene.addPolygon( QPolygonF([ QPointF(30, 170), QPointF(50, 170), QPointF(50, 160), QPointF(30, 160) ]), pen, QBrush(Qt.white)) self.rhip = scene.addPolygon( QPolygonF([ QPointF(100, 170), QPointF(120, 170), QPointF(120, 160), QPointF(100, 160) ]), pen, QBrush(Qt.white)) self.lthigh = scene.addEllipse(QRectF(30, 200, 20, 10), pen, QBrush(Qt.white)) self.rthigh = scene.addEllipse(QRectF(100, 200, 20, 10), pen, QBrush(Qt.white)) self.displays = [ self.lhip, self.lthigh, self.lback, self.rhip, self.rthigh, self.rback, self.sonic ] view.setScene(scene) view.setFixedWidth(150) view.setMinimumHeight(400) view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setWindowTitle("센서 조정") self.setWindowIcon(QIcon('icon.png')) self.setGeometry(300, 300, 560, 600) self.label = QLabel() self.label.setProperty("class", "big") self.label.setAlignment(Qt.AlignHCenter) movie = QMovie("loader.gif") movie.start() busy_label = QLabel() busy_label.setMovie(movie) busy_label.setAlignment(Qt.AlignHCenter) layout = QVBoxLayout() layout.addStretch(1) layout.addWidget(self.label) layout.addWidget(view) layout.setAlignment(view, Qt.AlignHCenter) layout.addWidget(busy_label) layout.addStretch(1) layout.setContentsMargins(50, 50, 50, 50) layout.setSpacing(20) frame = QWidget() frame.setLayout(layout) frame.setProperty("class", "frame") main_layout = QVBoxLayout() main_layout.addWidget(frame) main_layout.setContentsMargins(0, 0, 0, 0) self.setLayout(main_layout) self.setProperty("class", "root") self.setContentsMargins(0, 0, 0, 0) self.setAttribute(Qt.WA_TranslucentBackground) self.device_changed(device.is_connected()) device.connectedChanged.connect(self.device_changed) device.updateNumber.connect(self.sensor_update)