pyqt / python-qt5

Unofficial PyQt5 via PyPI for Python 2.7 64-bit on Windows
GNU General Public License v3.0
280 stars 77 forks source link

PyQt5 shows white border while displaying image in full screen #81

Open ammar3010 opened 1 week ago

ammar3010 commented 1 week ago

I'm using PyQt5 to build a UI for my computer vision app. The app has six pages, and on the fourth page, I receive video frames from a backend thread that runs when the app reaches this page. However, I'm having trouble getting the QLabel on the fourth page to resize correctly and display the video frames in full screen.

Here is the code snippet that sends frames to the frontend:

qImg = QImage(combined_frame2.data, combined_frame2.shape[1], combined_frame2.shape[0], QImage.Format_RGB888)
self.update_video_frame.emit(qImg.rgbSwapped())

Here is the class for the fourth page:

class FourthPage(QWidget):
    recording_finished = pyqtSignal()
    switch_to_fifth_page = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.initUI()

    def initUI(self):
        self.setContentsMargins(0, 0, 0, 0)

        # Set up the video label to take up the entire space
        self.video_label = QLabel(self)
        self.video_label.setAlignment(Qt.AlignCenter)
        self.video_label.setStyleSheet("background-color: transparent;")  # Optional: Set transparent background

        # Set video_label to cover the entire widget
        self.video_label.setGeometry(0, 0, self.width(), self.height())

        self.click_player = QMediaPlayer()

        # Install event filter to detect clicks on the video label
        self.video_label.installEventFilter(self)

    def resizeEvent(self, event):
        # Ensure video_label resizes with the widget
        self.video_label.setGeometry(0, 0, self.width(), self.height())

    def stopRecording(self):
        self.recording_finished.emit()

    def playClickSound(self):
        self.click_player.setMedia(QMediaContent(QUrl.fromLocalFile("/path/to/Click.mp3")))
        self.click_player.setVolume(100)
        self.click_player.play()

    def handleMouseClick(self):
        self.stopRecording()
        self.playClickSound()
        QTimer.singleShot(500, self.switch_to_fifth_page.emit)

    def eventFilter(self, source, event):
        if event.type() == QEvent.MouseButtonPress and source == self.video_label:
            self.handleMouseClick()
            return True
        return super().eventFilter(source, event)

Here is the main class that controls the flow of the app:

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.stack = QStackedWidget(self)
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.setGeometry(0, 0, 800, 600)
        self.showFullScreen()
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout(self)
        self.introPage = IntroPage()
        self.firstPage = FirstPage()
        self.secondPage = SecondPage()
        self.thirdPage = ThirdPage()
        self.fourthPage = FourthPage()
        self.startRecordingPage = StartRecordingPage()
        self.fifthPage = FifthPage()
        self.sixthPage = SixthPage()
        self.stack.addWidget(self.introPage)
        self.stack.addWidget(self.firstPage)
        self.stack.addWidget(self.secondPage)
        self.stack.addWidget(self.thirdPage)
        self.stack.addWidget(self.startRecordingPage)
        self.stack.addWidget(self.fourthPage)
        self.stack.addWidget(self.fifthPage)
        self.stack.addWidget(self.sixthPage)
        layout.addWidget(self.stack)
        self.setLayout(layout)

        self.introPage.switch_to_first_page.connect(self.showFirstPage)
        self.firstPage.switch_to_second_page.connect(self.showSecondPage)
        self.secondPage.switch_to_third_page.connect(self.showThirdPage)
        self.thirdPage.switch_to_recording_page.connect(self.showStartRecordingPage)
        self.startRecordingPage.switch_to_fourth_page.connect(self.showFourthPage)
        self.fourthPage.switch_to_fifth_page.connect(self.showFifthPage)
        self.fourthPage.recording_finished.connect(self.stopRecording)
        self.sixthPage.restart_requested.connect(self.restartApp)
        self.sixthPage.exit_requested.connect(self.exitApp)

        self.backend_thread = BackendThread()
        self.backend_thread.update_video_frame.connect(self.update_video_frame)
        self.backend_thread.finished.connect(self.showSixthPage)
        self.showFullScreen()

    def stopRecording(self):
        self.backend_thread.stop_recording = True

    def showFirstPage(self):
        self.stack.setCurrentWidget(self.firstPage)

    def showSecondPage(self):
        self.stack.setCurrentWidget(self.secondPage)

    def showThirdPage(self):
        self.stack.setCurrentWidget(self.thirdPage)

    def showStartRecordingPage(self):
        self.stack.setCurrentWidget(self.startRecordingPage)

    def showFourthPage(self):
        self.stack.setCurrentWidget(self.fourthPage)
        self.backend_thread.start()

    def showFifthPage(self):
        self.stack.setCurrentWidget(self.fifthPage)
        QTimer.singleShot(100, self.run_processing)  # Delay the processing to allow the UI to update

    def showSixthPage(self):
        self.stack.setCurrentWidget(self.sixthPage)
        self.display_results()

    def run_processing(self):
        self.backend_thread.run_processing()

    def update_video_frame(self, qImg):
        self.fourthPage.video_label.setPixmap(QPixmap.fromImage(qImg))

    def display_results(self):
        font = self.sixthPage.results_label.font()
        font.setPointSize(14)
        self.sixthPage.results_label.setFont(font)
        self.sixthPage.results_label.setWordWrap(True)
        self.sixthPage.results_label.setFixedWidth(self.width() - 20)
        self.sixthPage.results_label.setText(
            f"Frame count: {self.backend_thread.frame_count}\n"
            f"FPS: {self.backend_thread.fps}\n"
            f"Transcript: {self.backend_thread.transcript}\n"
            f"Objects List: {self.backend_thread.objects_list}\n"
            f"Phrase Timestamps: {self.backend_thread.phrase_timestamps}\n"
        )

    def restartApp(self):
        self.stack.setCurrentWidget(self.introPage)

    def exitApp(self):
        QApplication.instance().quit()

Problem: The QLabel on the fourth page does not resize correctly to display the video frames in full screen. I've tried different spacing and margin options, but none of them work. It gives white borders on left, right and top

Question: How can I ensure that the QLabel resizes correctly and displays the video frames in full screen on the fourth page?

Any help or suggestions would be greatly appreciated!