class ImageView(QGraphicsView): def __init__(self, mode): # parameter self.mode = mode # create scene self.scene = QGraphicsScene() super().__init__(self.scene) self.setScene(self.scene) # use in draw sequence # - items : Scene 에 추가된 item list # - 임시 item 들은 obj에 관리된다. self.items = [] self.obj = {} # View 출력을 위한 임시 저장장소 self._object_reset() self.rect_p0 = None self.rect_p1 = None self.select = [] # use in data load self.image = None self.pixmap = None self.image_item = None self.metadata = None # use in key event self._zoom = 0 self.KEY_SHIFT = False self.KEY_ALT = False self.KEY_CTRL = False self.KEY_MOUSE_LEFT = False # backup self.last_mask = None self.last_polygon = None # QGraphicsView setting self.setDragMode(self.mode.VIEW_DRAG_MODE) self.setMouseTracking(True) # remove scrollbar option if not self.mode.SCROLLBAR_VIEW: self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) def load_image(self, image, metadata): self.reset() self.image = image # Qimage 를 가져온다. image = self.image.get_image() # pixmap data 생성 pixmap = QPixmap(image) self.pixmap = pixmap self.image_item = QGraphicsPixmapItem(pixmap) self.scene.addItem(self.image_item) self._load_metadata(metadata) def refresh(self): """ 현재 작업중인 임시 정보를 모두 삭제하고, 현재 설정값을 재설정한다. """ # Object 초기화 self._object_reset() # Mode 설정 self.setDragMode(self.mode.VIEW_DRAG_MODE) # Data Reset self.rect_p0 = None self.rect_p1 = None self.select.clear() # Key 초기화 self.KEY_SHIFT = False self.KEY_ALT = False self.KEY_MOUSE_LEFT = False # Mask Draw self._mask_draw() # update self._update() def reset(self): """ 이미지 정보를 포함하여 모든 정보를 삭제한다. """ # Scene 에 표시되는 물체들을 제거한다. self._delete_items(self.items) self.scene.removeItem(self.image_item) # backup 초기화 self.last_mask = None self.last_polygon = None # image 정보 초기화 self.image = None self.pixmap = None self.image_item = None self.metadata = None # refresh self.refresh() def restore(self): print('restore') if self.last_mask is not None and self.image is not None: self.image.restore_mask(self.last_mask) if self.last_polygon is not None: self._polygon_delete(self.last_polygon) print('1') self.last_mask = None self.last_polygon = None self._mask_draw() def callback_selected(self, e, item): """ Image Item 객체가 선택되었을 때, View 에 직접 호출 할 수 있는 함수 Image Item 객체의 event 함수에서 호출된다. """ pass def callback_polygon_double_click(self, polygon_item): if self.KEY_CTRL and self.mode.CURRENT == 0: # delete polygon # 1. remove text item if polygon_item.text_item is not None: self.items.remove(polygon_item.text_item) self.scene.removeItem(polygon_item.text_item) # 2. remove polygon self.items.remove(polygon_item) self.scene.removeItem(polygon_item) elif self.KEY_CTRL: print('2') self._polygon_delete(polygon_item) def callback_polygon_hover_enter(self, polygon_item): if self.mode.CURRENT == 0: self.setDragMode(QGraphicsView.NoDrag) def callback_polygon_hover_move(self, polygon_item): if self.mode.CURRENT == 0: self.setDragMode(QGraphicsView.NoDrag) def callback_polygon_hover_leave(self, polygon_item): if self.mode.CURRENT == 0: self.setDragMode(self.mode.VIEW_DRAG_MODE) def _load_metadata(self, metadata): """ Image Annotation 을 읽어와 View 에 출력한다. """ self.metadata = metadata polygons = metadata.out_polygons_to_list() for polygon in polygons: [attribute, x, y, id] = polygon assert len(x) == len(y), "Invalid polygon information in metadata" qpol = QPolygonF() for idx in range(len(x)): qpol.append(QPointF(x[idx], y[idx])) self._polygon_draw(qpol, attribute, id) def _update(self): pass def _delete_items(self, items): for item in items: self.scene.removeItem(item) items.clear() def _object_reset(self): """ Object 를 초기화한다. obj Dictionary 에는 view 그리기에 필요한 임시값들이 저장되어있다. """ # polygon : 현재 작성중인 polygon 좌표들을 QPointF list 형태로 가지고 있는다. if 'polygon' not in self.obj: self.obj['polygon'] = [] else: self.obj['polygon'].clear() # lines : View 에 출력되는 직선들이다. if 'lines' not in self.obj: self.obj['lines'] = [] else: self._delete_items(self.obj['lines']) self.obj['lines'].clear() # mask : magicwand mask if 'mask' in self.obj and self.obj['mask'] is not None: self.scene.removeItem(self.obj['mask']) self.obj['mask'] = None # paint sign if 'paint' in self.obj and self.obj['paint'] is not None: self.scene.removeItem(self.obj['paint']) self.obj['paint'] = None def _polygon_check(self, polygon_list): """ polygon 의 시작 위치와 종료 위치를 이용하여 생성 조건을 반환한다. """ if polygon_list is None or len(polygon_list) < 3: return False # 거리 계산 dx = polygon_list[-1].x() - polygon_list[0].x() dy = polygon_list[-1].y() - polygon_list[0].y() d = dx * dx + dy * dy if d < self.mode.POLYGON_END_THRESHOLD: # 마지막 위치 수정 del (polygon_list[-1]) polygon_list.append(polygon_list[0]) return True else: return False def _polygon_draw(self, polygon, attribute, id=-1): """ polygon 을 그린다. polygon 객체를 인수로 받아서 scene 에 추가한다. """ # Call by Value attribute = attribute.copy() pen = QPen(self.mode.DRAW_PEN_COLOR, 3) if attribute['name'] in self.mode.POLYGON_BRUSH_COLOR: brush = QBrush(self.mode.POLYGON_BRUSH_COLOR[attribute['name']]) else: brush = QBrush(self.mode.DRAW_BRUSH_COLOR) # polygon_item 생성 polygon_item = PolygonItem(self, polygon, attribute, id) polygon_item.setPen(pen) polygon_item.setBrush(brush) # scene 에 추가 self.items.append(polygon_item) self.scene.addItem(polygon_item) # polygon location self._polygon_location(polygon_item) # QGraphicPolygonItem 반환 return polygon_item def _polygon_location(self, polygon_item): polygon = polygon_item.polygon attribute = polygon_item.attribute # Set text location text_locate, compare_list_y = [], [] for i in range(len(polygon) - 1): compare_list_y.append(polygon[i].toPoint().y()) top_of_polygon_y = min(compare_list_y) index = compare_list_y.index(top_of_polygon_y) text_locate.append(polygon[index].toPoint().x()) text_locate.append(polygon[index].toPoint().y()) text_locate[0] = text_locate[0] - 5 text_locate[1] = text_locate[1] - 5 # add text item if 'name' not in attribute: attribute['name'] = 'none' item = self.scene.addText(attribute['name'], QFont('Arial', 10)) self.items.append(item) polygon_item.text_item = item item.setPos(text_locate[0], text_locate[1]) def _polygon_add_info(self, polygon_item): """ polygon 을 metadata 에 추가한다. """ region_attribute = polygon_item.attribute polygon = polygon_item.polygon xs = [] ys = [] for point in polygon: xs.append(int(point.x())) ys.append(int(point.y())) polygon_item.id = self.metadata.add_polygon(region_attribute, xs, ys) def _polygon_delete(self, polygon_item): # delete polygon # 1. remove metadata print('0') print(polygon_item.id) self.metadata.delete_polygon(polygon_item.id) # 2. remove text item if polygon_item.text_item is not None: self.items.remove(polygon_item.text_item) self.scene.removeItem(polygon_item.text_item) # 3. remove polygon self.items.remove(polygon_item) self.scene.removeItem(polygon_item) def _mask_draw(self): if self.image is None: return # QBitmap 생성 bitmap = self.image.get_mask() # QPixmap 생성 pixmap = QPixmap(self.pixmap) pixmap.fill(self.mode.DRAW_MASK_COLOR) # pixmap 에 Mask를 씌운다. pixmap.setMask(bitmap) # Item 생성 및 추가 if self.obj['mask'] is not None: self.scene.removeItem(self.obj['mask']) self.obj['mask'] = QGraphicsPixmapItem(pixmap) self.scene.addItem(self.obj['mask']) def _mask_reset(self): # Reset Mask if self.image is not None: self.image.reset_mask() def _paint_draw_sign(self, x, y): # draw paint sign brush = QBrush(self.mode.DRAW_MASK_COLOR ) if self.mode.DRAW_PAINT_MODE else QBrush( QColor(255, 255, 255, 50)) pen = QPen(QColor(0, 0, 0), 3) # Item 생성 및 추가 width = self.mode.DRAW_PAINT_WIDTH if self.obj['paint'] is not None: self.scene.removeItem(self.obj['paint']) self.obj['paint'] = QGraphicsEllipseItem(int(x - width / 2), int(y - width / 2), width, width) self.obj['paint'].setBrush(brush) self.obj['paint'].setPen(pen) self.scene.addItem(self.obj['paint']) def _draw_sequence_press(self, pos, out_of_range): """ view 에 item 들을 그린다. mode 로 view 에 그리는 방법을 다르게 설정 할 수 있다. press, move, release sequence 함수들은 서로 의존적이다. mousePressEvent 에서 호출된다. """ if out_of_range: return last_pos = self.rect_p0 self.rect_p0 = pos # Mode 1. polygon draw if self.mode.CURRENT == 1: # 새로운 위치를 지정 및 기억한다. polygon_list = self.obj['polygon'] polygon_list.append(pos) # 조건을 확인하여 polygon 을 그린다. if self._polygon_check(polygon_list): # polygon list 를 이용하여 QPolygonF 객체 생성 polygon = QPolygonF([QPointF(point) for point in polygon_list]) # polygon 을 그린다. polygon_item = self._polygon_draw( polygon, self.mode.POLYGON_CURRENT_ATTRIBUTE) # metadata 추가 / id 할당 self._polygon_add_info(polygon_item) # polygon list 정보 삭제 polygon_list.clear() # lines 삭제 self._delete_items(self.obj['lines']) # 좌표 초기화 self.rect_p0 = None self.rect_p1 = None elif self.rect_p1 != None: # 임시 표시 직선을 그린다. pen = QPen(self.mode.DRAW_PEN_COLOR, self.mode.DRAW_PEN_WIDTH) if not out_of_range \ else QPen(self.mode.DRAW_PEN_COLOR_WARNNING, self.mode.DRAW_PEN_WIDTH) line = QLineF(self.rect_p0.x(), self.rect_p0.y(), last_pos.x(), last_pos.y()) self.obj['lines'].insert(0, self.scene.addLine(line, pen)) # Mode 2. Magic Wand elif self.mode.CURRENT == 2: # option 설정 if self.KEY_SHIFT and self.KEY_ALT: option = 'and' elif self.KEY_SHIFT: option = 'or' elif self.KEY_SHIFT: option = 'sub' else: option = 'select' # 현재 point mask 생성 self.image.set_tolerance(self.mode.DRAW_MASK_TOLERANCE) self.image.set_mask(int(pos.x()), int(pos.y()), option=option) # mask 를 그린다. self._mask_draw() # Mode 3. Paint elif self.mode.CURRENT == 3: # paint or erase if self.mode.DRAW_PAINT_MODE: self.image.paint_mask(int(pos.x()), int(pos.y()), self.mode.DRAW_PAINT_WIDTH) else: self.image.erase_mask(int(pos.x()), int(pos.y()), self.mode.DRAW_PAINT_WIDTH) self._mask_draw() self._paint_draw_sign(int(pos.x()), int(pos.y())) def _draw_sequence_move(self, pos, out_of_range): """ view 에 item 들을 그린다. mouseMoveEvent 에서 호출된다. """ # polygon draw if self.mode.CURRENT == 1: if self.rect_p0 is None: return else: self.rect_p1 = pos # QPen 선택 pen = QPen(self.mode.DRAW_PEN_COLOR, self.mode.DRAW_PEN_WIDTH) if not out_of_range \ else QPen(self.mode.DRAW_PEN_COLOR_WARNNING, self.mode.DRAW_PEN_WIDTH) # 마지막에 그렸던 직선 삭제 if len(self.obj['lines']) > 0: self.scene.removeItem(self.obj['lines'][-1]) del (self.obj['lines'][-1]) # 새로운 직선을 그린다 line = QLineF(self.rect_p0.x(), self.rect_p0.y(), self.rect_p1.x(), self.rect_p1.y()) self.obj['lines'].append(self.scene.addLine(line, pen)) elif self.mode.CURRENT == 3 and not out_of_range: # paint or erase if self.KEY_MOUSE_LEFT: if self.mode.DRAW_PAINT_MODE: self.image.paint_mask(int(pos.x()), int(pos.y()), self.mode.DRAW_PAINT_WIDTH) else: self.image.erase_mask(int(pos.x()), int(pos.y()), self.mode.DRAW_PAINT_WIDTH) self._mask_draw() self._paint_draw_sign(int(pos.x()), int(pos.y())) def _mouse_check(self, e): """ 현재 좌표와 좌표가 이미지 위에 위치하는지 여부를 반환한다. Image 가 할당된 이후에 호출될 수 있어야 한다. QMouseEvent 가 주어져야한다. """ assert self.image_item is not None, "No image to check" # 마우스 위치를 Scene 좌표로 변환한다. pos = self.mapToScene(e.pos()) # 변환된 Scene 좌표를 item 좌표로 변환한다. pos = self.image_item.mapFromScene(pos) # image item 좌표 범위를 QRectF 클래스로 받아온다. rect = self.image_item.boundingRect() # 좌표와 좌표 위치 정보 반환. return pos, not rect.contains(pos) def keyPressEvent(self, e): super().keyPressEvent(e) if self.image is None: return if e.key() == Qt.Key_Escape: self.last_mask = self.image.backup_mask() self._mask_reset() self.refresh() if e.key() == Qt.Key_Shift: self.KEY_SHIFT = True self.mode.DRAW_PAINT_MODE = not self.mode.DRAW_PAINT_MODE if e.key() == Qt.Key_Alt: self.KEY_ALT = True if e.key() == Qt.Key_Control: self.KEY_CTRL = True if e.key() == Qt.Key_Space and self.image is not None: # Mask To Polygon (with backup) self.last_mask = self.image.backup_mask() polygon = self.image.get_polygon() if polygon is not None: polygon_item = self._polygon_draw( polygon, self.mode.POLYGON_CURRENT_ATTRIBUTE) self._polygon_add_info(polygon_item) self.last_polygon = polygon_item self._mask_reset() self.refresh() def keyReleaseEvent(self, e): if e.key() == Qt.Key_Shift: self.KEY_SHIFT = False if e.key() == Qt.Key_Alt: self.KEY_ALT = False if e.key() == Qt.Key_Control: self.KEY_CTRL = False def showEvent(self, e): self._update() super().showEvent(e) def wheelEvent(self, e): if self.KEY_CTRL: if self.mode.CURRENT == 3: pos, out_of_range = self._mouse_check(e) if not out_of_range: # pain wheel self._paint_draw_sign(int(pos.x()), int(pos.y())) return # zoom in / out 구현 if e.angleDelta().y() > 0 and self._zoom < 10: self.scale(1.25, 1.25) self._zoom += 1 elif e.angleDelta().y() < 0 and self._zoom > -10: self.scale(0.8, 0.8) self._zoom -= 1 def mousePressEvent(self, e): # QGraphicsView.ScrollHandDrag middle mouse super().mousePressEvent(e) if self.KEY_CTRL: return # 좌표와 정보를 받아온다. if self.image_item is not None: pos, out_of_range = self._mouse_check(e) else: return # Reset Mask if self.mode.CURRENT not in [0, 2, 3]: self._mask_reset() self._mask_draw() # Left Button if e.button() == Qt.LeftButton: self.KEY_MOUSE_LEFT = True # 좌표를 이용하여 view 를 그린다. self._draw_sequence_press(pos, out_of_range) def mouseMoveEvent(self, e): super().mouseMoveEvent(e) # Left Button if self.image_item is not None: # 좌표와 정보를 받아온다. pos, out_of_range = self._mouse_check(e) # 좌표를 이용하여 view 를 그린다. self._draw_sequence_move(pos, out_of_range) def mouseReleaseEvent(self, e): super().mouseReleaseEvent(e) # 좌표와 정보를 받아온다. if self.image_item is not None: pos, out_of_range = self._mouse_check(e) else: return # Left Button if e.button() == Qt.LeftButton: self.KEY_MOUSE_LEFT = False
class HorizonApp(QtWidgets.QMainWindow, design.Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) self.initScene() def initScene(self): self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, 1033, 579) self.graphicsView.setScene(self.scene) self.scene.setBackgroundBrush(Qt.white) self.pen = QPen() self.pen.setWidth(1) self.pen.setColor(Qt.black) self.displayButton.clicked.connect(self.prepareForDrawing) def FloatHorizon(self, borders_x, x_step, borders_z, z_step, f, angles): global top, bottom # Инициализируем начальными значениями массивы горизонтов. top = [0] * WIDTH # Верхний. bottom = [HEIGHT] * WIDTH # Нижний. x_start = borders_x[0] x_end = borders_x[1] z_start = borders_z[0] z_end = borders_z[1] x_left, y_left = -1, -1 x_right, y_right = -1, -1 z = z_end while z >= z_start - z_step / 2: x_prev = x_start y_prev = f(x_start, z) x_prev, y_prev = transform(x_prev, y_prev, z, angles) flag_prev = Visible(x_prev, y_prev) # x_left, y_left = Side(x_prev, y_prev, x_left, y_left, self) x = x_start while x <= x_end + x_step / 2: y_curr = f(x, z) x_curr, y_curr = transform(x, y_curr, z, angles) # Проверка видимости текущей точки. flag_curr = Visible(x_curr, y_curr) # Равенство флагов означает, что обе точки находятся # Либо выше верхнего горизонта, либо ниже нижнего, # Либо обе невидимы. if flag_curr == flag_prev: # Если текущая вершина выше верхнего горизонта # Или ниже нижнего (Предыдущая такая же) if flag_curr != 0: # Значит отображаем отрезок от предыдущей до текущей. self.scene.addLine(x_prev, y_prev, x_curr, y_curr) Horizon(x_prev, y_prev, x_curr, y_curr) # flag_curr == 0 означает, что и flag_prev == 0, # А значит часть от flag_curr до flag_prev невидима. Ничего не делаем. else: # Если видимость изменилась, то # Вычисляем пересечение. if flag_curr == 0: if flag_prev == 1: # Сегмент "входит" в верхний горизонт. # Ищем пересечение с верхним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, top) else: # flag_prev == -1 (flag_prev нулю (0) не может быть равен, т.к. мы обработали это выше). # Сегмент "входит" в нижний горизонт. # Ищем пересечение с нижним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, bottom) # Отображаем сегмент, от предыдущий точки, до пересечения. self.scene.addLine(x_prev, y_prev, xi, yi) Horizon(x_prev, y_prev, xi, yi) else: if flag_curr == 1: if flag_prev == 0: # Сегмент "выходит" из верхнего горизонта. # Ищем пересечение с верхним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, top) # Отображаем сегмент от пересечения до текущей точки. self.scene.addLine(xi, yi, x_curr, y_curr) Horizon(xi, yi, x_curr, y_curr) else: # flag_prev == -1 # Сегмент начинается с точки, ниже нижнего горизонта # И заканчивается в точке выше верхнего горизонта. # Нужно искать 2 пересечения. # Первое пересечение с нижним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, bottom) # Отображаем сегмент от предыдущей то пересечения. self.scene.addLine(x_prev, y_prev, xi, yi) Horizon(x_prev, y_prev, xi, yi) # Второе пересечение с верхним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, top) # Отображаем сегмент от пересечения до текущей. self.scene.addLine(xi, yi, x_curr, y_curr) Horizon(xi, yi, x_curr, y_curr) else: # flag_curr == -1 if flag_prev == 0: # Сегмент "выходит" из нижнего горизонта. # Ищем пересечение с нижним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, bottom) self.scene.addLine(xi, yi, x_curr, y_curr) Horizon(xi, yi, x_curr, y_curr) else: # Сегмент начинается с точки, выше верхнего горизонта # И заканчивается в точке ниже нижнего горизонта. # Нужно искать 2 пересечения. # Первое пересечение с верхним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, top) # Отображаем сегмент от предыдущей до пересечения. self.scene.addLine(x_prev, y_prev, xi, yi) Horizon(x_prev, y_prev, xi, yi) # Ищем второе пересечение с нижним горизонтом. xi, yi = Intersection(x_prev, y_prev, x_curr, y_curr, bottom) # Отображаем сегмент от пересечения до текущей. self.scene.addLine(xi, yi, x_curr, y_curr) Horizon(xi, yi, x_curr, y_curr) x_prev, y_prev = x_curr, y_curr flag_prev = flag_curr x += x_step x_right, y_right = Side(x_prev, y_prev, x_right, y_right, self) z -= z_step def prepareForDrawing(self): self.scene.clear() bordersForX = [self.xFrom.value(), self.xTo.value()] stepForX = self.xStep.value() bordersForX = [self.zFrom.value(), self.zTo.value()] stepForZ = self.zStep.value() angles = [ self.rotateX.value(), self.rotateY.value(), self.rotateZ.value() ] function = checkFunc(self) self.FloatHorizon(bordersForX, stepForX, bordersForX, stepForZ, function, angles)
class CircuitDiagramView(QGraphicsView): mousePress = pyqtSignal(tuple, tuple, name='mousePress') mouseMove = pyqtSignal(tuple, tuple, name='mouseMove') mouseRelease = pyqtSignal(tuple, tuple, name='mouseRelease') def __init__(self, parent=None): QGraphicsView.__init__(self, parent) self._model = None self.controller = None self.setAcceptDrops(True) # setup & render circuit diagram grid self.scene = QGraphicsScene() self.setScene(self.scene) self._shouldShowSelection = False self._selection = None self._dragging = False self.mousePosition = None self.draggingStart = None self.render() @property def shouldShowSelection(self): return self._shouldShowSelection @shouldShowSelection.setter def shouldShowSelection(self, value): if self.shouldShowSelection is not value and value is not None: self._shouldShowSelection = value self.render() @property def model(self): return self._model @model.setter def model(self, value): self._model = value self.model.modelChanged.connect(self.render) @property def selection(self): return self._selection @selection.setter def selection(self, value): if self.selection is not value: self._selection = value self.render() @property def dragging(self): return self._dragging @dragging.setter def dragging(self, value): self._dragging = value self.render() def componentTypeToImageName(self, componentType): dictionary = { ComponentType.Battery: "assets/battery.png", ComponentType.Resistor: "assets/resistor.png", ComponentType.Voltmeter: "assets/voltmeter.png", ComponentType.Ammeter: "assets/ammeter.png", ComponentType.Switch: "assets/switch-off.png", ComponentType.Bulb: "assets/bulb-off.png", ComponentType.Button: "assets/button-off.png", } return dictionary[componentType] def componentToImage(self, component): if component.type == ComponentType.Wire: image = QPixmap("assets/icon.png").scaled(self.blockSideLength, self.blockSideLength) if component.numberOfConnections() == 1: image = QPixmap("assets/wire-top.png").scaled(self.blockSideLength, self.blockSideLength) if component.connections[Direction.Right] is not None: image = image.transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Bottom] is not None: image = image.transformed(QtGui.QTransform().rotate(180)) elif component.connections[Direction.Left] is not None: image = image.transformed(QtGui.QTransform().rotate(270)) elif component.numberOfConnections() == 2: if component.connections[Direction.Left] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength) elif component.connections[Direction.Top] is not None and component.connections[Direction.Bottom] is not None: image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Top] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength) elif component.connections[Direction.Top] is not None and component.connections[Direction.Left] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(270)) elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Left] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(180)) elif component.numberOfConnections() == 3: image = QPixmap("assets/wire-left-top-right.png").scaled(self.blockSideLength, self.blockSideLength) if component.connections[Direction.Left] is None: image = image.transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Top] is None: image = image.transformed(QtGui.QTransform().rotate(180)) elif component.connections[Direction.Right] is None: image = image.transformed(QtGui.QTransform().rotate(270)) return image else: imageName = "assets/wire-right.png" if component.type == ComponentType.Bulb: if component.isOn(): imageName = "assets/bulb-on.png" else: imageName = "assets/bulb-off.png" elif component.type == ComponentType.Switch: if component.closed: imageName = "assets/switch-on.png" else: imageName = "assets/switch-off.png" elif component.type == ComponentType.Button: if component.closed: imageName = "assets/button-on.png" else: imageName = "assets/button-off.png" else: imageName = self.componentTypeToImageName(component.type) return QPixmap(imageName).scaled(self.blockSideLength, self.blockSideLength) def mouseCoordinatesToBlockIndex(self, x, y): if self.model is None or x < self.startingX or y < self.startingY or x > self.startingX + self.model.gridSize * self.blockSideLength or y > self.startingY + self.model.gridSize * self.blockSideLength: return (-1, -1) else: return (int((x - self.startingX) / self.blockSideLength), int((y - self.startingY) / self.blockSideLength)) def blockIndexToCoordinate(self, x, y): return (self.startingX + self.blockSideLength * x, self.startingY + self.blockSideLength * y) def mousePressEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mousePress.emit(index, (event.x(), event.y())) def dragEnterEvent(self, event): event.acceptProposedAction() def dragMoveEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y()) self.mouseMove.emit(index, (event.pos().x(), event.pos().y())) def dropEvent(self, event): event.acceptProposedAction() index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y()) self.mouseRelease.emit(index, (event.pos().x(), event.pos().y())) def mouseMoveEvent(self, event): self.mousePosition = (event.x(), event.y()) if self.dragging: self.render() index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mouseMove.emit(index, (event.pos().x(), event.pos().y())) def mouseReleaseEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mouseRelease.emit(index, (event.pos().x(), event.pos().y())) def resizeEvent(self, event): self.render() def render(self): if self.model is not None: self.scene.clear() self.renderCircuitDiagramGrid() self.renderComponents() def renderComponents(self): if self.model is not None: for component in self.model.components: pixmap = self.componentToImage(component) pixmapItem = self.scene.addPixmap(pixmap) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) pixmapItem.setOffset(offset[0],offset[1]) pixmapItem.setTransformationMode(Qt.SmoothTransformation) if component is self.selection: if self.dragging: renderPosition = (self.startingX + self.selection.position[0] * self.blockSideLength + self.mousePosition[0] - self.draggingStart[0], self.startingY + self.selection.position[1] * self.blockSideLength + self.mousePosition[1] - self.draggingStart[1]) pixmapItem.setOffset(renderPosition[0], renderPosition[1]) elif self.shouldShowSelection: pen = QPen(QBrush(QColor(0,0,255,100)), 2, Qt.DashLine) self.scene.addRect(self.startingX + component.position[0] * self.blockSideLength, self.startingY + component.position[1] * self.blockSideLength, self.blockSideLength, self.blockSideLength, pen) if component.type is ComponentType.Ammeter: font = QFont("Arial", self.blockSideLength/3.5) reading = self.scene.addText(str("%.2f" % component.current) + "A", font) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4) elif component.type is ComponentType.Voltmeter: font = QFont("Arial", self.blockSideLength/3.5) reading = self.scene.addText(str("%.2f" % component.voltage) + "V", font) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4) def renderCircuitDiagramGrid(self): pen = QPen(QBrush(QColor(200,200,200,255)), 1) pen2 = QPen(QBrush(QColor(100,100,100,255)), 3) width = self.width() height = self.height() self.blockSideLength = width / (self.model.gridSize + 2) if width < height else height / (self.model.gridSize + 2) # draw vertical lines currentX = width / 2 self.startingX = currentX - (self.model.gridSize / 2) * self.blockSideLength while currentX - self.blockSideLength >= 0: currentX -= self.blockSideLength while currentX < width: self.scene.addLine(currentX, 1, currentX, height - 1, pen) currentX += self.blockSideLength # draw horizontal lines currentY = height / 2 self.startingY = currentY - (self.model.gridSize / 2) * self.blockSideLength while currentY - self.blockSideLength >= 0: currentY -= self.blockSideLength while currentY < height: self.scene.addLine(1, currentY, width - 1, currentY, pen) currentY += self.blockSideLength self.scene.addLine(self.startingX, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, pen2) self.scene.addLine(self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2) self.scene.addLine(self.startingX, self.startingY, self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, pen2) self.scene.addLine(self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2)
class QImageViewer(QGraphicsView): # Mouse button signals emit image scene (x, y) coordinates. # !!! For image (row, column) matrix indexing, row = y and column = x. leftMouseButtonPressed = pyqtSignal(float, float) leftMouseButtonReleased = pyqtSignal(float, float) def __init__(self, widget): super(QImageViewer, self).__init__() self.mainWindow = utils.get_app() # Image is displayed as a QPixmap in a QGraphicsScene attached to this QGraphicsView. self.scene = QGraphicsScene() self.setScene(self.scene) # Store a local handle to the scene's current image pixmap. self._pixmapHandle = None # Image aspect ratio mode. # !!! ONLY applies to full image. Aspect ratio is always ignored when zooming. # Qt.IgnoreAspectRatio: Scale image to fit viewport. # Qt.KeepAspectRatio: Scale image to fit inside viewport, preserving aspect ratio. # Qt.KeepAspectRatioByExpanding: Scale image to fill the viewport, preserving aspect ratio. self.aspectRatioMode = Qt.KeepAspectRatioByExpanding # Scroll bar behaviour. # Qt.ScrollBarAlwaysOff: Never shows a scroll bar. # Qt.ScrollBarAlwaysOn: Always shows a scroll bar. # Qt.ScrollBarAsNeeded: Shows a scroll bar only when zoomed. self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Flags for enabling/disabling mouse interaction. self.KeyControl = False self.isPanning = False # Cursor settings cursorbit = QBitmap( QPixmap(utils.get_path(["iconImages", "CursorBit.png"]))) cursormask = QBitmap( QPixmap(utils.get_path(["iconImages", "CursorMask.png"]))) self.crossHair = QCursor(cursorbit, cursormask, -1, -1) # self.setCursor(self.crossHair) # Mouse coordinate updates self.setMouseTracking(True) self.digitizerOn = False # Ty edit: anchor at mouse position self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) #self.setResizeAnchor(QGraphicsView.AnchorViewCenter) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) # Ty edit: record the zoom, pan, and others self.InitialFrame = True self.Zoom_recorder = 0 GlobalData.currentFrame = 1 GlobalData.totalFrames = 0 self.ViewRectX = 0 self.ViewRectY = 0 self.ViewRectWidth = 0 self.ViewRectHeight = 0 # Ty keypoint drawing initialization self.SceneSize = 4.5 self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder self.BoxDrawer = QPen(Qt.green) self.BoxDrawer.setWidth(0.01) self.BoxFill = QBrush(Qt.green) self.key_points = [] # Ty draw trail lines initialization self.displayLineOn = False self.LineDrawer = QPen(Qt.green) self.LineWidth = (4 / 5)**self.Zoom_recorder self.LineDrawer.setWidth(self.LineWidth) self.LinePath = [] def hasImage(self): """ Returns whether or not the scene contains an image pixmap. """ return self._pixmapHandle is not None def clearImage(self): """ Removes the current image pixmap from the scene if it exists. """ if self.hasImage(): self.scene.removeItem(self._pixmapHandle) self._pixmapHandle = None def pixmap(self): """ Returns the scene's current image pixmap as a QPixmap, or else None if no image exists. :rtype: QPixmap | None """ if self.hasImage(): return self._pixmapHandle.pixmap() return None def image(self): """ Returns the scene's current image pixmap as a QImage, or else None if no image exists. :rtype: QImage | None """ if self.hasImage(): return self._pixmapHandle.pixmap().toImage() return None def setImage(self, fileName): """ Set the scene's current image pixmap to the input QImage or QPixmap. Raises a RuntimeError if the input image has type other than QImage or QPixmap. :type image: QImage | QPixmap """ image = QImage(fileName) if type(image) is QPixmap: pixmap = image elif type(image) is QImage: pixmap = QPixmap.fromImage(image) else: raise RuntimeError( "ImageViewer.setImage: Argument must be a QImage or QPixmap.") if self.hasImage(): self._pixmapHandle.setPixmap(pixmap) else: self._pixmapHandle = self.scene.addPixmap(pixmap) self.setSceneRect(QRectF( pixmap.rect())) # Set scene size to image size. self.updateViewer() self.mainWindow.ShowFrame.setText( 'frame:%3d' % GlobalData.currentFrame) ##put framenumber as text self.mainWindow.qtSceneViewer.setImage(fileName) def updateViewer(self): """ Show current zoom (if showing entire image, apply current aspect ratio mode). """ if not self.hasImage(): return if self.InitialFrame: self.fitInView( self.sceneRect(), self.aspectRatioMode ) # Show entire image (use current aspect ratio mode). self.GetFrame() self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox( self.ViewRectX, self.ViewRectY, self.ViewRectWidth, self.ViewRectHeight) def GetFrame(self): Rect = self.rect() Rect = self.mapToScene(Rect) self.ViewRectX = Rect[0].x() self.ViewRectY = Rect[0].y() RectD = Rect[2] - Rect[0] self.ViewRectWidth = RectD.x() self.ViewRectHeight = RectD.y() def wheelEvent( self, event): #need to have the setting on Qt.KeepAspectRatioByExpanding if event.angleDelta().y() < 0 and self.KeyControl is True: factor = 4 / 5 self.Zoom_recorder -= 1 elif event.angleDelta().y() > 0 and self.KeyControl is True: factor = 5 / 4 self.Zoom_recorder += 1 else: factor = 1 if factor != 1 and self.KeyControl is True: self.scale(factor, factor) self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder self.LineWidth = (4 / 5)**self.Zoom_recorder self.GetFrame() self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox( self.ViewRectX, self.ViewRectY, self.ViewRectWidth, self.ViewRectHeight) self.draw_key_points() self.draw_line_path() def Zoom_large(self): factor = 9 / 8 self.Zoom_recorder += 1 self.scale(factor, factor) factor = 1 self.GetFrame() self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox( self.ViewRectX, self.ViewRectY, self.ViewRectWidth, self.ViewRectHeight) self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder self.LineWidth = (4 / 5)**self.Zoom_recorder self.draw_key_points() self.draw_line_path() def Zoom_small(self): factor = 8 / 9 self.Zoom_recorder -= 1 self.scale(factor, factor) factor = 1 self.GetFrame() self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox( self.ViewRectX, self.ViewRectY, self.ViewRectWidth, self.ViewRectHeight) self.ViewSize = self.SceneSize * (4 / 5)**self.Zoom_recorder self.LineWidth = (4 / 5)**self.Zoom_recorder self.draw_key_points() self.draw_line_path() def mouseMoveEvent(self, event): scenePos = self.mapToScene(event.pos()) self.sX = int(round(scenePos.x())) self.sY = int(round(scenePos.y())) self.mainWindow.CursorXY.setText('x:%4d y:%4d ' % (self.sX, GlobalData.imgHeight - self.sY)) ##put coordinate as text QGraphicsView.mouseMoveEvent(self, event) if self.isPanning is True and self.mouseLeftPress is True: self.GetFrame() self.YellowBox = self.mainWindow.qtSceneViewer.DrawViewBox( self.ViewRectX, self.ViewRectY, self.ViewRectWidth, self.ViewRectHeight) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.mouseLeftPress = True if self.KeyControl: self.setDragMode(QGraphicsView.ScrollHandDrag) self.isPanning = True if self.digitizerOn is True and self.KeyControl is False: self.add_coordinate(self.sX, self.sY) if self.mainWindow.AutoNextMode.autoNextMode == 0: pass if self.mainWindow.AutoNextMode.autoNextMode == 1: self.next_frame() if self.mainWindow.AutoNextMode.autoNextMode == 2: self.prev_frame() if self.mainWindow.AutoNextMode.autoNextMode == 3: self.mainWindow.visableItemsLayout.selectNextItem() QGraphicsView.mousePressEvent(self, event) def mouseReleaseEvent(self, event): QGraphicsView.mouseReleaseEvent(self, event) if event.button() == Qt.LeftButton: self.setDragMode(QGraphicsView.NoDrag) self.mouseLeftPress = False self.isPanning = False self.leftMouseButtonReleased.emit(self.sX, self.sY) def next_frame(self): # Frame increment if GlobalData.currentFrame == GlobalData.totalFrames: pass else: GlobalData.currentFrame += 1 self.setImage( os.path.join(GlobalData.videoPath, str(GlobalData.currentFrame) + ".jpg")) self.mainWindow.Slider.setValue(GlobalData.currentFrame) self.draw_key_points() def prev_frame(self): # Frame decrement if GlobalData.currentFrame == 1: pass else: GlobalData.currentFrame -= 1 self.setImage( os.path.join(GlobalData.videoPath, str(GlobalData.currentFrame) + ".jpg")) self.mainWindow.Slider.setValue(GlobalData.currentFrame) self.draw_key_points() def slider_frame(self): GlobalData.currentFrame = self.mainWindow.Slider.value() self.setImage( os.path.join(GlobalData.videoPath, str(GlobalData.currentFrame) + ".jpg")) self.draw_key_points() def draw_key_points(self): if self.mainWindow.video_file_loaded == True and self.mainWindow.freezeAllEdite == False: # Grab all points references at the current frame if self.key_points: for reference in self.key_points: self.scene.removeItem(reference) self.key_points = [] for subject in GlobalData.global_subject_list: for part in subject.parts: if part.checked == True: x = part.x[GlobalData.currentFrame - 1] y = part.y[GlobalData.currentFrame - 1] reference = self.add_key_point(x, y) if reference == None: continue else: reference.setVisible(True) self.key_points.append(reference) def add_coordinate(self, x, y): selected_items = self.mainWindow.visableItemsLayout._visable_items.selectedItems( ) if len(selected_items) > 0: first_item = selected_items[0] parent_item = first_item.parent() # If the selected item is a child, then we can add coordinates if parent_item != None: subject_found = [ subject for subject in GlobalData.global_subject_list if subject.name == parent_item.text(0) ] part_found = [ part for part in subject_found[0].parts if part.name == first_item.text(0) ] item = recordItem(subject_found[0].name, part_found[0].name, part_found[0].x[GlobalData.currentFrame - 1], part_found[0].y[GlobalData.currentFrame - 1]) part_found[0].x[GlobalData.currentFrame - 1] = x part_found[0].y[GlobalData.currentFrame - 1] = y self.draw_key_points() self.draw_line_path() updateRecord(item) self.mainWindow.Undo_action.setEnabled(True) self.mainWindow.Redo_action.setEnabled(False) def add_key_point(self, x, y): if None in (x, y): reference = None else: reference = self.scene.addRect(x - self.ViewSize, y - self.ViewSize, 2 * self.ViewSize, 2 * self.ViewSize, self.BoxDrawer, self.BoxFill) return reference def draw_line_path(self): if self.LinePath: for segment in self.LinePath: self.scene.removeItem(segment) if self.displayLineOn: self.LinePath = [] self.LineDrawer.setWidth(self.LineWidth) #We will draw the object that is checked in the tree widget selected_items = self.mainWindow.visableItemsLayout._visable_items.selectedItems( ) if len(selected_items) > 0: first_item = selected_items[0] parent_item = first_item.parent() # If the selected item is a child, then we can add coordinates if parent_item != None: subject_found = [ subject for subject in GlobalData.global_subject_list if subject.name == parent_item.text(0) ] part_found = [ part for part in subject_found[0].parts if part.name == first_item.text(0) ] for i in range(GlobalData.totalFrames - 1): if None in (part_found[0].x[i], part_found[0].y[i], part_found[0].x[i + 1], part_found[0].y[i + 1]): continue else: segment = self.scene.addLine( part_found[0].x[i], part_found[0].y[i], part_found[0].x[i + 1], part_found[0].y[i + 1], self.LineDrawer) self.LinePath.append(segment) def keyPressEvent(self, event): #present in both mainWindow and QtImageViewer if event.key() == Qt.Key_Control: self.KeyControl = True if event.key() == Qt.Key_Down: self.mainWindow.visableItemsLayout.selectNextItem() if event.key() == Qt.Key_Up: self.mainWindow.visableItemsLayout.selectPreviousItem() def keyReleaseEvent(self, event): #present in both mainWindow and QtImageViewer if event.key() == Qt.Key_Control: self.KeyControl = False
if __name__ == '__main__': logInstance = Logger() logInstance.addLogger(loggers.StreamLogger([0])) setLoggerInstance(logInstance) log("Setting up window...") app = QApplication(sys.argv) #ex = GoWindow() #app.exec_() #log("Done!") w = Window(500, 500, "test", processingLoop=loop) # create a scene scene = QGraphicsScene() scene.addLine(10, 10, 500, 500) g = Grid(10, 10, 10, 10) scene.addItem(g) #scene.addRect(150,0,40,20, QPen(), QBrush(QColor(30,60,120))) elem = GUIElement() scene.addItem(elem) w.addScene(scene) w.setScene(0) app.exec_() #w.display()
class Spectrum(QWidget): """Plot the power spectrum for a specified channel. Attributes ---------- parent : instance of QMainWindow the main window. x_limit : tuple or list 2 values specifying the limit on x-axis y_limit : tuple or list 2 values specifying the limit on y-axis log : bool log-transform the data or not idx_chan : instance of QComboBox the element with the list of channel names. idx_x_min : instance of QLineEdit value with min x value idx_x_max : instance of QLineEdit value with max x value idx_y_min : instance of QLineEdit value with min y value idx_y_max : instance of QLineEdit value with max y value idx_log : instance of QCheckBox widget that defines if log should be used or not idx_fig : instance of QGraphicsView the view with the power spectrum scene : instance of QGraphicsScene the scene with GraphicsItems Notes ----- If data contains NaN, it doesn't create any spectrum (feature or bug?). """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigSpectrum(self.display_window) self.selected_chan = None self.idx_chan = None self.idx_fig = None self.scene = None self.create() def create(self): """Create empty scene for power spectrum.""" self.idx_chan = QComboBox() self.idx_chan.activated.connect(self.display_window) self.idx_fig = QGraphicsView(self) self.idx_fig.scale(1, -1) layout = QVBoxLayout() layout.addWidget(self.idx_chan) layout.addWidget(self.idx_fig) self.setLayout(layout) self.resizeEvent(None) def show_channame(self, chan_name): self.selected_chan = self.idx_chan.currentIndex() self.idx_chan.clear() self.idx_chan.addItem(chan_name) self.idx_chan.setCurrentIndex(0) def update(self): """Add channel names to the combobox.""" self.idx_chan.clear() for chan_name in self.parent.traces.chan: self.idx_chan.addItem(chan_name) if self.selected_chan is not None: self.idx_chan.setCurrentIndex(self.selected_chan) self.selected_chan = None def display_window(self): """Read the channel name from QComboBox and plot its spectrum. This function is necessary it reads the data and it sends it to self.display. When the user selects a smaller chunk of data from the visible traces, then we don't need to call this function. """ if self.idx_chan.count() == 0: self.update() chan_name = self.idx_chan.currentText() lg.debug('Power spectrum for channel ' + chan_name) if chan_name: trial = 0 data = self.parent.traces.data(trial=trial, chan=chan_name) self.display(data) else: self.scene.clear() def display(self, data): """Make graphicsitem for spectrum figure. Parameters ---------- data : ndarray 1D vector containing the data only This function can be called by self.display_window (which reads the data for the selected channel) or by the mouse-events functions in traces (which read chunks of data from the user-made selection). """ value = self.config.value self.scene = QGraphicsScene(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) self.idx_fig.setScene(self.scene) self.add_grid() self.resizeEvent(None) s_freq = self.parent.traces.data.s_freq f, Pxx = welch(data, fs=s_freq, nperseg=int(min( (s_freq, len(data))))) # force int freq_limit = (value['x_min'] <= f) & (f <= value['x_max']) if self.config.value['log']: Pxx_to_plot = log(Pxx[freq_limit]) else: Pxx_to_plot = Pxx[freq_limit] self.scene.addPath(Path(f[freq_limit], Pxx_to_plot), QPen(QColor(LINE_COLOR), LINE_WIDTH)) def add_grid(self): """Add axis and ticks to figure. Notes ----- I know that visvis and pyqtgraphs can do this in much simpler way, but those packages create too large a padding around the figure and this is pretty fast. """ value = self.config.value # X-AXIS # x-bottom self.scene.addLine(value['x_min'], value['y_min'], value['x_min'], value['y_max'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # at y = 0, dashed self.scene.addLine(value['x_min'], 0, value['x_max'], 0, QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine)) # ticks on y-axis y_high = int(floor(value['y_max'])) y_low = int(ceil(value['y_min'])) x_length = (value['x_max'] - value['x_min']) / value['x_tick'] for y in range(y_low, y_high): self.scene.addLine(value['x_min'], y, value['x_min'] + x_length, y, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # Y-AXIS # left axis self.scene.addLine(value['x_min'], value['y_min'], value['x_max'], value['y_min'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # larger ticks on x-axis every 10 Hz x_high = int(floor(value['x_max'])) x_low = int(ceil(value['x_min'])) y_length = (value['y_max'] - value['y_min']) / value['y_tick'] for x in range(x_low, x_high, 10): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # smaller ticks on x-axis every 10 Hz y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2 for x in range(x_low, x_high, 5): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) def resizeEvent(self, event): """Fit the whole scene in view. Parameters ---------- event : instance of Qt.Event not important """ value = self.config.value self.idx_fig.fitInView(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) def reset(self): """Reset widget as new""" self.idx_chan.clear() if self.scene is not None: self.scene.clear() self.scene = None
class myWindow(QtWidgets.QWidget, Ui_MainWindow): def __init__(self): super(myWindow, self).__init__() self.setupUi(self) self.Ui_init() myWindow.setWindowFlags(self, QtCore.Qt.WindowStaysOnTopHint) def Ui_init(self): # 传递界面类 self.fupin = fupinWindow() self.shiyan = shiyanWindow() self.conn = connectWindow() self.busy = busyWindow() # 菜单栏初始化 self.printAction1 = QAction(self.tr("退出"), self) self.menu.addAction(self.printAction1) self.printAction1.triggered.connect(lambda: self.tuichu()) self.printAction2 = QAction(self.tr("幅频显示"), self) self.printAction3 = QAction(self.tr("点对点时延"), self) self.menu_2.addAction(self.printAction2) self.menu_2.addAction(self.printAction3) self.printAction2.triggered.connect(lambda: self.showFupin()) self.fupin.backsignal1.connect(lambda: self.showmain()) self.printAction3.triggered.connect(lambda: self.showShiyan()) self.shiyan.backsignal2.connect(lambda: self.showmain()) self.busy.backsignal5.connect(self.busy_backsignal5) self.printAction4 = QAction(self.tr("参数设置"), self) self.menu_3.addAction(self.printAction4) self.printAction4.triggered.connect(lambda: self.showConnect()) self.conn.backsignal3.connect(self.context_unit) self.conn.backsignal4.connect(lambda: self.showmain()) # 窗口底部图标简介 pix1 = QPixmap(':/myIcons/绿.jpg').scaledToWidth(18).scaledToHeight(18) self.label_2.setPixmap(pix1) pix2 = QPixmap(':/myIcons/红.jpg').scaledToWidth(20).scaledToHeight(20) self.label_4.setPixmap(pix2) # 参数 self.old = 2 self.error = True self.connectError = False # 拓扑显示初始化 self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.graphicsView.scene = QtWidgets.QGraphicsScene(0, 0, 1920, 1080) self.graphicsView.setScene(self.graphicsView.scene) self.graphicsView.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.graphicsView.setSceneRect(0, 0, 3840, 1160) # fix scene size 500 500 self.graphicsView.setRenderHint(QPainter.Antialiasing) ##设置视图的抗锯齿渲染模式。 self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) # 拓扑显示控制按钮 self.pushButton_3.clicked.connect(lambda: self.startShow()) # 联机按钮 self.pushButton.clicked.connect(lambda: self.connect()) # 默认显示之前的页面 global topoList_A, topoList_B, topoList_C, oldNodeList getTopoA = "select * from oldTopo_A" getTopoB = "select * from oldTopo_B" getTopoC = "select * from oldTopo_C" topoList_A = self.getTopo(getTopoA) oldNodeList.extend(topoList_A) topoList_B = self.getTopo(getTopoB) oldNodeList.extend(topoList_B) topoList_C = self.getTopo(getTopoC) oldNodeList.extend(topoList_C) self.initialization(oldNodeList) #开始测量按钮 self.pushButton_4.clicked.connect(lambda: self.startMeasure()) self.pushButton_3.setEnabled(False) self.pushButton_4.setEnabled(False) self.printAction2.setEnabled(False) self.printAction3.setEnabled(False) # 线程 self.startM = Qmeasure() self.startM.endflag.connect(self.changeUI) self.topo = QTopo() self.topo.endflag.connect(self.newToposhow) self.countnum = Qcount() self.countnum.count.connect(self.showcount) self.counttopo = Qcounttopo() self.counttopo.count.connect(self.showcounttopo) self.step = 0 self.progressBar.setValue(self.step) #选项框 self.comboBox.currentIndexChanged.connect(self.btnStateChange) readConfigurationFile("Serial").setCon("serial_or_udp", "1") # myconfig = configparser.ConfigParser() # myconfig.read('config.ini') # myconfig.set("Serial", "serial_or_udp", "1") # myconfig.write(open("config.ini", "w+")) ''' 页面跳转的方法 showmain():显示主页面 tuichu():退出程序 showFupin():显示幅频页面 showShiyan():显示时延页面 showBusy():显示繁忙页面 context_unit():将参数设置页面中设置的参数返回主页面中 ''' # 显示主页面 def showmain(self): self.setVisible(1) # 退出应用 def tuichu(self): self.close() # 显示幅频曲线界面 def showFupin(self): self.fupin.cancelbt() self.setVisible(0) # 隐藏主界面 self.fupin.setVisible(1) # 显示时延界面 def showShiyan(self): self.shiyan.cancelbt() self.shiyan.textEdit.clear() self.setVisible(0) self.shiyan.setVisible(1) def showConnect(self): self.setVisible(0) self.conn.setVisible(1) # print(context) def showBusy(self): self.setVisible(0) self.busy.setVisible(1) def context_unit(self, i1, i2, i3, i4, i5): global paraList paraList = [] paraList.append(i1) paraList.append(i2) paraList.append(i3) paraList.append(i4) paraList.append(i5) self.setVisible(1) #选项框状态修改 def btnStateChange(self): s1 = str(self.comboBox.currentText()) if s1 == '串口': readConfigurationFile("Serial").setCon("serial_or_udp", "1") else: readConfigurationFile("Serial").setCon("serial_or_udp", "0") ''' 测量过程中主页面显示函数 根据标志位flag=1时,将测量按钮设为禁用状态,当测量结束后并调用拓扑发现算法,恢复测量到的网络拓扑结构 标志位flag!=1时,则表明测量过程中出现错误,要想重新测量则将测量按钮激活,否则的话退出程序 ''' # 测量过程中主页面显示的逻辑 def changeUI(self, flag): if flag == 1: self.pushButton_3.setEnabled(True) self.printAction2.setEnabled(True) self.printAction3.setEnabled(True) self.pushButton_4.setText('启动测量') self.pushButton_4.setDisabled(False) end = QMessageBox.information(self, "测量结束提示框", "结束测量,是否开始显示", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if end == QMessageBox.Yes: # time.sleep(1) QApplication.processEvents() self.topo.start() self.counttopo.start() self.pushButton_4.setText('正在计算拓扑') self.pushButton_4.setDisabled(True) self.pushButton_3.setEnabled(False) self.pushButton.setEnabled(False) self.printAction2.setEnabled(False) self.printAction3.setEnabled(False) else: start = QMessageBox.information(self, "测量错误提示框", "是否重新测量?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if start == QMessageBox.Yes: self.pushButton_3.setEnabled(True) self.printAction2.setEnabled(True) self.printAction3.setEnabled(True) self.pushButton_4.setText('启动测量') self.pushButton_4.setDisabled(False) else: self.tuichu() ''' 拓扑计算完成后的拓扑显示函数 计算完成后将菜单栏中的“时延测量”、“幅频显示”选项的状态激活 若是计算过程中出错则直接退出程序 ''' # 拓扑计算完成后的拓扑显示函数 def newToposhow(self, flag): if flag == 1: self.pushButton_4.setText('计算完成') self.pushButton_4.setDisabled(False) self.pushButton_3.setDisabled(False) self.pushButton.setEnabled(False) self.printAction2.setEnabled(True) self.printAction3.setEnabled(True) logging.info('计算完成') time.sleep(1) global topoList_A, topoList_B, topoList_C, newNodeList getTopoA = "select * from newTopo_A" getTopoB = "select * from newTopo_B" getTopoC = "select * from newTopo_C" topoList_A = self.getTopo(getTopoA) newNodeList.extend(topoList_A) topoList_B = self.getTopo(getTopoB) newNodeList.extend(topoList_B) topoList_C = self.getTopo(getTopoC) newNodeList.extend(topoList_C) self.initialization(newNodeList) self.pushButton_4.setText('启动测量') self.old = 1 self.pushButton_3.setText("当前拓扑") QApplication.processEvents() logging.info('拓扑已显示') else: start = QMessageBox.information(self, "计算错误提示框", "拓扑计算出错,退出!", QMessageBox.Yes, QMessageBox.Yes) if start == QMessageBox.Yes: self.tuichu() ''' 设置进度条值的函数 showcount():将已测量节点数目线程返回的数值处理后,设置进度条的值 showcounttopo():将拓扑计算算法过程的线程返回数值处理后,设置进度条的值 ''' def showcount(self, connect_num): self.step = (connect_num / num) * 85 self.progressBar.setValue(int(self.step)) self.label_6.setText('已经测量了 %d 个点' % connect_num) def showcounttopo(self, measure_num): self.step = measure_num + 85 self.progressBar.setValue(self.step) if self.step < 100: self.label_6.setText("正在计算拓扑") else: self.label_6.setText("测量完成") ''' 系统繁忙页面返回信号的槽函数 若是选择重新发送操作选项,则是直接返回主页面 若是选择取消操作选项,则是调用接口程序 ''' # 系统繁忙 def busy_backsignal5(self, num): if num == 1: # 重新发送操作 self.setVisible(1) else: self.setVisible(1) def settreeflag(self, flag): global tree_flag tree_flag = flag ''' 主页面显示函数 (1)节点目录和节点信息目录清空 (2)查询数据库节点信息,设置节点目录treeWidget和节点信息目录tableWidget中的信息 (3)调用isclick函数,点击节点目录treeWidget中的节点,会在节点信息目录tableWidget中显示相应的节点信息 (4)调用topo_show函数,显示恢复的网络拓扑 ''' # 默认显示之前的页面 def initialization(self, nodelist): logging.info('页面初始化开始') global reallist reallist = self.getRealNode(nodelist) self.treeWidget.clear() self.tableWidget.clear() # 树状目录初始化 self.treeWidget.setColumnCount(1) self.treeWidget.setColumnWidth(0, 50) self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) groupname = 'root' root1 = self.creategroup(groupname, reallist) root1.setExpanded(False) # 设置树状结构最外层节点的图标显示 i = 0 while i < self.treeWidget.topLevelItemCount(): self.treeWidget.topLevelItem(i).setIcon(0, QIcon(':/myIcons/房.jpg')) i = i + 1 # 表格初始化 self.tableWidget.setRowCount(1) self.tableWidget.setColumnCount(2) self.tableWidget.setHorizontalHeaderLabels(['名字', '与父节点的距离']) self.tableWidget.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) QTableWidget.resizeColumnsToContents(self.tableWidget) QTableWidget.resizeRowsToContents(self.tableWidget) self.treeWidget.itemClicked.connect(self.isclick) # 显示拓扑 t1 = threading.Thread(target=self.topo_show(topoList_A, topoList_B, topoList_C), name='function') t1.start() logging.info('页面初始化完成') ''' 联机函数 调用接口程序,根据接口程序返回的标志位flag进行相应的操作 flag=1,则表示联机成功,并调用connectEnd()函数 flag=-1,则表示系统繁忙,并调用showBusy()函数 flag!=1且flag!=-1,则表示联机出错,并调用connectEnd()函数,退出程序 ''' # 联机函数 def connect(self): logging.info('联机开始') global num # 根据设定的参数来进行联机操作 (flag, num) = ser.build_order() flag = 1 if flag == 1: self.connectError = False self.connectEnd() elif flag == -1: self.showBusy() else: self.connectError = True self.connectEnd() ''' 联机是否成功函数 connectError= True,则表示联机出错,退出程序 connectError= False,则表示联机成功,将联机按钮状态设为禁用,其余按钮设为激活状态 ''' def connectEnd(self): if self.connectError: QMessageBox.information(self, "联机出错提示框", "组网未成功", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) time.sleep(2) # 模拟退出页面 self.tuichu() else: QMessageBox.information(self, "联机成功提示框", "联机成功", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) #20200120 by e self.pushButton.setEnabled(False) self.pushButton.setText('已联机') self.pushButton_3.setDisabled(False) # self.old=2 self.pushButton_3.setText('历史拓扑') self.pushButton_4.setEnabled(True) self.printAction2.setEnabled(True) self.printAction3.setEnabled(True) self.comboBox.setDisabled(True) QApplication.processEvents() logging.info('联机完成') ''' 拓扑切换函数,根据self.old值显示拓扑图 ''' #拓扑控制按钮 def startShow(self): logging.info('拓扑切换开始') if self.old == 1: global topoList_A, topoList_B, topoList_C, oldNodeList getTopoA = "select * from oldTopo_A" getTopoB = "select * from oldTopo_B" getTopoC = "select * from oldTopo_C" topoList_A = self.getTopo(getTopoA) oldNodeList.extend(topoList_A) topoList_B = self.getTopo(getTopoB) oldNodeList.extend(topoList_B) topoList_C = self.getTopo(getTopoC) oldNodeList.extend(topoList_C) self.initialization(oldNodeList) QApplication.processEvents() self.pushButton_3.setText("历史拓扑") self.old = 2 elif self.old == 2: getTopoA = "select * from newTopo_A" getTopoB = "select * from newTopo_B" getTopoC = "select * from newTopo_C" topoList_A = self.getTopo(getTopoA) newNodeList.extend(topoList_A) topoList_B = self.getTopo(getTopoB) newNodeList.extend(topoList_B) topoList_C = self.getTopo(getTopoC) newNodeList.extend(topoList_C) self.initialization(newNodeList) QApplication.processEvents() self.pushButton_3.setText("当前拓扑") self.old = 1 logging.info('拓扑切换完成') ''' 节点目录创建分组函数、节点点击和节点信息显示联动函数 ''' # 节点目录创建分组 def creategroup(self, groupname, childList): group = QTreeWidgetItem(self.treeWidget) num_child = len(childList) j = 0 while j < num_child: dict1 = childList[j].getName() child = QTreeWidgetItem() child.setText(0, dict1) child.setIcon(0, QIcon(':/myIcons/绿.jpg')) child.setTextAlignment(0, Qt.AlignHCenter | Qt.AlignVCenter) j = j + 1 group.addChild(child) group.setText(0, groupname) return group # 节点点击和拓扑显示联动 def isclick(self, item, column): # 最小的节点,输出节点信息 global reallist if item.child(0) is None: for i in range(0, len(reallist)): if item.text(column) == reallist[i].getName(): newItem1 = QTableWidgetItem(reallist[i].getName()) self.tableWidget.setItem(0, 0, newItem1) newItem2 = QTableWidgetItem(str(reallist[i].getLength())) self.tableWidget.setItem(0, 1, newItem2) break else: newItem1 = QTableWidgetItem(reallist[0].getName()) self.tableWidget.setItem(0, 0, newItem1) newItem2 = QTableWidgetItem(str(reallist[0].getLength())) self.tableWidget.setItem(0, 1, newItem2) # 开始测量页面显示的槽函数,调用接口程序并将已测量节点数目返回主页面 def startMeasure(self): logging.info('重新测量开始') # 弹出参数设置页面 logging.info('参数设置') # 测量开始提示框 start = QMessageBox.information(self, "测量开始提示框", "是否开始测量?", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if start == QMessageBox.Yes: self.startM.start() self.countnum.start() self.pushButton_4.setText('正在测量') self.pushButton_4.setDisabled(True) self.pushButton_3.setEnabled(False) self.pushButton.setEnabled(False) self.printAction2.setEnabled(False) self.printAction3.setEnabled(False) logging.info('重新测量结束') # 重新测量 def reMeasure(self): logging.info('重新测量页面开始显示') global topoList_A, topoList_B, topoList_C, newNodeList, newRealList getTopoA = "select * from newTopo_A" getTopoB = "select * from newTopo_B" getTopoC = "select * from newTopo_C" topoList_A = self.getTopo(getTopoA) newNodeList.extend(topoList_A) topoList_B = self.getTopo(getTopoB) newNodeList.extend(topoList_B) topoList_C = self.getTopo(getTopoC) newNodeList.extend(topoList_C) newRealList = self.getRealNode(newNodeList) self.treeWidget.clear() self.tableWidget.clear() logging.info('节点信息显示') # 树状目录初始化 self.treeWidget.setColumnCount(1) self.treeWidget.setColumnWidth(0, 50) self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) groupname = 'root' root1 = self.creategroup(groupname, newRealList) root1.setExpanded(False) # 设置树状结构最外层节点的图标显示 self.treeWidget.topLevelItem(0).setIcon(0, QIcon(':/myIcons/房.jpg')) # 表格初始化 self.tableWidget.setRowCount(1) self.tableWidget.setColumnCount(2) self.tableWidget.setHorizontalHeaderLabels(['名字', '与父节点的距离']) self.tableWidget.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) QTableWidget.resizeColumnsToContents(self.tableWidget) QTableWidget.resizeRowsToContents(self.tableWidget) self.treeWidget.itemClicked.connect(self.newisclick) logging.info('节点信息显示完成') self.graphicsView.setScene(self.graphicsView.scene) self.graphicsView.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.graphicsView.setSceneRect(0, 0, 3840, 1160) # fix scene size 500 500 self.graphicsView.setRenderHint(QPainter.Antialiasing) ##设置视图的抗锯齿渲染模式。 self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) logging.info('拓扑显示') t1 = threading.Thread(target=self.topo_show(topoList_A, topoList_B, topoList_C), name='function') t1.start() logging.info('重新测量页面完成显示') # 节点点击和拓扑显示联动 def newisclick(self, item, column): # 最小的节点,输出节点信息 global newRealList if item.child(0) is None: for i in range(0, len(newRealList)): if item.text(column) == newRealList[i].getName(): newItem1 = QTableWidgetItem(newRealList[i].getName()) self.tableWidget.setItem(0, 0, newItem1) newItem2 = QTableWidgetItem(newRealList[i].getLength()) self.tableWidget.setItem(0, 1, newItem2) break else: newItem1 = QTableWidgetItem(newRealList[0].getName()) self.tableWidget.setItem(0, 0, newItem1) newItem2 = QTableWidgetItem(newRealList[0].getLength()) self.tableWidget.setItem(0, 1, newItem2) ''' 处理读取到的数据库信息的函数 getTopo():读取数据库中的内容,并将数据库中每一行的数据使用Node对象存储起来,将全部数据使用list数据类型存储 getRoot():获取getTopo()函数返回的list数据类型中的root节点 getRealNode():获取getTopo()函数返回的list数据类型中的真实节点,返回list数据类型 ''' def getTopo(self, sql): newList = [] IDListNew = {} try: results = Sqlite().select(sql) for row in results: node = Node() IDListNew[row[0]] = node newList.append(node) for row in results: n = IDListNew.get(row[0]) if row[1] != None: n.setName(row[1]) if row[2] != None: n.setFather(IDListNew.get(row[2])) n.setLength(row[3]) if row[4] != None: n.setFirstChild(IDListNew.get(row[4])) if row[5] != None: n.setRightBrother(IDListNew.get(row[5])) if row[6] == 1: n.setisVirtualNode(True) except: print("No Data") return newList def getRoot(self, List: list): node = Node() for n in List: if n.getFather() == None: node = n break return node def getRealNode(self, List: list): RealNodeList = [] for node in List: if node.getisVirtualNode(): continue RealNodeList.append(node) return RealNodeList def create_icon(self, type, x, y): ccoimage = QImage('../Interface/cco.png') steimage = QImage('../Interface/ste.png') vimage = QImage('../Interface/v.png') if type == "cco": ret = QGraphicsPixmapItem(QPixmap.fromImage(ccoimage)) elif type == "ste": ret = QGraphicsPixmapItem(QPixmap.fromImage(steimage)) else: ret = QGraphicsPixmapItem(QPixmap.fromImage(vimage)) ret.setPos(x, y) self.scene.addItem(ret) return ret def topo_show(self, ListA: list, ListB: list, ListC: list): sip.delete(self.graphicsView.scene) # self.graphicsView.scene = QtWidgets.QGraphicsScene(0, 0, 800, 600) self.graphicsView.scene = QtWidgets.QGraphicsScene(0, 0, 1500, 1000) self.graphicsView.setScene(self.graphicsView.scene) self.graphicsView.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) # self.graphicsView.setSceneRect(0, 0, 1600, 1200) # fix scene size 500 500 self.graphicsView.setSceneRect(0, 0, 3000, 1800) # fix scene size 500 500 self.graphicsView.setRenderHint(QPainter.Antialiasing) ##设置视图的抗锯齿渲染模式。 self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) root_nodeA = self.getRoot(ListA) root_nodeB = self.getRoot(ListB).getFirstChild() root_nodeC = self.getRoot(ListC).getFirstChild() color_A = QPen(Qt.green) ymax_A = self.single_topo(ListA, 0, 0, 0, root_nodeA, color_A) yby = ymax_A - 80 color_B = QPen(Qt.darkCyan) ymax_B = self.single_topo(ListB, 10, yby, ymax_A, root_nodeB, color_B) ycy = ymax_B - 80 color_C = QPen(Qt.cyan) self.single_topo(ListC, 20, ycy, ymax_B, root_nodeC, color_C) self.graphicsView.centerOn(0, 00) printer_pixmap = QPrinter(QPrinter.HighResolution) printer_pixmap.setPageSize(QPrinter.A4) printer_pixmap.setOutputFormat(QPrinter.PdfFormat) time_str = datetime.datetime.now().strftime('%Y%m%d-%H_%M_%S') pngname = '../backup/topo/' + time_str + '.pdf' printer_pixmap.setOutputFileName(pngname) outputimg = QPixmap(3840, 1160) outputimg.fill(Qt.white) self.graphicsView.viewport().render(outputimg) painter_pixmap = QPainter() painter_pixmap.begin(printer_pixmap) rect = painter_pixmap.viewport() multiple = 3 * rect.width() / outputimg.width() painter_pixmap.scale(multiple, multiple) painter_pixmap.drawPixmap(0, 0, outputimg) painter_pixmap.end() def single_topo(self, List: list, xm, ym, ymax, root_node: Node, color): MIN = float(readConfigurationFile("Topo").getCon("min_dely")) threshold = MIN + 0.1 icon_width = 32 toponodes = [] toponodes.append(root_node) icons = [] icon_count = 0 index_y = [] if len(List) == 0: return 0 for node in toponodes: (y, x) = topo_picture().icon_locate(node, icon_width, icon_width, 100, 100) y = y + ym x = x - xm index_y.append(y) if node == root_node: if xm == 0: x = x - 10 y = y - 10 iconi = self.create_icon("cco", x, y) icons.append(iconi) iconi.setPos(x, y) icon_count = icon_count + 1 self.root_name = QGraphicsTextItem(str(node.getName())) self.root_name.setDefaultTextColor(Qt.black) # self.name.setDefaultTextColor(QColor(0, 160, 230)) self.root_name.setPos(QPointF(x, y + icon_width / 2 + 7)) self.scene.addItem(self.root_name) else: self.scene.addRect(x + icon_width / 2 - 4, y + icon_width / 2 - 4, 8, 8, QPen(Qt.blue), QBrush(Qt.darkBlue)) else: xp = x + icon_width / 2 yp = y + icon_width / 2 node_father = None node_graFather = None fx = 0 fy = 0 if node is not None: node_father = node.getFather() if node_father is not None: node_graFather = node_father.getFather() if node_graFather is not None: if node_graFather.getisVirtualNode( ) and node_father.getisVirtualNode(): if float(node_father.getLength()) < threshold: if node_graFather.getLength() is not None: while node_graFather.getFather( ) is not None and float( node_graFather.getLength() < threshold ): if node_graFather.getFather( ).getisVirtualNode(): node_graFather = node_graFather.getFather( ) else: break (fy, fx) = topo_picture().icon_locate( node_graFather, icon_width, icon_width, 100, 100) else: (fy, fx) = topo_picture().icon_locate( node_father, icon_width, icon_width, 100, 100) else: (fy, fx) = topo_picture().icon_locate( node_father, icon_width, icon_width, 100, 100) else: (fy, fx) = topo_picture().icon_locate(node_father, icon_width, icon_width, 100, 100) fxp = fx + icon_width / 2 - xm fyp = fy + icon_width / 2 + ym ky = fyp - yp kx = fxp - xp if ky != 0: k = kx / ky if float(node.getLength()) > threshold: self.scene.addLine(xp, yp, fxp, fyp, color) elif float(node.getLength() ) <= threshold and node.getisVirtualNode() == False: self.scene.addLine(xp, yp, fxp, fyp, color) elif float(node.getLength()) <= threshold and node.getFather( ).getFather() is None: self.scene.addLine(xp, yp, fxp, fyp, color) if ky == 0 or k == 0: if float(node.getLength()) > threshold: self.length = Decimal(node.getLength()) self.length = self.length.quantize( Decimal('1'), ROUND_UP) self.context = QGraphicsTextItem(str(self.length)) self.context.setDefaultTextColor(Qt.black) self.font = QFont() self.font.setPixelSize(10) self.context.setFont(self.font) self.context.setPos( QPointF((xp + fxp - icon_width) / 2, (yp + fyp - icon_width) / 2)) self.scene.addItem(self.context) elif float(node.getLength( )) <= threshold and node.getisVirtualNode() == False: self.length = Decimal(node.getLength()) self.length = self.length.quantize( Decimal('1'), ROUND_UP) self.context = QGraphicsTextItem(str(self.length)) self.context.setDefaultTextColor(Qt.black) self.font = QFont() self.font.setPixelSize(10) self.context.setFont(self.font) self.context.setPos( QPointF((xp + fxp - icon_width) / 2, (yp + fyp - icon_width) / 2)) self.scene.addItem(self.context) elif node.getFather().getFather() is None: self.length = Decimal(node.getLength()) self.length = self.length.quantize( Decimal('1'), ROUND_UP) self.context = QGraphicsTextItem(str(self.length)) self.context.setDefaultTextColor(Qt.black) self.font = QFont() self.font.setPixelSize(10) self.context.setFont(self.font) self.context.setPos( QPointF((xp + fxp - icon_width) / 2, (yp + fyp - icon_width) / 2)) self.scene.addItem(self.context) else: if node.getisVirtualNode() == False: self.length = Decimal(node.getLength()) self.length = self.length.quantize( Decimal('1'), ROUND_UP) self.context = QGraphicsTextItem(str(self.length)) self.context.setDefaultTextColor(Qt.black) self.font = QFont() self.font.setPixelSize(10) self.context.setFont(self.font) self.context.setPos( QPointF((xp + fxp - icon_width) / 2, (yp + fyp - icon_width) / 2)) self.scene.addItem(self.context) elif node.getisVirtualNode() and float( node.getLength()) > threshold: self.length = Decimal(node.getLength()) self.length = self.length.quantize( Decimal('1'), ROUND_UP) self.context = QGraphicsTextItem(str(self.length)) self.context.setDefaultTextColor(Qt.black) self.font = QFont() self.font.setPixelSize(10) self.context.setFont(self.font) self.context.setPos( QPointF((xp + fxp - icon_width) / 2, (yp + fyp - icon_width) / 2)) self.scene.addItem(self.context) if node.getisVirtualNode(): if float(node.getLength()) > threshold: self.scene.addRect(x + icon_width / 2 - 4, y + icon_width / 2 - 4, 8, 8, QPen(Qt.blue), QBrush(Qt.darkBlue)) elif float( node.getLength() ) <= threshold and node_father.getisVirtualNode() == False: self.scene.addRect(x + icon_width / 2 - 4, y + icon_width / 2 - 4, 8, 8, QPen(Qt.blue), QBrush(Qt.darkBlue)) else: iconi = self.create_icon("ste", x, y) icons.append(iconi) iconi.setPos(x, y) # 添加真实节点的名字 self.name = QGraphicsTextItem(str(node.getName()[-4:])) self.name.setDefaultTextColor(Qt.black) self.name.setPos(QPointF(x, y + icon_width / 2 + 7)) self.scene.addItem(self.name) child = node.getFirstChild() while child is not None: for node_child in List: if child == node_child: toponodes.append(node_child) child = child.getRightBrother() if xm != 0: fxp1 = 100 + icon_width / 2 - xm fyp1 = 100 + icon_width / 2 xp1 = fxp1 yp1 = fyp1 + ymax - xm self.scene.addLine(fxp1, fyp1, xp1, yp1, color) self.length = Decimal(node.getLength()) self.length = self.length.quantize(Decimal('1'), ROUND_UP) self.context = QGraphicsTextItem(str(self.length)) self.font = QFont() self.font.setPixelSize(10) self.context.setFont(self.font) self.context.setDefaultTextColor(Qt.black) self.context.setPos(QPointF(xp1, (yp1 + fyp1) / 2)) self.scene.addItem(self.context) ymax = max(index_y) return ymax
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)
class SchedulerGUI(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent=parent) self.setupUi(self) self.schedule = sampleSchedule() self.activatedColumns = {} for key in self.schedule.columns: self.activatedColumns[key] = True self.lang = 'en' self.restore_buttons = [] self.restoreAllButton.clicked.connect(self.restoreAllColumns) self.translateDict = {} for widget in self.centralwidget.findChildren((QPushButton, QLabel)): langDict = {} for l in languages: langDict[l] = trans(widget.text(), l) key = widget self.translateDict[key] = langDict self.translateWidgets() self.language0Button.clicked.connect(partial(self.changeLang, 'en')) self.language1Button.clicked.connect(partial(self.changeLang, 'ru')) self.language2Button.clicked.connect(partial(self.changeLang, 'de')) self.drawAlarm = QTimer() self.drawAlarm.timeout.connect(self.drawAlarmFunc) self.drawAlarm.start(0.3) def closeEvent(self, event): quit() def resizeEvent(self, event): self.draw() def drawAlarmFunc(self): self.drawAlarm.stop() self.draw() def draw(self): self.scheduleScene = QGraphicsScene() self.activatedScene = QGraphicsScene() self.w = self.scheduleView.width() self.h = Y_SIDE * 24 self.h_a = self.activatedView.height() self.gridPen = QPen(QtCore.Qt.gray) for i in range(0, 24): self.scheduleScene.addLine(0, i * Y_SIDE, self.w, i * Y_SIDE) self.drawTimeTapes() cols = self.getActivatedColumns() if (len(cols) > 0): self.drawColumns(cols) self.scheduleView.setScene(self.scheduleScene) self.activatedView.setScene(self.activatedScene) def drawTimeTapes(self): for i in range(0, len(self.schedule.timeTapes)): self.scheduleScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h) self.activatedScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h_a) l = QLabel(self.schedule.timeTapes[i].name) l.move(WIDTH_TL * i, 0) self.activatedScene.addWidget(l) for j in range(0, 24): l = QLabel(self.schedule.timeTapes[i].labels[j]) l.move(WIDTH_TL * i, Y_SIDE * j) self.scheduleScene.addWidget(l) def drawColumns(self, cols): x_offset = WIDTH_TL * len(self.schedule.timeTapes) act_col_width = (self.w - x_offset) / len(cols) self.deactivateButtons = [] for i in range(0, len(cols)): self.scheduleScene.addLine(x_offset + act_col_width * i, 0, x_offset + act_col_width * i, self.h) self.activatedScene.addLine(x_offset + act_col_width * i, 0, x_offset + act_col_width * i, self.h_a) b = QPushButton(cols[i].name[self.lang]) b.move(x_offset + act_col_width * i, 0) b.clicked.connect(partial(self.deactivateColumn, cols[i].abr)) b.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) b.resize(act_col_width, self.h_a) b = self.activatedScene.addWidget(b) for event in cols[i].events: self.drawEvent(event, x_offset, act_col_width, i) def drawEvent(self, event, x_offset, col_width, x_loc): t0_f = timeStrToFloat(event.t0) t1_f = timeStrToFloat(event.t1) length = (t1_f - t0_f) * (self.h / 24) space = QtCore.QSizeF(col_width, length) ### Checks maximum font size if level font_size = MAX_EVENT_FONT_PT l_title = QLabel(event.title[self.lang]) l_time = QLabel(' (' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \ l_time.fontMetrics().boundingRect(l_time.text()).width() title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() while (title_height > length or title_width > col_width) and font_size > MIN_EVENT_FONT_PT: font_size -= 1 l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \ l_time.fontMetrics().boundingRect(l_time.text()).width() title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() font_size_level = font_size over_height_level = title_height - length over_width_level = title_width - col_width ### Checks maximum font size ifstacked font_size = MAX_EVENT_FONT_PT l_title = QLabel(event.title[self.lang]) l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = max( l_title.fontMetrics().boundingRect(l_title.text()).width(), l_time.fontMetrics().boundingRect(l_time.text()).width()) title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \ l_time.fontMetrics().boundingRect(l_time.text()).height() while (title_height > length or title_width > col_width) and font_size > MIN_EVENT_FONT_PT: font_size -= 1 l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) title_width = max( l_title.fontMetrics().boundingRect(l_title.text()).width(), l_time.fontMetrics().boundingRect(l_time.text()).width()) title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \ l_time.fontMetrics().boundingRect(l_time.text()).height() font_size_stacked = font_size over_height_stacked = title_height - length over_width_stacked = title_width - col_width ### Doesn't draw labels if there is no way to fit them in the available #space if ((over_width_level > 0 or over_height_level > 0) and \ (over_width_stacked > 0 or over_height_stacked > 0)): r = QtCore.QRectF( QtCore.QPointF(x_offset + x_loc * col_width, t0_f * (self.h / 24)), space) pen = QtGui.QPen(QtCore.Qt.red) brush = QtGui.QBrush(QtCore.Qt.red) self.scheduleScene.addRect(r, pen, brush) return ### Sets font and arrangement to the better layout if font_size_level > font_size_stacked: level = True elif font_size_level < font_size_stacked: level = False else: if over_width_level <= 0 and over_height_level <= 0: level = True elif over_width_level > col_width: level = False elif over_height_stacked > 0: level = True else: level = False if level: l_title = QLabel(event.title[self.lang]) l_time = QLabel(' (' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level, QtGui.QFont.Bold)) l_title.move(x_offset + x_loc * col_width, t0_f * (self.h / 24)) l_time.move(x_offset + x_loc * col_width + \ l_title.fontMetrics().boundingRect(l_title.text()).width(), t0_f * (self.h/24)) else: l_title = QLabel(event.title[self.lang]) l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked, QtGui.QFont.Bold)) l_title.move(x_offset + x_loc * col_width, t0_f * (self.h / 24)) l_time.move(x_offset + x_loc * col_width, t0_f * (self.h/24) + \ l_title.fontMetrics().boundingRect(l_title.text()).height()) r = QtCore.QRectF( QtCore.QPointF(x_offset + x_loc * col_width, t0_f * (self.h / 24)), space) pen = QtGui.QPen(QtCore.Qt.blue) brush = QtGui.QBrush(QtCore.Qt.blue) self.scheduleScene.addRect(r, pen, brush) self.scheduleScene.addWidget(l_title) self.scheduleScene.addWidget(l_time) def getActivatedColumns(self): cols = [] for key in self.schedule.columns: if self.activatedColumns[key]: cols.append(self.schedule.columns[key]) cols = sorted(cols, key=lambda x: x.abr) return cols def getDeactivatedColumns(self): cols = [] for key in self.schedule.columns: if not self.activatedColumns[key]: cols.append(self.schedule.columns[key]) cols = sorted(cols, key=lambda x: x.abr) return cols def deactivateColumn(self, key): b = QPushButton(RESTORE[self.lang] + ' ' + self.schedule.columns[key].name[self.lang]) b.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) #b.setMinimumSize(20,1) self.restoreButtonLayout.insertWidget(-1, b) b.clicked.connect(partial(self.activateColumn, key, b)) self.restore_buttons.append(b) self.activatedColumns[key] = False self.draw() def activateColumn(self, key, b): self.activatedColumns[key] = True self.draw() b.deleteLater() self.restore_buttons.remove(b) def restoreAllColumns(self): for key in self.activatedColumns: self.activatedColumns[key] = True for b in self.restore_buttons: b.deleteLater() self.restore_buttons = [] self.draw() def translateWidgets(self): for widget in self.centralwidget.findChildren((QPushButton, QLabel)): try: widget.setText(self.translateDict[widget][self.lang]) except KeyError: langDict = {} for l in languages: langDict[l] = trans(widget.text(), l) key = widget self.translateDict[key] = langDict widget.setText(self.translateDict[widget][self.lang]) def changeLang(self, lang): self.lang = lang self.translateWidgets() self.drawAlarm.start(1)
class QGraphView(QGraphicsView): def __init__(self, centralwidget, graph: Graph): super().__init__(centralwidget) self.scene = QGraphicsScene() self.setScene(self.scene) self.rightButtonPressed = False self.leftButtonPressed = True self.startPos = QPointF() self.endPos = None self.edge_from = None self.moveVertex = None self.isVertex = None self.i = 0 self.setRenderHint(QPainter.Antialiasing) self.pen = QPen(QColor(0, 0, 0), 3) self.greenPen = QPen(QColor(68, 191, 46), 3) self.pathPen = QPen(QColor(68, 133, 255), 3) self.pathBrush = QBrush(QColor(68, 133, 255)) self.graph = graph self.graph.signals.update.connect(self.drawGraph) def mouseDoubleClickEvent(self, event: QMouseEvent): # print('double click') # только левая кнопка мыши pos = QPointF(self.mapToScene(event.pos())) if event.button() == 1: # получаем имя вершины name = self.graph.get_new_vertex_name() # преобразум коодинаты в координаты сцены # добавляем вершину в граф self.graph.add_vertex(name, pos.x(), pos.y()) elif event.button() == 2: item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform()) if item is None: return if type(item) is QGraphicsLineItem or type(item) is GraphicsEdge or 'node' in item.group().__dict__: if self.graph.oriented: context_menu = QMenu(self) change_orient = context_menu.addAction("Изменить направление") action = context_menu.exec_(self.mapToGlobal(event.pos())) if action == change_orient: if type(item) is GraphicsEdge: d = item.__dict__ else: d = item.group().__dict__ self.graph.change_orient(d['v_from'].name, d['v_to'].name, d['weight'], d['node']) elif type(item) is QGraphicsEllipseItem or type(item) is QGraphicsSimpleTextItem: context_menu = QMenu(self) add_loop = context_menu.addAction("Добавить петлю") delete_loop = context_menu.addAction("Удалить петлю") delete_vertex = context_menu.addAction("Удалить вершину") action = context_menu.exec_(self.mapToGlobal(event.pos())) if action == delete_vertex: self.graph.del_vertex(item.group().v.name) self.drawGraph() if action == add_loop: print(item.group().v.name) self.graph.add_edge(item.group().v.name, item.group().v.name) if action == delete_loop: self.graph.del_edge(item.group().v.name, item.group().v.name) def mousePressEvent(self, event: QMouseEvent): if event.button() == 2: self.rightButtonPressed = True item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform()) if item: if type(item) is QGraphicsLineItem: pass elif type(item) is GraphicsVertex: self.startPos = self.mapToScene(event.pos()) self.edge_from = item.v.name elif type(item) is QGraphicsEllipseItem or QGraphicsSimpleTextItem and not type(item) is GraphicsEdge: if 'v' in item.group().__dict__: self.startPos = self.mapToScene(event.pos()) self.edge_from = item.group().v.name elif event.button() == 1: self.leftButtonPressed = True item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform()) if item: if type(item) is QGraphicsLineItem: pass elif type(item) is GraphicsEdge: self.moveVertex = item.node self.setCursor(Qt.ClosedHandCursor) elif type(item) is GraphicsVertex: self.moveVertex = item.v self.setCursor(Qt.ClosedHandCursor) elif type(item) is QGraphicsEllipseItem or QGraphicsSimpleTextItem and not type(item) is GraphicsEdge: if type(item.group()) is GraphicsVertex: self.moveVertex = item.group().v else: self.moveVertex = item.group().node self.setCursor(Qt.ClosedHandCursor) def mouseMoveEvent(self, event: QMouseEvent): self.drawGraph() if self.rightButtonPressed and self.edge_from is not None: self.endPos = self.mapToScene(event.pos()) self.scene.addLine(self.startPos.x(), self.startPos.y(), self.endPos.x(), self.endPos.y()) # self.isVertex = True elif self.leftButtonPressed and self.moveVertex is not None: pos = QPointF(self.mapToScene(event.pos())) self.moveVertex.x = pos.x() self.moveVertex.y = pos.y() def mouseReleaseEvent(self, event: QMouseEvent): if event.button() == 2 and self.edge_from is not None: self.rightButtonPressed = False if type(self.scene.items()[0]) == QGraphicsLineItem: self.scene.removeItem(self.scene.items()[0]) item = self.scene.itemAt(self.mapToScene(event.pos()), QTransform()) if item: if type(item) is QGraphicsLineItem: pass elif type(item) is GraphicsVertex: edge_to = item.v.name if edge_to == 'node': return if edge_to != self.edge_from: self.graph.add_edge(self.edge_from, edge_to) elif type(item) is QGraphicsEllipseItem or QGraphicsSimpleTextItem: if type(item.group()) is GraphicsEdge: return edge_to = item.group().v.name if edge_to == 'node': return if edge_to != self.edge_from: self.graph.add_edge(self.edge_from, edge_to) self.edge_from = None elif event.button() == 1: self.leftButtonPressed = False self.moveVertex = None self.setCursor(Qt.ArrowCursor) def drawGraph(self, simple: bool = False): if simple: self.simpleDrawGraph() return # очищаем сцену self.scene.clear() # рисуем ребра for v_from, to_dict in self.graph.vertexes.items(): v_from = self.graph.vertexes_coordinates[v_from] for v_to, to_list in to_dict.items(): v_to = self.graph.vertexes_coordinates[v_to] try: for weight, node in to_list: # key = f'{v_from.name}_{v_to.name}' # if key in self.graph.edge_path and self.graph.edge_path[key] == weight: # pen = self.pathPen # elif self.graph.oriented: # pen = self.greenPen # else: # pen = self.pen # if v_from is v_to: # pen = QPen(QBrush(QColor(255, 0, 0)), 3) # ellipse = QGraphicsEllipseItem(v_from.x - 30, v_from.y - 30, 30, 30) # ellipse.setPen(pen) # self.scene.addItem(ellipse) # else: # print(self.graph.oriented) if self.graph.oriented: key = f'{v_from.name}_{v_to.name}' if (key, node) in self.graph.edge_path.items(): pen = self.pathPen else: pen = self.greenPen self.scene.addLine(v_from.x, v_from.y, node.x, node.y, self.pen) self.scene.addLine(node.x, node.y, v_to.x, v_to.y, pen) # self.scene.addItem(line1) # self.scene.addItem(line2) self.scene.addItem(GraphicsEdge(v_from, v_to, node, self.graph.oriented, weight)) elif int(v_from.name) > int(v_to.name): key = f'{v_from.name}_{v_to.name}' rev_key = f'{v_to.name}_{v_from.name}' if (key in self.graph.edge_path and self.graph.edge_path[key] == weight)\ or (rev_key in self.graph.edge_path and self.graph.edge_path[rev_key] == weight): pen = self.pathPen else: pen = self.pen self.scene.addLine(v_from.x, v_from.y, node.x, node.y, pen) self.scene.addLine(node.x, node.y, v_to.x, v_to.y, pen) # self.scene.addItem(line1) # self.scene.addItem(line2) self.scene.addItem(GraphicsEdge(v_from, v_to, node, self.graph.oriented, weight)) except TypeError as e: # print(e) self.graph.restore() self.drawGraph() except Exception as e: print(e) exit(-2) # рисуем вершины for v in self.graph.vertexes_coordinates.values(): self.scene.addItem(GraphicsVertex(v)) def simpleDrawGraph(self): self.scene.clear() for v_from, to_dict in self.graph.vertexes.items(): v_from = self.graph.vertexes_coordinates[v_from] for v_to, to_list in to_dict.items(): v_to = self.graph.vertexes_coordinates[v_to] for weight, node in to_list: self.scene.addLine(v_from.x, v_from.y, v_to.x, v_to.y) # рисуем вершины for v in self.graph.vertexes_coordinates.values(): self.scene.addItem(GraphicsVertex(v))
class mainWindow(QtWidgets.QMainWindow): SCENE_WIDTH = 1070 SCENE_HEIGHT = 751 LINE_COLOR = QColorConstants.Black CUTTED_LINE_COLOR = QColorConstants.Magenta CUTTER_COLOR = QColorConstants.Red def __init__(self): QtWidgets.QWidget.__init__(self) uic.loadUi("mainwindow.ui", self) self.scene = QGraphicsScene(0, 0, self.SCENE_WIDTH, self.SCENE_HEIGHT) self.main_scene.setScene(self.scene) self.lines = [] self.ctrl_pressed = False self.adding_cutter = False # If False then adding line on screen, otherwise adding cutter rectangle self.curr_line = [] self.line_preview = None self.current_cutter = [] self.cutter_preview = None self.cutter: Cutter = None self.add_line_btn.clicked.connect(self.addLineBtnHandler) self.clean_btn.clicked.connect(self.cleanScreen) self.add_cutter_btn.clicked.connect(self.addCutterBtnHandler) self.cut_btn.clicked.connect(self.cutBtnHandler) self.main_scene.setMouseTracking(True) self.main_scene.viewport().installEventFilter(self) def addLineBtnHandler(self): p1 = QPoint(self.x0_spin.value(), self.y0_spin.value()) p2 = QPoint(self.x1_spin.value(), self.y1_spin.value()) self.addLine(p1, p2) def addCutterBtnHandler(self): self.__delCutter() self.adding_cutter = True def cutBtnHandler(self): if self.cutter: xl = self.cutter.topLeft().x() yu = self.cutter.topLeft().y() xr = self.cutter.bottomRight().x() yd = self.cutter.bottomRight().y() for i in self.lines: p1 = [i.p1().x(), i.p1().y()] p2 = [i.p2().x(), i.p2().y()] visible, p1, p2 = simple_cut(xl, xr, yd, yu, p1, p2) if visible: self.scene.addLine(p1[0], p1[1], p2[0], p2[1], self.CUTTED_LINE_COLOR) def eventFilter(self, source, event): if event.type( ) == QEvent.MouseMove and source is self.main_scene.viewport(): self.__previewCutter(event.pos()) self.__previewLine(event.pos()) return QWidget.eventFilter(self, source, event) def mousePressEvent(self, a0: QtGui.QMouseEvent): but = a0.button() x = a0.x() y = a0.y() borders = self.main_scene.geometry().getCoords() if borders[0] <= x < borders[2] and borders[1] <= y < borders[3]: x -= borders[0] y -= borders[1] else: return if a0.buttons() == Qt.LeftButton: pos = QPoint(x, y) self.__drawLineHandler(pos) self.__drawCutterHandler(pos) def addLine(self, p1: QPoint, p2: QPoint): l = Line(p1, p2) self.lines.append(l) self.__drawLine(l) def addCutter(self, p1: QPoint, p2: QPoint): c = Cutter(p1, p2) self.cutter = c self.__drawCutter(c) def keyPressEvent(self, event): key = event.key() if key == Qt.Key_Control: self.ctrl_pressed = True def keyReleaseEvent(self, event): key = event.key() if key == Qt.Key_Control: self.ctrl_pressed = False def __drawLine(self, l: Line): lp = l.p1() rp = l.p2() l.setSceneItem( self.scene.addLine(lp.x(), lp.y(), rp.x(), rp.y(), self.LINE_COLOR)) def __drawCutter(self, c: Cutter): tl = c.topLeft() br = c.bottomRight() c.setSceneItem( self.scene.addRect(tl.x(), tl.y(), br.x() - tl.x(), br.y() - tl.y(), self.CUTTER_COLOR)) def __drawLineHandler(self, p: QPoint): if self.adding_cutter == False: if len(self.curr_line) == 0 or not self.ctrl_pressed: self.curr_line.append(p) elif self.ctrl_pressed: line_start = self.curr_line[0] dx = p.x() - line_start.x() dy = p.y() - line_start.y() if abs(dy) > abs(dx): self.curr_line.append(QPoint(line_start.x(), p.y())) else: self.curr_line.append(QPoint(p.x(), line_start.y())) if len(self.curr_line) == 2: p1, p2 = self.curr_line self.addLine(p1, p2) self.curr_line.clear() self.scene.removeItem(self.line_preview) def __drawCutterHandler(self, p: QPoint): if self.adding_cutter: self.current_cutter.append(p) if len(self.current_cutter) == 2: v1, v2 = self.current_cutter self.addCutter(v1, v2) self.current_cutter.clear() self.scene.removeItem(self.cutter_preview) self.adding_cutter = False def __previewLine(self, p: QPoint): if len(self.curr_line) == 1: line_start = self.curr_line[0] if self.line_preview: self.scene.removeItem(self.line_preview) if self.ctrl_pressed: dx = p.x() - line_start.x() dy = p.y() - line_start.y() if abs(dy) >= abs(dx): right_p = QPoint(line_start.x(), p.y()) else: right_p = QPoint(p.x(), line_start.y()) self.line_preview = self.scene.addLine(line_start.x(), line_start.y(), right_p.x(), right_p.y(), self.LINE_COLOR) else: self.line_preview = self.scene.addLine(line_start.x(), line_start.y(), p.x(), p.y(), self.LINE_COLOR) def __previewCutter(self, p: QPoint): if len(self.current_cutter) == 1: lu_p = self.current_cutter[0] rd_p = p x_l = lu_p.x() x_r = rd_p.x() y_u = lu_p.y() y_d = rd_p.y() if self.cutter_preview: self.scene.removeItem(self.cutter_preview) if x_l > x_r: x_l, x_r = x_r, x_l if y_u > y_d: y_u, y_d = y_d, y_u self.cutter_preview = self.scene.addRect(x_l, y_u, x_r - x_l, y_d - y_u, self.CUTTER_COLOR) def __delCutter(self): if self.cutter is not None: self.scene.removeItem(self.cutter.sceneItem()) self.current_cutter.clear() def cleanScreen(self): self.lines.clear() self.curr_line.clear() self.current_cutter.clear() self.line_preview = None self.cutter_preview = None self.cutter = None self.adding_cutter = False self.scene.clear()
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()))
class SchedulerGUI(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent=parent) self.setStyleSheet(MAIN_WINDOW_CSS) self.setupUi(self) self.scheduleFolder = sampleSchedule() self.schedule = self.scheduleFolder.schedulers[ self.calendarWidget.selectedDate()] self.schedule.events[62].customGUI = MeasureWidget self.activatedColumns = {} for key in self.scheduleFolder.columns: self.activatedColumns[key] = True self.lang = 'en' self.restore_buttons = {} self.restoreAllButton.clicked.connect(self.restoreAllColumns) self.translateDict = {} for widget in self.centralwidget.findChildren((QPushButton)): langDict = {} for l in languages: langDict[l] = trans(widget.text(), l) key = widget self.translateDict[key] = langDict self.translateWidgets() self.language0Button.clicked.connect(partial(self.changeLang, 'en')) self.language1Button.clicked.connect(partial(self.changeLang, 'ru')) self.language2Button.clicked.connect(partial(self.changeLang, 'de')) self.language3Button.clicked.connect(partial(self.changeLang, 'ja')) self.language4Button.clicked.connect(partial(self.changeLang, 'fr')) self.language5Button.clicked.connect(partial(self.changeLang, 'it')) self.language0Button.setIcon(QtGui.QIcon('flags/United-States.png')) self.language1Button.setIcon(QtGui.QIcon('flags/Russia.png')) self.language2Button.setIcon(QtGui.QIcon('flags/Germany.png')) self.language3Button.setIcon(QtGui.QIcon('flags/Japan.png')) self.language4Button.setIcon(QtGui.QIcon('flags/France.png')) self.language5Button.setIcon(QtGui.QIcon('flags/Italy.png')) self.drawAlarm = QTimer() self.drawAlarm.timeout.connect(self.drawAlarmFunc) self.drawAlarm.start(0.3) self.calendarWidget.setNavigationBarVisible(False) self.calendarWidget.setStyleSheet(CALENDAR_CSS) self.calendarWidget.clicked.connect(self.updateDisplayedDate) self.calendarWidget.currentPageChanged.connect(self.updateNavBarDate) self.calendarWidget.selectionChanged.connect(self.updateDisplayedDate) self.updateDisplayedDate() self.updateNavBarDate() self.nextMonthButton.clicked.connect(self.calendarWidget.showNextMonth) self.prevMonthButton.clicked.connect( self.calendarWidget.showPreviousMonth) self.nextDayButton.clicked.connect(self.selectNextDate) self.prevDayButton.clicked.connect(self.selectPrevDate) self.todayButton.clicked.connect(self.selectToday) navBarWidgets = [ self.prevMonthButton, self.displayedCalendarLabel, self.nextMonthButton ] for widget in self.centralwidget.findChildren(QPushButton): #if widget not in navBarWidgets: widget.setStyleSheet(MAIN_BUTTONS_CSS) weekendFormat = QTextCharFormat() weekendFormat.setForeground(QBrush(Qt.black, Qt.SolidPattern)) self.calendarWidget.setWeekdayTextFormat(Qt.Saturday, weekendFormat) self.calendarWidget.setWeekdayTextFormat(Qt.Sunday, weekendFormat) self.customGUIs = {} def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_A: self.selectPrevDate() elif event.key() == QtCore.Qt.Key_D: self.selectNextDate() def closeEvent(self, event): quit() def resizeEvent(self, event): self.draw() def eventClicked(self, event): ''' try: self.dockWidget.deleteLater() except AttributeError: pass ''' if event.customGUI != None: self.dockWidget = event.customGUI(self) else: self.dockWidget = DefaultEvent(self) self.dockWidget.setAllowedAreas(Qt.RightDockWidgetArea | Qt.NoDockWidgetArea) self.dockWidget.setMinimumWidth(450) self.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget) self.dockWidgetEvent = event self.updateEventPopupText() def updateEventPopupText(self): try: timeText = self.dockWidgetEvent.t0 + ' - ' + self.dockWidgetEvent.t1 + ' (GMT)' self.dockWidget.timeLabel.setText(timeText) self.dockWidget.titleLabel.setText( self.dockWidgetEvent.title[self.lang]) self.dockWidget.summaryLabel.setText( self.dockWidgetEvent.summary[self.lang]) self.dockWidget.descriptionLabel.setText( self.dockWidgetEvent.description[self.lang]) self.dockWidget.setWindowTitle( self.dockWidgetEvent.title[self.lang]) except AttributeError: pass def selectNextDate(self): date = self.calendarWidget.selectedDate() self.calendarWidget.setSelectedDate(date.addDays(1)) def selectPrevDate(self): date = self.calendarWidget.selectedDate() self.calendarWidget.setSelectedDate(date.addDays(-1)) def selectToday(self): self.calendarWidget.setSelectedDate(QDate.currentDate()) self.calendarWidget.showToday() def updateNavBarDate(self): month = MONTH[self.calendarWidget.monthShown()][self.lang] year = self.calendarWidget.yearShown() self.displayedCalendarLabel.setText(month + " " + str(year)) def updateDisplayedDate(self): self.dateLabel.setText( self.dateToStr(self.calendarWidget.selectedDate())) try: self.schedule = self.scheduleFolder.schedulers[ self.calendarWidget.selectedDate()] except KeyError: self.schedule = Scheduler([]) self.draw() def dateToStr(self, date): month = MONTH[date.month()][self.lang] year = date.year() day = date.day() return month + " " + str(day) + " " + str(year) def drawAlarmFunc(self): self.drawAlarm.stop() self.draw() def draw(self, w=-1): self.scheduleScene = QGraphicsScene() self.activatedScene = QGraphicsScene() if w == -1: self.w = self.scheduleView.width() else: self.w = w self.h = Y_SIDE * 24 self.h_a = self.activatedView.height() self.gridPen = QPen(GRID_COLOR) for i in range(0, 24): self.scheduleScene.addLine(0, i * Y_SIDE, self.w, i * Y_SIDE) self.drawTimeTapes() cols = self.getActivatedColumns() x_offset = WIDTH_TL * len(self.scheduleFolder.timeTapes) if (len(cols) > 0): col_width = (self.w - x_offset) / len(cols) col_positions = self.drawColumns(cols, x_offset, col_width) for i in range(0, len(self.schedule.events)): try: pos = col_positions[self.schedule.events[i].column_abr] self.drawEvent(self.schedule.events[i], col_width, pos) except KeyError: pass t_now = QTime.currentTime().hour() + QTime.currentTime().minute() / 60 self.gridPen = QPen(Qt.green) self.gridPen.setWidth(2) self.scheduleScene.addLine(0, t_now * (self.h / 24), self.w, t_now * (self.h / 24), self.gridPen) t_fast_return = t_now + 40 / 60 self.gridPen = QPen(Qt.red) self.gridPen.setWidth(2) self.scheduleScene.addLine(0, t_fast_return * (self.h / 24), self.w, t_fast_return * (self.h / 24), self.gridPen) self.scheduleView.setScene(self.scheduleScene) self.activatedView.setScene(self.activatedScene) def drawTimeTapes(self): for i in range(0, len(self.scheduleFolder.timeTapes)): self.scheduleScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h) self.activatedScene.addLine(WIDTH_TL * i, 0, WIDTH_TL * i, self.h_a) l = QLabel(self.scheduleFolder.timeTapes[i].name) l.move(WIDTH_TL * i + TT_X_BUFFER, TT_Y_BUFFER) l.setStyleSheet(TIME_TAPE_CSS) self.activatedScene.addWidget(l) for j in range(0, 24): l = QLabel(self.scheduleFolder.timeTapes[i].labels[j]) l.move(WIDTH_TL * i + TT_X_BUFFER, Y_SIDE * j + TT_Y_BUFFER) l.setStyleSheet(TIME_TAPE_CSS) self.scheduleScene.addWidget(l) def drawColumns(self, cols, x_offset, col_width): col_positions = {} self.deactivateButtons = [] for i in range(0, len(cols)): self.scheduleScene.addLine(x_offset + col_width * i, 0, x_offset + col_width * i, self.h) ''' self.activatedScene.addLine(x_offset + col_width * i, 0, x_offset + col_width * i, self.h_a) ''' b = QPushButton(cols[i].name['en']) b.move(x_offset + col_width * i + COLUMN_BUTTON_X_BUFFER + 1, 0) b.clicked.connect(partial(self.deactivateColumn, cols[i].abr)) b.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) b.setStyleSheet(MAIN_BUTTONS_CSS) b.resize(col_width - COLUMN_BUTTON_X_BUFFER * 2, self.h_a - 2) b = self.activatedScene.addWidget(b) col_positions[cols[i].abr] = x_offset + col_width * i return col_positions def drawEvent(self, event, col_width, x_loc): t0_f = timeStrToFloat(event.t0) t1_f = timeStrToFloat(event.t1) length = (t1_f - t0_f) * (self.h / 24) space = QtCore.QSizeF(col_width - PEN_WIDTH, length - PEN_WIDTH) r = QtCore.QRectF(QtCore.QPointF(x_loc + 1, t0_f * (self.h / 24) + 1), space) pen = QPen(QtCore.Qt.black) pen.setWidth(PEN_WIDTH) brush = QBrush(event.color) ### Checks maximum font size if level font_size = MAX_EVENT_FONT_PT l_title = QLabel(event.title[self.lang] + " ") l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \ l_time.fontMetrics().boundingRect(l_time.text()).width() + W_BUFFER title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() + H_BUFFER while (title_height > length or title_width > col_width) and font_size > MIN_EVENT_FONT_PT: font_size -= FONT_STEP l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) title_width = l_title.fontMetrics().boundingRect(l_title.text()).width() + \ l_time.fontMetrics().boundingRect(l_time.text()).width() + W_BUFFER title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() + H_BUFFER font_size_level = font_size over_height_level = title_height - length over_width_level = title_width - col_width ### Checks maximum font size if stacked font_size = MAX_EVENT_FONT_PT l_title = QLabel(event.title[self.lang]) l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = max( l_title.fontMetrics().boundingRect(l_title.text()).width(), l_time.fontMetrics().boundingRect( l_time.text()).width()) + W_BUFFER title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \ l_time.fontMetrics().boundingRect(l_time.text()).height() + H_BUFFER while (title_height > length or title_width > col_width) and font_size > MIN_EVENT_FONT_PT: font_size -= FONT_STEP l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Normal)) title_width = max( l_title.fontMetrics().boundingRect(l_title.text()).width(), l_time.fontMetrics().boundingRect( l_time.text()).width()) + W_BUFFER title_height = l_title.fontMetrics().boundingRect(l_title.text()).height() + \ l_time.fontMetrics().boundingRect(l_time.text()).height() + H_BUFFER font_size_stacked = font_size over_height_stacked = title_height - length over_width_stacked = title_width - col_width ### Checks if it can draw the event without the time label if it is too big if ((over_width_level > 0 or over_height_level > 0) and \ (over_width_stacked > 0 or over_height_stacked > 0)): font_size = MAX_EVENT_FONT_PT l_title = QLabel(event.title[self.lang]) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = l_title.fontMetrics().boundingRect( l_title.text()).width() + W_BUFFER title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() + H_BUFFER while (title_height > length or title_width > col_width) and font_size > MIN_EVENT_FONT_PT: font_size -= FONT_STEP l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size, QtGui.QFont.Bold)) title_width = l_title.fontMetrics().boundingRect( l_title.text()).width() + W_BUFFER title_height = l_title.fontMetrics().boundingRect( l_title.text()).height() + H_BUFFER font_size_level = font_size over_height_level = title_height - length over_width_level = title_width - col_width if (over_height_level > 0 or over_width_level > 0): l_title = QLabel('') l_time = QLabel('') else: l_title = QLabel(event.title[self.lang] + " ") l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level, QtGui.QFont.Bold)) l_title.move(x_loc + X_BUFFER, t0_f * (self.h / 24) + Y_BUFFER) l_time = QLabel('') r = RectEvent(r) r.setInfo(self, event) r.setPen(pen) r.setBrush(brush) self.scheduleScene.addItem(r) l_title.setStyleSheet(EVENT_LABEL_CSS) l_time.setStyleSheet(EVENT_LABEL_CSS) self.scheduleScene.addWidget(l_title) self.scheduleScene.addWidget(l_time) return ### Sets font and arrangement to the better layout if font_size_level > font_size_stacked: level = True elif font_size_level < font_size_stacked: level = False else: if over_width_level <= 0 and over_height_level <= 0: level = True elif over_width_level > col_width: level = False elif over_height_stacked > 0: level = True else: level = False if level: l_title = QLabel(event.title[self.lang] + " ") l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_level, QtGui.QFont.Bold)) l_title.move(x_loc + X_BUFFER, t0_f * (self.h / 24) + Y_BUFFER) l_time.move(x_loc + X_BUFFER + \ l_title.fontMetrics().boundingRect(l_title.text()).width(), t0_f * (self.h/24) + Y_BUFFER) else: l_title = QLabel(event.title[self.lang]) l_time = QLabel('(' + event.t0 + ' - ' + event.t1 + ')') l_time.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked, QtGui.QFont.Normal)) l_title.setFont( QtGui.QFont(DEFAULT_EVENT_FONT, font_size_stacked, QtGui.QFont.Bold)) l_title.move(x_loc + X_BUFFER, t0_f * (self.h / 24) + Y_BUFFER) l_time.move(x_loc + X_BUFFER, t0_f * (self.h/24) + Y_BUFFER + STACKED_BUFFER + \ l_title.fontMetrics().boundingRect(l_title.text()).height()) r = RectEvent(r) r.setInfo(self, event) r.setPen(pen) r.setBrush(brush) self.scheduleScene.addItem(r) l_title.setStyleSheet(EVENT_LABEL_CSS) l_time.setStyleSheet(EVENT_LABEL_CSS) self.scheduleScene.addWidget(l_title) self.scheduleScene.addWidget(l_time) def getActivatedColumns(self): cols = [] for key in self.scheduleFolder.columns: if self.activatedColumns[key]: cols.append(self.scheduleFolder.columns[key]) cols = sorted(cols, key=lambda x: x.abr) return cols def getDeactivatedColumns(self): cols = [] for key in self.scheduleFolder.columns: if not self.activatedColumns[key]: cols.append(self.scheduleFolder.columns[key]) cols = sorted(cols, key=lambda x: x.abr) return cols def deactivateColumn(self, key): b = QPushButton(RESTORE[self.lang] + ' ' + self.scheduleFolder.columns[key].name[self.lang]) b.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) #b.setMinimumSize(20,1) b.setStyleSheet(MAIN_BUTTONS_CSS) self.restoreButtonLayout.insertWidget(-1, b) b.clicked.connect(partial(self.activateColumn, key, b)) self.restore_buttons[b] = key self.activatedColumns[key] = False self.draw() def activateColumn(self, key, b): self.activatedColumns[key] = True self.draw() b.deleteLater() del self.restore_buttons[b] def restoreAllColumns(self): for key in self.activatedColumns: self.activatedColumns[key] = True for b in self.restore_buttons: b.deleteLater() self.restore_buttons = {} self.draw() def translateWidgets(self): restoreButs = list(self.restoreButtonLayout.itemAt(i).widget() \ for i in range(1,self.restoreButtonLayout.count())) for widget in self.centralwidget.findChildren(QPushButton): if widget not in restoreButs: try: widget.setText(self.translateDict[widget][self.lang]) except KeyError: langDict = {} for l in languages: langDict[l] = trans(widget.text(), l) key = widget self.translateDict[key] = langDict widget.setText(self.translateDict[widget][self.lang]) else: key = self.restore_buttons[widget] widget.setText(RESTORE[self.lang] + ' ' + self.scheduleFolder.columns[key].name['en']) def changeLang(self, lang): self.lang = lang self.translateWidgets() self.drawAlarm.start(1) self.updateDisplayedDate() self.updateNavBarDate() self.updateEventPopupText()
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.selected_area = 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.items_to_remove = [ ] # 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.graphics_scene = QGraphicsScene(0, 0, self.screenPixel.width(), self.screenPixel.height()) self.show() self.setScene(self.graphics_scene) 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.selected_area = QRect() self.selected_area.setTopLeft(QPoint(event.x(), event.y())) self.selected_area.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.selected_area = QRect() self.selected_area.setTopLeft(QPoint(event.x(), event.y())) self.selected_area.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.detect_mouse_position(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.selected_area.setBottomRight(QPoint(event.x(), event.y())) self.redraw() elif self.action == ACTION_MOVE_SELECTED: self.selected_area = QRect(self.selectedAreaRaw) if self.mousePosition == MousePosition.INSIDE_AREA: move_to_x = event.x( ) - self.startX + self.selected_area.left() move_to_y = event.y( ) - self.startY + self.selected_area.top() if 0 <= move_to_x <= self.screenPixel.width( ) - 1 - self.selected_area.width(): self.selected_area.moveLeft(move_to_x) if 0 <= move_to_y <= self.screenPixel.height( ) - 1 - self.selected_area.height(): self.selected_area.moveTop(move_to_y) self.selected_area = self.selected_area.normalized() self.selectedAreaRaw = QRect(self.selected_area) self.startX, self.startY = event.x(), event.y() self.redraw() elif self.mousePosition == MousePosition.ON_THE_LEFT_SIDE: move_to_x = event.x( ) - self.startX + self.selected_area.left() if move_to_x <= self.selected_area.right(): self.selected_area.setLeft(move_to_x) self.selected_area = self.selected_area.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_RIGHT_SIDE: move_to_x = event.x( ) - self.startX + self.selected_area.right() self.selected_area.setRight(move_to_x) self.selected_area = self.selected_area.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_UP_SIDE: move_to_y = event.y( ) - self.startY + self.selected_area.top() self.selected_area.setTop(move_to_y) self.selected_area = self.selected_area.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_DOWN_SIDE: move_to_y = event.y( ) - self.startY + self.selected_area.bottom() self.selected_area.setBottom(move_to_y) self.selected_area = self.selected_area.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_TOP_LEFT_CORNER: move_to_x = event.x( ) - self.startX + self.selected_area.left() move_to_y = event.y( ) - self.startY + self.selected_area.top() self.selected_area.setTopLeft(QPoint(move_to_x, move_to_y)) self.selected_area = self.selected_area.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_BOTTOM_RIGHT_CORNER: move_to_x = event.x( ) - self.startX + self.selected_area.right() move_to_y = event.y( ) - self.startY + self.selected_area.bottom() self.selected_area.setBottomRight( QPoint(move_to_x, move_to_y)) self.selected_area = self.selected_area.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_TOP_RIGHT_CORNER: move_to_x = event.x( ) - self.startX + self.selected_area.right() move_to_y = event.y( ) - self.startY + self.selected_area.top() self.selected_area.setTopRight(QPoint( move_to_x, move_to_y)) self.selected_area = self.selected_area.normalized() self.redraw() elif self.mousePosition == MousePosition.ON_THE_BOTTOM_LEFT_CORNER: move_to_x = event.x( ) - self.startX + self.selected_area.left() move_to_y = event.y( ) - self.startY + self.selected_area.bottom() self.selected_area.setBottomLeft( QPoint(move_to_x, move_to_y)) 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.selected_area.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.selected_area.setBottomRight(QPoint(event.x(), event.y())) self.selectedAreaRaw = QRect(self.selected_area) self.action = ACTION_MOVE_SELECTED self.redraw() elif self.action == ACTION_MOVE_SELECTED: self.selectedAreaRaw = QRect(self.selected_area) 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 detect_mouse_position(self, point): """ :type point: QPoint :param point: the mouse position you want to check :return: """ if self.selected_area == QRect(): self.mousePosition = MousePosition.OUTSIDE_AREA return if self.selected_area.left() - ERRORRANGE <= point.x( ) <= self.selected_area.left() and ( self.selected_area.top() - ERRORRANGE <= point.y() <= self.selected_area.top()): self.mousePosition = MousePosition.ON_THE_TOP_LEFT_CORNER elif self.selected_area.right() <= point.x( ) <= self.selected_area.right() + ERRORRANGE and ( self.selected_area.top() - ERRORRANGE <= point.y() <= self.selected_area.top()): self.mousePosition = MousePosition.ON_THE_TOP_RIGHT_CORNER elif self.selected_area.left() - ERRORRANGE <= point.x( ) <= self.selected_area.left() and ( self.selected_area.bottom() <= point.y() <= self.selected_area.bottom() + ERRORRANGE): self.mousePosition = MousePosition.ON_THE_BOTTOM_LEFT_CORNER elif self.selected_area.right() <= point.x( ) <= self.selected_area.right() + ERRORRANGE and ( self.selected_area.bottom() <= point.y() <= self.selected_area.bottom() + ERRORRANGE): self.mousePosition = MousePosition.ON_THE_BOTTOM_RIGHT_CORNER elif -ERRORRANGE <= point.x() - self.selected_area.left() <= 0 and ( self.selected_area.topLeft().y() < point.y() < self.selected_area.bottomLeft().y()): self.mousePosition = MousePosition.ON_THE_LEFT_SIDE elif 0 <= point.x() - self.selected_area.right() <= ERRORRANGE and ( self.selected_area.topRight().y() < point.y() < self.selected_area.bottomRight().y()): self.mousePosition = MousePosition.ON_THE_RIGHT_SIDE elif -ERRORRANGE <= point.y() - self.selected_area.top() <= 0 and ( self.selected_area.topLeft().x() < point.x() < self.selected_area.topRight().x()): self.mousePosition = MousePosition.ON_THE_UP_SIDE elif 0 <= point.y() - self.selected_area.bottom() <= ERRORRANGE and ( self.selected_area.bottomLeft().x() < point.x() < self.selected_area.bottomRight().x()): self.mousePosition = MousePosition.ON_THE_DOWN_SIDE elif not self.selected_area.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 watch_area_width = 16 watch_area_height = 16 cursor_pos = self.mousePoint watch_area = QRect( QPoint(cursor_pos.x() - watch_area_width / 2, cursor_pos.y() - watch_area_height / 2), QPoint(cursor_pos.x() + watch_area_width / 2, cursor_pos.y() + watch_area_height / 2)) if watch_area.left() < 0: watch_area.moveLeft(0) watch_area.moveRight(watch_area_width) if self.mousePoint.x( ) + watch_area_width / 2 >= self.screenPixel.width(): watch_area.moveRight(self.screenPixel.width() - 1) watch_area.moveLeft(watch_area.right() - watch_area_width) if self.mousePoint.y() - watch_area_height / 2 < 0: watch_area.moveTop(0) watch_area.moveBottom(watch_area_height) if self.mousePoint.y( ) + watch_area_height / 2 >= self.screenPixel.height(): watch_area.moveBottom(self.screenPixel.height() - 1) watch_area.moveTop(watch_area.bottom() - watch_area_height) # tricks to solve the hidpi impact on QCursor.pos() watch_area.setTopLeft( QPoint(watch_area.topLeft().x() * self.scale, watch_area.topLeft().y() * self.scale)) watch_area.setBottomRight( QPoint(watch_area.bottomRight().x() * self.scale, watch_area.bottomRight().y() * self.scale)) watch_area_pixmap = self.screenPixel.copy(watch_area) # second, calculate the magnifier area magnifier_area_width = watch_area_width * 10 magnifier_area_height = watch_area_height * 10 font_area_height = 40 cursor_size = 24 magnifier_area = QRectF( QPoint(QCursor.pos().x() + cursor_size, QCursor.pos().y() + cursor_size), QPoint(QCursor.pos().x() + cursor_size + magnifier_area_width, QCursor.pos().y() + cursor_size + magnifier_area_height)) if magnifier_area.right() >= self.screenPixel.width(): magnifier_area.moveLeft(QCursor.pos().x() - magnifier_area_width - cursor_size / 2) if magnifier_area.bottom( ) + font_area_height >= self.screenPixel.height(): magnifier_area.moveTop(QCursor.pos().y() - magnifier_area_height - cursor_size / 2 - font_area_height) # third, draw the watch area to magnifier area watch_area_scaled = watch_area_pixmap.scaled( QSize(magnifier_area_width * self.scale, magnifier_area_height * self.scale)) magnifier_pixmap = self.graphics_scene.addPixmap(watch_area_scaled) magnifier_pixmap.setOffset(magnifier_area.topLeft()) # then draw lines and text self.graphics_scene.addRect(QRectF(magnifier_area), QPen(QColor(255, 255, 255), 2)) self.graphics_scene.addLine( QLineF( QPointF(magnifier_area.center().x(), magnifier_area.top()), QPointF(magnifier_area.center().x(), magnifier_area.bottom())), QPen(QColor(0, 255, 255), 2)) self.graphics_scene.addLine( QLineF( QPointF(magnifier_area.left(), magnifier_area.center().y()), QPointF(magnifier_area.right(), magnifier_area.center().y())), QPen(QColor(0, 255, 255), 2)) # get the rgb of mouse point point_rgb = QColor(self.screenPixel.toImage().pixel(self.mousePoint)) # draw information self.graphics_scene.addRect( QRectF( magnifier_area.bottomLeft(), magnifier_area.bottomRight() + QPoint(0, font_area_height + 30)), Qt.black, QBrush(Qt.black)) rgb_info = self.graphics_scene.addSimpleText( ' Rgb: ({0}, {1}, {2})'.format(point_rgb.red(), point_rgb.green(), point_rgb.blue())) rgb_info.setPos(magnifier_area.bottomLeft() + QPoint(0, 5)) rgb_info.setPen(QPen(QColor(255, 255, 255), 2)) rect = self.selected_area.normalized() size_info = self.graphics_scene.addSimpleText( ' Size: {0} x {1}'.format(rect.width() * self.scale, rect.height() * self.scale)) size_info.setPos(magnifier_area.bottomLeft() + QPoint(0, 15) + QPoint(0, font_area_height / 2)) size_info.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.selected_area) 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) 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.graphics_scene.clear() # draw screenshot self.graphics_scene.addPixmap(self.screenPixel) # prepare for drawing selected area rect = QRectF(self.selected_area) rect = rect.normalized() top_left_point = rect.topLeft() top_right_point = rect.topRight() bottom_left_point = rect.bottomLeft() bottom_right_point = rect.bottomRight() top_middle_point = (top_left_point + top_right_point) / 2 left_middle_point = (top_left_point + bottom_left_point) / 2 bottom_middle_point = (bottom_left_point + bottom_right_point) / 2 right_middle_point = (top_right_point + bottom_right_point) / 2 # draw the picture mask mask = QColor(0, 0, 0, 155) if self.selected_area == QRect(): self.graphics_scene.addRect(0, 0, self.screenPixel.width(), self.screenPixel.height(), QPen(Qt.NoPen), mask) else: self.graphics_scene.addRect(0, 0, self.screenPixel.width(), top_right_point.y(), QPen(Qt.NoPen), mask) self.graphics_scene.addRect(0, top_left_point.y(), top_left_point.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphics_scene.addRect( top_right_point.x(), top_right_point.y(), self.screenPixel.width() - top_right_point.x(), rect.height(), QPen(Qt.NoPen), mask) self.graphics_scene.addRect( 0, bottom_left_point.y(), self.screenPixel.width(), self.screenPixel.height() - bottom_left_point.y(), QPen(Qt.NoPen), mask) # draw the toolBar if self.action != ACTION_SELECT: spacing = 5 # show the toolbar first, then move it to the correct position # because the width of it may be wrong if this is the first time it shows self.tooBar.show() dest = QPointF(rect.bottomRight() - QPointF(self.tooBar.width(), 0) - QPointF(spacing, -spacing)) if dest.x() < spacing: dest.setX(spacing) pen_set_bar_height = self.penSetBar.height( ) if self.penSetBar is not None else 0 if dest.y() + self.tooBar.height( ) + pen_set_bar_height >= self.height(): if rect.top() - self.tooBar.height( ) - pen_set_bar_height < spacing: dest.setY(rect.top() + spacing) else: dest.setY(rect.top() - self.tooBar.height() - pen_set_bar_height - spacing) self.tooBar.move(dest.toPoint()) if self.penSetBar is not None: self.penSetBar.show() self.penSetBar.move(dest.toPoint() + QPoint(0, self.tooBar.height() + spacing)) if self.action == ACTION_TEXT: self.penSetBar.showFontWidget() else: self.penSetBar.showPenWidget() else: self.tooBar.hide() if self.penSetBar is not None: self.penSetBar.hide() # draw the list for step in self.drawListResult: self.drawOneStep(step) if self.drawListProcess is not None: self.drawOneStep(self.drawListProcess) if self.action != ACTION_TEXT: self.drawListProcess = None if self.selected_area != QRect(): self.items_to_remove = [] # draw the selected rectangle pen = QPen(QColor(0, 255, 255), 2) self.items_to_remove.append(self.graphics_scene.addRect(rect, pen)) # draw the drag point radius = QPoint(3, 3) brush = QBrush(QColor(0, 255, 255)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(top_left_point - radius, top_left_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(top_middle_point - radius, top_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(top_right_point - radius, top_right_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(left_middle_point - radius, left_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(right_middle_point - radius, right_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(bottom_left_point - radius, bottom_left_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(bottom_middle_point - radius, bottom_middle_point + radius), pen, brush)) self.items_to_remove.append( self.graphics_scene.addEllipse( QRectF(bottom_right_point - radius, bottom_right_point + radius), pen, brush)) # draw the textedit if self.textPosition is not None: textSpacing = 50 position = QPoint() if self.textPosition.x() + self.textInput.width( ) >= self.screenPixel.width(): position.setX(self.textPosition.x() - self.textInput.width()) else: position.setX(self.textPosition.x()) if self.textRect is not None: if self.textPosition.y() + self.textInput.height( ) + self.textRect.height() >= self.screenPixel.height(): position.setY(self.textPosition.y() - self.textInput.height() - self.textRect.height()) else: position.setY(self.textPosition.y() + self.textRect.height()) else: if self.textPosition.y() + self.textInput.height( ) >= self.screenPixel.height(): position.setY(self.textPosition.y() - self.textInput.height()) else: position.setY(self.textPosition.y()) self.textInput.move(position) self.textInput.show() # self.textInput.getFocus() # draw the magnifier if self.action == ACTION_SELECT: self.drawMagnifier() if self.mousePressed: self.drawSizeInfo() if self.action == ACTION_MOVE_SELECTED: self.drawSizeInfo() # deal with every step in drawList def drawOneStep(self, step): """ :type step: tuple """ if step[0] == ACTION_RECT: self.graphics_scene.addRect( QRectF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_ELLIPSE: self.graphics_scene.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.graphics_scene.addPolygon(arrow, step[5], step[6]) elif step[0] == ACTION_LINE: self.graphics_scene.addLine( QLineF(QPointF(step[1], step[2]), QPointF(step[3], step[4])), step[5]) elif step[0] == ACTION_FREEPEN: self.graphics_scene.addPath(step[1], step[2]) elif step[0] == ACTION_TEXT: textAdd = self.graphics_scene.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.selected_area.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.items_to_remove.append( self.graphics_scene.addRect(QRectF(sizeInfoArea), Qt.white, QBrush(Qt.black))) sizeInfo = self.graphics_scene.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.items_to_remove.append(sizeInfo) def drawRect(self, x1, x2, y1, y2, result): rect = self.selected_area.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.selected_area.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.selected_area.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.selected_area.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.selected_area = 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 InitialPoseDialog(QDialog, Ui_PoseDialog): data_manager = None image = None y_line = 0 y_top_line = 0 y_lower_line = 0 landmark_size = 2 lines = None middle_idx = 0 pose_model = None def __init__(self, data_manager): super(InitialPoseDialog, self).__init__() self.setupUi(self) self.setAttribute(Qt.WA_DeleteOnClose) assert isinstance(data_manager, DataManager) self.data_manager = data_manager self.pose_model = InitialPoseModel(data_manager) self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.image = Filter.crop_image(self.data_manager.radiographs[0].image) self.findButton.clicked.connect(self.find_jaw_divider) self.openButton.clicked.connect(self._open_radiograph) self._redraw() def find_jaw_divider(self): self.y_top_line, self.y_lower_line = self.pose_model._find_jaw_separation_line(self.pose_model._crop_image_sides(self.image)) upper_jaw_image = self.pose_model.crop_upper_jaw(self.image, self.y_top_line) lower_jaw_image = self.pose_model.crop_lower_jaw(self.image, self.y_lower_line) # Filter the image upper_jaw_image = Filter.process_image(upper_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6) lower_jaw_image = Filter.process_image(lower_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6) upper_jaw_image = self.pose_model._convert_to_binary_image(upper_jaw_image) lower_jaw_image = self.pose_model._convert_to_binary_image(lower_jaw_image) upper_lines = self.pose_model._find_hough_lines(upper_jaw_image, threshold=15) lower_lines = self.pose_model._find_hough_lines(lower_jaw_image, threshold=15) # Filter out lines upper_lines = self.pose_model._filter_lines(upper_lines, upper_jaw_image.shape, line_offset=6, max_line_gap=90) lower_lines = self.pose_model._filter_lines(lower_lines, lower_jaw_image.shape, line_offset=2, max_line_gap=60) self.image = lower_jaw_image self.lines = lower_lines self._redraw() def _open_radiograph(self): file_dialog = QFileDialog(self) file_dialog.setDirectory("./data/Radiographs") file_dialog.setFileMode(QFileDialog.ExistingFile) file_dialog.setNameFilter("Radiograph (*.tif)") if file_dialog.exec_() and len(file_dialog.selectedFiles()) == 1: radiograph = Radiograph() radiograph.path_to_img = file_dialog.selectedFiles()[0] #self.image = radiograph.image #crop_translation = -Filter.get_cropping_region(radiograph.image).left_top self.image = Filter.crop_image(radiograph.image) self.lines = None self._redraw() def _redraw(self, normalize=False): self.scene.clear() img = self.image.copy() if normalize: img = (img / img.max()) * 255 # Draw image qimg = toQImage(img.astype(np.uint8)) self.scene.addPixmap(QPixmap.fromImage(qimg)) # Add jaws divider self.scene.addLine(QLineF(0, self.y_line, self.image.shape[1], self.y_line), pen=QPen(QColor.fromRgb(255, 0, 0))) self.scene.addLine(QLineF(0, self.y_top_line, self.image.shape[1], self.y_top_line), pen=QPen(QColor.fromRgb(255, 0, 0))) self.scene.addLine(QLineF(0, self.y_lower_line, self.image.shape[1], self.y_lower_line), pen=QPen(QColor.fromRgb(255, 0, 0))) # Add image center self.scene.addEllipse(self.image.shape[0]/2 - self.landmark_size, self.image.shape[1]/2 - self.landmark_size, self.landmark_size * 2, self.landmark_size * 2, pen=QPen(QColor.fromRgb(255, 0, 0)), brush=QBrush(QColor.fromRgb(255, 0, 0))) # Draw Hough lines if self.lines is not None: #for x1,y1,x2,y2 in self.lines[0]: for i, line_param in enumerate(self.lines): rho,theta = line_param a = np.cos(theta) b = np.sin(theta) x0 = a*rho y0 = b*rho x1 = int(x0 + 200*(-b)) y1 = int(y0 + 200*(a)) x2 = int(x0 - 200*(-b)) y2 = int(y0 - 200*(a)) self.scene.addLine(QLineF(x1, y1, x2, y2), pen=QPen(QColor.fromRgb(0, 255, 0)))
class MapPainter(object): def __init__(self, parent, view, displayCities, displayConnections, displayBestUnit): super().__init__() self.view = view self.displayCities = displayCities self.displayConnections = displayConnections self.displayBestUnit = displayBestUnit self.problemMap = None self.bestUnit = None self.scene = QGraphicsScene(parent) self.resizeScene() self.view.setScene(self.scene) self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) def resizeScene(self): height = self.view.size().height() width = self.view.size().width() self.scene.setSceneRect(0.0, 0.0, width, height) def setProblemMap(self, problemMap): self.problemMap = problemMap def setBestUnit(self, unit): self.bestUnit = unit def setDisplayCities(self, enabled = False): self.displayCities = bool(enabled) def setDisplayConnections(self, enabled = False): self.displayConnections = bool(enabled) def setDisplayBestUnit(self, enabled = False): self.displayBestUnit = bool(enabled) def repaint(self): if self.problemMap is None: return self.scene.clear() self.resizeScene() height = self.scene.height() width = self.scene.width() if self.displayCities: cityBrush = QBrush(QColor(0, 0, 0), Qt.SolidPattern) cityPen = QPen(cityBrush, 5.0) for city in self.problemMap.cities: x = width * city.positionX y = height * city.positionY self.scene.addEllipse(x, y, 4, 4, cityPen, cityBrush) if self.displayConnections: connectionBrush = QBrush(QColor(0, 0, 255), Qt.SolidPattern) connectionPen = QPen(connectionBrush, 1.0) for city in self.problemMap.cities: for neighbour in city.connections: x = width * city.positionX y = height * city.positionY x2 = width * self.problemMap.cities[neighbour].positionX y2 = height * self.problemMap.cities[neighbour].positionY self.scene.addLine(x, y, x2, y2, connectionPen) if self.displayBestUnit and self.bestUnit is not None: bestUnitBrush = QBrush(QColor(255, 0, 0), Qt.SolidPattern) bestUnitPen = QPen(bestUnitBrush, 2.0) for i in range(-1, len(self.bestUnit.path)-1): currCity = self.problemMap.cities[self.bestUnit.path[i]] nextCity = self.problemMap.cities[self.bestUnit.path[i+1]] x = width * currCity.positionX y = height * currCity.positionY x2 = width * nextCity.positionX y2 = height * nextCity.positionY self.scene.addLine(x, y, x2, y2, bestUnitPen) self.view.fitInView(self.scene.sceneRect())
class Pyqt5_Serial(QtWidgets.QMainWindow, Ui_MainWindow): # 声明信号 serial_signal = pyqtSignal(int, int) def __init__(self, parent=None): super(Pyqt5_Serial, self).__init__(parent=parent) self.setupUi(self) self.init() self.setWindowTitle("UWB串口助手") self.serial_uwb = serial.Serial() self.port_check() otherClass = MyDynamicMplCanvas() # 信号和槽,传送数据给QDialoge self.serial_signal.connect(otherClass.robot_position) self.serial_signal.emit(0, 0) self.graphicsView.scale(1, -1) # x轴倒转 self.graphics() def init(self): # 串口检测按钮 self.s1__box_1.clicked.connect(self.port_check) # 串口信息显示 # self.s1__box_2.currentTextChanged.connect(self.port_info) # 打开串口按钮 self.open_serial_button.clicked.connect(self.port_open) # 关闭串口按钮 self.close_serial_button.clicked.connect(self.port_close) # 接受数据定时器 self.timer_receive = QTimer(self) self.timer_receive.timeout.connect(self.data_receive) def port_check(self): """ 检测所有串口 """ self.Com_Dict = {} # 将所有串口信息存储在字典中 port_list = list(serial.tools.list_ports.comports()) self.s1__box_2.clear() for port in port_list: self.Com_Dict["%s" % port[0]] = "%s" % port[1] self.s1__box_2.addItem(port[0]) if len(self.Com_Dict) == 0: self.open_serial_button.setEnabled(False) def port_open(self): """ 打开串口 """ # self.serial_uwb.port = "COM3" #串口号 self.serial_uwb.port = self.s1__box_2.currentText() self.serial_uwb.baudrate = int(115200) # 波特率 self.serial_uwb.bytesize = int(8) # 数据位 self.serial_uwb.parity = "N" # 奇偶性,即校验位 self.serial_uwb.stopbits = int(1) # 停止位 # sudo chmod a+rw /dev/ttyACM0 给予权限 try: self.serial_uwb.open() except: QMessageBox.critical(self, "Port Error", "此串口不能打开!") return None # 打开串口接收定时器,周期为2ms self.timer_receive.start(200) if self.serial_uwb.isOpen(): self.open_serial_button.setEnabled(False) self.close_serial_button.setEnabled(True) def port_close(self): """ 关闭串口 """ self.timer_receive.stop() try: self.serial_uwb.close() except: pass self.open_serial_button.setEnabled(True) self.close_serial_button.setEnabled(False) def data_receive(self): otherClass = MyDynamicMplCanvas() # 信号和槽,传送数据给QDialoge """ 数据接收 """ try: num = self.serial_uwb.inWaiting() except: self.port_close() return None if num > 0: serial_data = self.serial_uwb.read(num) unicode_data = serial_data.decode('iso-8859-1') # print(unicode_data) # return unicode_data data_lines = unicode_data.split('\r\n') # 列表 for line in data_lines: data = line.split() if len(data) == 10: # print(data) if (data[0] == 'ma'): # 表示基站0到基站x的距离 if ( data[1] != '0e' ): # MASK=e(0000 1111)表示 RANGE0,RANGE1,RANGE2,RANGE3 都有效 print("ma's Range 只有 " + data[1] + " 工作。") # break else: # 16进制转为10进制,距离单位:mm # range_0 = int(data[2],16) range_0没有'ma'对应的操作说明 # self.serial__receive_text.insertPlainText(unicode_data) range_1 = int(data[3], 16) range_2 = int(data[4], 16) # range_3 = int(data[5],16) # print("基站0到基站1的距离:%d"%(range_1)+",基站0到基站2的距离:%d"%(range_2)+",基站0到基站3的距离:%d"%(range_3)) else: # data[0] == 'mc' or 'mr' :表示标签x到基站y的距离 if (data[1] != '07' ): # MASK=7(0000 0111)表示 RANGE0,RANGE1,RANGE2 都有效 print("mc's Range 只有 " + data[1] + " 工作。") # break else: # 16进制转为10进制,距离单位:mm range_0 = int(data[2], 16) range_1 = int(data[3], 16) range_2 = int(data[4], 16) # range_3 = int(data[5],16) # print("标签x到基站0的距离:%d" % (range_0) + # ",标签x到基站1的距离:%d" % (range_1) + # ",标签x到基站2的距离:%d" % (range_2)) anchor_0 = np.array([0, 0], dtype=np.int64) anchor_1 = np.array([7500, 0], dtype=np.int64) anchor_2 = np.array([0, 5000], dtype=np.int64) tag_position = self.getLocation( anchor_0, anchor_1, anchor_2, range_0, range_1, range_2) # if (tag_position[0]-anchor_2[0])**2 + (tag_position[1]-anchor_2[1])**2 > range_2: if tag_position[1] != -1: # print("标签坐标X:%f" % # tag_position[0] + ",Y:%f" % tag_position[1]) self.graphics( [tag_position[0], tag_position[1]]) self.serial_signal.connect( otherClass.robot_position) self.serial_signal.emit( tag_position[0], tag_position[1]) else: pass def getLocation(self, anchor_0, anchor_1, anchor_2, range_0, range_1, range_2): """ 根据trilateration 计算标签的坐标 """ tag_position = np.array([0, 0], dtype=np.int64) tag_position[0] = int( (range_0**2 - range_1**2 + anchor_1[0]**2) / (2 * anchor_1[0])) distance = range_0**2 - tag_position[0]**2 # print(type(distance)) if distance > 0: tag_position[1] = np.sqrt(distance) else: tag_position[1] = -1 return tag_position # ValueError: cannot convert float NaN to integer #17 def graphics(self, newPos=[0, 0]): """ qt绘图 """ axis_x = 750 axis_y = 500 # self.rect = QRectF(0,0,w-10,h-10) # self.scene = QGraphicsScene(self.rect) self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.scene.addRect(0, 0, axis_x, axis_y) self.scene.addEllipse(0 - 8, 0 - 8, 15, 15, brush=QBrush(QColor.fromRgb(120, 50, 255))) self.scene.addEllipse(0 - 8, axis_y - 8, 15, 15, brush=QBrush(QColor.fromRgb(120, 50, 255))) self.scene.addEllipse(axis_x - 8, 0 - 8, 15, 15, brush=QBrush(QColor.fromRgb(120, 50, 255))) self.scene.addEllipse(axis_x - 8, axis_y - 8, 15, 15, brush=QBrush(QColor.fromRgb(120, 50, 255))) self.scene.addLine(0, 0, axis_x, 0, pen=QPen(QColor.fromRgb(255, 0, 0))) self.scene.addLine(0, 0, 0, axis_y, pen=QPen(QColor.fromRgb(255, 0, 0))) self.anchor_0 = np.array([0, 0], dtype=np.int64) self.anchor_1 = np.array([axis_x, 0], dtype=np.int64) self.anchor_2 = np.array([0, axis_y], dtype=np.int64) brick_width = 1000 / 10 # 砖长:300mm brick_height = 1000 / 10 self.brick_gap = 50 / 10 # 砖间隙:5mm global height_num, width_num height_num = np.int(self.anchor_2[1] / brick_height) width_num = np.int(self.anchor_1[0] / brick_width) global bricks # 全局 bricks = np.zeros((width_num * height_num, 5), dtype=int) # 可利用json数据类型 """ 砖摆放,从x,y轴出发 """ for j in range(height_num): for i in range(width_num): self.brick_x = i * (self.brick_gap + brick_width) self.brick_y = j * (self.brick_gap + brick_height) bricks[i + j] = [i, j, self.brick_x, self.brick_y, 0] # 填写每一块砖的信息 # print(bricks[i+j]) rectangle_item = QGraphicsRectItem(self.brick_x, self.brick_y, brick_width, brick_height) # Add the patch to the Axes # currentAxis.add_patch(self.rectangle) self.scene.addItem(rectangle_item) robot_item = QGraphicsEllipseItem(newPos[0] / 10, newPos[1] / 10, 10, 10) robot_item.setBrush(QBrush(QColor.fromRgb(0, 255, 255))) self.scene.addItem(robot_item) def wheelEvent(self, event): """ Zoom in or out of the view. """ zoomInFactor = 1.25 zoomOutFactor = 1 / zoomInFactor # Save the scene pos oldPos = self.graphicsView.mapToScene(event.pos()) # print("oldPos:%d" %oldPos[0]) # Zoom if event.angleDelta().y() > 0: zoomFactor = zoomInFactor else: zoomFactor = zoomOutFactor self.graphicsView.scale(zoomFactor, zoomFactor) # Get the new position newPos = self.graphicsView.mapToScene(event.pos()) # Move scene to old position delta = newPos - oldPos self.graphicsView.translate(delta.x(), delta.y())
class GraphCanvas(QGraphicsView): def __init__(self, width, height): QGraphicsView.__init__(self) self.width, self.height = width, height self.setGeometry(0, 0, width, height) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, width, height - 80) self.setScene(self.scene) self.chrisSteps = { 1: "self.colorMST", 2: "self.colorOddVertices", 3: "self.oddVSubGraph", 4: "self.perfectMatching", 5: "self.eulerian", 6: "self.hamiltonian" } self.delay = 2000 def drawGraph(self, verticesNb): self.scene.clear() blackPen = QPen(Qt.black) blackPen.setWidth(3) vertices = [] self.graphicVertices = [] self.verticesNb = verticesNb for i in range(verticesNb): y = (self.height / 10 + self.width / 2) - sin( radians(i * 360 / verticesNb)) * (self.width / 2 - 20) x = self.width / 2 + cos(radians( i * 360 / verticesNb)) * (self.width / 2 - 20) self.graphicVertices.append( self.scene.addEllipse(x - 15, y - 15, 30, 30, blackPen)) j = i + 1 for j in range(i): self.scene.addLine(x, y, vertices[j][0], vertices[j][1]) vertices.append((x, y)) self.scene.update() return vertices def drawStep(self, edges, color="black"): self.scene.clear() pen = QPen(eval("Qt." + color)) pen.setWidth(3) self.drawVertices() for e in edges: self.scene.addLine(e[0][0], e[0][1], e[1][0], e[1][1], pen) self.scene.update() def colorSubTour(self, subTours, step): print("hello") self.scene.clear() pen = QPen() pen.setWidth(2) self.drawVertices() for subTour in subTours: pen.setColor( QColor(randint(0, 255), randint(0, 255), randint(0, 255))) for i in range(len(subTour) - 1): self.scene.addLine(subTour[i][0], subTour[i][1], subTour[i + 1][0], subTour[i + 1][1], pen) self.scene.addLine(subTour[-1][0], subTour[-1][1], subTour[0][0], subTour[0][1], pen) if not step: QtTest.QTest.qWait(self.delay) def drawVertices(self): pen = QPen(Qt.black) pen.setWidth(2) for i in range(self.verticesNb): y = (self.height / 10 + self.width / 2) - sin( radians(i * 360 / self.verticesNb)) * (self.width / 2 - 20) x = self.width / 2 + cos(radians( i * 360 / self.verticesNb)) * (self.width / 2 - 20) ellipse = self.scene.addEllipse(x - 15, y - 15, 30, 30, pen) ################################################################################################################# # # CHRISTOFIDES # ################################################################################################################# def updateChristofides(self, step, *args): if not step: QtTest.QTest.qWait(self.delay) print("args[0] " + str(args[0])) step = self.chrisSteps[args[0]] args = args[1:] eval(step + "(*args)") def colorMST(self, MST): self.MST = MST self.drawEdges(MST, Qt.blue) def colorOddVertices(self, oddVertices): self.oVertices = [] brush = QBrush() brush.setStyle(Qt.SolidPattern) brush.setColor(Qt.cyan) for vertice in oddVertices: self.oVertices.append(vertice) self.graphicVertices[vertice].setBrush(brush) def oddVSubGraph(self, vertices): pen = QPen() pen.setWidth(2) pen.setColor(Qt.cyan) self.scene.clear() self.drawGraph(self.verticesNb) self.colorOddVertices(self.oVertices) for i in range(len(self.oVertices)): for j in range(i, len(self.oVertices)): self.scene.addLine(vertices[self.oVertices[i]][0], vertices[self.oVertices[i]][1], vertices[self.oVertices[j]][0], vertices[self.oVertices[j]][1], pen) def perfectMatching(self, PM): self.PM = PM self.drawEdges(PM, Qt.red) def eulerian(self, PM): self.scene.clear() self.drawGraph(self.verticesNb) self.drawEdges(self.PM, Qt.red) self.drawEdges(self.MST, Qt.blue) QtTest.QTest.qWait(2000) eulerian = self.PM + self.MST self.drawEdges(eulerian, Qt.magenta) def hamiltonian(self, edges): self.scene.clear() self.drawGraph(self.verticesNb) self.drawEdges(edges, Qt.green) def drawEdges(self, edges, color=Qt.black): pen = QPen() pen.setWidth(2) pen.setColor(color) for edge in edges: self.scene.addLine(edge[0][0], edge[0][1], edge[1][0], edge[1][1], pen) self.scene.update() # def drawGraph(self,vertices,edges): # for vertice in vertices: def updateDelay(self, delay): self.delay = delay
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 RecordsetWindow(QWidget): #sensorsColor = ['e0c31e', '14148c', '006325', '6400aa', '14aaff', 'ae32a0', '80c342', '868482'] def __init__(self, manager, recordset, parent=None): super(QWidget, self).__init__(parent=parent) self.UI = Ui_frmRecordsets() self.UI.setupUi(self) self.sensors = {} self.sensors_items = {} self.sensors_graphs = {} self.time_pixmap = False self.time_bar = None self.dbMan = manager self.recordsets = recordset # Init temporal browser self.timeScene = QGraphicsScene() self.UI.graphTimeline.setScene(self.timeScene) self.UI.graphTimeline.fitInView(self.timeScene.sceneRect(), Qt.KeepAspectRatio) self.UI.graphTimeline.time_clicked.connect(self.timeview_clicked) """blackBrush = QBrush(Qt.black) blueBrush = QBrush(Qt.blue) blackPen = QPen(Qt.black) self.timeScene.addRect(100, 0, 80, 100, blackPen, blueBrush) rectangle = self.timeScene.addRect(100, 0, 80, 100, blackPen, blackBrush) rectangle.setFlag(QGraphicsItem.ItemIsMovable)""" # Update general informations about recordsets self.update_recordset_infos() # Load sensors for that recordset self.load_sensors() self.UI.lstSensors.itemChanged.connect(self.sensor_current_changed) def paintEvent(self, QPaintEvent): if not self.time_pixmap: self.draw_recordsets() self.draw_sensors() self.draw_dates() self.draw_timebar() self.time_pixmap = True def load_sensors(self): self.UI.lstSensors.clear() self.sensors = {} self.sensors_items = {} # Create sensor colors used_colors = [] #colors = QColor.colorNames() colors = [ 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategray', 'darkslategrey', 'darkturquoise', 'darkviolet' ] # Filter "bad" colors for sensors """colors.remove("white") colors.remove("black") colors.remove("transparent") colors.remove("red") colors.remove("green")""" # shuffle(colors) color_index = 0 if len(self.recordsets) > 0: for sensor in self.dbMan.get_sensors(self.recordsets[0]): self.sensors[sensor.id_sensor] = sensor for sensor in self.sensors.values(): index = -1 location_item = self.UI.lstSensors.findItems( sensor.location, Qt.MatchExactly) if len(location_item) == 0: item = QListWidgetItem(sensor.location) item.setFlags(Qt.NoItemFlags) self.UI.lstSensors.addItem(item) else: index = self.UI.lstSensors.indexFromItem( location_item[0]).row() # Check if sensor is already there under that location item sensor_name = sensor.name + " (" + sensor.hw_name + ")" present = False if index != -1: for i in range(index, self.UI.lstSensors.count()): if self.UI.lstSensors.item(i).text() == sensor_name: present = True break if not present: item = QListWidgetItem(QIcon(':/OpenIMU/icons/sensor.png'), sensor_name) item.setCheckState(Qt.Unchecked) item.setForeground(QColor(colors[color_index])) item.setData(Qt.UserRole, sensor.id_sensor) #self.sensors_colors.append(colors[color_index]) self.sensors_items[sensor.id_sensor] = item color_index += 1 if color_index >= len(colors): color_index = 0 if index == -1: self.UI.lstSensors.addItem(item) else: self.UI.lstSensors.insertItem(index + 2, item) def update_recordset_infos(self): if len(self.recordsets) == 0: self.UI.lblTotalValue.setText("Aucune donnée.") self.UI.lblDurationValue.setText("Aucune donnée.") return start_time = self.recordsets[0].start_timestamp end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp # Coverage self.UI.lblTotalValue.setText(str(start_time) + " @ " + str(end_time)) # Duration self.UI.lblDurationValue.setText(str(end_time - start_time)) self.UI.lblCursorTime.setText(str(start_time)) def get_relative_timeview_pos(self, current_time): start_time = self.recordsets[0].start_timestamp end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp time_span = (end_time - start_time ).total_seconds() # Total number of seconds in recordsets return (((current_time - self.recordsets[0].start_timestamp).total_seconds()) / time_span) * self.UI.graphTimeline.width() def draw_dates(self): if len(self.recordsets) == 0: return # Computations start_time = self.recordsets[0].start_timestamp end_time = self.recordsets[len(self.recordsets) - 1].end_timestamp time_span = (end_time - start_time ).total_seconds() # Total number of seconds in recordsets current_time = (datetime(start_time.year, start_time.month, start_time.day, 0, 0, 0) + timedelta(days=1)) # Drawing tools whitePen = QPen(Qt.white) blackPen = QPen(Qt.black) blackBrush = QBrush(Qt.black) # Date background rectangle self.timeScene.addRect(0, 0, self.UI.graphTimeline.width(), self.UI.graphTimeline.height() / 4, blackPen, blackBrush) # First date date_text = self.timeScene.addText(start_time.strftime("%d-%m-%Y")) date_text.setPos(0, -5) date_text.setDefaultTextColor(Qt.white) self.timeScene.addLine(0, 0, 0, self.UI.graphTimeline.height(), whitePen) # Date separators while current_time <= end_time: pos = self.get_relative_timeview_pos(current_time) self.timeScene.addLine(pos, 0, pos, self.UI.graphTimeline.height(), whitePen) date_text = self.timeScene.addText( current_time.strftime("%d-%m-%Y")) date_text.setPos(pos, -5) date_text.setDefaultTextColor(Qt.white) current_time += timedelta(days=1) def draw_recordsets(self): greenBrush = QBrush(QColor(212, 247, 192)) transPen = QPen(Qt.transparent) # Empty rectangle (background) self.timeScene.addRect(0, 0, self.UI.graphTimeline.width(), self.UI.graphTimeline.height(), transPen, QBrush(Qt.red)) self.timeScene.setBackgroundBrush(QBrush(Qt.red)) # Recording length for record in self.recordsets: start_pos = self.get_relative_timeview_pos(record.start_timestamp) end_pos = self.get_relative_timeview_pos(record.end_timestamp) span = end_pos - start_pos self.timeScene.addRect(start_pos, 0, span, self.UI.graphTimeline.height(), transPen, greenBrush) def draw_sensors(self): if len(self.sensors) == 0: return bar_height = (3 * (self.UI.graphTimeline.height() / 4)) / len(self.sensors) # for sensor in self.sensors: i = 0 for sensor in self.sensors.values(): sensorBrush = QBrush( self.sensors_items[sensor.id_sensor].foreground()) sensorPen = QPen(Qt.transparent) for record in self.recordsets: datas = self.dbMan.get_all_sensor_data( sensor=sensor, recordset=record, channel=sensor.channels[0]) for data in datas: start_pos = self.get_relative_timeview_pos( data.start_timestamp) end_pos = self.get_relative_timeview_pos( data.end_timestamp) span = max(end_pos - start_pos, 1) self.timeScene.addRect( start_pos, i * bar_height + (self.UI.graphTimeline.height() / 4), span, bar_height, sensorPen, sensorBrush) i += 1 def draw_timebar(self): self.time_bar = self.timeScene.addLine(0, 0, 0, self.timeScene.height(), QPen(Qt.cyan)) @pyqtSlot(QListWidgetItem) def sensor_current_changed(self, item): sensor = self.sensors[item.data(Qt.UserRole)] timeseries = [] # Color map colors = [Qt.red, Qt.green, Qt.darkBlue] if item.checkState() == Qt.Checked: # Choose the correct display for each sensor channels = self.dbMan.get_all_channels(sensor=sensor) for channel in channels: # Will get all data (converted to floats) channel_data = [] for record in self.recordsets: channel_data += self.dbMan.get_all_sensor_data( recordset=record, convert=True, sensor=sensor, channel=channel) if sensor.id_sensor_type == SensorType.ACCELEROMETER \ or sensor.id_sensor_type == SensorType.GYROMETER \ or sensor.id_sensor_type == SensorType.BATTERY\ or sensor.id_sensor_type == SensorType.LUX: timeseries.append(self.create_data_timeseries(channel_data)) timeseries[-1]['label'] = channel.label graph = IMUChartView() # graph.add_test_data() # Add series for series in timeseries: graph.add_data(series['x'], series['y'], color=colors.pop(), legend_text=series['label']) graph.set_title(item.text()) self.UI.mdiArea.addSubWindow(graph).setWindowTitle(item.text()) graph.show() self.sensors_graphs[sensor.id_sensor] = graph graph.aboutToClose.connect(self.graph_was_closed) graph.cursorMoved.connect(self.graph_cursor_changed) self.tile_graphs_vertically() if sensor.id_sensor_type == SensorType.GPS: graph = GPSView(self.UI.mdiArea) for data in channel_data: gps = GPSGeodetic() gps.from_bytes(data.data) if gps.latitude != 0 and gps.longitude != 0: graph.addPosition(data.start_timestamp, gps.latitude / 1e7, gps.longitude / 1e7) graph.setCursorPositionFromTime(data.start_timestamp) # print (gps) self.UI.mdiArea.addSubWindow(graph).setWindowTitle(item.text()) graph.show() self.sensors_graphs[sensor.id_sensor] = graph graph.aboutToClose.connect(self.graph_was_closed) graph.cursorMoved.connect(self.graph_cursor_changed) else: # Remove from display if self.sensors_graphs[sensor.id_sensor] is not None: self.UI.mdiArea.removeSubWindow( self.sensors_graphs[sensor.id_sensor].parent()) self.sensors_graphs[sensor.id_sensor] = None @pyqtSlot(QObject) def graph_was_closed(self, graph): for sensor_id, sensor_graph in self.sensors_graphs.items(): if sensor_graph == graph: self.sensors_graphs[sensor_id] = None self.sensors_items[sensor_id].setCheckState(Qt.Unchecked) break # self.tile_graphs_vertically() @pyqtSlot(datetime) def graph_cursor_changed(self, timestamp): for graph in self.sensors_graphs.values(): if graph is not None: graph.setCursorPositionFromTime(timestamp, False) pos = self.get_relative_timeview_pos(timestamp) self.time_bar.setPos(pos, 0) @pyqtSlot(int) def timeview_clicked(self, x): self.time_bar.setPos(x, 0) # Find time corresponding to that position timestamp = (x / self.timeScene.width()) * ( self.recordsets[len(self.recordsets) - 1].end_timestamp - self. recordsets[0].start_timestamp) + self.recordsets[0].start_timestamp self.UI.lblCursorTime.setText(str(timestamp)) for graph in self.sensors_graphs.values(): if graph is not None: #try: graph.setCursorPositionFromTime(timestamp, True) #except AttributeError: # continue @timing def create_data_timeseries(self, sensor_data_list: list): time_values = [] data_values = [] for sensor_data in sensor_data_list: # print('sensor_data', sensor_data) # Will get a dict with keys: time, values vals = sensor_data.to_time_series() # print('vals is length', len(vals)) time_values.append(vals['time']) data_values.append(vals['values']) # print('time_values length', len(time_values)) # print('data_values length', len(data_values)) # Concat vectors time_array = np.concatenate(time_values) data_array = np.concatenate(data_values) # Test, remove first time # time_array = time_array - time_array[0] # print('time_array_shape, data_array_shape', time_array.shape, data_array.shape) # return data return {'x': time_array, 'y': data_array} def tile_graphs_horizontally(self): if self.UI.mdiArea.subWindowList() is None: return position = QPoint(0, 0) for window in self.UI.mdiArea.subWindowList(): rect = QRect( 0, 0, self.UI.mdiArea.width() / len(self.UI.mdiArea.subWindowList()), self.UI.mdiArea.height()) window.setGeometry(rect) window.move(position) position.setX(position.x() + window.width()) def tile_graphs_vertically(self): if self.UI.mdiArea.subWindowList() is None: return position = QPoint(0, 0) for window in self.UI.mdiArea.subWindowList(): rect = QRect( 0, 0, self.UI.mdiArea.width(), self.UI.mdiArea.height() / len(self.UI.mdiArea.subWindowList())) window.setGeometry(rect) window.move(position) position.setY(position.y() + window.height())
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 DijkstraGui(QMainWindow, Ui_MainWindow): def __init__(self): QMainWindow.__init__(self) Ui_MainWindow.__init__(self) self.setupUi(self) # event self.btnGenerate.clicked.connect(self.btnGenerate_Clicked) self.btnFind.clicked.connect(self.btnFind_Clicked) self.cbxShowSteps.stateChanged.connect(self.cbxShowSteps_Clicked) self.lineEditPoint.textChanged.connect(self.lineEditPoint_TextChanged) self.lineEditLine.textChanged.connect(self.lineEditLine_TextChanged) self.countPoints = self.lineEditPoint.text() self.countLines = self.lineEditLine.text() self.RADIUS = 20 self.RADIUS2 = self.RADIUS * 2 self.RADIUS3 = self.RADIUS + 3 self.SIZE = 150 self.countPoint, self.countLine, self.countStep, self.maxStep = 0, 0, 0, 0 self.newDistance, self.listSteps, self.listPath = [], [], [] self.points = [QPoint(0, 0) for i in range(20)] self.listLine = [QPoint(0, 0) for i in range(400)] self.distance = np.empty((20, 20), dtype=object) self.lines = np.empty((20, 20), dtype=Pair) self.start, self.end = -1, -1 self.isDone, self.isFounded = False, False self.chooseState = 0 self.textChoose = [ 'vuongdq85', 'Choose point start...', 'Choose point end...' ] pen = QPen(Qt.black, 2) penStart = QPen(Qt.darkGreen, 4) penDest = QPen(Qt.darkRed, 4) pencil = QPen(Qt.red, 4) # draw canvas self.scene = QGraphicsScene() self.scene.addLine(400, 100, 100, 100, pencil) self.graphicsViewPaint.setScene(self.scene) # self.reset() self.generate() # func event def btnGenerate_Clicked(self): print("btnGenerate") print("Point: {0}".format(self.countPoints)) print("Line: {0}".format(self.countLines)) self.reset() ok = False try: self.countPoints = int(self.lineEditPoint.text()) self.countLines = int(self.lineEditLine.text()) if ((0 < self.countPoints and self.countPoints <= 20) and (0 < self.countLines and self.countLines <= 380)): ok = True except Exception as ex: pass print(ok) if ok: self.generate() else: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText("Wrong amount of points") msg.setWindowTitle("Error") msg.exec_() def btnFind_Clicked(self): print("btnFind") def cbxShowSteps_Clicked(self, int): if (self.cbxShowSteps.isChecked()): print("cbxShowSteps Checked") else: print("cbxShowSteps unChecked") def lineEditPoint_TextChanged(self): self.countPoints = self.lineEditPoint.text() def lineEditLine_TextChanged(self): self.countLines = self.lineEditLine.text() def graphicsViewPaint_draw(self): self.scene.addEllipse(400, 100, 100, 100) self.graphicsViewPaint.setScene(self.scene) def generate(self): print('generate') array = np.zeros(20, dtype=np.int64) k = 0 count = 20 region = 0 for i in range(0, int(self.countPoints)): for j in range(0, int(self.countPoints)): self.distance[i, j] = 0 if (i != j): self.listLine[k] = QPoint(i, j) k = k + 1 n = rd.randint(0, count - 1) region = array[n] count = count - 1 array[n] = array[count] p = self.randomInRegion(region) self.points[i] = p for i in range(0, int(self.countLines)): n = rd.randint(0, k) p = self.listLine[n] k = k - 1 self.listLine[n] = self.listLine[k] self.distance[p.x()][p.y()] = self.calDistance( self.points[p.x()], self.points[p.y()]) px1 = self.points[p.x()].x() px2 = self.points[p.y()].x() py1 = self.points[p.x()].y() py2 = self.points[p.y()].y() try: offsetX = (px2 - px1) * self.RADIUS3 / self.distance[p.x()][p.x()] offsetY = (py2 - py1) * self.RADIUS3 / self.distance[p.x()][p.x()] except ZeroDivisionError as e: pass finally: self.lines[p.x(), p.y()] = Pair(QPoint(px1 + offsetX, py1 + offsetY), QPoint(px2 - offsetX, py2 - offsetY)) for i in range(0, int(self.countPoints)): for j in range(0, int(self.countPoints)): if self.distance[i, j] != 0: self.scene.addLine(self.lines[i, j].first, self.lines[i, j].second) self.graphicsViewPaint.setScene(self.scene) def randomInRegion(self, region): minX = region % 5 * self.SIZE + self.RADIUS maxX = minX + self.SIZE - self.RADIUS2 minY = region / 5 * self.SIZE + self.RADIUS maxY = minY + self.SIZE - self.RADIUS2 return QPoint(rd.randint(minX, maxX), rd.randint(minY, maxY)) def calDistance(self, p1, p2): x = p1.x() - p2.x() y = p1.y() - p2.y() return int(math.sqrt(x * x + y * y)) def reset(self): self.start, self.end = -1, -1 self.listPath = list() self.chooseState = 0 self.lblStatus.setText(self.textChoose[self.chooseState]) self.lblPointStart.setText('Point start: ') self.lblPointEnd.setText('Point end: ') self.lblSteps.setText('Steps: ') self.lblNodes.setText('Nodes: ') self.isFouded = False self.isDone = False
class AMANDisplay(QGraphicsView): def __init__(self): super(AMANDisplay, self).__init__() self.setGeometry(0, 0, 500, 600) self.setStyleSheet("background-color:#233370") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, 500, 600) # Timeline boundaries pen = QPen(QColor("white")) brush = QBrush(QColor("#233370")) self.scene.addLine(220, 0, 220, 600, pen) self.scene.addLine(280, 0, 280, 600, pen) self.scene.addLine(0, 30, 500, 30, pen) timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush) timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True) # Timeline scale self.timeline = QGraphicsItemGroup() self.timeline.setParentItem(timelinebox) self.timeticks = [] for i in range(40): y = 15 * i w = 6 if i % 5 == 0: w = 10 self.timeticks.append(self.scene.addText("%02d" % (40 - i), QFont("Courier", 10))) self.timeticks[-1].setPos(240, y - 10) self.timeticks[-1].setDefaultTextColor(QColor("white")) self.timeline.addToGroup(self.timeticks[-1]) self.timeline.addToGroup(self.scene.addLine(220, y, 220 + w, y, pen)) self.timeline.addToGroup(self.scene.addLine(280 - w, y, 280, y, pen)) self.lrwy = self.scene.addText("18R", QFont("Arial", 20, 50)) self.lrwy.setPos(1, 1) self.lrwy.setDefaultTextColor(QColor("white")) # Finalize self.setScene(self.scene) self.show() def update(self, simt, data): # data has: ids, iafs, eats, etas, delays, rwys, spdratios # First delete old labels for (key,) in self.aircraft.keys: if key not in data.ids: # del label del self.aircraft[key] for i in len(data.ids): if data.ids[i] not in self.aircraft: # self.aircraft[data.ids[i]] = QLabel() pass # Generate the new label text and position newtext = "<font color=Red>bla</font>" # veranderen lbl = self.aircraft[data.ids[i]] lbl.setText(newtext) lbl.move(posx, posy) # move in pixels
class ApplicationWindow(QMainWindow): class State(Enum): running = 1 idle = 2 placing_module = 3 drawing_stream = 4 placing_readout = 5 drawing_readout = 6 dragging_joint = 7 running = State.running idle = State.idle placing_module = State.placing_module drawing_stream = State.drawing_stream placing_readout = State.placing_readout drawing_readout = State.drawing_readout dragging_joint_line = State.dragging_joint def __init__(self): super(ApplicationWindow, self).__init__() self.initUI() def initUI(self): self.mouse_x = 0 self.mouse_y = 0 self.ui = Ui_MainWindow() self.ui.setupUi(self) self.state = ApplicationWindow.idle self.scene = QGraphicsScene(self) self.ui.graphicsView.setScene(self.scene) self.setWindowTitle('Flow Modeler') self.show() self.views = [] self.simulation = Simulation(self) self.timer = QTimer() self.timer.setInterval(100) self.timer.timeout.connect(self.simulation.run) self.ui.actionStart.triggered.connect(self.run_sim) self.ui.actionStop.triggered.connect(self.stop_sim) self.ui.actionSource.triggered.connect(self.create_source_slot) self.ui.actionTank.triggered.connect(self.create_tank_slot) self.ui.actionPump.triggered.connect(self.create_pump_slot) self.ui.actionSink.triggered.connect(self.create_sink_slot) self.ui.actionSplitter.triggered.connect(self.create_splitter_slot) self.ui.actionHydrocyclone.triggered.connect(self.create_hydrocyclone_slot) self.ui.actionJoiner.triggered.connect(self.create_joiner_slot) self.ui.actionReadout.triggered.connect(self.create_readout) self.ui.actionFiberReadout.triggered.connect(self.create_fiber_readout) self.setMouseTracking(True) self.ui.centralwidget.setMouseTracking(True) self.ui.graphicsView.setMouseTracking(True) self.installEventFilter(self) self.ui.graphicsView.viewport().installEventFilter(self) screen = QGuiApplication.primaryScreen() screen_width = screen.geometry().width() screen_height = screen.geometry().height() self.scene.setSceneRect(QRectF(0, 0, screen_width, screen_height)) self.floating_model = None self.floating_line = None def map_from_global_to_scene(self, pos): pos = self.ui.graphicsView.parent().mapFromParent(pos) pos = self.ui.graphicsView.mapFromParent(pos) pos = self.ui.graphicsView.mapToScene(pos) return pos @property def mouse_scene_pos(self): return self.map_from_global_to_scene(QPoint(self.mouse_x, self.mouse_y)) def offset_point(self, point, dx, dy): return QPoint(point.x() + dx, point.y() + dy) def remove_floating_objects(self): try: self.views.remove(self.floating_model.view) except Exception: pass self.floating_model = None try: self.scene.removeItem(self.floating_line) except Exception: pass self.floating_line = None # Processes mouse events. Override of parent method. def eventFilter(self, source, event): if event.type() == QEvent.HoverMove and source is self: self.mouse_x = event.pos().x() self.mouse_y = event.pos().y() graphics_view_parent = self.ui.graphicsView.parent() mapped_event_pos = graphics_view_parent.mapFromParent(event.pos()) inbounds = mapped_event_pos.x() >= 0 and \ mapped_event_pos.y() >= 0 and \ mapped_event_pos.x() < self.ui.graphicsView.width() and \ mapped_event_pos.y() < self.ui.graphicsView.height() if inbounds and self.state is ApplicationWindow.placing_module: width = self.floating_model.view.graphics_item.pixmap().width() height = self.floating_model.view.graphics_item.pixmap().height() self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width, -height)) elif inbounds and self.state is self.placing_readout: width = self.floating_model.view.graphics_item.rect().width() height = self.floating_model.view.graphics_item.rect().height() self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2)) elif inbounds and self.state is ApplicationWindow.drawing_stream: p1 = self.floating_line.line().p1() p2 = self.mouse_scene_pos self.floating_line.setLine(QLineF(p1, p2)) elif inbounds and self.state is ApplicationWindow.drawing_readout: p1 = self.floating_line.mapToScene(self.floating_line.line().p1()) width = self.floating_model.view.graphics_item.rect().width() height = self.floating_model.view.graphics_item.rect().height() self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2)) p1 = self.floating_line.mapFromScene(p1) p2 = self.floating_line.mapFromScene(self.mouse_scene_pos) self.floating_line.setLine(QLineF(p1, p2)) elif inbounds and self.state is ApplicationWindow.dragging_joint_line: self.floating_model.view.set_joint_line(self.mouse_scene_pos) elif event.type() == QEvent.MouseButtonRelease: scene_pos = self.map_from_global_to_scene(event.pos()) if self.state is ApplicationWindow.idle: pass elif self.state is ApplicationWindow.dragging_joint_line: self.state = ApplicationWindow.idle self.floating_model = None return super(ApplicationWindow, self).eventFilter(source, event) def mousePressEvent(self, event): scene_pos = self.map_from_global_to_scene(event.pos()) if self.state is ApplicationWindow.idle: stream = self.check_for_click_collisions(scene_pos) if stream: self.state = ApplicationWindow.dragging_joint_line self.floating_model = stream elif self.state is ApplicationWindow.placing_module: self.place_module() elif self.state is ApplicationWindow.drawing_stream: self.complete_stream(scene_pos) elif self.state is ApplicationWindow.drawing_readout: self.complete_readout(scene_pos) elif self.state is ApplicationWindow.placing_readout: self.start_readout(scene_pos) def run_sim(self): self.state = ApplicationWindow.running self.timer.start() def stop_sim(self): self.state = ApplicationWindow.idle self.timer.stop() def check_for_click_collisions(self, pos): for stream in self.simulation.streams: if stream.view.check_for_joint_line_collision(pos): return stream return None @pyqtSlot() def create_source_slot(self): volume_fractions = {} for species in Event.registered_species: if species.name == 'fiber': volume_fractions[species] = 0.01 elif species.name == 'water': volume_fractions[species] = 0.99 self.add_module(Source(self, 'Source', 1000, volume_fractions)) @pyqtSlot() def create_tank_slot(self): volume_fractions = {} for species in Event.registered_species: if species.name == 'fiber': volume_fractions[species] = 0.00014 elif species.name == 'water': volume_fractions[species] = 0.99986 self.add_module(Tank(self, 'Tank', 0, volume_fractions)) @pyqtSlot() def create_pump_slot(self): self.add_module(Pump(self)) @pyqtSlot() def create_sink_slot(self): self.add_module(Sink(self)) @pyqtSlot() def create_splitter_slot(self): self.add_module(Splitter(self)) @pyqtSlot() def create_hydrocyclone_slot(self): self.add_module(Hydrocyclone(self)) @pyqtSlot() def create_joiner_slot(self): self.add_module(Joiner(self)) def add_module(self, module): self.state = self.placing_module module.view.add_to_scene(self.scene) width = module.view.graphics_item.pixmap().width() height = module.view.graphics_item.pixmap().height() module.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width, -height)) self.floating_model = module def place_module(self): self.state = self.idle self.floating_model = None def socket_clicked(self, graphics_item, event): scene_pos = graphics_item.mapToScene(event.pos()) if self.state == ApplicationWindow.idle: self.create_stream(scene_pos) elif self.state == ApplicationWindow.drawing_stream: self.complete_stream(scene_pos) def create_stream(self, pos): self.floating_model = Stream(self) line = QLineF(pos, pos) self.floating_line = self.scene.addLine(line) self.floating_line.setZValue(-1) for colliding_item in self.scene.collidingItems(self.floating_line): for view in self.views: if isinstance(view.model, Socket) and view.graphics_item is colliding_item: self.floating_model.add_socket(view.model) self.state = self.drawing_stream width = colliding_item.boundingRect().width() height = colliding_item.boundingRect().height() p1 = self.offset_point(colliding_item.scenePos(), width / 2 - 1, height / 2 - 1) p2 = pos pen = QPen() pen.setWidth(2) self.floating_line.setPen(pen) self.floating_line.setLine(QLineF(p1, p2)) if self.state is not ApplicationWindow.drawing_stream: self.state = self.idle self.floating_model.cleanup() self.remove_floating_objects() def complete_stream(self, pos): self.state = self.idle line = QLineF(pos, pos) test_line_item = self.scene.addLine(line) self.floating_model.view.graphics_item = None completed = False for colliding_item in self.scene.collidingItems(test_line_item): for view in self.views: if isinstance(view.model, Socket) and view.graphics_item is colliding_item: if not self.floating_model.add_socket(view.model): continue p1 = QPointF(colliding_item.scenePos().x() + colliding_item.boundingRect().width() / 2 - 1, colliding_item.scenePos().y() + colliding_item.boundingRect().height() / 2 - 1) p2 = self.floating_line.line().p1() self.scene.removeItem(self.floating_line) self.floating_line.setLine(QLineF(p1, p2)) self.floating_model.view.graphics_item = self.floating_line self.floating_model.view.set_lines(self.floating_line.line()) self.floating_model.view.snap_line() self.floating_model = None self.floating_line = None completed = True self.scene.removeItem(test_line_item) # If second socket to stream was not succesfully added if not completed: self.state = ApplicationWindow.idle # Remove initial socket made self.floating_model.cleanup() self.remove_floating_objects() @pyqtSlot() def create_readout(self): self.state = self.placing_readout self.floating_model = Readout(self) self.scene.addItem(self.floating_model.view.graphics_item) width = self.floating_model.view.graphics_item.rect().width() height = self.floating_model.view.graphics_item.rect().height() self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2)) @pyqtSlot() def create_fiber_readout(self): self.state = self.placing_readout self.floating_model = FiberReadout(self) self.scene.addItem(self.floating_model.view.graphics_item) width = self.floating_model.view.graphics_item.rect().width() height = self.floating_model.view.graphics_item.rect().height() self.floating_model.view.graphics_item.setPos(self.offset_point(self.mouse_scene_pos, -width / 2, -height / 2)) def start_readout(self, pos): for colliding_item in self.scene.collidingItems(self.floating_model.view.graphics_item): if self.state is ApplicationWindow.idle: break for view in self.views: if type(view.model) is Stream and isinstance(view, StreamView) and colliding_item in view.line_items: # If stream already has a Readout, cancel creation of new Readout. if not self.floating_model.connect_to_stream(view.model): self.state = ApplicationWindow.idle break else: self.state = self.drawing_readout self.floating_line = self.scene.addLine(QLineF()) self.floating_line.setParentItem(self.floating_model.view.graphics_item) p1 = p2 = pos angle = colliding_item.line().angle() # snap readout line to colliding line item if angle == 0.0 or angle == 180.0: p1.setY(colliding_item.line().y1()) self.floating_model.view.orientation = ReadoutView.Orientation.vertical elif angle == 90.0 or angle == 270.0: p1.setX(colliding_item.line().x1()) self.floating_model.view.orientation = ReadoutView.Orientation.horizontal p1 = self.floating_line.mapFromScene(p1) p2 = self.floating_line.mapFromScene(p2) pen = QPen() pen.setWidth(2) self.floating_line.setLine(QLineF(p1, p2)) self.floating_line.setPen(pen) self.floating_line.setZValue(-1) if self.state is not ApplicationWindow.drawing_readout: self.state = self.idle self.floating_model.cleanup() self.remove_floating_objects() def complete_readout(self, pos): self.state = self.idle rect_graphics_item = self.floating_model.view.graphics_item line_graphics_item = self.floating_line if self.floating_model.view.orientation is ReadoutView.Orientation.horizontal: p1 = QPoint(line_graphics_item.line().x1(), line_graphics_item.line().y1()) p2 = QPoint(line_graphics_item.line().x2(), line_graphics_item.line().y1()) else: p1 = QPoint(line_graphics_item.line().x1(), line_graphics_item.line().y1()) p2 = QPoint(line_graphics_item.line().x1(), line_graphics_item.line().y2()) width = rect_graphics_item.rect().width() height = rect_graphics_item.rect().height() p1 = rect_graphics_item.mapToScene(p1) p2 = rect_graphics_item.mapToScene(p2) rect_graphics_item.setPos(QPoint(p2.x() - width / 2 - 1, p2.y() - height / 2 - 1)) p1 = rect_graphics_item.mapFromScene(p1) p2 = rect_graphics_item.mapFromScene(p2) line_graphics_item.setLine(QLineF(p1, p2)) self.floating_model.view.init_text() self.floating_model = None self.floating_line = None
class Spectrum(QWidget): """Plot the power spectrum for a specified channel. Attributes ---------- parent : instance of QMainWindow the main window. x_limit : tuple or list 2 values specifying the limit on x-axis y_limit : tuple or list 2 values specifying the limit on y-axis log : bool log-transform the data or not idx_chan : instance of QComboBox the element with the list of channel names. idx_x_min : instance of QLineEdit value with min x value idx_x_max : instance of QLineEdit value with max x value idx_y_min : instance of QLineEdit value with min y value idx_y_max : instance of QLineEdit value with max y value idx_log : instance of QCheckBox widget that defines if log should be used or not idx_fig : instance of QGraphicsView the view with the power spectrum scene : instance of QGraphicsScene the scene with GraphicsItems Notes ----- If data contains NaN, it doesn't create any spectrum (feature or bug?). """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigSpectrum(self.display_window) self.selected_chan = None self.idx_chan = None self.idx_fig = None self.scene = None self.create() def create(self): """Create empty scene for power spectrum.""" self.idx_chan = QComboBox() self.idx_chan.activated.connect(self.display_window) self.idx_fig = QGraphicsView(self) self.idx_fig.scale(1, -1) layout = QVBoxLayout() layout.addWidget(self.idx_chan) layout.addWidget(self.idx_fig) self.setLayout(layout) self.resizeEvent(None) def show_channame(self, chan_name): self.selected_chan = self.idx_chan.currentIndex() self.idx_chan.clear() self.idx_chan.addItem(chan_name) self.idx_chan.setCurrentIndex(0) def update(self): """Add channel names to the combobox.""" self.idx_chan.clear() for chan_name in self.parent.traces.chan: self.idx_chan.addItem(chan_name) if self.selected_chan is not None: self.idx_chan.setCurrentIndex(self.selected_chan) self.selected_chan = None def display_window(self): """Read the channel name from QComboBox and plot its spectrum. This function is necessary it reads the data and it sends it to self.display. When the user selects a smaller chunk of data from the visible traces, then we don't need to call this function. """ if self.idx_chan.count() == 0: self.update() chan_name = self.idx_chan.currentText() lg.info('Power spectrum for channel ' + chan_name) if chan_name: trial = 0 data = self.parent.traces.data(trial=trial, chan=chan_name) self.display(data) else: self.scene.clear() def display(self, data): """Make graphicsitem for spectrum figure. Parameters ---------- data : ndarray 1D vector containing the data only This function can be called by self.display_window (which reads the data for the selected channel) or by the mouse-events functions in traces (which read chunks of data from the user-made selection). """ value = self.config.value self.scene = QGraphicsScene(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) self.idx_fig.setScene(self.scene) self.add_grid() self.resizeEvent(None) s_freq = self.parent.traces.data.s_freq f, Pxx = welch(data, fs=s_freq, nperseg=int(min((s_freq, len(data))))) # force int freq_limit = (value['x_min'] <= f) & (f <= value['x_max']) if self.config.value['log']: Pxx_to_plot = log(Pxx[freq_limit]) else: Pxx_to_plot = Pxx[freq_limit] self.scene.addPath(Path(f[freq_limit], Pxx_to_plot), QPen(QColor(LINE_COLOR), LINE_WIDTH)) def add_grid(self): """Add axis and ticks to figure. Notes ----- I know that visvis and pyqtgraphs can do this in much simpler way, but those packages create too large a padding around the figure and this is pretty fast. """ value = self.config.value # X-AXIS # x-bottom self.scene.addLine(value['x_min'], value['y_min'], value['x_min'], value['y_max'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # at y = 0, dashed self.scene.addLine(value['x_min'], 0, value['x_max'], 0, QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine)) # ticks on y-axis y_high = int(floor(value['y_max'])) y_low = int(ceil(value['y_min'])) x_length = (value['x_max'] - value['x_min']) / value['x_tick'] for y in range(y_low, y_high): self.scene.addLine(value['x_min'], y, value['x_min'] + x_length, y, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # Y-AXIS # left axis self.scene.addLine(value['x_min'], value['y_min'], value['x_max'], value['y_min'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # larger ticks on x-axis every 10 Hz x_high = int(floor(value['x_max'])) x_low = int(ceil(value['x_min'])) y_length = (value['y_max'] - value['y_min']) / value['y_tick'] for x in range(x_low, x_high, 10): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # smaller ticks on x-axis every 10 Hz y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2 for x in range(x_low, x_high, 5): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) def resizeEvent(self, event): """Fit the whole scene in view. Parameters ---------- event : instance of Qt.Event not important """ value = self.config.value self.idx_fig.fitInView(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) def reset(self): """Reset widget as new""" self.idx_chan.clear() if self.scene is not None: self.scene.clear() self.scene = None
class ViewWindow(QMainWindow): # QWidget): def __init__(self): super().__init__() self.pilorig = None self.savedImg = None self.controlPanel = None self.dirName, self.fileName = '', '' self.dirFileNames = [] self.fileIdx = -1 self.ctrl = None # transformation control widget self.locator = None # locator rectangle widget self.locator1 = None # locator 1st point self.locator2 = None # locator 2nd point self.scale = (1, 1) self.show_histogram = False # usage of QGraphicsScene and QGraphicsView is taken from # https://stackoverflow.com/questions/50851587/undo-functionality-for-qpainter-drawellipse-function self.gv = None self.scene = None self.scaledPixmap = None self.histogram = [] self.initUI() def initUI(self): self.setWindowTitle("PyQT Tuts!") transforms.editWindow = self bar = self.menuBar() makeMenu(bar, FILE_MENU, self) menu = bar.actions()[2].menu() menu.addSeparator() addAction(menu, self, 'Show &Histogram', self.toggleHistogram, 'Ctrl+H', 'Show/hide histogram') menu = bar.actions()[1].menu() menu.addSeparator() for item in transforms.getTransforms(): addAction(menu, self, item[0], item[2], item[3], item[4]) # item[1] (Icon is ignored, todo: add support) menu = bar.actions()[0].menu() menu.addSeparator() addAction(menu, self, '&Next', self.onNextBtn, 'Ctrl+N', 'Next image') addAction(menu, self, '&Prev', self.onPrevBtn, 'Ctrl+P', 'Prev image') addAction(menu, self, '&Save', self.onSaveImg, 'Ctrl+S', 'Save image') layout1 = QVBoxLayout() self.gv = QGraphicsView() self.scene = QGraphicsScene() self.gv.setScene(self.scene) self.gv.installEventFilter(self) layout1.addWidget(self.gv) panel = QWidget(self) self.controlPanel = QHBoxLayout() panel.setLayout(self.controlPanel) layout1.addWidget(panel) center = QWidget() center.setLayout(layout1) self.setCentralWidget(center) def toggleHistogram(self): self.show_histogram = not self.show_histogram self.make_histogram() def eventFilter(self, obj, event): if obj == self.gv and event.type() == QEvent.MouseButtonPress: p = self.gv.mapToScene(event.pos()) self.setLocation(p) return QWidget.eventFilter(self, obj, event) def setLocation(self, pos): if self.locator2 is not None: self.locator1 = None self.locator2 = None if self.locator1: self.locator2 = (pos.x(), pos.y()) self.drawLocator() else: self.locator1 = (pos.x(), pos.y()) def drawLocator(self): if self.locator: self.scene.removeItem(self.locator) self.locator = None pen = QPen(Qt.red, 3) self.locator = self.scene.addRect(self.locator1[0], self.locator1[1], self.locator2[0] - self.locator1[0], self.locator2[1] - self.locator1[1], pen) print('locator', self.locator1, self.locator2) self.gv.update() # self.label.update() #QApplication.processEvents() def resizeEvent(self, event): QWidget.resizeEvent(self, event) self.sizeImage() def openImage(self, fileName): self.setWindowTitle(fileName) self.dirName = os.path.dirname(fileName) self.fileName = os.path.basename(fileName) self.dirFileNames = list(imgFiles(self.dirName)) self.fileIdx = self.dirFileNames.index(self.fileName) if fileName: self.pilorig = PIL.Image.open(fileName) self.sizeImage() def fullFileName(self): if self.fileName: return os.path.join(self.dirName, self.fileName) else: return None def showImage(self, fileName): self.openImage(fileName) self.show() def updateImage(self, pilImage): self.pilorig = pilImage self.sizeImage() def sizeImage(self): orig = pil2pixmap(self.pilorig) if self.pilorig: if self.scaledPixmap: self.scene.removeItem(self.scaledPixmap) self.scaledPixmap = None if self.locator: self.scene.removeItem(self.locator) self.locator = None pixmap = orig.scaled(self.gv.width(), self.gv.height(), Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation) self.scaledPixmap = self.scene.addPixmap(pixmap) self.scale = (orig.size().width() / pixmap.size().width(), orig.size().height() / pixmap.size().height()) self.make_histogram() def absLocatorRect(self): return [ self.locator1[0] * self.scale[0], self.locator1[1] * self.scale[1], self.locator2[0] * self.scale[0], self.locator2[1] * self.scale[1] ] def nextFileName(self): if self.fileIdx < len(self.dirFileNames) - 1: return os.path.join(self.dirName, self.dirFileNames[self.fileIdx + 1]) else: return None def prevFileName(self): if self.fileIdx > 0: return os.path.join(self.dirName, self.dirFileNames[self.fileIdx - 1]) else: return None def onNextBtn(self): fn = self.nextFileName() if fn: self.openImage(os.path.join(self.dirName, fn)) #@staticmethod def onPrevBtn(self): fn = self.prevFileName() if fn: self.openImage(os.path.join(self.dirName, fn)) def onSaveImg(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getSaveFileName( self, "Save as ...", os.path.join(self.dirName, self.fileName), "All Files (*);;Jpeg Files(*.jpg)", options=options) if fileName: print(fileName) self.pilorig.save(fileName) def make_histogram(self): # should it be a ShowWin class method? #self.canvas.delete('histogram') for it in self.histogram: self.scene.removeItem(it) del self.histogram[:] if not self.show_histogram: return img = self.pilorig if not img: return h = img.convert("L").histogram() maxVal = 1 for i in range(0, len(h)): if h[i] > maxVal: maxVal = h[i] _X = float(img.size[1]) x = 100 if _X > 100 else _X penGray = QPen(Qt.gray, 3) penRed = QPen(Qt.red, 3) for i in range(0, len(h)): if h[i] == maxVal: pen = penRed else: pen = penGray self.histogram.append( self.scene.addLine(i, x, i, x - x * h[i] / maxVal, pen)) self.histogram.append(self.scene.addRect(0, 0, len(h), x, penGray)) self.gv.update() # support transformation plugins def controlImg(self, checkCtrl=True): if checkCtrl and not self.ctrl: return None else: return self.savedImg def setCtrl(self, ctrl): if ctrl and self.ctrl: return # do not allow two control panels if self.ctrl and not ctrl: self.ctrl.setParent(None) self.ctrl = ctrl if ctrl: self.controlPanel.addWidget(ctrl) self.savedImg = self.pilorig def unsetCtrl(self): if self.ctrl: self.ctrl.setParent(None) self.ctrl = None
def paint(self, scene: QtWidgets.QGraphicsScene): for i in range(1, len(self.points)): scene.addLine(QtCore.QLineF(self.points[i - 1], self.points[i]), self.color)
class MyWidget(QtWidgets.QWidget): text_updater = QtCore.pyqtSignal(str) # Signal to update text display # Initialise the GUI def __init__(self, parent=None): super(MyWidget, self).__init__(parent) self.parent = parent self.text = QtWidgets.QTextEdit() self.scene = QGraphicsScene() self.view = MyView(self.scene) self.view.setRenderHint(QPainter.Antialiasing) self.sigpins = {} self.measure_text() self.scene.addRect(0, 0, *FRAME_SIZE, pen=FRAME_PEN, brush=FRAME_BRUSH) self.draw_rect(BOARD_GPOS, BOARD_GSIZE, BOARD_PEN, BOARD_BRUSH) self.draw_pin_labels(BOARD_GPOS, BOARD_GSIZE) self.draw_part_pins(BOARD_GPOS, BOARD_GSIZE, BOARDPINS, PIN_SIZE, True) self.draw_rect(SEGDISP_GPOS, SEGDISP_GSIZE, SEGDISP_PEN, SEGDISP_BRUSH) self.draw_part_pins(SEGDISP_GPOS, SEGDISP_GSIZE, SEG_IDENTS, SMALLPIN_SIZE, True) self.draw_part_segs(SEGDISP_GPOS) self.draw_button() layout = QtWidgets.QVBoxLayout() layout.addWidget(self.view, 30) layout.addWidget(self.text, 10) self.setLayout(layout) self.text_updater.connect(self.update_text) sys.stdout = self # Convert x,y grid position to graphics position def grid_pos(self, gpos): return gpos[0]*GRID_PITCH + GRID_ADJ[0], gpos[1]*GRID_PITCH + GRID_ADJ[1] # Convert w,h grid size to graphics size def grid_size(self, gsize): return gsize[0]*GRID_PITCH, gsize[1]*GRID_PITCH # Add rectangle to grid, given top-left corner def draw_rect(self, gpos, gsize, pen=Qt.gray, brush=Qt.darkGray): x,y = self.grid_pos(gpos) w,h = self.grid_size(gsize) rect = self.scene.addRect(0, 0, w, h, pen, brush) rect.setPos(x-GRID_PITCH/2.0, y-GRID_PITCH/2.0) return rect # Add circle to grid, given centre def draw_circle(self, gpos, size, pen, brush=PIN_ON_BRUSH): size *= GRID_PITCH x,y = self.grid_pos(gpos) p = self.scene.addEllipse(0, 0, size, size, pen, brush) p.setPos(x-size/2.0, y-size/2.0) return p # Measure text for positioning def measure_text(self, txt="ABCD"): fm = QFontMetrics(LABEL_FONT) self.label_wd, self.label_ht = fm.width(txt)*LABEL_SCALE, fm.height()*LABEL_SCALE # Add labels to part def draw_pin_labels(self, gpos, gsize): for n, id in enumerate(BOARDPINS): gx = gpos[0] + n%20 gy = gpos[1] + (0 if n<20 else gsize[1]-3) self.draw_label((gx, gy), id) # Add text label to grid def draw_label(self, gpos, text, font=LABEL_FONT): x,y = self.grid_pos(gpos) size = self.label_wd, self.label_ht txt = self.scene.addText(text, font) txt.setScale(LABEL_SCALE) txt.setTransformOriginPoint(size[0], size[1]/2.0) txt.setRotation(90) txt.setPos(x+LABEL_OSET[0]-size[0]/2.0, y+LABEL_OSET[1]) # Add pins to a part def draw_part_pins(self, gpos, gsize, pins, pinsize=PIN_SIZE, animate=False): for n, name in enumerate(pins): gx = gpos[0] + n%gsize[0] gy = gpos[1] + (0 if n<gsize[0] else gsize[1]-1) p = self.draw_pin((gx, gy), pinsize) if animate: self.add_pin_signal(name, p) # Add signal to animation list def add_pin_signal(self, name, pin): if name not in self.sigpins: self.sigpins[name] = [] self.sigpins[name].append(pin) # Add pin to graphics display def draw_pin(self, gpos, pinsize): p = self.draw_circle(gpos, pinsize, PIN_ON_PEN, PIN_ON_BRUSH) p.setOpacity(PIN_OFF_OPACITY) return p # Add segments to 7-segment display def draw_part_segs(self, gpos): x2 = y2 = None self.segments = [] for line in SEG_LINES: x1, y1 = self.grid_pos((line[0]+gpos[0], line[1]+gpos[1])) if x2 is not None: seg = self.scene.addLine(x1, y1, x2, y2, SEG_PEN) seg.setOpacity(PIN_OFF_OPACITY) self.segments.append(seg) x2, y2 = x1, y1 self.segments.insert(5, self.segments.pop(0)) # Re-order to segment A first dpos = SEG_DP_OSET[0]+gpos[0], SEG_DP_OSET[1]+gpos[1] dp = self.draw_circle(dpos, SEG_DP_SIZE, SEG_DP_PEN) dp.setOpacity(PIN_OFF_OPACITY) self.segments.append(dp) for n, seg in enumerate(self.segments): bitnum = SEG_BITNUM[chr(n + ord('a'))] self.add_pin_signal("%s%u" % (SEGPORT, bitnum), seg) # Draw pushbutton def draw_button(self): self.draw_rect(BUTTON_GPOS, BUTTON_GSIZE, BUTTON_OFF_PEN, BUTTON_OFF_BRUSH) gx, gy = BUTTON_GPOS[0]+BUTTON_GSIZE[0]/4, BUTTON_GPOS[1]+BUTTON_GSIZE[1]/4 p = self.draw_circle((gx, gy), BUTTON_GSIZE[0], BUTTON_OFF_PEN, BUTTON_ON_BRUSH) p.setOpacity(PIN_OFF_OPACITY) self.add_pin_signal(BUTTON_PIN, p) return p # Set port pins on/off states # Space-delimited 'name=value' with 16 bit hex value, e.g. 'PA=12C PB=D3E4' def set_ports(self, s): data = str(s).split(' ') for d in data: name,eq,num = d.partition('=') if eq and num is not None: val = int(num, 16) print("Port %s = %X" % (name, val)) for i in range(0, 16): self.set_pin("%s%u=%X" % (name, i, (val>>i)&1)) # Set pin (or segment) on/off state # Format is 'name=value', e.g. 'PA10=1' def set_pin(self, s): name, eq, num = s.partition('=') if eq and name in self.sigpins: val = int(num, 16) for p in self.sigpins[name]: if int(p.opacity()) != val: p.setOpacity(PIN_ON_OPACITY if val else PIN_OFF_OPACITY) # Handler to update graphics display def update_graph(self, s): self.set_ports(s) # Handler to update text display def update_text(self, text): disp = self.text.textCursor() # Move cursor to end disp.movePosition(QTextCursor.End) text = str(text).replace("\r", "") # Eliminate CR while text: head,sep,text = text.partition("\n")# New line on LF disp.insertText(head) if sep: disp.insertBlock() self.text.ensureCursorVisible() # Scroll if necessary # Handle sys.stdout.write: update text display def write(self, text): self.text_updater.emit(str(text)) def flush(self): pass
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 AMANDisplay(QGraphicsView): def __init__(self): super(AMANDisplay, self).__init__() self.setGeometry(0, 0, 500, 600) self.setStyleSheet('background-color:#233370') self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, 500, 600) # Timeline boundaries pen = QPen(QColor('white')) brush = QBrush(QColor('#233370')) self.scene.addLine(220, 0, 220, 600, pen) self.scene.addLine(280, 0, 280, 600, pen) self.scene.addLine(0, 30, 500, 30, pen) timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush) timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True) # Timeline scale self.timeline = QGraphicsItemGroup() self.timeline.setParentItem(timelinebox) self.timeticks = [] for i in range(40): y = 15 * i w = 6 if i % 5 == 0: w = 10 self.timeticks.append( self.scene.addText('%02d' % (40 - i), QFont('Courier', 10))) self.timeticks[-1].setPos(240, y - 10) self.timeticks[-1].setDefaultTextColor(QColor('white')) self.timeline.addToGroup(self.timeticks[-1]) self.timeline.addToGroup( self.scene.addLine(220, y, 220 + w, y, pen)) self.timeline.addToGroup( self.scene.addLine(280 - w, y, 280, y, pen)) self.lrwy = self.scene.addText('18R', QFont('Arial', 20, 50)) self.lrwy.setPos(1, 1) self.lrwy.setDefaultTextColor(QColor('white')) # Finalize self.setScene(self.scene) self.show() def update(self, simt, data): # data has: ids, iafs, eats, etas, delays, rwys, spdratios # First delete old labels for key, in self.aircraft.keys: if key not in data.ids: # del label del self.aircraft[key] for i in len(data.ids): if data.ids[i] not in self.aircraft: # self.aircraft[data.ids[i]] = QLabel() pass # Generate the new label text and position newtext = '<font color=Red>bla</font>' # veranderen lbl = self.aircraft[data.ids[i]] lbl.setText(newtext) lbl.move(posx, posy) # move in pixels
class MainWindow(QMainWindow): """Main window class of our UI""" def __init__(self, g): """Constructor""" super(MainWindow, self).__init__() self.g = g # Load user interface from UI-file uic.loadUi('exed1.ui', self) self.init_scene() def calc_bounding_box(self): """Calc geometry bounding box""" self.max_x = -1e300 self.max_y = -1e300 self.min_x = 1e300 self.min_y = 1e300 for p in self.g.points.values(): if p[0][0] > self.max_x: self.max_x = p[0][0] if p[0][0] < self.min_x: self.min_x = p[0][0] if p[0][1] > self.max_y: self.max_y = p[0][1] if p[0][1] < self.min_y: self.min_y = p[0][1] self.bw = self.max_x - self.min_x self.bh = self.max_y - self.min_y self.hs = (self.bw + self.bh) * 0.5 * 0.075 def init_scene(self): """Setup scene""" self.scene = QGraphicsScene() self.green_brush = QBrush(Qt.green) self.gray_brush = QBrush(Qt.gray) self.white_brush = QBrush(Qt.white) self.pen = QPen(Qt.gray) self.pen.setWidth(4) self.pen.setCosmetic(True) self.line_pen = QPen(Qt.red) self.line_pen.setWidth(4) self.line_pen.setCosmetic(True) self.calc_bounding_box() for c in self.g.curves.values(): if c[0] == 'Spline': i0 = c[1][0] i1 = c[1][1] p0 = self.g.points[i0][0] p1 = self.g.points[i1][0] gi = self.scene.addLine(p0[0], p0[1], p1[0], p1[1], self.pen) for p in self.g.points.values(): gi = QGraphicsEllipseItem(-self.hs / 2, -self.hs / 2, self.hs, self.hs) gi.setBrush(self.white_brush) gi.setPen(self.pen) gi.setPos(p[0][0], p[0][1]) gi.setFlag(QGraphicsItem.ItemIsMovable) gi.setFlag(QGraphicsItem.ItemIsSelectable) self.scene.addItem(gi) #gi = self.scene.addEllipse(-self.hs/2, -self.hs/2, self.hs, self.hs, self.pen, self.white_brush) print(self.scene.sceneRect()) #self.scene.setSceneRect(self.min_x, self.min_y, self.max_x-self.min_x, self.max_y-self.min_y) self.graphics_view.setScene(self.scene) #self.graphics_view.fitInView(self.min_x, self.min_y, self.max_x-self.min_x, self.max_y-self.min_y) self.graphics_view.scale(200.0, 200.0) #ellipse = self.scene.addEllipse(20,20, 200,200, self.pen, self.greenBrush) #rect = self.scene.addRect(self.min_x, self.min_y, self.max_x-self.min_x, self.max_y-self.min_y, self.pen) #ellipse.setFlag(QGraphicsItem.ItemIsMovable) #rect.setFlag(QGraphicsItem.ItemIsMovable) #ellipse.setFlag(QGraphicsItem.ItemIsSelectable) self.scene.focusItemChanged.connect(self.on_focus_item_changed) self.scene.selectionChanged.connect(self.on_selection_changed) def on_focus_item_changed(self, new_focus_item, old_focus_item, reason): print("on_focus_item_changed", new_focus_item, reason) def on_selection_changed(self): if len(self.scene.selectedItems()) > 0: print("on_selection_changed", self.scene.selectedItems()[0].pos()) def on_item_mouse_move(self): print("on_item_mouse_move")
class BoardGUI(QWidget): """cointain the graphical representation of the Board""" # ratio of bordersize compared to the size of one base square borderRatio = 0.8 baseRectRatio = 14/15 # 12/13 for normal ratio but looks weird stoneScale = 0.46 # siganl stoneClicked = pyqtSignal(tuple) def __init__(self, parent, game): super().__init__() self.initUI(game) def initUI(self, game): self.board = game.currentBoard self.game = game self.showCoords = True self.scene = QGraphicsScene() # grid containing coordinates for the scene self.grid = [] self.drawGrid() # initialize and set layout + view self.view = QGraphicsView(self.scene) self.view.setMouseTracking(True) self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setMouseTracking(True) box = QHBoxLayout() box.addWidget(self.view) self.setLayout(box) # stones for all positions are created and listed in self.pos dict self.createPosition() self.makeCoords() # has to be called after drawGrid! def resizeEvent(self, e): self.view.fitInView(self.view.scene().sceneRect(), Qt.KeepAspectRatio) def boardWidth(self): """returns the max width fitting into widget""" width = self.contentsRect().width()*0.95 height = self.contentsRect().height()*0.95 return min(width, height*self.baseRectRatio) def boardHeight(self): """returns the max width fitting into widget """ return self.boardWidth()*(1/self.baseRectRatio) def makeGrid(self): """ returns coords [[(x, y)]] for the Grid according to current window mesures """ # set scenesize to window size self.scene.setSceneRect(0, 0, self.boardWidth(), self.boardHeight()) denom = self.board.size + 2*self.borderRatio baseWidth = self.boardWidth() / denom baseHeight = self.boardHeight() / denom leftOffset = 0.5*baseWidth # (self.contentsRect().width()-self.boardWidth())/2 topOffset = 0 # (self.contentsRect().height()-self.boardHeight())/2 partionWidth = [leftOffset+(self.borderRatio+x)*baseWidth for x in range(self.board.size)] partionHeight = [topOffset+(self.borderRatio+x)*baseHeight for x in range(self.board.size)] grid = [[(x, y) for x in partionWidth] for y in partionHeight] self.grid = grid self.baseWidth = baseWidth def drawGrid(self): """draws the background grid""" self.makeGrid() for line in self.grid: self.scene.addLine(*line[0], *line[-1]) for (pointT, pointB) in zip(self.grid[0], self.grid[-1]): self.scene.addLine(*pointT, *pointB) self.drawHoshis() def makeCoords(self): """ draws Coordinates """ xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ" yLabels = list(range(1, 26)) botGrid = [] leftGrid = [] # generate pixel coordinates grids for n in range(self.board.size): (xBot, yBot) = self.grid[self.board.size-1][n] yBot += self.baseWidth*0.4/self.baseRectRatio xBot -= self.baseWidth*0.1 botGrid.append((xBot, yBot)) (xLeft, yLeft) = self.grid[n][0] xLeft -= self.baseWidth*1.2 yLeft -= self.baseWidth*0.3/self.baseRectRatio leftGrid.append((xLeft, yLeft)) # generate Text items and add them to group self.coordGroup = QGraphicsItemGroup() for n in range(self.board.size): leftText = QGraphicsSimpleTextItem(str(yLabels[n])) leftText.setPos(*leftGrid[n]) self.coordGroup.addToGroup(leftText) bottomText = QGraphicsSimpleTextItem(xLabels[n]) bottomText.setPos(*botGrid[n]) self.coordGroup.addToGroup(bottomText) # draw coordinates and update visibility according to self.showCoords self.scene.addItem(self.coordGroup) self.updateCoords() def updateCoords(self): """ slot that updates the visibility os the coordiantes. """ self.coordGroup.setVisible(self.showCoords) def setCoordVis(self, visibility): """ set the self.showCoords boolean """ self.showCoords = visibility self.updateCoords() def drawHoshis(self): """ Draws Hoshi dots""" hoshis = [] rad = self.baseWidth*0.15 for (x, y) in self.board.getHoshis(): hoshis.append(self.grid[x][y]) for point in hoshis: (x, y) = point self.scene.addEllipse(x-rad, y-rad, rad*2.0, rad*2.0, QPen(), QBrush(Qt.SolidPattern)) def updatePosition(self): """ sets the colors for all stones in self.pos according to the status in self.board """ for (x, y) in self.pos: color = self.game.currentBoard.getPosition(x, y) self.pos[(x, y)].setMark(None) self.pos[(x, y)].setColor(color) lastMove = self.game.currentBoard.lastMove if lastMove: self.pos[lastMove].setMark(GoMarks.circel) ko = self.game.currentBoard.ko if ko: self.pos[ko].setMark(GoMarks.square) def createPosition(self): """ Creates the self.pos dictionary containing all possible stones on the board initialized as empty stones also connects a signal form each stone to ??? """ self.pos = {} radius = self.stoneScale*self.baseWidth for row in range(self.board.size): for col in range(self.board.size): (x, y) = self.grid[row][col] newStone = Stone(x, y, radius) self.pos[(row, col)] = newStone self.scene.addItem(newStone) self.updatePosition() self.connecting() def connecting(self): for key in self.pos: self.pos[key].clicked.connect(lambda key=key: self.resend(key)) def resend(self, pos): """ emits the captured signal again, with (int, in) parameter for stone clicked """ self.stoneClicked.emit(pos)
class Editor(QWidget): def __init__(self, song): super().__init__() self.initUI(song) def initUI(self, song): self.songLenInBeats = 100 self.songBeatsPBar = 4 self.reverse = 1 self.pixPSec = 1000.0 self.disp8 = True self.disp12 = False self.disp16 = True self.disp24 = False self.disp32 = False self.disp48 = False self.disp64 = False self.spectrogramDisplay = True self.cursorExists = False self.framecount = 0 self.timeOutLength = 17 self.timer = QTimer() self.editorTheme = self.getTheme() self.boxw = self.editorTheme['BoxWidth'] self.topLayout = QVBoxLayout() self.topLayout.setContentsMargins(0, 0, 0, 0) self.song = song self.song.pos = 0 self.setLayout(self.topLayout) self.gs = QGraphicsScene() self.gv = QGraphicsView(self.gs) self.drawBG() self.song = song # self.drawArrowDemo() self.boxes = [] self.topLayout.addWidget(self.gv) def update(self, song, level): self.gs.clear() print(self.song.pos) self.song = song self.cursorExists = False self.song.pos = 0 self.play(0) self.pause() self.updatescreen() if self.spectrogramDisplay: self.spectrogramPixMap = QPixmap(spectrogram_dir + song.audioFile + '.png') width = self.spectrogramPixMap.width() height = self.spectrogramPixMap.height() self.spectrogramPixMap = self.gs.addPixmap(self.spectrogramPixMap) self.spectrogramPixMap.setRotation(90) self.spectrogramPixMap.setTransform(QTransform().scale( -1, (self.song.lengthInSeconds * self.pixPSec) / width)) self.drawGrid(self.song.levels[level]) self.drawArrowDemo(self.song.levels[level]) #self.play(0) def levelSelected(self, level): print("Selected ", level) if level in self.song.levels: print('switching') self.update(self.song, level) else: print('creating new level') def play(self, pos): self.timer.timeout.connect(self.updatescreen) self.timer.start(self.timeOutLength) self.song.playSong(pos) def pause(self): self.timer.stop() self.song.pauseSong() def keyPressEvent(self, event): key = event.key() shiftPressed = event.modifiers() == Qt.ShiftModifier ctrlPressed = event.modifiers() == Qt.ControlModifier altPressed = event.modifiers() == Qt.AltModifier restart = self.song.isPlaying if key == Qt.Key_Space: if self.song.isPlaying: self.pause() else: self.play(self.song.pos / 1000) elif key == Qt.Key_BracketRight: restart = self.song.isPlaying self.pause() if ctrlPressed: self.song.pos += 10000 elif shiftPressed: self.song.pos += 1000 elif altPressed: self.song.pos += 10 else: self.song.pos += 100 if not (self.song.pos > self.song.lengthInSeconds * 1000): if restart: self.play(self.song.pos / 1000) else: self.play(self.song.pos / 1000) self.pause() else: self.song.pos = self.song.lengthInSeconds * 1000 - 1 self.play(self.song.pos / 1000) self.pause() self.updatescreen() elif key == Qt.Key_BracketLeft: self.pause() if ctrlPressed: self.song.pos -= 10000 elif shiftPressed: self.song.pos -= 1000 elif altPressed: self.song.pos -= 10 else: self.song.pos -= 100 if self.song.pos < 0: self.song.pos = 0 if restart: self.play(self.song.pos / 1000) else: self.play(self.song.pos / 1000) self.pause() self.updatescreen() elif key == Qt.Key_BraceRight: restart = self.song.isPlaying self.pause() if ctrlPressed: self.song.pos += 10000 elif shiftPressed: self.song.pos += 1000 elif altPressed: self.song.pos += 10 else: self.song.pos += 200 if not (self.song.pos > self.song.lengthInSeconds * 1000): if restart: self.play(self.song.pos / 1000) else: self.play(self.song.pos / 1000) self.pause() else: self.song.pos = self.song.lengthInSeconds * 1000 - 1 self.play(self.song.pos / 1000) self.pause() self.updatescreen() elif key == Qt.Key_BraceLeft: self.pause() if ctrlPressed: self.song.pos -= 10000 elif shiftPressed: self.song.pos -= 1000 elif altPressed: self.song.pos += 10 else: self.song.pos -= 200 if self.song.pos < 0: self.song.pos = 0 if restart: self.play(self.song.pos / 1000) else: self.play(self.song.pos / 1000) self.pause() self.updatescreen() def updatescreen(self): self.song.updatePos() if self.song.isPlaying: self.framecount += 1 curTime = time.time() if (curTime - self.song.time > 1): print('FPS: ', self.framecount) self.framecount = 0 self.song.time = curTime if self.cursorExists: self.gs.removeItem(self.cursorLine) ypos = (self.song.pos / 1000.0 * self.pixPSec) self.gv.centerOn(0, ypos) self.cursorLine = self.gs.addLine(0, ypos, 1000, ypos, self.editorTheme['GridMeasure']) self.cursorExists = True self.cursor = True if self.song.pos < 0: self.song.pos = 0 self.gv.centerOn(0, 0) self.pause() def drawArrowDemo(self, level): boxRotation = [180, 0, 90, 270, 225, 135, 315, 45, 0] for beatBox in level.notes: if beatBox.type == 0: if beatBox.cutDirection == 8: notePixmap = QPixmap(graphics_dir + 'redcircle.png') else: notePixmap = QPixmap(graphics_dir + 'redarrow.png') elif beatBox.type == 1: if beatBox.cutDirection == 8: notePixmap = QPixmap(graphics_dir + 'bluecircle.png') else: notePixmap = QPixmap(graphics_dir + 'bluearrow.png') else: notePixmap = QPixmap(graphics_dir + 'mine.png') notePixmap = notePixmap.scaled(40, 40) noteBox = NoteBox() noteBox.setPixmap(notePixmap) noteBox.setBox(beatBox) box = self.gs.addItem(noteBox) print(type(noteBox)) noteBox.setTransformOriginPoint(20, 20) noteBox.setRotation(boxRotation[beatBox.cutDirection]) boxy = (level.beatToSec(beatBox.time) * self.pixPSec - (self.reverse * 20)) * self.reverse boxx = 40 * beatBox.lineIndex + 170 * beatBox.lineLayer noteBox.setPos(boxx, boxy) self.boxes.append(noteBox) def drawBG(self): self.gs.setBackgroundBrush(self.editorTheme['BG']) def drawGrid(self, level): #DEBUG need to through a clear grid in here self.drawGridConstantTime(level) def drawGridConstantBeat(self): pass def drawGridConstantTime(self, level): # DONT FORGET TO ADD REVERSE SCROLL # self.disp192 = True self.noteLayer1 = self.gs.createItemGroup([]) self.noteLayer2 = self.gs.createItemGroup([]) self.noteLayer3 = self.gs.createItemGroup([]) self.obstacleLayer = self.gs.createItemGroup([]) self.eventLayer = self.gs.createItemGroup([]) width = self.editorTheme['BoxWidth'] * 4 spacing = self.editorTheme['LaneSpacing'] self.noteLayer1Values = LayerValue(0, 0, width) self.noteLayer2Values = LayerValue((width + spacing), 0, width) self.noteLayer3Values = LayerValue((width + spacing) * 2, 0, width) self.obstacleLayerValues = LayerValue((width + spacing) * 3, 0, width) self.eventLayerValues = LayerValue((width + spacing) * 4, 0, width) self.drawGridLaneConstantTime(self.noteLayer1, self.noteLayer1Values, level) self.drawGridLaneConstantTime(self.noteLayer2, self.noteLayer2Values, level) self.drawGridLaneConstantTime(self.noteLayer3, self.noteLayer3Values, level) self.drawGridLaneConstantTime(self.obstacleLayer, self.obstacleLayerValues, level) self.drawGridLaneConstantTime(self.eventLayer, self.eventLayerValues, level) def drawGridLaneConstantTime(self, lane, values, level): #debug songlen not a int need to address leftover time for beat in range(int(self.song.lengthInBeats)): if beat % self.song.beatsPerBar == 0: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat)) * self.pixPSec, self.editorTheme['GridMeasure'])) else: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat)) * self.pixPSec, self.editorTheme['Grid4'])) if self.disp8: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .5)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .5)) * self.pixPSec, self.editorTheme['Grid8'])) if self.disp16: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .25)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .25)) * self.pixPSec, self.editorTheme['Grid16'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .75)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .75)) * self.pixPSec, self.editorTheme['Grid16'])) if self.disp32: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .125)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .125)) * self.pixPSec, self.editorTheme['Grid32'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .375)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .375)) * self.pixPSec, self.editorTheme['Grid32'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .625)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .625)) * self.pixPSec, self.editorTheme['Grid32'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .875)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .875)) * self.pixPSec, self.editorTheme['Grid32'])) if self.disp64: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .0625)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .0625)) * self.pixPSec, self.editorTheme['Grid64'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .1875)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .1875)) * self.pixPSec, self.editorTheme['Grid64'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .3125)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .3125)) * self.pixPSec, self.editorTheme['Grid64'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .4375)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .4375)) * self.pixPSec, self.editorTheme['Grid64'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .5625)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .5625)) * self.pixPSec, self.editorTheme['Grid64'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .6875)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .6875)) * self.pixPSec, self.editorTheme['Grid64'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .8125)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .8125)) * self.pixPSec, self.editorTheme['Grid64'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .9375)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .9375)) * self.pixPSec, self.editorTheme['Grid64'])) if self.disp12: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 1 / 3)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 1 / 3)) * self.pixPSec, self.editorTheme['Grid12'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 2 / 3)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 2 / 3)) * self.pixPSec, self.editorTheme['Grid12'])) if self.disp24: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 1 / 6)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 1 / 6)) * self.pixPSec, self.editorTheme['Grid24'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .5)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .5)) * self.pixPSec, self.editorTheme['Grid24'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 5 / 6)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 5 / 6)) * self.pixPSec, self.editorTheme['Grid24'])) if self.disp48: lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 1 / 12)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 1 / 12)) * self.pixPSec, self.editorTheme['Grid48'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .25)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .25)) * self.pixPSec, self.editorTheme['Grid48'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 5 / 12)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 5 / 12)) * self.pixPSec, self.editorTheme['Grid48'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 7 / 12)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 7 / 12)) * self.pixPSec, self.editorTheme['Grid48'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + .75)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + .75)) * self.pixPSec, self.editorTheme['Grid48'])) lane.addToGroup( self.gs.addLine( values.x + self.editorTheme['GridLineWidth'], self.reverse * (self.song.offset + level.beatToSec(beat + 11 / 12)) * self.pixPSec, values.x + values.w - self.editorTheme['GridLineWidth'] * 2, self.reverse * (self.song.offset + level.beatToSec(beat + 11 / 12)) * self.pixPSec, self.editorTheme['Grid48'])) lane.addToGroup( self.gs.addLine( values.x, values.y, values.x, self.reverse * (self.song.offset + level.beatToSec(self.song.lengthInBeats)) * self.pixPSec, self.editorTheme['GridLayer1Vert'])) lane.addToGroup( self.gs.addLine( values.x + values.w * .25, values.y, values.x + values.w * .25, self.reverse * (self.song.offset + level.beatToSec(self.song.lengthInBeats)) * self.pixPSec, self.editorTheme['GridLayer1Vert'])) lane.addToGroup( self.gs.addLine( values.x + values.w * .5, values.y, values.x + values.w * .5, self.reverse * (self.song.offset + level.beatToSec(self.song.lengthInBeats)) * self.pixPSec, self.editorTheme['GridLayer1Vert'])) lane.addToGroup( self.gs.addLine( values.x + values.w * .75, values.y, values.x + values.w * .75, self.reverse * (self.song.offset + level.beatToSec(self.song.lengthInBeats)) * self.pixPSec, self.editorTheme['GridLayer1Vert'])) lane.addToGroup( self.gs.addLine( values.x + values.w, values.y, values.x + values.w, self.reverse * (self.song.offset + level.beatToSec(self.song.lengthInBeats)) * self.pixPSec, self.editorTheme['GridLayer1Vert'])) def getTheme(self): return { 'BoxWidth': 60, 'LaneSpacing': 20, 'BG': QBrush(QColor(0, 0, 0), Qt.SolidPattern), 'GridLayer1Vert': QPen(QBrush(QColor(255, 255, 255)), 1, Qt.SolidLine), 'GridLayer1BG': QBrush(Qt.black, Qt.SolidPattern), 'GridLayer2Vert': QPen(Qt.white, Qt.SolidLine), 'GridLayer2BG': QBrush(Qt.black, Qt.SolidPattern), 'GridLayer3Vert': QPen(Qt.white, Qt.SolidLine), 'GridLayer3BG': QBrush(Qt.black, Qt.SolidPattern), 'GridObs': QPen(Qt.blue, Qt.SolidLine), 'GridObsBG': QBrush(Qt.black, Qt.SolidPattern), 'GridEventVert': QPen(Qt.red, Qt.SolidLine), 'GridEventBG': QBrush(Qt.black, Qt.SolidPattern), 'GridMeasure': QPen(QBrush(QColor(255, 0, 0)), 2, Qt.SolidLine), 'Grid4': QPen(QBrush(QColor(255, 255, 255)), 2, Qt.DashLine), 'Grid8': QPen(QBrush(QColor(0, 150, 255)), 2, Qt.DotLine), 'Grid12': QPen(QBrush(QColor(100, 255, 50)), 2, Qt.DotLine), 'Grid16': QPen(QBrush(QColor(255, 255, 50)), 2, Qt.DotLine), 'Grid24': QPen(QBrush(QColor(150, 100, 255)), 2, Qt.DotLine), 'Grid32': QPen(QBrush(QColor(0, 255, 150)), 2, Qt.DotLine), 'Grid48': QPen(QBrush(QColor(255, 100, 150)), 2, Qt.DotLine), 'Grid64': QPen(QBrush(QColor(150, 200, 100)), 2, Qt.DotLine), # 'Grid192': QPen(Qt.red,Qt.SolidLine), 'GridLineWidth': 1 }