Home > Software engineering >  How to solve QMLQQuickPaintedItem crash and not rendering?
How to solve QMLQQuickPaintedItem crash and not rendering?

Time:04-18

I try to show stream of preprocessed Images so I create custom QQuickPaintedItem to paint images The problem that when image change ,Nothing happen just application crashed but print statement of paint method still print and mouse cursor look like sign.

here is my LiveCamera subclass from QQuickPaintedItem

class LiveCamera(QQuickPaintedItem):

imageChanged=Signal(QImage)
def __init__(self):

    super().__init__()
    self.setRenderTarget(QQuickPaintedItem.FramebufferObject)

    self.m_image = QImage("C://Users//Hassan//Documents//python-gui-projects//PortMafiaSecurity//images//loading.jpg")


def paint(self,painter: QPainter):
    print('hey')
    if self.m_image.isNull(): return
    img = self.m_image.scaled(self.size().toSize(),Qt.KeepAspectRatioByExpanding ,Qt.SmoothTransformation)
    painter.drawPixmap(QPoint(),QPixmap.fromImage(img))

@Property(QImage, notify=imageChanged)
def image(self):
     return self.m_image

@image.setter
def image(self, image):
    if self.m_image == image: return
    self.m_image = image
    self.imageChanged.emit(self.m_image)
    #self.paint(QPainter())
    self.update()

Here is main.py

 class CamThread(QThread):
    def __init__(self,UI):
        super().__init__()
        self.UI=UI


    def run(self):


          cap = open_images_capture(args.input, args.loop)
          frame_processor = FrameProcessor(args)

       

          frame_num = 0
          output_transform = None

          while True:
              start_time = perf_counter()
              frame = cap.read()

              if frame_num == 0:
                  output_transform = OutputTransform(frame.shape[:2], args.output_resolution)


              detections = frame_processor.process(frame)
              frame = draw_detections(frame, frame_processor, detections, output_transform)

              frame_num  = 1
              h, w, ch = frame.shape


              p = QImage(frame.data, h, w,QImage.Format_RGB888)
              self.UI.changeImage.emit(p)




class MainThread(QObject):
    def __init__(self):
         QObject.__init__(self)
         self.cam=CamThread(self)


    changeImage=Signal(QImage)

    @Slot(bool)
    def click(self,first):
        if first:
         self.cam.run()
        else:
         self.cam.quit()



if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    main = MainThread()

    engine.rootContext().setContextProperty("cam_recording", main)
    qmlRegisterType(LiveCamera, "LiveCameraPlugin", 1, 0, "LiveCamera")

    engine.load(os.fspath(Path(__file__).resolve().parent / "qml/main.qml"))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

Here is Qml

   Rectangle{
        x: 72
        y: 84
        width: 649
        height: 366

        LiveCamera{
            id:camera
            anchors.fill: parent
        }

    }

    LeftMenuBtn {
        //some stuff

    }

    Connections{
        target: cam_recording
        function onChangeImage(img){
                camera.image=img

        }

Is there a way to solve that problem ,I tried a lot to search for solution but I didn't find also I tried QtQuickImageProvider same problem so is there better way?

Here is Application Crash Moment

CodePudding user response:

According to the screenshot, this isn't a crash. The program seems to be to busy (on the main/gui thread) to respond to user interaction, resulting in Windows saying the application is not responsive.

To debug such a problem, you should use a debugger, pause the program and see what he is doing (on the main thread).

The problem in this case is that you are running CamThread::run (which executes an infinite loop) inside the main thread, instead of running it on a separate thread as intended. You shouldn't call QThread::run explicitly, but call QThread::start, which will start a new thread and execute the QThread::run function on that new thread.

Note that QThread::quit does nothing in your case, as by reimplementing QThread::run, the QEventLoop isn't started on that thread. Either you should start the event loop or you should implement your own signal, to interrupt the infinite loop inside CamThread::run to let the thread finish gracefull.

  • Related