class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.resize(600, 400) self.view = QMyGraphicsView() # 创建视图窗口 self.setCentralWidget(self.view) # 设置中央控件 self.statusbar = self.statusBar() # 添加状态栏 self.labviewcorrd = QLabel('view坐标:') self.labviewcorrd.setMinimumWidth(150) self.statusbar.addWidget(self.labviewcorrd) self.labscenecorrd = QLabel('scene坐标:') self.labscenecorrd.setMinimumWidth(150) self.statusbar.addWidget(self.labscenecorrd) self.labitemcorrd = QLabel('item坐标:') self.labitemcorrd.setMinimumWidth(150) self.statusbar.addWidget(self.labitemcorrd) rect = QRectF(-200, -100, 400, 200) self.scene = QGraphicsScene(rect) # 创建场景 # 参数:场景区域 # 场景坐标原点默认在场景中心---场景中心位于界面中心 self.view.setScene(self.scene) # 给视图窗口设置场景 item1 = QGraphicsRectItem(rect) # 创建矩形---以场景为坐标 item1.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) # 给图元设置标志 # QGraphicsItem.ItemIsSelectable---可选择 # QGraphicsItem.ItemIsFocusable---可设置焦点 # QGraphicsItem.ItemIsMovable---可移动 # QGraphicsItem.ItemIsPanel--- self.scene.addItem(item1) # 给场景添加图元 for pos, color in zip([rect.left(), 0, rect.right()], [Qt.red, Qt.yellow, Qt.blue]): item = QGraphicsEllipseItem(-50, -50, 100, 100) # 创建椭圆--场景坐标 # 参数1 参数2 矩形左上角坐标 # 参数3 参数4 矩形的宽和高 item.setPos(pos, 0) # 给图元设置在场景中的坐标(移动图元)--图元中心坐标 item.setBrush(color) # 设置画刷 item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) self.scene.addItem(item) self.scene.clearSelection() # 【清除选择】 self.view.sigMouseMovePoint.connect(self.slotMouseMovePoint) def slotMouseMovePoint(self, pt): self.labviewcorrd.setText('view坐标:{},{}'.format(pt.x(), pt.y())) ptscene = self.view.mapToScene(pt) # 把view坐标转换为场景坐标 self.labscenecorrd.setText('scene坐标:{:.0f},{:.0f}'.format( ptscene.x(), ptscene.y())) item = self.scene.itemAt(ptscene, self.view.transform()) # 在场景某点寻找图元--最上面的图元 # 返回值:图元地址 # 参数1 场景点坐标 # 参数2 ???? if item is not None: ptitem = item.mapFromScene(ptscene) # 把场景坐标转换为图元坐标 self.labitemcorrd.setText('item坐标:{:.0f},{:.0f}'.format( ptitem.x(), ptitem.y()))
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.ui=Ui_MainWindow() #创建UI对象 self.ui.setupUi(self) #构造UI界面 self.setWindowTitle("Demo8_6, Graphics View绘图") self.__buildStatusBar() #构造状态栏 self.__iniGraphicsSystem() #初始化 graphics View系统 self.__ItemId=1 #绘图项自定义数据的key self.__ItemDesc=2 #绘图项自定义数据的key self.__seqNum=0 #每个图形项设置一个序号 self.__backZ=0 #后置序号 self.__frontZ=0 #前置序号 ## ==============自定义功能函数============ def __buildStatusBar(self): ##构造状态栏 self.__labViewCord=QLabel("View 坐标:") self.__labViewCord.setMinimumWidth(150) self.ui.statusBar.addWidget(self.__labViewCord) self.__labSceneCord=QLabel("Scene 坐标:") self.__labSceneCord.setMinimumWidth(150) self.ui.statusBar.addWidget(self.__labSceneCord) self.__labItemCord=QLabel("Item 坐标:") self.__labItemCord.setMinimumWidth(150) self.ui.statusBar.addWidget(self.__labItemCord) self.__labItemInfo=QLabel("ItemInfo: ") self.ui.statusBar.addPermanentWidget(self.__labItemInfo) def __iniGraphicsSystem(self): ##初始化 Graphics View系统 self.view=QmyGraphicsView(self) #创建图形视图组件 self.setCentralWidget(self.view) self.scene=QGraphicsScene(-300,-200,600,200) #创建QGraphicsScene self.view.setScene(self.scene) #与view关联 self.view.setCursor(Qt.CrossCursor) #设置鼠标 self.view.setMouseTracking(True) self.view.setDragMode(QGraphicsView.RubberBandDrag) ## 4个信号与槽函数的关联 self.view.mouseMove.connect(self.do_mouseMove) #鼠标移动 self.view.mouseClicked.connect(self.do_mouseClicked) #左键按下 self.view.mouseDoubleClick.connect(self.do_mouseDoubleClick) #鼠标双击 self.view.keyPress.connect(self.do_keyPress) #左键按下 def __setItemProperties(self,item,desc): ##item是具体类型的QGraphicsItem item.setFlag(QGraphicsItem.ItemIsFocusable) item.setFlag(QGraphicsItem.ItemIsMovable) item.setFlag(QGraphicsItem.ItemIsSelectable) self.__frontZ=1+self.__frontZ item.setZValue(self.__frontZ) #叠放次序 item.setPos(-150+random.randint(1,200),-200+random.randint(1,200)) self.__seqNum=1+self.__seqNum item.setData(self.__ItemId,self.__seqNum) #图件编号 item.setData(self.__ItemDesc,desc) #图件描述 self.scene.addItem(item) self.scene.clearSelection() item.setSelected(True) def __setBrushColor(self,item): ##设置填充颜色 color=item.brush().color() color=QColorDialog.getColor(color,self,"选择填充颜色") if color.isValid(): item.setBrush(QBrush(color)) ##==============event 处理函数======================= ## ==========由connectSlotsByName() 自动连接的槽函数================== ##==============创建基本图件============== @pyqtSlot() ##添加一个矩形 def on_actItem_Rect_triggered(self): item=QGraphicsRectItem(-50,-25,100,50) item.setBrush(QBrush(Qt.yellow)) #设置填充颜色 self.__setItemProperties(item,"矩形") @pyqtSlot() ##添加一个椭圆 def on_actItem_Ellipse_triggered(self): item=QGraphicsEllipseItem(-50,-30,100,60) item.setBrush(QBrush(Qt.blue)) #设置填充颜色 self.__setItemProperties(item,"椭圆") @pyqtSlot() ##添加一个圆 def on_actItem_Circle_triggered(self): item=QGraphicsEllipseItem(-50,-50,100,100) item.setBrush(QBrush(Qt.cyan)) #设置填充颜色 self.__setItemProperties(item,"圆形") @pyqtSlot() ##添加三角形 def on_actItem_Triangle_triggered(self): item=QGraphicsPolygonItem() points=[QPointF(0,-40), QPointF(60,40), QPointF(-60,40)] item.setPolygon(QPolygonF(points)) item.setBrush(QBrush(Qt.magenta)) #设置填充颜色 self.__setItemProperties(item,"三角形") @pyqtSlot() ##添加梯形 def on_actItem_Polygon_triggered(self): item=QGraphicsPolygonItem() points=[QPointF(-40,-40), QPointF(40,-40), QPointF(100,40),QPointF(-100,40)] item.setPolygon(QPolygonF(points)) item.setBrush(QBrush(Qt.green)) #设置填充颜色 self.__setItemProperties(item,"梯形") @pyqtSlot() ##添加直线 def on_actItem_Line_triggered(self): item=QGraphicsLineItem(-100,0,100,0) pen=QPen(Qt.red) pen.setWidth(4) item.setPen(pen) #设置线条属性 self.__setItemProperties(item,"直线") @pyqtSlot() ##添加文字 def on_actItem_Text_triggered(self): strText,OK=QInputDialog.getText(self,"输入","请输入文字") if (not OK): return item=QGraphicsTextItem(strText) font=self.font() font.setPointSize(20) font.setBold(True) item.setFont(font) #设置字体 item.setDefaultTextColor(Qt.black) #设置颜色 self.__setItemProperties(item,"文字") ##=============图件的编辑操作=================== @pyqtSlot() ##放大 def on_actZoomIn_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) #选中的图形项的个数 if cnt==1: #只有一个图形项 item=items[0] item.setScale(0.1+item.scale()) else: self.view.scale(1.1,1.1) @pyqtSlot() ##缩小 def on_actZoomOut_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) #选中的图形项的个数 if cnt==1: #只有一个图形项 item=items[0] item.setScale(item.scale()-0.1) else: self.view.scale(0.9,0.9) @pyqtSlot() ##"恢复"取消所有缩放和旋转变换 def on_actRestore_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) if cnt==1: #单个图形项 item=items[0] item.setScale(1) #缩放还原 item.setRotation(0) #旋转还原 ## item.resetTransform() #不起作用,BUG, PyQt 5.12 else: self.view.resetTransform() @pyqtSlot() ##左旋转 def on_actRotateLeft_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) if cnt==1: item=items[0] item.setRotation(-30+item.rotation()) else: self.view.rotate(-30) @pyqtSlot() ##右旋转 def on_actRotateRight_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) if cnt==1: item=items[0] item.setRotation(30+item.rotation()) else: self.view.rotate(30) @pyqtSlot() ##前置 def on_actEdit_Front_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) if cnt>0 : item=items[0] self.__frontZ=1+self.__frontZ item.setZValue(self.__frontZ) @pyqtSlot() ##后置 def on_actEdit_Back_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) if cnt>0 : item=items[0] self.__backZ=self.__backZ-1 item.setZValue(self.__backZ) @pyqtSlot() ##组合 def on_actGroup_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) #选中的图形项个数 if (cnt<=1): return group =QGraphicsItemGroup() #创建组合 self.scene.addItem(group) #组合添加到场景中 for i in range(cnt): item=items[i] item.setSelected(False) #清除选择虚线框 item.clearFocus() group.addToGroup(item) #添加到组合 group.setFlag(QGraphicsItem.ItemIsFocusable) group.setFlag(QGraphicsItem.ItemIsMovable) group.setFlag(QGraphicsItem.ItemIsSelectable) self.__frontZ=1+self.__frontZ group.setZValue(self.__frontZ) self.scene.clearSelection() group.setSelected(True) @pyqtSlot() ##打散组合 def on_actGroupBreak_triggered(self): items=self.scene.selectedItems() cnt=len(items) if (cnt==1): #假设选中的是QGraphicsItemGroup group=items[0] self.scene.destroyItemGroup(group) @pyqtSlot() ##删除所有选中的绘图项 def on_actEdit_Delete_triggered(self): items=self.scene.selectedItems() cnt=len(items) for i in range(cnt): item=items[i] self.scene.removeItem(item) #删除绘图项 ## =============自定义槽函数=============================== def do_mouseMove(self,point): ##鼠标移动 ##鼠标移动事件,point是 GraphicsView的坐标,物理坐标 self.__labViewCord.setText("View 坐标:%d,%d" %(point.x(),point.y())) pt=self.view.mapToScene(point) #转换到Scene坐标 self.__labSceneCord.setText("Scene 坐标:%.0f,%.0f"%(pt.x(),pt.y())) def do_mouseClicked(self,point): ##鼠标单击 pt=self.view.mapToScene(point) #转换到Scene坐标 item=self.scene.itemAt(pt,self.view.transform()) #获取光标下的图形项 if (item == None): return pm=item.mapFromScene(pt) #转换为绘图项的局部坐标 self.__labItemCord.setText("Item 坐标:%.0f,%.0f"%(pm.x(),pm.y())) self.__labItemInfo.setText(str(item.data(self.__ItemDesc)) +", ItemId="+str(item.data(self.__ItemId))) def do_mouseDoubleClick(self,point): ##鼠标双击 pt=self.view.mapToScene(point) #转换到Scene坐标,QPointF item=self.scene.itemAt(pt,self.view.transform()) #获取光标下的绘图项 if (item == None): return className=str(type(item)) #将类名称转换为字符串 ## print(className) if (className.find("QGraphicsRectItem") >=0): #矩形框 self.__setBrushColor(item) elif (className.find("QGraphicsEllipseItem")>=0): #椭圆和圆都是 QGraphicsEllipseItem self.__setBrushColor(item) elif (className.find("QGraphicsPolygonItem")>=0): #梯形和三角形 self.__setBrushColor(item) elif (className.find("QGraphicsLineItem")>=0): #直线,设置线条颜色 pen=item.pen() color=item.pen().color() color=QColorDialog.getColor(color,self,"选择线条颜色") if color.isValid(): pen.setColor(color) item.setPen(pen) elif (className.find("QGraphicsTextItem")>=0): #文字,设置字体 font=item.font() font,OK=QFontDialog.getFont(font) if OK: item.setFont(font) def do_keyPress(self,event): ##按键操作 items=self.scene.selectedItems() cnt=len(items) if (cnt!=1): return item=items[0] key=event.key() if (key==Qt.Key_Delete): #删除 self.scene.removeItem(item) elif (key==Qt.Key_Space): #顺时针旋转90度 item.setRotation(90+item.rotation()) elif (key==Qt.Key_PageUp): #放大 item.setScale(0.1+item.scale()) elif (key==Qt.Key_PageDown): #缩小 item.setScale(-0.1+item.scale()) elif (key==Qt.Key_Left): #左移 item.setX(-1+item.x()) elif (key==Qt.Key_Right): #右移 item.setX(1+item.x()) elif (key==Qt.Key_Up): #上移 item.setY(-1+item.y()) elif (key==Qt.Key_Down): #下移 item.setY(1+item.y())
class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.filename = "" self.copiedItem = QByteArray() self.pasteOffset = 5 self.prevPoint = QPoint() self.addOffset = 5 self.borders = [] self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) self.view = GraphicsView() self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, PageSize[0], PageSize[1]) self.addBorders() self.view.setScene(self.scene) self.wrapped = [] # Needed to keep wrappers alive buttonLayout = QVBoxLayout() for text, slot in ( ("Add &Text", self.addText), ("Add &Box", self.addBox), ("Add Pi&xmap", self.addPixmap), ("&Align", None), ("&Copy", self.copy), ("C&ut", self.cut), ("&Paste", self.paste), ("&Delete...", self.delete), ("&Rotate", self.rotate), ("Pri&nt...", self.print_), ("&Open...", self.open), ("&Save", self.save), ("&Quit", self.accept)): button = QPushButton(text) if not MAC: button.setFocusPolicy(Qt.NoFocus) if slot is not None: button.clicked.connect(slot) if text == "&Align": menu = QMenu(self) for text, arg in ( ("Align &Left", Qt.AlignLeft), ("Align &Right", Qt.AlignRight), ("Align &Top", Qt.AlignTop), ("Align &Bottom", Qt.AlignBottom)): wrapper = functools.partial(self.setAlignment, arg) self.wrapped.append(wrapper) menu.addAction(text, wrapper) button.setMenu(menu) if text == "Pri&nt...": buttonLayout.addStretch(5) if text == "&Quit": buttonLayout.addStretch(1) buttonLayout.addWidget(button) buttonLayout.addStretch() layout = QHBoxLayout() layout.addWidget(self.view, 1) layout.addLayout(buttonLayout) self.setLayout(layout) fm = QFontMetrics(self.font()) self.resize(self.scene.width() + fm.width(" Delete... ") + 50, self.scene.height() + 50) self.setWindowTitle("Page Designer") def addBorders(self): self.borders = [] rect = QRectF(0, 0, PageSize[0], PageSize[1]) self.borders.append(self.scene.addRect(rect, Qt.yellow)) margin = 5.25 * PointSize self.borders.append(self.scene.addRect( rect.adjusted(margin, margin, -margin, -margin), Qt.yellow)) def removeBorders(self): while self.borders: item = self.borders.pop() self.scene.removeItem(item) del item def reject(self): self.accept() def accept(self): self.offerSave() QDialog.accept(self) def offerSave(self): if (Dirty and QMessageBox.question(self, "Page Designer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes): self.save() def position(self): point = self.mapFromGlobal(QCursor.pos()) if not self.view.geometry().contains(point): coord = random.randint(36, 144) point = QPoint(coord, coord) else: if point == self.prevPoint: point += QPoint(self.addOffset, self.addOffset) self.addOffset += 5 else: self.addOffset = 5 self.prevPoint = point return self.view.mapToScene(point) def addText(self): dialog = TextItemDlg(position=self.position(), scene=self.scene, parent=self) dialog.exec_() def addBox(self): BoxItem(self.position(), self.scene) def addPixmap(self): path = (QFileInfo(self.filename).path() if self.filename else ".") fname,filetype = QFileDialog.getOpenFileName(self, "Page Designer - Add Pixmap", path, "Pixmap Files (*.bmp *.jpg *.png *.xpm)") if not fname: return self.createPixmapItem(QPixmap(fname), self.position()) def createPixmapItem(self, pixmap, position, matrix=QTransform()): item = GraphicsPixmapItem(pixmap) item.setFlags(QGraphicsItem.ItemIsSelectable| QGraphicsItem.ItemIsMovable) item.setPos(position) item.setTransform(matrix) self.scene.clearSelection() self.scene.addItem(item) item.setSelected(True) global Dirty Dirty = True return item def selectedItem(self): items = self.scene.selectedItems() if len(items) == 1: return items[0] return None def copy(self): item = self.selectedItem() if item is None: return self.copiedItem.clear() self.pasteOffset = 5 stream = QDataStream(self.copiedItem, QIODevice.WriteOnly) self.writeItemToStream(stream, item) def cut(self): item = self.selectedItem() if item is None: return self.copy() self.scene.removeItem(item) del item def paste(self): if self.copiedItem.isEmpty(): return stream = QDataStream(self.copiedItem, QIODevice.ReadOnly) self.readItemFromStream(stream, self.pasteOffset) self.pasteOffset += 5 def setAlignment(self, alignment): # Items are returned in arbitrary order items = self.scene.selectedItems() if len(items) <= 1: return # Gather coordinate data leftXs, rightXs, topYs, bottomYs = [], [], [], [] for item in items: rect = item.sceneBoundingRect() leftXs.append(rect.x()) rightXs.append(rect.x() + rect.width()) topYs.append(rect.y()) bottomYs.append(rect.y() + rect.height()) # Perform alignment if alignment == Qt.AlignLeft: xAlignment = min(leftXs) for i, item in enumerate(items): item.moveBy(xAlignment - leftXs[i], 0) elif alignment == Qt.AlignRight: xAlignment = max(rightXs) for i, item in enumerate(items): item.moveBy(xAlignment - rightXs[i], 0) elif alignment == Qt.AlignTop: yAlignment = min(topYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - topYs[i]) elif alignment == Qt.AlignBottom: yAlignment = max(bottomYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - bottomYs[i]) global Dirty Dirty = True def rotate(self): for item in self.scene.selectedItems(): item.setRotation(item.rotation()+30) def delete(self): items = self.scene.selectedItems() if (len(items) and QMessageBox.question(self, "Page Designer - Delete", "Delete {0} item{1}?".format(len(items), "s" if len(items) != 1 else ""), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes): while items: item = items.pop() self.scene.removeItem(item) del item global Dirty Dirty = True def print_(self): dialog = QPrintDialog(self.printer) if dialog.exec_(): painter = QPainter(self.printer) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.TextAntialiasing) self.scene.clearSelection() self.removeBorders() self.scene.render(painter) self.addBorders() def open(self): self.offerSave() path = (QFileInfo(self.filename).path() if self.filename else ".") fname,filetype = QFileDialog.getOpenFileName(self, "Page Designer - Open", path, "Page Designer Files (*.pgd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.ReadOnly): raise IOError(str(fh.errorString())) items = self.scene.items() while items: item = items.pop() self.scene.removeItem(item) del item self.addBorders() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) magic = stream.readInt32() if magic != MagicNumber: raise IOError("not a valid .pgd file") fileVersion = stream.readInt16() if fileVersion != FileVersion: raise IOError("unrecognised .pgd file version") while not fh.atEnd(): self.readItemFromStream(stream) except IOError as e: QMessageBox.warning(self, "Page Designer -- Open Error", "Failed to open {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def save(self): if not self.filename: path = "." fname,filetype = QFileDialog.getSaveFileName(self, "Page Designer - Save As", path, "Page Designer Files (*.pgd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.WriteOnly): raise IOError(str(fh.errorString())) self.scene.clearSelection() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) stream.writeInt32(MagicNumber) stream.writeInt16(FileVersion) for item in self.scene.items(): self.writeItemToStream(stream, item) except IOError as e: QMessageBox.warning(self, "Page Designer -- Save Error", "Failed to save {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def readItemFromStream(self, stream, offset=0): type = "" position = QPointF() matrix = QTransform() rotateangle=0#add by yangrongdong type=stream.readQString() stream >> position >> matrix if offset: position += QPointF(offset, offset) if type == "Text": text = "" font = QFont() text=stream.readQString() stream >> font rotateangle=stream.readFloat() tx=TextItem(text, position, self.scene, font, matrix) tx.setRotation(rotateangle) elif type == "Box": rect = QRectF() stream >> rect style = Qt.PenStyle(stream.readInt16()) rotateangle=stream.readFloat() bx=BoxItem(position, self.scene, style, rect, matrix) bx.setRotation(rotateangle) elif type == "Pixmap": pixmap = QPixmap() stream >> pixmap rotateangle=stream.readFloat() px=self.createPixmapItem(pixmap, position, matrix) px.setRotation(rotateangle) def writeItemToStream(self, stream, item): if isinstance(item, TextItem): stream.writeQString("Text") stream<<item.pos()<< item.transform() stream.writeQString(item.toPlainText()) stream<< item.font() stream.writeFloat(item.rotation())#add by yangrongdong elif isinstance(item, GraphicsPixmapItem): stream.writeQString("Pixmap") stream << item.pos() << item.transform() << item.pixmap() stream.writeFloat(item.rotation())#add by yangrongdong elif isinstance(item, BoxItem): stream.writeQString("Box") stream<< item.pos() << item.transform() << item.rect stream.writeInt16(item.style) stream.writeFloat(item.rotation())#add by yangrongdong
class QMyGraphicsview(QGraphicsView): sigMouseMovePoint = pyqtSignal(QPoint) sigNetDeviceItemPress = pyqtSignal(list) paths = [[[0], [1, 4, 3, 2], [1, 4, 3], [1, 4], [0], [1, 6]], [[2, 1], [0], [2, 4, 3], [2, 4], [0], [2, 6]], [], [], [], []] devices = [] line_items = [] def __init__(self, parent=None): super(QMyGraphicsview, self).__init__(parent) self.rect = QRectF(-200, -200, 400, 400) self.myScene = QGraphicsScene(self.rect) self.setScene(self.myScene) self.initPoints() self.initGraphicSystem() def initPoints(self): # 准备6个节点圆形 for i in range(1, 7): item = NetDeviceItem(self, NetNodeInfo(i, "green")) x = 150 * math.sin(math.radians(60 * i)) y = 150 * math.cos(math.radians(60 * i)) item.setPos(x, y) item.setBrush(Qt.green) item.setRect(-15, -15, 30, 30) item.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable) self.devices.append(item) def initGraphicSystem(self): # 清除所有item self.myScene.clear() # 显示scene边框 item1 = WholeDeviceItem(self.rect, self, ["whole", "white"]) item1.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable) self.myScene.addItem(item1) # 显示节点 for item in self.devices: self.myScene.addItem(item) text_item = self.myScene.addSimpleText(str(item.infos.id)) text_item.setPos(item.pos().x() + 20, item.pos().y()) self.myScene.clearSelection() def mouseMoveEvent(self, evt): self.sigMouseMovePoint.emit(evt.pos()) def emitItemPressEvent(self, infos): self.sigNetDeviceItemPress.emit(infos) def removeAllLines(self): for item in self.line_items: self.myScene.removeItem(item) self.line_items.clear() def drawAllLines(self): self.removeAllLines() for path in self.paths: if len(path) == 6: for line in path: if len(line) > 1: for i in range(len(line) - 1): p1 = self.devices[line[i] - 1] p2 = self.devices[line[i + 1] - 1] line_item = self.myScene.addLine( p1.pos().x(), p1.pos().y(), p2.pos().x(), p2.pos().y()) self.line_items.append(line_item) def drawLines(self, id): self.removeAllLines() """画出id节点的连接线""" for line in self.paths[id - 1]: if len(line) > 1: for i in range(len(line) - 1): p1 = self.devices[line[i] - 1] p2 = self.devices[line[i + 1] - 1] line_item = self.myScene.addLine(p1.pos().x(), p1.pos().y(), p2.pos().x(), p2.pos().y()) self.line_items.append(line_item)
class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) #调用父类构造函数,创建窗体 self.__buildUI() #构造界面 self.__iniGraphicsSystem() #初始化 graphics View系统 self.view.mouseMove.connect(self.do_mouseMovePoint) #鼠标移动 self.view.mouseClicked.connect(self.do_mouseClicked) #左键按下 ## ==============自定义功能函数============ def __buildUI(self): ##构造界面 self.resize(600, 450) self.setWindowTitle("Demo8_5, View/Scene/Item关系和坐标变换") font = self.font() font.setPointSize(11) self.setFont(font) centralWidget = QWidget(self) #中间工作区组件 vLayoutMain = QVBoxLayout(centralWidget) #垂直布局 groupBox = QGroupBox(centralWidget) #显示两个Label的groupBox vLayoutGroup = QVBoxLayout(groupBox) self.__labViewSize = QLabel(groupBox) self.__labViewSize.setText("view坐标,左上角(0,0),宽度=,长度=") vLayoutGroup.addWidget(self.__labViewSize) self.__labSceneRect = QLabel(groupBox) self.__labSceneRect.setText("view.sceneRect=()") vLayoutGroup.addWidget(self.__labSceneRect) vLayoutMain.addWidget(groupBox) #主布局添加groupBox self.view = QmyGraphicsView(centralWidget) #绘图视图 self.view.setCursor(Qt.CrossCursor) self.view.setMouseTracking(True) ## self.view.setDragMode(QGraphicsView.RubberBandDrag) vLayoutMain.addWidget(self.view) #添加到主布局 self.setCentralWidget(centralWidget) #设置工作区中间组件 statusBar = QStatusBar(self) #状态栏 self.setStatusBar(statusBar) self.__labViewCord = QLabel("View 坐标:") self.__labViewCord.setMinimumWidth(150) statusBar.addWidget(self.__labViewCord) self.__labSceneCord = QLabel("Scene 坐标:") self.__labSceneCord.setMinimumWidth(150) statusBar.addWidget(self.__labSceneCord) self.__labItemCord = QLabel("Item 坐标:") self.__labItemCord.setMinimumWidth(150) statusBar.addWidget(self.__labItemCord) def __iniGraphicsSystem(self): ##初始化 graphics View系统 rect = QRectF(-200, -100, 400, 200) self.scene = QGraphicsScene(rect) #scene逻辑坐标系定义 self.view.setScene(self.scene) ## 画一个矩形框,大小等于scene item = QGraphicsRectItem(rect) #矩形框正好等于scene的大小 item.setFlag(QGraphicsItem.ItemIsSelectable) #可选, item.setFlag(QGraphicsItem.ItemIsFocusable) #可以有焦点 pen = QPen() pen.setWidth(2) item.setPen(pen) self.scene.addItem(item) ##一个位于scene中心的椭圆,测试局部坐标 #矩形框内创建椭圆,绘图项的局部坐标,左上角(-100,-50),宽200,高100 item2 = QGraphicsEllipseItem(-100, -50, 200, 100) item2.setPos(0, 0) item2.setBrush(QBrush(Qt.blue)) item2.setFlag(QGraphicsItem.ItemIsSelectable) #可选, item2.setFlag(QGraphicsItem.ItemIsFocusable) #可以有焦点 item2.setFlag(QGraphicsItem.ItemIsMovable) #可移动 self.scene.addItem(item2) ##一个圆,中心位于scene的边缘 item3 = QGraphicsEllipseItem(-50, -50, 100, 100) #矩形框内创建椭圆,绘图项的局部坐标 item3.setPos(rect.right(), rect.bottom()) item3.setBrush(QBrush(Qt.red)) item3.setFlag(QGraphicsItem.ItemIsSelectable) #可选, item3.setFlag(QGraphicsItem.ItemIsFocusable) #可以有焦点 item3.setFlag(QGraphicsItem.ItemIsMovable) #可移动 self.scene.addItem(item3) self.scene.clearSelection() ##==============event 处理函数======================= def resizeEvent(self, event): self.__labViewSize.setText('view坐标,左上角(0,0),宽度=%d,高度=%d' % (self.view.width(), self.view.height())) rectF = self.view.sceneRect() #Scene的矩形区,QRectF self.__labSceneRect.setText( 'view.sceneRect=(%.0f,%.0f,%.0f,%.0f)' % (rectF.left(), rectF.top(), rectF.width(), rectF.height())) ## ==========由connectSlotsByName() 自动连接的槽函数================== ## =============自定义槽函数=============================== def do_mouseMovePoint(self, point): ##鼠标移动事件,point是 GraphicsView的坐标,物理坐标 self.__labViewCord.setText("View坐标:%d,%d" % (point.x(), point.y())) pt = self.view.mapToScene(point) #转换到Scene坐标 self.__labSceneCord.setText("Scene坐标:%.0f,%.0f" % (pt.x(), pt.y())) def do_mouseClicked(self, point): pt = self.view.mapToScene(point) #转换到Scene坐标 item = None item = self.scene.itemAt(pt, self.view.transform()) #获取光标下的绘图项 if (item != None): #有绘图项 pm = item.mapFromScene(pt) #转换为绘图项的局部坐标 self.__labItemCord.setText("Item坐标:%.0f,%.0f" % (pm.x(), pm.y()))
class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.filename = "" self.copiedItem = QByteArray() self.pasteOffset = 5 self.prevPoint = QPoint() self.addOffset = 5 self.borders = [] self.printer = QPrinter(QPrinter.HighResolution) # enum QPrinter::PrinterMode # HighRes是一个高分辨率模式,是PrinterMode组成 self.printer.setPageSize(QPrinter.A4) self.view = GraphicsView() self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, PageSize[0], PageSize[1]) self.addBorders() self.view.setScene(self.scene) # 不用写 view.show? self.wrapped = [] # Needed to keep wrappers alive buttonLayout = QVBoxLayout() for text, slot in (("Add &Text", self.addText), ("Add &Box", self.addBox), ("Add Pi&xmap", self.addPixmap), ("&Align", None), ("&Copy", self.copy), ("C&ut", self.cut), ("&Paste", self.paste), ("&Delete...", self.delete), ("&Rotate", self.rotate), ("Pri&nt...", self.print_), ("&Open...", self.open), ("&Save", self.save), ("&Quit", self.accept)): button = QPushButton(text) if not MAC: button.setFocusPolicy(Qt.NoFocus) if slot is not None: button.clicked.connect(slot) if text == "&Align": menu = QMenu(self) for text, arg in (("Align &Left", Qt.AlignLeft), ("Align &Right", Qt.AlignRight), ("Align &Top", Qt.AlignTop), ("Align &Bottom", Qt.AlignBottom)): wrapper = functools.partial(self.setAlignment, arg) # ????? self.wrapped.append(wrapper) menu.addAction(text, wrapper) button.setMenu(menu) if text == "Pri&nt...": buttonLayout.addStretch(5) if text == "&Quit": buttonLayout.addStretch(1) buttonLayout.addWidget(button) buttonLayout.addStretch() layout = QHBoxLayout() layout.addWidget(self.view, 1) # QBoxLayout::addWidget(QWidget *widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment()) layout.addLayout(buttonLayout) self.setLayout(layout) fm = QFontMetrics(self.font()) self.resize(self.scene.width() + fm.width(" Delete... ") + 50, self.scene.height() + 50) self.setWindowTitle("Page Designer 页面设计器") def addBorders(self): '''添加出血框和打印边界框,对scene进行操作同时添加到self.borders这一列表中''' self.borders = [] rect = QRectF(0, 0, PageSize[0], PageSize[1]) self.borders.append(self.scene.addRect( rect, Qt.black)) # addRect px,py,x,y,QPen,QBrush or QRectF,QPen,QBrush # scene.addRect(): Return QGraphicsRectItem;Inherits: QGraphicsItem margin = 5.25 * PointSize self.borders.append( self.scene.addRect(rect.adjusted(margin, margin, -margin, -margin), Qt.red)) def removeBorders(self): '''从列表删除边框,从scene删除边框''' while self.borders: item = self.borders.pop() self.scene.removeItem( item ) #Removes the item item and all its children from the scene. 接受参数为QGraphicsItem del item def reject(self): self.accept() def accept(self): self.offerSave() QDialog.accept( self ) # 完成提示保存之后传递给QDialog的accept命令,之前几章好像讲过为什么要直接调用QDialog这个父类,这里的MWindow是QDialog def offerSave(self): '''根据Dirty判断是否更改,如果更改则弹出保存对话框,调用save()函数进行保存。''' if (Dirty and QMessageBox.question( self, "Page Designer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes): self.save() def position(self): point = self.mapFromGlobal(QCursor.pos( )) # mFG接受一个QPoint参数,包含两个元素的元组 此函数转换QPoint到map,返回依旧是QPoint # Translates the global screen coordinate pos to widget coordinates. if not self.view.geometry().contains( point): #?????????????????????????????????????????????? coord = random.randint(36, 144) point = QPoint(coord, coord) else: if point == self.prevPoint: point += QPoint(self.addOffset, self.addOffset) self.addOffset += 5 else: self.addOffset = 5 self.prevPoint = point return self.view.mapToScene( point) # 将Widght的点左边转换成为Scene坐标,调用对象是QGView def addText(self): dialog = TextItemDlg(position=self.position(), scene=self.scene, parent=self) dialog.exec_() def addBox(self): BoxItem(self.position(), self.scene) def addPixmap(self): path = (QFileInfo(self.filename).path() if self.filename else "." ) # 获取filename定义的正确地址,或者返回此程序根目录 fname, filetype = QFileDialog.getOpenFileName( self, "Page Designer - Add Pixmap", path, "Pixmap Files (*.bmp *.jpg *.png *.xpm)") if not fname: return self.createPixmapItem( QPixmap(fname), self.position()) # 插入时候要将地址传递给QPixmap生成对象,并且还需要位置参数 def createPixmapItem(self, pixmap, position, matrix=QTransform()): # 传递参数为:文件、位置和变换 item = GraphicsPixmapItem(pixmap) # 第一步,将QPixmap转换成为GPItem item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable) # 设置一些属性 item.setPos(position) # 设置位置 item.setTransform(matrix) # 将变换参数应用到GPItem之中 self.scene.clearSelection() # 选择清空 self.scene.addItem(item) # 添加项目 item.setSelected(True) # 并且选中 global Dirty Dirty = True # 全局变量Dirty设置为True return item # 为什么需要返回这个??? def selectedItem( self): # 默认的scene选择的是一个列表,如果只有一个则返回index=0的item,如果多选则不返回任何一个 items = self.scene.selectedItems() if len(items) == 1: return items[0] return None def copy(self): item = self.selectedItem() if item is None: return self.copiedItem.clear() self.pasteOffset = 5 stream = QDataStream(self.copiedItem, QIODevice.WriteOnly) self.writeItemToStream(stream, item) # 写入到流 def cut(self): item = self.selectedItem() if item is None: return self.copy() self.scene.removeItem(item) del item def paste(self): if self.copiedItem.isEmpty(): return stream = QDataStream(self.copiedItem, QIODevice.ReadOnly) self.readItemFromStream( stream, self.pasteOffset) # 从数据流中读入信息,并且输出到self.pasteOffset中 self.pasteOffset += 5 def setAlignment(self, alignment): # Items are returned in arbitrary order items = self.scene.selectedItems() if len(items) <= 1: return # Gather coordinate data leftXs, rightXs, topYs, bottomYs = [], [], [], [] for item in items: rect = item.sceneBoundingRect() # Returns the bounding rect of this item in scene coordinates : Return QRectF leftXs.append(rect.x()) rightXs.append(rect.x() + rect.width()) topYs.append(rect.y()) bottomYs.append(rect.y() + rect.height()) # Perform alignment if alignment == Qt.AlignLeft: xAlignment = min(leftXs) for i, item in enumerate(items): item.moveBy(xAlignment - leftXs[i], 0) # void QGraphicsItem::moveBy(qreal dx, qreal dy) # Moves the item by dx points horizontally, and dy point vertically. elif alignment == Qt.AlignRight: xAlignment = max(rightXs) for i, item in enumerate(items): item.moveBy(xAlignment - rightXs[i], 0) elif alignment == Qt.AlignTop: yAlignment = min(topYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - topYs[i]) elif alignment == Qt.AlignBottom: yAlignment = max(bottomYs) for i, item in enumerate(items): item.moveBy(0, yAlignment - bottomYs[i]) global Dirty Dirty = True def rotate(self): for item in self.scene.selectedItems(): item.setRotation(item.rotation() + 30) def delete(self): # 从基本scene属性中选取选择的多个,弹出对话框,如果允许,则迭代进行删除,并且设置Dirty为True items = self.scene.selectedItems() if (len(items) and QMessageBox.question( self, "Page Designer - Delete", "Delete {0} item{1}?".format( len(items), "s" if len(items) != 1 else ""), QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes): while items: item = items.pop() self.scene.removeItem(item) del item global Dirty Dirty = True def print_(self): # dialog = QPrintDialog(self.printer) # 在此已经设置好了self.printer 也就是QPrinter对象,QPDlg直接传递回了Printer对象,之后重新由 # # printer对象声称心的QPrinter就可以继续使用在这句话中设置好的参数了。 # if dialog.exec_(): painter = QPainter(self.printer) painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QPainter.TextAntialiasing) self.scene.clearSelection() self.removeBorders() self.scene.render(painter) # [void] Renders the source rect from scene into target, using painter. This function is useful for capturing the contents # of the scene onto a paint device, such as a QImage (e.g., to take a screenshot), or for printing with QPrinter. For example: self.addBorders() def open(self): self.offerSave() path = (QFileInfo(self.filename).path() if self.filename else ".") fname, filetype = QFileDialog.getOpenFileName( self, "Page Designer - Open", path, "cmPage Designer Files (*.cmpd *.pgd *.cmd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.ReadOnly): raise IOError(str(fh.errorString())) items = self.scene.items() # 返回所有的QGitem List形式 while items: item = items.pop() # 从列表中删除一个,从scene中删除一个,迭代到全部删除 self.scene.removeItem(item) del item self.addBorders() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) magic = stream.readInt32() if magic != MagicNumber: raise IOError("not a valid .cmpd file") fileVersion = stream.readInt16() if fileVersion != FileVersion: raise IOError("unrecognised .cmpd file version") while not fh.atEnd(): self.readItemFromStream(stream) except IOError as e: QMessageBox.warning( self, "Page Designer -- Open Error", "Failed to open {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def save(self): if not self.filename: path = "." fname, filetype = QFileDialog.getSaveFileName( self, "Page Designer - Save As", path, "cmPage Designer Files (*.cmpd *.pgd *.cmd)") if not fname: return self.filename = fname fh = None try: fh = QFile(self.filename) if not fh.open(QIODevice.WriteOnly): raise IOError(str(fh.errorString())) self.scene.clearSelection() stream = QDataStream(fh) stream.setVersion(QDataStream.Qt_5_7) stream.writeInt32(MagicNumber) stream.writeInt16(FileVersion) for item in self.scene.items(): self.writeItemToStream(stream, item) except IOError as e: QMessageBox.warning( self, "Page Designer -- Save Error", "Failed to save {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def readItemFromStream(self, stream, offset=0): type = "" position = QPointF() matrix = QTransform() rotateangle = 0 #add by yangrongdong type = stream.readQString() stream >> position >> matrix if offset: position += QPointF(offset, offset) if type == "Text": text = "" font = QFont() text = stream.readQString() stream >> font rotateangle = stream.readFloat() tx = TextItem(text, position, self.scene, font, matrix) tx.setRotation(rotateangle) elif type == "Box": rect = QRectF() stream >> rect style = Qt.PenStyle(stream.readInt16()) rotateangle = stream.readFloat() bx = BoxItem(position, self.scene, style, rect, matrix) bx.setRotation(rotateangle) elif type == "Pixmap": pixmap = QPixmap() stream >> pixmap rotateangle = stream.readFloat() px = self.createPixmapItem(pixmap, position, matrix) px.setRotation(rotateangle) def writeItemToStream(self, stream, item): if isinstance(item, TextItem): stream.writeQString("Text") stream << item.pos() << item.transform() stream.writeQString(item.toPlainText()) stream << item.font() stream.writeFloat(item.rotation()) #add by yangrongdong elif isinstance(item, GraphicsPixmapItem): stream.writeQString("Pixmap") stream << item.pos() << item.transform() << item.pixmap() stream.writeFloat(item.rotation()) #add by yangrongdong elif isinstance(item, BoxItem): stream.writeQString("Box") stream << item.pos() << item.transform() << item.rect stream.writeInt16(item.style) stream.writeFloat(item.rotation()) #add by yangrongdong
class Ui_MainWindow(): def __init__(self): self.a =-1 self.nom="" self.op="" self.Nomserie="" self.step=0 self.time=False self.type_graph="" def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget) self.graphicsView.setGeometry(QtCore.QRect(10,10,556,392)) self.graphicsView.setObjectName("graphicsView") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0,0,673,125)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menufile") MainWindow.setMenuBar(self.menubar) self.actionOpen = QtWidgets.QAction(MainWindow) self.actionOpen.setObjectName("actionOpen") self.actionOpen.triggered.connect(self.showDialog) self.actionExit = QtWidgets.QAction(MainWindow) self.actionExit.setObjectName("actionExit") self.actionExit.triggered.connect(QApplication.quit) self.actionAbout = QtWidgets.QAction(MainWindow) self.actionAbout.setObjectName("actionAbout") self.actionAbout.triggered.connect(self.showAbout) self.menuFile.addAction(self.actionOpen) self.menuFile.addAction(self.actionAbout) #<------ self.menuFile.addAction(self.actionExit) self.menubar.addAction(self.menuFile.menuAction()) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) # Create textbox self.textbox = QLineEdit(MainWindow) self.textbox.move(580,280) self.textbox.resize(280,40) # Create a button in the window self.button = QPushButton('Ok', MainWindow) self.button.move(580,320) #Create a button 2 in the window self.button2 = QPushButton('Drawing graphs',MainWindow) self.button2.move(580,165) # connect button to function on_click self.button.clicked.connect(self.on_click) self.button2.clicked.connect(self.on_click2) #Getchoice self.cb = QComboBox(MainWindow) self.cb.move(580,250) self.cb.addItem("") self.cb.addItem("Degree") self.cb.addItem("Closeness") self.cb.addItems(["Pagerank", "Betweeness"]) self.cb.currentIndexChanged.connect(self.selectionchange) #object presents the user with a integer self.l1 = QLabel("current value:") self.l1.move(650,250) self.sp = QSpinBox(MainWindow) self.sp.setMaximum(1049) self.sp.move(700,250) self.sp.valueChanged.connect(self.valuechange) #Getchoice 2 self.cb2 = QComboBox(MainWindow) self.cb2.move(580,50) self.cb2.addItem("") self.cb2.addItem("Game of Thrones") self.cb2.addItem("Breaking Bad") self.cb2.addItem("House of Card") self.cb2.currentIndexChanged.connect(self.selectionchange2) #Radiobutton for graph self.b0 = QRadioButton("Classical",MainWindow) self.b0.move(580,140) self.b0.setChecked(True) self.b0.toggled.connect(lambda:self.btnstate(self.b0)) self.b1 = QRadioButton("Random",MainWindow) self.b1.move(580,80) self.b1.setChecked(True) self.b1.toggled.connect(lambda:self.btnstate(self.b1)) self.b2 = QRadioButton("Circular",MainWindow) self.b2.move(580,95) self.b2.setChecked(True) self.b2.toggled.connect(lambda:self.btnstate(self.b2)) self.b3 = QRadioButton("Spectral",MainWindow) self.b3.move(580,110) self.b3.setChecked(True) self.b3.toggled.connect(lambda:self.btnstate(self.b3)) self.b4 = QRadioButton("Shell",MainWindow) self.b4.move(580,125) self.b4.setChecked(True) self.b4.toggled.connect(lambda:self.btnstate(self.b4)) if self.time == False : #ProgressBar self.bar = QProgressBar(MainWindow) self.bar.setGeometry(50, 80, 500, 39) self.bar.move(140,650) self.bar.setMaximum(50) self.bar.setMinimum(0) def showDialog(self): #permetde charger l'image avec la bar du menu fileName = QFileDialog.getOpenFileName(MainWindow, 'Open file')[0] print(fileName) self.scene = QGraphicsScene() self.scene.addPixmap(QPixmap(fileName)) self.graphicsView.setScene(self.scene) def showAbout(self):#permet d'afficher le about du menu QMessageBox.question(MainWindow,'About',"Authors of the program: Yannis Hutt and Julien Cadier", QMessageBox.Ok, QMessageBox.Ok) def retranslateUi(self, MainWindow):#permet de faire le menu déroulant _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Mainwindow")) self.menuFile.setTitle(_translate("MainWindow","F&ile")) self.actionOpen.setText(_translate("MainWindow","Open")) self.actionAbout.setText(_translate("MainWindow","About")) self.actionExit.setText(_translate("MainWindow","Exit")) def on_click(self): #permet de faire l'évenement pour faire le graph self.bar.setMaximum(0) textboxValue = self.textbox.text() QMessageBox.question(MainWindow, 'result', "You typed: " + textboxValue, QMessageBox.Ok, QMessageBox.Ok) self.nom = self.textbox.text() print(self.nom) print(self.op) lireGraph2.start_main(self.Nomserie,self.a,self.nom,self.op) self.scene = QGraphicsScene() self.scene.clearSelection() self.scene.addPixmap(QPixmap("images/" + self.nom +self.op+ ".jpg")) self.graphicsView.setScene(self.scene) self.bar.setMaximum(50) def on_click2(self): self.bar.setMaximum(0) test_lireGraph.start_graph(self.Nomserie,self.type_graph) self.scene = QGraphicsScene() self.scene.clearSelection() self.scene.addPixmap(QPixmap("images/" + self.Nomserie+"_"+self.type_graph+ ".jpg")) self.graphicsView.setScene(self.scene) self.bar.setMaximum(50) def selectionchange(self,i): # permet de faire la selection des opérations print ("Items in the list are :") for count in range(self.cb.count()): print (self.cb.itemText(count)) print ("Current index",i,"selection changed ",self.cb.currentText()) self.op = self.cb.currentText() def f(x): return { "" : 'essai', "Degree" : 'd', "Closeness" : 'c', "Pagerank" : 'p', "Betweeness" : 'b' }[x] self.op=f(self.op) print(self.op) def selectionchange2(self,i): print("Items in the second list are :") for count in range(self.cb2.count()): print (self.cb2.itemText(count)) print ("current index", i,"selection changed ", self.cb.currentText()) self.Nomserie = self.cb2.currentText() print(self.Nomserie) def valuechange(self): self.l1.setText("current value:"+str(self.sp.value())) print(self.sp.value()) self.a = self.sp.value() #affectation valeur int def text_changed(self): """ updates the list of possible completions each time a key is pressed """ pattern = str(self.le.text()) self.new_list = [item for item in lireGraph2.dicoNomToNum if item.find(pattern) == 0] self.lm.setAllData(self.new_list) def btnstate(self,b): #permet de savoir quelle graph faire if b.text() == "Random": if b.isChecked() == True: print(b.text()+" is selected") self.type_graph = "Random" else: print(b.text()+" is deselcted") if b.text() == "Circular": if b.isChecked() == True: print(b.text()+" is selected") self.type_graph = "Circular" else: print(b.text()+" is deselcted") if b.text() == "Spectral": if b.isChecked() == True: print(b.text()+" is selected") self.type_graph = "Spectral" else: print(b.text()+" is deselcted") if b.text() == "Shell": if b.isChecked() == True: print(b.text()+" is selected") self.type_graph = "Shell" else: print(b.text()+" is deselcted") if b.text() == "Classical": if b.isChecked() == True: print(b.text()+" is selected") self.type_graph = "Classical" else: print(b.text()+" is deselcted")
class WorldFrame(QGraphicsView): msg2Statusbar = pyqtSignal(str) def __init__(self, parent, world): super().__init__(parent) self._zoom = 0 self._scene = QGraphicsScene(self) self._world = world self._worldview = WorldView(self, world) self._scene.addItem(self._worldview) self.setScene(self._scene) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self.setBackgroundBrush(QBrush(QColor(30, 30, 30))) self.setFrameShape(QFrame.NoFrame) self.pointerMode = PointerMode.Normal self.setCacheMode(QGraphicsView.CacheBackground) self.setDragMode(QGraphicsView.NoDrag) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setMouseTracking(True) self.logger = parent.logger def fitInView(self, scale=True): rect = QRectF(self._worldview.boundingRect()) if not rect.isNull(): self.setSceneRect(rect) 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 resetViewport(self): self.fitInView() self.update() def mouseMoveEvent(self, event): point = self.mapToScene(event.x(), event.y()) ex, ey = point.x(), point.y() try: self.currentGridPoint = self._worldview.pixToGrid(ex, ey) except IndexError: self.currentGridPoint = Space(0, 0, Terrain()) gridx, gridy = self.currentGridPoint landmark = " " players = " " if 0 < gridx < self._world.Width and 0 < gridy < self._world.Height: space = self._world.Map[gridy][gridx] if space in self._world.Towns or space in self._world.Wilds: landmark += space.Name for p in self._world.Players: if p.Location == space: players += p.Name + " " self.msg2Statusbar.emit("({}, {}) {} [{}]".format(int(gridx), int(gridy), landmark, players)) super().mouseMoveEvent(event) self.update() def wheelEvent(self, event): 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 update(self): super().update() self._worldview.update() def changePointerMode(self, mode): self.pointerMode = mode def mousePressEvent(self, event): if event.buttons() & Qt.MiddleButton: self.middleClickEvent(event) elif event.buttons() & Qt.LeftButton: self.leftClickEvent(event) elif event.buttons() & Qt.RightButton: self.rightClickEvent(event) super().mousePressEvent(event) def middleClickEvent(self, event): if self.dragMode() == QGraphicsView.ScrollHandDrag: self.setDragMode(QGraphicsView.NoDrag) self.pointerMode = PointerMode.Normal else: self.setDragMode(QGraphicsView.ScrollHandDrag) self.pointerMode = PointerMode.Drag def leftClickEvent(self, event): if self.pointerMode == PointerMode.AddTown: dialog = AddTownDialog(self, self.currentGridPoint) if dialog.exec_(): town = dialog.returnData self._world.addTown(town) if dialog.isStartingTown: self._world.StartingTown = town self.pointerMode = PointerMode.Normal if self.pointerMode == PointerMode.AddWilds: dialog = AddWildsDialog(self, self.currentGridPoint) if dialog.exec_(): self._world.addWilds(dialog.returnData) self.pointerMode = PointerMode.Normal def rightClickEvent(self, event): if self.pointerMode != PointerMode.Normal: self.pointerMode = PointerMode.Normal self.update() def mouseReleaseEvent(self, event): if self.dragMode() == QGraphicsView.ScrollHandDrag: self.setDragMode(QGraphicsView.NoDrag) self.pointerMode = PointerMode.Normal super().mouseReleaseEvent(event) def getBoundingSubrectangle(self, spaces: [Space]) -> QRectF: def getTopLeftSpace(spaces): minX = min([s.X for s in spaces]) minY = min([s.Y for s in spaces]) topLeft = [s for s in spaces if s.X == minX and s.Y == minY][0] return topLeft def getBottomRightSpace(spaces): maxX = max([s.X for s in spaces]) maxY = max([s.Y for s in spaces]) botRight = [s for s in spaces if s.X == maxX and s.Y == maxY][0] return botRight topLeftSpace = getTopLeftSpace(spaces) topLeftPix = self.mapFromParent(self._worldview.gridToPix(topLeftSpace.X, topLeftSpace.Y)) bottomRightSpace = getBottomRightSpace(spaces) bottomRightPix = self.mapFromParent(self._worldview.gridToPix(bottomRightSpace.X, bottomRightSpace.Y)) + \ QPoint(self._worldview.squareWidth, self._worldview.squareHeight) subBoundingRect = QRectF(topLeftPix, bottomRightPix) return subBoundingRect def saveSubimage(self, spaces: [Space], filename="capture.png"): self._scene.clearSelection() boundingRect = self.getBoundingSubrectangle(spaces) self._scene.setSceneRect(boundingRect) pix = QImage(self._scene.sceneRect().size().toSize(), QImage.Format_ARGB32) pix.fill(Qt.TransparentMode) painter = QPainter(pix) painter.setRenderHint(QPainter.Antialiasing) self._scene.render(painter) painter.end() # Removing will cause silent crash pix.save(filename)
class GraphDigitGraphicsView(QGraphicsView): sigMouseMovePoint = pyqtSignal(QPoint, QPointF) sigModified = pyqtSignal(bool) sigNewCurveAdded = pyqtSignal() # 自定义信号sigMouseMovePoint,当鼠标移动时,在mouseMoveEvent事件中,将当前的鼠标位置发送出去 # QPoint--传递的是view坐标 def __init__(self, parent=None): super(GraphDigitGraphicsView, self).__init__(parent) # scene rect = QRectF(0, 0, 300, 400) self.scene = QGraphicsScene(rect) # 创建场景 参数:场景区域 self.setScene(self.scene) # 给视图窗口设置场景 # image self.graphicsPixmapItem = QGraphicsPixmapItem() # chart image self.scene.addItem(self.graphicsPixmapItem) # setAntialias self.setRenderHint(QPainter.Antialiasing) # image object stored in project data # item objects storage self.axesxObjs = {} self.axesyObjs = {} self.gridObjs = [] self.curveObjs = {} self.pointObjs = {} # axis coord stored in project data # grid setting stored in project data # grid position self.gridxpos = [] self.gridypos = [] # axes curve and point datamodel self.axesxModel = QStandardItemModel() self.axesyModel = QStandardItemModel() self.axesxSelectModel = QItemSelectionModel(self.axesxModel) self.axesySelectModel = QItemSelectionModel(self.axesyModel) self.curveModel = QStandardItemModel() self.pointsModel = QStandardItemModel() self.curveModel.setHorizontalHeaderLabels( ["current", "name", "visible"]) self.pointsModel.setHorizontalHeaderLabels(["order", "x", "y"]) self.axesxModel.setHorizontalHeaderLabels(["position", "x"]) self.axesyModel.setHorizontalHeaderLabels(["position", "y"]) ### self.xNo = 0 self.yNo = 0 ### self.mode = OpMode.default # data manage self.proj = Digi() # init self.currentCurve = None self.pointsModel.itemChanged.connect(self.changePointOrder) self.curveModel.itemChanged.connect(self.changeCurveVisible) self.scene.selectionChanged.connect(self.slotSceneSeletChanged) # state self._lastCurve = None def load(self, proj): # image # only for load self.scaleGraphImage(proj.imgScale) # axes xadded = [] yadded = [] for xpos, xcoord in proj.data["axesxObjs"].items(): if xpos in xadded: continue else: xadded.append(xpos) item = QGraphicsAxesItem( 0, self.scene.sceneRect().y(), 0, self.scene.sceneRect().y() + self.scene.sceneRect().height()) item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) item.setPos(xpos, 0) item.axis = "x" item.setPen(QPen(Qt.red, 1, Qt.DashLine)) self.scene.addItem(item) self.axesxObjs[item] = xcoord labelitem = QStandardItem("x:{}".format(xpos)) labelitem.setData(item) self.axesxModel.appendRow([labelitem, QStandardItem(str(xcoord))]) self.xNo += 1 self.axesxModel.setVerticalHeaderItem( self.axesxModel.rowCount() - 1, QStandardItem("x{}".format(self.xNo))) for ypos, ycoord in proj.data["axesyObjs"].items(): if ypos in yadded: continue else: yadded.append(ypos) item = QGraphicsAxesItem( self.scene.sceneRect().x(), 0, self.scene.sceneRect().x() + self.scene.sceneRect().width(), 0) item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) item.setPos(0, ypos) item.axis = "y" item.setPen(QPen(Qt.red, 1, Qt.DashLine)) self.scene.addItem(item) self.axesyObjs[item] = ycoord labelitem = QStandardItem("y:{}".format(ypos)) labelitem.setData(item) self.axesyModel.appendRow([labelitem, QStandardItem(str(ycoord))]) # curve for curve in proj.data["curves"]: self.pointObjs[curve] = [] self.addCurve(curve) clr = RandItem.nextColor() for x, y in proj.data["curves"][curve]: ptitem = QGraphicsPointItem() ptitem.pointColor = clr ptitem.linewidth = 1 ptitem.setPos(x, y) ptitem.parentCurve = curve ptitem.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) i = pointInsertPosition(ptitem, self.pointObjs[self.currentCurve]) self.pointObjs[self.currentCurve].insert(i, ptitem) self.scene.addItem(ptitem) self.updateCurve(curve) # grid self.calGridCoord() self.updateGrid() self.sigModified.emit(True) self.mode = OpMode.select def resetview(self): self.setGraphImage(None) self.scaleGraphImage(1) for obj in self.axesxObjs: self.scene.removeItem(obj) self.axesxObjs = {} for obj in self.axesyObjs: self.scene.removeItem(obj) self.axesyObjs = {} for obj in self.gridObjs: self.scene.removeItem(obj) self.gridObjs = [] for curve in self.curveObjs: for obj in self.curveObjs[curve]: self.scene.removeItem(obj) self.curveObjs = {} for curve in self.pointObjs: for obj in self.pointObjs[curve]: self.scene.removeItem(obj) self.pointObjs = {} self.axesxModel.clear() self.axesyModel.clear() self.curveModel.clear() self.pointsModel.clear() self.axesxSelectModel.clear() self.axesySelectModel.clear() self.curveModel.setHorizontalHeaderLabels( ["current", "name", "visible"]) self.pointsModel.setHorizontalHeaderLabels(["order", "x", "y"]) self.axesxModel.setHorizontalHeaderLabels(["position", "x"]) self.axesyModel.setHorizontalHeaderLabels(["position", "y"]) self.xNo = 0 self.yNo = 0 ### self.mode = OpMode.default # data manage self.proj.resetData(True) # init self.currentCurve = None self._lastCurve = None def dump(self): proj = self.proj proj.data["axesxObjs"] = {} # [x1,x2,x3] proj.data["axesyObjs"] = {} # [y1,y2,y3] proj.data["curves"] = {} # {'default':(x1,y1),(x2,y2)} # axes for item, xcoord in self.axesxObjs.items(): proj.data["axesxObjs"][item.pos().x()] = xcoord for item, ycoord in self.axesyObjs.items(): proj.data["axesyObjs"][item.pos().y()] = ycoord # curve for curve in self.pointObjs: proj.data["curves"][curve] = [] for item in self.pointObjs[curve]: proj.data["curves"][curve].append((item.x(), item.y())) def mouseMoveEvent(self, evt): pt = evt.pos() # 获取鼠标坐标--view坐标 self.sigMouseMovePoint.emit(pt, self.mapToScene(pt)) # 发送鼠标位置 QGraphicsView.mouseMoveEvent(self, evt) item = self.scene.focusItem() if not item: items = self.scene.selectedItems() if len(items) != 1: return else: item = items[0] if item: if isinstance(item, QGraphicsPointItem) and item.parentCurve: # self.changeCurrentCurve(item.parentCurve) self.updateCurve(self.currentCurve, Qt.red) self.updateCurvePoints(self.currentCurve) self.sigModified.emit(True) elif isinstance(item, QGraphicsAxesItem): if item.axis == "x": if self.mode != OpMode.axesx: self.scene.clearSelection() return self.axesxSelectModel.clearSelection() self.axesySelectModel.clearSelection() for i in range(self.axesxModel.rowCount()): if self.axesxModel.item(i, 0).data() is item: parent = QModelIndex() topleftindex = self.axesxModel.index( i, 0, parent) # self.axesxModel.item(i,0).index() rightbottomindex = self.axesxModel.index( i, 1, parent) self.axesxSelectModel.select( QItemSelection(topleftindex, rightbottomindex), QItemSelectionModel.Select) self.axesxModel.item(i, 0).setText("x:{}".format( evt.pos().x())) break item.setLine( 0, self.scene.sceneRect().y(), 0, self.scene.sceneRect().y() + self.scene.sceneRect().height()) item.setPos(self.mapToScene(evt.pos()).x(), 0) self.sigModified.emit(True) self.calGridCoord() self.updateGrid() elif item.axis == "y": if self.mode != OpMode.axesy: self.scene.clearSelection() return self.axesxSelectModel.clearSelection() self.axesySelectModel.clearSelection() for i in range(self.axesyModel.rowCount()): if self.axesyModel.item(i, 0).data() is item: topleftindex = self.axesyModel.index( i, 0) # self.axesxModel.item(i,0).index() rightbottomindex = self.axesyModel.index(i, 1) self.axesySelectModel.select( QItemSelection(topleftindex, rightbottomindex), QItemSelectionModel.Select) self.axesyModel.item(i, 0).setText("y:{}".format( evt.pos().y())) break item.setLine( self.scene.sceneRect().x(), 0, self.scene.sceneRect().x() + self.scene.sceneRect().width(), 0) item.setPos(0, self.mapToScene(evt.pos()).y()) self.sigModified.emit(True) self.calGridCoord() self.updateGrid() # self.updateCurve(self.currentCurve) # self.repaint() # self.setDragMode(QGraphicsView.NoDrag) #(RubberBandDrag) #ScrollHandDrag) #NoDrag) def mousePressEvent(self, event): super().mousePressEvent(event) self.__pressPt = event.pos() ptscene = self.mapToScene(event.pos()) if self.mode is OpMode.axesx: for axisitem in self.axesxObjs: if abs(ptscene.x() - axisitem.pos().x()) < 5: self.scene.clearSelection() axisitem.setSelected(True) return elif self.mode is OpMode.axesy: for axisitem in self.axesyObjs: if abs(ptscene.y() - axisitem.pos().y()) < 5: self.scene.clearSelection() axisitem.setSelected(True) return def keyPressEvent(self, event: QKeyEvent) -> None: # super().keyPressEvent(event) item = self.scene.focusItem() if not item: items = self.scene.selectedItems() if len(items) != 1: return else: item = items[0] if item: if isinstance(item, QGraphicsPointItem) and item.parentCurve: if event.key() == Qt.Key_Up: item.setPos(item.pos().x(), item.pos().y() - 1) elif event.key() == Qt.Key_Down: item.setPos(item.pos().x(), item.pos().y() + 1) elif event.key() == Qt.Key_Left: item.setPos(item.pos().x() - 1, item.pos().y()) elif event.key() == Qt.Key_Right: item.setPos(item.pos().x() + 1, item.pos().y()) else: return self.updateCurve(self.currentCurve, Qt.red) self.updateCurvePoints(self.currentCurve) self.sigModified.emit(True) elif isinstance(item, QGraphicsAxesItem): if item.axis == "x": if event.key() == Qt.Key_Left: item.moveBy(-1, 0) elif event.key() == Qt.Key_Right: item.moveBy(1, 0) else: return self.sigModified.emit(True) self.calGridCoord() self.updateGrid() self.axesxSelectModel.clearSelection() self.axesySelectModel.clearSelection() for i in range(self.axesxModel.rowCount()): if self.axesxModel.item(i, 0).data() is item: parent = QModelIndex() topleftindex = self.axesxModel.index( i, 0, parent) # self.axesxModel.item(i,0).index() rightbottomindex = self.axesxModel.index( i, 1, parent) self.axesxSelectModel.select( QItemSelection(topleftindex, rightbottomindex), QItemSelectionModel.Select) self.axesxModel.item(i, 0).setText("x:{}".format( item.pos().x())) break elif item.axis == "y": if event.key() == Qt.Key_Up: item.setPos(0, item.pos().y() - 1) elif event.key() == Qt.Key_Down: item.setPos(0, item.pos().y() + 1) else: return self.sigModified.emit(True) self.calGridCoord() self.updateGrid() self.axesxSelectModel.clearSelection() self.axesySelectModel.clearSelection() for i in range(self.axesyModel.rowCount()): if self.axesyModel.item(i, 0).data() is item: topleftindex = self.axesyModel.index( i, 0) # self.axesxModel.item(i,0).index() rightbottomindex = self.axesyModel.index(i, 1) self.axesySelectModel.select( QItemSelection(topleftindex, rightbottomindex), QItemSelectionModel.Select) self.axesyModel.item(i, 0).setText("y:{}".format( item.pos().y())) break def mouseReleaseEvent(self, event): super().mouseReleaseEvent(event) ptscene = self.mapToScene(event.pos()) # item = self.scene.itemAt(ptscene, self.transform()) clicked = True if event.pos() == self.__pressPt else False if self.mode is OpMode.select: pass # super().mousePressEvent(event) elif self.mode is OpMode.axesx and clicked: self.axesxSelectModel.clear() self.axesySelectModel.clear() for axisitem in self.axesxObjs: if abs(ptscene.x() - axisitem.pos().x()) < 5: self.scene.clearSelection() axisitem.setSelected(True) return item = QGraphicsAxesItem( 0, self.scene.sceneRect().y(), 0, self.scene.sceneRect().y() + self.scene.sceneRect().height()) item.setPos(ptscene.x(), 0) item.axis = "x" item.setPen(QPen(Qt.red, 1, Qt.DashLine)) self.scene.addItem(item) item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) xs = list(self.axesxObjs.values()) if not self.axesxObjs: nextx = 0 elif len(self.axesxObjs) == 1: nextx = xs[0] + 0.1 else: nextx = 2 * xs[-1] - xs[-2] x, okPressed = QInputDialog.getDouble( self, self.tr("set x coordiniate"), self.tr("set the x coord for axis"), nextx, decimals=3) if okPressed and x not in self.axesxObjs.values(): self.axesxObjs[item] = x labelItem = QStandardItem("x:{}".format(item.pos().x())) labelItem.setData(item) self.axesxModel.appendRow([labelItem, QStandardItem(str(x))]) self.calGridCoord("x") self.updateGrid() # item.setSelected(True) for i in range(self.axesxModel.rowCount()): if self.axesxModel.item(i, 0).data() is item: topleftindex = self.axesxModel.index( i, 0) # self.axesxModel.item(i,0).index() rightbottomindex = self.axesxModel.index(i, 1) self.axesxSelectModel.select( QItemSelection(topleftindex, rightbottomindex), QItemSelectionModel.Select) break self.sigModified.emit(True) self.scene.clearSelection() else: self.scene.removeItem(item) elif self.mode is OpMode.axesy and clicked: self.axesxSelectModel.clear() self.axesySelectModel.clear() for axisitem in self.axesyObjs: if abs(ptscene.y() - axisitem.pos().y()) < 5: self.scene.clearSelection() axisitem.setSelected(True) return item = QGraphicsAxesItem( self.scene.sceneRect().x(), 0, self.scene.sceneRect().x() + self.scene.sceneRect().width(), 0) item.setPos(0, ptscene.y()) item.axis = "y" item.setPen(QPen(Qt.red, 1, Qt.DashLine)) self.scene.addItem(item) item.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) ys = list(self.axesyObjs.values()) if not self.axesyObjs: nexty = 0 elif len(self.axesyObjs) == 1: nexty = ys[0] + 0.1 else: nexty = 2 * ys[-1] - ys[-2] y, okPressed = QInputDialog.getDouble( self, self.tr("set y coordiniate"), self.tr("set the y coord for axis"), nexty, decimals=3) if okPressed and y not in self.axesyObjs.values(): self.axesyObjs[item] = y labelItem = QStandardItem("y:{}".format(item.pos().y())) labelItem.setData(item) self.axesyModel.appendRow([labelItem, QStandardItem(str(y))]) self.calGridCoord("y") self.updateGrid() # item.setSelected(True) for i in range(self.axesyModel.rowCount()): if self.axesyModel.item(i, 0).data() is item: topleftindex = self.axesyModel.index( i, 0) # self.axesxModel.item(i,0).index() rightbottomindex = self.axesyModel.index(i, 1) self.axesySelectModel.select( QItemSelection(topleftindex, rightbottomindex), QItemSelectionModel.Select) break self.sigModified.emit(True) else: self.scene.removeItem(item) elif self.mode is OpMode.curve and clicked: self.sigMouseMovePoint.emit(event.pos(), ptscene) if len(self.curveObjs) == 0: self.addCurve('curve1') if self.currentCurve not in self.pointObjs: self.pointObjs[self.currentCurve] = [] ptitem = QGraphicsPointItem() ptitem.pointColor = Qt.blue ptitem.linewidth = 1 ptitem.setPos(ptscene) ptitem.parentCurve = self.currentCurve ptitem.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable) self.scene.addItem(ptitem) i = pointInsertPosition(ptitem, self.pointObjs[self.currentCurve]) self.pointObjs[self.currentCurve].insert(i, ptitem) self.updateCurve(self.currentCurve, Qt.red) self.sigModified.emit(True) ptitem.setSelected(True) # item1=QGraphicsRectItem(rect) #创建矩形---以场景为坐标 # item1.setFlags(QGraphicsItem.ItemIsSelectable|QGraphicsItem.ItemIsFocusable|QGraphicsItem.ItemIsMovable) #给图元设置标志 # QGraphicsItem.ItemIsSelectable---可选择 # QGraphicsItem.ItemIsFocusable---可设置焦点 # QGraphicsItem.ItemIsMovable---可移动 # QGraphicsItem.ItemIsPanel--- # self.scene.addItem(item1) #给场景添加图元 def slotSceneSeletChanged(self): items = self.scene.selectedItems() if len(items) != 1: # ony allow select one item self.scene.clearSelection() return # item = items[0] item = self.scene.focusItem() if not item: items = self.scene.selectedItems() if len(items) != 1: return else: item = items[0] if item: if isinstance(item, QGraphicsPointItem) and item.parentCurve: self.changeCurrentCurve(item.parentCurve) def deleteItem(self, item): """delete point on curve or axis object""" curvechange = None if isinstance(item, QGraphicsPointItem): for curvename, pointitems in self.pointObjs.items(): for ptitem in pointitems: if ptitem is item: curvechange = curvename pointitems.remove(ptitem) self.scene.removeItem(item) self.sigModified.emit(True) break if curvechange: self.updateCurve(curvechange) if isinstance(item, QGraphicsAxesItem): if item.axis == "x": for line in self.axesxObjs: if line is item: for i in range(self.axesxModel.rowCount()): if self.axesxModel.item(i, 0).data( ) is item: # float(self.axesxModel.item(i, 0).text().strip("x:")) == line.pos().x(): self.axesxModel.removeRow(i) break self.axesxObjs.pop(line) self.scene.removeItem(line) self.sigModified.emit(True) break elif item.axis == "y": for line in self.axesyObjs: if line is item: for i in range(self.axesyModel.rowCount()): if float( self.axesyModel.item(i, 0).text().strip( "y:")) == line.pos().y(): self.axesyModel.removeRow(i) break self.axesyObjs.pop(line) self.scene.removeItem(line) self.sigModified.emit(True) break self.calGridCoord() self.updateGrid() def deleteSelectedItem(self): pointitems = self.scene.selectedItems() if len(pointitems) == 1: self.deleteItem(pointitems[0]) def setGraphImage(self, imgfile): if not isinstance(imgfile, str): img = QPixmap(300, 400) img.fill(QColor("#EEE")) self.graphicsPixmapItem.setPixmap(img) self.scene.setSceneRect(0, 0, 300, 400) elif os.path.exists(imgfile): img = QPixmap(imgfile) self.graphicsPixmapItem.setPixmap(img) self.scene.setSceneRect(0, 0, img.width(), img.height()) self.scene.clearSelection() # 【清除选择】 self.sigModified.emit(True) return True else: return False def scaleGraphImage(self, scale=1): if scale and scale > 0: self.proj.imgScale = scale self.graphicsPixmapItem.setScale(scale) if self.graphicsPixmapItem.pixmap().width( ) > 0 and self.graphicsPixmapItem.pixmap().height() > 0: self.scene.setSceneRect( 0, 0, self.graphicsPixmapItem.pixmap().width() * scale, self.graphicsPixmapItem.pixmap().height() * scale) self.scene.clearSelection() # 【清除选择】 self.sigModified.emit(True) def addCurve(self, name=None): if not name: name = nextName(self.currentCurve) while (name in self.curveObjs): name = nextName(name) self.curveObjs[name] = [] self.pointObjs[name] = [] item1 = IconItem() item2 = QStandardItem(name) item3 = QStandardItem() item1.setEditable(False) item3.setCheckable(True) item3.setAutoTristate(False) item3.setEditable(False) item3.setCheckState(Qt.Checked) item1.setTextAlignment(Qt.AlignCenter) item2.setTextAlignment(Qt.AlignCenter) item3.setTextAlignment(Qt.AlignCenter) self.curveModel.appendRow([item1, item2, item3]) self.changeCurrentCurve(name) self.sigModified.emit(True) self.sigNewCurveAdded.emit() def renameCurve(self, newname=None, name=None): if name not in self.curveObjs: name = self.currentCurve if not newname: newname, okPressed = QInputDialog.getText( self, self.tr("change curve name"), self.tr("Curve to be renamed:{}".format(name)), QLineEdit.Normal, name) if okPressed and newname != '': if newname != name: self.curveObjs[newname] = self.curveObjs.pop(name) self.pointObjs[newname] = self.pointObjs.pop(name) for i in range(self.curveModel.rowCount()): item = self.curveModel.item(i, 1) if item.text() == name: item.setText(newname) self.sigModified.emit(True) self.changeCurrentCurve(newname) def delCurve(self, name=None): if name is None: name = self.currentCurve if name not in self.curveObjs: return try: self.curveObjs.pop(name) self.pointObjs.pop(name) for i in range(self.curveModel.rowCount()): item = self.curveModel.item(i, 1) if item.text() == name: self.curveModel.removeRows(i, 1) self.sigModified.emit(True) if len(self.curveObjs) > 0: self.changeCurrentCurve(list(self.curveObjs.keys())[0]) else: self.currentCurve = None except: pass def showCurve(self, curvename, visible=True): for pts in self.pointObjs[curvename]: pts.setVisible(visible) for line in self.curveObjs[curvename]: line.setVisible(visible) def updateCurve(self, name, color=Qt.black): # if name in self.curveObjs: # curveitem = self.curveObjs[name] # else: # curveitem = QGraphicsPathItem() # self.scene.addItem(curveitem) # # path=curveitem.path() # path = QPainterPath() # # pointItems = self.curvePointObjs[name] # if len(pointItems) > 0: # path.moveTo(pointItems[0].pos()) # for pointitem in pointItems[1:]: # path.lineTo(pointitem.pos()) # curveitem.setPath(path) # curveitem.update(curveitem.boundingRect()) # curveitem.prepareGeometryChange() # self.scene.update() # self.viewport().repaint() # self.viewport().update() if not isinstance(name, str): return if name not in self.pointObjs: return lastitems = [] if name in self.curveObjs: lastitems = self.curveObjs[name] if not isinstance(lastitems, list): lastitems = [] if name in self.pointObjs: pointItems = self.pointObjs[name] else: pointItems = [] points = [] for ptitem in pointItems: points.append(ptitem.pos()) self.curveObjs[name] = [] if len(points) > 1: for i in range(1, len(points)): l = QGraphicsLineItem(points[i - 1].x(), points[i - 1].y(), points[i].x(), points[i].y()) l.setPen(color) l.setZValue(10) # l.setFlag(QGraphicsItem.ItemIsSelectable) self.curveObjs[name].append(l) self.scene.addItem(l) for line in lastitems: self.scene.removeItem(line) self.updateCurvePoints(name) def showAxes(self, visible=True): if visible: for line in self.axesxObjs: line.setVisible(True) for line in self.axesyObjs: line.setVisible(True) else: for line in self.axesxObjs: line.setVisible(False) for line in self.axesyObjs: line.setVisible(False) def showGrid(self, visible=True): if visible: for line in self.gridObjs: line.setVisible(True) else: for line in self.gridObjs: line.setVisible(False) def calGridCoord(self, mode="all"): """calc the coord and pixel position of gridx list and gridy list""" if mode in ("x", "all") and len(self.axesxObjs) >= 2: axesxcoord = list(self.axesxObjs.values()) xmin = min(axesxcoord) if self.proj.gridx[0] is None else min( self.proj.gridx[0], min(axesxcoord)) xmax = max(axesxcoord) if self.proj.gridx[1] is None else max( self.proj.gridx[1], max(axesxcoord)) if self.proj.gridx[2] is None: if len(self.axesxObjs) == 2: xstep = (xmax - xmin) / 5 else: axesStep = round(abs(axesxcoord[1] - axesxcoord[0]), 5) for i in range(2, len(axesxcoord)): st = round(abs(axesxcoord[i] - axesxcoord[i - 1]), 5) if axesStep > st: axesStep = st xstep = axesStep else: xstep = self.proj.gridx[2] n = int(round((xmax - xmin) / xstep, 0)) + 1 gridxcoord = list(np.linspace(xmin, xmax, n)) else: gridxcoord = [] if mode in ("y", "all") and len(self.axesyObjs) >= 2: axesycoord = list(self.axesyObjs.values()) ymin = min(axesycoord) if self.proj.gridy[0] is None else min( self.proj.gridy[0], min(axesycoord)) ymax = max(axesycoord) if self.proj.gridy[1] is None else max( self.proj.gridy[1], max(axesycoord)) if self.proj.gridy[2] is None: if len(self.axesyObjs) == 2: ystep = (ymax - ymin) / 5 else: axesStep = round(abs(axesycoord[1] - axesycoord[0]), 5) for i in range(2, len(axesycoord)): st = round(axesycoord[i] - axesycoord[i - 1], 5) if axesStep > st: axesStep = st ystep = axesStep else: ystep = self.proj.gridy[2] n = int(round((ymax - ymin) / ystep, 0)) + 1 gridycoord = list(np.linspace(ymin, ymax, n)) # gridycoord = list(np.arange(ymin, ymax, ystep)) + [ymax] else: gridycoord = [] xpos, ypos = self.coordToPoint(gridxcoord, gridycoord) if mode in ["x", "all"]: self.gridxpos = xpos if mode in ["y", "all"]: self.gridypos = ypos return def updateGrid(self): for line in self.gridObjs: self.scene.removeItem(line) if self.gridxpos and self.gridypos: clr = QColor(self.proj.gridColor) clr.setAlphaF(self.proj.gridOpacity) for x in self.gridxpos: line = QGraphicsLineItem(x, self.gridypos[0], x, self.gridypos[-1]) line.setZValue(5) line.setPen( QPen(clr, self.proj.gridLineWidth, self.proj.gridLineType)) self.gridObjs.append(line) self.scene.addItem(line) for y in self.gridypos: line = QGraphicsLineItem(self.gridxpos[0], y, self.gridxpos[-1], y) line.setZValue(5) line.setPen( QPen(clr, self.proj.gridLineWidth, self.proj.gridLineType)) self.gridObjs.append(line) self.scene.addItem(line) def updateCurvePoints(self, name): extra = len(self.pointObjs[name]) - self.pointsModel.rowCount() if extra > 0: for i in range(extra): item1 = QStandardItem() item2 = QStandardItem() item3 = QStandardItem() item2.setEditable(False) item3.setEditable(False) self.pointsModel.appendRow([item1, item2, item3]) elif extra < 0: j = self.pointsModel.rowCount() i = j + extra self.pointsModel.removeRows(i, -extra) for i in range(self.pointsModel.rowCount()): pt = self.pointObjs[name][i] self.pointsModel.item(i, 0).setText(str(i + 1)) xlist, ylist = self.pointToCoord([pt.x()], [pt.y()]) self.pointsModel.item(i, 1).setText(str(round(xlist[0], 6))) self.pointsModel.item(i, 2).setText(str(round(ylist[0], 6))) def calcCurveCoords(self): """calculate datas for export""" data = {} for curve in self.pointObjs: data[curve] = ([], []) for item in self.pointObjs[curve]: data[curve][0].append(item.x()) data[curve][1].append(item.y()) data[curve] = self.pointToCoord(data[curve][0], data[curve][1]) return data def axisvalid(self): """if there are axes with same coord value, or if there are axes at the save position, return False""" a = len(self.axesxObjs) b = len(set(self.axesxObjs.values())) if a != b: return False a = len(self.axesyObjs) b = len(set(self.axesyObjs.values())) if a != b: return False xs = [] for item in self.axesxObjs: xs.append(item.pos().x()) ys = [] for item in self.axesyObjs: ys.append(item.pos().y()) a = len(xs) b = len(set(xs)) if a != b: return False a = len(ys) b = len(set(ys)) if a != b: return False return True def exportToCSVtext(self): """return text in csv format, like following: curve1 x,1,2,3 y,2,3,4 """ text = "" data = self.calcCurveCoords() for curve in data: text += curve text += "\nx," for x in data[curve][0]: text += str(x) + ',' text += "\ny," for y in data[curve][1]: text += str(y) + ',' text += "\n" return text def changeCurrentCurve(self, name=None): self._lastCurve = self.currentCurve if name is None: name = self.currentCurve if name is None: return for i in range(self.curveModel.rowCount()): if self.curveModel.item(i, 1).text() == name: self.curveModel.item(i, 0).switch(True) else: self.curveModel.item(i, 0).switch(False) self.currentCurve = name self.updateCurve(self._lastCurve) self.updateCurve(self.currentCurve, Qt.red) self.updateCurvePoints(name) def changeCurveVisible(self, item): if item.index().column() == 2: visible = item.checkState() curvename = self.curveModel.item(item.index().row(), 1).text() self.showCurve(curvename, visible) def changePointOrder(self, item): row = item.row() if item.column() != 0: return newindex = item.text() if not newindex.isdigit(): return newindex = int(newindex) if newindex == row + 1: return if newindex > self.pointsModel.rowCount(): newindex = self.pointsModel.rowCount() newindex -= 1 self.pointObjs[self.currentCurve].insert( newindex, self.pointObjs[self.currentCurve].pop(row)) self.updateCurve(self.currentCurve) self.updateCurvePoints(self.currentCurve) # def curvetabChanged(self, item): # i = item.row() # j = item.column() # if j == 0: # if item.checkState() is Qt.Checked: # self.curveModel.item(i,0).setCheckState(Qt.Checked) # return # else: # for k in range(self.curveModel.rowCount()): # if k == i: # #self.curveModel.item(k,0).setCheckState(Qt.Checked) # newcurrent = self.curveModel.item(k,1).text() # print(self.curveModel.item(k,0).checkState()) # else: # self.curveModel.item(k,0).setCheckState(Qt.Unchecked) # if newcurrent and newcurrent != self.currentCurve: # self.changeCurrentCurve(newcurrent) def pointToCoord(self, xlist, ylist): if len(self.axesxObjs) >= 2: gridxs = [] for item in self.axesxObjs: gridxs.append(item.pos().x()) coordx = list(self.axesxObjs.values()) xCoords = interp(gridxs, coordx, xlist) else: xCoords = xlist if len(self.axesyObjs) >= 2: gridys = [] for item in self.axesyObjs: gridys.append(item.pos().y()) coordy = list(self.axesyObjs.values()) yCoords = interp(gridys, coordy, ylist) else: yCoords = ylist return (xCoords, yCoords) def coordToPoint(self, xlist, ylist): if len(self.axesxObjs) >= 2: gridxpos = [] for item in self.axesxObjs: gridxpos.append(item.pos().x()) coordx = list(self.axesxObjs.values()) xposs = interp(coordx, gridxpos, xlist) else: xposs = xlist if len(self.axesyObjs) >= 2: gridypos = [] for item in self.axesyObjs: gridypos.append(item.pos().y()) coordy = list(self.axesyObjs.values()) yposs = interp(coordy, gridypos, ylist) else: yposs = ylist return (xposs, yposs)
class QmyMainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.__buildStatusBar() self.__iniGraphicsSystem() self.__ItemId = 1 self.__ItemDesc = 2 self.__seqNum = 0 self.__backZ = 0 self.__frontZ = 0 def __buildStatusBar(self): self.__labViewCord = QLabel("View 坐标:") self.__labViewCord.setMinimumWidth(150) self.ui.qStatusBar.addWidget(self.__labViewCord) self.__labSceneCord = QLabel("Scene 坐标:") self.__labSceneCord.setMinimumWidth(150) self.ui.qStatusBar.addWidget(self.__labSceneCord) self.__labItemCord = QLabel("Item 坐标:") self.__labItemCord.setMinimumWidth(150) self.ui.qStatusBar.addWidget(self.__labItemCord) self.__labItemInfo = QLabel("ItemInfo: ") self.ui.qStatusBar.addWidget(self.__labItemInfo) def __iniGraphicsSystem(self): self.view = QmyGraphicsView(self) self.setCentralWidget(self.view) self.scene = QGraphicsScene(-300, -200, 600, 200) self.view.setScene(self.scene) self.view.setCursor(Qt.CrossCursor) self.view.setMouseTracking(True) self.view.setDragMode(QGraphicsView.RubberBandDrag) self.view.mouseMove.connect(self.do_mouseMove) self.view.mouseClicked.connect(self.do_mouseClicked) self.view.mouseDoubleClick.connect(self.do_mouseDoubleClick) self.view.keyPress.connect(self.do_keyPress) def __setItemProperties(self, item, desc): item.setFlag(QGraphicsItem.ItemIsFocusable) item.setFlag(QGraphicsItem.ItemIsMovable) item.setFlag(QGraphicsItem.ItemIsSelectable) self.__frontZ += 1 item.setZValue(self.__frontZ) item.setPos(-150 + random.randint(1, 200), -200 + random.randint(1, 200)) self.__seqNum += 1 item.setData(self.__ItemId, self.__seqNum) item.setData(self.__ItemDesc, desc) self.scene.addItem(item) self.scene.clearSelection() item.setSelected(True) def __setBrushColor(self, item): color = item.brush().color() color = QColorDialog.getColor(color, self, "选择填充颜色") if color.isValid(): item.setBrush(QBrush(color)) @pyqtSlot() def on_qAction12_triggered(self): item = QGraphicsRectItem(-50, -25, 100, 50) item.setBrush(QBrush(Qt.yellow)) self.__setItemProperties(item, "矩形") @pyqtSlot() def on_qAction13_triggered(self): item = QGraphicsEllipseItem(-50, -30, 100, 60) item.setBrush(QBrush(Qt.blue)) self.__setItemProperties(item, "椭圆") @pyqtSlot() def on_qAction14_triggered(self): item = QGraphicsEllipseItem(-50, -50, 100, 100) item.setBrush(QBrush(Qt.cyan)) self.__setItemProperties(item, "圆形") @pyqtSlot() def on_qAction15_triggered(self): item = QGraphicsPolygonItem() points = [QPointF(0, -40), QPointF(60, 40), QPointF(-60, 40)] item.setPolygon(QPolygonF(points)) item.setBrush(QBrush(Qt.magenta)) self.__setItemProperties(item, "三角形") @pyqtSlot() def on_qAction16_triggered(self): item = QGraphicsPolygonItem() points = [ QPointF(-40, -40), QPointF(40, -40), QPointF(100, 40), QPointF(-100, 40) ] item.setPolygon(QPolygonF(points)) item.setBrush(QBrush(Qt.green)) self.__setItemProperties(item, "梯形") @pyqtSlot() def on_qAction17_triggered(self): item = QGraphicsLineItem(-100, 0, 100, 0) pen = QPen(Qt.red) pen.setWidth(4) item.setPen(pen) self.__setItemProperties(item, "直线") @pyqtSlot() def on_qAction18_triggered(self): strText, OK = QInputDialog.getText(self, "输入", "请输入文字") if (not OK): return item = QGraphicsTextItem(strText) font = self.font() font.setPointSize(20) font.setBold(True) item.setFont(font) item.setDefaultTextColor(Qt.black) self.__setItemProperties(item, "文字") @pyqtSlot() def on_qAction1_triggered(self): items = self.scene.selectedItems() cnt = len(items) if cnt == 1: item = items[0] item.setScale(0.1 + item.scale()) else: self.view.scale(1.1, 1.1) @pyqtSlot() def on_qAction2_triggered(self): items = self.scene.selectedItems() cnt = len(items) if cnt == 1: item = items[0] item.setScale(item.scale() - 0.1) else: self.view.scale(0.9, 0.9) @pyqtSlot() def on_qAction3_triggered(self): items = self.scene.selectedItems() cnt = len(items) if cnt == 1: item = items[0] item.setScale(1) item.setRotation(0) else: self.view.resetTransform() @pyqtSlot() def on_qAction4_triggered(self): items = self.scene.selectedItems() cnt = len(items) if cnt == 1: item = items[0] item.setRotation(-30 + item.rotation()) else: self.view.rotate(-30) @pyqtSlot() def on_qAction5_triggered(self): items = self.scene.selectedItems() cnt = len(items) if cnt == 1: item = items[0] item.setRotation(30 + item.rotation()) else: self.view.rotate(30) @pyqtSlot() def on_qAction6_triggered(self): # 前置 items = self.scene.selectedItems() cnt = len(items) if cnt > 0: item = items[0] self.__frontZ += 1 item.setZValue(self.__frontZ) @pyqtSlot() def on_qAction7_triggered(self): # 后置 items = self.scene.selectedItems() cnt = len(items) if cnt > 0: item = items[0] self.__backZ -= 1 item.setZValue(self.__backZ) @pyqtSlot() def on_qAction8_triggered(self): # 组合 items = self.scene.selectedItems() cnt = len(items) if cnt <= 1: return group = QGraphicsItemGroup() self.scene.addItem(group) for i in range(cnt): item = items[i] item.setSelected(False) item.clearFocus() group.addToGroup(item) group.setFlag(QGraphicsItem.ItemIsFocusable) group.setFlag(QGraphicsItem.ItemIsMovable) group.setFlag(QGraphicsItem.ItemIsSelectable) self.__frontZ += 1 group.setZValue(self.__frontZ) self.scene.clearSelection() group.setSelected(True) @pyqtSlot() def on_qAction9_triggered(self): items = self.scene.selectedItems() cnt = len(items) if (cnt == 1): group = items[0] self.scene.destroyItemGroup(group) @pyqtSlot() def on_qAction10_triggered(self): items = self.scene.selectedItems() cnt = len(items) for i in range(cnt): item = items[i] self.scene.removeItem(item) def do_mouseMove(self, point): self.__labViewCord.setText("View 坐标:%d, %d" % (point.x(), point.y())) pt = self.view.mapToScene(point) self.__labSceneCord.setText("Scene 坐标:%.0f, %.0f" % (pt.x(), pt.y())) def do_mouseClicked(self, point): pt = self.view.mapToScene(point) item = self.scene.itemAt(pt, self.view.transform()) if (item == None): return pm = item.mapFromScene(pt) self.__labItemCord.setText("item 坐标:%.0f, %.0f" % (pm.x(), pm.y())) self.__labItemInfo.setText( str(item.data(self.__ItemDesc)) + ", ItemId=" + str(item.data(self.__ItemId))) def do_mouseDoubleClick(self, point): pt = self.view.mapToScene(point) item = self.scene.itemAt(pt, self.view.transform()) if (item == None): return className = str(type(item)) if (className.find("QGraphicsRectItem") >= 0): self.__setBrushColor(item) elif (className.find("QGraphicsEllipseItem") >= 0): self.__setBrushColor(item) elif (className.find("QGraphicsEllipseItem") >= 0): self.__setBrushColor(item) elif (className.find("QGraphicsLineItem") >= 0): pen = item.pen() color = item.pen().color() color = QColorDialog.getColor(color, self, "选择线条颜色") if color.isValid(): pen.setColor(color) item.setPen(pen) elif (className.find("QGraphicsTextItem") >= 0): font = item.font() font, OK = QFontDialog.getFont(font) if OK: item.setfont(font) def do_keyPress(self, event): items = self.scene.selectedItems() cnt = len(items) if (cnt != 1): return item = items[0] key = event.key() if (key == Qt.Key_Delete): self.scene.removeItem(item) elif (key == Qt.Key_Space): item.setRotation(90 + item.rotation()) elif (key == Qt.Key_PageUp): item.setScale(0.1 + item.scale()) elif (key == Qt.Key_PageDown): item.setScale(-0.1 + item.scale()) elif (key == Qt.Key_Left): item.setX(-1 + item.x()) elif (key == Qt.Key_Right): item.setX(1 + item.x()) elif (key == Qt.Key_Up): item.setY(-1 + item.y()) elif (key == Qt.Key_Down): item.setY(1 + item.y())
class MainForm(QDialog): def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.filename = "" self.copiedItem = QByteArray() self.pasteOffset = 5 self.prevPoint = QPoint() self.addOffset = 5 self.borders = [] self.printer = QPrinter(QPrinter.HighResolution) self.printer.setPageSize(QPrinter.Letter) self.view = GraphicsView(self) self.scene = QGraphicsScene(self) self.scene.setSceneRect(0, 0, PageSize[0], PageSize[1]) # self.addBorders() self.view.setScene(self.scene) self.wrapped = [] # Needed to keep wrappers alive buttonLayout = QVBoxLayout() for text, slot in ( ("Add &Location", self.addLocation), ("Add &Edge", self.addEdge), ("Add &Variable", self.addVariable), # ("List &TextName", self.listTextName), ("&Open...", self.open), ("&Save", self.save), ("&RePaint", self.RePaintLine), ("&Quit", self.accept), #("&SameX", self.SameX), ("&New Black HA", self.newHA), ("QLineEdit", "Current HA Name"), ("QComboBox", "HA Name List"), ("QLineEdit", "Current Model Name"), ("S&witch HA", self.switchHA), ("&Delete HA", self.deleteHA), ("&Copy And New HA", self.copyHA)): if text in ['QLineEdit', 'QComboBox']: lbl = QLabel(slot) buttonLayout.addWidget(lbl) if slot == 'Current HA Name': self.txtHAName = QLineEdit() self.txtHAName.setText("NoName") buttonLayout.addWidget(self.txtHAName) #self.txtHAName.textChanged.connect(self.txtChanged) if slot == 'Current Model Name': self.txtModelName = QLineEdit() self.txtModelName.setText("NoName") buttonLayout.addWidget(self.txtModelName) self.txtModelName.hide() #self.txtModelName.textChanged.connect(self.txtChanged) lbl.hide() if slot == 'HA Name List': self.cmbHANameList = QComboBox() buttonLayout.addWidget(self.cmbHANameList) else: button = QPushButton(text) if not MAC: button.setFocusPolicy(Qt.NoFocus) if slot is not None: button.clicked.connect(slot) #if shortcutKey: # shortcut = QShortcut(QKeySequence(shortcutKey), self) # shortcut.activated.connect(slot) if text == "&Align": menu = QMenu(self) for text, arg in (("Align &Left", Qt.AlignLeft), ("Align &Right", Qt.AlignRight), ("Align &Top", Qt.AlignTop), ("Align &Bottom", Qt.AlignBottom)): wrapper = functools.partial(self.setAlignment, arg) self.wrapped.append(wrapper) menu.addAction(text, wrapper) button.setMenu(menu) if text == "Pri&nt...": buttonLayout.addStretch(5) if text == "&Quit": buttonLayout.addStretch(1) buttonLayout.addWidget(button) buttonLayout.addStretch() layout = QHBoxLayout() layout.addWidget( self.view, 1, ) layout.addLayout(buttonLayout) layoutTable = QVBoxLayout() #BoxLayout() self.EdgeWidget = QTableWidget() layoutTable.addWidget(self.EdgeWidget) # setup table widget self.EdgeWidget.itemDoubleClicked.connect(self.EdgeWidgetDoubleClicked) self.EdgeWidget.setColumnCount(3) self.EdgeWidget.setHorizontalHeaderLabels( ['EdgeName', 'Guard', 'Reset']) self.EdgeWidget.setColumnWidth(0, 40) self.EdgeWidget.setColumnWidth(1, 200) self.EdgeWidget.setColumnWidth(2, 200) self.EdgeWidget.setSelectionMode(QAbstractItemView.SingleSelection) self.EdgeWidget.setSelectionBehavior(QAbstractItemView.SelectItems) self.EdgeWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) #self.EdgeWidget.resizeColumnsToContents() self.VariablesWidget = QTableWidget() layoutTable.addWidget(self.VariablesWidget) # setup table widget self.VariablesWidget.itemDoubleClicked.connect( self.VariablesWidgetDoubleClicked) self.VariablesWidget.setColumnCount(5) self.VariablesWidget.setHorizontalHeaderLabels( ['Name', 'Initial Value', 'Input', 'Output', "IsConstant"]) #self.VariablesWidget.hideColumn(0) self.VariablesWidget.setColumnWidth(0, 100) self.VariablesWidget.setColumnWidth(1, 200) self.VariablesWidget.setColumnWidth(2, 100) self.VariablesWidget.setColumnWidth(3, 100) self.VariablesWidget.setColumnWidth(4, 100) self.VariablesWidget.setSelectionMode( QAbstractItemView.SingleSelection) #self.VariablesWidget.setSelectionBehavior(QAbstractItemView.SelectRows) self.VariablesWidget.setSelectionBehavior( QAbstractItemView.SelectItems) self.VariablesWidget.setEditTriggers(QAbstractItemView.NoEditTriggers) #self.VariablesWidget.resizeColumnsToContents() layoutMain = QVBoxLayout() layoutMain.addLayout(layout) layoutMain.addLayout(layoutTable) layoutMain.setStretchFactor(layout, 8) layoutMain.setStretchFactor(layoutTable, 2) self.setLayout(layoutMain) fm = QFontMetrics(self.font()) self.resize(self.scene.width() + fm.width(" Delete... ") + 50, self.scene.height() + 50) self.setWindowTitle("Simulation of HA Designer") self.setWindowFlags(Qt.Window | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint) self.dicText = {} self.dicLine = {} self.dicVariable = {} self.dicHA = {} self.dicModel = {} #self.dicModel["HAs"]={} self.currentProject = {} #self.currentProject["Models"]={} #self.currentProject["Models"]["NoName"]=self.dicModel self.currentHA = None def txtChanged(self): self.setDirty() def setDirty(self, newDirty=None): if newDirty is None: newDirty = True global Dirty Dirty = newDirty #create a blank HA def newHA(self): if self.txtHAName.text() == "NoName": if (Dirty): QMessageBox.question( self, "Please Input HA Name", "Fail to New HA,Please Change the HA Name from 'NoName' to a new name you want!", QMessageBox.Ok) return self.offerSave() if (Dirty): QMessageBox.question( self, "Please Save or Discard Current Editing", "Fail to new HA,Please Save or Discard current editing first!", QMessageBox.Ok) return self.clearCurrent() self.txtHAName.setText("NoName") self.currentHA = None # create a new HA who has locations, edges and variables as same as the selected HA def copyHA(self): global Dirty if self.txtHAName.text() == "NoName": if (Dirty): QMessageBox.question( self, "Please Input HA Name", "Fail to copy HA,Please Change the HA Name from 'NoName' to a new name you want!", QMessageBox.Ok) return self.offerSave() if (Dirty): QMessageBox.question( self, "Please Save or Discard Current Editing", "Fail to copy HA,Please Save or Discard current editing first!", QMessageBox.Ok) return '''if (self.cmbHANameList.currentText()==""): QMessageBox.question(self, "Please Select HA Name", "Fail to copy HA,Please select a HA Name in HA Name List!", QMessageBox.Ok ) return ''' self.currentHA = self.currentProject["Models"][ self.txtModelName.text()]["HAs"][self.txtHAName.text()] self.clearCurrent() self.DrawHA(self.currentHA) self.txtHAName.setText("NoName") self.currentHA = None self.setDirty() # change to current designed HA by select another HA name in “HA Name List” def switchHA(self): if self.txtHAName.text() == "NoName": if (Dirty): QMessageBox.question( self, "Please Input HA Name", "Fail to switch HA,Please Change the HA Name from 'NoName' to a new name you want!", QMessageBox.Ok) return NewHAName = self.cmbHANameList.currentText() self.offerSave() if (Dirty): QMessageBox.question( self, "Please Save or Discard Current Editing", "Fail to switch HA,Please Save or Discard current editing first!", QMessageBox.Ok) return if (self.cmbHANameList.currentText() == ""): QMessageBox.question( self, "Please Select HA Name", "Fail to switch HA,Please select a HA Name in HA Name List!", QMessageBox.Ok) return self.clearCurrent() self.cmbHANameList.setEditText(NewHAName) self.txtHAName.setText(self.cmbHANameList.currentText()) self.DrawHA() #delete an HA whose name is selected in “Ha Name List”. def deleteHA(self): strHAName = self.txtHAName.text() if (strHAName in self.currentProject["Models"][ self.txtModelName.text()]["HAs"].keys()): self.currentProject["Models"][self.txtModelName.text()]["HAs"].pop( strHAName) self.clearCurrent() if not self.filename: pass else: with open(self.filename, 'w') as fh: json.dump(self.currentProject, fh) self.setDirty(False) self.DrawDefaultHA() #edit selected edge def EdgeWidgetDoubleClicked(self, item): selectItemText = self.EdgeWidget.item(item.row(), 0).text() if selectItemText in self.dicLine: dialog = EdgeItemDlg(self.dicLine[selectItemText], None, self.scene, self) dialog.exec_() #edit selected Variable def VariablesWidgetDoubleClicked(self, item): selectItemText = self.VariablesWidget.item(item.row(), 0).text() if selectItemText in self.dicVariable: dialog = VariableItemDlg(self.dicVariable[selectItemText], self) dialog.exec_() #delete location def deleteText(self, LocationItem): if LocationItem.boxName in self.dicText: self.dicText.pop(LocationItem.boxName) self.scene.removeItem(LocationItem) self.scene.update() #delete edge def deleteLine(self, lineItem): self.dicLine.pop(lineItem.boxName) self.scene.removeItem(lineItem) self.scene.update() rowCount = self.EdgeWidget.rowCount() for row_index in range(rowCount): if self.EdgeWidget.item(row_index, 0).text() == lineItem.boxName: self.EdgeWidget.removeRow(row_index) return #rename edge def renameLine(self, OldName, NewName): rowCount = self.EdgeWidget.rowCount() for row_index in range(rowCount): if self.EdgeWidget.item(row_index, 0).text() == OldName: self.EdgeWidget.setItem(row_index, 0, QTableWidgetItem(NewName, 0)) return #delete variable def deleteVariable(self, VariableItem): self.dicVariable.pop(VariableItem.boxName) rowCount = self.VariablesWidget.rowCount() for row_index in range(rowCount): if self.VariablesWidget.item(row_index, 0).text() == VariableItem.boxName: self.VariablesWidget.removeRow(row_index) return #rename variable def renameVariable(self, OldName, NewName): rowCount = self.VariablesWidget.rowCount() for row_index in range(rowCount): if self.VariablesWidget.item(row_index, 0).text() == OldName: self.VariablesWidget.setItem(row_index, 0, QTableWidgetItem(NewName, 0)) return # add a variable def addVariableInTable(self, variableItem): row_index = self.VariablesWidget.rowCount() self.VariablesWidget.insertRow(row_index) row_index = row_index self.VariablesWidget.setItem(row_index, 0, QTableWidgetItem(variableItem.boxName, 0)) self.VariablesWidget.setItem( row_index, 1, QTableWidgetItem(variableItem.initialValue, 0)) self.VariablesWidget.setItem( row_index, 2, QTableWidgetItem(str(variableItem.isInput), 0)) self.VariablesWidget.setItem( row_index, 3, QTableWidgetItem(str(variableItem.isOutput), 0)) self.VariablesWidget.setItem( row_index, 4, QTableWidgetItem(str(variableItem.isConstant), 0)) self.VariablesWidget.resizeRowToContents(row_index) self.VariablesWidget.resizeRowsToContents() self.VariablesWidget.resizeColumnsToContents() #update variable def setVariableInTable(self, variableItem): rowCount = self.VariablesWidget.rowCount() for row_index in range(rowCount): if self.VariablesWidget.item(row_index, 0).text() == variableItem.boxName: self.VariablesWidget.setItem( row_index, 1, QTableWidgetItem(variableItem.initialValue, 0)) self.VariablesWidget.setItem( row_index, 2, QTableWidgetItem(str(variableItem.isInput), 0)) self.VariablesWidget.setItem( row_index, 3, QTableWidgetItem(str(variableItem.isOutput), 0)) self.VariablesWidget.setItem( row_index, 4, QTableWidgetItem(str(variableItem.isConstant), 0)) self.VariablesWidget.resizeRowToContents(row_index) self.VariablesWidget.resizeColumnsToContents() return #add an Edge def addEdgeInTable(self, edgeItem): row_index = self.EdgeWidget.rowCount() self.EdgeWidget.insertRow(row_index) row_index = row_index self.EdgeWidget.setItem(row_index, 0, QTableWidgetItem(edgeItem.boxName, 0)) self.EdgeWidget.setItem(row_index, 1, QTableWidgetItem(edgeItem.guard, 0)) self.EdgeWidget.setItem(row_index, 2, QTableWidgetItem(edgeItem.reset, 0)) self.EdgeWidget.resizeRowToContents(row_index) self.EdgeWidget.resizeRowsToContents() self.EdgeWidget.resizeColumnsToContents() #update an Edge def setEdgeInTable(self, edgeItem): rowCount = self.EdgeWidget.rowCount() for row_index in range(rowCount): if self.EdgeWidget.item(row_index, 0).text() == edgeItem.boxName: self.EdgeWidget.setItem(row_index, 1, QTableWidgetItem(edgeItem.guard, 0)) self.EdgeWidget.setItem(row_index, 2, QTableWidgetItem(edgeItem.reset, 0)) self.EdgeWidget.resizeRowToContents(row_index) self.EdgeWidget.resizeColumnsToContents() return #add a new location def addLocation(self): dialog = LocationItemDlg(position=self.position(), scene=self.scene, parent=self) dialog.exec_() def listTextName(self): buttonReply = QMessageBox.question(self, 'PyQt5 message', str(self.dicText), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) buttonReply = QMessageBox.question(self, 'PyQt5 message', str(self.dicLine.keys()), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) #add a new Variable def addVariable(self): dialog = VariableItemDlg(parent=self) dialog.exec_() def addPicture(self): fig, ax = plt.subplots(figsize=(8, 5)) X, Y = fig.get_dpi() * fig.get_size_inches() h = Y i = 2 if i == 2: name = 'aa' formula = r'$x=\frac{3}{100}$' ax.text(0.5, 2.5, name + formula, fontsize=(h), horizontalalignment='left', verticalalignment='center') ax.set_xlim(1, X) ax.set_ylim(1, Y) ax.set_axis_off() #fig.subplots_adjust(left=0, right=1, top=1, bottom=0, hspace=0, wspace=0) plt.show() #add a new Edge def addEdge(self): dialog = EdgeItemDlg(position=self.position(), scene=self.scene, parent=self) dialog.exec_() #to refresh the design file def RePaintLine(self): for line in self.dicLine.values(): line.resetLine() for item in self.dicText.values(): item.rePaint() item.update() # self.scene.update() def position(self): point = self.mapFromGlobal(QCursor.pos()) if not self.view.geometry().contains(point): coord = random.randint(36, 144) point = QPoint(coord, coord) else: if point == self.prevPoint: point += QPoint(self.addOffset, self.addOffset) self.addOffset += 5 else: self.addOffset = 5 self.prevPoint = point return self.view.mapToScene(point) #clear the screen and ready to draw a new HA def clearCurrent(self): self.EdgeWidget.clearContents() self.EdgeWidget.setRowCount(0) self.VariablesWidget.clearContents() self.VariablesWidget.setRowCount(0) items = self.scene.items() while items: item = items.pop() self.scene.removeItem(item) del item #self.addBorders() dictItemJson={} self.dicItem = {} self.dicLine = {} self.dicText = {} self.dicVariable = {} #show a HA on screen def DrawHA(self, currentHA=None): if (currentHA is None): if not self.txtModelName.text( ) in self.currentProject["Models"].keys(): return if not self.txtHAName.text() in self.currentProject["Models"][ self.txtModelName.text()]["HAs"].keys(): return self.currentHA = self.currentProject["Models"][ self.txtModelName.text()]["HAs"][self.txtHAName.text()] else: self.currentHA = currentHA for key, item in self.currentHA["boxes"].items(): self.readItemFrom(item) self.DrawLine(self.currentHA["lines"]) self.DrawVariable(self.currentHA["variables"]) #show Default HA on screen def DrawDefaultHA(self): if ("NoName" in self.currentProject["Models"].keys()) or len( self.currentProject["Models"]) == 0: self.txtModelName.setText("NoName") else: self.txtModelName.setText( next(iter(self.currentProject["Models"].keys()))) if ("NoName" in self.currentProject["Models"][self.txtModelName.text()] ["HAs"].keys()) or len(self.currentProject["Models"][ self.txtModelName.text()]["HAs"]) == 0: self.txtHAName.setText("NoName") else: self.txtHAName.setText( next( iter(self.currentProject["Models"][ self.txtModelName.text()]["HAs"].keys()))) self.cmbHANameList.clear() self.cmbHANameList.addItems([ key for key in self.currentProject["Models"][ self.txtModelName.text()]["HAs"].keys() ]) self.DrawHA() # load a exists HA file to edit def open(self): self.offerSave() path = "." # (QFileInfo(self.filename).path() #if self.filename else ".") fname, filetype = QFileDialog.getOpenFileName( self, "Designer - Open", path, "Designer Files (*.json)") if not fname: return self.filename = fname self.clearCurrent() fh = None try: #if 1==1: with open(self.filename, 'r') as fh: self.currentProject = json.load(fh) self.DrawDefaultHA() except IOError as e: QMessageBox.warning( self, "Designer -- Open Error", "Failed to open {0}: {1}".format(self.filename, e)) finally: if fh is not None: fh.close() global Dirty Dirty = False def reject(self): self.accept() def accept(self): self.offerSave() QDialog.accept(self) #save the current HA def offerSave(self): if self.currentHA is not None: if not self.currentHA["name"] == self.txtHAName.text(): self.setDirty() if (Dirty and QMessageBox.question( self, "Page Designer - Unsaved Changes", "Save unsaved changes?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes): self.save() def SameX(self): if self.scene.selectedItems() == None: return if len(self.scene.selectedItems()) == 0: return x = self.scene.selectedItems()[0].x() for box in self.scene.selectedItems(): box.setPos(x, box.y()) lines = [ line for line in self.dicLine.values() if (line.fromBox.boxName == box.boxName or line.toBox.boxName == box.boxName) ] for line in lines: line.resetLine() self.scene.update() def SameY(self): if self.scene.selectedItems() == None: return y = self.scene.selectedItems()[0].y() for box in self.scene.selectedItems(): box.setPos(box.x(), y) self.scene.update() #save the current HA def save(self): if not self.filename: path = "." fname, filetype = QFileDialog.getSaveFileName( self, "Page Designer - Save As", path, "Page Designer Files (*.json)") if not fname: return self.filename = fname fh = None #try: if 1 == 1: self.scene.clearSelection() dicBoxSave = {} dicLineSave = {} dicVariableSave = {} for item in self.dicText.values(): dicBoxSave[item.boxName] = item.toSaveJson() for item in self.dicLine.values(): dicLineSave[item.boxName] = item.toSaveJson() for item in self.dicVariable.values(): dicVariableSave[item.boxName] = item.toSaveJson() if self.currentHA is not None: if not self.currentHA["name"] == self.txtHAName.text(): self.currentProject["Models"][ self.txtModelName.text()]["HAs"].pop( self.currentHA["name"]) HASave = {} HASave["boxes"] = dicBoxSave HASave["lines"] = dicLineSave HASave["variables"] = dicVariableSave HASave["type"] = "HA" HASave["name"] = self.txtHAName.text() #self.dicHA[self.txtHAName.text()]=HASave if (len(dicBoxSave) > 0): if not "Models" in self.currentProject.keys(): self.currentProject["Models"] = {} if not self.txtModelName.text( ) in self.currentProject["Models"].keys(): self.currentProject["Models"][ self.txtModelName.text()] = {} if not "HAs" in self.currentProject["Models"][ self.txtModelName.text()].keys(): self.currentProject["Models"][ self.txtModelName.text()]["HAs"] = {} self.currentProject["Models"][self.txtModelName.text()]["HAs"][ self.txtHAName.text()] = HASave CurrentModel = {} CurrentModel["HAs"] = self.dicHA CurrentModel["type"] = "Model" CurrentModel["name"] = self.txtModelName.text() #self.dicModel[self.txtModelName.text()]=CurrentModel self.currentHA = HASave #self.currentProject["Models"]=self.dicModel self.cmbHANameList.clear() self.cmbHANameList.addItems([ key for key in self.currentProject["Models"][ self.txtModelName.text()]["HAs"].keys() ]) with open(self.filename, 'w') as fh: json.dump(self.currentProject, fh) global Dirty Dirty = False #show current variables in screen def DrawVariable(self, Variables): #draw lines between diffenent Loaation for key, ln in Variables.items(): if ln["type"] == "Variable": if not "isConstant" in ln.keys(): ln["isConstant"] = False if not "initialValue" in ln.keys(): ln["initialValue"] = "0" v = VariableItem(ln["boxName"], ln["isInput"], ln["isOutput"], ln["isConstant"], ln["initialValue"], self) self.dicVariable[v.boxName] = v self.addVariableInTable(v) #show current edges in screen def DrawLine(self, Lines): #draw lines between diffenent Loaation for key, ln in Lines.items(): if ln["type"] == "Edge": str1 = ln["strFromLocation"] str2 = ln["strToLocation"] if not (str1 == str2): n = EdgeItem(ln["boxName"], self.dicText[ln["strFromLocation"]], self.dicText[ln["strToLocation"]], ln["guard"], ln["reset"], self.scene, self, ln["style"]) self.dicLine[ln["boxName"]] = n n.setRotation(ln["rotation"]) self.addEdgeInTable(n) #draw lines in a Loaation self for key, ln in Lines.items(): if ln["type"] == "Edge": str1 = ln["strFromLocation"] str2 = ln["strToLocation"] if (str1 == str2): n = EdgeItem(ln["boxName"], self.dicText[ln["strFromLocation"]], self.dicText[ln["strToLocation"]], ln["guard"], ln["reset"], self.scene, self, ln["style"]) self.dicLine[ln["boxName"]] = n n.setRotation(ln["rotation"]) self.addEdgeInTable(n) #show current edges in screen def DrawLineFromRead(self): #draw lines between diffenent Loaation for key, ln in self.dicItem.items(): if ln["type"] == "Edge": str1 = ln["strFromLocation"] str2 = ln["strToLocation"] if not (str1 == str2): n = EdgeItem(ln["boxName"], self.dicText[ln["strFromLocation"]], self.dicText[ln["strToLocation"]], ln["guard"], ln["reset"], self.scene, self, ln["style"]) self.dicLine[ln["boxName"]] = n n.setRotation(ln["rotation"]) self.addEdgeInTable(n) #draw lines in a Loaation self for key, ln in self.dicItem.items(): if ln["type"] == "Edge": str1 = ln["strFromLocation"] str2 = ln["strToLocation"] if (str1 == str2): n = EdgeItem(ln["boxName"], self.dicText[ln["strFromLocation"]], self.dicText[ln["strToLocation"]], ln["guard"], ln["reset"], self.scene, self, ln["style"]) self.dicLine[ln["boxName"]] = n n.setRotation(ln["rotation"]) self.addEdgeInTable(n) #get a HA from file def readItemFrom(self, item): if item["type"] == "Text": tx = TextItem(item, '', '', self.scene, self) self.dicText[tx.boxName] = tx tx.setRotation(item["rotation"]) elif item["type"] == "Location": # def __init__(self, boxName, equation, guard, position, isInitial, isNameAbove, scene,parentForm, style=Qt.SolidLine, tx = LocationItem(item, '', '', '', '', '', '', '', self.scene, self) self.dicText[tx.boxName] = tx tx.setRotation(item["rotation"]) pass elif type == "Pixmap": pass elif type == "Line": pass def writeItemToStream( self, item, ): #if isinstance(item, TextItem): data = item.toSaveJson() self.dictItemJson[item.boxName] = data
class MapWidget(QtWidgets.QFrame): """ Custom tab widget with function for editing templates """ mapItem_delete_signal = QtCore.pyqtSignal(object) def __init__(self, parent, mainWindow): super().__init__(parent) self.mainWindow = mainWindow self.mapManager = MapManager() self.map = None self.init_bar() self.init_ui() self.mapItem_delete_signal.connect(self.item_delete_slot) def init_ui(self): """ Init map widget UI :return: """ self.setFrameShape(QtWidgets.QFrame.NoFrame) self.frameLayout = QtWidgets.QVBoxLayout(self) self.frameLayout.setObjectName("Frame layout") self.grview = QGraphicsView() self.grview.setRenderHints(self.grview.renderHints() | QPainter.Antialiasing | QPainter.SmoothPixmapTransform) self.scene = QGraphicsScene() # scene.setSceneRect(0, 0, 1500, 459) self.grview.setScene(self.scene) noMap = QPixmap('resources/icons/no_map.png') self.scene.addPixmap(noMap) self.grview.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) self.frameLayout.addWidget(self.grview) def init_bar(self) -> None: """ Init function bar, set to right side of widget :return: """ toolbar = QToolBar() toolbar.setObjectName('MapToolbar') self.mainWindow.addToolBar(Qt.RightToolBarArea, toolbar) # ------------------------------- Open map ---------------------------------- self.openMap_action = QAction(QIcon('resources/icons/openMap.png'), TR().tr('Open_map'), self.mainWindow, triggered=self.open_map_action, enabled=False) toolbar.addAction(self.openMap_action) # ------------------------------- Zoom in ---------------------------------- self.zoomIn_action = QAction(QIcon('resources/icons/zoomIn.png'), TR().tr('Zoom_in'), self.mainWindow, triggered=self.zoom_in_action, shortcut='Ctrl++', enabled=False) toolbar.addAction(self.zoomIn_action) # ------------------------------- Zoom out ---------------------------------- self.zoomOut_action = QAction(QIcon('resources/icons/zoomOut.png'), TR().tr('Zoom_out'), self.mainWindow, triggered=self.zoom_out_action, shortcut='Ctrl++', enabled=False) toolbar.addAction(self.zoomOut_action) # ------------------------------- Edit info ---------------------------------- self.info_action = QAction(QIcon('resources/icons/scroll.png'), TR().tr('Edit_info'), self.mainWindow, triggered=self.edit_info_action, shortcut='Ctrl+P', enabled=False) toolbar.addAction(self.info_action) toolbar.addSeparator() # ------------------------------- Add monster ---------------------------------- self.addMonster_action = QAction(QIcon('resources/icons/addMonster.png'), TR().tr('Add_monster'), self.mainWindow, triggered=self.add_monster_action, shortcut='Ctrl+M', enabled=False) toolbar.addAction(self.addMonster_action) # ------------------------------- Add item ---------------------------------- self.addItem_action = QAction(QIcon('resources/icons/addItem.png'), TR().tr('Add_item'), self.mainWindow, triggered=self.add_item_action, enabled=False) toolbar.addAction(self.addItem_action) # ------------------------------- Add room ---------------------------------- self.addRoom_action = QAction(QIcon('resources/icons/addRoom.png'), TR().tr('Add_room'), self.mainWindow, triggered=self.add_room_action, enabled=False) toolbar.addAction(self.addRoom_action) # ------------------------------- Add object ---------------------------------- self.addObject_action = QAction(QIcon('resources/icons/addObject.png'), TR().tr('Add_object_map'), self.mainWindow, triggered=self.add_object_action, enabled=False) toolbar.addAction(self.addObject_action) def enable_tool_bar(self) -> None: """ Enable tool bar actions """ self.openMap_action.setEnabled(True) self.zoomIn_action.setEnabled(True) self.zoomOut_action.setEnabled(True) self.info_action.setEnabled(True) self.addItem_action.setEnabled(True) self.addRoom_action.setEnabled(True) self.addMonster_action.setEnabled(True) self.addObject_action.setEnabled(True) def tree_item_doubleclick_action(self, item) -> None: """ Slot for double click on map at tree widget :param item: item in tree widget """ if self.map: self.save_map() if item: if item.data(0, 11).object_type is not ObjectType.MAP: self.mainWindow.redraw_context_widget(item.data(0, 11).object_type, item) else: self.enable_tool_bar() map = MapDAO().get(item.data(0, 11).id) if self.map and self.map.id == map.id: map = MapDAO().get(item.data(0, 11).id) self.map = map self.redraw() def item_delete_slot(self, mapItem) -> None: """ Slot for deleting map item from map. Deleted from map and updated in database :param mapItem: map item, that you want to delete :return: """ # mapItem.number self.map.mapItemDraws.remove(self.map.mapItemDraws[mapItem.number - 1]) MapItemDAO().delete(mapItem.mapItem.id) # self.redraw() def save_map(self) -> None: """ Save image of map :return: """ self.mapManager.update(self.map) self.save_map_action() def redraw(self) -> None: """ Redraw scene in widget Whole scene is cleared and new map and map items is draw """ self.scene.clear() if self.map.mapFile: pixMap = QPixmap(self.map.mapFile) sceneMap = self.scene.addPixmap(pixMap) self.map.mapPixMap = sceneMap self.grview.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) for num, mapItem in enumerate(self.map.mapItems): mapItem.number = num + 1 item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def open_map_action(self) -> None: """ Open image with map slot, if some map is here, old one is deleted """ fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self.mainWindow, "Open File", QtCore.QDir.currentPath()) if fileName: if self.map.mapPixMap: self.scene.removeItem(self.map.mapPixMap) fileName = self.mapManager.copy_map(fileName, self.map) self.map.mapFile = fileName self.map.mapPixMap = self.scene.addPixmap(QPixmap(fileName)) self.grview.fitInView(self.scene.itemsBoundingRect(), Qt.KeepAspectRatio) def zoom_in_action(self) -> None: """ Zoom in whole map widget """ self.grview.scale(1.2, 1.2) def zoom_out_action(self) -> None: """ Zoom out whole map widget """ self.grview.scale(0.8, 0.8) def add_item_action(self) -> None: """ Add item to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.ITEM) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def add_monster_action(self) -> None: """ Add monster to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.MONSTER) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def add_room_action(self) -> None: """ Add room to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.ROOM) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def add_object_action(self) -> None: """ Add object to map :return: """ data, choice = NewMapItem.get_data() if choice: number = len(self.map.mapItemDraws) + 1 mapItem = MapItem(None, data.get('name', ''), data.get('description', ''), QPointF(), 0, number, None, self.map.id, MapItemType.OBJECT) id = MapItemDAO().create(mapItem) mapItem.id = id item = MapItemDraw(mapItem, self.mapItem_delete_signal) self.scene.addItem(item) self.map.addMapItemDraws(item) def edit_info_action(self) -> None: """ Edit map info, when click on edit button """ data, choice = EditMapItem.get_data(None, self.map) if choice: self.map.name = data['name'] self.map.description = data['description'] def save_map_action(self): """ Save whole map action. This action create image from map :return: """ self.scene.clearSelection() self.scene.setSceneRect(self.scene.itemsBoundingRect()) img = QImage(self.scene.sceneRect().size().toSize(), QImage.Format_ARGB32) img.fill(Qt.transparent) painter = QPainter(img) self.scene.render(painter) name = 'resources/maps/exportedMap-{}.png'.format(self.map.id) img.save(name) del painter def drawItems(self, painter, items, options, widget=None): pass