2016-09-27 1 views
1

첫 번째 메모리 게임을 만들려고합니다.PyQt5 : 위젯 메서드를 통해 QAction 후 MainApplication 레이아웃 업데이트

저는 최근에 내 질문 here의 대답 덕분에 작동 방법을 알아 냈습니다. 작업 코드는 동일한 링크에 게시되었지만 이제는 위젯과 기본 응용 프로그램 클래스를 1) 분리 된 상태로 유지하려고 노력하고 있습니다. 2) OOP의 작동 방식을 더 잘 배우기 위해서입니다.

그래서 여기에 마지막 코드를 제외하고는 작동하는 새 코드가 게시됩니다. 개념 :

  1. MainApplication 이미지의 폴더 경로를 허용하는 도구 모음을 가지고 있으며, 회전의 빈 QGridLayout를 초기화 MemoryGame 위젯을 인스턴스화합니다.
  2. 메뉴 모음에서 파일 -> 열기를 클릭하면 showDialog 메서드가 호출됩니다.
  3. 폴더를 선택하면 populate_grid (MemoryGame obj의) 메서드가 호출됩니다.
  4. populate_grid "발견 된 각 이미지로 QGridLayout을 채워야"합니다.
  5. 그리드가 화면에 표시되지만 그렇지 않은되어야한다 ....

그 문제는 내가 그리드 레이아웃에 요소를 추가 populate_grid의 매우 마지막 행에 확신 ,하지만 문제를 해결하는 방법을 찾을 수 없습니다. 당신이 레이아웃 자체가없는 MemoryGame 위젯, 내부의 gridWidget을 넣어 때문에

#!/usr/bin/python3 
# -*- coding: utf-8 -*- 

""" 
Memory game 3 

My first memory game in PyQt5. 

author: Umberto Minora 
last edited: September 2016 
""" 

import os 
import sys 
import glob 
import math 

from PyQt5.QtWidgets import (QMainWindow, QWidget, 
    QGridLayout, QPushButton, QApplication, 
    QAction, QFileDialog, QLabel) 

from PyQt5.QtGui import QPixmap 

class MainApplication(QMainWindow): 
    """This is the main application. 
    All widgets should be put inside it.""" 
    def __init__(self, widget): 
     super().__init__() 

     self.widget = widget 
     self.initUI() 

    def showDialog(self): 
     folder = str(QFileDialog.getExistingDirectory(self, "Select Directory", 
      '.', QFileDialog.ShowDirsOnly)) 

     images = glob.glob(os.path.join(folder, '*.jpg')) 

     if images: 
      self.widget.populate_grid(images) 

    def initUI(self): 
     self.statusBar() 

     openFile = QAction('Open', self) 
     openFile.setShortcut('Ctrl+O') 
     openFile.setStatusTip('Search image folder') 
     openFile.triggered.connect(self.showDialog) 

     menubar = self.menuBar() 
     self.fileMenu = menubar.addMenu('&File') 
     self.fileMenu.addAction(openFile) 

     self.setCentralWidget(self.widget) 

     self.setGeometry(300, 300, 350, 300) 
     self.setWindowTitle('Memory Game!') 
     self.show() 

class MemoryGame(QWidget): 
    """This is the Memory Game Widget""" 
    def __init__(self): 
     super().__init__() 

     self.gridWidget = QWidget(self) 
     self.gridLayout = QGridLayout(self.gridWidget) 

    def populate_grid(self, images): 
     n_cols = math.ceil(math.sqrt(len(images))) 
     n_rows = math.ceil(math.sqrt(len(images))) 
     positions = [(i,j) for i in range(n_cols) for j in range(n_rows)] 
     for position, img in zip(positions, images): 
      if img == '': 
       continue 
      pixmap = QPixmap(img) 
      scaled = pixmap.scaled(pixmap.width()/3, pixmap.height()/3) 
      del(pixmap) 
      lbl = QLabel(self) 
      lbl.setPixmap(scaled) 
      self.gridLayout.addWidget(lbl, *position) 

if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = MainApplication(MemoryGame()) 
    sys.exit(app.exec_()) 

답변

1

이미지가 표시되지 않는 이유입니다. MemoryGame 위젯은 실제로 그래서 당신이해야 할 모든이되면, gridWidget를 교체해야합니다 :

class MemoryGame(QWidget): 
    """This is the Memory Game Widget""" 
    def __init__(self): 
     super().__init__() 
     self.gridLayout = QGridLayout(self) 

나는 또한 당신이 MemoryGame 위젯을 만드는 방법은 불필요하게 복잡한 생각합니다. 맞춤 위젯 클래스는 다른 클래스처럼 취급해야합니다. 그와 같은 MainApplication 생성자에 전달할 필요가 없습니다 - 단지 initUi 내에서 직접 작성 : 다시

def initUI(self): 
    ...   
    self.widget = MemoryGame() 
    self.setCentralWidget(self.widget) 
+0

감사합니다! 어쨌든, MainApplication을 다른 게임 (예 : PokerGame)으로 구현하고 싶다고 상상해보십시오. 주 응용 프로그램을 자식 위젯과 분리하는 것이 더 좋지 않겠습니까? 물론, 이제는 MainApplication이 매우 간단합니다. 어떻게 잠재적으로 될지 생각하고 있습니다. – umbe1987

+0

여러 게임을 원한다면 각 게임은 완전히 독립적이어야합니다 (앞에서 제안한 것처럼 모든 게임이 한 클래스에 포함되어야 함). 현재 메모리 게임은 2 개의 클래스로 나누어 져 있으며, 각각의 클래스는 다른 클래스 없이는 작동하지 않습니다. 여러 게임에서 각 게임은 자신 만의 메뉴를 제공해야합니다. 따라서 메인 애플리케이션은 게임의 메인 위젯을로드하고 메인 메뉴 바에 게임의 메뉴를 표시 할 책임이 있습니다.하지만 게임은 다른 모든 것을 할 것입니다. 게임에는 일반 인터페이스가 있어야하며 기본 응용 프로그램에서는이를 "블랙 박스"로 처리해야합니다. – ekhumoro