def click_button1(self): global pic_path pic_path = tkinter.filedialog.askopenfilename() root = tkinter.Tk() # 创建一个Tkinter.Tk()实例 root.withdraw() # 将Tkinter.Tk()实例隐藏 print(pic_path) link = pic_path # request.urlretrieve(link,'F:/Pycharm/PyCharm Community Edition 2020.2.3/ServiceInnovate/CNN/inputs') copyfile(pic_path, 'inputs/01.jpg') img = cv2.imread(pic_path) # 读取图像 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换图像通道 x = img.shape[1] # 获取图像大小 y = img.shape[0] self.zoomscale = 1 # 图片放缩尺度 frame = QImage(img, x, y, QImage.Format_RGB888) pix = QPixmap.fromImage(frame) self.item = QGraphicsPixmapItem(pix) # 创建像素图元 self.item.setScale(self.zoomscale) self.scene = QGraphicsScene() # 创建场景 self.scene.addItem(self.item) self.ui.graphicsView.setScene(self.scene) # 将场景添加至视图
def __init__(self, name: str, id: int, optionsSet: bool, inputs=None, parent: QtWidgets.QGraphicsItem = None, output: bool = True): """Create an instance of this class """ super().__init__(parent) if inputs is None: inputs = list() self._name = name self._id = id # Set font used for label (operation name) self._title_font = QtGui.QFont("Arial", 14) # Compute size of label to display self._width = max(150, GraphNode.__headerSize(self._name, self._title_font).width()) self._height = 130 self._outline = 6 self._slot_radius = 10 self._label_height = 34 self._bbox = None # cache container self._round_slot = None self._rect_slot = None self._hover_slot = False self.setFlags(QtWidgets.QGraphicsItem.ItemIsMovable | QtWidgets.QGraphicsItem.ItemIsSelectable) self.setAcceptHoverEvents(False) # Build output slot self._output = NodeSlot(name="out", parent=self, family=NodeSlot.OUTPUT) if output else None # Build input slots self._inputs = [] for i, slot_name in enumerate(inputs): an_input = NodeSlot(name=slot_name, parent=self, position=i) self._inputs.append(an_input) self._status = NodeStatus.NONE self._status_slot = NodeSlot(name=None, parent=self, family=NodeSlot.STATUS) # Update internal containers self._update() # Node options indicator self._optionsSet: bool = None self._optionsIndicator: QGraphicsPixmapItem = QGraphicsPixmapItem(self) self.setOptionsIndicator(optionsSet) center = self.boundingRect().center() offsetW = self._optionsIndicator.boundingRect().width() // 2 offsetH = self._optionsIndicator.boundingRect().height() // 2 self._optionsIndicator.setPos(center.x() - offsetW, center.y() - offsetH // 2)
def __init__(self, readImg): QFrame.__init__(self) self._readImg = weakref.ref(readImg) self.graphicsView = QtWidgets.QGraphicsView(self) self.graphicsView.setTransformationAnchor( self.graphicsView.AnchorUnderMouse) self.graphicsView.setResizeAnchor(self.graphicsView.AnchorUnderMouse) self.graphicsView.setFrameStyle(QFrame.NoFrame) self.graphicsView.setObjectName("graphicsView") self.qtTool = QtImgTool(self) self.graphicsView.setBackgroundBrush(QColor(Qt.white)) self.graphicsView.setCursor(Qt.OpenHandCursor) self.graphicsView.setResizeAnchor(self.graphicsView.AnchorViewCenter) self.graphicsView.setTransformationAnchor( self.graphicsView.AnchorViewCenter) self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform) self.graphicsView.setCacheMode(self.graphicsView.CacheBackground) self.graphicsView.setViewportUpdateMode( self.graphicsView.SmartViewportUpdate) self.graphicsItem = QGraphicsPixmapItem() self.graphicsItem.setFlags(QGraphicsPixmapItem.ItemIsFocusable | QGraphicsPixmapItem.ItemIsMovable) self.graphicsScene = QGraphicsScene(self) # 场景 self.graphicsView.setScene(self.graphicsScene) self.graphicsScene.addItem(self.graphicsItem) self.graphicsView.setMinimumSize(10, 10) self.graphicsView.installEventFilter(self) self.graphicsView.setWindowFlag(Qt.FramelessWindowHint) self.pixMap = QPixmap() self.scaleCnt = 0
def setBackgroundImage(self): img = QImage(QSize(256, 256), QImage.Format_ARGB32) img.fill(QColor(100, 100, 100)) a = np.arange(256) buf = np.meshgrid(a, a) buf1 = QImageBuffer(img)[:, :, :3][:, :, ::-1] buf1[:, :, 0], buf1[:, :, 1] = buf buf1[:, :, 2] = 1 buf2 = np.tensordot(buf1, self.invM, axes=(-1, -1)) * 255 np.clip(buf2, 0, 255, out=buf2) buf1[...] = buf2 qp = QPainter(img) qp.drawLine(self.R, self.G) qp.drawLine(self.G, self.B) qp.drawLine(self.B, self.R) b = (self.B + self.R + self.G) / 3.0 qp.drawLine(b - QPointF(10, 0), b + QPointF(10, 0)) qp.drawLine(b - QPointF(0, 10), b + QPointF(0, 10)) qp.end() self.scene().addItem(QGraphicsPixmapItem(QPixmap.fromImage(img)))
def transparency_change_sld(self, value): self.img_transparency_edit.setText(str(value)) self.layer_alpha = int(255 * (1.0 - (value / 100))) # Change layer image's transparency(alpha value) for y in range(self.org_img_height): for x in range(self.org_img_width): self.layer_qimg.setPixelColor( QPoint(x, y), QColor(0, 0, 0, self.layer_alpha)) self.layer_pixmap = QPixmap.fromImage(self.layer_qimg) # remove previous layer image self.scene.removeItem(self.imgs_pixmap[-1]) self.imgs_pixmap.pop(-1) # add new layer image to scene self.imgs_pixmap.append(QGraphicsPixmapItem(self.layer_pixmap)) self.scene.addItem(self.imgs_pixmap[-1]) self.show()
def dispaly_image(self): '''在 ModifyQGraphicsView 显示一张图片 在 ModifyQGraphicsView 显示一张图片 @参数说明: 无 @返回值: 无 @注意: 无 ''' # 根据图片的维度,进行不同的处理 if self._image_shape is 2: # 如果是二维灰度图片,读取方式为QImage.Format_Grayscale8 temp_q_image = QImage(self._image_data, self._image_h, self._image_w, QImage.Format_Grayscale8) elif self._image_shape is 3: # 由于QImage读取方式为RGB,但 opencv 读取图片形式为BGR,所以要进行色彩转换 temp_q_image = cv2.cvtColor(self._image_data, cv2.COLOR_BGR2RGB) # 如果是三维灰度图片,读取方式为QImage.Format_RGB888 temp_q_image = QImage(temp_q_image, self._image_h, self._image_w, QImage.Format_RGB888) else: return None # 2. 像素映射 temp_q_image_pix = QPixmap.fromImage(temp_q_image) # 将给定图像转换为像素映射 # 3. 在graphics_view中显示图片 temp_item = QGraphicsPixmapItem(temp_q_image_pix) temp_q_sece = QGraphicsScene() temp_q_sece.addItem(temp_item) self.setScene(temp_q_sece) temp_q_sece.clearSelection()
def nextImage(self): #print("nextImageに入りました") #self.clear() print('self.currentは', self.current) self.current_imagenum = self.Imagelist.index(self.current) print('今見ている画像の番号は', self.current_imagenum) self.next_image = self.Imagelist[self.current_imagenum + 1] print('次の画像は', self.next_image) self.current = self.next_image print('self.currentは', self.current) self.next_item = QGraphicsPixmapItem(QPixmap(QImage(self.next_image))) #print(self.next_item) self.height, self.width, _ = (cv2.imread(self.next_image)).shape #print(self.height) self.addItem(self.next_item) self.setBackgroundBrush(QBrush(Qt.black)) #print('nextimage内のselfは', self) return self
def Show_Image(self): print('show_Image') self.imgpass = '******'.format(self.count) self.Image = QImage(self.imgpass) color = QColor() color.setRgb(0, 0, 255, a=255) joint_list = self.take_joint() if joint_list: #print('joint_listは存在する', joint_list) for joint in joint_list: if joint != '': jointx, jointy = joint.split(',') jointx, jointy = int(float(jointx)), int(float(jointy)) for x in range(jointx - 4, jointx + 5): self.Image.setPixelColor(x, jointy - 1, color) self.Image.setPixelColor(x, jointy, color) self.Image.setPixelColor(x, jointy + 1, color) for y in range(jointy - 4, jointy + 5): self.Image.setPixelColor(jointx - 1, y, color) self.Image.setPixelColor(jointx, y, color) self.Image.setPixelColor(jointx + 1, y, color) else: continue else: pass self.image_item = QGraphicsPixmapItem(QPixmap(self.Image)) self.scene().clear() self.scene().addItem(self.image_item) self.height, self.width, _ = (cv2.imread(self.imgpass)).shape self.setFixedSize(self.width, self.height) #print('width, height', self.width, self.height) return self
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 initialize_map(self): self.grahpicsitem = [] self.scene.clear() for i in self.hex: if self.game.map[i[0]][i[1]] == " ": cell = QGraphicsPixmapItem(self.grass) cell.setPos(QPointF(i[1] * 10, i[0] * 10)) self.grahpicsitem.append(cell) self.scene.addItem(cell) elif self.game.map[i[0]][i[1]] == "#": cell = QGraphicsPixmapItem(self.black) cell.setPos(QPointF(i[1] * 10, i[0] * 10)) self.grahpicsitem.append(cell) self.scene.addItem(cell) elif self.game.map[i[0]][i[1]] == "+": cell = QGraphicsPixmapItem(self.white) cell.setPos(QPointF(i[1] * 10, i[0] * 10)) self.grahpicsitem.append(cell) self.scene.addItem(cell) if self.game.map[i[0]][i[1]] == "@": cell = QGraphicsPixmapItem(self.apple) cell.setPos(QPointF(i[1] * 10, i[0] * 10)) self.grahpicsitem.append(cell) self.scene.addItem(cell)
class Scene(QGraphicsScene): def __init__(self, parent=None, view=None): QGraphicsScene.__init__(self, parent) self.undoStack = QUndoStack(self) # super(Scene, self).__init__(parent) self.view = view self.imgPosibleConnectH = QGraphicsPixmapItem( os.path.join(PATHBLOCKSIMG, "ConnectH.png")) super(Scene, self).addItem(self.imgPosibleConnectH) self.imgPosibleConnectH.setVisible(False) self.imgPosibleConnectV = QGraphicsPixmapItem( os.path.join(PATHBLOCKSIMG, "ConnectV.png")) super(Scene, self).addItem(self.imgPosibleConnectV) self.imgPosibleConnectV.setVisible(False) self.oldPos = None self.createActions() def createActions(self): self.popMenu = QMenu() self.undoAction = self.undoStack.createUndoAction( self, self.tr("&Undo")) self.undoAction.setShortcuts(QKeySequence.Undo) self.popMenu.addAction(self.undoAction) self.redoAction = self.undoStack.createRedoAction( self, self.tr("&Redo")) self.redoAction.setShortcuts(QKeySequence.Redo) self.popMenu.addAction(self.redoAction) self.disableAction = QAction(self.tr("&Disable"), self) self.disableAction.triggered.connect(self.setEnabledMain) self.popMenu.addAction(self.disableAction) def setEnabledMain(self): for item in self.items(): if isinstance(item, QGraphicsBlockItem) and item.isBlockDef(): if item.functionname == "main": item.setEnabled(not item.isEnabled()) elif item.functionname == "when": item.setEnabled(not item.isEnabled()) def addItem(self, item: QGraphicsItem, fromStack=False): if fromStack: super(Scene, self).addItem(item) else: self.undoStack.push(AddCommand(item, self)) def mousePressEvent(self, event: QGraphicsSceneMouseEvent): movingItem = self.itemAt(event.scenePos(), self.view.transform()) if movingItem is None and event.button() is Qt.MouseButton.RightButton: self.popMenu.exec_(event.screenPos()) if movingItem is not None and event.button( ) is Qt.MouseButton.LeftButton: self.oldPos = movingItem.pos() self.clearSelection() super(Scene, self).mousePressEvent(event) def mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent): if len(self.selectedItems()) is not 0: movingItem = self.selectedItems()[0] else: movingItem = None if movingItem is not None and event.button( ) is Qt.MouseButton.LeftButton: if self.oldPos is not movingItem.pos(): self.undoStack.push(MoveCommand(movingItem, self.oldPos, self)) super(Scene, self).mouseReleaseEvent(event) def getListInstructions(self): list = [] for item in self.items(): if isinstance(item, QGraphicsBlockItem) and item.isBlockDef( ) and item.isEnabled(): inst = item.getInstructions() list.append(inst) return list
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()
class PhotoViewer(QGraphicsView): photoClicked = Signal(QPoint) def __init__(self, parent): super(PhotoViewer, self).__init__(parent) self._zoom = 0 self._empty = True self._scene = QGraphicsScene(self) self._photo = QGraphicsPixmapItem() self._scene.addItem(self._photo) self.setScene(self._scene) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setBackgroundBrush(QBrush(QColor(30, 30, 30))) self.setFrameShape(QFrame.NoFrame) def hasPhoto(self): return not self._empty def fitInView(self, scale=True): rect = QRectF(self._photo.pixmap().rect()) if not rect.isNull(): self.setSceneRect(rect) if self.hasPhoto(): unity = self.transform().mapRect(QRectF(0, 0, 1, 1)) self.scale(1 / unity.width(), 1 / unity.height()) viewrect = self.viewport().rect() scenerect = self.transform().mapRect(rect) factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height()) self.scale(factor, factor) self._zoom = 0 def setPhoto(self, pixmap=None): self._zoom = 0 if pixmap and not pixmap.isNull(): self._empty = False self.setDragMode(QGraphicsView.ScrollHandDrag) self._photo.setPixmap(pixmap) else: self._empty = True self.setDragMode(QGraphicsView.NoDrag) self._photo.setPixmap(QPixmap()) self.fitInView() def wheelEvent(self, event): if self.hasPhoto(): if event.angleDelta().y() > 0: factor = 1.05 self._zoom += 1 else: factor = 0.95 self._zoom -= 1 if self._zoom > 0: self.scale(factor, factor) elif self._zoom == 0: self.fitInView() else: if self._zoom > -10: self.scale(factor, factor) else: self._zoom = -10 def toggleDragMode(self): if self.dragMode() == QGraphicsView.ScrollHandDrag: self.setDragMode(QGraphicsView.NoDrag) elif not self._photo.pixmap().isNull(): self.setDragMode(QGraphicsView.ScrollHandDrag) def mousePressEvent(self, event): if self._photo.isUnderMouse(): self.photoClicked.emit(QPoint(event.pos())) super(PhotoViewer, self).mousePressEvent(event)
class QtImg(QtWidgets.QWidget): def __init__(self): super(self.__class__, self).__init__() self.bookId = "" self.epsId = 0 self.curIndex = 0 self.gridLayout = QtWidgets.QGridLayout(self) self.setWindowTitle("图片查看") self.setWindowModality(QtCore.Qt.ApplicationModal) self.resize(402, 509) # self.setWindowFlags(Qt.FramelessWindowHint) self.graphicsView = QtWidgets.QGraphicsView(self) self.graphicsView.setFrameStyle(QFrame.NoFrame) self.graphicsView.setObjectName("graphicsView") self.graphicsView.setBackgroundBrush(QColor(Qt.white)) self.graphicsView.setCursor(Qt.OpenHandCursor) self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform) self.graphicsView.setCacheMode(self.graphicsView.CacheBackground) self.graphicsView.setViewportUpdateMode( self.graphicsView.SmartViewportUpdate) self.graphicsItem = QGraphicsPixmapItem() self.graphicsItem.setFlags(QGraphicsPixmapItem.ItemIsFocusable | QGraphicsPixmapItem.ItemIsMovable) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.CopyPicture) self.graphicsScene = QGraphicsScene(self) # 场景 self.graphicsView.setScene(self.graphicsScene) self.graphicsScene.addItem(self.graphicsItem) self.graphicsView.setMinimumSize(10, 10) self.pixMap = QPixmap("加载中") self.graphicsItem.setPixmap(self.pixMap) # self.radioButton.setChecked(True) self.isStripModel = False # self.radioButton.installEventFilter(self) # self.radioButton_2.installEventFilter(self) self.graphicsView.installEventFilter(self) self.graphicsView.setWindowFlag(Qt.FramelessWindowHint) self.gridLayout.addWidget(self.graphicsView) self._delta = 0.1 self.scaleCnt = 0 def ShowImg(self, pixMap): self.scaleCnt = 0 self.pixMap = QPixmap(pixMap) self.show() self.graphicsItem.setPixmap(self.pixMap) self.graphicsView.setSceneRect( QRectF(QPointF(0, 0), QPointF(self.pixMap.width(), self.pixMap.height()))) self.ScalePicture() def ScalePicture(self): rect = QRectF(self.graphicsItem.pos(), QSizeF(self.pixMap.size())) unity = self.graphicsView.transform().mapRect(QRectF(0, 0, 1, 1)) width = unity.width() height = unity.height() if width <= 0 or height <= 0: return self.graphicsView.scale(1 / width, 1 / height) viewRect = self.graphicsView.viewport().rect() sceneRect = self.graphicsView.transform().mapRect(rect) if sceneRect.width() <= 0 or sceneRect.height() <= 0: return x_ratio = viewRect.width() / sceneRect.width() y_ratio = viewRect.height() / sceneRect.height() x_ratio = y_ratio = min(x_ratio, y_ratio) self.graphicsView.scale(x_ratio, y_ratio) # if self.readImg.isStripModel: # height2 = self.pixMap.size().height() / 2 # height3 = self.graphicsView.size().height()/2 # height3 = height3/x_ratio # p = self.graphicsItem.pos() # self.graphicsItem.setPos(p.x(), p.y()+height2-height3) self.graphicsView.centerOn(rect.center()) for _ in range(abs(self.scaleCnt)): if self.scaleCnt > 0: self.graphicsView.scale(1.1, 1.1) else: self.graphicsView.scale(1 / 1.1, 1 / 1.1) def resizeEvent(self, event) -> None: super(self.__class__, self).resizeEvent(event) self.ScalePicture() def eventFilter(self, obj, ev): if ev.type() == QEvent.KeyPress: return True else: return super(self.__class__, self).eventFilter(obj, ev) def wheelEvent(self, event): if event.angleDelta().y() > 0: self.zoomIn() else: self.zoomOut() def zoomIn(self): """放大""" self.zoom(1.1) def zoomOut(self): """缩小""" self.zoom(1 / 1.1) def zoom(self, factor): """缩放 :param factor: 缩放的比例因子 """ _factor = self.graphicsView.transform().scale(factor, factor).mapRect( QRectF(0, 0, 1, 1)).width() if _factor < 0.07 or _factor > 100: # 防止过大过小 return if factor >= 1: self.scaleCnt += 1 else: self.scaleCnt -= 1 self.graphicsView.scale(factor, factor) def CopyPicture(self): clipboard = QApplication.clipboard() clipboard.setPixmap(self.pixMap) QtBubbleLabel.ShowMsgEx(self, "复制成功") return
def image2Qpixmap(self, data): pixmap = QPixmap.fromImage(data) item = QGraphicsPixmapItem(pixmap) scene = QGraphicsScene() scene.addItem(item) return scene
class ImageSegmenterView(QGraphicsView): photoClicked = Signal(QPoint) def __init__(self, parent): super(ImageSegmenterView, self).__init__(parent) self._zoom = 0 self.empty = True self._scene = QGraphicsScene(self) self._photo = QGraphicsPixmapItem() self.image_hidden = False self._seglayer = QGraphicsPixmapItem() self._seglayer.setOpacity(0.5) self._scene.addItem(self._photo) self._scene.addItem(self._seglayer) self.setScene(self._scene) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) # self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setBackgroundBrush(QBrush(QtCore.Qt.darkGray)) self.setFrameShape(QFrame.NoFrame) self.seg_image = None self.start = False self.prev_point = None self.painter = None self.segmenter_pen = QPen(QtCore.Qt.green, 30, QtCore.Qt.SolidLine) self.segmenter_pen.setCapStyle(QtCore.Qt.RoundCap) self.segmenter_pen.setJoinStyle(QtCore.Qt.RoundJoin) self.erase = False self.changed = False self.history = collections.deque(maxlen=10) self.future = collections.deque(maxlen=10) def hasPhoto(self): return not self.empty def fitInView(self, scale=True): rect = QtCore.QRectF(self._photo.pixmap().rect()) if not rect.isNull(): self.setSceneRect(rect) if self.hasPhoto(): unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1)) self.scale(1 / unity.width(), 1 / unity.height()) viewrect = self.viewport().rect() scenerect = self.transform().mapRect(rect) factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height()) self.scale(factor, factor) self._zoom = 0 def setPhoto(self, pixmap=None): self._zoom = 0 if pixmap and not pixmap.isNull(): self.empty = False self.changed = False self._photo.setPixmap(pixmap) self.seg_image = QImage(pixmap.width(), pixmap.height(), QImage.Format_ARGB32_Premultiplied) self.seg_image.fill(QtCore.Qt.transparent) self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image)) else: self._empty = True self._photo.setPixmap(QPixmap()) self.fitInView() def save_state(self): if self.future is not None: while len(self.future) > 0: present = self.future.pop() del present if self.seg_image is not None: self.history.append(self.seg_image.copy()) def clear_history(self): while len(self.history) > 0: present = self.history.pop() del present def undo(self): if len(self.history) > 0: self.future.append(self.seg_image) present = self.history.pop() self.seg_image = present self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image)) def redo(self): if len(self.future) > 0: self.history.append(self.seg_image) present = self.future.pop() self.seg_image = present self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image)) def setSegLayer(self, pixmap=None): if not self._photo.pixmap().isNull(): self.save_state() self.seg_image = QImage(pixmap.toImage()) self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image)) def resetSegLayer(self): if not self._photo.pixmap().isNull(): self.changed = True self.save_state() del self.seg_image self.seg_image = QImage(self._photo.pixmap().width(), self._photo.pixmap().height(), QImage.Format_ARGB32_Premultiplied) self.seg_image.fill(QtCore.Qt.transparent) self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image)) def wheelEvent(self, event): if self.hasPhoto() and not self.start: if event.angleDelta().y() > 0: factor = 1.25 self._zoom += 1 else: factor = 0.8 self._zoom -= 1 if self._zoom > 0: self.scale(factor, factor) elif self._zoom == 0: self.fitInView() else: self._zoom = 0 def mousePressEvent(self, event): if not self._photo.pixmap().isNull(): if event.button() == QtCore.Qt.LeftButton: self.save_state() self.start = True self.painter = QPainter(self.seg_image) if self.erase: self.painter.setCompositionMode( QPainter.CompositionMode_Clear) self.painter.setPen(self.segmenter_pen) self.paint_point(event.pos()) elif event.button() == QtCore.Qt.RightButton: if not self._photo.pixmap().isNull(): self.setDragMode(QGraphicsView.ScrollHandDrag) self.scroll_origin = self.mapToScene(event.pos()) # if self._photo.isUnderMouse(): # self.photoClicked.emit(self.mapToScene(event.pos()).toPoint()) super(ImageSegmenterView, self).mousePressEvent(event) def mouseMoveEvent(self, event): if not self._photo.pixmap().isNull(): if self.start: self.paint_point(event.pos()) if event.buttons() & QtCore.Qt.RightButton: newpoint = self.mapToScene(event.pos()) translation = newpoint - self.scroll_origin self.translate(translation.x(), translation.y()) self.scroll_origin = self.mapToScene(event.pos()) super(ImageSegmenterView, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): if not self._photo.pixmap().isNull(): if self.start: self.start = False self.prev_point = None self.painter.end() if self.dragMode() == QGraphicsView.ScrollHandDrag: self.setDragMode(QGraphicsView.NoDrag) def paint_point(self, pos): self.changed = True pos = self.mapToScene(pos).toPoint() if self.prev_point is not None: self.painter.drawLine(self.prev_point, pos) else: self.painter.drawPoint(pos) self.prev_point = pos self._seglayer.setPixmap(QPixmap.fromImage(self.seg_image)) def set_foreground(self): self.erase = False self.segmenter_pen.setColor(QtCore.Qt.green) def set_possible_foreground(self): self.erase = False self.segmenter_pen.setColor(QtCore.Qt.blue) def set_possible_background(self): self.erase = True self.segmenter_pen.setColor(QtCore.Qt.transparent) def set_background(self): self.erase = False self.segmenter_pen.setColor(QtCore.Qt.red) def set_pen_size(self, size): self.segmenter_pen.setWidth(size) def set_opacity(self, value): self._seglayer.setOpacity(value / 100) def hide_image(self): if self.image_hidden: self._photo.setOpacity(1) self.image_hidden = False else: self._photo.setOpacity(0) self.image_hidden = True
def __init__(self, cModel, targetImage=None, axeSize=500, LUTSize=LUTSIZE, layer=None, parent=None, mainForm=None): """ @param cModel: color space used by colorPicker, slider2D and colorPicker @type cModel: cmConverter object @param axeSize: size of the color wheel @type axeSize: int @param targetImage: @type targetImage: imImage @param LUTSize: @type LUTSize: int @param layer: layer of targetImage linked to graphics form @type layer : QLayer @param parent: @type parent: """ super().__init__(parent=parent) self.mainForm = mainForm # used by saveLUT() # context help tag self.helpId = "LUT3DForm" self.cModel = cModel border = 20 self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setMinimumSize(axeSize + 90, axeSize + 200) self.setAttribute(Qt.WA_DeleteOnClose) self.setBackgroundBrush(QBrush(Qt.black, Qt.SolidPattern)) self.currentHue, self.currentSat, self.currentPb = 0, 0, self.defaultColorWheelBr self.currentR, self.currentG, self.currentB = 0, 0, 0 self.size = axeSize # back links to image self.targetImage = weakProxy(targetImage) self.layer = weakProxy(layer) # currently selected grid node self.selected = None self.graphicsScene = QGraphicsScene() self.graphicsScene.options = None self.setScene(self.graphicsScene) # back to image layer self.graphicsScene.layer = weakProxy(layer) # init LUT freshLUT3D = LUT3D(None, size=LUTSize, alpha=True) self.graphicsScene.lut = freshLUT3D # init 2D slider QImg = hueSatPattern(axeSize, axeSize, cModel, bright=self.defaultColorWheelBr, border=border) self.graphicsScene.slider2D = colorChooser(cModel, QImg, target=self.targetImage, size=axeSize, border=border) self.graphicsScene.selectMarker = activeMarker.fromCross(parent=self.graphicsScene.slider2D) self.graphicsScene.selectMarker.setPos(axeSize / 2, axeSize / 2) # color wheel event handler def f1(p, r, g, b): h, s, br = self.cModel.rgb2cm(r, g, b) self.currentHue, self.currentSat, self.currentPb = h, s, br self.currentR, self.currentG, self.currentB = r, g, b self.bSliderUpdate() self.displayStatus() self.graphicsScene.slider2D.onMouseRelease = f1 self.graphicsScene.addItem(self.graphicsScene.slider2D) # Brightness slider self.bSliderHeight = 20 self.bSliderWidth = self.graphicsScene.slider2D.QImg.width() px = brightnessPattern(self.bSliderWidth, self.bSliderHeight, cModel, self.currentHue, self.currentSat).rPixmap self.graphicsScene.bSlider = QGraphicsPixmapItem(px, parent=self.graphicsScene.slider2D) self.graphicsScene.bSlider.setPos(QPointF(-border, self.graphicsScene.slider2D.QImg.height() - border)) bSliderCursor = activeMarker.fromTriangle(parent=self.graphicsScene.bSlider) bSliderCursor.setMoveRange(QRectF(0.0, bSliderCursor.size, self.graphicsScene.bSlider.pixmap().width(), 0.0)) bSliderCursor.setPos(self.graphicsScene.bSlider.pixmap().width() * self.defaultColorWheelBr, bSliderCursor.size) # cursor event handlers def f2(e, p, q): self.currentPb = p / float(self.bSliderWidth) QToolTip.showText(e.screenPos(), (str(int(self.currentPb * 100.0))), self) bSliderCursor.onMouseMove = f2 def f3(e, p, q): self.currentPb = p / float(self.bSliderWidth) self.graphicsScene.slider2D.QImg.setPb(self.currentPb) self.graphicsScene.slider2D.setPixmap(self.graphicsScene.slider2D.QImg.rPixmap) self.displayStatus() bSliderCursor.onMouseRelease = f3 # status bar offset = 60 self.graphicsScene.statusBar = QGraphicsTextItem() self.graphicsScene.statusBar.setPos(-20, axeSize + offset) self.graphicsScene.statusBar.setDefaultTextColor(QColor(255, 255, 255)) self.graphicsScene.statusBar.setPlainText('') self.graphicsScene.addItem(self.graphicsScene.statusBar) self.displayStatus() # self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform) # grid self.grid = activeGrid(self.graphicsScene.lut.size, self.cModel, parent=self.graphicsScene.slider2D) self.graphicsScene.grid = self.grid # buttons pushButton1 = QbLUePushButton("Reset Grid") pushButton1.clicked.connect(self.onReset) pushButton2 = QbLUePushButton("Save LUT") pushButton2.clicked.connect(self.saveLUT) pushButton3 = QbLUePushButton("Smooth Grid") pushButton3.clicked.connect(self.onSmoothGrid) pushButton4 = QbLUePushButton('Set Mask') pushButton4.clicked.connect(self.setMask) # pushButton4 needs enabling/disabling self.pushButton4 = pushButton4 # options options1, optionNames1 = ['use image', 'use selection'], ['Use Image', 'Use Selection'] self.listWidget1 = optionsWidget(options=options1, optionNames=optionNames1, exclusive=True) """ def onSelect1(item): self.graphicsScene.options['use selection'] = item is self.listWidget1.items['use selection'] self.listWidget1.onSelect = onSelect1 """ self.listWidget1.setFocusPolicy(Qt.NoFocus) # set initial selection to 'use image' self.listWidget1.checkOption(self.listWidget1.intNames[0]) options2, optionNames2 = ['add node', 'remove node'], ['Add Node', 'Remove Node'] self.listWidget2 = optionsWidget(options=options2, optionNames=optionNames2, exclusive=True) """ def onSelect2(item): self.graphicsScene.options['add node'] = item is self.listWidget2.items['add node'] self.listWidget2.onSelect = onSelect2 """ # set initial selection to add node' self.listWidget2.checkOption(self.listWidget2.intNames[0]) options3 = ['select neighbors', 'reset removed nodes', 'show histogram', 'keep alpha'] optionNames3 = ['Select Neighbors', 'Reset Removed', 'Show Histogram', 'Keep Alpha'] self.listWidget3 = optionsWidget(options=options3, optionNames=optionNames3, exclusive=False) self.listWidget3.checkOption(self.listWidget3.intNames[0]) self.listWidget3.checkOption(self.listWidget3.intNames[1]) def onSelect3(item): option = item.internalName if option == 'show histogram': self.graphicsScene.slider2D.showTargetHist = self.graphicsScene.options[option] # .isChecked() self.graphicsScene.slider2D.updatePixmap() return if option == 'keep alpha': self.enableButtons() self.layer.applyToStack() self.listWidget3.onSelect = onSelect3 # set initial selection to 'select naighbors' item = self.listWidget3.items[options3[0]] item.setCheckState(Qt.Checked) self.graphicsScene.options = UDict((self.listWidget1.options, self.listWidget2.options, self.listWidget3.options)) # layouts hlButtons = QHBoxLayout() hlButtons.addWidget(pushButton1) hlButtons.addWidget(pushButton3) hlButtons.addWidget(pushButton2) hl = QHBoxLayout() vl1 = QVBoxLayout() vl1.addWidget(self.listWidget1) vl1.addWidget(pushButton4) hl.addLayout(vl1) hl.addWidget(self.listWidget2) hl.addWidget(self.listWidget3) vl = QVBoxLayout() for l in [hlButtons, hl]: vl.addLayout(l) # Init QWidget container for adding buttons and options to graphicsScene container = QWidget() container.setObjectName("container") container.setLayout(vl) ss = """QWidget#container{background: black}\ QListWidget{background-color: black; selection-background-color: black; border: none; font-size: 7pt}\ QListWidget::item{color: white;}\ QListWidget::item::selected{background: black; border: none}""" container.setStyleSheet(ss) for wdg in [self.listWidget1, self.listWidget2, self.listWidget3]: wdg.setMinimumWidth(wdg.sizeHintForColumn(0)) wdg.setMinimumHeight(wdg.sizeHintForRow(0)*len(wdg.items)) container.setGeometry(-offset//2, axeSize + offset - 20, axeSize + offset, 20) self.graphicsScene.addWidget(container) #container.setStyleSheet("QPushButton {color: white;}\ # QPushButton:pressed, QPushButton:hover {background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #0d5ca6, stop: 1 #2198c0);}") self.setWhatsThis( """ <b>2.5D LUT Editor</b><br> HSpB layers are slower than HSV, but usually they give better results.<br> <b>Select nodes</b> with mouse clicks on the image. Selected nodes are shown as small black circles on the color wheel.<br> <b>Modify the color</b> of a node by dragging it on the wheel. Several nodes can be moved simultaneously by grouping them.<br> <b>Group nodes</b> :<br> 1 - select them with the mouse : while pressing the mouse left button, drag a rubber band around the nodes to select;<br> 2 - next, right click any one of the selected nodes and choose group from the context menu<br> <b>unselect nodes</b> :<br> 1 - check the option Remove Node;<br> 2 - ungroup;<br> 3 - on the image, click the pixels to unselect.<br> <b>Caution</b> : Selecting nodes with the mouse is enabled only when the Color Chooser is closed.<br> Click the <b> Smooth Grid</b> button to smooth color transitions between neighbor nodes.<br> Check the <br>Keep Alpha</b> option to forward the alpha channel without modifications.<br> This option must be unchecked to build a mask from the 3D LUT.<br> """ ) # end of setWhatsThis
def __init__(self, cModel, targetImage=None, axeSize=500, LUTSize=LUTSIZE, layer=None, parent=None, mainForm=None): """ @param cModel: color space used by colorPicker, slider2D and colorPicker @type cModel: cmConverter object @param axeSize: size of the color wheel @type axeSize: int @param targetImage: @type targetImage: imImage @param LUTSize: @type LUTSize: int @param layer: layer of targetImage linked to graphics form @type layer : QLayer @param parent: @type parent: """ super().__init__(targetImage=targetImage, layer=layer, parent=parent) self.mainForm = mainForm # used by saveLUT() # context help tag self.helpId = "LUT3DForm" self.cModel = cModel border = 20 self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setMinimumSize(axeSize + 90, axeSize + 250) self.setAttribute(Qt.WA_DeleteOnClose) self.setBackgroundBrush(QBrush(Qt.black, Qt.SolidPattern)) self.currentHue, self.currentSat, self.currentPb = 0, 0, self.defaultColorWheelBr self.currentR, self.currentG, self.currentB = 0, 0, 0 self.size = axeSize # currently selected grid node self.selected = None # init LUT freshLUT3D = LUT3D(None, size=LUTSize, alpha=True) self.graphicsScene.lut = freshLUT3D # init 2D slider (color wheel) swatchImg = hueSatPattern(axeSize, axeSize, cModel, bright=self.defaultColorWheelBr, border=border) slider2D = colorChooser(cModel, swatchImg, target=self.targetImage, size=axeSize, border=border) ######################################################################### # CAUTION : sliedr2D has a non null offset # slider2D (and QImg) topleft corner is at scene pos -slider2D.offset() ######################################################################### self.graphicsScene.addItem(slider2D) self.graphicsScene.slider2D = slider2D ############################## # neutral and working markers ############################## offset = slider2D.offset() neutralMarker = activeMarker.fromCross(parent=slider2D) neutralMarker.setPos(swatchImg.width() / 2 + offset.x(), swatchImg.height() / 2 + offset.y()) self.workingMarker = activeMarker.fromCross(parent=slider2D) # default pos: average skin tone pt = QPointF(*swatchImg.GetPoint(*rgb2hsB(*cmyk2rgb(6, 25, 30, 0))[:2])) + offset self.workingMarker.setPos(pt.x(), pt.y()) self.workingMarker.onMouseMove = lambda e, x, y: self.displayStatus() # swatch event handler def f1(p, r, g, b): h, s, br = self.cModel.rgb2cm(r, g, b) self.currentHue, self.currentSat, self.currentPb = h, s, br self.currentR, self.currentG, self.currentB = r, g, b self.bSliderUpdate() self.displayStatus() self.graphicsScene.slider2D.onMouseRelease = f1 # Brightness slider self.bSliderHeight = 20 self.bSliderWidth = self.graphicsScene.slider2D.QImg.width() px = brightnessPattern(self.bSliderWidth, self.bSliderHeight, cModel, self.currentHue, self.currentSat).rPixmap self.graphicsScene.bSlider = QGraphicsPixmapItem(px, parent=self.graphicsScene.slider2D) self.graphicsScene.bSlider.setPos(QPointF(-border, self.graphicsScene.slider2D.QImg.height() - border)) bSliderCursor = activeMarker.fromTriangle(parent=self.graphicsScene.bSlider) bSliderCursor.setMoveRange(QRectF(0.0, bSliderCursor.size, self.graphicsScene.bSlider.pixmap().width(), 0.0)) bSliderCursor.setPos(self.graphicsScene.bSlider.pixmap().width() * self.defaultColorWheelBr, bSliderCursor.size) # bSlider event handlers def f2(e, p, q): self.currentPb = p / float(self.bSliderWidth) self.graphicsScene.slider2D.QImg.setPb(self.currentPb) self.graphicsScene.slider2D.setPixmap(self.graphicsScene.slider2D.QImg.rPixmap) QToolTip.showText(e.screenPos(), (str(int(self.currentPb * 100.0))), self) bSliderCursor.onMouseMove = f2 def f3(e, p, q): self.currentPb = p / float(self.bSliderWidth) # self.graphicsScene.slider2D.QImg.setPb(self.currentPb) # self.graphicsScene.slider2D.setPixmap(self.graphicsScene.slider2D.QImg.rPixmap) self.displayStatus() bSliderCursor.onMouseRelease = f3 # grid self.grid = activeGrid(self.graphicsScene.lut.size, self.cModel, parent=self.graphicsScene.slider2D) self.graphicsScene.grid = self.grid # buttons pushButton1 = QbLUePushButton("Reset Grid") pushButton1.clicked.connect(self.onReset) pushButton2 = QbLUePushButton("Save LUT") pushButton2.clicked.connect(self.saveLUT) pushButton3 = QbLUePushButton("Smooth Grid") pushButton3.clicked.connect(self.onSmoothGrid) pushButton4 = QbLUePushButton('Set Mask') pushButton4.clicked.connect(self.setMask) # pushButton4 needs enabling/disabling self.pushButton4 = pushButton4 # options options1, optionNames1 = ['use image', 'use selection'], ['Use Image', 'Use Selection'] self.listWidget1 = optionsWidget(options=options1, optionNames=optionNames1, exclusive=True) self.listWidget1.setFocusPolicy(Qt.NoFocus) # set initial selection to 'use image' self.listWidget1.checkOption(self.listWidget1.intNames[0]) options2, optionNames2 = ['add node', 'remove node'], ['Add Node', 'Remove Node'] self.listWidget2 = optionsWidget(options=options2, optionNames=optionNames2, exclusive=True) # set initial selection to 'add node' self.listWidget2.checkOption(self.listWidget2.intNames[0]) options3 = ['select neighbors', 'reset removed nodes', 'show histogram', 'keep alpha'] optionNames3 = ['Select Neighbors', 'Reset Removed', 'Show Histogram', 'Keep Alpha'] self.listWidget3 = optionsWidget(options=options3, optionNames=optionNames3, exclusive=False) self.listWidget3.checkOption(self.listWidget3.intNames[0]) self.listWidget3.checkOption(self.listWidget3.intNames[1]) def onSelect3(item): option = item.internalName if option == 'show histogram': self.graphicsScene.slider2D.showTargetHist = self.graphicsScene.options[option] self.graphicsScene.slider2D.updatePixmap() return if option == 'keep alpha': self.enableButtons() self.layer.applyToStack() self.listWidget3.onSelect = onSelect3 # set initial selection to 'select naighbors' item = self.listWidget3.items[options3[0]] item.setCheckState(Qt.Checked) self.graphicsScene.options = UDict((self.listWidget1.options, self.listWidget2.options, self.listWidget3.options)) for wdg in [self.listWidget1, self.listWidget2, self.listWidget3]: wdg.setMinimumWidth(wdg.sizeHintForColumn(0)) wdg.setMinimumHeight(wdg.sizeHintForRow(0)*len(wdg.items)) # color format combo infoCombo = QComboBox() oDict = OrderedDict([('RGB', 0), ('CMYK', 1), ('HSV', 2)]) for key in oDict: infoCombo.addItem(key, oDict[key]) labelFormat = QLabel() def colorInfoFormatChanged(value): self.colorInfoFormat = infoCombo.itemData(value) if self.colorInfoFormat == 0: labelFormat.setText('RGB') elif self.colorInfoFormat == 1: labelFormat.setText('CMYK') elif self.colorInfoFormat == 2: labelFormat.setText('HSV') self.displayStatus() infoCombo.currentIndexChanged.connect(colorInfoFormatChanged) # working marker position editor self.info = QLineEdit() self.info.setMaximumSize(120, 40) # returnPressed slot def infoDone(): try: token = self.info.text().split(' ') if self.colorInfoFormat == 0: # RGB r, g, b = [int(x) for x in token if x.isdigit()] pt = QPointF(*swatchImg.GetPoint(*rgb2hsB(r, g, b)[:2])) + offset elif self.colorInfoFormat == 1: # CMYK c, m, y, k = [int(x) for x in token if x.isdigit()] pt = QPointF(*swatchImg.GetPoint(*rgb2hsB(*cmyk2rgb(c, m, y, k))[:2])) + offset elif self.colorInfoFormat == 2: # HSV h, s, _ = [int(x) for x in token if x.isdigit()] if not 0 <= s <= 100: raise ValueError pt = QPointF(*swatchImg.GetPoint(h, s / 100.0)) + offset else: raise ValueError self.workingMarker.setPos(pt.x(), pt.y()) except ValueError: dlgWarn("Invalid color") self.info.returnPressed.connect(infoDone) # layout gl = QGridLayout() for i, button in enumerate([pushButton1, pushButton3, pushButton2]): gl.addWidget(button, 0, i) gl.addWidget(pushButton4, 1, 0) gl.addWidget(infoCombo, 1, 1) for i, widget in enumerate([self.listWidget1, self.listWidget2, self.listWidget3]): gl.addWidget(widget, 2 if i < 2 else 1, i, 1 if i < 2 else 2, 1, 0) hl = QHBoxLayout() hl.addWidget(labelFormat) hl.addWidget(self.info) gl.addLayout(hl, 3, 0, -1, -1) self.addCommandLayout(gl) # set defaults self.colorInfoFormat = 0 # RGB colorInfoFormatChanged(self.colorInfoFormat) # whatsthis self.setWhatsThis( """ <b>2.5D LUT Editor</b><br> <b>Select nodes</b> with mouse clicks on the image. Selected nodes are shown as small black circles on the color wheel.<br> <b>Modify the color</b> of a node by dragging it on the wheel. Several nodes can be moved simultaneously by grouping them.<br> <b>Group nodes</b> :<br> 1 - group nodes with the mouse : while pressing the mouse left button, drag a rubber band around the nodes to group;<br> 2 - next, right click any one of the selected nodes and choose group from the context menu<br> <b>Unselect nodes</b> :<br> 1 - check the option Remove Node;<br> 2 - ungroup;<br> 3 - on the image, click the pixels to unselect.<br> <b>Warning</b> : Selecting/unselecting nodes with the mouse is enabled only when the Color Chooser is closed.<br> Press the <b> Smooth Grid</b> button to smooth color transitions between neighbor nodes.<br> <b>Crosshair</b> markers indicate neutral gray tones and average skin tones. They can be moved with the mouse. The position of the second marker is reflected in the editable bottom right box. Due to inherent properties of the CMYK color model, CMYK input values may be modified silently.<br> <b>The grid can be zoomed</b> with the mouse wheel.<br> Check the <b>Keep Alpha</b> option to forward the alpha channel without modifications.<br> This option must be unchecked to build a mask from the 3D LUT.<br> HSpB layer is slower than HSV, but usually gives better results.<br> """ ) # end of setWhatsThis
def create_qr_scene(self, scene, qr_pixel_map, qr_text, backgound_pixmap) : pixmap_item = QGraphicsPixmapItem(qr_pixel_map) pixmap_item.setY(100) pixmap_item.setX(100) background_item = QGraphicsPixmapItem(backgound_pixmap) url_item = QGraphicsTextItem(qr_text) url_item.setFont(QFont('Arial', 50)) url_item.setTextWidth(820) url_item.setY(450) url_item.setX(1150) url_item.setZValue(1) pixmap_item.setZValue(1) background_item.setZValue(-1) scene.addItem(pixmap_item) scene.addItem(url_item) scene.addItem(background_item) return scene
class LabelingWidget(QGraphicsView): def __init__(self): super().__init__() self._tag_brushes = [] self._tag_brushes.append(QBrush(QColor(0, 0, 0, 0))) self._tag_brushes.append(QBrush(QColor(255, 0, 0, 90))) self._image_item = QGraphicsPixmapItem() self._create_default_scene() self.setScene(self._scene) def _create_default_scene(self): self._scene = QGraphicsScene() self._scene.addItem(self._image_item) line_pen = QPen(Qt.black, 2) for i in range(LABELING_TAG_WIDTH + 1): self._scene.addLine(i * LABELING_STEP, 0, i * LABELING_STEP, LABELING_HEIGHT, line_pen) for i in range(LABELING_TAG_HEIGHT + 1): self._scene.addLine(0, i * LABELING_STEP, LABELING_WIDTH, i * LABELING_STEP, line_pen) self._tags = np.zeros((LABELING_TAG_HEIGHT, LABELING_TAG_WIDTH), dtype=int) self._tags_items = [] tag_pen = QPen(Qt.black, 0) for i in range(LABELING_TAG_HEIGHT): tags = [] for j in range(LABELING_TAG_WIDTH): item = self._scene.addRect(j * LABELING_STEP, i * LABELING_STEP, LABELING_STEP, LABELING_STEP, tag_pen, self._tag_brushes[0]) tags.append(item) self._tags_items.append(tags) def _update_tags(self): for i in range(LABELING_TAG_HEIGHT): for j in range(LABELING_TAG_WIDTH): self._tags_items[i][j].setBrush( self._tag_brushes[self._tags[i, j]]) def set_image(self, path): self._image_item.setPixmap(QPixmap(path)) def clear(self): self._tags[:, :] = 0 self._update_tags() def get_tags(self): return self._tags.copy() def set_tags(self, tags): if tags.shape[0] != LABELING_TAG_HEIGHT or tags.shape[ 1] != LABELING_TAG_WIDTH: raise ValueError('Wrong tags shape') self._tags = tags.copy() self._update_tags() def resizeEvent(self, event): super().resizeEvent(event) self.fitInView(self._scene.sceneRect(), Qt.KeepAspectRatio) def mousePressEvent(self, event): point = self.mapToScene(event.pos()) index_x = int(point.x() / LABELING_STEP) index_y = int(point.y() / LABELING_STEP) if event.buttons() & Qt.LeftButton != 0: self._tags[index_y, index_x] = 1 elif event.buttons() & Qt.RightButton != 0: self._tags[index_y, index_x] = 0 self._update_tags() def mouseMoveEvent(self, event): point = self.mapToScene(event.pos()) index_x = int(point.x() / LABELING_STEP) index_y = int(point.y() / LABELING_STEP) if event.buttons() & Qt.LeftButton != 0: self._tags[index_y, index_x] = 1 elif event.buttons() & Qt.RightButton != 0: self._tags[index_y, index_x] = 0 self._update_tags()
class QtImg(QtWidgets.QWidget, Ui_Img): def __init__(self): super(self.__class__, self).__init__() Ui_Img.__init__(self) self.setupUi(self) self.bookId = "" self.epsId = 0 self.curIndex = 0 self.setWindowTitle("图片查看") self.setWindowModality(QtCore.Qt.ApplicationModal) self.resize(800, 900) self.radioButton.setChecked(True) self.index = 1 self.comboBox.setCurrentIndex(self.index) # self.setWindowFlags(Qt.FramelessWindowHint) self.graphicsView.setFrameStyle(QFrame.NoFrame) self.graphicsView.setObjectName("graphicsView") self.graphicsView.setBackgroundBrush(QColor(Qt.white)) self.graphicsView.setCursor(Qt.OpenHandCursor) self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform) self.graphicsView.setCacheMode(self.graphicsView.CacheBackground) self.graphicsView.setViewportUpdateMode(self.graphicsView.SmartViewportUpdate) self.graphicsItem = QGraphicsPixmapItem() self.graphicsItem.setFlags(QGraphicsPixmapItem.ItemIsFocusable | QGraphicsPixmapItem.ItemIsMovable) self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.CopyPicture) self.graphicsScene = QGraphicsScene(self) # 场景 self.graphicsView.setScene(self.graphicsScene) self.graphicsScene.addItem(self.graphicsItem) self.graphicsView.setMinimumSize(10, 10) self.pixMap = QPixmap("加载中") self.graphicsItem.setPixmap(self.pixMap) # self.radioButton.setChecked(True) self.isStripModel = False # self.radioButton.installEventFilter(self) # self.radioButton_2.installEventFilter(self) self.graphicsView.installEventFilter(self) self.graphicsView.setWindowFlag(Qt.FramelessWindowHint) self._delta = 0.1 self.scaleCnt = 0 def ShowImg(self, data): self.scaleCnt = 0 self.pixMap = QPixmap() self.pixMap.loadFromData(data) self.show() self.graphicsItem.setPixmap(self.pixMap) self.graphicsView.setSceneRect(QRectF(QPointF(0, 0), QPointF(self.pixMap.width(), self.pixMap.height()))) self.ScalePicture() def ScalePicture(self): rect = QRectF(self.graphicsItem.pos(), QSizeF( self.pixMap.size())) unity = self.graphicsView.transform().mapRect(QRectF(0, 0, 1, 1)) width = unity.width() height = unity.height() if width <= 0 or height <= 0: return self.graphicsView.scale(1 / width, 1 / height) viewRect = self.graphicsView.viewport().rect() sceneRect = self.graphicsView.transform().mapRect(rect) if sceneRect.width() <= 0 or sceneRect.height() <= 0: return x_ratio = viewRect.width() / sceneRect.width() y_ratio = viewRect.height() / sceneRect.height() x_ratio = y_ratio = min(x_ratio, y_ratio) self.graphicsView.scale(x_ratio, y_ratio) # if self.readImg.isStripModel: # height2 = self.pixMap.size().height() / 2 # height3 = self.graphicsView.size().height()/2 # height3 = height3/x_ratio # p = self.graphicsItem.pos() # self.graphicsItem.setPos(p.x(), p.y()+height2-height3) self.graphicsView.centerOn(rect.center()) for _ in range(abs(self.scaleCnt)): if self.scaleCnt > 0: self.graphicsView.scale(1.1, 1.1) else: self.graphicsView.scale(1/1.1, 1/1.1) def resizeEvent(self, event) -> None: super(self.__class__, self).resizeEvent(event) self.ScalePicture() def eventFilter(self, obj, ev): if ev.type() == QEvent.KeyPress: return True else: return super(self.__class__, self).eventFilter(obj, ev) def wheelEvent(self, event): if event.angleDelta().y() > 0: self.zoomIn() else: self.zoomOut() def zoomIn(self): """放大""" self.zoom(1.1) def zoomOut(self): """缩小""" self.zoom(1/1.1) def zoom(self, factor): """缩放 :param factor: 缩放的比例因子 """ _factor = self.graphicsView.transform().scale( factor, factor).mapRect(QRectF(0, 0, 1, 1)).width() if _factor < 0.07 or _factor > 100: # 防止过大过小 return if factor >= 1: self.scaleCnt += 1 else: self.scaleCnt -= 1 self.graphicsView.scale(factor, factor) def CopyPicture(self): clipboard = QApplication.clipboard() clipboard.setPixmap(self.pixMap) QtBubbleLabel.ShowMsgEx(self, "复制成功") return def ReduceScalePic(self): self.zoom(1/1.1) return def AddScalePic(self): self.zoom(1.1) return def OpenPicture(self): try: filename = QFileDialog.getOpenFileName(self, "Open Image", ".", "Image Files(*.jpg *.png)") if filename and len(filename) >= 1: name = filename[0] if os.path.isfile(name): f = open(name, "rb") data = f.read() f.close() QtImgMgr().ShowImg(data) except Exception as ex: Log.Error(ex) return def StartWaifu2x(self): if not QtImgMgr().data: return self.comboBox.setEnabled(False) self.changeButton.setEnabled(False) self.index = self.comboBox.currentIndex() index = self.comboBox.currentIndex() model = ToolUtil.GetModelByIndex(index) QtTask().AddConvertTask("", QtImgMgr().data, model, self.AddConvertBack, cleanFlag="QtImg") self.changeButton.setText("正在转换") return def AddConvertBack(self, data, waifuId, backParam, tick): if data: QtImgMgr().waifu2xData = data if self.radioButton.isChecked(): self.ShowImg(data) self.changeButton.setText("已转换") self.changeButton.setEnabled(False) else: self.changeButton.setEnabled(True) self.comboBox.setEnabled(True) return def SavePicture(self): data = QtImgMgr().waifu2xData if QtImgMgr().waifu2xData else QtImgMgr().data if not data: return try: today = time.strftime("%Y%m%d%H%M%S", time.localtime(time.time())) filepath = QFileDialog.getSaveFileName(self, "保存", "{}.jpg".format(today)) if filepath and len(filepath) >= 1: name = filepath[0] f = open(name, "wb") f.write(data) f.close() except Exception as es: Log.Error(es) return def SwithPicture(self): if self.radioButton.isChecked() and QtImgMgr().waifu2xData: self.ShowImg(QtImgMgr().waifu2xData) else: self.ShowImg(QtImgMgr().data) return def ChangeModel(self, index): if self.comboBox.currentIndex() == self.index: return # self.index = self.comboBox.currentIndex() self.changeButton.setText("转换") self.changeButton.setEnabled(True) return
class ConversationBust(QGraphicsItemGroup): def __init__(self, parent=None, left=False): super().__init__(parent) self._is_left = left self._portrait_textures: Optional[Dict[str, Texture]] = None self._portrait_image: Optional[Image] = None self._blush_image: Optional[Image] = None self._sweat_image: Optional[Image] = None self._blush_x = None self._blush_y = None self._sweat_x = None self._sweat_y = None self._portrait_view = QGraphicsPixmapItem() self.addToGroup(self._portrait_view) def clear(self): self._portrait_textures = None self._portrait_image = None self._blush_image = None self._sweat_image = None self._blush_x = None self._blush_y = None self._sweat_x = None self._sweat_y = None self._portrait_view.setPixmap(QPixmap()) def set_portraits(self, fid: str): self.clear() conversation_service = locator.get_scoped("ConversationService") portraits = conversation_service.get_portraits_for_fid(fid) self._portrait_textures = portraits blush_and_sweat_coordinates = conversation_service.get_blush_and_sweat_coordinates( fid, "st") if blush_and_sweat_coordinates: (self._blush_x, self._blush_y) = blush_and_sweat_coordinates[0] (self._sweat_x, self._sweat_y) = blush_and_sweat_coordinates[1] def set_emotions(self, emotions: List[str]): emotions = emotions.copy() if "照" in emotions: self.add_blush() emotions.remove("照") if "汗" in emotions: self.add_sweat() emotions.remove("汗") if emotions: self._portrait_image = self._get_image_for_emotion(emotions[0]) def add_blush(self): self._blush_image = self._get_image_for_emotion("照") def add_sweat(self): self._sweat_image = self._get_image_for_emotion("汗") def _get_image_for_emotion(self, emotion: str): if not self._portrait_textures: return None if emotion not in self._portrait_textures: return None return self._portrait_textures[emotion].raw_image() def show_normal(self): self._portrait_view.setPixmap(self._assemble_image()) def show_faded(self): self._portrait_view.setPixmap(self._assemble_image(faded=True)) def _assemble_image(self, faded=False) -> QPixmap: if not self._portrait_image: return QPixmap() image: Image.Image = self._portrait_image.copy() if self._blush_image: image.paste(self._blush_image, (self._blush_x, self._blush_y), self._blush_image) if self._sweat_image: image.paste(self._sweat_image, (self._sweat_x, self._sweat_y), self._sweat_image) if faded: image = locator.get_scoped("ConversationService").fade_image(image) if self._is_left: return image.transpose(Image.FLIP_LEFT_RIGHT).toqpixmap() else: return image.toqpixmap()
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 SlideshowWindow(QWidget, Ui_SlideshowWindow): def __init__(self, sd_id, img_serial, parent=None): super(SlideshowWindow, self).__init__(parent) self.setupUi(self) self._curr_sd_id = sd_id self._curr_img_serial = img_serial self._is_slideshow_looped = settings.get(SettingType.SLIDESHOW_LOOP, False, 'bool') self._slideshow_iterval = settings.get(SettingType.SLIDESHOW_INTERVAL, 1000, 'int') self._mouse_idle_interval = 1000 self._is_slideshow = True self._gfx_item = None self._last_mouse_pos = QtCore.QPoint() self._curr_mouse_pos = QtCore.QPoint() self._is_mouse_inside_controls = False self._shortcut_exit = QShortcut(QKeySequence(QtCore.Qt.Key_Escape), self) self._shortcut_exit.activated.connect(self.closeWindow) self._timer = QTimer() self._timer.setSingleShot(True) self._timer.timeout.connect(self.slide_next_img) self._idle_timer = QTimer() self._timer.setSingleShot(True) self._idle_timer.timeout.connect(self.hide_slideshow_controls) self.gfx_slide = SlideshowGraphicsView() self.gfx_slide.mouse_moved.connect(self.on_mouse_moved) self.horizontalLayout.addWidget(self.gfx_slide) self._gfx_scene = QtWidgets.QGraphicsScene() self.gfx_slide.setScene(self._gfx_scene) self.gfx_slide.setAlignment(QtCore.Qt.AlignCenter) self._control_widget = SlideshowControlWidget(self._slideshow_iterval) self._control_widget.stop_slideshow.connect(self.closeWindow) self._control_widget.start_slideshow.connect(self.slideshow_start) self._control_widget.next_slide.connect(self.slide_next_img) self._control_widget.prev_slide.connect(self.slide_prev_img) self._control_widget.slideshow_interval_changed.connect( self.on_slideshow_interval_changed) self._meta_files_mgr = MetaFilesManager() self._meta_files_mgr.connect() def resizeEvent(self, event): if event.spontaneous(): self._control_widget_proxy = self._gfx_scene.addWidget( self._control_widget) self._control_widget_proxy.setY( self.gfx_slide.size().height() - self._control_widget_proxy.size().height()) self._control_widget_proxy.setZValue(1) self._control_widget_proxy.setFlag( QtWidgets.QGraphicsItem.ItemIsFocusable, True) self.slideshow_start() @Slot(object) def on_mouse_moved(self, mouse_pos): if self.gfx_slide.mapFromScene( self._control_widget_proxy.geometry()).boundingRect().contains( mouse_pos): self._is_mouse_inside_controls = True else: self._is_mouse_inside_controls = False self.show_slideshow_controls() self.slideshow_stop() self._idle_timer.stop() self._idle_timer.start(self._mouse_idle_interval) @Slot() def slideshow_start(self): self.hide_slideshow_controls() dr_img = self._meta_files_mgr.get_scan_dir_image( self._curr_sd_id, self._curr_img_serial) self.load_image(dr_img['abspath']) self._timer.start(self._slideshow_iterval) def slideshow_stop(self): self._timer.stop() @Slot() def slide_next_img(self): print(self._curr_img_serial) self._curr_img_serial += 1 dr_img = self._meta_files_mgr.get_scan_dir_image( self._curr_sd_id, self._curr_img_serial) if not dr_img: if self._is_slideshow_looped: self._curr_img_serial = 0 self._timer.start(self._slideshow_iterval) else: self._curr_img_serial -= 1 self._timer.stop() else: self.load_image(dr_img['abspath']) if self._is_slideshow: self._timer.start(self._slideshow_iterval) @Slot() def slide_prev_img(self): self._curr_img_serial -= 1 dr_img = self._meta_files_mgr.get_scan_dir_image( self._curr_sd_id, self._curr_img_serial) if not dr_img: self._curr_img_serial += 1 else: self.load_image(dr_img['abspath']) @Slot(object) def on_slideshow_interval_changed(self, interval): self._slideshow_iterval = interval def load_image(self, abspath): if self._gfx_item: self._gfx_scene.removeItem(self._gfx_item) self.gfx_slide.viewport().update() self.gfx_slide.centerOn(0, 0) self._gfx_item = QGraphicsPixmapItem() img = QImage(abspath) pixmap = QPixmap(img) pixmap = pixmap.scaled(self.gfx_slide.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation) self._control_widget_proxy.setX((pixmap.width() / 2) - ( self._control_widget_proxy.size().width() / 2)) self._gfx_item.setPixmap(pixmap) self._gfx_scene.addItem(self._gfx_item) self._gfx_scene.setSceneRect(self._gfx_item.sceneBoundingRect()) @Slot() def show_slideshow_controls(self): self.setCursor(QtCore.Qt.ArrowCursor) self._control_widget.setMouseTracking(True) self._control_widget.show() @Slot() def hide_slideshow_controls(self): if not self._is_mouse_inside_controls: self.setCursor(QtCore.Qt.BlankCursor) self._control_widget.hide() @Slot() def closeWindow(self): self._timer.stop() self._meta_files_mgr.disconnect() self.close()
class NodeItem(AbstractNodeItem): """ Base Node item. Args: name (str): name displayed on the node. parent (QtWidgets.QGraphicsItem): parent item. """ def __init__(self, name='node', parent=None): super(NodeItem, self).__init__(name, parent) pixmap = QtGui.QPixmap(ICON_NODE_BASE) if pixmap.size().height() > NODE_ICON_SIZE: pixmap = pixmap.scaledToHeight(NODE_ICON_SIZE, QtCore.Qt.SmoothTransformation) self._properties['icon'] = ICON_NODE_BASE self._icon_item = QGraphicsPixmapItem(pixmap, self) self._icon_item.setTransformationMode(QtCore.Qt.SmoothTransformation) self._text_item = QGraphicsTextItem(self.name, self) self._x_item = XDisabledItem(self, 'DISABLED') self._input_items = {} self._output_items = {} self._widgets = {} def paint(self, painter, option, widget): """ Draws the node base not the ports. Args: painter (QtGui.QPainter): painter used for drawing the item. option (QtGui.QStyleOptionGraphicsItem): used to describe the parameters needed to draw. widget (QtWidgets.QWidget): not used. """ painter.save() bg_border = 1.0 rect = QtCore.QRectF(0.5 - (bg_border / 2), 0.5 - (bg_border / 2), self._width + bg_border, self._height + bg_border) radius = 2 border_color = QtGui.QColor(*self.border_color) path = QtGui.QPainterPath() path.addRoundedRect(rect, radius, radius) painter.setPen(QtGui.QPen(border_color.darker(200), 1.5)) painter.drawPath(path) rect = self.boundingRect() bg_color = QtGui.QColor(*self.color) painter.setBrush(bg_color) painter.setPen(QtCore.Qt.NoPen) painter.drawRoundRect(rect, radius, radius) if self.selected and NODE_SEL_COLOR: painter.setBrush(QtGui.QColor(*NODE_SEL_COLOR)) painter.drawRoundRect(rect, radius, radius) label_rect = QtCore.QRectF(rect.left() + (radius / 2), rect.top() + (radius / 2), self._width - (radius / 1.25), 28) path = QtGui.QPainterPath() path.addRoundedRect(label_rect, radius / 1.5, radius / 1.5) painter.setBrush(QtGui.QColor(0, 0, 0, 50)) painter.fillPath(path, painter.brush()) border_width = 0.8 if self.selected and NODE_SEL_BORDER_COLOR: border_width = 1.2 border_color = QtGui.QColor(*NODE_SEL_BORDER_COLOR) border_rect = QtCore.QRectF(rect.left() - (border_width / 2), rect.top() - (border_width / 2), rect.width() + border_width, rect.height() + border_width) pen = QtGui.QPen(border_color, border_width) pen.setCosmetic(self.viewer().get_zoom() < 0.0) path = QtGui.QPainterPath() path.addRoundedRect(border_rect, radius, radius) painter.setBrush(QtCore.Qt.NoBrush) painter.setPen(pen) painter.drawPath(path) painter.restore() def mousePressEvent(self, event): if event.button() == QtCore.Qt.MouseButton.LeftButton: start = PortItem().boundingRect().width() end = self.boundingRect().width() - start x_pos = event.pos().x() if not start <= x_pos <= end: event.ignore() super(NodeItem, self).mousePressEvent(event) def mouseReleaseEvent(self, event): if event.modifiers() == QtCore.Qt.AltModifier: event.ignore() return super(NodeItem, self).mouseReleaseEvent(event) def itemChange(self, change, value): if change == self.ItemSelectedChange and self.scene(): self.reset_pipes() if value: self.hightlight_pipes() self.setZValue(Z_VAL_NODE) if not self.selected: self.setZValue(Z_VAL_NODE + 1) return super(NodeItem, self).itemChange(change, value) def _tooltip_disable(self, state): tooltip = '<b>{}</b>'.format(self._properties['name']) if state: tooltip += ' <font color="red"><b>(DISABLED)</b></font>' tooltip += '<br/>{}<br/>'.format(self._properties['type']) self.setToolTip(tooltip) def _set_base_size(self): """ setup initial base size. """ self._width = NODE_WIDTH self._height = NODE_HEIGHT width, height = self.calc_size() if width > self._width: self._width = width if height > self._height: self._height = height def _set_text_color(self, color): """ set text color. Args: color (tuple): color value in (r, g, b, a). """ text_color = QtGui.QColor(*color) for port, text in self._input_items.items(): text.setDefaultTextColor(text_color) for port, text in self._output_items.items(): text.setDefaultTextColor(text_color) self._text_item.setDefaultTextColor(text_color) def activate_pipes(self): """ active pipe color. """ ports = self.inputs + self.outputs for port in ports: for pipe in port.connected_pipes: pipe.activate() def hightlight_pipes(self): """ highlight pipe color. """ ports = self.inputs + self.outputs for port in ports: for pipe in port.connected_pipes: pipe.highlight() def reset_pipes(self): """ reset the pipe color. """ ports = self.inputs + self.outputs for port in ports: for pipe in port.connected_pipes: pipe.reset() def calc_size(self): """ calculate minimum node size. """ width = 0.0 if self._widgets: widget_widths = [ w.boundingRect().width() for w in self._widgets.values() ] width = max(widget_widths) if self._text_item.boundingRect().width() > width: width = self._text_item.boundingRect().width() port_height = 0.0 if self._input_items: input_widths = [] for port, text in self._input_items.items(): input_width = port.boundingRect().width() * 2 if text.isVisible(): input_width += text.boundingRect().width() input_widths.append(input_width) width += max(input_widths) port = list(self._input_items.keys())[0] port_height = port.boundingRect().height() * 2 if self._output_items: output_widths = [] for port, text in self._output_items.items(): output_width = port.boundingRect().width() * 2 if text.isVisible(): output_width += text.boundingRect().width() output_widths.append(output_width) width += max(output_widths) port = list(self._output_items.keys())[0] port_height = port.boundingRect().height() * 2 in_count = len([p for p in self.inputs if p.isVisible()]) out_count = len([p for p in self.outputs if p.isVisible()]) height = port_height * (max([in_count, out_count]) + 2) if self._widgets: wid_height = sum( [w.boundingRect().height() for w in self._widgets.values()]) if wid_height > height: height = wid_height + (wid_height / len(self._widgets)) height += 10 return width, height def arrange_icon(self): """ Arrange node icon to the default top left of the node. """ self._icon_item.setPos(2.0, 2.0) def arrange_label(self): """ Arrange node label to the default top center of the node. """ text_rect = self._text_item.boundingRect() text_x = (self._width / 2) - (text_rect.width() / 2) self._text_item.setPos(text_x, 1.0) def arrange_widgets(self): """ Arrange node widgets to the default center of the node. """ if not self._widgets: return wid_heights = sum( [w.boundingRect().height() for w in self._widgets.values()]) pos_y = self._height / 2 pos_y -= wid_heights / 2 for name, widget in self._widgets.items(): rect = widget.boundingRect() pos_x = (self._width / 2) - (rect.width() / 2) widget.setPos(pos_x, pos_y) pos_y += rect.height() def arrange_ports(self, padding_x=0.0, padding_y=0.0): """ Arrange input, output ports in the node layout. Args: padding_x (float): horizontal padding. padding_y: (float): vertical padding. """ width = self._width - padding_x height = self._height - padding_y # adjust input position inputs = [p for p in self.inputs if p.isVisible()] if inputs: port_width = inputs[0].boundingRect().width() port_height = inputs[0].boundingRect().height() chunk = (height / len(inputs)) port_x = (port_width / 2) * -1 port_y = (chunk / 2) - (port_height / 2) for port in inputs: port.setPos(port_x + padding_x, port_y + (padding_y / 2)) port_y += chunk # adjust input text position for port, text in self._input_items.items(): if not port.isVisible(): continue txt_height = text.boundingRect().height() - 8.0 txt_x = port.x() + port.boundingRect().width() txt_y = port.y() - (txt_height / 2) text.setPos(txt_x + 3.0, txt_y) # adjust output position outputs = [p for p in self.outputs if p.isVisible()] if outputs: port_width = outputs[0].boundingRect().width() port_height = outputs[0].boundingRect().height() chunk = height / len(outputs) port_x = width - (port_width / 2) port_y = (chunk / 2) - (port_height / 2) for port in outputs: port.setPos(port_x, port_y + (padding_y / 2)) port_y += chunk # adjust output text position for port, text in self._output_items.items(): if not port.isVisible(): continue txt_width = text.boundingRect().width() txt_height = text.boundingRect().height() - 8.0 txt_x = width - txt_width - (port.boundingRect().width() / 2) txt_y = port.y() - (txt_height / 2) text.setPos(txt_x - 1.0, txt_y) def offset_icon(self, x=0.0, y=0.0): """ offset the icon in the node layout. Args: x (float): horizontal x offset y (float): vertical y offset """ if self._icon_item: icon_x = self._icon_item.pos().x() + x icon_y = self._icon_item.pos().y() + y self._icon_item.setPos(icon_x, icon_y) def offset_label(self, x=0.0, y=0.0): """ offset the label in the node layout. Args: x (float): horizontal x offset y (float): vertical y offset """ icon_x = self._text_item.pos().x() + x icon_y = self._text_item.pos().y() + y self._text_item.setPos(icon_x, icon_y) def offset_widgets(self, x=0.0, y=0.0): """ offset the node widgets in the node layout. Args: x (float): horizontal x offset y (float): vertical y offset """ for name, widget in self._widgets.items(): pos_x = widget.pos().x() pos_y = widget.pos().y() widget.setPos(pos_x + x, pos_y + y) def offset_ports(self, x=0.0, y=0.0): """ offset the ports in the node layout. Args: x (float): horizontal x offset y (float): vertical y offset """ for port, text in self._input_items.items(): port_x, port_y = port.pos().x(), port.pos().y() text_x, text_y = text.pos().x(), text.pos().y() port.setPos(port_x + x, port_y + y) text.setPos(text_x + x, text_y + y) for port, text in self._output_items.items(): port_x, port_y = port.pos().x(), port.pos().y() text_x, text_y = text.pos().x(), text.pos().y() port.setPos(port_x + x, port_y + y) text.setPos(text_x + x, text_y + y) def post_init(self, viewer=None, pos=None): """ Called after node has been added into the scene. Adjust the node layout and form after the node has been added. Args: viewer (NodeGraphQt.widgets.viewer.NodeViewer): not used pos (tuple): cursor position. """ # setup initial base size. self._set_base_size() # set text color when node is initialized. self._set_text_color(self.text_color) # set the tooltip self._tooltip_disable(self.disabled) # --- setup node layout --- # arrange label text self.arrange_label() self.offset_label(0.0, 5.0) # arrange icon self.arrange_icon() self.offset_icon(5.0, 2.0) # arrange node widgets self.arrange_widgets() self.offset_widgets(0.0, 10.0) # arrange input and output ports. self.arrange_ports(padding_y=35.0) self.offset_ports(0.0, 15.0) # set initial node position. if pos: self.xy_pos = pos @property def icon(self): return self._properties['icon'] @icon.setter def icon(self, path=None): self._properties['icon'] = path path = path or ICON_NODE_BASE pixmap = QtGui.QPixmap(path) if pixmap.size().height() > NODE_ICON_SIZE: pixmap = pixmap.scaledToHeight(NODE_ICON_SIZE, QtCore.Qt.SmoothTransformation) self._icon_item.setPixmap(pixmap) if self.scene(): self.post_init() @AbstractNodeItem.width.setter def width(self, width=0.0): w, h = self.calc_size() width = width if width > w else w AbstractNodeItem.width.fset(self, width) @AbstractNodeItem.height.setter def height(self, height=0.0): w, h = self.calc_size() h = 70 if h < 70 else h height = height if height > h else h AbstractNodeItem.height.fset(self, height) @AbstractNodeItem.disabled.setter def disabled(self, state=False): AbstractNodeItem.disabled.fset(self, state) for n, w in self._widgets.items(): w.widget.setDisabled(state) self._tooltip_disable(state) self._x_item.setVisible(state) @AbstractNodeItem.selected.setter def selected(self, selected=False): AbstractNodeItem.selected.fset(self, selected) if selected: self.hightlight_pipes() @AbstractNodeItem.name.setter def name(self, name=''): AbstractNodeItem.name.fset(self, name) self._text_item.setPlainText(name) if self.scene(): self.post_init() @property def inputs(self): """ Returns: list[PortItem]: input port graphic items. """ return list(self._input_items.keys()) @property def outputs(self): """ Returns: list[PortItem]: output port graphic items. """ return list(self._output_items.keys()) def add_input(self, name='input', multi_port=False, display_name=True): """ Args: name (str): name for the port. multi_port (bool): allow multiple connections. display_name (bool): display the port name. Returns: PortItem: input item widget """ port = PortItem(self) port.name = name port.port_type = IN_PORT port.multi_connection = multi_port port.display_name = display_name text = QGraphicsTextItem(port.name, self) text.font().setPointSize(8) text.setFont(text.font()) text.setVisible(display_name) self._input_items[port] = text if self.scene(): self.post_init() return port def add_output(self, name='output', multi_port=False, display_name=True): """ Args: name (str): name for the port. multi_port (bool): allow multiple connections. display_name (bool): display the port name. Returns: PortItem: output item widget """ port = PortItem(self) port.name = name port.port_type = OUT_PORT port.multi_connection = multi_port port.display_name = display_name text = QGraphicsTextItem(port.name, self) text.font().setPointSize(8) text.setFont(text.font()) text.setVisible(display_name) self._output_items[port] = text if self.scene(): self.post_init() return port def get_input_text_item(self, port_item): """ Args: port_item (PortItem): port item. Returns: QGraphicsTextItem: graphic item used for the port text. """ return self._input_items[port_item] def get_output_text_item(self, port_item): """ Args: port_item (PortItem): port item. Returns: QGraphicsTextItem: graphic item used for the port text. """ return self._output_items[port_item] @property def widgets(self): return dict(self._widgets) def add_combo_menu(self, name='', label='', items=None, tooltip=''): items = items or [] widget = NodeComboBox(self, name, label, items) widget.setToolTip(tooltip) self.add_widget(widget) return widget def add_text_input(self, name='', label='', text='', tooltip=''): widget = NodeLineEdit(self, name, label, text) widget.setToolTip(tooltip) self.add_widget(widget) return widget def add_checkbox(self, name='', label='', text='', state=False, tooltip=''): widget = NodeCheckBox(self, name, label, text, state) widget.setToolTip(tooltip) self.add_widget(widget) return widget def add_widget(self, widget): if isinstance(widget, NodeBaseWidget): self._widgets[widget.name] = widget else: raise TypeError('{} is not an instance of a node widget.') def get_widget(self, name): widget = self._widgets.get(name) if widget: return widget raise KeyError('node has no widget "{}"'.format(name)) def delete(self): for port, text in self._input_items.items(): port.delete() for port, text in self._output_items.items(): port.delete() super(NodeItem, self).delete() def from_dict(self, node_dict): super(NodeItem, self).from_dict(node_dict) widgets = node_dict.pop('widgets', {}) for name, value in widgets.items(): if self._widgets.get(name): self._widgets[name].value = value
class QtImgFrame(QFrame): def __init__(self, readImg): QFrame.__init__(self) self._readImg = weakref.ref(readImg) self.graphicsView = QtWidgets.QGraphicsView(self) self.graphicsView.setTransformationAnchor( self.graphicsView.AnchorUnderMouse) self.graphicsView.setResizeAnchor(self.graphicsView.AnchorUnderMouse) self.graphicsView.setFrameStyle(QFrame.NoFrame) self.graphicsView.setObjectName("graphicsView") self.qtTool = QtImgTool(self) self.graphicsView.setBackgroundBrush(QColor(Qt.white)) self.graphicsView.setCursor(Qt.OpenHandCursor) self.graphicsView.setResizeAnchor(self.graphicsView.AnchorViewCenter) self.graphicsView.setTransformationAnchor( self.graphicsView.AnchorViewCenter) self.graphicsView.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.graphicsView.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform) self.graphicsView.setCacheMode(self.graphicsView.CacheBackground) self.graphicsView.setViewportUpdateMode( self.graphicsView.SmartViewportUpdate) self.graphicsItem = QGraphicsPixmapItem() self.graphicsItem.setFlags(QGraphicsPixmapItem.ItemIsFocusable | QGraphicsPixmapItem.ItemIsMovable) self.graphicsScene = QGraphicsScene(self) # 场景 self.graphicsView.setScene(self.graphicsScene) self.graphicsScene.addItem(self.graphicsItem) self.graphicsView.setMinimumSize(10, 10) self.graphicsView.installEventFilter(self) self.graphicsView.setWindowFlag(Qt.FramelessWindowHint) self.pixMap = QPixmap() self.scaleCnt = 0 @property def readImg(self): return self._readImg() def resizeEvent(self, event) -> None: super(self.__class__, self).resizeEvent(event) self.ScaleFrame() self.ScalePicture() def ScaleFrame(self): size = self.size() w = size.width() h = size.height() self.graphicsView.setGeometry(0, 0, w, h) h = min(700, h) self.qtTool.setGeometry(w - 220, 0, 220, h) return def ScalePicture(self): if self.readImg.isStripModel: self.graphicsItem.setPos(0, 0) rect = QRectF(self.graphicsItem.pos(), QSizeF(self.pixMap.size())) unity = self.graphicsView.transform().mapRect(QRectF(0, 0, 1, 1)) width = unity.width() height = unity.height() if width <= 0 or height <= 0: return self.graphicsView.scale(1 / width, 1 / height) viewRect = self.graphicsView.viewport().rect() sceneRect = self.graphicsView.transform().mapRect(rect) if sceneRect.width() <= 0 or sceneRect.height() <= 0: return x_ratio = viewRect.width() / sceneRect.width() y_ratio = viewRect.height() / sceneRect.height() if not self.readImg.isStripModel: x_ratio = y_ratio = min(x_ratio, y_ratio) else: x_ratio = y_ratio = max(x_ratio, y_ratio) self.graphicsView.scale(x_ratio, y_ratio) if self.readImg.isStripModel: height2 = self.pixMap.size().height() / 2 height3 = self.graphicsView.size().height() / 2 height3 = height3 / x_ratio p = self.graphicsItem.pos() self.graphicsItem.setPos(p.x(), p.y() + height2 - height3) self.graphicsView.centerOn(rect.center()) for _ in range(abs(self.scaleCnt)): if self.scaleCnt > 0: self.graphicsView.scale(1.1, 1.1) else: self.graphicsView.scale(1 / 1.1, 1 / 1.1)
def initUI(self): self.scene = QGraphicsScene() self.pixmap = QGraphicsPixmapItem() self.scene.addItem(self.pixmap) self.boxRect = None # option to draw box around overlay spots if False: outlineBox = self.imageFile.box( self.imageFile.findCenterOfMass(self.frameIdx)) self.scene.addRect(QRect(*outlineBox), pen=QtGui.QPen(QtCore.Qt.blue, 1)) self.boxRect = self.scene.items()[ 0] # not the best way to get rect self.view = MyGraphicsView(self) self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setScene(self.scene) self.setCentralWidget(self.view) controlDock = QDockWidget() controlDock.setFeatures(QDockWidget.NoDockWidgetFeatures) self.addDockWidget(Qt.TopDockWidgetArea, controlDock) main_layout = QHBoxLayout() main_layout.setContentsMargins(0, 0, 0, 0) # first frame button firstButton = QPushButton('<<', self) firstButton.clicked.connect(self.firstFrame) main_layout.addWidget(firstButton) # previous frame button prevButton = QPushButton('<', self) prevButton.clicked.connect(self.prevFrame) main_layout.addWidget(prevButton) # next frame button nextButton = QPushButton('>', self) nextButton.clicked.connect(self.nextFrame) main_layout.addWidget(nextButton) # last frame button lastButton = QPushButton('>>', self) lastButton.clicked.connect(self.lastFrame) main_layout.addWidget(lastButton) # zoom button zoomButton = QPushButton('zoom', self) zoomButton.clicked.connect(self.toggleZoom) main_layout.addWidget(zoomButton) # zoom button overlayButton = QPushButton('color', self) overlayButton.clicked.connect(self.toggleOverlay) main_layout.addWidget(overlayButton) # add dock widget dockContainerWidget = QWidget(controlDock) dockContainerWidget.setLayout(main_layout) dockContainerWidget.setGeometry(0, 0, self.imageFile.imgW, 20) self.setFixedSize(self.imageFile.imgW, self.imageFile.imgH + dockContainerWidget.height()) self.show()
class InteractiveMap(QGraphicsView): def __init__(self, parent): super(InteractiveMap, self).__init__() # setup properties of class self.countries = {} self.scene = QGraphicsScene() self.backgroundMapImg = QImage() self.renderer = QSvgRenderer() self.initialSliderPosition = {"horizontal": 0, "vertical": 0} self.initialMousePosition = QPoint() self.isMouseMoving = False self.currentScale = 1.25 self.currentlySelected = "" self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # prevents unintended scrolling with middle mouse button self.horizontalScrollBar().setEnabled(False) self.verticalScrollBar().setEnabled(False) self.displayMap() self.setScene(self.scene) self.scale(self.currentScale, self.currentScale) # scroll area of map is centered around Europe self.horizontalScrollBar().setValue(1500) self.verticalScrollBar().setValue(100) def displayMap(self): # TODO: modulate the gui.py file more # set the background behind countries to be blue (representing the sea) seaColouredBrush = QBrush(QColor("lightskyblue")) self.setBackgroundBrush(seaColouredBrush) # display image layer for detecting mouse presses self.backgroundMapImg.load("resources/bg_map.png", "png") self.backgroundMap = QGraphicsPixmapItem( QPixmap.fromImage(self.backgroundMapImg)) self.backgroundMap.hide() self.scene.addItem(self.backgroundMap) # display individual countries as SVG elements self.renderer.load("resources/coloured_map_no_text.svg") # TODO: Should only occur when the bootstrapping "script" is run with open("countries.json") as file: countries = json.load(file) # TODO: need to add error checking for opening json file for country in countries: self.countries[country] = Country(self, country, countries[country]) # country added to the database db.countries.add({ "iso": countries[country]["iso"], "name": countries[country]["name"], "knoemaKey": countries[country]["datasetIdentifiers"]["knoemaKey"], "knoemaRegionId": countries[country]["datasetIdentifiers"]["knoemaRegionId"] }) self.scene.addItem(self.countries[country]) # MAKESHIFT BOOTSTRAPPING CODE # TODO: A button should trigger this instead and somewhere else # db.indicators.createIndicatorTypes() # db.countries.grabCountryData() def mousePressEvent(self, event): if not (event.buttons() == Qt.RightButton or event.buttons() == Qt.MiddleButton): return event.ignore() self.initialMousePosition = event.pos() self.initialSliderPosition["horizontal"] = self.horizontalScrollBar( ).value() self.initialSliderPosition["vertical"] = self.verticalScrollBar( ).value() def mouseMoveEvent(self, event): if not (event.buttons() == Qt.RightButton or event.buttons() == Qt.MiddleButton): return event.ignore() self.isMouseMoving = True changeX = self.initialMousePosition.x() - event.x() changeY = self.initialMousePosition.y() - event.y() self.horizontalScrollBar().setValue( self.initialSliderPosition["horizontal"] + changeX) self.verticalScrollBar().setValue( self.initialSliderPosition["vertical"] + changeY) def mouseReleaseEvent(self, event): if self.isMouseMoving: self.isMouseMoving = False else: # check what country corresponds to colour if event.button() == Qt.LeftButton: # get the colour of the pixel on the background map image that is currently selected by the pointer pixelColour = self.backgroundMapImg.pixelColor( (event.pos() + QPoint(self.horizontalScrollBar().value(), self.verticalScrollBar().value())) / self.currentScale) # if a country is already selected, deselect it if self.currentlySelected: self.countries[self.currentlySelected].deselectCountry() # linear search ??? for country in self.countries: if self.countries[country].colour == pixelColour: self.countries[country].selectCountry() self.currentlySelected = country return self.findCountry(self.countries[country].name) self.parent().countryInfo.hide() def scaleMap(self, movement): # zooming in and out of map if movement == "in": self.scale(1.25, 1.25) elif movement == "out": self.scale(0.75, 0.75) # self.transform.m11() refers to the horizontal scale factor # this is updated in order to ensure that mouse presses on countries are still detected when scale is changed self.currentScale = self.transform().m11() def wheelEvent(self, event): movement = event.angleDelta().y() if movement == 120: self.scaleMap("in") elif movement == -120: self.scaleMap("out") def findCountry(self, country): text = QLabel() text.setText(country) self.parent().showCountryDock(text) qDebug("Country clicked: " + country)