PySide2

界面布局 Layout

QHBoxLayout 水平布局

from PySide2 import QtWidgets


class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        button1 = QtWidgets.QPushButton('按钮1', self)
        button2 = QtWidgets.QPushButton('按钮2', self)
        button3 = QtWidgets.QPushButton('按钮3', self)

        # 创建layout对象,并且添加内部控件
        hl = QtWidgets.QHBoxLayout()
        hl.addWidget(button1)
        hl.addWidget(button2)
        hl.addWidget(button3)

        # 指定容器控件自身使用的layout
        self.setLayout(hl)


app = QtWidgets.QApplication()
window = Window()
window.resize(400, 200)
window.show()
app.exec_()

image-1696987765761

        # 剩余空间弹性布局
        hl.addStretch()

image-1696987815273

QVBoxLayout 垂直布局

from PySide2 import QtWidgets


class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        button1 = QtWidgets.QPushButton('按钮1', self)
        button2 = QtWidgets.QPushButton('按钮2', self)
        button3 = QtWidgets.QPushButton('按钮3', self)

        # 创建layout对象,并且添加内部控件
        vl = QtWidgets.QVBoxLayout()
        vl.addWidget(button1)
        vl.addWidget(button2)
        vl.addWidget(button3)
        vl.addStretch()

        # 指定容器控件自身使用的layout
        self.setLayout(vl)


app = QtWidgets.QApplication()
window = Window()
window.resize(400, 200)
window.show()
app.exec_()

image-1696987903764

QGridLayout 表格布局

from PySide2 import QtWidgets


class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        button1 = QtWidgets.QPushButton('按钮1', self)
        button2 = QtWidgets.QPushButton('按钮2', self)
        button3 = QtWidgets.QPushButton('按钮3', self)

        # 创建一个水平layout作为内部layout
        gl = QtWidgets.QGridLayout()
        gl.addWidget(button1, 0, 0)  # 添加到第1行,第1列
        gl.addWidget(button2, 0, 1)  # 添加到第1行,第2列
        gl.addWidget(button3, 1, 1)  # 添加到第2行,第2列

        # 指定自身使用的layout
        self.setLayout(gl)


app = QtWidgets.QApplication([])
window = Window()
window.resize(400, 200)
window.show()
app.exec_()

image-1696988106406

QFormLayout 表单布局

from PySide2 import QtWidgets


class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        fl = QtWidgets.QFormLayout()
        fl.addRow(QtWidgets.QLabel("Label 1"), QtWidgets.QLineEdit())
        fl.addRow(QtWidgets.QLabel("Label 2"), QtWidgets.QLineEdit())
        fl.addRow(QtWidgets.QLabel("Label 3"), QtWidgets.QLineEdit())
        # 指定自身使用的layout
        self.setLayout(fl)


app = QtWidgets.QApplication([])
window = Window()
window.resize(400, 200)
window.show()
app.exec_()

image-1696988289900

Graphic View

简单示例

  • QGraphicsScene 画布
  • QGraphicsView 展示层
  • QGraphicsItem 元素, 控制层
from PySide2 import QtWidgets, QtGui

app = QtWidgets.QApplication()

# 创建 QGraphicsScene 对象, 设置位置和高度宽度
scene = QtWidgets.QGraphicsScene(0, 0, 400, 400)
# 设置背景色
scene.setBackgroundBrush(QtGui.QColor('#C1E9F5'))

# 创建 QGraphicsView 对象
view = QtWidgets.QGraphicsView(scene)

# 创建矩形对象
rect = QtWidgets.QGraphicsRectItem(10, 10, 200, 50)

# 添加到 QGraphicsScene 中
scene.addItem(rect)

# 允许移动
rect.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)

view.show()
app.exec_()

20231010223116

两侧布局并支持拖拽

from PySide2 import QtWidgets, QtGui, QtCore

PIC_LIST = ["1", "2", "3"]

WIDTH, HEIGHT = 1000, 800


class DraggableLabel(QtWidgets.QLabel):
  def __init__(self, parent=None, image_path=None):
    super(DraggableLabel, self).__init__(parent)
    # 加载图片
    pixmap = QtGui.QPixmap(image_path)
    # 设定图片缩放大小, 高度等比缩放
    pixmap = pixmap.scaledToWidth(40, QtCore.Qt.SmoothTransformation)
    # 设置label的图片
    self.setPixmap(pixmap)
    self.setAcceptDrops(True)  # 设置可接受拖拽

  def mousePressEvent(self, event):
    if event.button() == QtCore.Qt.LeftButton:
      # 创建拖拽对象
      drag = QtGui.QDrag(self)
      mime_data = QtCore.QMimeData()
      mime_data.setImageData(self.pixmap().toImage())  # 设置拖拽的图片数据
      drag.setMimeData(mime_data)
      drag.exec_(QtCore.Qt.CopyAction)


class MyGraphicsView(QtWidgets.QGraphicsView):
  def __init__(self, parent=None):
    super(MyGraphicsView, self).__init__(parent)
    self.setAcceptDrops(True)  # 设置可接受拖拽
    scene = QtWidgets.QGraphicsScene(0, 0, int(WIDTH * 0.8), int(HEIGHT * 0.8))
    self.setScene(scene)

  def __drag(self, action, event):
    if event.mimeData().hasImage():
      if action == "drop":
        # 在GraphicsView中显示拖拽的图片
        image = event.mimeData().imageData()
        pixmap = QtGui.QPixmap.fromImage(image)
        item = self.scene().addPixmap(pixmap)
        # 将坐标转换为场景坐标
        scene_pos = self.mapToScene(event.pos())
        item.setPos(scene_pos)
      event.accept()
    else:
      event.ignore()

  def dragEnterEvent(self, event):
    self.__drag("enter", event)

  def dragMoveEvent(self, event):
    self.__drag("move", event)

  def dropEvent(self, event):
    self.__drag("drop", event)


class MWindow(QtWidgets.QMainWindow):
  def __init__(self):
    super().__init__()
    self.resize(WIDTH, HEIGHT)
    centralWidget = QtWidgets.QWidget(self)
    self.setCentralWidget(centralWidget)
    # 设置水平布局
    self.mainLayout = QtWidgets.QHBoxLayout(centralWidget)
    self.setupLeftPane()  # 左边区域
    self.setupCanvas()  # 右边区域

  def setupLeftPane(self):
    gl = QtWidgets.QGridLayout()
    for index, name in enumerate(PIC_LIST):
      row, col = int(index / 2), index % 2
      label = DraggableLabel(image_path=f"./images/{name}.png")
      gl.addWidget(label, row, col)
    # 添加左侧的布局到主布局
    leftLayout = QtWidgets.QVBoxLayout()
    leftLayout.addLayout(gl)
    leftLayout.addStretch()
    self.mainLayout.addLayout(leftLayout)

  def setupCanvas(self):
    self.view = MyGraphicsView()
    # 添加绘制组件到主布局
    self.mainLayout.addWidget(self.view)


def main():
  app = QtWidgets.QApplication()
  # 对于显示器使用缩放图片的, 加上这一句使得图片不毛糙
  app.setHighDpiScaleFactorRoundingPolicy(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.Round)
  window = MWindow()
  window.show()
  app.exec_()


if __name__ == '__main__':
  main()

20231011000641