PyQt - перетаскивание в разные виджеты QLabel - PullRequest
0 голосов
/ 05 декабря 2018

Я использую Windows, Python 3.6, OpenCV3 и PyQt5.У меня есть главное окно с двумя виджетами QLabel (label1 и label2).Я хочу перетаскивать разные видеофайлы в оба виджета 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_())

1 Ответ

0 голосов
/ 06 декабря 2018

Документация указывает, что underMouse() может завершиться ошибкой в ​​процессе перетаскивания:

bool 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_())
...