You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5中如何拖拽QLabel并控制堆叠层级,使最新拖拽控件居顶

PyQt5运行时控制控件Z轴层级实现卡牌置顶

在PyQt5中,完全可以通过QWidget类提供的方法控制控件的堆叠顺序,核心方法包括:

  • raise_():将控件置于所有同级控件的顶层
  • lower():将控件置于所有同级控件的底层
  • stackUnder(QWidget *w):将当前控件放到指定控件的下方

针对你的卡牌游戏场景,最合理的做法是在用户点击拖拽卡牌时,自动将该卡牌控件置于顶层,这样拖拽过程中卡牌始终不会被其他卡牌遮挡。

修改后的完整代码

cardTableQT.py

# cardTableQT.py

# imports
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QtGui import QPixmap, QDrag, QPainter
from PyQt5.QtCore import Qt, QMimeData

# classes
class DraggableLabel(QLabel):
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_start_position = event.pos()            
            # 将当前卡牌置于顶层
            self.raise_()
            if len(label_being_dragged) > 0:
                label_being_dragged[0] = self
            else:
                label_being_dragged.append(self)

    def mouseMoveEvent(self, event):
        if not (event.buttons() & Qt.LeftButton):
            return
        if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
            return
        self.setVisible(False)
        drag = QDrag(self)
        mimedata = QMimeData()
        mimedata.setText(self.text())
        drag.setMimeData(mimedata)
        pixmap = QPixmap(self.size())
        painter = QPainter(pixmap)
        painter.drawPixmap(self.rect(), self.grab())
        painter.end()
        drag.setPixmap(pixmap)
        drag.setHotSpot(event.pos())
        drag.exec_(Qt.CopyAction | Qt.MoveAction)        
        if not self.isVisible(): self.setVisible(True) # if dragged off window, make visible again

class cardTableQTGUI(QMainWindow):

    def __init__(self):
        super(cardTableQTGUI, self).__init__()
        uic.loadUi('cardTableQT.ui', self)
        self.setAcceptDrops(True)

        self.setWindowTitle('cardTableQT V1.0')

        green_baise = '#008800' # colour the card table
        self.stackedWidget.setStyleSheet(f"background-color: {green_baise};")

        # this folder contains 52 card images (0.png - 51.png)
        cards_path = 'Y:/Downloads/p/PlayingCards/cards_png_zip/deck/renamed'

        # create a deck of 52 cards
        self.card_labels = []
        for n in range(52):
            self.card_labels.append(DraggableLabel("", self.stackedWidget))
            self.card_labels[-1].setGeometry(10 + n * 22, 10, 66, 100)
            self.card_labels[-1].setScaledContents(True)
            self.card_labels[-1].setPixmap(QPixmap(cards_path + '/' + str(n) + '.png'))

        self.show()

    def dragEnterEvent(self, event):
        if event.mimeData().hasText():
            event.acceptProposedAction()

    def dropEvent(self, event):
        pos = event.pos()
        x = pos.x() - 33 # centre the point on image
        y = pos.y() - 50
        label_dragged = label_being_dragged[0]
        label_dragged.setGeometry(x, y, 66, 100)
        label_dragged.setVisible(True)
        label_being_dragged.pop()
        event.acceptProposedAction()    

# global variables
label_being_dragged = []

# main program gui
app = QApplication([])
gui = cardTableQTGUI()

# start app
app.exec_()

cardTableQT.ui(无需修改)

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>1255</width>
    <height>672</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QStackedWidget" name="stackedWidget">
    <property name="geometry">
     <rect>
      <x>10</x>
      <y>9</y>
      <width>1231</width>
      <height>651</height>
     </rect>
    </property>
    <widget class="QWidget" name="page"/>
    <widget class="QWidget" name="page_2"/>
   </widget>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>

关键修改说明

  1. 在DraggableLabel的mousePressEvent方法中添加self.raise_():用户点击卡牌时,立即将该卡牌控件移到顶层,确保拖拽过程中始终可见。
  2. 优化了卡牌控件的父容器:创建DraggableLabel时指定父控件为self.stackedWidget,避免直接作为主窗口子控件可能导致的层级问题。

原理说明

Qt中,父控件的子控件绘制顺序由它们在父控件子列表中的顺序决定——最后添加的控件会被最后绘制,因此显示在最上层。raise_()方法会将当前控件移动到父控件子列表的末尾,从而实现置顶显示;反之lower()会将控件移到列表开头,显示在底层。

内容的提问来源于stack exchange,提问作者Raspberry Pieman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 05:05:18