2017-10-26 17 views
0

나는 많은 PNG 이미지를로드하고 이후에 PyQt를 사용하여 테마를 표시하려고하는데 문제가 있습니다. 내 현재 워크 플로우는 다중 프로세서 풀을 사용하여 'rb'값을 가진 각 파일을 여는 함수를 매핑 한 다음 각 파일의 바이트를 통합 목록으로 읽는 것입니다. 마지막으로 부모 프로세스는 QPixmap 개체의 fromImageData 메서드를 호출하여 이미지를 표시합니다. 이 방법은 잘 동작하는 것처럼 보이지만 이미지 (8K 해상도)를 전환 할 때마다 새 픽스맵을 다시 그리는 속도가 매우 느립니다.스레드에서 QPixmap 만들기

각 단계마다 새로운 이미지로 동일한 픽스맵을 재현하는 것이 아니라 각 이미지에 대한 픽스맵을 작성하고 픽스맵을 순환하는 것이 더 빠르다는 것을 기대하고있었습니다. 이렇게하려면 다중 프로세스 함수에서 픽스맵을 만들려고했지만 스레드에 부모 QApp가 없기 때문에 허용되지 않습니다.

제 질문은 적절한 방법이 있습니까? 나는 셀러리/reddis와 함께 alsp 생각을 가지고 있지만, 나는 다른 ourcome을 갖는 것을 볼 수 없습니다. 각 이미지에 대한 새로운 픽스맵을 만들고 setPixmap을 사용하여 전환하는 것이 가능한 옵션입니까 아니면이를 구현하는 더 적절한 방법이 있습니까?

답변

2

픽스맵을로드하는 코드를 래핑하는 QThreadPool 및 일부 QRunnable을 사용하여이를 수행 할 수 있어야합니다. 다음과 같이하십시오 :

from PyQt5 import QtCore, QtGui 

class PixmapLoader(QtCore.QRunnable): 
    def __init__(self, filename): 
     super().__init__() 
     self.filename = filename 
    def run(self): 
     # Load pixmap at filename 
     # ... 
     # then emit in a signal 
     loaded.emit(pixmap) 

    loaded = QtCore.pyqtSignal(QtGui.QPixmap) 

그런 다음 주 응용 프로그램의 어딘가에 스레드 풀을 만들고로드 객체를 실행하고 신호를 처리하십시오.

pool = QtCore.QThreadPool() 
loaders = [PixmapLoader(filename) for filename in filenames] 
for loader in loaders: 
    loader.loaded.connect(handle_new_pixmap) 
    pool.start(loader) 

def handle_new_pixmap(QtGui.QPixmap): 
    # do stuff with pixmap 

는 나는이을 시도하지했지만, Qt는이 스레드를 처리하기 때문에, 이것은 잘 여러 개의 스레드를 활용할 수 있어야합니다.

바와 같이 코멘트 설명 편집이 작동하지 않습니다. QRunnableQObject을 상속하지 않으며, QPixmaps은 기본 스레드 외부에서 생성 할 수 없다는 사실을 잊어 버렸습니다. 그러나 대신에 이미지 로더 객체를 사용하고 하나 이상의 배경 스레드로 이동하여 QImage을로드 한 다음 나중에 사용할 수 있도록 기본 스레드로 전송합니다. 현재 디렉토리에서 모든 PNG 파일을로드하여 베어 본을 수행 할 테스트 된 코드입니다.

#!/usr/bin/env python3 

import os 

from PyQt5.QtCore import pyqtSignal, QObject, QThread 
from PyQt5.QtGui import QImage 
from PyQt5.QtWidgets import QApplication 

class ImageLoader(QObject): 
    loaded = pyqtSignal(str, QImage) 

    def __init__(self, filename): 
     super().__init__() 
     self.filename = filename 

    def on_load_signal(self): 
     img = QImage(self.filename) 
     self.loaded.emit(self.filename, img) 


class LoaderManager(QObject): 
    request_img_load = pyqtSignal() 

    def __init__(self): 
     super().__init__() 
     self.loaders = list(map(ImageLoader, 
       filter(lambda f: f.endswith('.png'), os.listdir()))) 
     self.bg_thread = QThread() 

     for loader in self.loaders: 
      self.request_img_load.connect(loader.on_load_signal) 
      loader.loaded.connect(self.handle_img_loaded) 
      loader.moveToThread(self.bg_thread) 

     self.bg_thread.start() 

    def __del__(self): 
     self.bg_thread.quit() 

    def load_all(self): 
     self.request_img_load.emit() 

    def handle_img_loaded(self, name, img): 
     print('File {} of size {} loaded'.format(name, img.byteCount())) 

if __name__ == '__main__': 

    app = QApplication([]) 
    manager = LoaderManager() 
    manager.load_all() 
+0

감사합니다. @bnaecker! 최대한 빨리 시도해 보겠습니다 –

+1

이 코드는 작동하지 않습니다. Qt는 주 스레드 외부에서 픽스맵을 만드는 것을 지원하지 않으므로, 대신에'QImage'를 사용해야합니다. 또한,'QRunnable'은'QObject'를 상속받지 않으므로 신호를 낼 수 없습니다. 'QThread'를 사용해야합니다. – ekhumoro

+0

@ekhumoro 지적 해 주셔서 고맙습니다. 저는 답변을 업데이트했습니다. – bnaecker