def testQGraphicsProxyWidget(self): scene = QGraphicsScene() proxy = QGraphicsProxyWidget(None, Qt.Window) widget = QLabel('Widget') proxy.setWidget(widget) proxy.setCacheMode(QGraphicsItem.DeviceCoordinateCache) scene.addItem(proxy) scene.setSceneRect(scene.itemsBoundingRect()) view = QGraphicsView(scene) view.setRenderHints(QPainter.Antialiasing|QPainter.SmoothPixmapTransform) view.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) view.show() timer = QTimer.singleShot(100, self.app.quit) self.app.exec_()
class MainWindowClass(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.ui = Ui_MainWindowContainer() self.ui.setupUi(self) self.WindowWidth = 1000 self.WindowHeight = 1000 self.GraphicsSceneCont = QGraphicsScene() self.GraphicsSceneCont.setSceneRect(0, 0, self.WindowWidth, self.WindowHeight) self.ui.graphicsView.setScene(self.GraphicsSceneCont) def SetModuleWidget(self, x, y, WindowModule): Widget = QGraphicsProxyWidget() Widget.setWidget(WindowModule) Widget.setWindowFlags(Qt.Window) Widget.setPos(x, y) Widget.setFlag(PySide2.QtWidgets.QGraphicsItem.ItemIsMovable, True) Widget.setFlag(PySide2.QtWidgets.QGraphicsItem.ItemIsSelectable, True) self.GraphicsSceneCont.addItem(Widget) def SetWindowItem(self, x, y, WindowModule): WindowModule.setPos(x, y) WindowModule.resize(250, 250) #WindowModule.setWindowFlags(Qt.Window) WindowModule.setFlag(PySide2.QtWidgets.QGraphicsItem.ItemIsMovable, True) WindowModule.setFlag(PySide2.QtWidgets.QGraphicsItem.ItemIsSelectable, True) self.GraphicsSceneCont.addItem(WindowModule)
def __init__(self, player_1: Player, player_2: Player, size: int = 600): super().__init__() self.setWindowTitle("Ultimate Tic-Tac-Toe") self.player_1 = player_1 self.player_2 = player_2 self.game = UltimateTicTacToe() self.size = size # size of window self.maxi_size = size self.mini_size = int(self.size / 3 * 0.8) self.click_needed = False self.clear = True scene = QGraphicsScene() self.board = TicTacToeBoard(state=self.game.get_maxiboard(), point=(self.size // 2, self.size // 2), size=self.maxi_size, board_thickness=6, token_thickness=4) scene.addItem(self.board) self.mini_centers = self._find_miniboard_centers() self.miniboards = [ TicTacToeBoard(state=self.game.get_miniboard(i), point=self.mini_centers[i], size=self.mini_size, board_thickness=3, token_thickness=8) for i in range(9) ] for miniboard in self.miniboards: scene.addItem(miniboard) miniboard.setPos(miniboard.get_point()[0], miniboard.get_point()[1]) scene.setSceneRect(0, 0, self.size, self.size) self.setScene(scene)
def _set_portrait_from_current_index(self): portrait_name, texture = self._portraits[self._current_index] self.portrait_name_label.setText(portrait_name) self.current_image_label.setText( "%d / %d" % (self._current_index + 1, len(self._portraits))) scene = QGraphicsScene() scene.addPixmap(QPixmap.fromImage(texture.image())) scene.setSceneRect(0.0, 0.0, 128.0, 128.0) self.display.setScene(scene) self.display.setSceneRect(0.0, 0.0, float(texture.width()), float(texture.height()))
class GameWidget(QGraphicsView): def __init__(self, parent=None): super(GameWidget, self).__init__(parent) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.m = 150 self.n = 150 self.scene = QGraphicsScene(self) self.setScene(self.scene) self.scene.setSceneRect(0, 0, self.width(), self.height()) self.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.universe = engine.Universe(self.n, self.m) print(Qt.red) self.timer = QTimer(self) self.timer.timeout.connect(self.step) def load(self, item): self.universe.file_input(item) def drawUniverse(self): width = self.width() height = self.height() cellWidth = width / self.universe.n cellHeight = height / self.universe.m x = 0 y = 0 for this_list in self.universe.map: y = 0 for elem in this_list: color = Qt.gray if elem == 1: color = Qt.green self.scene.addRect(x, y, cellWidth, cellHeight, brush=color) y += cellHeight x += cellWidth def step(self): self.scene.clear() self.universe.step() self.drawUniverse() self.scene.update() def run(self): self.timer.start() def stop(self): self.timer.stop()
class GameWindow(QGraphicsView): def __init__(self, parent=None): super(GameWindow, self).__init__(parent=parent) self.screen = None self.scene = QGraphicsScene() self.scene.setSceneRect( QRect(left=0, top=0, width=PLAYGROUND_SIZEX * SCALE_FACTORX, height=PLAYGROUND_SIZEY * SCALE_FACTORY)) self.setFrameStyle(4) self.setScene(self.scene) self.snake = [] # define SnakeHead self.snake.append(QGraphicsRectItem()) self.snake[0].setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY)) self.snake[0].setBrush(brushHead) self.scene.addItem(self.snake[0]) # define rest of the snake for i in range(1, MAX_LENGTH_SNAKE): self.snake.append(QGraphicsRectItem()) self.snake[i].setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY)) self.snake[i].setBrush(brushBody) self.snake[i].setVisible(False) self.scene.addItem(self.snake[i]) # Create the graphic item for apple self.goal = QGraphicsRectItem() self.goal.setRect(QRect(0, 0, SCALE_FACTORX, SCALE_FACTORY)) self.goal.setBrush(brushGoal) self.scene.addItem(self.goal) self.show() def draw(self, state): self.goal.setPos(state.goal.x * SCALE_FACTORX, state.goal.y * SCALE_FACTORY) self.goal.setVisible(True) self.snake[0].setPos(float(state.snake[0].x * SCALE_FACTORX), float(state.snake[0].y * SCALE_FACTORY)) for i in range(1, state.snake_length): self.snake[i].setPos(state.snake[i].x * SCALE_FACTORX, state.snake[i].y * SCALE_FACTORY) self.snake[i].setVisible(True) for i in range(state.snake_length, MAX_LENGTH_SNAKE): self.snake[i].setVisible(False) def screenshot(self): self.screen = self.grab() self.screen.save("./snake_screen.png")
def __init__(self, params): MWB.__init__(self, params) QGraphicsView.__init__(self) self.setFixedWidth(300); self.setFixedHeight(300); scene = QGraphicsScene(self) scene.setSceneRect(0,0, self.width()-5, self.height()-5) self.setScene(scene) self.setCacheMode(QGraphicsView.CacheBackground) self.setRenderHint(QPainter.Antialiasing) self.setStyleSheet(''' border: none; ''')
class MainWindow(QMainWindow): def __init__(self): # super(MainWindow, self).__init__() super().__init__() # self.ui = QMainWindow() self.label = QLabel(f'<h1>Hello World</h1>') self.setGeometry(10, 70, 1000, 700) self.view = QGraphicsView() self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 800, 520) self.view.setScene(self.scene) # greenBrush = QBrush(Qt.green) # blueBrush = QBrush(Qt.blue) # outlinePen = QPen(Qt.black) # outlinePen.setWidth(2) # self.rectangle = self.scene.addRect(100, 0, 80, 100, outlinePen, blueBrush) # self.ellipse = self.scene.addEllipse(0, -100, 300, 60, outlinePen, greenBrush) # self.text = self.scene.addText('Hello World') # item = SlotItem(1); # self.scene.addItem(item) self.bracket1 = BracketItem(1) self.bracket1.setPos(10, 10) self.bracket2 = BracketItem(2) self.bracket2.setPos(10, 300) self.bracket3 = BracketItem(3) self.bracket3.setPos(450, 10) self.bracket4 = BracketItem(4) self.bracket4.setPos(450, 300) self.scene.addItem(self.bracket1) self.scene.addItem(self.bracket2) self.scene.addItem(self.bracket3) self.scene.addItem(self.bracket4) # self.bracket1.drawNodes() self.setCentralWidget(self.view)
class AbstractGraphicViewer(QGraphicsView, TcWidget): def __init__(self, parent=None): super(AbstractGraphicViewer, self).__init__(parent) self.m_scaleX = 0 self.m_scaleY = 0 self._pan = False self._panStartX = 0 self._panStartY = 0 self.scene = QGraphicsScene() self.scene.setItemIndexMethod(QGraphicsScene.NoIndex) self.scene.setSceneRect(-2000, -2000, 4000, 4000) self.setScene(self.scene) self.setCacheMode(QGraphicsView.CacheBackground) self.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) self.setRenderHint(QPainter.Antialiasing) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setMinimumSize(400, 400) self.adjustSize() self.setMouseTracking(True) self.viewport().setMouseTracking(True) def wheelEvent(self, event): if event.angleDelta().y() > 0: factor = 1.1 else: factor = 0.9 view_pos = event.pos() scene_pos = self.mapToScene(view_pos) self.centerOn(scene_pos) self.scale(factor, factor) delta = self.mapToScene(view_pos) - self.mapToScene(self.viewport().rect().center()) self.centerOn(scene_pos - delta) def resizeEvent(self, event): super(AbstractGraphicViewer, self).resizeEvent(event) def mouseMoveEvent(self, event): if self._pan: self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - (event.x() - self._panStartX)) self.verticalScrollBar().setValue(self.verticalScrollBar().value() - (event.y() - self._panStartY)) self._panStartX = event.x() self._panStartY = event.y() event.accept() super(AbstractGraphicViewer, self).mouseMoveEvent(event) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self._pan = True self._panStartX = event.x() self._panStartY = event.y() self.setCursor(QCursor.ClosedHandCursor) event.accept() return super(AbstractGraphicViewer, self).mousePressEvent(event) def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self._pan = False self.setCursor(QCursor.ArrowCursor) event.accept() super(AbstractGraphicViewer, self).mouseReleaseEvent(event) def showEvent(self, event): super(AbstractGraphicViewer, self).showEvent(event) adjusted = self.scene.itemsBoundingRect().adjusted(-100, -100, 100, 100) self.scene.setSceneRect(adjusted) # FitInView is called two times because of this bug: https://bugreports.qt.io/browse/QTBUG-1047 update_state = self.updatesEnabled() self.setUpdatesEnabled(False) self.fitInView(adjusted, Qt.KeepAspectRatio) QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) self.fitInView(adjusted, Qt.KeepAspectRatio) self.setUpdatesEnabled(update_state)
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) view = QGraphicsView() self.scene = QGraphicsScene() self.scene.setSceneRect(QRectF(0, 0, *WINDOW_SIZE)) felt = QBrush(QPixmap(os.path.join('images', 'felt.png'))) self.scene.setBackgroundBrush(felt) name = QGraphicsPixmapItem() name.setPixmap(QPixmap(os.path.join('images', 'ronery.png'))) name.setPos(QPointF(170, 375)) self.scene.addItem(name) view.setScene(self.scene) # Timer for the win animation only. self.timer = QTimer() self.timer.setInterval(5) self.timer.timeout.connect(self.win_animation) self.animation_event_cover = AnimationCover() self.scene.addItem(self.animation_event_cover) menu = self.menuBar().addMenu("&Game") deal_action = QAction( QIcon(os.path.join('images', 'playing-card.png')), "Deal...", self) deal_action.triggered.connect(self.restart_game) menu.addAction(deal_action) menu.addSeparator() deal1_action = QAction("1 card", self) deal1_action.setCheckable(True) deal1_action.triggered.connect(lambda: self.set_deal_n(1)) menu.addAction(deal1_action) deal3_action = QAction("3 card", self) deal3_action.setCheckable(True) deal3_action.setChecked(True) deal3_action.triggered.connect(lambda: self.set_deal_n(3)) menu.addAction(deal3_action) dealgroup = QActionGroup(self) dealgroup.addAction(deal1_action) dealgroup.addAction(deal3_action) dealgroup.setExclusive(True) menu.addSeparator() rounds3_action = QAction("3 rounds", self) rounds3_action.setCheckable(True) rounds3_action.setChecked(True) rounds3_action.triggered.connect(lambda: self.set_rounds_n(3)) menu.addAction(rounds3_action) rounds5_action = QAction("5 rounds", self) rounds5_action.setCheckable(True) rounds5_action.triggered.connect(lambda: self.set_rounds_n(5)) menu.addAction(rounds5_action) roundsu_action = QAction("Unlimited rounds", self) roundsu_action.setCheckable(True) roundsu_action.triggered.connect(lambda: self.set_rounds_n(None)) menu.addAction(roundsu_action) roundgroup = QActionGroup(self) roundgroup.addAction(rounds3_action) roundgroup.addAction(rounds5_action) roundgroup.addAction(roundsu_action) roundgroup.setExclusive(True) menu.addSeparator() quit_action = QAction("Quit", self) quit_action.triggered.connect(self.quit) menu.addAction(quit_action) self.deck = [] self.deal_n = 3 # Number of cards to deal each time self.rounds_n = 3 # Number of rounds (restacks) before end. for suit in SUITS: for value in range(1, 14): card = Card(value, suit) self.deck.append(card) self.scene.addItem(card) card.signals.doubleclicked.connect( lambda card=card: self.auto_drop_card(card)) self.setCentralWidget(view) self.setFixedSize(*WINDOW_SIZE) self.deckstack = DeckStack() self.deckstack.setPos(OFFSET_X, OFFSET_Y) self.scene.addItem(self.deckstack) # Set up the working locations. self.works = [] for n in range(7): stack = WorkStack() stack.setPos(OFFSET_X + CARD_SPACING_X * n, WORK_STACK_Y) self.scene.addItem(stack) self.works.append(stack) self.drops = [] # Set up the drop locations. for n in range(4): stack = DropStack() stack.setPos(OFFSET_X + CARD_SPACING_X * (3 + n), OFFSET_Y) stack.signals.complete.connect(self.check_win_condition) self.scene.addItem(stack) self.drops.append(stack) # Add the deal location. self.dealstack = DealStack() self.dealstack.setPos(OFFSET_X + CARD_SPACING_X, OFFSET_Y) self.scene.addItem(self.dealstack) # Add the deal click-trigger. dealtrigger = DealTrigger() dealtrigger.signals.clicked.connect(self.deal) self.scene.addItem(dealtrigger) self.shuffle_and_stack() self.setWindowTitle("Ronery") self.show() def restart_game(self): reply = QMessageBox.question( self, "Deal again", "Are you sure you want to start a new game?", QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.shuffle_and_stack() def quit(self): self.close() def set_deal_n(self, n): self.deal_n = n def set_rounds_n(self, n): self.rounds_n = n self.deckstack.update_stack_status(self.rounds_n) def shuffle_and_stack(self): # Stop any ongoing animation. self.timer.stop() self.animation_event_cover.hide() # Remove cards from all stacks. for stack in [self.deckstack, self.dealstack ] + self.drops + self.works: stack.reset() random.shuffle(self.deck) # Deal out from the top of the deck, turning over the # final card on each line. cards = self.deck[:] for n, workstack in enumerate(self.works, 1): for a in range(n): card = cards.pop() workstack.add_card(card) card.turn_back_up() if a == n - 1: card.turn_face_up() # Ensure removed from all other stacks here. self.deckstack.stack_cards(cards) def deal(self): if self.deckstack.cards: self.dealstack.spread_from = len(self.dealstack.cards) for n in range(self.deal_n): card = self.deckstack.take_top_card() if card: self.dealstack.add_card(card) card.turn_face_up() elif self.deckstack.can_restack(self.rounds_n): self.deckstack.restack(self.dealstack) self.deckstack.update_stack_status(self.rounds_n) def auto_drop_card(self, card): for stack in self.drops: if stack.is_valid_drop(card): card.stack.remove_card(card) stack.add_card(card) break def check_win_condition(self): complete = all(s.is_complete for s in self.drops) if complete: # Add click-proof cover to play area. self.animation_event_cover.show() # Get the stacks of cards from the drop,stacks. self.timer.start() def win_animation(self): # Start off a new card for drop in self.drops: if drop.cards: card = drop.cards.pop() if card.vector is None: card.vector = QPoint(-random.randint(3, 10), -random.randint(0, 10)) break for card in self.deck: if card.vector is not None: card.setPos(card.pos() + card.vector) card.vector += QPoint(0, 1) # Gravity if card.pos().y() > WINDOW_SIZE[1] - CARD_DIMENSIONS.height(): # Bounce the card, losing some energy. card.vector = QPoint( card.vector.x(), -max(1, int(card.vector.y() * BOUNCE_ENERGY))) # Bump back up to base of screen. card.setPos(card.pos().x(), WINDOW_SIZE[1] - CARD_DIMENSIONS.height()) if card.pos().x() < -CARD_DIMENSIONS.width(): card.vector = None # Put the card back where it started. card.stack.add_card(card)
class AppView(QGraphicsView): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Arrival") self.gscene = QGraphicsScene() self.setScene(self.gscene) CanvasSize = (WorldSize[0] * WorldScale, WorldSize[1] * WorldScale) self.gscene.setSceneRect(0, 0, *CanvasSize) global _Scene _Scene = self.gscene worker = Worker(execute_this_fn) worker.signals.result.connect(print_output) worker.signals.finished.connect(thread_complete) worker.signals.progress.connect(progress_fn) self.worker = worker self.threadpool = QThreadPool() self.threadpool.start(worker) def mousePressEvent(self, event): p = self.mapToScene(event.pos()) WorldCenter = (WorldSize[0] // 2, WorldSize[1] // 2) mouse = (p.x() // WorldScale - WorldCenter[0], p.y() // WorldScale - WorldCenter[1]) self.worker.mouse_click = mouse def keyPressEvent(self, event): ctrl = (event.modifiers() == Qt.ControlModifier) or ( event.modifiers() == (Qt.ControlModifier | Qt.ShiftModifier)) if ctrl: if event.key() == 45: self.zoom_out() elif (event.key() == 43) or (event.key() == 61): self.zoom_in() elif event.key() == 71: self.input_state() elif event.key() == 73: self.ocr() else: print('keyboard:', event.key(), file=sys.stderr) def zoom_in(self): global WorldScale WorldScale += 1 if WorldScale > 14: WorldScale = int(WorldScale * 1.1) self.worker.redraw = True def zoom_out(self): global WorldScale if WorldScale > 14: WorldScale = int(WorldScale / 1.1) WorldScale = max(1, WorldScale - 1) self.worker.redraw = True def input_state(self): text, ok = QInputDialog().getText(self, "Enter state", "State:", QLineEdit.Normal, '[2, [1, -1], 0, []]') if ok and text: self.worker.set_state = eval(text) self.worker.mouse_click = (-1000, -1000) def ocr(self): self.worker.ocr = True
class Apartment2D(object): def __init__(self, ui): #self.ui = ui #self.ui.guiDlg.resize(QDesktopWidget().availableGeometry(self).size() * 0.6) self.scene = QGraphicsScene() self.dim = { "HMIN": -3000, "VMIN": -4000, "WIDTH": 6000, "HEIGHT": 8000 } self.scene.setSceneRect(self.dim['HMIN'], self.dim['VMIN'], self.dim['WIDTH'], self.dim['HEIGHT']) ui.graphicsView.setScene(self.scene) self.boxes = [] #self.ui.graphicsView.setViewport(QGLWidget()) ui.graphicsView.scale(1, -1) ui.graphicsView.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) ui.graphicsView.setTransformationAnchor(QGraphicsView.NoAnchor) ui.graphicsView.setResizeAnchor(QGraphicsView.NoAnchor) self.persons = {} self.pixmapSize = (0, 0) self.initializeWorld() def addPerson(self, pos, angle=0, color=-1, size=100): colors = QColor.colorNames() color = colors[random.randint(0, len(colors) - 1)] if color == -1 else color pos = [pos[0], pos[2]] if len(pos) > 2 else pos p = self.scene.addEllipse(pos[0] - size // 2, pos[1] - size // 2, size, size, pen=QPen(QColor(color), 20), brush=QBrush(color=QColor(color))) # pixmap pixmap = QPixmap("person.png").scaled(600, 300) self.pixmapSize = (pixmap.width() / 2, pixmap.height() / 2) pixItem = QGraphicsPixmapItem(pixmap) pixItem.setTransformOriginPoint(pixItem.boundingRect().center()) pixItem.setZValue(20) self.scene.addItem(pixItem) self.persons[p] = pixItem return p def movePerson(self, elipse, pos, size=100): #elipse.setPos(pos[0], pos[1]) pos = [pos[0], pos[2]] if len(pos) > 2 else pos color = elipse.pen().color() self.scene.addEllipse(pos[0] - size // 2, pos[1] - size // 2, size, size, pen=QPen(QColor(color), 20), brush=QBrush(color=QColor(color))) # pixmap self.persons[elipse].setPos(pos[0] - self.pixmapSize[0], pos[1] - self.pixmapSize[1]) # change rotation value when provided self.persons[elipse].setRotation(180) def wheelEvent(self, event): zoomInFactor = 1.15 zoomOutFactor = 1 / zoomInFactor # Zoom if event.delta() > 0: zoomFactor = zoomInFactor else: zoomFactor = zoomOutFactor self.graphicsView.scale(zoomFactor, zoomFactor) def initializeWorld(self): with open('autonomy.json', 'r') as f: world = json.load(f) #load dimensions dim = world["dimensions"] x_offset = -3200 y_offset = 1850 # load roundtables # for k,v in world["roundTables"].items(): # print(v) # box = self.scene.addEllipse(QRectF(-v[2]// 2, -v[3]// 2, v[2], v[3]), QPen(QColor("Khaki")), QBrush(QColor("Khaki"))); # box.setPos(v[4]+x_offset, v[5]+x_offset); # self.boxes.append(box) # load tables for k, v in world["tables"].items(): box = self.scene.addRect( QRectF(-v[2] // 2, -v[3] // 2, v[2], v[3]), QPen(QColor("SandyBrown")), QBrush(QColor("SandyBrown"))) box.setPos(v[4] + x_offset, v[5] + y_offset) box.setTransformOriginPoint(box.mapFromScene(QPointF(0, 0))) box.setRotation(v[6]) self.boxes.append(box) # load walls for k, v in world['walls'].items(): box = self.scene.addRect( QRectF(-v[2] // 2, -v[3] // 2, v[2], v[3]), QPen(QColor("Brown")), QBrush(QColor("Brown"))) box.setPos(v[4] + x_offset, v[5] + y_offset) box.setTransformOriginPoint(box.mapFromScene(QPointF(0, 0))) box.setRotation(v[6]) self.boxes.append(box) # } # //load points # QVariantMap points = mainMap[QString("points")].toMap(); # for (auto &t : points) # { # QVariantList object = t.toList(); # auto box = scene.addRect(QRectF(-object[2].toFloat() / 2, -object[3].toFloat() / 2, object[2].toFloat(), object[3].toFloat()), QPen(QColor("Brown")), QBrush(QColor("Brown"))); # box->setPos(object[4].toFloat()+x_offset, object[5].toFloat()+y_offset); # boxes.push_back(box); # } # //load boxes # QVariantMap cajas = mainMap[QString("boxes")].toMap(); # for (auto &t : cajas) # { # QVariantList object = t.toList(); # auto box = scene.addRect(QRectF(-object[2].toFloat() / 2, -object[3].toFloat() / 2, object[2].toFloat(), object[3].toFloat()), QPen(QColor("Brown")), QBrush(QColor("Orange"))); # box->setPos(object[4].toFloat()+x_offset, object[5].toFloat()+y_offset); # //box->setPos(object[4].toFloat(), object[5].toFloat()); # //box->setRotation(object[6].toFloat()*180/M_PI2); # box->setFlag(QGraphicsItem::ItemIsMovable); # boxes.push_back(box); # } # QTransform t; # //t.translate(3200, -1850); # t.rotate(-90); # //t.translate(-3200, 1850); # for(auto &item : boxes) # { # item->setPos(t.map(item->pos())); # item->setRotation(item->rotation() + 90); # item->setPos(item->pos() + QPointF(1850,3200)); # } # ///////////// # //AXIS self.scene.addLine(0, 0, 400, 0, QPen(QBrush(QColor("red")), 20)) self.scene.addLine(0, 0, 0, 400, QPen(QBrush(QColor("blue")), 20))
class EvisionCamera(QWidget): def __init__(self): super(EvisionCamera, self).__init__() self.ui = Ui_EvisionCameraForm() self.ui.setupUi(self) self.device = 0 self.camtype = "usb_cam" self.colorspace = "rgb" self.image_suffix = "png" self.video_codec = "AVC1" self.video_suffix = "avi" self.dst = Path("./") self.parent_dir = Path(__file__).parent.resolve() self.filename_rule_lst = FileIO.file_save self.filename_rule = FileIO.file_save_lst[-1] self.is_display = True self.param_separate = False self.slot = Slot(self) cam = self.get_cam() self.camera = cam(self.device, self.colorspace, parent=self) self.support_params = self.camera.get_supported_params() self.current_params = self.camera.get_current_params("full") self.prop_table = [["Fourcc", "aa"], ["Width", 640], ["Height", 480], ["FPS", 30.0], ["Bit depth", 8], ["File naming style", self.filename_rule]] self.setup() self.set_timer() def get_cam(self): """Return camera object according to current OS. Detects what OS you are using, return camera objects in order to function properly. - Linux: LinuxCamera - RaspberryPi OS: RaspiCamera - Windows: WindowsCamera Returns: Camera class """ self.system = sys.platform if self.system == 'linux': return LinuxCamera elif self.system == 'win32': return WindowsCamera else: return "Unknown type" def setup(self): """Setup the main window for displaying frame and widget. Creates a QMainWindow object, then add menubar, toolbar, statusbar, widgets and layout into the window. """ self.setFocusPolicy(Qt.ClickFocus) self.setContentsMargins(20, 0, 20, 0) # self.information_window_setup() self.view_setup() self.layout_setup() self.image_setup() self.update_prop_table() self.adjust_windowsize() def set_timer(self): """Set QTimer Creates a QTimer object to update frame on view area. The interval is set to the inverse of camera FPS. """ self.qtime_factor = 0.8 self.fps = 30.0 if self.fps: self.msec = 1 / self.fps * 1000 * self.qtime_factor else: self.msec = 1 / 30.0 * 1000 * self.qtime_factor self.timer = QTimer() self.timer.setInterval(self.msec) self.timer.timeout.connect(self.next_frame) self.timer.start() def next_frame(self): """Get next frame from the connected camera. Get next frame, set it to the view area and update. """ #print("display :", self.is_display) if self.is_display: self.camera.read_frame() self.convert_frame() self.scene.clear() self.scene.addPixmap(self.pixmap) self.update() #print("update") def convert_frame(self): """Convert the class of frame Create qimage, qpixmap objects from ndarray frame for displaying on the window. """ if self.colorspace == "rgb" or self.colorspace == "RGB": self.qimage = QImage(self.camera.frame.data, self.camera.frame.shape[1], self.camera.frame.shape[0], self.camera.frame.shape[1] * 3, QImage.Format_RGB888) elif self.colorspace == "gray": self.qimage = QImage(self.camera.frame.data, self.camera.frame.shape[1], self.camera.frame.shape[0], self.camera.frame.shape[1] * 1, QImage.Format_Grayscale8) self.pixmap.convertFromImage(self.qimage) def stop_timer(self): """Deactivate the Qtimer object. """ self.timer.stop() def start_timer(self): """Activate the Qtimer object. """ self.fps = 30.0 if self.fps: self.msec = 1 / self.fps * 1000 * self.qtime_factor else: self.msec = 1 / 30.0 * 1000 * self.qtime_factor self.timer.setInterval(self.msec) self.timer.start() def view_setup(self): """Set view area to diplay read frame in part of the main window """ self.scene = QGraphicsScene() self.ui.view.setScene(self.scene) self.width = 640 self.height = 480 self.scene.setSceneRect(0, 0, self.width, self.height) self.ui.view.setMouseTracking(True) self.ui.view.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) self.ui.view.setCacheMode(QGraphicsView.CacheBackground) self.ui.view.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) def layout_setup(self): """Set layout of objects on the window. """ # self.add_statusbar() self.add_buttons() self.add_prop_window() def add_statusbar(self): """Create status bar, then add to the main window. The status bar shows the coordinates on the frame where the cursor is located and its pixel value. The pixel value has RGB if the format of is color (RGB), does grayscale value if grayscale. """ self.statbar_list = [] if self.colorspace == "rgb": self.stat_css = { "postion": "color: white", "R": "color: white;", "G": "color: white;", "B": "color: white;", "alpha": "color: white;", } else: self.stat_css = { "postion": "color: black;", "gray": "color: black" } for s in self.stat_css.values(): stat = QStatusBar(self) stat.setStyleSheet(s) self.statbar_list.append(stat) first = True for stat in self.statbar_list: if first: # self.ssetStatusBar(stat) self.statbar_list[0].reformat() first = False else: self.statbar_list[0].addPermanentWidget(stat) def add_buttons(self): self.ui.save_button.clicked.connect(self.save_frame) self.ui.stop_button.clicked.connect(self.stop_frame) self.ui.rec_button.clicked.connect(self.record) self.ui.close_button.clicked.connect(self.slot.quit) self.ui.theme_button.clicked.connect(self.slot.switch_theme) self.ui.help_button.clicked.connect(self.slot.usage) self.ui.frame_button.clicked.connect(self.slot.change_frame_prop) self.ui.default_button.clicked.connect(self.set_param_default) self.ui.filerule_button.clicked.connect(self.slot.set_file_rule) pass def add_prop_window(self): """Create a table to show the current properties of camera. Returns: QGridLayout: PySide2 QGridLayout """ header = ["property", "value"] self.ui.prop_table_widget.setColumnCount(len(header)) self.ui.prop_table_widget.setRowCount(len(self.prop_table)) self.ui.prop_table_widget.setHorizontalHeaderLabels(header) self.ui.prop_table_widget.verticalHeader().setVisible(False) self.ui.prop_table_widget.setAlternatingRowColors(True) self.ui.prop_table_widget.horizontalHeader().setStretchLastSection( True) self.ui.prop_table_widget.setEditTriggers( QAbstractItemView.NoEditTriggers) self.ui.prop_table_widget.setFocusPolicy(Qt.NoFocus) for row, content in enumerate(self.prop_table): for col, elem in enumerate(content): self.item = QTableWidgetItem(elem) self.ui.prop_table_widget.setItem(row, col, self.item) self.ui.prop_table_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) # self.prop_table_widget.resizeColumnsToContents() # self.prop_table_widget.resizeRowsToContents() self.ui.prop_table_widget.setVerticalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.ui.prop_table_widget.setHorizontalScrollBarPolicy( Qt.ScrollBarAlwaysOff) self.ui.prop_table_widget.setSizeAdjustPolicy( QAbstractScrollArea.AdjustToContentsOnFirstShow) self.ui.prop_table_widget.setColumnWidth(0, 150) self.ui.prop_table_widget.setColumnWidth(1, 150) # slot save_button_down def save_frame(self): """Save the frame on the window as an image. """ if self.filename_rule == "Manual": self.save_frame_manual() if not self.filename: return None prm = re.sub(r"\.(.*)", ".csv", str(self.filename)) else: self.filename = FileIO.get_filename(self.filename_rule, self.image_suffix, self.parent_dir) prm = str(self.filename).replace(self.image_suffix, "csv") if not self.dst.exists(): self.dst.mkdir(parents=True) im = Image.fromarray(self.camera.frame) im.save(self.filename) # make a parameter file with open(prm, "w") as f: for name, key in self.current_params.items(): f.write("{},{}\n".format(name, self.current_params[name]["value"])) self.write_text("{:<10}: {}".format("save image", self.filename)) self.write_text("{:<10}: {}".format("save param", prm)) def stop_frame(self, checked: bool): """Stop reading next frame. Args: checked (bool): True when presse the Stop button (toggle on). False when press again (toggel off). """ if checked: self.write_text("Stop !!") self.is_display = False self.ui.stop_button.setText('Start') self.ui.stop_button.setChecked(True) else: self.write_text("Start !!") self.is_display = True self.ui.stop_button.setText('&Pause') self.ui.stop_button.setChecked(False) def record(self): """Start or end recording """ if self.camera.is_recording: self.camera.stop_recording() self.rec_button.setText('&Rec') self.rec_act.setText('&Record') self.write_text("save : {}".format(self.video_filename)) else: self.video_filename = FileIO.get_filename(self.filename_rule, self.video_suffix, self.parent_dir) self.camera.start_recording(self.video_filename, self.video_codec) self.rec_button.setText('Stop rec') self.rec_act.setText('Stop record') def image_setup(self): """Creates a Qimage to assign frame, then initialize with an image which has zero in all pixels. """ self.frame = np.zeros((640, 480, 3), dtype=np.uint8) #cinit = np.ctypeslib.as_ctypes(self.frame) #self.frame.buffer = sharedctypes.RawArray(cinit._type_, cinit) self.qimage = QImage(self.frame.data, 640, 480, 640 * 3, QImage.Format_RGB888) self.pixmap = QPixmap.fromImage(self.qimage) def update_prop_table(self): """Updates the table that shows the camera properties. """ w, h, cc, f = self.camera.get_properties() self.prop_table = [["Fourcc", cc], ["Width", int(w)], ["Height", int(h)], ["FPS", "{:.1f}".format(f)], ["Bit depth", 8], ["Naming Style", self.filename_rule]] col = 1 for row in range(len(self.prop_table)): text = str(self.prop_table[row][col]) self.ui.prop_table_widget.item(row, col).setText(text) def adjust_windowsize(self): """Adjusts the main window size """ system = Utility.get_os() if system == "linux": w, h, _ = self.get_screensize() wscale = 0.5 hscale = 0.7 self.resize(wscale * w, hscale * h) else: self.resize(800, 600) def set_param_default(self): """Sets all paramters to default. """ for param, values in self.current_params.items(): default = values["default"] self.camera.set_parameter(param, default) self.current_params[param]["slider"].setValue(int(default)) self.current_params[param]["slider_value"].setText(str(default)) def write_text(self, text: str, level: str = "info", color: str = None): print(text) # decorator def display(func): def wrapper(self, *args, **kwargs): try: self.is_display = False self.stop_timer() func(self, *args, **kwargs) finally: self.is_display = True self.start_timer() return wrapper @display def save_frame_manual(self) -> bool: """Determine file name of image to save with QFileDialog """ self.dialog = QFileDialog() self.dialog.setWindowTitle("Save File") self.dialog.setNameFilters( ["image (*.jpg *.png *.tiff *.pgm)", "All Files (*)"]) self.dialog.setAcceptMode(QFileDialog.AcceptSave) self.dialog.setOption(QFileDialog.DontUseNativeDialog) if self.dialog.exec_(): r = self.dialog.selectedFiles() # If the file name doesn't include supproted suffixes, add to the end. if re.search(".pgm$|.png$|.jpg$|.tiff$", r[0]): self.filename = r[0] else: self.filename = "{}.{}".format(r[0], self.image_suffix) return True else: return False def get_properties(self) -> list: """Get the current camera properties. Returns: list: parameters. fourcc, width, height, fps. """ tmp = [] for row in range(4): tmp.append(self.prop_table[row][1]) return tmp
class DisplayWidget(QStackedWidget): imageClicked = Signal(int, QEvent) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.max_columns = None # Set when presenter starts # Max cols for multimages self.cached_images = {} # Cache read of image from disk self.start() def emitter(self, index, event): self.imageClicked.emit(index, event) def start(self): # Layout for single images self.single_image = QWidget() self.single_image_layout = QGridLayout() self.single_image_view = QGraphicsView() self.single_image_scene = QGraphicsScene() self.single_image_view.setScene(self.single_image_scene) self.single_image_layout.addWidget(self.single_image_view) self.single_image.setLayout(self.single_image_layout) # Layout for multiple images self.multiple_image = QWidget() self.multiple_image_view_layout = QVBoxLayout() self.multiple_image_layout = QGraphicsGridLayout() self.multiple_image_view = QGraphicsView() self.multiple_image_scene = QGraphicsScene() self.multiple_image_view.setScene(self.multiple_image_scene) self.panel = QGraphicsWidget() self.multiple_image_scene.addItem(self.panel) self.multiple_image_view_layout.addWidget(self.multiple_image_view) self.panel.setLayout(self.multiple_image_layout) self.multiple_image.setLayout(self.multiple_image_view_layout) self.addWidget(self.single_image) self.addWidget(self.multiple_image) def setMaxColumns(self, max_cols): self.max_columns = max_cols def images_load(self, images): """ Take list of images and display in main window """ num = len(images) if num == 0: return width = self.width() maxcol = self.max_columns if num < maxcol: maxcol = num colwidth = width / maxcol # Set proper widget for display of multiple or single images if num > 1: self.setCurrentWidget(self.multiple_image) # Clear the layout while self.multiple_image_layout.count(): self.multiple_image_layout.removeAt(0) # Clear the scene for child in self.panel.childItems(): child.setParent(None) else: self.setCurrentWidget(self.single_image) self.single_image_scene.clear() self.single_image_scene.setSceneRect( self.single_image_scene.itemsBoundingRect()) # Display images or image row = 0 col = -1 for index, image in images.items(): col += 1 if col >= maxcol: col = 0 row += 1 # Used any cached reads if index not in self.cached_images.keys(): image_reader = QImageReader() image_reader.setDecideFormatFromContent(True) image_reader.setFileName(image.getFilename()) self.cached_images[index] = image_reader.read() cached_image = self.cached_images[index] pixmap = QPixmap(cached_image) if num > 1: pixmap = pixmap.scaledToWidth(colwidth - 20) rec = MultiImageWidget(pixmap, basename(image.getFilename()), index) rec.imageClicked.connect(self.emitter) self.multiple_image_layout.addItem(rec, row, col) else: self.single_image_scene.addPixmap(pixmap) adjusted = self.multiple_image_scene.itemsBoundingRect() adjusted.adjust(0, 0, 0, 8 * row) self.multiple_image_scene.setSceneRect(adjusted)
class Window(QMainWindow): """Class to create main widnow Creates main window for displaying frame read from a connected camera. The main window contains memu bar, tool bar, status bar, sliders and the boxes showing the camera's information. These widget are created and added to main window in the instance method of this class. """ def __init__( self, device: int = 0, suffix: str = "png", camtype: str = "usb_cam", color: str = "RGB", dst: str = ".", param: str = "full", rule: str = "Sequential", parent=None): super(Window, self).__init__(parent) self.device = device self.camtype = camtype self.colorspace = color self.image_suffix = suffix self.video_codec = "AVC1" self.video_suffix = "avi" self.dst = Path(dst) self.parent_dir = Path(__file__).parent.resolve() self.filename_rule_lst = FileIO.file_save self.filename_rule = FileIO.file_save_lst[-1] self.is_display = True self.param_separate = False self.slot = Slot(self) cam = self.get_cam() self.camera = cam(self.device, self.colorspace, parent=self) self.support_params = self.camera.get_supported_params() self.current_params = self.camera.get_current_params(param) # List of camera properties with temporal initial values self.prop_table = [ ["Fourcc", "aa"], ["Width", 640], ["Height", 480], ["FPS", 30.0], ["Bit depth", 8], ["File naming style", self.filename_rule] ] self.setup() self.set_timer() def get_cam(self) -> str: """Return camera object according to current OS. Detects what OS you are using, return camera objects in order to function properly. - Linux: LinuxCamera - RaspberryPi OS: RaspiCamera - Windows: WindowsCamera Returns: Camera class """ if self.camtype == "raspi": return RaspiCamera self.system = platform.system() if re.search("linux", self.system, re.IGNORECASE): return LinuxCamera elif re.search("windows", self.system, re.IGNORECASE): return WindowsCamera else: return "Unknown type" def setup(self): """Setup the main window for displaying frame and widget. Creates a QMainWindow object, then add menubar, toolbar, statusbar, widgets and layout into the window. """ self.setFocusPolicy(Qt.ClickFocus) self.setContentsMargins(20, 0, 20, 0) self.information_window_setup() self.view_setup() self.layout_setup() self.image_setup() self.toolbar_setup() self.setWindowTitle("usbcamGUI") self.update_prop_table() self.adjust_windowsize() self.set_theme() def adjust_windowsize(self): """Adjusts the main window size """ system = Utility.get_os() if system == "linux": w, h, _ = self.get_screensize() wscale = 0.5 hscale = 0.7 self.resize(wscale * w, hscale * h) else: self.resize(800, 600) def set_theme(self): """Set color theme of the main window. """ self.style_theme = "light" self.style_theme_sheet = ":/{}.qss".format(self.style_theme) self.slot.switch_theme() self.set_font(self.camera.font_family, self.camera.font_size) def set_font(self, family: str = "Yu Gothic", size: int = 14): """Sets font-family and size of UI. Args: family (str, optional): Font-family. Defaults to "Yu Gothic". size (int, optional): Font-size. Defaults to 20. """ self.setStyleSheet('font-family: "{}"; font-size: {}px;'.format(family, size)) def set_timer(self): """Set QTimer Creates a QTimer object to update frame on view area. The interval is set to the inverse of camera FPS. """ self.qtime_factor = 0.8 self.fps = 30.0 if self.fps: self.msec = 1 / self.fps * 1000 * self.qtime_factor else: self.msec = 1 / 30.0 * 1000 * self.qtime_factor self.timer = QTimer() self.timer.setInterval(self.msec) self.timer.timeout.connect(self.next_frame) self.timer.start() def stop_timer(self): """Deactivate the Qtimer object. """ self.timer.stop() def start_timer(self): """Activate the Qtimer object. """ self.fps = 30.0 if self.fps: self.msec = 1 / self.fps * 1000 * self.qtime_factor else: self.msec = 1 / 30.0 * 1000 * self.qtime_factor self.timer.setInterval(self.msec) self.timer.start() def toolbar_setup(self): """Create toolbar """ self.toolbar = QToolBar("test", self) self.addToolBar(self.toolbar) current_size = str(self.font().pointSize()) lst = [str(i) for i in range(6, 14)] lst.extend([str(i) for i in range(14, 40, 2)]) index = lst.index(current_size) self.fontsize_combo = QComboBox() self.fontsize_combo.addItems(lst) self.fontsize_combo.setCurrentIndex(index) self.fontsize_combo.currentTextChanged.connect(self.slot.set_fontsize) self.fontsize_label = QLabel("Font size") self.fontsize_label.setFrameShape(QFrame.Box) self.comb = QFontComboBox() self.toolbar.addWidget(self.save_button) self.toolbar.addWidget(self.stop_button) self.toolbar.addWidget(self.rec_button) self.toolbar.addWidget(self.close_button) self.toolbar.addWidget(self.theme_button) self.toolbar.addWidget(self.help_button) self.toolbar.addWidget(self.fontsize_label) self.toolbar.addWidget(self.fontsize_combo) self.toolbar.setStyleSheet( """ QToolBar {spacing:5px;} """ ) def view_setup(self): """Set view area to diplay read frame in part of the main window """ self.view = QGraphicsView() self.scene = QGraphicsScene() self.view.setScene(self.scene) self.width = 640 self.height = 480 self.scene.setSceneRect(0, 0, self.width, self.height) self.view.setMouseTracking(True) self.view.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) self.view.setCacheMode(QGraphicsView.CacheBackground) self.view.setViewportUpdateMode(QGraphicsView.SmartViewportUpdate) def layout_setup(self): """Set layout of objects on the window. """ self.window = QWidget() self.setCentralWidget(self.window) #self.view.mouseMoveEvent = self.get_coordinates self.main_layout = QHBoxLayout() self.window.setLayout(self.main_layout) self.add_actions() self.add_menubar() self.add_statusbar() self.button_block = self.add_buttons() self.slider_group = self.add_params() self.prop_block = self.add_prop_window() self.create_mainlayout() def image_setup(self): """Creates a Qimage to assign frame, then initialize with an image which has zero in all pixels. """ self.frame = np.zeros((640, 480, 3), dtype=np.uint8) #cinit = np.ctypeslib.as_ctypes(self.frame) #self.frame.buffer = sharedctypes.RawArray(cinit._type_, cinit) self.qimage = QImage( self.frame.data, 640, 480, 640 * 3, QImage.Format_RGB888 ) self.pixmap = QPixmap.fromImage(self.qimage) def add_actions(self): """Add actions executed when press each item in the memu window. """ self.save_act = self.create_action("&Save", self.save_frame, "Ctrl+s") self.stop_act = self.create_action("&Pause", self.stop_frame, "Ctrl+p", checkable=True) self.rec_act = self.create_action("&Record", self.record, "Ctrl+r", True) self.quit_act = self.create_action("&Quit", self.slot.quit, "Ctrl+q") self.theme_act = self.create_action("Switch &Theme", self.slot.switch_theme, "Ctrl+t") self.param_act = self.create_action("Choose parameter slider", self.slot.switch_paramlist, "Ctrl+g") self.show_paramlist_act = self.create_action("Parameters &List", self.slot.show_paramlist, "Ctrl+l") self.show_shortcut_act = self.create_action("&Keybord shortcut", self.slot.show_shortcut, "Ctrl+k") self.font_act = self.create_action("&Font", self.slot.set_font, "Ctrl+f") self.usage_act = self.create_action("&Usage", self.slot.usage, "Ctrl+h") self.about_act = self.create_action("&About", self.slot.about, "Ctrl+a") def create_action(self, text: str, slot: Callable, key: str = None, checkable: bool = False, check_defalut: bool = False) -> QAction: """Create a QAction object. Args: text (str): Text shown on menu. slot (Callable): A method called when click the menu. key (str, optional): Shortcut key. Defaults to None. checkable (bool, optional): Add a checkbox into the menu. Defaults to False. check_defalut (bool, optional): Check default status. Defaults to False. Returns: QAction: PySide2 QAction """ act = QAction(text) act.setShortcut(key) if checkable: act.setCheckable(True) act.setChecked(check_defalut) act.toggled.connect(slot) else: act.triggered.connect(slot) return act def add_menubar(self): """Create menu bar, then add to the main window. """ self.menubar = QMenuBar() self.setMenuBar(self.menubar) self.file_tab = QMenu("&File") self.file_tab.addAction(self.save_act) self.file_tab.addAction(self.stop_act) self.file_tab.addAction(self.rec_act) self.file_tab.addSeparator() self.file_tab.addAction(self.quit_act) #self.file_tab.setSizePolicy(policy) self.view_tab = QMenu("&View") self.view_tab.addAction(self.theme_act) self.view_tab.addAction(self.font_act) self.view_tab.addAction(self.param_act) self.view_tab.addAction(self.show_shortcut_act) self.view_tab.addAction(self.show_paramlist_act) self.help_tab = QMenu("&Help") self.help_tab.addAction(self.usage_act) self.help_tab.addAction(self.about_act) self.menubar.addMenu(self.file_tab) self.menubar.addMenu(self.view_tab) self.menubar.addMenu(self.help_tab) self.menubar.setStyleSheet( """ QMenuBar { font-size: 16px; spacing:10px; padding-top: 5px; padding-bottom: 10px; } """ ) def add_statusbar(self): """Create status bar, then add to the main window. The status bar shows the coordinates on the frame where the cursor is located and its pixel value. The pixel value has RGB if the format of is color (RGB), does grayscale value if grayscale. """ self.statbar_list = [] if self.colorspace == "rgb": self.stat_css = { "postion": "color: white", "R": "color: white;", "G": "color: white;", "B": "color: white;", "alpha": "color: white;", } else: self.stat_css = { "postion": "color: black;", "gray": "color: black" } for s in self.stat_css.values(): stat = QStatusBar(self) stat.setStyleSheet(s) self.statbar_list.append(stat) first = True for stat in self.statbar_list: if first: self.setStatusBar(stat) self.statbar_list[0].reformat() first = False else: self.statbar_list[0].addPermanentWidget(stat) def add_buttons(self): """Add push buttons on the window. Add quit, save stop and usage buttons on the windows. When press each button, the set method (called "slot" in Qt framework) are execeuted. """ self.save_button = self.create_button("&Save", self.save_frame, None, None, "Save the frame") self.stop_button = self.create_button("&Pause", self.stop_frame, None, None, "Stop reading frame", True) self.rec_button = self.create_button("&Rec", self.record, None, None, "Start recording", True) self.close_button = self.create_button("&Quit", self.slot.quit, None, None, "Quit the program") self.theme_button = self.create_button("Light", self.slot.switch_theme, None, None, "Switche color theme") self.help_button = self.create_button("&Usage", self.slot.usage, None, None, "Show usage") self.frame_button = self.create_button( "Properties", self.slot.change_frame_prop, None, tip="Change properties", minsize=(150, 30) ) self.default_button = self.create_button( "&Default params", self.set_param_default, "Ctrl+d", tip="Set default parameters", minsize=(150, 30) ) self.filerule_button = self.create_button( "&Naming style", self.slot.set_file_rule, "Ctrl+n", tip="Change naming style", minsize=(150, 30) ) hbox = QHBoxLayout() hbox.addWidget(self.save_button) hbox.addWidget(self.stop_button) hbox.addWidget(self.rec_button) hbox.addWidget(self.close_button) hbox.addWidget(self.theme_button) hbox.addWidget(self.help_button) return hbox def create_button(self, text: str, slot: Callable, key: str = None, icon: Icon = None, tip: str = None, checkable: bool = False, minsize: tuple = None) -> QPushButton: """Create a QPushButton object. Args: text (str): Text shown on the button. slot (Callable): A method called when click the button. key (str, optional): Shortcut key. Defaults to None. icon (Icon, optional): An icon shown on the button. Defaults to None. tip (str, optional): A tips shown when position the pointer on the button. Defaults to None. checkable (bool, optional): Add button to checkbox. Defaults to False. msize (tuple, optional): Minimum size of the button box, (width, height). Returns: QPushButton: PySide2 QPushButton """ button = QPushButton(text) if checkable: button.setCheckable(True) button.toggled.connect(slot) else: button.clicked.connect(slot) if key: button.setShortcut(key) if icon: button.setIcon(QIcon(icon)) if tip: button.setToolTip(tip) if minsize: button.setMinimumSize(minsize[0], minsize[1]) else: button.setMinimumSize(80, 30) return button def add_params(self) -> QGridLayout: """Set the properties of camera parameter. Set the properties of camera parameter, then add sliders to change each parameter. When change value on the slider, the value of paramter also changes by the caller function. """ lst = self.current_params for key, value in lst.items(): self.add_slider(key) # add sliders self.slider_table = QGridLayout() self.slider_table.setSpacing(15) self.slider_table.setContentsMargins(20, 20, 20, 20) for row, param in enumerate(self.current_params): self.slider_table.addWidget(self.current_params[param]["slider_label"], row, 0) self.slider_table.addWidget(self.current_params[param]["slider"], row, 1) self.slider_table.addWidget(self.current_params[param]["slider_value"], row, 2) if len(self.current_params) > 15: self.param_separate = True else: self.param_separate = False return self.slider_table def update_params(self, plist: list) -> QGridLayout: """Update camera's paramters and sliders shown on the windows. """ #self.current_params.clear() self.current_params = self.camera.get_current_params("selected", plist) for key, value in self.current_params.items(): self.add_slider(key) # add sliders grid = QGridLayout() grid.setSpacing(15) grid.setContentsMargins(20, 20, 20, 20) for row, param in enumerate(self.current_params): grid.addWidget(self.current_params[param]["slider_label"], row, 0) grid.addWidget(self.current_params[param]["slider"], row, 1) grid.addWidget(self.current_params[param]["slider_value"], row, 2) if len(self.current_params) > 15: self.param_separate = True else: self.param_separate = False self.slider_group = grid self.update_mainlayout() self.update_prop_table() self.write_text("update sliders") return grid def add_slider(self, param: str): """Creates slider, labels to show pamarater's name and its value. Args: param (str): A parameter to create slider. """ min_ = self.current_params[param]["min"] max_ = self.current_params[param]["max"] step = self.current_params[param]["step"] value = self.current_params[param]["value"] slider = QSlider(Qt.Horizontal) if max_: slider.setRange(min_, max_) else: slider.setRange(0, 1) slider.setValue(int(value)) slider.setTickPosition(QSlider.TicksBelow) slider.valueChanged.connect(lambda val, p=param: self.set_sliderval(p, val)) if step: if max_ < 5: slider.setTickInterval(step) else: slider.setTickInterval(10) slider_label = QLabel(param) slider_value = QLabel(str(value)) slider_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) slider_value.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.current_params[param]["slider"] = slider self.current_params[param]["slider_label"] = slider_label self.current_params[param]["slider_value"] = slider_value def add_prop_window(self) -> QGridLayout: """Create a table to show the current properties of camera. Returns: QGridLayout: PySide2 QGridLayout """ header = ["property", "value"] self.prop_table_widget = QTableWidget(self) self.prop_table_widget.setColumnCount(len(header)) self.prop_table_widget.setRowCount(len(self.prop_table)) self.prop_table_widget.setHorizontalHeaderLabels(header) self.prop_table_widget.verticalHeader().setVisible(False) self.prop_table_widget.setAlternatingRowColors(True) self.prop_table_widget.horizontalHeader().setStretchLastSection(True) self.prop_table_widget.setEditTriggers(QAbstractItemView.NoEditTriggers) self.prop_table_widget.setFocusPolicy(Qt.NoFocus) for row, content in enumerate(self.prop_table): for col, elem in enumerate(content): self.item = QTableWidgetItem(elem) self.prop_table_widget.setItem(row, col, self.item) self.prop_table_widget.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) #self.prop_table_widget.resizeColumnsToContents() #self.prop_table_widget.resizeRowsToContents() self.prop_table_widget.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.prop_table_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.prop_table_widget.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContentsOnFirstShow) self.prop_table_widget.setColumnWidth(0, 150) self.prop_table_widget.setColumnWidth(1, 150) vbox = QVBoxLayout() vbox.addWidget(self.prop_table_widget) vbox.setContentsMargins(20, 20, 20, 20) self.prop_group = QGroupBox("Frame Properties") self.prop_group.setLayout(vbox) return self.prop_group def information_window_setup(self): """Creates information window. Creates the information window where the event related to camera or window. """ self.text_edit = QTextEdit() self.text_edit.setReadOnly(True) self.text_edit.show() vbox = QVBoxLayout() vbox.addWidget(self.text_edit) self.text_edit_box = QGroupBox("Information", self) self.text_edit_box.setLayout(vbox) self.text_edit_box.setAlignment(Qt.AlignLeft) def create_mainlayout(self): """Create the main layout which consists of view area and information window. """ self.main_layout.addLayout(self.create_view_area_layout()) self.main_layout.addLayout(self.create_information_layout()) def update_mainlayout(self): """Recreate the main layout. """ self.delete_layout(self.information_layout) self.delete_layout(self.upper_right) self.add_prop_window() self.main_layout.addLayout(self.create_information_layout()) def delete_layout(self, layout): """Delete layout Args: layout (QBoxLayout): QBoxLayout class object to delete """ while layout.count(): child = layout.takeAt(0) if child.widget(): child.widget().deleteLater() try: child.spacerIitem().deleteLater() except: pass def create_view_area_layout(self) -> QVBoxLayout: """Creates view area layout """ self.view_area_layout = QVBoxLayout() self.view_area_layout.addWidget(self.view, 2) self.view_area_layout.addWidget(self.text_edit_box) return self.view_area_layout def create_information_layout(self): """Creates information part layout upper-left: current properties upper-right: buttons lower: sliders """ if self.param_separate: self.entry_box = QVBoxLayout() self.entry_box.addWidget(self.frame_button) self.entry_box.addWidget(self.filerule_button) self.entry_box.addWidget(self.default_button) self.entry_box.addStretch(1) self.entry_box.setSpacing(20) self.entry_box.setContentsMargins(20, 20, 20, 20) self.button_group_box = QGroupBox("Buttons", self) self.button_group_box.setLayout(self.entry_box) self.button_group_box.setAlignment(Qt.AlignLeft) self.upper_right = QVBoxLayout() self.upper_right.addWidget(self.prop_group, 1) self.upper_right.addWidget(self.button_group_box, 1) self.slider_group_box = QGroupBox("Parameters") self.slider_group_box.setLayout(self.slider_group) self.slider_group_box.setContentsMargins(20, 20, 20, 20) self.information_layout = QHBoxLayout() self.information_layout.addLayout(self.upper_right, 1) self.information_layout.addWidget(self.slider_group_box, 2) #self.information_layout.addStretch(1) return self.information_layout else: self.entry_box = QVBoxLayout() self.entry_box.addWidget(self.frame_button) self.entry_box.addWidget(self.filerule_button) self.entry_box.addWidget(self.default_button) self.entry_box.addStretch(1) self.entry_box.setSpacing(20) self.entry_box.setContentsMargins(20, 20, 20, 20) self.button_group_box = QGroupBox("Buttons", self) self.button_group_box.setLayout(self.entry_box) self.button_group_box.setAlignment(Qt.AlignLeft) self.upper_right = QHBoxLayout() self.upper_right.addWidget(self.prop_group) self.upper_right.addWidget(self.button_group_box) self.slider_group_box = QGroupBox("Parameters") self.slider_group_box.setLayout(self.slider_group) self.slider_group_box.setContentsMargins(20, 20, 20, 20) self.information_layout = QVBoxLayout() self.information_layout.addLayout(self.upper_right) self.information_layout.addWidget(self.slider_group_box) self.information_layout.setSpacing(30) return self.information_layout # decorator def display(func): def wrapper(self, *args, **kwargs): try: self.is_display = False self.stop_timer() func(self, *args, **kwargs) finally: self.is_display = True self.start_timer() return wrapper def stop_frame(self, checked: bool): """Stop reading next frame. Args: checked (bool): True when presse the Stop button (toggle on). False when press again (toggel off). """ if checked: self.write_text("Stop !!") self.is_display = False self.stop_button.setText('Start') self.stop_button.setChecked(True) self.stop_act.setText('Start') self.stop_act.setChecked(True) else: self.write_text("Start !!") self.is_display = True self.stop_button.setText('&Pause') self.stop_button.setChecked(False) self.stop_act.setText('&Pause') self.stop_act.setChecked(False) def keyPressEvent(self, event): """Exit the program This method will be called when press the Escape key on the window. """ if event.key() == Qt.Key_Escape: QApplication.quit() def get_coordinates(self, event): """Show the current coordinates and value in the pixel where the cursor is located. The status bar is updates by the obtained values. """ if self.item is self.view.itemAt(event.pos()): sp = self.view.mapToScene(event.pos()) lp = self.item.mapFromScene(sp).toPoint() (x, y) = lp.x(), lp.y() #color = self.frame.image.pixel(x, y) color = self.qimage.pixelColor(x, y) if self.colorspace == "rgb": value = color.getRgb() elif self.colorspace == "gray": value = color.value() # Return none if the coordinates are out of range if x < 0 and self.frame.width < x: return elif y < 0 and self.frame.height < y: return if self.frame.img_is_rgb: status_list = [ "( x : {}, y :{} )".format(x, y), "R : {}".format(value[0]), "G : {}".format(value[1]), "B : {}".format(value[2]), "alpha : {}".format(value[3]) ] else: status_list = [ "( x : {}, y :{} )".format(x, y), "gray value : {}".format(value), ] for statbar, stat in zip(self.statbar_list, status_list): statbar.showMessage(stat) def next_frame(self): """Get next frame from the connected camera. Get next frame, set it to the view area and update. """ #print("display :", self.is_display) if self.is_display: self.camera.read_frame() self.convert_frame() self.scene.clear() self.scene.addPixmap(self.pixmap) self.update() #print("update") def convert_frame(self): """Convert the class of frame Create qimage, qpixmap objects from ndarray frame for displaying on the window. """ if self.colorspace == "rgb": self.qimage = QImage( self.camera.frame.data, self.camera.frame.shape[1], self.camera.frame.shape[0], self.camera.frame.shape[1] * 3, QImage.Format_RGB888 ) elif self.colorspace == "gray": self.qimage = QImage( self.camera.frame.data, self.camera.frame.shape[1], self.camera.frame.shape[0], self.camera.frame.shape[1] * 1, QImage.Format_Grayscale8) self.pixmap.convertFromImage(self.qimage) def save_frame(self): """Save the frame on the window as an image. """ if self.filename_rule == "Manual": self.save_frame_manual() if not self.filename: return None prm = re.sub(r"\.(.*)", ".csv", str(self.filename)) else: self.filename = FileIO.get_filename(self.filename_rule, self.image_suffix, self.parent_dir) prm = str(self.filename).replace(self.image_suffix, "csv") if not self.dst.exists(): self.dst.mkdir(parents=True) im = Image.fromarray(self.camera.frame) im.save(self.filename) # make a parameter file with open(prm, "w") as f: for name, key in self.current_params.items(): f.write("{},{}\n".format(name, self.current_params[name]["value"])) self.write_text("{:<10}: {}".format("save image", self.filename)) self.write_text("{:<10}: {}".format("save param", prm)) def update_prop_table(self): """Updates the table that shows the camera properties. """ w, h, cc, f = self.camera.get_properties() self.prop_table = [ ["Fourcc", cc], ["Width", int(w)], ["Height", int(h)], ["FPS", "{:.1f}".format(f)], ["Bit depth", 8], ["Naming Style", self.filename_rule] ] col = 1 for row in range(len(self.prop_table)): text = str(self.prop_table[row][col]) self.prop_table_widget.item(row, col).setText(text) def record(self): """Start or end recording """ if self.camera.is_recording: self.camera.stop_recording() self.rec_button.setText('&Rec') self.rec_act.setText('&Record') self.write_text("save : {}".format(self.video_filename)) else: self.video_filename = FileIO.get_filename(self.filename_rule, self.video_suffix, self.parent_dir) self.camera.start_recording(self.video_filename, self.video_codec) self.rec_button.setText('Stop rec') self.rec_act.setText('Stop record') @display def save_frame_manual(self) -> bool: """Determine file name of image to save with QFileDialog """ self.dialog = QFileDialog() self.dialog.setWindowTitle("Save File") self.dialog.setNameFilters([ "image (*.jpg *.png *.tiff *.pgm)", "All Files (*)" ]) self.dialog.setAcceptMode(QFileDialog.AcceptSave) self.dialog.setOption(QFileDialog.DontUseNativeDialog) if self.dialog.exec_(): r = self.dialog.selectedFiles() # If the file name doesn't include supproted suffixes, add to the end. if re.search(".pgm$|.png$|.jpg$|.tiff$", r[0]): self.filename = r[0] else: self.filename = "{}.{}".format(r[0], self.image_suffix) return True else: return False def get_screensize(self): """Get current screen size from the output of linux cmd `xrandr`. """ cmd = ["xrandr"] ret = subprocess.check_output(cmd) output = ret.decode() pattern = r"current(\s+\d+\s+x\s+\d+)" m = re.search(pattern, output) if m: size = re.sub(" ", "", m.group(1)) w, h = map(int, size.split("x")) return w, h, size else: return None def set_sliderval(self, param: str, value: int): """Changes a camera parameter. Updates the label on the right of the slider if input value is valid. Args: param (str): A camera parameter value (int): its value """ val = self.camera.set_parameter(param, value) self.current_params[param]["value"] = str(val) self.current_params[param]["slider_value"].setText(str(value)) def set_param_default(self): """Sets all paramters to default. """ for param, values in self.current_params.items(): default = values["default"] self.camera.set_parameter(param, default) self.current_params[param]["slider"].setValue(int(default)) self.current_params[param]["slider_value"].setText(str(default)) def get_properties(self) -> list: """Get the current camera properties. Returns: list: parameters. fourcc, width, height, fps. """ tmp = [] for row in range(4): tmp.append(self.prop_table[row][1]) return tmp def write_text(self, text: str, level: str = "info", color: str = None): """Writes the message into information window. Args: text (str): A text to write. level (str, optional): Log lebel of the message. Defaults to "info". color (str, optional): Font color. Defaults to None. """ now = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") now = now[:-3] if color == "red": form = f"<font color='red'>[{level.upper():<4} {now}] {text}</font>" elif color == "yellow": form = f"<font color='yellow'>[{level.upper():<4} {now}] {text}</font>" else: form = f"[{level.upper():<4} {now}] {text}" self.text_edit.append(form)
class QTraceViewer(QWidget): """ Load a basic block trace through json and visualize it in the disassembly Ref: https://github.com/angr/angr-management/pull/122 """ TAG_SPACING = 50 LEGEND_X = -50 LEGEND_Y = 0 LEGEND_WIDTH = 10 TRACE_FUNC_X = 0 TRACE_FUNC_Y = 0 TRACE_FUNC_WIDTH = 50 TRACE_FUNC_MINHEIGHT = 1000 TAB_HEADER_SIZE = 40 MAX_WINDOW_SIZE = 500 MARK_X = LEGEND_X MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH MARK_HEIGHT = 1 def __init__(self, workspace, disasm_view, parent=None): super().__init__(parent=parent) self.workspace = workspace self.disasm_view = disasm_view self.mark = None self.legend = None self.legend_height = 0 self.legend_img = None self.trace_func_unit_height = 0 self.trace_func = None self.trace_id = None self.view = None self.traceView = None self.traceTab = None self.traceScene = None self.multiView = None self.listView = None self.mark = None self.curr_position = 0 self._use_precise_position = False self._selected_traces = [] self._init_widgets() self.trace.am_subscribe(self._on_set_trace) self.selected_ins.am_subscribe(self._on_select_ins) self.traceTab.installEventFilter(self) # # Forwarding properties # @property def trace(self): return self.workspace.instance.trace @property def multi_trace(self): return self.workspace.instance.multi_trace @property def selected_ins(self): return self.disasm_view.infodock.selected_insns def _init_widgets(self): self.view = QTabWidget() # QGraphicsView() self.traceTab = QWidget() tracelayout = QVBoxLayout() self.traceView = QGraphicsView() self.traceScene = QGraphicsScene() self.traceView.setScene(self.traceScene) self.listView = QTableWidget(0, 2) # row, col self.listView.setHorizontalHeaderItem(0, QTableWidgetItem("Trace ID")) self.listView.setHorizontalHeaderItem(1, QTableWidgetItem("Input ID")) self.listView.setSelectionMode(QAbstractItemView.SingleSelection) self.listView.setSelectionBehavior(QAbstractItemView.SelectRows) # self.listView.horizontalHeader().setStretchLastSection(True) # self.listView.horizontalHeader().setSectionResizeModel(0, QHeaderView.Stretch) self.listView.cellClicked.connect(self._switch_current_trace) self.traceSeedButton = QPushButton("View Input Seed") self.traceSeedButton.clicked.connect(self._view_input_seed) tracelayout.addWidget(self.traceView) tracelayout.addWidget(self.listView) tracelayout.addWidget(self.traceSeedButton) self.traceTab.setLayout(tracelayout) self.multiView = QWidget() multiLayout = QVBoxLayout() self.multiTraceList = QTableWidget(0, 2) # row, col self.multiTraceList.setSelectionMode(QAbstractItemView.MultiSelection) self.multiTraceList.setSelectionBehavior(QAbstractItemView.SelectRows) self.multiTraceList.setHorizontalScrollMode( self.multiTraceList.ScrollPerPixel) self.multiTraceList.setHorizontalHeaderItem( 0, QTableWidgetItem("Trace ID")) self.multiTraceList.setHorizontalHeaderItem( 1, QTableWidgetItem("Input ID")) self.selectMultiTrace = QPushButton("Refresh Heatmap") self.selectMultiTrace.clicked.connect(self._refresh_heatmap) multiLayout.addWidget(self.multiTraceList) multiLayout.addWidget(self.selectMultiTrace) self.multiView.setLayout(multiLayout) self.view.addTab(self.traceTab, "SingleTrace") self.view.addTab(self.multiView, "MultiTrace HeatMap") self.SINGLE_TRACE = 0 self.MULTI_TRACE = 1 self.view.currentChanged.connect(self._on_tab_change) self._reset() layout = QVBoxLayout() layout.addWidget(self.view) layout.setContentsMargins(0, 0, 0, 0) layout.setAlignment(self.view, Qt.AlignLeft) self.setLayout(layout) def _reset(self): self.traceScene.clear() #clear items self.listView.clearContents() self.multiTraceList.clearContents() self.mark = None self.legend = None self.legend_height = 0 self.trace_func = QGraphicsItemGroup() self.trace_id = QGraphicsItemGroup() self.traceScene.addItem(self.trace_func) self.hide() def _view_input_seed(self): current_trace_stats = self.trace.am_obj input_id = current_trace_stats.input_id inputSeed = self.multi_trace.am_obj.get_input_seed_for_id(input_id) msgText = "%s" % inputSeed msgDetails = "Input for [%s]" % current_trace_stats.id msgbox = QMessageBox() msgbox.setWindowTitle("Seed Input") msgbox.setDetailedText(msgDetails) msgbox.setText(msgText) msgbox.setStandardButtons(QMessageBox.Ok) msgbox.exec() def _switch_current_trace(self, row): if self.listView.rowCount() <= 0: return current_trace = self.trace.am_obj.id new_trace = self.multiTraceList.item(row, 0).text() if current_trace == new_trace: return trace_stats = self.multi_trace.am_obj.get_trace_with_id(new_trace) if trace_stats: self.trace.am_obj = trace_stats self._on_set_trace() def _on_set_trace(self): self._reset() if self.trace.am_none or self.trace.count is None: return l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT, self.trace.count) if self.trace.count <= 0: l.warning( "No valid addresses found in trace to show. Check base address offsets?" ) self.trace.am_obj = None self.trace.am_event() return if self.TRACE_FUNC_MINHEIGHT < self.trace.count * 15: self.trace_func_unit_height = 15 show_func_tag = True else: self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.trace.count show_func_tag = True self.legend_height = int(self.trace.count * self.trace_func_unit_height) self._show_trace_func(show_func_tag) self._show_legend() self._show_trace_ids() self._set_mark_color() self._refresh_multi_list() boundingSize = self.traceScene.itemsBoundingRect().width() windowSize = boundingSize if boundingSize > self.MAX_WINDOW_SIZE: windowSize = self.MAX_WINDOW_SIZE self.traceScene.setSceneRect( self.traceScene.itemsBoundingRect()) #resize self.setFixedWidth(windowSize) # self.listScene.setSceneRect(self.listScene.itemsBoundingRect()) #resize self.multiView.setFixedWidth(windowSize) cellWidth = windowSize // 2 self.listView.setColumnWidth(0, cellWidth) self.listView.setColumnWidth(1, cellWidth) self.listView.setFixedHeight(self.multiView.height() // 4) self.multiTraceList.setColumnWidth(0, cellWidth) self.multiTraceList.setColumnWidth(1, cellWidth) self.view.setFixedWidth(windowSize) self.show() def _populate_trace_table(self, view, trace_ids): numIDs = len(trace_ids) view.clearContents() view.setRowCount(numIDs) row = 0 #start after label row for traceID in trace_ids: inputID = self.multi_trace.am_obj.get_input_id_for_trace_id( traceID) if inputID is None: self.workspace.log("No inputID found for trace %s" % traceID) view.setItem(row, 0, QTableWidgetItem(traceID)) view.setItem(row, 1, QTableWidgetItem(inputID)) row += 1 def _refresh_heatmap(self): multiTrace = self.multi_trace.am_obj multiTrace.clear_heatmap() multiTrace.is_active_tab = True selected_items = self.multiTraceList.selectedItems() self._selected_traces.clear() for row in range(self.multiTraceList.rowCount()): item = self.multiTraceList.item(row, 0) if item in selected_items: self._selected_traces.append(item.text()) multiTrace.reload_heatmap(self._selected_traces) self.multi_trace.am_event() def _refresh_multi_list(self): multiTrace = self.multi_trace.am_obj trace_ids = multiTrace.get_all_trace_ids() self.multiTraceList.clearContents() self._populate_trace_table(self.multiTraceList, trace_ids) if self._selected_traces and self.multiTraceList.rowCount() > 0: self.multiTraceList.item(0, 0).setSelected(True) self.multiTraceList.item(0, 1).setSelected(True) else: for row in range(self.multiTraceList.rowCount()): item = self.multiTraceList.item(row, 0) inputItem = self.multiTraceList.item(row, 1) if item.text() in self._selected_traces: item.setSelected(True) inputItem.setSelected(True) self.multi_trace.am_event() def _on_tab_change(self): # self._reset() multiTrace = self.multi_trace.am_obj if self.view.currentIndex() == self.MULTI_TRACE: multiTrace.is_active_tab = True self._refresh_multi_list() elif self.view.currentIndex() == self.SINGLE_TRACE: multiTrace = self.multi_trace.am_obj multiTrace.is_active_tab = False self._show_trace_ids() def _on_select_ins(self, **kwargs): # pylint: disable=unused-argument if self.trace.am_none: return if self.mark is not None: for i in self.mark.childItems(): self.mark.removeFromGroup(i) self.traceScene.removeItem(i) self.traceScene.removeItem(self.mark) self.mark = QGraphicsItemGroup() self.traceScene.addItem(self.mark) if self.selected_ins: addr = next(iter(self.selected_ins)) positions = self.trace.get_positions(addr) if positions: #if addr is in list of positions if not self._use_precise_position: #handle case where insn was selected from disas view self.curr_position = positions[0] - self.trace.count for p in positions: color = self._get_mark_color(p, self.trace.count) y = self._get_mark_y(p) if p == self.trace.count + self.curr_position: #add thicker line for 'current' mark self.mark.addToGroup( self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT * 4, QPen(QColor('black')), QBrush(color))) else: self.mark.addToGroup( self.traceScene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT, QPen(color), QBrush(color))) self.traceScene.update() #force redraw of the traceScene self.scroll_to_position(self.curr_position) def scroll_to_position(self, position): relative_pos = self.trace.count + position y_offset = self._get_mark_y(relative_pos) scrollValue = 0 if y_offset > 0.5 * self.traceView.size().height(): scrollValue = y_offset - 0.5 * self.traceView.size().height() scrollValue = min(scrollValue, self.traceView.verticalScrollBar().maximum()) self.traceView.verticalScrollBar().setValue(scrollValue) self._use_precise_position = False def jump_next_insn(self): if self.curr_position + self.trace.count < self.trace.count - 1: #for some reason indexing is done backwards self.curr_position += 1 self._use_precise_position = True bbl_addr = self.trace.get_bbl_from_position(self.curr_position) func = self.trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def jump_prev_insn(self): if self.curr_position + self.trace.count > 0: self.curr_position -= 1 self._use_precise_position = True bbl_addr = self.trace.get_bbl_from_position(self.curr_position) func = self.trace.get_func_from_position(self.curr_position) self._jump_bbl(func, bbl_addr) def eventFilter(self, obj, event): #specifically to catch arrow keys #pylint: disable=unused-argument # more elegant solution to link w/ self.view's scroll bar keypressevent? if event.type() == QEvent.Type.KeyPress: if not event.modifiers() & Qt.ShiftModifier: #shift + arrowkeys return False key = event.key() if key in [Qt.Key_Up, Qt.Key_Left]: self.jump_prev_insn() elif key in [Qt.Key_Down, Qt.Key_Right]: self.jump_next_insn() return True return False # pass through all other events def mousePressEvent(self, event): button = event.button() pos = self._to_logical_pos(event.pos()) if button == Qt.LeftButton and self.view.currentIndex( ) == self.SINGLE_TRACE and self._at_legend(pos): func = self._get_func_from_y(pos.y()) bbl_addr = self._get_bbl_from_y(pos.y()) self._use_precise_position = True self.curr_position = self._get_position(pos.y()) self._jump_bbl(func, bbl_addr) def _jump_bbl(self, func, bbl_addr): all_insn_addrs = self.workspace.instance.project.factory.block( bbl_addr).instruction_addrs # TODO: replace this with am_events perhaps? if func is None: return self.workspace.on_function_selected(func) self.selected_ins.clear() self.selected_ins.update(all_insn_addrs) self.selected_ins.am_event() # TODO: this ought to happen automatically as a result of the am_event self.disasm_view.current_graph.show_instruction(bbl_addr) def _get_mark_color(self, i, total): relative_gradient_pos = i * 1000 // total return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2, relative_gradient_pos) def _get_mark_y(self, i): return self.TRACE_FUNC_Y + self.trace_func_unit_height * i def _show_trace_ids(self): trace_ids = self.multi_trace.get_all_trace_ids() # traceID = self.listScene.addText(id_txt, QFont("Source Code Pro", 7)) # traceID.setPos(5,5) self.listView.clearContents() self._populate_trace_table(self.listView, trace_ids) if len(self.listView.selectedItems()) <= 0 and not self.trace.am_none: for row in range(self.listView.rowCount()): item = self.listView.item(row, 0) inputItem = self.listView.item(row, 1) if self.trace.id in item.text(): item.setSelected(True) inputItem.setSelected(True) break def _show_trace_func(self, show_func_tag): x = self.TRACE_FUNC_X y = self.TRACE_FUNC_Y prev_name = None for position in self.trace.trace_func: bbl_addr = position.bbl_addr func_name = position.func_name l.debug('Draw function %x, %s', bbl_addr, func_name) color = self.trace.get_func_color(func_name) self.trace_func.addToGroup( self.traceScene.addRect(x, y, self.TRACE_FUNC_WIDTH, self.trace_func_unit_height, QPen(color), QBrush(color))) if show_func_tag is True and func_name != prev_name: tag = self.traceScene.addText(func_name, QFont("Source Code Pro", 7)) tag.setPos(x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y - tag.boundingRect().height() // 2) self.trace_func.addToGroup(tag) anchor = self.traceScene.addLine( self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y, x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y) self.trace_func.addToGroup(anchor) prev_name = func_name y += self.trace_func_unit_height @staticmethod def _make_legend_gradient(x1, y1, x2, y2): gradient = QLinearGradient(x1, y1, x2, y2) gradient.setColorAt(0.0, Qt.red) gradient.setColorAt(0.4, Qt.yellow) gradient.setColorAt(0.6, Qt.green) gradient.setColorAt(0.8, Qt.blue) gradient.setColorAt(1.0, Qt.darkBlue) return gradient def _show_legend(self): pen = QPen(Qt.transparent) gradient = self._make_legend_gradient( self.LEGEND_X, self.LEGEND_Y, self.LEGEND_X, self.LEGEND_Y + self.legend_height) brush = QBrush(gradient) self.legend = self.traceScene.addRect(self.LEGEND_X, self.LEGEND_Y, self.LEGEND_WIDTH, self.legend_height, pen, brush) reference_gradient = self._make_legend_gradient( 0, 0, self.LEGEND_WIDTH, 1000) base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32) p = QPainter(base_img) p.fillRect(base_img.rect(), reference_gradient) self.legend_img = base_img #reference shade def _set_mark_color(self): for p in range(self.trace.count): color = self._get_mark_color(p, self.trace.count) self.trace.set_mark_color(p, color) def _at_legend(self, pos): x = pos.x() y = pos.y() return self.TRACE_FUNC_X + self.LEGEND_X < x < self.traceView.width() and \ self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height def _to_logical_pos(self, pos): x_offset = self.traceView.horizontalScrollBar().value() y_offset = self.traceView.verticalScrollBar().value() return QPoint(pos.x() + x_offset, pos.y() + y_offset) def _get_position(self, y): y_relative = y - self.legend_height - self.TAB_HEADER_SIZE return int(y_relative // self.trace_func_unit_height) def _get_bbl_from_y(self, y): position = self._get_position(y) return self.trace.get_bbl_from_position(position) def _get_func_from_y(self, y): position = self._get_position(y) func = self.trace.get_func_from_position(position) return func
class Escena(QWidget): def __init__(self): QWidget.__init__(self) self.resize(QDesktopWidget().availableGeometry(self).size() * 0.6) self.scene = QGraphicsScene() self.scene.setSceneRect(-3000, -4000, 6000, 8000) self.view = QGraphicsView(self.scene) self.view.resize(self.size()) self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) self.view.setParent(self) self.view.setTransformationAnchor(QGraphicsView.NoAnchor) self.view.setResizeAnchor(QGraphicsView.NoAnchor) self.view.scale(3, -3) self.lines = [] self.show() def wheelEvent(self, event): zoomInFactor = 1.15 zoomOutFactor = 1 / zoomInFactor # Zoom if event.delta() > 0: zoomFactor = zoomInFactor else: zoomFactor = zoomOutFactor self.view.scale(zoomFactor, zoomFactor) def resizeEvent(self, event): self.view.resize(self.size()) def draw(self, comps, cluster): colors = QColor.colorNames() # for co in sample: # print(co) # x, _, z, _ = co['world'] # self.scene.addEllipse(x-50,z-50,100,100, pen=QPen(QColor('orange'), 5)) # x,_,z,_ = sample[-1]['world'] # self.scene.addRect(x,z,60,60, pen=QPen(QColor('red'), 100)) # x,_,z,_ = sample[0]['world'] # self.scene.addRect(x,z,60,60, pen=QPen(QColor('green'), 100)) # for co in comps: # if sample[co[-1]]['timestamp']-sample[co[0]]['timestamp'] > 200 and len(co)> 4: # color = colors[random.randint(0, len(colors)-1)] # for c in co: # x, _, z, _ = sample[c]['world'] # self.scene.addEllipse(x-15,z-15,30,30, pen=QPen(QColor(color), 100), brush=QBrush(color=QColor(color))) if cluster[-1]['timestamp'] - cluster[0]['timestamp'] > 200 and len( cluster) > 4: color = colors[random.randint(0, len(colors) - 1)] for sample in cluster: x, _, z, _ = sample['world'] self.scene.addEllipse(x - 15, z - 15, 30, 30, pen=QPen(QColor(color), 100), brush=QBrush(color=QColor(color))) def drawTrack(self, clusters): colors = QColor.colorNames() # for line in self.lines: # self.scene.removeItem(line) self.scene.clear() for cluster in clusters: color = colors[random.randint(0, len(colors) - 1)] for t in cluster: self.scene.addLine(t[0][0], t[0][1], t[1][0], t[1][1], pen=QPen(QColor(color), 60))
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 500, 500) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setColor(QColor(0, 0, 0)) self.pen.setWidth(1) self.capturador = Capturador() self.ui.pushButton.clicked.connect(self.click) self.ui.pushButton_2.clicked.connect(self.mostrar) self.ui.actionGuardar.triggered.connect(self.guardar) self.ui.actionAbrir_2.triggered.connect(self.abrir) @Slot() def guardar(self): file = QFileDialog.getSaveFileName(self, 'Guardar archivo...', '.', 'JSON (*.json)') print(file) self.capturador.guardar(file[0], self.pen, self.scene) @Slot() def abrir(self): file = QFileDialog.getOpenFileName(self, 'Abrir archivo', '.', 'JSON (*.json)') self.capturador.recuperar(file[0]) @Slot() def mostrar(self): self.scene.addLine(0, 0, 499, 0, self.pen) for particula in self.capturador.lista: self.ui.plainTextEdit.insertPlainText(str(particula)) self.pen.setColor( QColor(particula.red, particula.green, particula.blue)) self.scene.addEllipse( particula.origenX, particula.origenY, 5, 5, self.pen, QBrush( QColor(particula.red, 10, particula.green, particula.blue))) self.scene.addLine(particula.origenX, particula.origenY, particula.destinoX, particula.destinoY, self.pen) #self.paqueteria.mostrar() @Slot() def click(self): id = self.ui.lineEdit.text() origenX = self.ui.lineEdit_2.text() origenY = self.ui.lineEdit_6.text() destinoX = self.ui.lineEdit_3.text() destinoY = self.ui.lineEdit_7.text() velocidad = self.ui.lineEdit_4.text() red = self.ui.lineEdit_5.text() green = self.ui.lineEdit_8.text() blue = self.ui.lineEdit_9.text() print(id, origenX, origenY, destinoX, destinoY, velocidad, red, green, blue) partiula = Particula() partiula.id = id partiula.origenX = int(origenX) partiula.origenY = int(origenY) partiula.destinoX = int(destinoX) partiula.destinoY = int(destinoY) partiula.distancia = math.sqrt( pow((int(destinoX) - int(origenX)), 2) + pow((int(destinoY) - int(origenY)), 2)) partiula.red = int(red) partiula.green = int(green) partiula.blue = int(blue) partiula.velocidad = int(velocidad) self.capturador.agregar(partiula) msg = QMessageBox.information( self, 'Exito', 'Se agrego paquete con exito' ) #Ventana de mensaje de la libreria QMessageBox self.ui.lineEdit.clear() #Limpiar campos self.ui.lineEdit_2.clear() self.ui.lineEdit_3.clear() self.ui.lineEdit_4.clear() self.ui.lineEdit_5.clear() self.ui.lineEdit_6.clear() self.ui.lineEdit_7.clear() self.ui.lineEdit_8.clear() self.ui.lineEdit_9.clear()
class ImageView(TopicMessageView): """ Popup image viewer """ name = 'Image' def __init__(self, timeline, parent, topic): super(ImageView, self).__init__(timeline, parent, topic) self._image = None self._image_topic = None self._image_stamp = None self.quality = Image.NEAREST # quality hint for scaling # TODO put the image_topic and image_stamp on the picture or display them in some fashion self._overlay_font_size = 14.0 self._overlay_indent = (4, 4) self._overlay_color = (0.2, 0.2, 1.0) self._image_view = QGraphicsView(parent) self._image_view.resizeEvent = self._resizeEvent self._scene = QGraphicsScene() self._image_view.setScene(self._scene) parent.layout().addWidget(self._image_view) # MessageView implementation def _resizeEvent(self, event): # TODO make this smarter. currently there will be no scrollbar even if the timeline extends beyond the viewable area self._scene.setSceneRect(0, 0, self._image_view.size().width() - 2, self._image_view.size().height() - 2) self.put_image_into_scene() def message_viewed(self, bag, msg_details): """ refreshes the image """ TopicMessageView.message_viewed(self, bag, msg_details) topic, msg, t = msg_details[:3] if not msg: self.set_image(None, topic, 'no message') else: self.set_image(msg, topic, msg.header.stamp) def message_cleared(self): TopicMessageView.message_cleared(self) self.set_image(None, None, None) # End MessageView implementation def put_image_into_scene(self): if self._image: resized_image = self._image.resize((self._image_view.size().width() - 2, self._image_view.size().height() - 2), self.quality) QtImage = ImageQt(resized_image) pixmap = QPixmap.fromImage(QtImage) self._scene.clear() self._scene.addPixmap(pixmap) def set_image(self, image_msg, image_topic, image_stamp): self._image_msg = image_msg if image_msg: self._image = image_helper.imgmsg_to_pil(image_msg) else: self._image = None self._image_topic = image_topic self._image_stamp = image_stamp self.put_image_into_scene()
class CanvasGraphicsView(QGraphicsView): onSelection = Signal(PickNode) requestEditMode = Signal(bool) def __init__(self, parent=None): super(CanvasGraphicsView, self).__init__(parent) self.setFocusPolicy(Qt.StrongFocus) # Scene properties self.setAcceptDrops(True) self.setMouseTracking(True) self.setRenderHint(QPainter.Antialiasing) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setBackgroundBrush(QBrush(QColor(51, 51, 51))) self.setFrameShape(QFrame.NoFrame) self.setDragMode(QGraphicsView.RubberBandDrag) self.ViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) self.init() def init(self): self.piiPath = str() self._model = {'background': str()} self._isPanning = False self._isZooming = False self._mousePressed = False self._scene = QGraphicsScene() self._scene.selectionChanged.connect(self.update_node_settings) self._backgroundNode = QGraphicsPixmapItem() self._scene.addItem(self._backgroundNode) self._orderSelected = list() self._lastPos = QPoint(0, 0) self.editMode = False self._namespace = str() self._dragMulti = list() self._defaultColor = QColor(255, 255, 255) self._defaultTextColor = QColor(0, 0, 0) self._defaultTextSize = 20 self._defaultText = "New Node" self.workHight = 2160 self.workWidth = 4096 self.setScene(self._scene) self.setContextMenuPolicy(Qt.CustomContextMenu) self.setBackgroundImage(str()) def update_node_settings(self): if self._orderSelected: node = self._orderSelected[-1] self._defaultText = node.toPlainText() self._defaultColor = node.Background self._defaultTextColor = node.defaultTextColor() self._defaultTextSize = node.font().pointSize() def update_maya_selection(self): ''' Update Maya Scene base on active selection. ''' clearSelection() selection = list() for each in self._orderSelected: selection += each.Items if selection: selectObjects(selection) def setBackgroundImage(self, path=str()): ''' Set background image Parameters ---------- path: (str) Path to background image. ''' self._model['background'] = path self.setStatusTip(self._model['background']) pixmap = QPixmap(self._model['background']) self._backgroundNode.setPixmap(pixmap) def getBackgroundImage(self): ''' Get background image ''' return self._model['background'] BackgroundImage = property(getBackgroundImage, setBackgroundImage) def actionMenu(self, QPos): ''' Show action menu. Parameters ---------- QPos: (list) list of x and y location. ''' self.mainMenu = QMenu() add_action = self.mainMenu.addAction('Add A Button') add_action.setEnabled(self.editMode) add_action.triggered.connect(self.add_node) addMany_action = self.mainMenu.addAction('Add Many Buttons') addMany_action.setEnabled(self.editMode) addMany_action.triggered.connect(self.add_multiple_nodes) activeNode = self.mouse_on_node() if activeNode: update_action = self.mainMenu.addAction('Update Button') update_action.setEnabled(self.editMode) update_action.triggered.connect( lambda: self.update_node(activeNode)) delete_action = self.mainMenu.addAction('Delete Button') delete_action.setEnabled(self.editMode) delete_action.setShortcut('Backspace') delete_action.triggered.connect(self.removeSelected) self.mainMenu.addSeparator() # search for selected ButtonNode btnStatus = [ isinstance(n, ButtonNode) for n in self._scene.selectedItems() ] if True in btnStatus: # first ButtonNode activeNode = self._scene.selectedItems()[btnStatus.index(True)] command_action = self.mainMenu.addAction('Edit Command Button...') command_action.setEnabled(self.editMode) command_action.triggered.connect( lambda: self.update_ButtonNode(activeNode)) else: command_action = self.mainMenu.addAction('add Command Button...') command_action.setEnabled(self.editMode) command_action.triggered.connect(self.add_commands) self.mainMenu.addSeparator() reset_action = self.mainMenu.addAction('Reset View') reset_action.setShortcut('H') reset_action.triggered.connect(self.reset_view) frame_action = self.mainMenu.addAction('Frame View') frame_action.setShortcut('F') frame_action.triggered.connect(self.frame_view) self.mainMenu.addSeparator() alignGrp = QMenu('Align') self.mainMenu.addMenu(alignGrp) hac_action = alignGrp.addAction('Horizontal Align Center') hac_action.setIcon(QIconSVG('h_align-01')) hac_action.setEnabled(self.editMode) hac_action.triggered.connect(self.align_horizontal) vac_action = alignGrp.addAction('Vertical Align Center') vac_action.setIcon(QIconSVG('v_align-01')) vac_action.setEnabled(self.editMode) vac_action.triggered.connect(self.align_vertical) hd_action = alignGrp.addAction('Horizontal Distribute') hd_action.setIcon(QIconSVG('h_d_align-01')) hd_action.setEnabled(self.editMode) hd_action.triggered.connect(self.align_horizontal_distribute) vd_action = alignGrp.addAction('Vertical Distribute') vd_action.setIcon(QIconSVG('v_d_align-01')) vd_action.setEnabled(self.editMode) vd_action.triggered.connect(self.align_vertical_distribute) alignGrp.addSeparator() ins_action = alignGrp.addAction('Increase Size') ins_action.setShortcut('+') ins_action.setEnabled(self.editMode) ins_action.triggered.connect(self.increase_size) dis_action = alignGrp.addAction('Decrease Size') dis_action.setShortcut('-') dis_action.setEnabled(self.editMode) dis_action.triggered.connect(self.decrease_size) self.mainMenu.addSeparator() edit_mode = self.mainMenu.addAction('Edit Mode') edit_mode.setCheckable(True) edit_mode.setChecked(self.editMode) edit_mode.triggered.connect( lambda: self.request_edit(not self.editMode)) pos = self.mapToGlobal(QPoint(0, 0)) self.mainMenu.move(pos + QPos) self.mainMenu.show() def mouse_on_node(self): globPosition = self.mapFromGlobal(QCursor.pos()) scenePosition = self.mapToScene(globPosition) for node in self._scene.items(): if isinstance(node, PickNode): if node.mapRectToScene( node.boundingRect()).contains(scenePosition): return node return None def update_node(self, node=PickNode): ''' Update the Node selection base on selection in maya. ''' mayaScene = getActiveItems() # for each in self._scene.selectedItems(): node.Items = mayaScene def update_ButtonNode(self, node=ButtonNode): ''' Update the ButtonNode commands. Parameters ---------- node: (ButtonNode) ButtonNode Node. ''' self.newCommand = CommandDialog(text=node.toPlainText(), cmd=node.Command, cmdType=node.CommandsType) if self.newCommand.exec_() == QDialog.Accepted: data = self.newCommand.Raw node.setPlainText(data[PIIButton.TEXT]) node.Command = data[PIIButton.COMMAND] node.CommandsType = data[PIIButton.COMMANDTYPE] def add_commands(self): ''' Create a new ButtonNode with Commands. ''' globPosition = self.mapFromGlobal(QCursor.pos()) scenePosition = self.mapToScene(globPosition) self.newCommand = CommandDialog() if self.newCommand.exec_() == QDialog.Accepted: data = self.newCommand.Raw self.create_button(position=scenePosition, text=data[PIIButton.TEXT], size=self._defaultTextSize, textColor=self._defaultTextColor, bgColor=self._defaultColor, cmd=data[PIIButton.COMMAND], cmdType=data[PIIButton.COMMANDTYPE]) def align_horizontal(self): ''' Align the selection to center horizontally. ''' selected = self._scene.selectedItems() if len(selected) > 1: minValue = selected[0].y() maxValue = selected[0].y() whole = None for each in selected: y = each.y() value = y + each.boundingRect().height() # finding lowest value minValue = y if y < minValue else minValue minValue = value if value < minValue else minValue # finding highest value maxValue = y if y > maxValue else maxValue maxValue = value if value > maxValue else maxValue total = maxValue - minValue if total != 0: middle = (maxValue + minValue) / 2 for each in selected: center = each.shape().boundingRect().center() start_y = each.y() offset = start_y + center.y() - middle each.setY(each.y() - offset) def align_vertical(self): ''' Align the selection to center vertically. ''' selected = self._scene.selectedItems() if len(selected) > 1: # sort it based on x position + width selected = sorted(selected, key=lambda x: x.x() + x.boundingRect().width()) leftNode = selected[0] rightNode = selected[-1] # total length of x axis total = rightNode.boundingRect().width() + rightNode.x( ) - leftNode.x() if total != 0: middle = (total / 2) + leftNode.x() for each in selected: center = each.shape().boundingRect().center() start_x = each.x() offset = start_x + center.x() - middle each.setX(each.x() - offset) def align_horizontal_distribute(self): ''' Disturbute the selected nodes evenly between first node on the left and last node on the right horizontally. ''' selected = self._scene.selectedItems() if len(selected) > 2: # sort it based on x position + width selected = sorted(selected, key=lambda x: x.x() + x.boundingRect().width()) startItem = selected.pop(0) endItem = selected.pop(-1) # total length of items itemsLength = int() for each in selected: itemsLength += each.boundingRect().width() startPoint = startItem.x() + startItem.boundingRect().width() total = endItem.x() - startPoint section_num = len(selected) + 1 extraSpace = total - itemsLength # nicly divide if extraSpace > 0: gap = extraSpace / section_num nextPlace = startPoint for each in selected: newLoc = nextPlace + gap nextPlace += gap + each.boundingRect().width() each.setX(newLoc) else: total = endItem.x() - startPoint gap = total / section_num nextPlace = startPoint for each in selected: nextPlace += gap each.setX(nextPlace) else: errorMes("PUPPETMASTER-INFO: Select more than 2 nodes.") def align_vertical_distribute(self): ''' Disturbute the selected nodes evenly between first node on the top and last node on the bottom vertically. ''' selected = self._scene.selectedItems() if len(selected) > 2: # sort it based on y position + width selected = sorted( selected, key=lambda node: node.y() + node.boundingRect().height()) startItem = selected.pop(0) endItem = selected.pop(-1) # total length of items itemsLength = int() for each in selected: itemsLength += each.boundingRect().height() startPoint = startItem.y() + startItem.boundingRect().height() total = endItem.y() - startPoint section_num = len(selected) + 1 extraSpace = total - itemsLength # nicly divide if extraSpace > 0: gap = extraSpace / section_num nextPlace = startPoint for each in selected: newLoc = nextPlace + gap nextPlace += gap + each.boundingRect().height() each.setY(newLoc) else: total = endItem.y() - startPoint gap = total / section_num nextPlace = startPoint for each in selected: nextPlace += gap each.setY(nextPlace) else: errorMes("PUPPETMASTER-INFO: Select more than 2 nodes.") def reset_view(self): ''' Fit all the items to the view. ''' items = self._scene.items() if items: rects = [ item.mapToScene(item.boundingRect()).boundingRect() for item in items ] rect = self.min_bounding_rect(rects) self._scene.setSceneRect(rect) self.fitInView(rect, Qt.KeepAspectRatio) def frame_view(self): ''' Fit selected items to the view. ''' items = self._scene.selectedItems() if items: rects = [ item.mapToScene(item.boundingRect()).boundingRect() for item in items ] rect = self.min_bounding_rect(rects) self.fitInView(rect, Qt.KeepAspectRatio) def fit_contents(self): ''' Update the scene boundery. ''' items = self._scene.items() if items: rects = [ item.mapToScene(item.boundingRect()).boundingRect() for item in items ] rect = self.min_bounding_rect(rects) self._scene.setSceneRect(rect) def request_edit(self, value=bool): self.requestEditMode.emit(value) def min_bounding_rect(self, rectList=list()): ''' Get the minimum boundry based on objects in the scene. Parameters ---------- rectList: (list) List of QRectF (boundry of objects) Return ------ out: (QRectF) Get the minimum boundry ''' minX = rectList[0].left() minY = rectList[0].top() maxX = rectList[0].right() maxY = rectList[0].bottom() for k in range(1, len(rectList)): minX = min(minX, rectList[k].left()) minY = min(minY, rectList[k].top()) maxX = max(maxX, rectList[k].right()) maxY = max(maxY, rectList[k].bottom()) return QRectF(minX, minY, maxX - minX, maxY - minY) def increase_size(self): ''' Increase the size of selected items by 1 unit. ''' selected = self._scene.selectedItems() for each in selected: font = each.font() fontSize = font.pointSize() if fontSize < 99: fontSize += 1 font.setPointSize(fontSize) each.setFont(font) def decrease_size(self): ''' Decrease the size of selected items by 1 unit. ''' selected = self._scene.selectedItems() for each in selected: font = each.font() fontSize = font.pointSize() if fontSize > 1: fontSize -= 1 font.setPointSize(fontSize) each.setFont(font) def is_texture(self, path=str): ''' Check if the texture path is valid. Return ------ out: (bool) True if texture is valide, otherwise False. ''' if path.lower().endswith(IMAGE_FORMATS): return True return False def _QMimeDataToFile(self, data=QMimeData): ''' Get all the filepath from drag file. Parameters ---------- data: (QMimeData) QMimeData of dragged file. ''' files = list() if data.hasUrls: for each in data.urls(): files.append(each.toLocalFile()) return files def _is_dragValid(self, event): ''' Check for draged file validation ''' dragedItems = self._QMimeDataToFile(event.mimeData()) if dragedItems: first_path = dragedItems[0] if self.is_texture(first_path) and self.editMode: return True return False def dragEnterEvent(self, event): event.accept() if self._is_dragValid(event) else event.ignore() def dragMoveEvent(self, event): event.accept() if self._is_dragValid(event) else event.ignore() def dropEvent(self, event): dragedItems = self._QMimeDataToFile(event.mimeData()) if dragedItems: first_path = dragedItems[0] if self.is_texture(first_path): self.setBackgroundImage(path=first_path) event.accept() else: event.ignore() def mousePressEvent(self, event): self._lastPos = event.pos() self._lastScenePos = self.mapToScene(event.pos()) if self._dragMulti: for each in self._dragMulti: each.setSelected(True) self._dragMulti = list() if event.button() == Qt.MiddleButton: self._isPanning = True self.setCursor(QPixmap(iconSVG('nav-pan-02'))) self._dragPos = event.pos() event.accept() elif event.button() == Qt.RightButton: if event.modifiers() == Qt.AltModifier: self._isZooming = True self.setCursor(QPixmap(iconSVG('nav-zoom-02'))) self._dragPos = event.pos() self._dragPos2 = self.mapToScene(event.pos()) else: self.actionMenu(event.pos()) event.accept() else: super(CanvasGraphicsView, self).mousePressEvent(event) def mouseMoveEvent(self, event): if self._dragMulti and len(self._dragMulti) > 1: start = self._lastScenePos end = self.mapToScene(event.pos()) total = len(self._dragMulti) - 1 xLength = start.x() - end.x() yLength = start.y() - end.y() xStep = 0 if xLength == 0 else -(xLength / total) yStep = 0 if yLength == 0 else -(yLength / total) num = 0 for each in self._dragMulti: position = QPointF(start.x() + (num * xStep), start.y() + (num * yStep)) each.setPos(position) num += 1 if self._isPanning: 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() elif self._isZooming: newPos = event.pos() diff = newPos - self._dragPos self._dragPos = newPos factor = 1.000 if diff.x() < 0: factor = 0.98 else: factor = 1.02 self.scale(factor, factor) event.accept() else: if event.modifiers() == Qt.ShiftModifier: diff = event.pos() - self._lastPos x = event.x() if abs(diff.x()) > abs( diff.y()) else self._lastPos.x() y = event.y() if abs(diff.y()) > abs( diff.x()) else self._lastPos.y() event = QMouseEvent(QEvent.MouseMove, QPoint(x, y), self.mapToGlobal(QPoint(x, y)), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier) super(CanvasGraphicsView, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): self._isPanning = False self._isZooming = False self.setCursor(Qt.ArrowCursor) super(CanvasGraphicsView, self).mouseReleaseEvent(event) self.fit_contents() self.update_maya_selection() def keyPressEvent(self, event): if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete: if self.editMode: self.removeSelected() elif event.key() == Qt.Key_Plus: if self.editMode: self.increase_size() elif event.key() == Qt.Key_Minus: if self.editMode: self.decrease_size() elif event.key() == Qt.Key_H: self.reset_view() elif event.key() == Qt.Key_F: self.frame_view() else: super(CanvasGraphicsView, self).keyPressEvent(event) def removeSelected(self): ''' Remove selected Items. ''' for each in self._scene.selectedItems(): self._scene.removeItem(each) self.remove_stack(each) def wheelEvent(self, event): factor = 1.05 if event.delta() < 0: # factor = .2 / factor factor = 0.95 self.scale(factor, factor) self.update() def add_node(self): ''' Add a new PickNode to the scene. ''' # Cursor Position on Scene globPosition = self.mapFromGlobal(QCursor.pos()) scenePosition = self.mapToScene(globPosition) self.create_node(text=self._defaultText, size=self._defaultTextSize, textColor=self._defaultTextColor, bgColor=self._defaultColor, position=scenePosition, items=getActiveItems(), shape=PickShape.SQUARE) def add_multiple_nodes(self): ''' Add group of PickNode bellow each other to the scene. ''' # Cursor Position on Scene globPosition = self.mapFromGlobal(QCursor.pos()) scenePosition = self.mapToScene(globPosition) self._dragMulti = list() for each in getActiveItems(): node = self.create_node(text=self._defaultText, size=self._defaultTextSize, textColor=self._defaultTextColor, bgColor=self._defaultColor, position=scenePosition, items=[each], shape=PickShape.SQUARE) self._dragMulti.append(node) # scenePosition = QPointF(scenePosition.x(), node.y() + node.boundingRect().height() + 5) def create_node(self, position=list, text=str, size=int, textColor=QColor, bgColor=QColor, items=list, shape=PickShape.SQUARE): ''' Create a new PickNode. Parameters ---------- position: (list) List of x and y location. text: (str) Name of the text. size: (int) Size of the text. textColor: (QColor) Color of the text. bgColor: (QColor) Background Color of the node. items: (list) List of selected Maya object. Return ------ out: (PickNode) Reference of created Node. ''' textNode = PickNode() font = QFont("SansSerif", size) font.setStyleHint(QFont.Helvetica) textNode.setFont(font) textNode.setDefaultTextColor(textColor) textNode.setFlag(QGraphicsItem.ItemIsMovable, self.editMode) textNode.setFlag(QGraphicsItem.ItemIsSelectable) # textNode.setFlag(QGraphicsItem.ItemIsFocusable, self.editMode) textNode.Background = bgColor textNode.Items = items textNode.Shape = shape textNode.onSelected.connect(lambda: self.onSelection.emit(textNode)) textNode.onAddToStack.connect(lambda: self.add_stack(textNode)) textNode.onRemoveFromStack.connect(lambda: self.remove_stack(textNode)) textNode.setPos(position) textNode.setPlainText(text) self._scene.addItem(textNode) return textNode def create_button(self, position=list, text=str, size=int, textColor=QColor, bgColor=QColor, cmd=str, cmdType=str): ''' Create a new ButtonNode. Parameters ---------- position: (list) List of x and y location. text: (str) Name of the text. size: (int) Size of the text. textColor: (QColor) Color of the text. bgColor: (QColor) Background Color of the node. cmd: (str) Command to run when it's pressed. cmdType: (str) Type of command.("python"/"mel") ''' btnNode = ButtonNode() font = QFont("SansSerif", size) font.setStyleHint(QFont.Helvetica) btnNode.setFont(font) btnNode.setDefaultTextColor(textColor) btnNode.setFlag(QGraphicsItem.ItemIsMovable, self.editMode) btnNode.setFlag(QGraphicsItem.ItemIsSelectable) btnNode.Background = bgColor btnNode.CommandsType = cmdType btnNode.Command = cmd # btnNode.onSelected.connect(lambda: self.onSelection.emit(textNode)) btnNode.onSelected.connect(lambda: self.onSelection.emit(btnNode)) btnNode.onClicked.connect(self.scriptJob) btnNode.setPos(position) btnNode.setPlainText(text) self._scene.addItem(btnNode) def scriptJob(self, cmdType=str, cmd=str): ''' Run a command. Parameters ---------- cmd: (str) Command to run. cmdType: (str) Type of command.("python"/"mel") ''' if not self.editMode: if cmdType == CommandType.PYTHON: runPython(cmd) elif cmdType == CommandType.MEL: runMel(cmd) def add_stack(self, node=PickNode): ''' Add a node selection in right order into the stack. Parameters ---------- node: (PickNode) Selected node. ''' self._orderSelected.append(node) def remove_stack(self, node=PickNode): ''' Remove a node from the stack. Parameters ---------- node: (PickNode) Selected node. ''' if node in self._orderSelected: index = self._orderSelected.index(node) self._orderSelected.pop(index) def get_edit(self): return self.editMode def set_edit(self, value=bool): self.editMode = value for each in self._scene.items(): if type(each) == PickNode: each.setFlag(QGraphicsItem.ItemIsMovable, self.editMode) elif type(each) == ButtonNode: each.setFlag(QGraphicsItem.ItemIsMovable, self.editMode) Edit = property(get_edit, set_edit) def get_path(self): return self.piiPath def set_path(self, path=str): self.piiPath = path Path = property(get_path, set_path) def get_raw(self): ''' Get the scene information. (can be be save in .pii) Return ------ out: (dict) Dictionary of scene date to be save in .pii file. ''' image_data = str() pixmap = self._backgroundNode.pixmap() # Extract Image Data if not pixmap.isNull(): buffer = QBuffer() buffer.open(QIODevice.WriteOnly) pixmap.save(buffer, "PNG") # Image Data image_data = bytes(buffer.data().toBase64()).decode('ascii') nodeList = [] for each in self._scene.items(): if type(each) == PickNode: textColor = each.defaultTextColor() bgColor = each.Background item = { PIIPick.TYPE: PIINode.PICK, PIIPick.TEXT: each.toPlainText(), PIIPick.SIZE: each.font().pointSize(), PIIPick.POSITION: (each.pos().x(), each.pos().y()), PIIPick.COLOR: (textColor.red(), textColor.green(), textColor.blue()), PIIPick.BACKGROUND: (bgColor.red(), bgColor.green(), bgColor.blue()), PIIPick.SELECTION: each.Items, PIIPick.SHAPE: each.Shape } nodeList.append(item) elif type(each) == ButtonNode: textColor = each.defaultTextColor() bgColor = each.Background item = { PIIButton.TYPE: PIINode.BUTTON, PIIButton.TEXT: each.toPlainText(), PIIButton.SIZE: each.font().pointSize(), PIIButton.POSITION: (each.pos().x(), each.pos().y()), PIIButton.COLOR: (textColor.red(), textColor.green(), textColor.blue()), PIIButton.BACKGROUND: (bgColor.red(), bgColor.green(), bgColor.blue()), PIIButton.COMMAND: each.Command, PIIButton.COMMANDTYPE: each.CommandsType } nodeList.append(item) rawData = { PII.VERSION: "1.0.0", PII.BACKGROUND: image_data, PII.NODES: nodeList } return rawData def set_raw(self, data=dict): ''' set the scene information. (information from .pii) Parameters ---------- data: (dict) Dictionary of date from .pii file. ''' if data: if data[PII.VERSION] == "1.0.0": self.load_1_0_0(data) Raw = property(get_raw, set_raw) def get_namespace(self): ''' Get namespace of all PickNode. Return ------ out: (list) List of namespaces. ''' namespaceList = [] for each in self._scene.items(): if type(each) == PickNode: valueList = each.Items for sObj in valueList: if ":" in sObj: group = sObj.split(":")[:-1] for index in range(len(group)): namespaceList.append(":".join(group[:index + 1])) return list(set(namespaceList)) def set_namespace(self, data=dict): ''' Set namespace of all PickNode. Parameters ---------- data: (dict) Dictionary of namespace with value of new namespace. ''' for each in self._scene.items(): if type(each) == PickNode: valueList = each.Items newValue = list() for sObj in valueList: if ":" in sObj: # namesapce nameS = ":".join(sObj.split(":")[:-1]) # object name object_name = sObj.split(":")[-1] keys = data.keys() keys.sort(reverse=True) for key in keys: if key in nameS: nameS = nameS.replace(key, data[key], 1) # making sure doesn't start with ':' nameS = nameS[1:] if nameS.startswith(":") else nameS # add the object to namespace nameS = ":".join([nameS, object_name ]) if nameS else object_name newValue.append(nameS) else: newValue.append(sObj) each.Items = newValue Namespace = property(get_namespace, set_namespace) def get_NSHistory(self): return self._namespace def set_NSHistory(self, name=str): self._namespace = name NamespaceHistory = property(get_NSHistory, set_NSHistory) def get_highlight(self): return def set_highlight(self, data=list): if data: for each in self._scene.items(): # QApplication.processEvents() if type(each) == PickNode: for item in data: if item in each.Items: each.Highlight = True break else: each.Highlight = False else: for each in self._scene.items(): if type(each) == PickNode: each.Highlight = False Highlight = property(get_highlight, set_highlight) def clear_scene(self): ''' Clear the scene. ''' self._orderSelected = list() self._scene.clear() self._backgroundNode = QGraphicsPixmapItem() self._scene.addItem(self._backgroundNode) self.reset_view() def is_changed(self): ''' Check for the scene changes. ''' if self._backgroundNode.pixmap(): return True elif len(self._scene.items()) > 1: return True return False def load_1_0_0(self, data=dict): ''' Load v1.0.0 of .pii version file. Parameters ---------- data: (dict) Dictionary of date from .pii file. ''' if data[PII.BACKGROUND]: # Import Image Data newPix = QPixmap() newPix.loadFromData( QByteArray.fromBase64(data[PII.BACKGROUND].encode('ascii')), "PNG") self._backgroundNode.setPixmap(newPix) for each in data[PII.NODES]: if each["type"] == PIINode.PICK: self.create_node(text=each[PIIPick.TEXT], size=each[PIIPick.SIZE], textColor=QColor(*each[PIIPick.COLOR]), bgColor=QColor(*each[PIIPick.BACKGROUND]), position=QPointF(*each[PIIPick.POSITION]), items=each[PIIPick.SELECTION], shape=each[PIIPick.SHAPE]) elif each["type"] == PIINode.BUTTON: self.create_button(position=QPointF(*each[PIIButton.POSITION]), text=each[PIIButton.TEXT], size=each[PIIButton.SIZE], textColor=QColor(*each[PIIButton.COLOR]), bgColor=QColor(*each[PIIButton.BACKGROUND]), cmd=each[PIIButton.COMMAND], cmdType=each[PIIButton.COMMANDTYPE]) def set_nodes_bg_color(self, color=QColor): ''' Set background color of selected nodes. Parameters ---------- color: (QColor) QColor value. ''' self._defaultColor = color for each in self._scene.selectedItems(): each.Background = color self.update() def set_nodes_font_color(self, color=QColor): ''' Set font color of selected nodes. Parameters ---------- color: (QColor) QColor value. ''' self._defaultTextColor = color for each in self._scene.selectedItems(): each.setDefaultTextColor(color) def set_nodes_font_size(self, size=int): ''' Set font size of selected nodes. Parameters ---------- size: (int) font size. ''' self._defaultTextSize = size for each in self._scene.selectedItems(): font = each.font() font.setPointSize(size) each.setFont(font) def set_nodes_text(self, text=str): ''' Set text for selected nodes. Parameters ---------- text: (str) text for the node. ''' self._defaultText = text for each in self._scene.selectedItems(): each.setPlainText(text) def set_nodes_shape(self, shape=str): ''' Set shape for selected nodes. Parameters ---------- shape: (str) name for the shape. ''' for each in self._scene.selectedItems(): if isinstance(each, PickNode): each.Shape = shape
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.paqueteria = Paqueteria() self.ui.pushButton.clicked.connect(self.click) self.ui.pushButton_2.clicked.connect(self.mostrar) self.ui.actionGuardar.triggered.connect(self.guardar) self.ui.actionAbrir.triggered.connect(self.abrir) self.scene = QGraphicsScene() ##COMENTERA ABAJAO self.scene.setSceneRect(0, 0, 500, 500) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setColor(QColor(0, 0, 0)) self.pen.setWidth(30) self.scene.addLine(0, 0, 499, 0, self.pen) self.scene.addLine(0, 499, 499, 499, self.pen) self.scene.addLine(0, 0, 0, 499, self.pen) self.scene.addLine(499, 0, 499, 499, self.pen) self.pen.setColor(QColor(100, 20, 200)) self.scene.addLine(10, 10, 490, 490, self.pen) self.scene.addEllipse(10, 10, 5, 5, self.pen, QBrush(QColor(50, 100, 0))) self.scene.addEllipse(490, 490, 5, 5, self.pen, QBrush(QColor(50, 100, 0))) self.ui.pushButton_3.clicked.connect(self.ordenar_origen) self.ui.pushButton_4.clicked.connect(self.ordenar_distancia) @Slot() def ordenar_origen(self): self.paqueteria.oredenar_origen() @Slot() def ordenar_distancia(self): self.paqueteria.ordenar_distancia() @Slot() def abrir(self): file = QFileDialog.getOpenFileName(self, 'Abrir archivo', '.', 'JSON(*.json)') self.paqueteria.recuperar(file[0]) @Slot() def mostrar(self): #self.paqueteria.mostrar() for paquete in self.paqueteria.lista: self.ui.plainTextEdit.insertPlainText(str(paquete)) @Slot() def guardar(self): file = QFileDialog.getSaveFileName(self, 'Guardar Archivo...', '.', 'JSON (*.json)') print(file) self.paqueteria.guardar(file[0]) @Slot() def click(self): id = self.ui.lineEdit.text() origen = self.ui.lineEdit_2.text() destino = self.ui.lineEdit_3.text() distancia = self.ui.lineEdit_4.text() peso = self.ui.lineEdit_5.text() print(id, origen, destino, distancia, peso) paquete = Paquete() paquete.id = id paquete.origen = origen paquete.destino = destino paquete.distancia = distancia paquete.peso = peso self.paqueteria.agregar(paquete) msg = QMessageBox.information( self, 'Exito', 'Se agrego paquete con exito' ) #Ventana de mensaje de la libreria QMessageBox self.ui.lineEdit.clear() #Limpiar campos self.ui.lineEdit_2.clear() self.ui.lineEdit_3.clear() self.ui.lineEdit_4.clear() self.ui.lineEdit_5.clear()
class DynamicView(QGraphicsView): viewChanged = Signal(QRect, float, int, int) def __init__(self, image, parent=None): super(DynamicView, self).__init__(parent) self.scene = QGraphicsScene() self.scene.setBackgroundBrush(Qt.darkGray) self.setScene(self.scene) self.set_image(image) self.setRenderHint(QPainter.SmoothPixmapTransform) self.setDragMode(QGraphicsView.ScrollHandDrag) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.ZOOM_STEP = 0.2 self.mouse_pressed = False self.next_fit = False self.fit_scale = 0 self.zoom_fit() def set_image(self, image): if type(image) is QPixmap: pixmap = image elif type(image) is QImage: pixmap = QPixmap.fromImage(image) elif type(image) is np.ndarray: pixmap = QPixmap.fromImage(mat2img(image)) else: raise TypeError( self.tr('DynamicView.set_image: Unsupported type: {}'.format( type(image)))) if not self.scene.items(): self.scene.addPixmap(pixmap) else: self.scene.items()[0].setPixmap(pixmap) self.scene.setSceneRect(QRectF(pixmap.rect())) def zoom_full(self): self.set_scaling(1) self.next_fit = True self.notify_change() def zoom_fit(self): self.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) self.fit_scale = self.matrix().m11() if self.fit_scale > 1: self.fit_scale = 1 self.zoom_full() else: self.next_fit = False self.notify_change() def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.mouse_pressed = True QGraphicsView.mousePressEvent(self, event) def mouseMoveEvent(self, event): QGraphicsView.mouseMoveEvent(self, event) if self.mouse_pressed: self.notify_change() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.mouse_pressed = False QGraphicsView.mouseReleaseEvent(self, event) def mouseDoubleClickEvent(self, event): if event.button() == Qt.LeftButton: if self.next_fit: self.zoom_fit() else: self.zoom_full() QGraphicsView.mouseDoubleClickEvent(self, event) def wheelEvent(self, event): if event.delta() > 0: self.change_zoom(+1) else: self.change_zoom(-1) def resizeEvent(self, event): # FIXME: Se la finestra viene massimizzata, il valore di fit_scale non si aggiorna if self.matrix().m11() <= self.fit_scale: self.zoom_fit() else: self.notify_change() QGraphicsView.resizeEvent(self, event) def change_zoom(self, direction): level = math.log2(self.matrix().m11()) if direction > 0: level += self.ZOOM_STEP else: level -= self.ZOOM_STEP scaling = 2**level if scaling < self.fit_scale: scaling = self.fit_scale self.next_fit = False elif scaling > 1: # scaling = 1 if scaling > 4: scaling = 4 self.next_fit = True self.set_scaling(scaling) self.notify_change() def set_scaling(self, scaling): matrix = QMatrix() matrix.scale(scaling, scaling) self.setMatrix(matrix) def change_view(self, _, new_scaling, new_horiz, new_vert): old_factor = self.matrix().m11() old_horiz = self.horizontalScrollBar().value() old_vert = self.verticalScrollBar().value() if new_scaling != old_factor or new_horiz != old_horiz or new_vert != old_vert: self.set_scaling(new_scaling) self.horizontalScrollBar().setValue(new_horiz) self.verticalScrollBar().setValue(new_vert) self.notify_change() def notify_change(self): scene_rect = self.get_rect() horiz_scroll = self.horizontalScrollBar().value() vert_scroll = self.verticalScrollBar().value() zoom_factor = self.matrix().m11() self.viewChanged.emit(scene_rect, zoom_factor, horiz_scroll, vert_scroll) def get_rect(self): top_left = self.mapToScene(0, 0).toPoint() if top_left.x() < 0: top_left.setX(0) if top_left.y() < 0: top_left.setY(0) view_size = self.viewport().size() bottom_right = self.mapToScene(view_size.width(), view_size.height()).toPoint() image_size = self.sceneRect().toRect() if bottom_right.x() >= image_size.width(): bottom_right.setX(image_size.width() - 1) if bottom_right.y() >= image_size.height(): bottom_right.setY(image_size.height() - 1) return QRect(top_left, bottom_right)
class QTraceViewer(QWidget): TAG_SPACING = 50 LEGEND_X = -50 LEGEND_Y = 0 LEGEND_WIDTH = 10 TRACE_FUNC_X = 0 TRACE_FUNC_Y = 0 TRACE_FUNC_WIDTH = 50 TRACE_FUNC_MINHEIGHT = 1000 MARK_X = LEGEND_X MARK_WIDTH = TRACE_FUNC_X - LEGEND_X + TRACE_FUNC_WIDTH MARK_HEIGHT = 1 def __init__(self, workspace, disasm_view, parent=None): super().__init__(parent=parent) self.workspace = workspace self.disasm_view = disasm_view self.view = None self.scene = None self.mark = None self.curr_position = 0 self._use_precise_position = False self._init_widgets() self.trace.am_subscribe(self._on_set_trace) self.selected_ins.am_subscribe(self._on_select_ins) self.view.installEventFilter(self) # # Forwarding properties # @property def trace(self): return self.workspace.instance.trace @property def selected_ins(self): return self.disasm_view.infodock.selected_insns def _init_widgets(self): self.view = QGraphicsView() self.scene = QGraphicsScene() self.view.setScene(self.scene) self._reset() layout = QHBoxLayout() layout.addWidget(self.view) layout.setContentsMargins(0, 0, 0, 0) layout.setAlignment(self.view, Qt.AlignLeft) self.setLayout(layout) def _reset(self): self.scene.clear() #clear items self.mark = None self.legend = None self.legend_height = 0 self.trace_func = QGraphicsItemGroup() self.scene.addItem(self.trace_func) self.hide() def _on_set_trace(self, **kwargs): self._reset() if self.trace.am_obj is not None: l.debug('minheight: %d, count: %d', self.TRACE_FUNC_MINHEIGHT, self.trace.count) if self.trace.count <= 0: l.warning( "No valid addresses found in trace to show. Check base address offsets?" ) self.trace.am_obj = None self.trace.am_event() return if self.TRACE_FUNC_MINHEIGHT < self.trace.count * 15: self.trace_func_unit_height = 15 show_func_tag = True else: self.trace_func_unit_height = self.TRACE_FUNC_MINHEIGHT / self.trace.count show_func_tag = True self.legend_height = int(self.trace.count * self.trace_func_unit_height) self._show_trace_func(show_func_tag) self._show_legend() self._set_mark_color() self.scene.setSceneRect(self.scene.itemsBoundingRect()) #resize self.setFixedWidth(self.scene.itemsBoundingRect().width()) self.view.setFixedWidth(self.scene.itemsBoundingRect().width()) self.show() def _on_select_ins(self, **kwargs): if self.trace == None: return if self.mark is not None: for i in self.mark.childItems(): self.mark.removeFromGroup(i) self.scene.removeItem(i) self.scene.removeItem(self.mark) self.mark = QGraphicsItemGroup() self.scene.addItem(self.mark) if self.selected_ins: addr = next(iter(self.selected_ins)) positions = self.trace.get_positions(addr) if positions: #if addr is in list of positions if not self._use_precise_position: #handle case where insn was selected from disas view self.curr_position = positions[0] - self.trace.count for p in positions: color = self._get_mark_color(p, self.trace.count) y = self._get_mark_y(p, self.trace.count) if p == self.trace.count + self.curr_position: #add thicker line for 'current' mark self.mark.addToGroup( self.scene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT * 4, QPen(QColor('black')), QBrush(color))) else: self.mark.addToGroup( self.scene.addRect(self.MARK_X, y, self.MARK_WIDTH, self.MARK_HEIGHT, QPen(color), QBrush(color))) #y = self._get_mark_y(positions[0], self.trace.count) #self.view.verticalScrollBar().setValue(y - 0.5 * self.view.size().height()) self.scene.update() #force redraw of the scene self.scroll_to_position(self.curr_position) def scroll_to_position(self, position): relative_pos = self.trace.count + position y_offset = self._get_mark_y(relative_pos, self.trace.count) scrollValue = 0 if y_offset > 0.5 * self.view.size().height(): scrollValue = y_offset - 0.5 * self.view.size().height() scrollValue = min(scrollValue, self.view.verticalScrollBar().maximum()) self.view.verticalScrollBar().setValue(scrollValue) self._use_precise_position = False def jump_next_insn(self): if self.curr_position + self.trace.count < self.trace.count - 1: #for some reason indexing is done backwards self.curr_position += 1 self._use_precise_position = True func_name = self.trace.trace_func[self.curr_position].func_name func = self._get_func_from_func_name(func_name) bbl_addr = self.trace.trace_func[self.curr_position].bbl_addr self._jump_bbl(func, bbl_addr) def jump_prev_insn(self): if self.curr_position + self.trace.count > 0: self.curr_position -= 1 self._use_precise_position = True func_name = self.trace.trace_func[self.curr_position].func_name func = self._get_func_from_func_name(func_name) bbl_addr = self.trace.trace_func[self.curr_position].bbl_addr self._jump_bbl(func, bbl_addr) def eventFilter(self, object, event): #specifically to catch arrow keys # more elegant solution to link w/ self.view's scroll bar keypressevent? if event.type() == QEvent.Type.KeyPress: if not (event.modifiers() & Qt.ShiftModifier): #shift + arrowkeys return False key = event.key() if key == Qt.Key_Up or key == Qt.Key_Left: self.jump_prev_insn() elif key == Qt.Key_Down or key == Qt.Key_Right: self.jump_next_insn() return True return False # pass through all other events def mousePressEvent(self, event): button = event.button() pos = self._to_logical_pos(event.pos()) if button == Qt.LeftButton and self._at_legend(pos): func = self._get_func_from_y(pos.y()) bbl_addr = self._get_bbl_from_y(pos.y()) self._use_precise_position = True self.curr_position = self._get_position(pos.y()) self._jump_bbl(func, bbl_addr) def _jump_bbl(self, func, bbl_addr): all_insn_addrs = self.workspace.instance.project.factory.block( bbl_addr).instruction_addrs # TODO: replace this with am_events perhaps? self.workspace.on_function_selected(func) self.selected_ins.clear() self.selected_ins.update(all_insn_addrs) self.selected_ins.am_event() # TODO: this ought to happen automatically as a result of the am_event self.disasm_view.current_graph.show_instruction(bbl_addr) def _get_mark_color(self, i, total): relative_gradient_pos = i * 1000 // total return self.legend_img.pixelColor(self.LEGEND_WIDTH // 2, relative_gradient_pos) def _get_mark_y(self, i, total): return self.TRACE_FUNC_Y + self.trace_func_unit_height * i def _show_trace_func(self, show_func_tag): x = self.TRACE_FUNC_X y = self.TRACE_FUNC_Y prev_name = None for position in self.trace.trace_func: bbl_addr = position.bbl_addr func_name = position.func_name l.debug('Draw function %x, %s', bbl_addr, func_name) color = self.trace.get_func_color(func_name) self.trace_func.addToGroup( self.scene.addRect(x, y, self.TRACE_FUNC_WIDTH, self.trace_func_unit_height, QPen(color), QBrush(color))) if show_func_tag is True and func_name != prev_name: tag = self.scene.addText(func_name, QFont("Source Code Pro", 7)) tag.setPos(x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y - tag.boundingRect().height() // 2) self.trace_func.addToGroup(tag) anchor = self.scene.addLine( self.TRACE_FUNC_X + self.TRACE_FUNC_WIDTH, y, x + self.TRACE_FUNC_WIDTH + self.TAG_SPACING, y) self.trace_func.addToGroup(anchor) prev_name = func_name y += self.trace_func_unit_height def _make_legend_gradient(self, x1, y1, x2, y2): gradient = QLinearGradient(x1, y1, x2, y2) gradient.setColorAt(0.0, Qt.red) gradient.setColorAt(0.4, Qt.yellow) gradient.setColorAt(0.6, Qt.green) gradient.setColorAt(0.8, Qt.blue) gradient.setColorAt(1.0, Qt.darkBlue) return gradient def _show_legend(self): pen = QPen(Qt.transparent) gradient = self._make_legend_gradient( self.LEGEND_X, self.LEGEND_Y, self.LEGEND_X, self.LEGEND_Y + self.legend_height) brush = QBrush(gradient) self.legend = self.scene.addRect(self.LEGEND_X, self.LEGEND_Y, self.LEGEND_WIDTH, self.legend_height, pen, brush) reference_gradient = self._make_legend_gradient( 0, 0, self.LEGEND_WIDTH, 1000) base_img = QImage(self.LEGEND_WIDTH, 1000, QImage.Format.Format_ARGB32) p = QPainter(base_img) p.fillRect(base_img.rect(), reference_gradient) self.legend_img = base_img #reference shade def _set_mark_color(self): for p in range(self.trace.count): color = self._get_mark_color(p, self.trace.count) self.trace.set_mark_color(p, color) def _at_legend(self, pos): x = pos.x() y = pos.y() if self.TRACE_FUNC_X + self.LEGEND_X < x < self.view.width() and \ self.TRACE_FUNC_Y < y < self.TRACE_FUNC_Y + self.legend_height: return True else: return False def _to_logical_pos(self, pos): x_offset = self.view.horizontalScrollBar().value() y_offset = self.view.verticalScrollBar().value() return QPoint(pos.x() + x_offset, pos.y() + y_offset) def _get_position(self, y): y_relative = y - self.legend_height return int(y_relative // self.trace_func_unit_height) def _get_bbl_from_y(self, y): position = self._get_position(y) return self.trace.get_bbl_from_position(position) def _get_func_from_func_name(self, func_name): return self.workspace.instance.kb.functions.function(name=func_name) def _get_func_from_y(self, y): position = self._get_position(y) func_name = self.trace.get_func_name_from_position(position) return self._get_func_from_func_name(func_name)
def __init__(self, main_window, parent_script, config=None): super(Flow, self).__init__() # SHORTCUTS place_new_node_shortcut = QShortcut(QKeySequence('Shift+P'), self) place_new_node_shortcut.activated.connect( self.place_new_node_by_shortcut) move_selected_nodes_left_shortcut = QShortcut( QKeySequence('Shift+Left'), self) move_selected_nodes_left_shortcut.activated.connect( self.move_selected_nodes_left) move_selected_nodes_up_shortcut = QShortcut(QKeySequence('Shift+Up'), self) move_selected_nodes_up_shortcut.activated.connect( self.move_selected_nodes_up) move_selected_nodes_right_shortcut = QShortcut( QKeySequence('Shift+Right'), self) move_selected_nodes_right_shortcut.activated.connect( self.move_selected_nodes_right) move_selected_nodes_down_shortcut = QShortcut( QKeySequence('Shift+Down'), self) move_selected_nodes_down_shortcut.activated.connect( self.move_selected_nodes_down) select_all_shortcut = QShortcut(QKeySequence('Ctrl+A'), self) select_all_shortcut.activated.connect(self.select_all) copy_shortcut = QShortcut(QKeySequence.Copy, self) copy_shortcut.activated.connect(self.copy) cut_shortcut = QShortcut(QKeySequence.Cut, self) cut_shortcut.activated.connect(self.cut) paste_shortcut = QShortcut(QKeySequence.Paste, self) paste_shortcut.activated.connect(self.paste) # UNDO/REDO self.undo_stack = QUndoStack(self) self.undo_action = self.undo_stack.createUndoAction(self, 'undo') self.undo_action.setShortcuts(QKeySequence.Undo) self.redo_action = self.undo_stack.createRedoAction(self, 'redo') self.redo_action.setShortcuts(QKeySequence.Redo) undo_shortcut = QShortcut(QKeySequence.Undo, self) undo_shortcut.activated.connect(self.undo_activated) redo_shortcut = QShortcut(QKeySequence.Redo, self) redo_shortcut.activated.connect(self.redo_activated) # GENERAL ATTRIBUTES self.parent_script = parent_script self.all_node_instances: [NodeInstance] = [] self.all_node_instance_classes = main_window.all_node_instance_classes # ref self.all_nodes = main_window.all_nodes # ref self.gate_selected: PortInstanceGate = None self.dragging_connection = False self.ignore_mouse_event = False # for stylus - see tablet event self.last_mouse_move_pos: QPointF = None self.node_place_pos = QPointF() self.left_mouse_pressed_in_flow = False self.mouse_press_pos: QPointF = None self.tablet_press_pos: QPointF = None self.auto_connection_gate = None # stores the gate that we may try to auto connect to a newly placed NI self.panning = False self.pan_last_x = None self.pan_last_y = None self.current_scale = 1 self.total_scale_div = 1 # SETTINGS self.algorithm_mode = Flow_AlgorithmMode() self.viewport_update_mode = Flow_ViewportUpdateMode() # CREATE UI scene = QGraphicsScene(self) scene.setItemIndexMethod(QGraphicsScene.NoIndex) scene.setSceneRect(0, 0, 10 * self.width(), 10 * self.height()) self.setScene(scene) self.setCacheMode(QGraphicsView.CacheBackground) self.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) self.setRenderHint(QPainter.Antialiasing) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setDragMode(QGraphicsView.RubberBandDrag) scene.selectionChanged.connect(self.selection_changed) self.setAcceptDrops(True) self.centerOn( QPointF(self.viewport().width() / 2, self.viewport().height() / 2)) # NODE CHOICE WIDGET self.node_choice_proxy = FlowProxyWidget(self) self.node_choice_proxy.setZValue(1000) self.node_choice_widget = NodeChoiceWidget( self, main_window.all_nodes) # , main_window.node_images) self.node_choice_proxy.setWidget(self.node_choice_widget) self.scene().addItem(self.node_choice_proxy) self.hide_node_choice_widget() # ZOOM WIDGET self.zoom_proxy = FlowProxyWidget(self) self.zoom_proxy.setFlag(QGraphicsItem.ItemIgnoresTransformations, True) self.zoom_proxy.setZValue(1001) self.zoom_widget = FlowZoomWidget(self) self.zoom_proxy.setWidget(self.zoom_widget) self.scene().addItem(self.zoom_proxy) self.set_zoom_proxy_pos() # STYLUS self.stylus_mode = '' self.current_drawing = None self.drawing = False self.drawings = [] self.stylus_modes_proxy = FlowProxyWidget(self) self.stylus_modes_proxy.setFlag( QGraphicsItem.ItemIgnoresTransformations, True) self.stylus_modes_proxy.setZValue(1001) self.stylus_modes_widget = FlowStylusModesWidget(self) self.stylus_modes_proxy.setWidget(self.stylus_modes_widget) self.scene().addItem(self.stylus_modes_proxy) self.set_stylus_proxy_pos() self.setAttribute(Qt.WA_TabletTracking) # DESIGN THEME Design.flow_theme_changed.connect(self.theme_changed) if config: config: dict # algorithm mode if config.keys().__contains__('algorithm mode'): if config['algorithm mode'] == 'data flow': self.parent_script.widget.ui.algorithm_data_flow_radioButton.setChecked( True) self.algorithm_mode.mode_data_flow = True else: # 'exec flow' self.parent_script.widget.ui.algorithm_exec_flow_radioButton.setChecked( True) self.algorithm_mode.mode_data_flow = False # viewport update mode if config.keys().__contains__('viewport update mode'): if config['viewport update mode'] == 'sync': self.parent_script.widget.ui.viewport_update_mode_sync_radioButton.setChecked( True) self.viewport_update_mode.sync = True else: # 'async' self.parent_script.widget.ui.viewport_update_mode_async_radioButton.setChecked( True) self.viewport_update_mode.sync = False node_instances = self.place_nodes_from_config(config['nodes']) self.connect_nodes_from_config(node_instances, config['connections']) if list(config.keys()).__contains__( 'drawings' ): # not all (old) project files have drawings arr self.place_drawings_from_config(config['drawings']) self.undo_stack.clear()
class HumanVisualizationWidget(QGraphicsView): def __init__(self, parent=None): super(HumanVisualizationWidget, self).__init__(parent) self._scene = QGraphicsScene(self) self.setScene(self._scene) # circle = QGraphicsEllipseItem( 10, 10, 10 ,10) # self._scene.addItem(circle) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self._boxes = [] self._humans = {} def load_inner_model(self, file): import xml.etree.cElementTree as ET tree = ET.ElementTree(file=file) root = tree.getroot() transforms = tree.findall(".//transform[plane]") walls = {} for trans in transforms: if 'id' in trans.attrib and 'pared' in trans.attrib['id']: print("Pared:", trans.attrib['id']) current_wall = [0] * 7 # "wall5": [x, y, width, height, posx, posy, 0] if 'tx' in trans.attrib: # print trans.attrib['tx'] current_wall[4] = int(float(trans.attrib['tx'])) if 'ty' in trans.attrib: # print trans.attrib['ty'] current_wall[5] = int(float(trans.attrib['tz'])) # current_wall = planes = trans.findall('plane') for plane in planes: if 'id' in plane.attrib and 'muro' in plane.attrib['id']: # if 'nx' in plane.attrib: # print plane.attrib['nx'] # if 'nz' in plane.attrib: # print plane.attrib['nz'] if 'size' in plane.attrib: # print int(float(plane.attrib['size'].split(',')[0]) current_wall[2] = int( float(plane.attrib['size'].split(',')[0])) / 2. # print int(float(plane.attrib['size'].split(',')[1]) current_wall[3] = int( float(plane.attrib['size'].split(',')[1])) / 2. if current_wall[2] < current_wall[3]: current_wall[2] = 200 else: current_wall[3] = 200 walls[trans.attrib['id']] = current_wall for id in sorted(walls.keys()): object = walls[id] # rect = QRectF(-float(object[2]) / 2, -float(object[3]) / 2, float(object[2]), float(object[3])) rect = QRectF(0, 0, float(object[2]), float(object[3])) border = QPen(QColor("black")) fill = QBrush(QColor("black")) box = self._scene.addRect(rect, border, fill) self._scene.addEllipse( QRectF(float(object[4]), float(object[5]), 10, 10), QPen(QColor("green")), QBrush(QColor("green"))) box.setPos(float(object[4]), float(object[5])) box.setRotation(float(object[6])) self._boxes.append(box) self._scene.update() QApplication.processEvents() sleep(1) def load_custom_json_world(self, file): if not os.path.isfile(file): print("Error reading world file, check config params:", file) return False with open(file, "r") as read_file: json_data = json.load(read_file) types_colors = { "tables": "SandyBrown", "roundTables": "Khaki", "walls": "Brown", "points": "Blue" } self.clear() for type, color in types_colors.items(): if type in json_data: tables = json_data[type] for object in tables.values(): rect = QRectF(-float(object[2]) / 2, -float(object[3]) / 2, float(object[2]), float(object[3])) border = QPen(QColor(color)) fill = QBrush(QColor(color)) if type == "roundTables": box = self._scene.addEllipse(rect, border, fill) else: box = self._scene.addRect(rect, border, fill) box.setPos(float(object[4]), float(object[5])) box.setRotation(float(object[6])) self._boxes.append(box) def load_json_world(self, file): if not os.path.isfile(file): print("Error reading world file, check config params:", file) return False with open(file, "r") as read_file: json_data = json.load(read_file) polygon_points = [] paths_count = 0 for item in json_data: if 'json_geometry' in item: geometry = item['json_geometry'] if geometry['type'] == 'Polygon': for coord in geometry['coordinates'][0]: if isinstance(coord, list) and ( (isinstance(coord, list) and len(coord) == 2) or (len(coord) == 3 and coord[3] == 0)): current_point = QPointF(coord[0], coord[1]) polygon_points.append(current_point) else: print("Unknown coord", geometry["coordinates"][0]) polygon = QPolygonF(polygon_points) path = QPainterPath() path.addPolygon(polygon) contour = QGraphicsPathItem(path) # r = lambda: random.randint(0, 255) # next_color = '#%02X%02X%02X' % (r(), r(), r()) contour.setPen(QPen(QColor("red"), 0.1)) contour.setBrush(QBrush(Qt.transparent)) # if paths_count == 4: print(item['json_featuretype']) self._scene.addItem(contour) paths_count += 1 self.update() def clear(self): for human in self._humans.values(): self._scene.removeItem(human) self._humans = {} # self._scene.setSceneRect(QRectF(0,0,400,400)) def resizeEvent(self, event): # skip initial entry self.own_resize() super(HumanVisualizationWidget, self).resizeEvent(event) def own_resize(self): self.fitInView(self._scene.itemsBoundingRect(), Qt.KeepAspectRatio) self._scene.setSceneRect(self._scene.itemsBoundingRect()) def add_human_by_pos(self, id, pos): x, y = pos human = QGraphicsEllipseItem(0, 0, 200, 200) self._scene.addItem(human) human.setBrush(QBrush(Qt.black, style=Qt.SolidPattern)) human_text = QGraphicsTextItem(str(pos)) font = QFont("Helvetica [Cronyx]", 40, QFont.Bold) human_text.setFont(font) human_text.setParentItem(human) human.setPos(pos[0], pos[1]) self._humans[id] = human human.setZValue(30) def move_human(self, id, pos): x, y = pos human = self._humans[id] human.setPos(x, y) def set_human_color(self, id, color): if id in self._humans: self._humans[id].setBrush(color)
class TestGUI(QMainWindow): def __init__(self): self.app = QApplication(sys.argv) ui_file = QFile("testgui.ui") ui_file.open(QFile.ReadOnly) loader = QUiLoader() self.window = loader.load(ui_file) ui_file.close() self.scene_gt = QGraphicsScene() self.scene_gt.setSceneRect(-2000, -3000, 4000, 6000) self.view_gt = QGraphicsView(self.scene_gt, self.window.scene_gt) self.view_gt.scale(-0.1, 0.1) self.view_gt.resize(self.window.scene_gt.geometry().width(), self.window.scene_gt.geometry().height()) self.personPos_gt = self.scene_gt.addEllipse( QRectF(-200, -200, 400, 400), QPen(QColor("LightGreen")), QBrush(QColor("LightGreen"))) self.personPos_gt.setFlag(QGraphicsItem.ItemIsMovable) self.personPos_gt.setPos(0, 0) self.personAng_gt = self.scene_gt.addRect(QRectF(-10, 0, 20, 300), QPen(QColor("Green")), QBrush(QColor("Green"))) self.personAng_gt.setFlag(QGraphicsItem.ItemIsMovable) self.personAng_gt.setPos(0, 0) self.scene_cc = QGraphicsScene() self.scene_cc.setSceneRect(-2000, -3000, 4000, 6000) self.view_cc = QGraphicsView(self.scene_cc, self.window.scene_cc) self.view_cc.scale(-0.1, 0.1) self.view_cc.resize(self.window.scene_cc.geometry().width(), self.window.scene_cc.geometry().height()) self.personPos_cc = self.scene_cc.addEllipse( QRectF(-200, -200, 400, 400), QPen(QColor("Red")), QBrush(QColor("Red"))) self.personPos_cc.setFlag(QGraphicsItem.ItemIsMovable) self.personPos_cc.setPos(0, 0) self.personAng_cc = self.scene_cc.addRect(QRectF(-10, 0, 20, 300), QPen(QColor("Black")), QBrush(QColor("Black"))) self.personAng_cc.setFlag(QGraphicsItem.ItemIsMovable) self.personAng_cc.setPos(0, 0) self.scene_nn = QGraphicsScene() self.scene_nn.setSceneRect(-2000, -3000, 4000, 6000) self.view_nn = QGraphicsView(self.scene_nn, self.window.scene_nn) self.view_nn.scale(-0.1, 0.1) self.view_nn.resize(self.window.scene_nn.geometry().width(), self.window.scene_nn.geometry().height()) self.personPos_nn = self.scene_nn.addEllipse( QRectF(-200, -200, 400, 400), QPen(QColor("LightBlue")), QBrush(QColor("LightBlue"))) self.personPos_nn.setFlag(QGraphicsItem.ItemIsMovable) self.personPos_nn.setPos(0, 0) self.personAng_nn = self.scene_nn.addRect(QRectF(-10, 0, 20, 300), QPen(QColor("Blue")), QBrush(QColor("Blue"))) self.personAng_nn.setFlag(QGraphicsItem.ItemIsMovable) self.personAng_nn.setPos(0, 0) self.loadData(sys.argv[1]) self.window.instantScrollBar.valueChanged.connect(self.changeInstant) self.it = 0 self.timer = QTimer() self.timer.timeout.connect(self.compute) self.timer.start(150) self.window.show() r = self.app.exec_() sys.exit(r) def loadData(self, filename): test_dataset = graph_generator.CalibrationDataset(filename, 'run', '1') with open(sys.argv[1], 'r') as f: raw = f.read() raw = list(raw) raws = ''.join(raw) data = json.loads(raws)['data_set'] model = trackerapi.TrackerAPI('.', test_dataset) self.x_gt = [] self.x_cc = [] self.x_nn = [] self.z_gt = [] self.z_cc = [] self.z_nn = [] self.a_gt = [] self.a_cc = [] self.a_nn = [] try: with open('kk', 'rb') as f: results = pickle.load(f) except: results = [x for x in model.predict()] with open('kk', 'wb') as f: pickle.dump(results, f, pickle.HIGHEST_PROTOCOL) eX_cc = [] eZ_cc = [] eA_cc = [] eX_nn = [] eZ_nn = [] eA_nn = [] self.trajectory = [] s = 0 ang_prev = 0 for i in range(int(len(results))): n_joints = 0 for cam in range(len(data[i]['superbody'])): n_joints += len(data[i]['superbody'][cam]['joints']) if n_joints < 3: continue s += 1 if s < 2 or s % 1 != 0: continue self.x_gt.append(data[i]['superbody'][0]['ground_truth'][0]) self.z_gt.append(data[i]['superbody'][0]['ground_truth'][2]) self.a_gt.append(data[i]['superbody'][0]['ground_truth'][3] * 180. / math.pi) self.trajectory.append(QPointF(self.x_gt[-1], self.z_gt[-1])) x_cc = 0 z_cc = 0 ncams = 0 for cam in range(0, len(data[i]['superbody'])): x_cc += data[i]['superbody'][cam]['world'][0] z_cc += data[i]['superbody'][cam]['world'][2] ncams += 1 self.x_cc.append(x_cc / ncams) self.z_cc.append(z_cc / ncams) s_cc = 0 c_cc = 0 ncams = 0 for cam in range(0, len(data[i]['superbody'])): joints = data[i]['superbody'][cam]["joints"] if ("right_shoulder" in joints and "left_shoulder" in joints) or ("right_hip" in joints and "left_hip" in joints): s_cc = math.sin(data[i]['superbody'][cam]['world'][3]) c_cc = math.cos(data[i]['superbody'][cam]['world'][3]) ncams += 1 if ncams > 0: a_cc = math.atan2(s_cc / ncams, c_cc / ncams) ang_prev = a_cc else: a_cc = ang_prev self.a_cc.append(a_cc * 180. / math.pi) self.x_nn.append(results[i][0] * 4000) self.z_nn.append(results[i][2] * 4000) self.a_nn.append( math.atan2(results[i][3] / 0.7, results[i][4] / 0.7) * 180. / math.pi) eX_cc.append(abs(self.x_gt[-1] - self.x_cc[-1])) eZ_cc.append(abs(self.z_gt[-1] - self.z_cc[-1])) eAng = 180 - abs(abs(self.a_gt[-1] - self.a_cc[-1]) - 180) if eAng < 0: eAng = 360 + eAng eA_cc.append(eAng) eX_nn.append(abs(self.x_gt[-1] - self.x_nn[-1].item())) eZ_nn.append(abs(self.z_gt[-1] - self.z_nn[-1].item())) eAng = 180 - abs(abs(self.a_gt[-1] - self.a_nn[-1]) - 180) if eAng < 0: eAng = 360 + eAng eA_nn.append(eAng) array_err_z = np.array(eZ_nn) print("len array error", len(array_err_z)) # self.window.eX_cc.display(np.array(eX_cc).mean()) # self.window.eZ_cc.display(np.array(eZ_cc).mean()) # self.window.eA_cc.display(np.array(eA_cc).mean()) # self.window.eX_nn.display(np.array(eX_nn).mean()) # self.window.eZ_nn.display(np.array(eZ_nn).mean()) # self.window.eA_nn.display(np.array(eA_nn).mean()) self.scene_gt.addPolygon(self.trajectory, QPen(QColor("Black"))) self.scene_cc.addPolygon(self.trajectory, QPen(QColor("Black"))) self.scene_nn.addPolygon(self.trajectory, QPen(QColor("Black"))) self.window.instantScrollBar.setMaximum(len(self.a_gt) - 1) def compute(self): if self.window.playButton.isChecked(): if self.it >= len(self.x_gt): self.it = 0 self.movePerson() self.it += 1 self.window.instantScrollBar.setValue(self.it) def changeInstant(self, instant): self.it = instant self.movePerson() def movePerson(self): self.personPos_gt.setPos(self.x_gt[self.it], self.z_gt[self.it]) self.personAng_gt.setPos(self.x_gt[self.it], self.z_gt[self.it]) self.personAng_gt.setRotation(self.a_gt[self.it]) self.personPos_cc.setPos(self.x_cc[self.it], self.z_cc[self.it]) self.personAng_cc.setPos(self.x_cc[self.it], self.z_cc[self.it]) self.personAng_cc.setRotation(self.a_cc[self.it]) self.personPos_nn.setPos(self.x_nn[self.it], self.z_nn[self.it]) self.personAng_nn.setPos(self.x_nn[self.it], self.z_nn[self.it]) self.personAng_nn.setRotation(self.a_nn[self.it])
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.listaparticulas = ListaParticulas() self.listadistances = ListaDistances() self.ui.pbGuardar.clicked.connect(self.click) self.ui.pbMostrar.clicked.connect(self.mostrar) self.ui.pbLimpiar.clicked.connect(self.clear) self.ui.actionGuardar.triggered.connect(self.guardarArchivo) self.ui.actionAbrir.triggered.connect(self.abrir) self.ui.pbVisualizar.clicked.connect(self.visualizar) self.ui.pbOrdenarDistancia.clicked.connect(self.ordenar_distancia) self.ui.pbOrdenarVelocidad.clicked.connect(self.ordenar_velocidad) self.ui.aVerPuntos.triggered.connect(self.ver_puntos) self.ui.aPuntosCercanos.triggered.connect(self.puntos_cercanos) self.ui.pbMostrarGrafo.clicked.connect(self.mostrarGrafo) self.ui.aRecorridoProfundidad.triggered.connect(self.recorridoProfundidad) self.ui.aRecorridoAnchura.triggered.connect(self.recorridoAnchura) self.ui.aPrim.triggered.connect(self.prim) self.ui.aKruskal.triggered.connect(self.kruskal) self.ui.aMostrar.triggered.connect(self.mostrarGrafoOriginal) @Slot() def mostrar(self): distance = Distance() #self.listaparticulas.mostrar() for particula in self.listaparticulas.lista: self.ui.plainTextEdit.insertPlainText(str(particula)) v1 = float(int(particula.destinoX) - int(particula.origenX)) v2 = float(int(particula.destinoY) - int(particula.origenY)) distancia = float(math.sqrt((v1) ** 2 + (v2) ** 2)) self.ui.plainTextEdit.insertPlainText(" -> Distancia: " + str(distancia) + '\n\n') distance.id = distancia distance.colorR = particula.colorR distance.colorG = particula.colorG distance.colorB = particula.colorB self.listadistances.agregar(distance) @Slot() def visualizar(self): self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 500, 500) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setColor(QColor(0, 0, 0)) self.pen.setWidth(3) self.scene.addLine(0, 0, 499, 0, self.pen) self.scene.addLine(0, 499, 499, 499, self.pen) self.scene.addLine(0, 0, 0, 499, self.pen) self.scene.addLine(499, 0, 499, 499, self.pen) for particula in self.listaparticulas.lista: self.pen.setColor(QColor(particula.colorR, particula.colorG, particula.colorB)) self.scene.addLine(particula.origenX, particula.origenY, particula.destinoX, particula.destinoY, self.pen) self.scene.addEllipse(particula.origenX, particula.origenY, 5, 5, self.pen, QBrush(QColor(50, 100, 0))) self.scene.addEllipse(particula.destinoX, particula.destinoY, 5, 5, self.pen, QBrush(QColor(100, 0, 0))) @Slot() def click(self): id = self.ui.leID.text() origenX = self.ui.leORIGENx.text() origenY = self.ui.leORIGENy.text() destinoX = self.ui.leDESTINOx.text() destinoY = self.ui.leDESTINOy.text() colorR = self.ui.leCOLORr.text() colorG = self.ui.leCOLORg.text() colorB = self.ui.leCOLORb.text() velocidad = self.ui.leVELOCIDAD.text() v1= float(int(destinoX)-int(origenX)) v2 = float(int(destinoY)-int(origenY)) distancia = float(math.sqrt((v1)**2 + (v2)**2)) print(id,origenX,origenY,destinoX,destinoY,colorR,colorG,colorB,velocidad, distancia) particula = Particula() particula.id = int(id) particula.origenX = int(origenX) particula.origenY = int(origenY) particula.destinoX = int(destinoX) particula.destinoY = int(destinoY) particula.colorR = int(colorR) particula.colorG = int(colorG) particula.colorB = int(colorB) particula.velocidad = int(velocidad) self.ui.lcdDistancia.display(distancia) self.listaparticulas.agregar(particula) msg = QMessageBox.information(self,'Éxito', 'Se agregó paquete con éxito') #clear() @Slot() def clear(self): self.ui.leID.clear() self.ui.leORIGENx.clear() self.ui.leORIGENy.clear() self.ui.leDESTINOx.clear() self.ui.leDESTINOy.clear() self.ui.leCOLORr.clear() self.ui.leCOLORg.clear() self.ui.leCOLORb.clear() self.ui.leVELOCIDAD.clear() @Slot() def abrir(self): print('abrir') file = QFileDialog.getOpenFileName(self, 'Abrir archivo', '.', 'JSON (*.json)') self.listaparticulas.recuperar(file[0]) @Slot() def ordenar_distancia(self): print('click') self.listaparticulas.ordenar_distancia() self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 400, 1000) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setColor(QColor(0,0,0)) self.pen.setWidth(3) i = 1 for particula in self.listaparticulas.lista: self.pen.setColor(QColor(particula.colorR, particula.colorG, particula.colorB)) v1 = float(int(particula.destinoX) - int(particula.origenX)) v2 = float(int(particula.destinoY) - int(particula.origenY)) distancia = float(math.sqrt((v1) ** 2 + (v2) ** 2)) self.scene.addLine(0, i, distancia, i, self.pen) i = i+1 @Slot() def ordenar_velocidad(self): print('click') self.listaparticulas.ordenar_velocidad() self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 400, 1000) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setColor(QColor(0,0,0)) self.pen.setWidth(3) i = 1 for particula in self.listaparticulas.lista: self.pen.setColor(QColor(particula.colorR, particula.colorG, particula.colorB)) self.scene.addLine(0, i, particula.velocidad, i, self.pen) i = i+1 @Slot() def guardarArchivo(self): file = QFileDialog.getSaveFileName(self, 'Guardar archivo...', '.', 'JSON(*.json)') print(file) self.listaparticulas.guardar(file[0]) @Slot() def ver_puntos(self): self.scene = QGraphicsScene() #self.scene.setSceneRect(0, 0, 400, 1000) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setColor(QColor(0, 0, 0)) self.pen.setWidth(3) listaPuntos = list() for particula in self.listaparticulas.lista: self.pen.setColor(QColor(particula.colorR, particula.colorG, particula.colorB)) self.scene.addEllipse(particula.origenX, particula.origenY, 3, 3, self.pen, QBrush(QColor(particula.colorR,particula.colorG, particula.colorB))) self.scene.addEllipse(particula.destinoX, particula.destinoY, 3, 3, self.pen, QBrush(QColor(particula.colorR, particula.colorG, particula.colorB))) origen = (particula.origenX,particula.origenY) destino = (particula.destinoX, particula.destinoY) listaPuntos.append(origen) listaPuntos.append(destino) #print(listaPuntos) @Slot() def puntos_cercanos(self): self.scene = QGraphicsScene() self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setWidth(1) listaPuntos = list() listaColores = list() for particula in self.listaparticulas.lista: self.pen.setColor(QColor(particula.colorR, particula.colorG, particula.colorB)) self.scene.addEllipse(particula.origenX, particula.origenY, 3, 3, self.pen, QBrush(QColor(particula.colorR, particula.colorG, particula.colorB))) self.scene.addEllipse(particula.destinoX, particula.destinoY, 3, 3, self.pen, QBrush(QColor(particula.colorR, particula.colorG, particula.colorB))) origen = (particula.origenX, particula.origenY) destino = (particula.destinoX, particula.destinoY) origenColores = (particula.colorR,particula.colorG, particula.colorB) destinoColores = (particula.colorR, particula.colorG, particula.colorB) listaPuntos.append(origen) listaPuntos.append(destino) listaColores.append(origenColores) listaColores.append(destinoColores) #print(listaColores) #print(listaPuntos) for i in range(0, len(listaPuntos)): auxI = listaPuntos[i] distancia = 1000000000000000 for y in range(0, len(listaPuntos)): auxY = listaPuntos[y] if (auxI[0] != auxY[0] or auxI[1] != auxY[1]): v1 = float(int(auxY[0]) - int(auxI[0])) v2 = float(int(auxY[1]) - int(auxI[1])) distanciaActual = float(math.sqrt((v1) ** 2 + (v2) ** 2)) #print('distancia: ', distanciaActual) if (distanciaActual <= distancia): distancia = distanciaActual colores = listaColores[i-1] auxR = colores[0] auxG = colores[1] auxB = colores[2] x = auxY[0] z = auxY[1] if (y == (len(listaPuntos)-1)): self.pen.setColor(QColor(auxR, auxG, auxB)) #print('ACTUAL: ',auxI[0],auxI[1]) #print('MÁS CERCANO ', x, z) self.pen.setWidth(1) self.scene.addLine(auxI[0], auxI[1], x, z , self.pen) @Slot() def mostrarGrafo(self): grafo = dict() for particula in self.listaparticulas.lista: pOrigen = str(particula.origenX) + ('.') + str(particula.origenY) pDestino = str(particula.destinoX) + ('.') + str(particula.destinoY) v1 = float(int(particula.destinoX) - int(particula.origenX)) v2 = float(int(particula.destinoY) - int(particula.origenY)) distancia = float(math.sqrt((v1) ** 2 + (v2) ** 2)) origen = pOrigen destino = pDestino peso = int(distancia) if origen in grafo: grafo[origen].append((destino, peso)) else: grafo[origen] = [(destino, peso)] if destino in grafo: grafo[destino].append((origen, peso)) else: grafo[destino] = [(origen, peso)] cadena = pprint.pformat(grafo, width=40) self.ui.plainTextEdit.insertPlainText(str(cadena)) @Slot() def recorridoProfundidad(self): grafo = dict() for particula in self.listaparticulas.lista: pOrigen = str(particula.origenX) + ('.') + str(particula.origenY) pDestino = str(particula.destinoX) + ('.') + str(particula.destinoY) origen = pOrigen destino = pDestino if origen in grafo: grafo[origen].append(destino) else: grafo[origen] = [destino] if destino in grafo: grafo[destino].append(origen) else: grafo[destino] = [origen] visitados = [] pila = [] eleccion = self.ui.origenGrafo.text() pila.append(eleccion) if eleccion in grafo.keys(): while pila: eleccion = pila.pop() if eleccion not in visitados: visitados.append(eleccion) for vecino in grafo[eleccion]: if vecino not in visitados: pila.append(vecino) self.ui.plainTextEdit.insertPlainText(str(visitados)) @Slot() def recorridoAnchura(self): grafo = dict() for particula in self.listaparticulas.lista: pOrigen = str(particula.origenX) + ('.') + str(particula.origenY) pDestino = str(particula.destinoX) + ('.') + str(particula.destinoY) origen = pOrigen destino = pDestino if origen in grafo: grafo[origen].append(destino) else: grafo[origen] = [destino] if destino in grafo: grafo[destino].append(origen) else: grafo[destino] = [origen] cadena = pprint.pformat(grafo, width=40) print(cadena) # self.ui.plainTextEdit.insertPlainText(str(cadena)) visitados = [] cola = [] eleccion = self.ui.origenGrafo.text() #eleccion = "72.321" cola.insert(0, eleccion) visitados.append(eleccion) if eleccion in grafo.keys(): while cola: eleccion = cola.pop() if eleccion not in visitados: visitados.append(eleccion) for vecino in grafo[eleccion]: if vecino not in visitados: cola.insert(0, vecino) print("=========Resultados=========") print("Visitados:", visitados) print("Cola:", cola) self.ui.plainTextEdit.insertPlainText(str(visitados)) # os.system("pause") else: print("No existe") @Slot() def prim(self): grafo = dict() for particula in self.listaparticulas.lista: pOrigen = str(particula.origenX) + ('.') + str(particula.origenY) pDestino = str(particula.destinoX) + ('.') + str(particula.destinoY) v1 = float(int(particula.destinoX) - int(particula.origenX)) v2 = float(int(particula.destinoY) - int(particula.origenY)) distancia = float(math.sqrt((v1) ** 2 + (v2) ** 2)) origen = pOrigen destino = pDestino peso = int(distancia) if origen in grafo: grafo[origen].append((destino, peso)) else: grafo[origen] = [(destino, peso)] if destino in grafo: grafo[destino].append((origen, peso)) else: grafo[destino] = [(origen, peso)] cadena = pprint.pformat(grafo, width=40) #print(cadena) visitados = [] grafoResultante = dict() colaPrioridad = [] eleccion = self.ui.origenGrafo.text() #eleccion = "400.200" visitados.append(eleccion) for vecino in grafo[eleccion]: adya = (eleccion,) + vecino if adya not in colaPrioridad: colaPrioridad.insert(0, adya) while len(colaPrioridad) != 0: aux = 10000000000000 for adyacente in colaPrioridad: if adyacente[1] not in visitados: if adyacente[0] == visitados[-1]: pesoD = adyacente[2] if pesoD < aux: aux = pesoD eliminado = adyacente if len(colaPrioridad) != 0: if eliminado in colaPrioridad: colaPrioridad.remove(eliminado) else: colaPrioridad.clear() if eliminado[1] not in visitados: visitados.append(eliminado[1]) for adyacente in grafo[eliminado[1]]: adya = (eliminado[1],) + adyacente if adya not in colaPrioridad: colaPrioridad.insert(0, adya) grafoResultante[eliminado[0]] = [(eliminado[1], eliminado[2])] self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 600, 600) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() longitud = len(grafoResultante) contador = 0 for item in grafoResultante.items(): #print(item) puntoO = item[0] puntoD = item[1][0][0] #print('Punto O', puntoO) #print('Punto D',puntoD) origenX = int(puntoO.split(".", 2)[0]) origenY = int(puntoO.split(".", 2)[1]) destinoX = int(puntoD.split(".", 2)[0]) destinoY = int(puntoD.split(".", 2)[0]) self.scene.addEllipse(origenX, origenY, 5, 5, self.pen, QBrush(QColor(50, 100, 0))) contador = contador +1 if contador == longitud: self.scene.addEllipse(int(item[1][0][0].split(".", 2)[0]), int(item[1][0][0].split(".", 2)[1]), 5, 5, self.pen, QBrush(QColor(50, 100, 0))) self.scene.addLine(int(item[0].split(".", 2)[0]), int(item[0].split(".", 2)[1]),int(item[1][0][0].split(".", 2)[0]), int(item[1][0][0].split(".", 2)[1])) @Slot() def mostrarGrafoOriginal(self): self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 500, 500) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() self.pen.setColor(QColor(0, 100, 0)) self.pen.setWidth(3) #self.scene.addLine(0, 0, 499, 0, self.pen) #self.scene.addLine(0, 499, 499, 499, self.pen) #self.scene.addLine(0, 0, 0, 499, self.pen) #self.scene.addLine(499, 0, 499, 499, self.pen) for particula in self.listaparticulas.lista: #self.pen.setColor(QColor(particula.colorR, particula.colorG, particula.colorB)) self.scene.addLine(particula.origenX, particula.origenY, particula.destinoX, particula.destinoY, self.pen) self.scene.addEllipse(particula.origenX, particula.origenY, 5, 5, self.pen, QBrush(QColor(50, 100, 0))) self.scene.addEllipse(particula.destinoX, particula.destinoY, 5, 5, self.pen, QBrush(QColor(100, 0, 0))) @Slot() def kruskal(self): def MAKE_SET(x): return [x] def FIND_SET(x, list): i = 0 for element in list: try: index= element.index(x) return i except: pass #print("This is an error message!") i = i + 1 def UNION(index_u, index_v,lista): L = lista[index_u] T = lista[index_v] lista.remove(L) lista.remove(T) final_list = list(set(L + T)) lista.append(final_list) return lista grafoResultante = [] colaPrioridad = [] disjointSet = [] for particula in self.listaparticulas.lista: pOrigen = str(particula.origenX) + ('.') + str(particula.origenY) pDestino = str(particula.destinoX) + ('.') + str(particula.destinoY) v1 = float(int(particula.destinoX) - int(particula.origenX)) v2 = float(int(particula.destinoY) - int(particula.origenY)) distancia = float(math.sqrt((v1) ** 2 + (v2) ** 2)) origen = pOrigen destino = pDestino peso = int(distancia) arista = [origen,destino,peso] colaPrioridad.append(arista) disjointSet.append(MAKE_SET(origen)) disjointSet.append(MAKE_SET(destino)) colaPrioridad.sort(key=lambda x: x[2]) disjointSet = [ii for n, ii in enumerate(disjointSet) if ii not in disjointSet[:n]] i = 0 print(disjointSet) if len(colaPrioridad) != 0: for element in colaPrioridad: index_u = FIND_SET(element[0], disjointSet) index_v = FIND_SET(element[1], disjointSet) if FIND_SET(element[0],disjointSet) != FIND_SET(element[1],disjointSet): grafoResultante.append(element) disjointSet = UNION(index_u,index_v, disjointSet) i = i + 1 print(disjointSet) print(' -> AEM ', grafoResultante) self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 600, 600) self.ui.graphicsView.setScene(self.scene) self.pen = QPen() for item in grafoResultante: puntoO = item[0] puntoD = item[1] origenX = int(puntoO.split(".", 2)[0]) origenY = int(puntoO.split(".", 2)[1]) destinoX = int(puntoD.split(".", 2)[0]) destinoY = int(puntoD.split(".", 2)[1]) self.scene.addEllipse(origenX, origenY, 5, 5, self.pen, QBrush(QColor(100, 100, 0))) self.scene.addEllipse(destinoX, destinoY, 5, 5, self.pen, QBrush(QColor(100, 100, 0))) self.scene.addLine(int(item[0].split(".", 2)[0]), int(item[0].split(".", 2)[1]), int(item[1].split(".", 2)[0]), int(item[1].split(".", 2)[1]))