我正在使用Windows,Python 3.6,OpenCV3和PyQt5。我有一个包含两个QLabel小部件(label1label2)的主窗口。我想将不同的视频文件拖放到两个QLabel小部件中。我的脚本显示了两个视频文件中每个视频的第一帧。


如果我将文件通过label1拖到label2中,然后释放
鼠标,则第一个视频帧显示在label1中(不是
我想要)。
如果我将label1周围的文件拖入label2,然后释放
鼠标,则第一个视频帧显示在label2中(要求
影响)。
如果我将文件通过label2拖到label1中,然后释放
鼠标,则第一个视频帧显示在label1中(要求
影响)。


我想在label2中显示视频,无论我拖动文件还是通过label1。有什么建议吗?

import sys, cv2
from PyQt5.QtWidgets import QApplication, QLabel, QFrame, QMainWindow
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import Qt

class Example(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):

        self.setGeometry(200, 300, 800, 600)
        self.setAcceptDrops(True)
        self.setMouseTracking(True)

        self.label1 = QLabel(self)
        self.label1.move(10, 10)
        self.label1.resize(780, 280)
        self.label1.setFrameShape(QFrame.Box)
        self.label1.setAcceptDrops(True)

        self.label2 = QLabel(self)
        self.label2.move(10, 310)
        self.label2.resize(780, 280)
        self.label2.setFrameShape(QFrame.Box)
        self.label2.setAcceptDrops(True)

        self.label1.setText("Label 1")
        self.label2.setText("Label 2")
        self.show()

    def dragEnterEvent(self, e):
        if e.mimeData().hasUrls:
            e.accept()
        else:
            e.ignore()

    def dropEvent(self, e):
        if e.mimeData().hasUrls:
            e.accept()
            for url in e.mimeData().urls():
                if self.label1.underMouse():
                    fname = str(url.toLocalFile())
                    self.openFile1(fname)
                elif self.label2.underMouse():
                    fname = str(url.toLocalFile())
                    self.openFile2(fname)
        else:
            e.ignore()

    def openFile1(self, filename):
        self.cap1 = cv2.VideoCapture(str(filename))
        self.cap1.set(cv2.CAP_PROP_POS_FRAMES, 0)
        width = self.cap1.get(cv2.CAP_PROP_FRAME_WIDTH)
        height = self.cap1.get(cv2.CAP_PROP_FRAME_HEIGHT)
        ret, frame = self.cap1.read()
        if ret == True:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img = QImage(frame, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
            pix = QPixmap.fromImage(img)
            pix = self.scalePix(self.label1, pix, width, height)
            self.label1.setPixmap(pix)

    def openFile2(self, filename):
        self.cap2 = cv2.VideoCapture(str(filename))
        self.cap2.set(cv2.CAP_PROP_POS_FRAMES, 0)
        width = self.cap2.get(cv2.CAP_PROP_FRAME_WIDTH)
        height = self.cap2.get(cv2.CAP_PROP_FRAME_HEIGHT)
        ret, frame = self.cap2.read()
        if ret == True:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img = QImage(frame, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
            pix = QPixmap.fromImage(img)
            pix = self.scalePix(self.label1, pix, width, height)
            self.label2.setPixmap(pix)

    def scalePix(self, label, p, width, height):
        window_width = label.width()
        ratio = height / width
        window_height = int(ratio * window_width)
        window_height = label.height()
        window_width = int(1 / ratio * window_height)
        p = p.scaledToWidth(window_width, Qt.SmoothTransformation)
        p = p.scaledToHeight(window_height, Qt.SmoothTransformation)
        return p

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

最佳答案

文档表明underMouse()在拖放过程中可能会失败:


  布尔QWidget :: underMouse()const
  
  如果小部件位于鼠标光标下方,则返回true;除此以外
  返回false。
  
  在拖放操作期间,此值未正确更新。


因此最好不要使用,相反,我们可以创建一个实现拖放的自定义QLabel:

import sys, cv2
from PyQt5 import QtCore, QtGui, QtWidgets

class OpenCVLabel(QtWidgets.QLabel):
    def __init__(self, *args, **kwargs):
        super(OpenCVLabel, self).__init__(*args, **kwargs)
        self.setFrameShape(QtWidgets.QFrame.Box)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, e):
        if e.mimeData().hasUrls():
            e.accept()
        else:
            e.ignore()

    def dropEvent(self, e):
        if e.mimeData().hasUrls():
            e.accept()
            for url in e.mimeData().urls():
                self.openFile(url.toLocalFile())
        else:
            e.ignore()

    def openFile(self, filename):
        cap = cv2.VideoCapture(str(filename))
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
        width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        ret, frame = cap.read()
        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img = QtGui.QImage(frame, frame.shape[1], frame.shape[0], QtGui.QImage.Format_RGB888)
            pix = QtGui.QPixmap.fromImage(img)
            pix = pix.scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
            self.setPixmap(pix)

class Example(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        label1 = OpenCVLabel("label1")
        label2 = OpenCVLabel("label2")
        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.addWidget(label1)
        lay.addWidget(label2)
        self.resize(780, 560)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

关于python - PyQt-拖放到不同的QLabel小部件中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53639933/

10-12 16:36