Trouble in retrieving window size and widget size

南笙酒味 提交于 2021-02-10 23:27:59

问题


Here is the code for a camera surveillance system. In the configuration_page.py file I'm getting the size of the window as 100x30 despite using self.showMaximized() and resizeEvent(). The widgets present in it are also showing the size as 640x480. I'm particularly interested in retrieving the size of a widget named self.mid_frame in CameraDisplay class present in config.py file.

Earlier I was facing the same issue in dashboard.py file but I found a workaround by explicitly passing width and height in that case. But this time I'm stuck because I need to get the size of the widget named self.mid_frame. I don't understand why even resizeEvent is showing the wrong size.

main.py

from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt, QRect
from threading import Thread, RLock, Lock
from collections import deque
from datetime import datetime
import time
import sys
import cv2
import imutils
from dashboard import *
from configuration_page import *
from global_widgets import *


class CameraWidget(QtGui.QWidget):
    """Independent camera feed
    Uses threading to grab IP camera frames in the background

    @param width - Width of the video frame
    @param height - Height of the video frame
    @param stream_link - IP/RTSP/Webcam link
    @param aspect_ratio - Whether to maintain frame aspect ratio or force into fraame
    """

    def __init__(self, stream_link=0, stacked_widget=None, width=0, height=0, btn_text=None, idx=None, aspect_ratio=False, parent=None, deque_size=1):
        super(CameraWidget, self).__init__(parent)

        # Initialize deque used to store frames read from the stream
        self.deque = deque(maxlen=deque_size)
        
        self.maintain_aspect_ratio = aspect_ratio
        self.camera_stream_link = stream_link
        self.stacked_widget = stacked_widget
        self.idx = idx

        # Flag to check if camera is valid/working
        self.online = False
        self.capture = None

        self.video_frame = QtGui.QLabel()
        self.video_frame_1 = QtGui.QLabel()

        self.load_network_stream()

        # Start background frame grabbing
        self.get_frame_thread = Thread(target=self.get_frame, args=())
        self.get_frame_thread.daemon = True
        self.get_frame_thread.start()

        # Periodically set video frame to display
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.set_frame)
        self.timer.start(.5)

        print('Started camera: {}'.format(self.camera_stream_link))

    def load_network_stream(self):
        """Verifies stream link and open new stream if valid"""

        def load_network_stream_thread():
            if self.verify_network_stream(self.camera_stream_link):
                self.capture = cv2.VideoCapture(self.camera_stream_link)
                self.online = True
        self.load_stream_thread = Thread(target=load_network_stream_thread, args=())
        self.load_stream_thread.daemon = True
        self.load_stream_thread.start()

    def verify_network_stream(self, link):
        """Attempts to receive a frame from given link"""

        cap = cv2.VideoCapture(link)
        if not cap.isOpened():
            return False
        cap.release()
        return True

    def get_frame(self):
        """Reads frame, resizes, and converts image to pixmap"""

        while True:
            try:
                if self.capture.isOpened() and self.online:
                    # Read next frame from stream and insert into deque
                    status, frame = self.capture.read()

                    if status:
                        self.deque.append(frame)
                    else:
                        self.capture.release()
                        self.online = False
                else:
                    # Attempt to reconnect
                    print('attempting to reconnect', self.camera_stream_link)
                    self.load_network_stream()
                    self.spin(2)
                self.spin(.001)
                
            except AttributeError:
                pass

    def spin(self, seconds):
        """Pause for set amount of seconds, replaces time.sleep so program doesnt stall"""

        time_end = time.time() + seconds
        while time.time() < time_end:
            QtGui.QApplication.processEvents()

    def set_frame(self):
        """Sets pixmap image to video frame"""

        if not self.online:
            self.spin(1)
            return

        if self.deque and self.online:
            # Grab latest frame
            frame = self.deque[-1]
            frame_1 = self.deque[-1]

            # Display frames on dashboard and configuration pages
            # Frame for dashboard
            # Keep frame aspect ratio
            if self.maintain_aspect_ratio:
                self.frame = imutils.resize(frame, width=self.screen_width)
            # Force resize
            else:
                self.frame = cv2.resize(frame, (self.screen_width, self.screen_height))
                self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
                h, w, ch = self.frame.shape
                bytesPerLine = ch * w

            # Frame for configuration page-----------------------------------------------------------------------------------------

                # print('2: ', self.screen_width_1, self.screen_height_1)
                self.frame_1 = cv2.resize(frame_1, (self.screen_width_1, self.screen_height_1))
                self.frame_1 = cv2.cvtColor(self.frame_1, cv2.COLOR_BGR2RGB)
                h_1, w_1, ch_1 = self.frame_1.shape
                bytesPerLine_1 = ch_1 * w_1

            # Convert to pixmap and set to video frame
            self.img = QtGui.QImage(self.frame, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
            self.pix = QtGui.QPixmap.fromImage(self.img)
            self.video_frame.setPixmap(self.pix)

            self.img_1 = QtGui.QImage(self.frame_1, w_1, h_1, bytesPerLine_1, QtGui.QImage.Format_RGB888)
            self.pix_1 = QtGui.QPixmap.fromImage(self.img_1)                                             
            self.video_frame_1.setPixmap(self.pix_1)

    def set_frame_params(self, width, height, btn_text=None, idx=0):
        self.screen_width = width
        self.screen_height = height
        self.btn_text = btn_text
        self.idx = idx

    def set_frame_params_1(self, width, height):
        self.screen_width_1 = width
        self.screen_height_1 = height

    def get_video_display_frame(self):
        self.video_display_frame = QtGui.QFrame()
        self.video_layout = QtGui.QVBoxLayout()
        self.video_btn = QtGui.QPushButton(self.btn_text)
        self.video_btn.setStyleSheet("background-color: rgb(128, 159, 255);")
        self.video_btn.clicked.connect(self.on_clicked)
        # self.video_frame = QtGui.QLabel()
        self.video_frame.setScaledContents(True)
        self.video_layout.addWidget(self.video_btn)
        self.video_layout.addWidget(self.video_frame)
        self.video_layout.setContentsMargins(0,0,0,0)
        self.video_layout.setSpacing(0)
        self.video_display_frame.setLayout(self.video_layout)

        return self.video_display_frame

    def get_video_frame(self):
        self.video_frame_1.setScaledContents(True)
        return self.video_frame_1

    @QtCore.pyqtSlot()
    def on_clicked(self):
        GlobalObject().dispatchEvent("hello", args=(self.idx,))
        self.stacked_widget.setCurrentIndex(1)


class Window(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.stacked_widget = QtGui.QStackedWidget()

        layout = QtGui.QVBoxLayout()
        layout.setContentsMargins(0,0,0,0)
        layout.addWidget(self.stacked_widget)

        widget = QtGui.QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.cam1 = CameraWidget(camera1, self.stacked_widget, idx=1)

        widget_1 = DashBoard(self.cam1, self.stacked_widget)
        widget_2 = ZoneConfig(self.cam1, self.stacked_widget)

        self.stacked_widget.addWidget(widget_1)
        self.stacked_widget.addWidget(widget_2)

        self.showMaximized()
        

camera1 = '../streams/Fog.avi'

if __name__ == '__main__':
    app = QtGui.QApplication([])
    app.setStyle(QtGui.QStyleFactory.create("plastique"))
    # app.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))

    window = Window()
    window.show()
    sys.exit(app.exec_())

dashboard.py

from PyQt4 import QtGui, QtCore
from global_widgets import *


class DashBoard(QtGui.QWidget):    
    def __init__(self, cam1, stacked_widget, parent=None):
        super(DashBoard, self).__init__(parent)

        self.showMaximized()

        self.screen_width = self.width()
        self.screen_height = self.height()

        self.stacked_widget = stacked_widget

        # Layouts and frames
        layout = QtGui.QVBoxLayout()

        top_frame = QtGui.QFrame()
        top_frame.setStyleSheet("background-color: rgb(208, 208, 225)")
        mid_frame = QtGui.QFrame()   
        mid_frame.setStyleSheet("background-color: rgb(153, 187, 255)")

        layout.addWidget(top_frame, 1)
        layout.addWidget(QHLine())
        layout.addWidget(mid_frame, 20)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(0)
        self.setLayout(layout)
        
        # Top frame
        label = QtGui.QLabel('Dashboard')
        label.setFont(QtGui.QFont('Times New Roman', 20))

        top_layout = QtGui.QHBoxLayout()
        top_layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)
        top_layout.setContentsMargins(5,5,5,5)
        top_frame.setLayout(top_layout)

        # Middle frame
        self.mid_layout = QtGui.QStackedLayout()

        # Create camera widgets
        print('Creating Camera Widgets...')

        cam_widget = Cam1(cam1, self.screen_width, self.screen_height, self)
        self.mid_layout.addWidget(cam_widget)
        self.mid_layout.setCurrentWidget(cam_widget)
        mid_frame.setLayout(self.mid_layout)  


class Cam1(QtGui.QWidget):
    def __init__(self, cam1, screen_width, screen_height, parent=None):
        super(Cam1, self).__init__(parent)

        cam1.set_frame_params(screen_width, screen_height, 'VIDS 01', 1)

        # Add widgets to layout
        print('Adding widgets to layout...')
        layout = QtGui.QGridLayout()
        layout.addWidget(cam1.get_video_display_frame(),0,0,1,1)
        layout.setContentsMargins(5,5,5,5)
        self.setLayout(layout)

configuration_page.py

from PyQt4 import QtGui, QtCore
from global_widgets import *
from ui_main import *


class ZoneConfig(QtGui.QWidget):

    def __init__(self, cam1, stacked_widget, parent=None):
        super(ZoneConfig, self).__init__(parent)
        
        GlobalObject().addEventListener("hello", self.set_cam)

        self.layout = QtGui.QVBoxLayout()
        
        self.frame = QtGui.QFrame()
        self.frame_layout = QtGui.QStackedLayout()
        # self.setLayout(self.frame_layout)

        self.screen_width = self.width()
        self.screen_height = self.height()

        cam_widget_1 = CameraDisplay(cam1, 1, self.frame_layout, stacked_widget, self)

        self.frame_layout.addWidget(cam_widget_1)

        self.frame.setLayout(self.frame_layout)
        self.layout.addWidget(self.frame)
        self.layout.setContentsMargins(0,0,0,0)
        self.setLayout(self.layout)

    @QtCore.pyqtSlot()
    def set_cam(self, index):
        if index == 1:
            self.frame_layout.setCurrentIndex(0)


class CameraDisplay(QtGui.QWidget):
    def __init__(self, cam, idx, frame_layout, stacked_widget, parent=None):
        super(CameraDisplay, self).__init__(parent)

        self.showMaximized()

        self.screen_width = self.width()
        self.screen_height = self.height()
        self.frame_layout = frame_layout
        self.stacked_widget = stacked_widget    

        print('size: ', self.screen_width, self.screen_height)

        # Layouts and frames
        layout = QtGui.QVBoxLayout()

        top_frame = QtGui.QFrame()
        top_frame.setStyleSheet("background-color: rgb(208, 208, 225)")
        self.mid_frame = QtGui.QFrame()                                           ## Size of this frame is needed
        self.mid_frame.setStyleSheet("background-color: rgb(153, 187, 255)")
        btm_frame = QtGui.QFrame()
        btm_frame.setStyleSheet("background-color: rgb(208, 208, 225)")
        
        # Top frame
        label = QtGui.QLabel('Configuration')
        label.setFont(QtGui.QFont('Times New Roman', 20))

        top_layout = QtGui.QHBoxLayout()
        top_layout.addWidget(label, alignment=QtCore.Qt.AlignCenter)
        top_layout.setContentsMargins(5,5,5,5)
        top_frame.setLayout(top_layout)

        # Middle frame
        mid_layout = QtGui.QHBoxLayout()

        # Create camera widgets
        print('Creating Camera Widgets...')
        mid_layout = QtGui.QHBoxLayout()
        self.video_frame = cam.get_video_frame()
        mid_layout.addWidget(self.video_frame)
        mid_layout.setContentsMargins(5,5,5,5)
        self.mid_frame.setLayout(mid_layout)

        # Bottom frame
        btn = QtGui.QPushButton('Dashboard')
        btn.clicked.connect(self.goMainWindow)

        btm_layout = QtGui.QHBoxLayout()
        btm_layout.addStretch()
        btm_layout.addWidget(btn)
        btm_layout.setContentsMargins(5,5,5,5)
        btm_frame.setLayout(btm_layout)

        layout.addWidget(top_frame, 1)
        layout.addWidget(QHLine())
        layout.addWidget(self.mid_frame, 50)
        layout.addWidget(QHLine())
        layout.addWidget(btm_frame, 1)
        layout.setContentsMargins(0,0,0,0)
        layout.setSpacing(0)

        self.setLayout(layout)
        # self.showMaximized()

        cam.set_frame_params_1(self.mid_frame.width(), self.mid_frame.height()-10)      ## here I want the size

    def resizeEvent(self, event):
        QtGui.QWidget.resizeEvent(self, event)

    def goMainWindow(self):
        self.stacked_widget.setCurrentIndex(0)

I think the problem is only in configuration_page.py file but I'm pasting entire code in case anyone wants to go throught the entire logic.


回答1:


Add the following to your code.

def event(self, e):
    if e.type() in (QEvent.Show, QEvent.Resize):
        widget_w = self.mid_frame.frameGeometry().width()
        widget_h = self.mid_frame.frameGeometry().height()
        screen_w = self.width()
        screen_h = self.height()

        # For "debugging" purposes:
        print("Widget - width: %s height: %s" % (widget_w, widget_h)
        print("screen - width: %s height: %s" % (screen_w, screen_h)
       
        return ((widget_w, widget_h), (screen_w, screen_h))

        #return {"widget": {"width": widget_w, "height": widget_h}, "screen": {"width": screen_w, "height": screen_h}}


来源:https://stackoverflow.com/questions/63214144/trouble-in-retrieving-window-size-and-widget-size

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!