How to control the z-order of QLabel widgets at run-time?
-
I am using Python and PyQt5.QtWidgets to simulate a card game. I have created a card table using QTdesigner and am dynamically creating QLabel widgets then using QPixmap to set them to one of 52 card images.
I can successfully drag and drop them anywhere on the card table.
However, when I drop them so they overlap each other, the widget which was created later, in time, is always in front of the one created earlier.
I still want to see both widgets even if one is partially overlapping the other.
Is there any way, in PyQt5, to control the z-axis, i.e. so I can decide at run-time which widget is to be on top?
I have included the python code and qtdesigner .ui xml below. I don't know how to include the 52 card images, but they can be simulated by creating simple .png images with a width of 66 and height of 100 pixels.
python code:
# cardTableQT.py # imports from PyQt5.QtWidgets import * from PyQt5 import uic from PyQt5.Qt import QStandardItemModel, QStandardItem 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() 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): global gui super(cardTableQTGUI, self).__init__() uic.loadUi('cardTableQT.ui', self) self.setAcceptDrops(True) gui = self 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)) 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_()
QTdesigner xml file: 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>
-
I am using Python and PyQt5.QtWidgets to simulate a card game. I have created a card table using QTdesigner and am dynamically creating QLabel widgets then using QPixmap to set them to one of 52 card images.
I can successfully drag and drop them anywhere on the card table.
However, when I drop them so they overlap each other, the widget which was created later, in time, is always in front of the one created earlier.
I still want to see both widgets even if one is partially overlapping the other.
Is there any way, in PyQt5, to control the z-axis, i.e. so I can decide at run-time which widget is to be on top?
I have included the python code and qtdesigner .ui xml below. I don't know how to include the 52 card images, but they can be simulated by creating simple .png images with a width of 66 and height of 100 pixels.
python code:
# cardTableQT.py # imports from PyQt5.QtWidgets import * from PyQt5 import uic from PyQt5.Qt import QStandardItemModel, QStandardItem 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() 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): global gui super(cardTableQTGUI, self).__init__() uic.loadUi('cardTableQT.ui', self) self.setAcceptDrops(True) gui = self 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)) 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_()
QTdesigner xml file: 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>
-
@RaspPieman
Look in QWidget forstackUnder()
,raise()
&lower()
.@JonB - Thanks, once I have worked out that, in Python, I must use
.raise_()
instead of.raise()
- it all worked as desired - Thank-you for your response.