【问题标题】:How I can use Vars on PyQt5 the same way as IntVar() or StringVar() on tkinter?如何以与 tkinter 上的 IntVar() 或 StringVar() 相同的方式在 PyQt5 上使用 Vars?
【发布时间】:2022-01-28 03:37:51
【问题描述】:

创建变量

region = {'top': tk.IntVar(), 'left': tk.IntVar(), 'right': tk.IntVar(), 'bottom': tk.IntVar()}

创建条目并连接到变量

tk.Entry(master, textvariable=region['top']).place(x=60, y=100)
tk.Entry(master, textvariable=region['left']).place(x=60, y=120)
tk.Entry(master, textvariable=region['right']).place(x=60, y=140)
tk.Entry(master, textvariable=region['bottom']).place(x=60, y=160)

我在一些函数上使用了变量

def get_region():
    np.array(ImageGrab.grab(bbox=(region['top'].get(), region['left'].get(), region['right'].get(), region['bottom'].get())))

并使用变量在应用程序上保存和打开配置文件

def open_file(self):
    with open('{}'.format(filedialog.askopenfilename(initialdir="/", title="Select file",
                                                     filetypes=(("json files", "*.json"),
                                                                ("all files", "*.*")))), 'r') as config:
        data = json.load(config)

        region['top'].set(data['region']['top'])
        region['left'].set(data['region']['left'])
        region['right'].set(data['region']['right'])
        region['bottom'].set(data['region']['bottom'])

def save_as(self):
    json.decoder = {
        'region': {
            'top': region['top'].get(),
            'left': region['left'].get(),
            'right': region['right'].get(),
            'bottom': region['bottom'].get(),
            },
        }

    with open('{}'.format(filedialog.asksaveasfilename(initialdir="/", title="Save file",
                                                       filetypes=(("json files", "*.json"),
                                                                  ("all files", "*.*")))), 'w',
              encoding='utf-8') as config:
        json.dump(json.decoder, config, ensure_ascii=False, indent=2)
        config.close()

我在 PyQt5 中使用什么而不是 IntVar() 来构建这样的结构?

【问题讨论】:

    标签: python python-3.x pyqt pyqt5


    【解决方案1】:

    Qt 中没有类似的元素(有 2 个不同的库,其方法不同),一个可能的解决方案是创建一个映射 qproperties 的对象:

    from dataclasses import dataclass
    import json
    import sys
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    import sip
    
    
    @dataclass
    class Property:
        qobject: QtCore.QObject = None
        qproperty: str = ""
    
        @property
        def value(self):
            if self.qobject and not sip.isdeleted(self.qobject):
                return self.qobject.property(self.qproperty)
    
        @value.setter
        def value(self, value):
            if self.qobject and not sip.isdeleted(self.qobject):
                self.qobject.setProperty(self.qproperty, value)
    
    
    class Widget(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            top_spinbox = QtWidgets.QSpinBox(maximum=2147483647)
            left_spinbox = QtWidgets.QSpinBox(maximum=2147483647)
            right_spinbox = QtWidgets.QSpinBox(maximum=2147483647)
            bottom_spinbox = QtWidgets.QSpinBox(maximum=2147483647)
    
            button = QtWidgets.QPushButton(self.tr("grab"), clicked=self.grab_screen)
    
            file_menu = self.menuBar().addMenu(self.tr("&File"))
    
            open_action = file_menu.addAction(self.tr("Open File..."))
            open_action.triggered.connect(self.load_config)
    
            save_action = file_menu.addAction(self.tr("Save"))
            save_action.triggered.connect(self.save_config)
    
            central_widget = QtWidgets.QWidget()
            self.setCentralWidget(central_widget)
            flay = QtWidgets.QFormLayout(central_widget)
            flay.addRow(button)
            flay.addRow("Top:", top_spinbox)
            flay.addRow("Left:", left_spinbox)
            flay.addRow("Right:", right_spinbox)
            flay.addRow("Bottom:", bottom_spinbox)
    
            self.resize(640, 480)
    
            self.region = {
                "top": Property(qobject=top_spinbox, qproperty="value"),
                "left": Property(qobject=left_spinbox, qproperty="value"),
                "right": Property(qobject=right_spinbox, qproperty="value"),
                "bottom": Property(qobject=bottom_spinbox, qproperty="value"),
            }
    
        @QtCore.pyqtSlot()
        def grab_screen(self):
            top = self.region["top"].value
            left = self.region["left"].value
            right = self.region["right"].value
            bottom = self.region["bottom"].value
    
            print(top, left, right, bottom)
    
        @QtCore.pyqtSlot()
        def load_config(self):
            filename, _ = QtWidgets.QFileDialog.getOpenFileName(
                self,
                self.tr("Select file"),
                "/",
                self.tr("JSON files (*.json);;All files (*.*)"),
            )
            if filename:
                with open(filename, "r") as f:
                    data = json.load(f)
                    if "region" in data:
                        self.region["top"].value = data["region"].get("top", 0)
                        self.region["left"].value = data["region"].get("left", 0)
                        self.region["right"].value = data["region"].get("right", 0)
                        self.region["bottom"].value = data["region"].get("bottom", 0)
    
        @QtCore.pyqtSlot()
        def save_config(self):
            filename, _ = QtWidgets.QFileDialog.getSaveFileName(
                self,
                self.tr("Save file"),
                "/",
                self.tr("JSON files (*.json);;All files (*.*)"),
            )
            if filename:
                with open(filename, "w", encoding="utf-8") as f:
                    data = {
                        "region": {
                            "top": self.region["top"].value,
                            "left": self.region["left"].value,
                            "right": self.region["right"].value,
                            "bottom": self.region["bottom"].value,
                        },
                    }
    
                    json.dump(data, f, ensure_ascii=False, indent=2)
    
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
        w = Widget()
        w.show()
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    QLineEdit 示例:

    from dataclasses import dataclass
    import sys
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    import sip
    
    
    @dataclass
    class Property:
        qobject: QtCore.QObject = None
        qproperty: str = ""
    
        @property
        def value(self):
            if self.qobject and not sip.isdeleted(self.qobject):
                return self.qobject.property(self.qproperty)
    
        @value.setter
        def value(self, value):
            if self.qobject and not sip.isdeleted(self.qobject):
                self.qobject.setProperty(self.qproperty, value)
    
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
        w = QtWidgets.QLineEdit()
    
        prop = Property(w, "text")
    
        # variable for test
        counter = 0
    
        def on_timeout():
            nonlocal counter
            print("text:", prop.value)
            counter += 1
            prop.value = counter
    
        timer = QtCore.QTimer(interval=1000, timeout=on_timeout)
        timer.start()
    
        w.show()
    
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

    • 感谢@eyllanesc,我使用了您的示例,并且能够使其在应用程序的某些部分工作,为了使其工作,我放弃了我制作的一些课程并将所有课程放在主课程上,其他部分不起作用是因为我需要使用 StringVar()、DoubleVar() 和 BooleanVar()。我认为我需要使用 QLineEdit 并从那里抓取文本,而不是使用 QSpinbox。当我在 tkinter 上使用 Vars 时,我将它们全部放在主类上,然后用控制器在其他类中抓取它们。你能帮我解决这个问题吗?谢谢
    • @Nuno 看来你还没有理解我的解决方案:1)在Qt中XVar不存在或将存在,所以你必须适应一些东西但它永远不会完美,2)我将添加一些示例,说明如何将我的解决方案用于某些类型的小部件,例如 QLineEdit(它不会涵盖所有 Qt 小部件,但它会让您了解如何使用它)
    • 我以前从未使用过数据类,我想我对类属性了解得更多,在第一个示例中,我将 QSpinbox 更改为 QLineEdit,将 qproperty 更改为“文本”并转换为 int 以用于一些功能,谢谢。
    猜你喜欢
    • 2011-06-05
    • 2018-08-29
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 2018-09-27
    相关资源
    最近更新 更多