如何使复制粘贴遵循相同的模式

时间:2019-08-09 07:23:33

标签: pyqt5

我正在使用QGraphicsitems创建一个设计。我已经选择了场景中的所有项目并将其粘贴。但是它并没有遵循相同的模式。我们能否使这些项目以与最初创建的模式相同的模式粘贴? –

我尝试使用以下代码

from PyQt5.QtCore import (QByteArray,QDataStream, QIODevice,pyqtSlot, QMimeData, QPointF, QPoint, Qt, QRect,QTimer,QLineF, QEvent,QRectF)
  from PyQt5.QtGui import QColor,QDrag, QPainter, QPixmap,QFont,QFontMetrics,QBrush, QLinearGradient, QIcon, QPen, QPainterPath, QTransform,QCursor,QMouseEvent,QClipboard
  from PyQt5.QtWidgets import QApplication,QGraphicsTextItem,QGraphicsItemGroup, QSizePolicy,QShortcut, QScrollArea, QPushButton,QLineEdit, QMainWindow,QInputDialog, QGraphicsPathItem,QDialog, QVBoxLayout,QGraphicsItem,QStatusBar,QTextEdit, QAction,QMenu, qApp,QSplitter, QButtonGroup, QToolButton, QFrame, QHBoxLayout, QGraphicsView, QGraphicsItem, QGraphicsPixmapItem, QLabel, QGraphicsScene, QWidget
  import importlib
  import SketchBook as sketchBook
  import Blocks as blocks


  import random
  custom_mimeType = "application/x-qgraphicsitems"
  pos1 = QPointF()



  def item_to_ds(it, ds):
      if not isinstance(it, QGraphicsItem):
          return
      ds.writeQString(it.__class__.__module__)
      ds.writeQString(it.__class__.__name__)
      ds.writeInt(it.flags())
      ds << it.pos()

      posdiff = it.pos().x() -pos1().x()
      pos1 = QPointF(it.pos().x(),it.pos().y())
      # ds.writeInt(it.UserType)
      ds.writeFloat(it.opacity())
      ds.writeFloat(it.rotation())
      ds.writeFloat(it.scale())
      # ds.writeString(it.type())
      # ds.writeQString(it.type1())
      # if isinstance(it, QGraphicsItem):
      #     ds << it.brush() << it.pen()
      if isinstance(it, QGraphicsPixmapItem):
          ds << it.pixmap()
      if isinstance(it, QGraphicsPathItem):
          ds << it.path()

  def ds_to_item(ds):
      module_name = ds.readQString()
      class_name = ds.readQString()
      if class_name == 'QGraphicsPixmapItem':
          mod = importlib.import_module(module_name)
          it = getattr(mod, class_name)()
          # flags = QGraphicsItem.GraphicsItemFlag(ds.readInt())
          # pos = QPointF()
          # ds >> pos
          # it.setFlags(flags)
          # it.setPos(pos)
          # it.setOpacity(ds.readFloat())
          # it.setRotation(ds.readFloat())
          # it.setScale(ds.readFloat())
      else:
          mod = importlib.import_module(module_name)
          it = getattr(mod, class_name)(blocks.selectedObjType)
      flags = QGraphicsItem.GraphicsItemFlag(ds.readInt())
      pos = QPointF()
      ds >> pos
      it.setFlags(flags)
      it.setPos(pos)
      it.setOpacity(ds.readFloat())
      it.setRotation(ds.readFloat())
      it.setScale(ds.readFloat())
      # if isinstance(it, QGraphicsItem):
      #     pen, brush = QPen(), QBrush()
      #     ds >> brush
      #     ds >> pen
      #     it.setPen(pen)
      #     it.setBrush(brush)
      if isinstance(it, QGraphicsPathItem):
          path = QPainterPath()
          ds >> path
          it.setPath(path)
      if isinstance(it, QGraphicsPixmapItem):
          pixmap = QPixmap()
          # pen, brush = QPen(), QBrush()
          # ds >> brush
          # ds >> pen
          ds >> pixmap
          it.setPixmap(pixmap)

      return it
  class GraphicsSceneClass(QGraphicsScene):
      global selectedObjType
      def __init__(self, parent=None):
          super(GraphicsSceneClass, self).__init__(parent)
          self.gridOn = 0
          self.setSceneRect(0, 0, 1920, 1080)
          self.setItemIndexMethod(QGraphicsScene.NoIndex)
          self.setBackgroundBrush(QBrush(Qt.black))

      def mousePressEvent(self, event):
              sampleTransform = QTransform()
              objectAtMouse = self.itemAt(event.scenePos(), sampleTransform)

              if objectAtMouse and event.button()== Qt.LeftButton:
                  objectAtMouse.setSelected(True)

              elif objectAtMouse==None and event.button()==Qt.RightButton:
                  # pass
                  self.grid = self.TargPosForLine(event.scenePos(), "ForLine")
              self.grid = self.TargPosForLine(event.scenePos(), "ForLine")
              print(self.grid)

              # else:
              #     self.DeselectItems()

              # objectAtMouse.QShortcut
      def TargPosForLine(self, position, mode):

          clicked_column = int((position.y() // 16)) * 16
          clicked_row = int((position.x() // 16)) * 16
          if clicked_column < 0:
              clicked_column = 0
          if clicked_row < 0:
              clicked_row = 0
          if(mode == "ForRect"):
              return QRect(clicked_row, clicked_column,16,16)
          elif(mode == "ForLine"):
              return QPointF(clicked_row,clicked_column)
      def DeselectItems(self):
          selectedObjects = self.selectedItems()
          for object in selectedObjects:
              object.setSelected(False)
      def mouseReleaseEvent(self, event):
          # self.DeselectItems()
          pass
  class MainWindow(QMainWindow):
      global selectedObjType
      # global item
      def __init__(self,):
          super(MainWindow, self).__init__()
          self.createActions()
          self.createMenus()
          self.createToolbars()

          self.scene = GraphicsSceneClass()
          MainWindow.obj = self.scene
          self.view = QGraphicsView(self.scene)
          # self.view.setDragMode(QGraphicsView.RubberBandDrag)
          self.view.setMouseTracking(True)
          self.view.setRenderHint(QPainter.HighQualityAntialiasing)
          self.widg = QWidget()
          self.horizontalLayout = QHBoxLayout()
          self.horizontalLayout.addWidget(self.view)
          self.widg.setMouseTracking(True)
          self.widget = QWidget()
          self.widget.setLayout(self.horizontalLayout)
          self.setCentralWidget(self.widget)
          self.obj=None
      def createMenus(self):
          menuBar = self.menuBar()
          fileMenu = menuBar.addMenu('&File')
          fileMenu.addAction(self.exitAction)

          fileMenu = menuBar.addMenu('&Edit')
          fileMenu.addAction(self.copyAction)
          fileMenu.addAction(self.pasteAction)
          fileMenu.addAction(self.selectAction)
      def createActions(self):

          self.exitAction = QAction("E&xit", self, shortcut="Ctrl+X", statusTip="Quit Scenediagram example",
                                    triggered=self.deleteItem)
          self.copyAction = QAction("C&opy", self, shortcut="Ctrl+C", triggered=self.copy)

          self.pasteAction = QAction("P&aste", self, shortcut="Ctrl+V", triggered=self.paste)

          self.selectAction = QAction("S&electAll", self, shortcut="Ctrl+A", triggered=self.selectAll)

      def createToolbars(self):
          GridButton = QToolButton()
          GridButton.setCheckable(True)
          GridButton.setIcon(QIcon('images/GridButton.png'))
          GridButton.clicked.connect(self.GridOnOffControl)
          GridButton.setToolTip("Grid Control")
          self.pointerToolbar = self.addToolBar("Pointer type")
          self.pointerToolbar.addWidget(GridButton)

      def deleteItem(self):
          for item in self.scene.selectedItems():
              self.scene.removeItem(item)
      def selectAll(self):

          for item in self.scene.items():
              item.setSelected(True)

      def GridOnOffControl(self):
          if self.scene.gridOn == 0:
              self.scene.gridOn = 1
          else:
              self.scene.gridOn = 0
          if self.scene.gridOn == 1:
              self.scene.setBackgroundBrush(QBrush(QPixmap('images/Grid.png')))
          else:
              self.scene.setBackgroundBrush(QBrush(Qt.black))

      def contextMenuEvent(self, event):
          contextMenu = QMenu(self)

          Cutaction = contextMenu.addAction("Cut")
          Coaction = contextMenu.addAction("Copy")
          Paaction = contextMenu.addAction("Paste")
          Propaction = contextMenu.addAction("draw1")
          Propaction1=contextMenu.addAction("draw2")
          quitAct = contextMenu.addAction("quit")
          action = contextMenu.exec_(self.mapToGlobal(event.pos()))
          if action == quitAct:
              self.close()

          elif action == Propaction:
              objectDrop = None
              # painterPath = QPainterPath()
              #
              # painterPath.moveTo(10, 50.0)
              # painterPath.lineTo(50,50)
              # painterPath.lineTo(50,55)
              # painterPath.lineTo(10,55)
              # gradient = QLinearGradient(1, 1, 1, 5)
              # gradient.setColorAt(0, QColor(Qt.gray))
              # gradient.setColorAt(0.5, QColor(192, 192, 192, 255))
              # gradient.setColorAt(1, QColor(Qt.darkGray))
              # painterPath.closeSubpath()
              #
              # objectDrop = QGraphicsPathItem()
              # objectDrop.setPath(painterPath)
              # objectDrop.setBrush(QBrush(gradient))
              objectDrop = QGraphicsPixmapItem(QPixmap("2AS_HG_RG.png"))
              objectDrop.setPos(self.scene.grid)
              print("sig",self.scene.grid)
              # objectDrop._position = QPointF(gridPos.x() + 2, gridPos.y() + 5.9)
              # objectDrop._type = "2AS_HG_RG"
              objectDrop._type1 = "2AS_HG_RG"
              self.scene.addItem(objectDrop)
              objectDrop.setFlag(QGraphicsItem.ItemIsSelectable)
              objectDrop.setFlag(QGraphicsItem.ItemIsMovable)
              objectDrop._type1="2AS_HG_RG"
              # self.scene.addPath(painterPath)

          elif action==Propaction1:
              objectDrop = None
              selectedObjType = "line"

              objectDrop = sketchBook.SketchBook(selectedObjType)


              print("line",self.scene.grid)
              objectDrop.setFlag(QGraphicsItem.ItemIsSelectable)
              objectDrop.setFlag(QGraphicsItem.ItemIsMovable)
              objectDrop._type1 = "line"
              objectDrop.setPos(self.scene.grid.x(),self.scene.grid.y()-48+5)
              self.scene.addItem(objectDrop)
          elif action == Coaction:
              self.copy()
          elif action == Paaction:
              self.paste()

      @pyqtSlot()
      def copy(self):

          mimedata = QMimeData()
          ba = QByteArray()
          ds = QDataStream(ba, QIODevice.WriteOnly)
          for it in self.scene.selectedItems():
              self.posdiff=item_to_ds(it, ds)
          mimedata.setData(custom_mimeType, ba)
          clipboard = QApplication.clipboard()
          clipboard.setMimeData(mimedata)

      @pyqtSlot()
      def paste(self):

          pos2=self.scene.grid
          clipboard = QApplication.clipboard()
          mimedata = clipboard.mimeData()
          if mimedata.hasFormat(custom_mimeType):
              ba = mimedata.data(custom_mimeType)
              # STR = str(ba)
              # QW = ba.capacity()
              ds = QDataStream(ba)
              while not ds.atEnd():
              # for it in ds:
                  it = ds_to_item(ds)


                  if isinstance(it, QGraphicsPixmapItem):
                      self.scene.addItem(it)
                      it.setPos(pos2)
                      it._position = QPointF(pos2.x() + 2, pos2.y() + 5.9)
                      print("sig",it._position)
                      it._type1 = "2AS_HG_RG"
                  else:
                      gradient = QLinearGradient(1, 1, 1, 5)
                      gradient.setColorAt(0, QColor(Qt.gray))
                      gradient.setColorAt(0.5, QColor(192, 192, 192, 255))
                      gradient.setColorAt(1, QColor(Qt.darkGray))
                      self.scene.addItem(it)
                      it.setBrush(QBrush(gradient))
                      it.setPos(pos2.x()+self.posdiff().x(),pos2.y()-48)
                      it._position = QPointF(pos2.x() + 2, pos2.y() + 5.9)
                      print(it._position)


                      # it.setFlags(QGraphicsItem.ItemIsSelectable)

                      # it._type1 = "line"


      def selectedItem(self):
          items = self.scene.selectedItems()

          if len(items) == 1:
              return items[0]
          return None
  if __name__=="__main__":
      import sys
      app=QApplication(sys.argv)
      mainWindow = MainWindow()

      mainWindow.show()

      sys.exit(app.exec_())

1)选择所有项目或要粘贴的项目

2)复制

3)粘贴

如果我们具有设计模式,则必须使item1紧随其后的是item2,再紧接着是item3,并分别具有距离。当我们复制并粘贴它时,它应该遵循相同的模式。

1 个答案:

答案 0 :(得分:0)

QGraphicsItem.setPos()对于场景(或相对于其父对象)是绝对的,替代解决方案是使用moveBy(x, y)(与setPos(self.pos() + deltaPos)相同,但必须考虑到根据参考点计算点击的相对位置。

我建议您不要设置位置,直到添加完所有项目,然后根据将用作“锚点”的特定项目设置其位置。

    @pyqtSlot()
    def paste(self):
        pos2=self.scene.grid
        clipboard = QApplication.clipboard()
        mimedata = clipboard.mimeData()
        items = []
        topLeft = None
        if mimedata.hasFormat(custom_mimeType):
            ba = mimedata.data(custom_mimeType)
            ds = QDataStream(ba)
            while not ds.atEnd():
                it = ds_to_item(ds)
                items.append(it)
                if not topLeft:
                    topLeft = it
                elif it.y() < topLeft.y() or it.x() < topLeft.x():
                    # find a possible topmost/leftmost item
                    topLeft = it
            # add items, but do not set their position here
            # ...

        delta = self.scene.grid - topLeft.pos()
        [i.moveBy(delta.x(), delta.y()) for i in items]

另一种方法是在复制过程中找到“锚点”,并设置每个项目相对于数据流中该点的位置,以便您可以在添加了moveBy(pos2.x(), pos2.y())之后直接使用项目。