How to drag and overlay QLabel widgets so that the most recently dropped is on top

188 Views Asked by At

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 "cardTableQT.ui" xml:

<?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>

code supplied, as suggested by: @Сергей Кох

1

There are 1 best solutions below

0
Raspberry Pieman On

Thanks to @JonB at https://forum.qt.io/topic/141865 He pointed me to QWidget.raise_() which solved the problem, using it in the def dropEvent