4.0版本在3.0版本基础上增加了双击某个位置时,如果这个位置在标注框内,则对选中的标注框进行标识出来,同时提示是否要删除当前选中的标注框,进行删除处理。
在这个版本中首先需要增加双击事件,在双击事件中对当前鼠标位置是否属于某个标注框进行遍历,某个位置可能属于多标注框时,则按照先入后出的原则,进行删除。
在绘制事件中主要是对当前位置所在的标注框进行区分显示。
其他代码基本未变。
一、修改MyLabel代码
增加鼠标双击事件
修改paintevent事件
代码语言:javascript复制
代码语言:javascript复制from PyQt5.QtWidgets import QWidget, QApplication, QLabel, QMessageBox
from PyQt5.QtCore import QRect, Qt
from PyQt5.QtGui import QPixmap, QPainter, QPen
from ui_labelchoose import DialogChoooseLabelWin
import sys
# 重定义QLabel,实现绘制事件和各类鼠标事件
class MyLabel(QLabel):
def __init__(self, parent=None):
'''
:param parent:
初始化基本参数
'''
super(MyLabel, self).__init__(parent)
self.x0 = 0
self.y0 = 0
self.x1 = 0
self.y1 = 0
self.x1RealTime = 0
self.y1RealTime = 0
self.rect = QRect()
self.flag = False
# 增加一个存储标注框坐标的列表
self.bboxList = []
self.labelindex = 0
self.curChoosedbbox = []
self.curbboxindex = -1
self.deleteboxflag = False
# 鼠标双击事件,选中当前坐标的被标注框
# 如存在在多个被标注框内,则显示最新标注的那个
# 再询问是否要删除标注框
# 如果确定要删除,则删除当前坐标所在的标注框
def mouseDoubleClickEvent(self, event):
x = event.pos().x()
y = event.pos().y()
self.curChoosedbbox = []
# 如果尚未做标注框,则不处理
if self.bboxList == []:
return
else:
# 以此判断当前双击坐标出现在哪个标注框中,最后标注的优先删除
tempbboxlist = self.bboxList
for index, bbox in enumerate(tempbboxlist):
# 判断坐标是否在标注框中
if bbox[0] <= x <= bbox[2] and bbox[1] <= y <= bbox[3]:
# 如果在的话,记录当前选中的标注框和list中的索引号
self.curChoosedbbox = bbox
self.curbboxindex = index
# 第一次绘制,高亮显示被选中的标注框
self.update()
# 判断是否已有选中的标注框
if self.curChoosedbbox != []:
reply = QMessageBox.question(self, "警告!", "是否要删除当前选中的标注框",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
QMessageBox.StandardButton.Yes)
if reply == QMessageBox.Yes:
self.deleteboxflag = True
self.bboxList.pop(self.curbboxindex)
self.update()
else:
return
# 单击鼠标触发事件
# 获取鼠标事件的开始位置
def mousePressEvent(self, event):
# 将绘制标志设置为True
self.flag = True
self.deleteboxflag = False
# 重新开始点击事件后,取消已选中的标注框
self.curChoosedbbox = []
self.x0 = event.pos().x()
self.y0 = event.pos().y()
# 鼠标移动事件
# 绘制鼠标行进过程中的矩形框
def mouseMoveEvent(self, event):
if self.flag:
self.x1RealTime = event.pos().x()
self.y1RealTime = event.pos().y()
self.update()
# 鼠标释放事件
def mouseReleaseEvent(self, event):
# 将绘制标志设置为False
self.flag = False
self.x1 = event.pos().x()
self.y1 = event.pos().y()
# 这样就不用画出实时框了
self.x1RealTime = self.x0
self.y1RealTime = self.y0
# 修正单击鼠标的保存事件bug,当开始坐标等于结束坐标时,或者为一条直线时,均不响应
if self.x0 == self.x1 or self.y0 == self.y1:
return
# 将标注框的四个坐标轴存储到bboxList
dialogChooseLabel = DialogChoooseLabelWin()
if dialogChooseLabel.exec_():
labelname = dialogChooseLabel.getValue()
self.saveBBbox(self.x0, self.y0, self.x1, self.y1, labelname)
event.ignore()
# 绘制事件
def paintEvent(self, event):
super().paintEvent(event)
painter = QPainter()
# 增加绘制开始和结束时间
painter.begin(self)
# 遍历之前存储的标注框坐标列表
for point in self.bboxList:
rect = QRect(point[0], point[1], abs(point[0] - point[2]), abs(point[1] - point[3]))
painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))
painter.drawRect(rect)
painter.drawText(point[0], point[1], point[4])
# 绘制当前标注框的举行
# 构造矩形框的起始坐标和宽度、高度
tempx0 = min(self.x0, self.x1RealTime)
tempy0 = min(self.y0, self.y1RealTime)
tempx1 = max(self.x0, self.x1RealTime)
tempy1 = max(self.y0, self.y1RealTime)
width = tempx1 - tempx0
height = tempy1 - tempy0
currect = QRect(tempx0, tempy0, width, height)
# 构造QPainter,进行矩形框绘制
painter.setPen(QPen(Qt.blue, 1, Qt.SolidLine))
painter.drawRect(currect)
# 判断是否有当前选中窗口,如果有,且未被删除,则高亮显示
if self.curChoosedbbox != []:
# 如果当前不是删除标志,则高亮显示
# 否则就不再绘制该标注框
if self.deleteboxflag == False:
point = self.curChoosedbbox
rect = QRect(point[0], point[1], abs(point[0] - point[2]), abs(point[1] - point[3]))
painter.setPen(QPen(Qt.green, 4, Qt.SolidLine))
painter.drawRect(rect)
painter.drawText(point[0], point[1], point[4])
painter.end()
# 保存到bbox列表
def saveBBbox(self, x0, y0, x1, y1, labelname):
tempx0 = min(x0, x1)
tempy0 = min(y0, y1)
tempx1 = max(x0, x1)
tempy1 = max(y0, y1)
bbox = (tempx0, tempy0, tempx1, tempy1, labelname, self.labelindex)
self.bboxList.append(bbox)
self.labelindex = 1
二、窗口类和main函数未做调整
代码语言:javascript复制# 窗口类
class LabelV1(QWidget):
def __init__(self):
super(LabelV1, self).__init__()
self.initUI()
def initUI(self):
self.resize(960, 540)
self.move(100, 50)
self.setWindowTitle('Label标注框4.0版本')
# 加载重定义的label
self.lbl = MyLabel(self)
# 构造QPixmap,加载待标注图片
img = QPixmap('010.png')
# 在自定义label中显示QImage
self.lbl.setPixmap(img)
self.lbl.setCursor(Qt.CrossCursor)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
labelwin = LabelV1()
sys.exit(app.exec())