PyQt에서 QPixmapCache 질문드립니다.

조회수 956회

현재 독학으로 파이썬과 pyqt 공부하고 있습니다. 모르는 게 있으면 인터넷으로 찾아가면서 Conway의 Life Game을 구현해보고 있는데, 각 Cell이 갱신될 때마다 다시 그리다가 QPixmapCache를 사용하면 실행속도와 메모리 사용에 이점이 있다고 해서 QPixmapCache를 사용하도록 코드를 수정했습니다.

그런데 실행 속도가 큰 차이가 없는 둘째치고 어느정도 프로그램을 실행하다 보면 갑자기 아래 표시한 부분에서 입력값에 해당하는 drawPixmap 함수의 오버로딩이 존재하지 않는다고 오류가 발생합니다.

제가 생각하기엔 캐시가 부족해서 Key가 죽은 거 같은데, 궁금한 부분이 만약 캐시가 부족해서 오류가 난다면 아예 처음부터 오류가 나야하는 거 아닌가요? 실행중에 drawPixmap을 하거나 QPixmapCache.find를 하는 것만으로도 캐시의 사용량이 늘어나는 건지 궁금합니다.

또 이 문제를 해결할 방법이 있는지도 궁금합니다.

#QPixmapCache의 Key
on_key = None
off_key = None

#각 Cell의 width/height
CELL_W = 10
CELL_H = 10

#Cell의 그래픽을 담당하는 class
class Cell(QWidget):
    def __init__(self, x, y, *args, **kwargs):
        super(Cell, self).__init__(*args, **kwargs)

        self.x = x
        self.y = y

    #MainWindow에서 업데이트하면 실행되는 부분
    def paintEvent(self, event):
        p = QPainter()
        p.begin(self)

        if is_map[self.y][self.x] is True:
            p.drawPixmap(self.rect(), QPixmapCache.find(on_key)) #<-이부분
        else:
            p.drawPixmap(self.rect(), QPixmapCache.find(off_key))
        p.end()
    #...

#MainWindow class
class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        #...

        self.pixmap_reset()

        self.show()

    #QPixmapCache에 처음 Pixmap들을 저장하는 부분
    def pixmap_reset(self):
        p = QPainter()
        on_map = QPixmap(CELL_W, CELL_H)
        off_map = QPixmap(CELL_W, CELL_H)

        global on_key, off_key #전역변수 불러오기

        # on_map에 Cell의 모양을 그린 후 QPixmapCache에 저장
        p.begin(on_map)
        p.setPen(Qt.black)
        p.setBrush(ON_COLOR)
        p.drawRect(on_map.rect())
        on_key = QPixmapCache.Key(QPixmapCache.insert(on_map))
        p.end()

        # off_map에 Cell의 모양을 그린 후 QPixmapCache에 저장
        p.begin(off_map)
        p.setPen(Qt.black)
        p.setBrush(OFF_COLOR)
        p.drawRect(off_map.rect())
        off_key = QPixmapCache.Key(QPixmapCache.insert(off_map))
        p.end()
  • (•́ ✖ •̀)
    알 수 없는 사용자

1 답변

  • 일단 에러부터 원인부터 알아보면,

    https://doc.qt.io/qtforpython/PySide2/QtGui/QPixmapCache.html

    QPixmapCache.find() 정적 멤버 함수는 bool을 리턴합니다. QPixmap.drawPixmap 멤버 함수 및 같은 이름으로 오버로딩 된 함수들 중, bool을 받는 함수가 없기 때문에 에러가 납니다.

    말씀하신 캐시가 부족해서 Key가 죽었다 라는 표현은 뭔가 상황 설명에 필요한 용어들이 생략된 듯 하지만

    아무튼 그게 문제는 아닌거죠.


    질문자님 상황에서의 캐시 효용성에 대해서 말씀드리면,

    위의 상황에서는 캐시를 사용한다고 해서 크게 이득을 볼 수는 없을 겁니다. 무거운 이미지 프로세싱으로 그리거나 많은 레이어를 합성해서 만들어내는 pixmap 이 아니고 간단한 color-filled-rect 일 뿐이니까요.

    저 캐시를 사용하는 대상은 공식 문서에 써 있는대로 만드는데 많은 비용이 들어가는 pixmap 입니다. 위 상황에서는 크게 도움이 안되는거죠.


    마지막으로 사용법에 대한 것인데,

    QPixmapCache.find(key) 함수는 pixmap을 리턴하지 않으니 작성하신 코드처럼 쓰면 안됩니다.

    단지 캐시를 써 보는데 의의를 둔다면,

    on_map = QPixmap(CELL_W, CELL_H)
    
    p = QPainter()
    p.begin(on_map)
    p.setPen(Qt.black)
    p.setBrush(ON_COLOR)
    p.drawRect(on_map.rect())
    p.end()
    
    on_key = QPixmapCache.insert(on_map) # 어짜피 key를 리턴
    
    # 다른 함수에서 이미 캐시된 pixmap을 쓰고 싶으면
    pm = QPixmap()
    QPixmapCache.find(on_key, pm)
    painter.drawPixmap(0, 0, pm)
    
    • 문서만 보고 코딩한거라 안 돌아갈 수 있습니다. 싫어요 누르셔도 할 말 없네요. doodoji 2019.7.19 15:03
    • 답변 감사드립니다! 만드는 데 비용이 많이 들어가는 경우에만 속도에 이득이 있는 건 잘 몰랐네요;; 그런데 좀 더 여쭤보고 싶은게, 1. 답변해 주신 대로 `QPixmapCache.find(on_key, pm)` 형식으로 작성하니까 `Process finished with exit code -1073740791 (0xC0000409)` 오류가 뜨고 그냥 꺼져버리는데, 왜 이런 오류가 나는지 혹시 아시나요? 2. 제가 `캐시가 부족해서 Key가 죽었다`고 표현한 건 실행 후 문제없이 몇천 번 잘 실행되다가 갑자기 `p.drawPixmap(self.rect(), pm) TypeError: arguments did not match any overloaded call:`이라면서 종료가 돼서 그렇게 표현한 거예요. 이부분을 더 잘 설명할 방법을 모르겠어서 그렇게 표현한 건데, 혹시 짐작가시는 부분은 없으신가요? 알 수 없는 사용자 2019.7.21 15:58
    • 흐음... pixmap_reset 이 함수가 업데이트마다 매 번 매 번 실행되고 있다면 말씀하신대로 캐시 부족현상이 맞을 수도 있습니다. 캐시 한계 용량을 넘어서게 되면 어떤 부작용이 있는지 모르나 해당 에러가 발생할 가능성은 있어보이네요. 참고로 QPixmapCache의 캐싱 용량은 10MB가 디폴트 입니다. 정확하게 알아보려면 디버깅을 해서 저 에러가 뜨는 시점에 pm값이 무엇인지를 확인해 보셔야 할 듯 합니다. doodoji 2019.7.22 14:10
    • 그리고 만약 매 번 그리고 있었다면 그럴 필요가 없습니다. pixmap은 한 번만 그려서 글로벌 혹은 클래스 멤버로 저장해 놓고 그것을 painter가 재사용 하는 형태로 코딩하는게 맞습니다. doodoji 2019.7.22 14:10

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)