PyQt 예제 2.2.4

마지막 대화 상자를 소개하겠다. 이번 대화 상자는 Live Modeless 대화 상자이다.

이 대화 상자는 Smart 대화 상자처럼 부모 윈도우와 계속 상호작용이 가능하다. 단, 변경된 사항이 즉시 적용되는 특성을 가지고 있다. 즉, Live 뜻 그대로 실시간으로 값이 적용된다.

따라서 확인이나 적용 단추가 없고, 위젯들의 값이 변경되면 바로 부모 윈도우의 위젯에 적용된다.

일단, 지난 번까지 대화 상자에서는 Live Dialog에 대한 버튼이 없었기 때문에, 부모 윈도우에서 약간의 레이아웃 수정을 했다.
 class Form(QDialog):
     def __init__(self, parent=None):
         super().__init__(parent)
 
+        self.liveDialog = None
+
         # Buttons
         simpleButton = QPushButton("Simple Dialog")
         signalButton = QPushButton("Signal Dialog")
@@ -29,6 +31,7 @@ class Form(QDialog):
         dumbButton = QPushButton("Dumb Dialog")
         standardButton = QPushButton("Standard Dialog")
         smartButton = QPushButton("Smart Dialog")
+        liveButton = QPushButton("Live Dialog")
         buttonLayout = QGridLayout()
         buttonLayout.addWidget(simpleButton, 0, 0)
         buttonLayout.addWidget(signalButton, 0, 1)
@@ -36,6 +39,7 @@ class Form(QDialog):
         buttonLayout.addWidget(dumbButton, 1, 0)
         buttonLayout.addWidget(standardButton, 1, 1)
         buttonLayout.addWidget(smartButton, 1, 2)
+        buttonLayout.addWidget(liveButton, 1, 3)
         buttonLayout.setColumnStretch(3, 1)
         self.connect(simpleButton, SIGNAL("clicked()"), self.SimpleCall)
         self.connect(signalButton, SIGNAL("clicked()"), self.SignalCall)
@@ -43,6 +47,7 @@ class Form(QDialog):
         self.connect(dumbButton, SIGNAL("clicked()"), self.DumbCall)
         self.connect(standardButton, SIGNAL("clicked()"), self.StandardCall)
         self.connect(smartButton, SIGNAL("clicked()"), self.SmartCall)
+        self.connect(liveButton, SIGNAL("clicked()"), self.LiveCall)

+ 되어 있는 부분이 추가된 부분이다.

먼저, self.liveDialog는 이후에 liveDialog 대화 상자를 유지하기 위한 변수이다. 그리고 버튼과 위젯 배치, connect 메소드가 추가되었을 뿐이다.

그럼, 먼저 Live 대화 상자를 부르는 메소드를 보겠다.
    def LiveCall(self):
        def update():
            self.textLabel.setText(self.values["label"])
            self.comboBoxLabel.setText(self.values["comboBox"])
            self.slider.setValue(self.values["slider"])

        self.values = {"label" : self.textLabel.text(), 
                        "comboBox" : self.comboBoxLabel.text(),
                        "slider" : self.slider.value()}
        if self.liveDialog is None:
            self.liveDialog = LiveDialog(self.values, update, self)
        self.liveDialog.refresh(self.values)
        self.liveDialog.show()
        self.liveDialog.raise_()
        self.liveDialog.activateWindow()

지난 번과 매우 유사하게 update 메소드를 선언하고, self.values를 할당해주었다. 그리고 self.liveDialog에 대화 상자가 생성되어 있지 않다면, 새로 생성을 해준다.

이때, self.values와 update 메소드를 값으로 넘겨주는데, update 메소드는 내부에서 값이 변경될 때마다 호출해주기 위함이다.

그리고 self.liveDialog가 생성된 후에 refresh를 통해서 대화 상자를 초기화 해준다. 이 부분은 책에 없는 부분이긴 한데, 대화 상자가 생성된 후에 다시 대화 상자를 호출하게 되면 부모 윈도우의 값이 변경되었을 지라도 live 대화 상자 값은 그대로 유지 되고 있기 때문에, 새로 초기화 해주기 위함이다.

그리고 show를 통해서 창을 보여주게 한 후에 raise를 통해서 창을 부모 윈도우 위로 나오게 하면서, activateWindow를 통해서 창을 활성화(초점 변경) 시킨다.

즉, smart 대화 상자의 경우 Qt.WA_DeleteOnClose 속성을 부가해줌으로써 대화 상자가 닫히면 삭제 되도록 했지만, 이번의 경우에는 대화 상자가 닫히면 그냥 숨겨진다. 따라서 대화 상자의 객체를 self.liveDialog를 통해서 계속 가지고 있어야 하고, 이미 생성되어 있다면 재 생성 되지 않도록 해야 한다. 또, 대화 상자가 다시 위로 나오게 해야한다.


그러면 이제 대화 상자 구현 부분을 보겠다.
class LiveDialog(QDialog):
    def __init__(self, arg, update, parent=None):
        super().__init__(parent)

        textEditLabel = QLabel("Main 레이블 변경: ")
        self.textLineEdit = QLineEdit(arg["label"])
        
        valueEditLabel = QLabel("Main 슬라이더 변경: ")
        self.valueLineEdit = QLineEdit(str(arg["slider"]))
        self.valueLineEdit.setInputMask("900")

        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
        self.update = update

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

        self.connect(self.textLineEdit, SIGNAL("textEdited(QString)"),
                        self.apply)
        self.connect(self.valueLineEdit, SIGNAL("textEdited(QString)"),
                        self.checkFix)
        self.connect(self.comboBox, SIGNAL("currentIndexChanged(int)"),
                        self.apply)

        layout = QVBoxLayout()
        layout.addLayout(widgetLayout)

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

    def checkFix(self):
        valueText = self.valueLineEdit.text()
        if len(valueText) == 0 or int(valueText) < 0 or int(valueText) > 100:
            self.valueLineEdit.setText("0")
            self.valueLineEdit.selectAll()
            self.valueLineEdit.setFocus()
        self.apply()

    def apply(self):
        value = int(self.valueLineEdit.text())
        self.result["label"] = self.textLineEdit.text()
        self.result["comboBox"] = self.comboBox.currentText()
        self.result["slider"] = value
        self.update()
    
    def refresh(self, arg):
        self.textLineEdit.setText(arg["label"])
        self.valueLineEdit.setText(str(arg["slider"]))
        comboBoxIndex = self.comboBox.findText(arg["comboBox"])
        if comboBoxIndex == -1:
            comboBoxIndex = 0
        self.comboBox.setCurrentIndex(comboBoxIndex)
        self.result = arg

대화 상자 초기화 부분은 지난번과 크게 다르지 않다. setInputMask를 통해서 위젯 수준에서 확인(validation)을 해준다. 다만, 이전과 다르다면, checkFix를 통해서 값의 오류를 알려주는 것이 아니라, 그냥 수정을 시킨다.

즉, 값의 수정이 바로 부모 윈도우의 위젯에 영향을 주기 때문에, 오류를 알려주는 것이 아니라 바로 수정을 해서 적용시켜야 한다.

이미 슬라이드 값은 라인 에디터에 의해서 3자리로 고정이므로, 그 범위만 조정해주면 된다. 만약, 범위가 넘어가게 되면 다시 0으로 초기화 시키고 초점을 그곳으로 이동시켜준다.

그리고 확인 및 수정이 이루어지면, apply를 통해서 값을 설정해준 다음에, 이전에 받았던 update 메소드를 통해서 부모 윈도우의 위젯의 값을 갱신해준다.

refresh 메소드에서는 위에서 말했 듯이, 대화 상자 위젯의 값을 새롭게 초기화 해주는 역할을 하고 있다.


이렇게 해서 일반적으로 많이 쓸 수 있는 4가지 대화 상자 종류를 모두 알아보았다. 가장 평범하고 많이 쓰는 방식은 역시 standard 대화 상자일 것이다. 부모 윈도우와의 결합 역시 낮으면서 대화 상자 자체로 많은 일을 할 수 있기 때문이다.

그리고 기본적으로 Qt 에 내장된 대화 상자들도 존재한다. 예를 들어, QInputDialog는 한 개의 값을 받을 때 간단하게 호출할 수 있는 대화 상자이다.

댓글 없음:

댓글 쓰기