I would like to drag a QListWidgetItem
out of QListWidget
. I'm making a program to create a soccer line up by dragging players (label with pixmap) around. I want to drag players from the "bench" to the "outfield", where the user can drag them freely in a soccer formation:
program on start:
dragging players between the "bench" and the "outfield":
I thought about using labels with pixmap for the "outfield" players, but I'm wondering if it's possible to use QListWidgetItem
out of QListWidget
. Is there a better way to do this?
Code:
import json
import os
import sys
from PyQt5 import QtGui
from PyQt5.Qt import QPixmap
from PyQt5.QtCore import QPoint, Qt, QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QListWidget, QListWidgetItem
class MainWindow(QMainWindow):
def __init__(self, *args, obj=None, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
class MovableLabel(QLabel):
"""WToolBar is a personalized toolbar."""
homeAction = None
oldPos = QPoint()
def __init__(self, mainWindow : MainWindow, filename: str):
super().__init__(mainWindow)
self.mainWindow = mainWindow
self.filename = filename
self.clicked = False
def mousePressEvent(self, evt):
"""Select the toolbar."""
self.oldPos = evt.globalPos()
if not self.clicked:
globalPos = self.mapToGlobal(self.pos())
self.setParent(self.mainWindow)
self.move(self.mapFromGlobal(globalPos))
self.raise_()
self.show()
self.clicked = True
self.grabMouse()
def mouseMoveEvent(self, evt):
"""Move the toolbar with mouse iteration."""
delta = QPoint(evt.globalPos() - self.oldPos)
self.move(self.x() + delta.x(), self.y() + delta.y())
self.oldPos = evt.globalPos()
def mouseReleaseEvent(self, ev: QtGui.QMouseEvent) -> None:
self.releaseMouse()
self.clicked = False
if ev.globalPos().x() < listWidget.width():
if self in self.mainWindow.players:
self.mainWindow.players.remove(self)
if self not in self.mainWindow.players:
self.mainWindow.players.append(self)
self.players = []
pixmap = QPixmap()
class MyItem(QListWidgetItem):
def __init__(self, label : MovableLabel):
super(MyItem, self).__init__()
self.label = label
class MyListWidget(QListWidget):
def __init__(self, mainWindow : MainWindow):
super(MyListWidget, self).__init__(mainWindow)
self.mainWindow = mainWindow
def mouseReleaseEvent(self, e: QtGui.QMouseEvent) -> None:
item = self.selectedItems()[0]
imageSize = item.icon().actualSize(QSize(100, 200))
self.removeItemWidget(item)
label = MovableLabel(self.mainWindow, 'Pogba.jpg')
pixmap = item.icon().pixmap(imageSize)
label.setPixmap(pixmap)
label.setFixedSize(imageSize)
label.move(e.globalPos())
label.show()
listWidget = MyListWidget(self)
listWidget.setViewMode(QListWidget.IconMode)
listWidget.setFixedSize(500, 700)
listWidget.setIconSize(QSize(100, 200))
listWidget.setDragDropMode(listWidget.InternalMove)
'''json file contains positions of "outfield" players'''
try:
with open('players.txt', 'r') as file:
data = json.load(file)
except:
data = []
dir = 'Players/'
for filename in os.listdir(dir):
pixmap = QPixmap(dir + filename).scaledToHeight(100, Qt.SmoothTransformation)
label = MovableLabel(self, filename)
label.setPixmap(pixmap)
label.setFixedSize(pixmap.width(), pixmap.height())
playersIndex = next((i for i, player in enumerate(data) if player['filename'] ==
filename), None)
if playersIndex == None:
item = QListWidgetItem(QIcon(dir + filename), '<Name>', listWidget)
else:
label.setParent(self)
label.move(data[playersIndex]['x'], data[playersIndex]['y'])
self.players.append(label)
self.setStyleSheet("background-color: black;")
self.showMaximized()
def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
with open('players.txt', 'w') as outfile:
json.dump([{'filename': player.filename, 'x': player.x(), 'y': player.y()} for player in self.players],
outfile, indent= 4)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
Edit:
I've tried to implement using label with pixmap when dragging the QListWidgetItem
out the QListWidget
, but the listWidgetItem won't disappear from the listWidget, I can't get the label to align with the item as it were it (I just moved the label to where the cursor is), and I'm unsure how to replace the player to the listWidget. What event is triggered when the item is dragged out the listWidget? Any feedback would be much appreciated.