Reputation: 23
I am trying to use draggable QLabels for cropping an image. The basic idea of my code is segmenting characters in an image.
So, the user will first upload an image contains three characters to the program.
Then, he will specify the type of the plate, is it short or long by checking on the suitable checkbox. Based on the checkbox, three boxes (QLabels) with specific size will be shown to the user so he can drag each box on a character in the uploaded image. Once the user is finished placing the boxes on the characters, he can click on the Segment
button to apply the cropping operation. The final result will be three images of the cropped characters.
I have done from the program interface and some functionality, However, I'm facing a problem with darg and cropping functions. I have tried different ways with dragging boxes (QLabels) but it's not working with me. I really don't know what's wrong in my code :(. I'm using python 3 and PyQt5.
This is my code:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QLabel, QWidget
from PyQt5.QtGui import QDrag, QPixmap, QPainter, QCursor
from PyQt5.QtCore import QMimeData, Qt
boxes_items = []
#=========================================================================
class DraggableLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
event.accept()
event.acceptProposedAction()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
event.accept()
self.setCursor(QtGui.QCursor(QtCore.Qt.CloseHandCursor))
self.drag_start_position = event.pos()
def mouseMoveEvent(self, event):
if not (event.buttons() & Qt.LeftButton):
return
if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
return
drag = QDrag(self)
'''
mimedata = QMimeData()
#mimedata.setText(self.text())
mimedata.setImageData(self.pixmap().toImage())
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)
'''
class DropLabel(QLabel):
def __init__(self, *args, **kwargs):
QLabel.__init__(self, *args, **kwargs)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasText():
event.acceptProposedAction()
def dropEvent(self, event):
pos = event.pos()
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
# text = event.mimeData().text()
# self.setText(text)
event.acceptProposedAction()
'''
#==========================================================================
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setEnabled(True)
Dialog.resize(1050, 800)
Dialog.setMinimumSize(QtCore.QSize(1050, 800))
Dialog.setMaximumSize(QtCore.QSize(1050, 800))
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("../.designer/backup/project pic/images LPR icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
Dialog.setWindowIcon(icon)
Dialog.setStyleSheet("background-color: rgb(217, 217, 217);\n"
"background-color: rgb(243, 243, 243);")
# Dialog.setAcceptDrops(True)
self.BrowesImageButton = QtWidgets.QPushButton(Dialog)
self.BrowesImageButton.setGeometry(QtCore.QRect(820, 60, 200, 60))
self.BrowesImageButton.setMinimumSize(QtCore.QSize(200, 60))
self.BrowesImageButton.setMaximumSize(QtCore.QSize(200, 60))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei UI")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.BrowesImageButton.setFont(font)
self.BrowesImageButton.setStyleSheet("")
self.BrowesImageButton.setCheckable(True)
self.BrowesImageButton.setObjectName("BrowesImageButton")
self.groupBox = QtWidgets.QGroupBox(Dialog)
self.groupBox.setGeometry(QtCore.QRect(820, 170, 211, 131))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.groupBox.setFont(font)
self.groupBox.setLayoutDirection(QtCore.Qt.LeftToRight)
self.groupBox.setObjectName("groupBox")
self.checkBox_Short = QtWidgets.QCheckBox(self.groupBox)
self.checkBox_Short.setGeometry(QtCore.QRect(20, 40, 141, 23))
font = QtGui.QFont()
font.setFamily("Adobe Heiti Std R")
font.setPointSize(10)
self.checkBox_Short.setFont(font)
self.checkBox_Short.setLayoutDirection(QtCore.Qt.LeftToRight)
self.checkBox_Short.setObjectName("checkBox_Short")
self.checkBox_Short.setEnabled(False)
self.checkBox_Long = QtWidgets.QCheckBox(self.groupBox)
self.checkBox_Long.setGeometry(QtCore.QRect(20, 80, 141, 23))
font = QtGui.QFont()
font.setFamily("Adobe Heiti Std R")
font.setPointSize(10)
self.checkBox_Long.setFont(font)
self.checkBox_Long.setLayoutDirection(QtCore.Qt.LeftToRight)
self.checkBox_Long.setObjectName("checkBox_Long")
self.checkBox_Long.setEnabled(False)
self.SegmentImageButton = QtWidgets.QPushButton(Dialog)
self.SegmentImageButton.setGeometry(QtCore.QRect(830, 330, 200, 60))
self.SegmentImageButton.setMinimumSize(QtCore.QSize(200, 60))
self.SegmentImageButton.setMaximumSize(QtCore.QSize(200, 60))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei UI")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.SegmentImageButton.setFont(font)
self.SegmentImageButton.setStyleSheet("")
self.SegmentImageButton.setCheckable(True)
self.SegmentImageButton.setObjectName("SegmentImageButton")
self.SegmentImageButton.setEnabled(False)
self.label = QtWidgets.QLabel(Dialog)
self.label.setGeometry(QtCore.QRect(980, 470, 45, 45))
self.label.setMinimumSize(QtCore.QSize(45, 45))
self.label.setMaximumSize(QtCore.QSize(45, 45))
self.label.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
self.label.setMouseTracking(True)
self.label.setAcceptDrops(True)
self.label.setStyleSheet("border-color: rgb(238, 0, 0); border-width : 2.0px; border-style:inset;")
self.label.setFrameShape(QtWidgets.QFrame.Box)
self.label.setLineWidth(2)
self.label.setText("")
self.label.setObjectName("label")
self.label.hide()
'''
self.graphicsView = QtWidgets.QGraphicsView(Dialog)
self.graphicsView.setGeometry(QtCore.QRect(40, 40, 750, 500))
self.graphicsView.setMinimumSize(QtCore.QSize(750, 500))
self.graphicsView.setMaximumSize(QtCore.QSize(750, 500))
self.graphicsView.setObjectName("graphicsView")
'''
self.UserImageLbl = QtWidgets.QLabel(Dialog)
self.UserImageLbl.setGeometry(QtCore.QRect(40, 40, 750, 500))
self.UserImageLbl.setMinimumSize(QtCore.QSize(750, 500))
self.UserImageLbl.setMaximumSize(QtCore.QSize(750, 500))
self.UserImageLbl.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.UserImageLbl.setFrameShadow(QtWidgets.QFrame.Plain)
self.UserImageLbl.setLineWidth(1)
self.UserImageLbl.setMidLineWidth(0)
self.UserImageLbl.setText("")
self.UserImageLbl.setScaledContents(False)
self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter)
self.UserImageLbl.setObjectName("UserImageLbl")
self.label_2 = QtWidgets.QLabel(Dialog)
self.label_2.setGeometry(QtCore.QRect(900, 470, 45, 45))
self.label_2.setMinimumSize(QtCore.QSize(45, 45))
self.label_2.setMaximumSize(QtCore.QSize(45, 45))
self.label_2.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
self.label_2.setMouseTracking(True)
self.label_2.setAcceptDrops(True)
self.label_2.setStyleSheet("border-color: rgb(238, 0, 0); border-width : 2.0px; border-style:inset;")
self.label_2.setFrameShape(QtWidgets.QFrame.Box)
self.label_2.setLineWidth(2)
self.label_2.setText("")
self.label_2.setObjectName("label_2")
self.label_2.hide()
self.label_3 = QtWidgets.QLabel(Dialog)
self.label_3.setGeometry(QtCore.QRect(820, 470, 45, 45))
self.label_3.setMinimumSize(QtCore.QSize(45, 45))
self.label_3.setMaximumSize(QtCore.QSize(45, 45))
self.label_3.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
self.label_3.setMouseTracking(True)
self.label_3.setAcceptDrops(True)
self.label_3.setStyleSheet("border-color: rgb(238, 0, 0); border-width : 2.0px; border-style:inset;")
self.label_3.setFrameShape(QtWidgets.QFrame.Box)
self.label_3.setLineWidth(2)
self.label_3.setText("")
self.label_3.setObjectName("label_3")
self.label_3.hide()
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
#Add labels in boxes items list
boxes_items.append(self.label)
boxes_items.append(self.label_2)
boxes_items.append(self.label_3)
#=================================== Calling =======================
self.BrowesImageButton.clicked.connect(self.setImage)
self.checkBox_Short.stateChanged.connect(self.Change_the_Checkbox_Short_Function)
self.checkBox_Long.stateChanged.connect(self.Change_the_Checkbox_Long_Function)
#=================================== Functions =========================
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Cropping"))
self.BrowesImageButton.setText(_translate("Dialog", "Select Image"))
self.groupBox.setTitle(_translate("Dialog", "Choose Plate Type"))
self.checkBox_Short.setText(_translate("Dialog", "Short Plate"))
self.checkBox_Long.setText(_translate("Dialog", "Long Plate"))
self.SegmentImageButton.setText(_translate("Dialog", "Segment Image"))
self.label.setToolTip(_translate("Dialog", "Drage it on first charecter"))
self.label_2.setToolTip(_translate("Dialog", "Drage it on second charecter"))
self.label_3.setToolTip(_translate("Dialog", "Drage it on third charecter"))
#=================================================================================
def setImage(self):
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Select Image", "", "Image Files (*.png *.jpg *jpeg *.bmp)") # Ask for file
if fileName: # If the user gives a file
pixmap = QtGui.QPixmap(fileName) # Setup pixmap with the provided image
pixmap = pixmap.scaled(self.UserImageLbl.width(), self.UserImageLbl.height(), QtCore.Qt.KeepAspectRatio) # Scale pixmap
self.UserImageLbl.setPixmap(pixmap) # Set the pixmap onto the label
self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter) # Align the label to center
#UserImageLbl = DropLabel()
self.checkBox_Short.setEnabled(True)
self.checkBox_Long.setEnabled(True)
#=====================================================================
def Change_the_Checkbox_Short_Function(self):
if self.checkBox_Short.isChecked():
self.checkBox_Long.setEnabled(False)
self.SegmentImageButton.setEnabled(True)
# Presenting 3 boxes 45x45 hear
for box_item in boxes_items:
#box_item.setDragEnabled(True)
box_item.setMinimumSize(QtCore.QSize(45, 45))
box_item.setMaximumSize(QtCore.QSize(45, 45))
box_item.show()
box_item = DraggableLabel()
else:
self.checkBox_Long.setEnabled(True)
for box_item in boxes_items:
box_item.hide()
#========================================================================
def Change_the_Checkbox_Long_Function(self):
if self.checkBox_Long.isChecked():
self.checkBox_Short.setEnabled(False)
self.SegmentImageButton.setEnabled(True)
# Presenting 3 boxes 40x40 hear
for box_item in boxes_items:
# box_item.setDragEnabled(True)
box_item.setMinimumSize(QtCore.QSize(40, 40))
box_item.setMaximumSize(QtCore.QSize(40, 40))
box_item.show()
box_item = DraggableLabel()
#for box_item in Sboxes_items:
#DraggableLabel(box_item)
else:
self.checkBox_Short.setEnabled(True)
for box_item in boxes_items:
box_item.hide()
#==========================================================================
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
I hope I can find someone who can help me with that. Thanks in advance.
Upvotes: 1
Views: 544
Reputation: 48384
I believe you are a bit confused about how drag and drop works, but the most important thing is that you don't need "actual" drag and drop for what you want to achieve.
In this example I added the draggable boxes instead of the labels, and they are free to be moved within the image rectangle. I had to do some modifications to your original code, because it was a bit confusing and had some logic that simply didn't work.
class DraggableLabel(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setStyleSheet("border-color: rgb(238, 0, 0); border-width : 2.0px; border-style:inset; background: transparent;")
self.origin = None
def setLimits(self, rect):
self.limits = rect
def mousePressEvent(self, event):
if not self.origin:
# update the origin point, we'll need that later
self.origin = self.pos()
if event.button() == Qt.LeftButton:
self.mousePos = event.pos()
def mouseMoveEvent(self, event):
if event.buttons() == Qt.LeftButton:
# move the box
self.move(self.pos() + event.pos() - self.mousePos)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
# if the box is not within the image boundaries, move it
# back to the original position
if not self.limits.contains(self.geometry()):
self.move(self.origin)
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setEnabled(True)
Dialog.resize(1050, 800)
Dialog.setMinimumSize(QtCore.QSize(1050, 800))
Dialog.setMaximumSize(QtCore.QSize(1050, 800))
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap("../.designer/backup/project pic/images LPR icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
Dialog.setWindowIcon(icon)
Dialog.setStyleSheet("background-color: rgb(217, 217, 217);\n"
"background-color: rgb(243, 243, 243);")
# Dialog.setAcceptDrops(True)
self.BrowesImageButton = QtWidgets.QPushButton(Dialog)
self.BrowesImageButton.setGeometry(QtCore.QRect(820, 60, 200, 60))
self.BrowesImageButton.setMinimumSize(QtCore.QSize(200, 60))
self.BrowesImageButton.setMaximumSize(QtCore.QSize(200, 60))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei UI")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.BrowesImageButton.setFont(font)
self.BrowesImageButton.setStyleSheet("")
self.BrowesImageButton.setCheckable(True)
self.BrowesImageButton.setObjectName("BrowesImageButton")
self.groupBox = QtWidgets.QGroupBox(Dialog)
self.groupBox.setGeometry(QtCore.QRect(820, 170, 211, 131))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei")
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.groupBox.setFont(font)
self.groupBox.setLayoutDirection(QtCore.Qt.LeftToRight)
self.groupBox.setObjectName("groupBox")
self.checkBox_Short = QtWidgets.QCheckBox(self.groupBox)
self.checkBox_Short.setGeometry(QtCore.QRect(20, 40, 141, 23))
font = QtGui.QFont()
font.setFamily("Adobe Heiti Std R")
font.setPointSize(10)
self.checkBox_Short.setFont(font)
self.checkBox_Short.setLayoutDirection(QtCore.Qt.LeftToRight)
self.checkBox_Short.setObjectName("checkBox_Short")
self.checkBox_Short.setEnabled(False)
self.checkBox_Long = QtWidgets.QCheckBox(self.groupBox)
self.checkBox_Long.setGeometry(QtCore.QRect(20, 80, 141, 23))
font = QtGui.QFont()
font.setFamily("Adobe Heiti Std R")
font.setPointSize(10)
self.checkBox_Long.setFont(font)
self.checkBox_Long.setLayoutDirection(QtCore.Qt.LeftToRight)
self.checkBox_Long.setObjectName("checkBox_Long")
self.checkBox_Long.setEnabled(False)
self.SegmentImageButton = QtWidgets.QPushButton(Dialog)
self.SegmentImageButton.setGeometry(QtCore.QRect(830, 330, 200, 60))
self.SegmentImageButton.setMinimumSize(QtCore.QSize(200, 60))
self.SegmentImageButton.setMaximumSize(QtCore.QSize(200, 60))
font = QtGui.QFont()
font.setFamily("Microsoft YaHei UI")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.SegmentImageButton.setFont(font)
self.SegmentImageButton.setStyleSheet("")
self.SegmentImageButton.setCheckable(True)
self.SegmentImageButton.setObjectName("SegmentImageButton")
self.SegmentImageButton.setEnabled(False)
self.UserImageLbl = QtWidgets.QLabel(Dialog)
self.UserImageLbl.setGeometry(QtCore.QRect(40, 40, 750, 500))
self.UserImageLbl.setMinimumSize(QtCore.QSize(750, 500))
self.UserImageLbl.setMaximumSize(QtCore.QSize(750, 500))
self.UserImageLbl.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.UserImageLbl.setFrameShadow(QtWidgets.QFrame.Plain)
self.UserImageLbl.setLineWidth(1)
self.UserImageLbl.setMidLineWidth(0)
self.UserImageLbl.setText("")
self.UserImageLbl.setScaledContents(False)
self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter)
self.UserImageLbl.setObjectName("UserImageLbl")
self.buttonGroup = QButtonGroup()
self.buttonGroup.addButton(self.checkBox_Short)
self.buttonGroup.addButton(self.checkBox_Long)
self.label_1 = DraggableLabel(Dialog)
self.label_2 = DraggableLabel(Dialog)
self.label_3 = DraggableLabel(Dialog)
self.label_1.move(820, 470)
self.label_2.move(900, 470)
self.label_3.move(980, 470)
self.labels = [self.label_1, self.label_2, self.label_3]
for label in self.labels:
label.hide()
label.raise_()
self.BrowesImageButton.clicked.connect(self.setImage)
self.checkBox_Long.toggled.connect(self.setBoxSizes)
self.checkBox_Short.toggled.connect(self.setBoxSizes)
def setImage(self):
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(None, "Select Image", "", "Image Files (*.png *.jpg *jpeg *.bmp)") # Ask for file
if fileName: # If the user gives a file
pixmap = QtGui.QPixmap(fileName) # Setup pixmap with the provided image
pixmap = pixmap.scaled(self.UserImageLbl.width(), self.UserImageLbl.height(), QtCore.Qt.KeepAspectRatio) # Scale pixmap
self.UserImageLbl.setPixmap(pixmap) # Set the pixmap onto the label
self.UserImageLbl.setAlignment(QtCore.Qt.AlignCenter) # Align the label to center
#UserImageLbl = DropLabel()
self.checkBox_Short.setEnabled(True)
self.checkBox_Long.setEnabled(True)
def setBoxSizes(self):
if self.checkBox_Short.isChecked():
boxSize = 40
else:
boxSize = 45
for label in self.labels:
label.setFixedSize(boxSize, boxSize)
label.setLimits(self.UserImageLbl.geometry())
label.show()
Upvotes: 1