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>
关键修改说明
- 在
DraggableLabel的mousePressEvent方法中添加self.raise_():用户点击卡牌时,立即将该卡牌控件移到顶层,确保拖拽过程中始终可见。 - 优化了卡牌控件的父容器:创建
DraggableLabel时指定父控件为self.stackedWidget,避免直接作为主窗口子控件可能导致的层级问题。
原理说明
Qt中,父控件的子控件绘制顺序由它们在父控件子列表中的顺序决定——最后添加的控件会被最后绘制,因此显示在最上层。raise_()方法会将当前控件移动到父控件子列表的末尾,从而实现置顶显示;反之lower()会将控件移到列表开头,显示在底层。
内容的提问来源于stack exchange,提问作者Raspberry Pieman
相关产品推荐
相关产品推荐

