PyQt 예제 2.2.2

이번 글에서는 Standard 대화 상자에 대해서 알아보겠다. 참고로 이번 글부터는 이전에 써둔 것도 없기 때문에 완전히 새로 시작하는 글이 되겠다.

먼저, Standard 대화 상자는 위젯에 따르는 값들을 초기값 인자로 넘겨주고, 받을 때에는 대화 상자의 메소드를 사용하여 값들을 받게 된다. Dumb와는 다르게 대화 상자에 직접 접근하지 않고, 그냥 호출만 하고 값을 받는 역할만 한다.

이러한 점 때문에 메인 윈도우 입장에서는 대화 상자가 어떠한 일을 하는지 전혀 알 필요가 없다. 단지, 초기값을 넘겨주고 그 값을 잘 처리해서 받기만 하면 되는 것이다.

또, Standard 대화 상자는 위젯 수준과 폼 수준의 확인(validation)을 처리할 수 있다.


그러면 예제를 살펴보겠다.
    def StandardCall(self):
        values = {"label" : self.textLabel.text(), 
                    "comboBox" : self.comboBoxLabel.text(),
                    "dial" : self.dial.value()}
        dialog = StandardDialog(values, self)
        if dialog.exec_():
            values = dialog.getResult()
            self.textLabel.setText(values["label"])
            self.comboBoxLabel.setText(values["comboBox"])
            self.dial.setValue(values["dial"])

일단, 대화 상자 호출 코드부터 보겠다. 위에서 말했 듯이, 초기값을 넘겨주기 위해서 사전 객체로 대화 상자가 쓸 인자들을 넘겨주고 있다. 초기값을 설정해준 다음에 객체를 초기값과 함께 생성하고, dialog.exec_() 를 사용하여 Modal 로 대화 상자를 실행한다.

그러면 부모 윈도우는 잠시 사용하지 못하는 상태가 되고, 대화 상자에서 값을 처리하게 되는데, Dumb 에서는 대화 상자의 위젯에 직접 접근해서 값을 가져왔지만, 여기서는 대화 상자에서 값을 리턴해주는 메소드를 호출하여 값을 받도록 했다.

이렇게 하면 대화 상자에서 어떠한 작업을 하던 간에, 부모 윈도우는 그것을 몰라도 원하는 값만 받을 수 있다.

이렇게 받은 값을 적절하게 현재 위젯에 설정을 해주면 대화 상자 호출이 완료되게 된다.


다음으로 대화 상자 클래스 부분을 보겠다.
class StandardDialog(QDialog):
    def __init__(self, arg, parent=None):
        super().__init__(parent)

        textEditLabel = QLabel("Main 레이블 변경: ")
        self.textLineEdit = QLineEdit(arg["label"])
        
        valueEditLabel = QLabel("Main 다이얼 변경: ")
        self.valueLineEdit = QLineEdit(str(arg["dial"]))

        comboBoxLabel = QLabel("Combo Box(&C): ")
        self.comboBox = QComboBox()
        comboBoxLabel.setBuddy(self.comboBox)
        for item in ["item1", "item2", "item3", "item4", "item5"]:
            self.comboBox.addItem(item)
        comboBoxIndex = self.comboBox.findText(arg["comboBox"])
        if comboBoxIndex == -1:
            comboBoxIndex = 0
        self.comboBox.setCurrentIndex(comboBoxIndex)

        self.result = arg.copy()

        widgetLayout = QFormLayout()
        widgetLayout.addRow(textEditLabel, self.textLineEdit)
        widgetLayout.addRow(valueEditLabel, self.valueLineEdit)
        widgetLayout.addRow(comboBoxLabel, self.comboBox)

        okButton = QPushButton("확인(&O)")
        cancelButton = QPushButton("취소")
        buttonBox = QDialogButtonBox()
        buttonBox.addButton(okButton, QDialogButtonBox.AcceptRole)
        buttonBox.addButton(cancelButton, QDialogButtonBox.RejectRole)
        okButton.setDefault(True)
        self.connect(buttonBox, SIGNAL("accepted()"), self, SLOT("accept()"))
        self.connect(buttonBox, SIGNAL("rejected()"), self, SLOT("reject()"))

        layout = QVBoxLayout()
        layout.addLayout(widgetLayout)
        layout.addWidget(buttonBox)

        self.setLayout(layout)
        self.setWindowTitle("Dumb Dialog")

    def accept(self):
        class OutOfRangeNumberError(Exception): pass

        try:
            value = int(self.valueLineEdit.text())
            if value < 0 or value > 100:
                raise OutOfRangeNumberError("This value is out of range "
                                            "from 0 to 100.")
        except ValueError:
            QMessageBox.warning(self, "Invalid number format",
                                    "This is not a number")
            self.valueLineEdit.selectAll()
            self.valueLineEdit.setFocus()
            return
        except OutOfRangeNumberError as e:
            QMessageBox.warning(self, "Out of Range of number", str(e))
            self.valueLineEdit.selectAll()
            self.valueLineEdit.setFocus()
            return

        self.result["label"] = self.textLineEdit.text()
        self.result["comboBox"] = self.comboBox.currentText()
        self.result["dial"] = value
        QDialog.accept(self)

    def getResult(self):
        return self.result

Dumb 대화 상자보다 코드가 긴데, 메소드가 추가 되었기 때문이다. 즉, 대화 상자의 행동이 더 똑똑해졌기 때문이다. 레이아웃 부분은 특별한 것이 없기 때문에 넘어가고, accept 메소드를 보겠다.

이것은 슈퍼 클래스의 메소드를 오버로딩 하고 있는 것이다. 따라서, 어떻게 하던 간에, 대화 상자에서 accept가 되게 되면, 이 메소드가 호출되어 값이 적절한지 판단하게 된다.

값이 위젯에 유효한지 판단하여 오류가 있을 경우 QMessageBox의 클래스 메소드를 사용하여 경고 메시지를 보여준다. 그리고 초점을 오류로 옮겨서 바로 수정을 할 수 있도록 한다.

그리고 값의 모두 유효하다면 그 값을 클래스 내부의 변수에 저장한다. 그리고 마지막에 슈퍼 클래스의 실제 메소드를 호출하면서 실행을 마친다.

또, getResult 메소드를 추가해서, 메인 윈도우에서 값을 얻을 수 있도록 해서, 메인 윈도우가 대화 상자의 변수나 값을 몰라도 간단하게 원하는 값을 가져갈 수 있다.

여기서 특별한 것이 있다면, QMessageBox 인데, 이것은 클래스 메소드가 있어서 간단하게 메시지 박스를 띄울 수 있다. 레퍼런스를 참고하면, 클래스 메소드를 통해서 경고나 주의, 확인 등의 메시지를 미리 만들어진 메시지 박스로 띄울 수 있게 되어 있다.

댓글 없음:

댓글 쓰기