用于将字符串或其他非列表/树类型绑定到qt小部件的简单模型(mvvm样式)

用于将字符串或其他非列表/树类型绑定到qt小部件的简单模型(mvvm样式),qt,mvvm,garbage-collection,pyqt,signals-slots,Qt,Mvvm,Garbage Collection,Pyqt,Signals Slots,我上一次使用桌面gui编程的主要经验是以mvvm方式使用c#/wpf。我添加了一个不必在主线程上更改的可观察集合(它是通过使用锁定将调用转发到正常可观察集合的实例并在适当时在gui线程上运行来实现的)。我在viewmodel中使用的方法只影响viewmodel,而不是在gui事件处理程序中导航文件树。我真的很喜欢这样一个事实,即您可以将大部分gui代码本身包含在内,并且视图模型代码基本上是直接的,除了通过更新状态和发送更改事件之外,可以避免处理视图 我正在使用pyqt 4.6构建一个小型的自包含

我上一次使用桌面gui编程的主要经验是以mvvm方式使用c#/wpf。我添加了一个不必在主线程上更改的可观察集合(它是通过使用锁定将调用转发到正常可观察集合的实例并在适当时在gui线程上运行来实现的)。我在viewmodel中使用的方法只影响viewmodel,而不是在gui事件处理程序中导航文件树。我真的很喜欢这样一个事实,即您可以将大部分gui代码本身包含在内,并且视图模型代码基本上是直接的,除了通过更新状态和发送更改事件之外,可以避免处理视图

我正在使用pyqt 4.6构建一个小型的自包含(如果可能的话没有依赖项)应用程序(因此我认为qml不可用,而且qtwebkit似乎是另一个包中的一个应用程序,而不是安装在这些盒子上)。我感兴趣的是尝试以一种mvvm的方式将数据从ui中分离出来

我可以对列表和树模型使用qt模型/视图(setModel),但我不确定如何处理字符串/整数/其他值。该应用程序可能是相当静态的(中间没有消失的gui元素),但如果它变得更复杂(比如弹出窗口),我希望它不会因为内存泄漏而崩溃或内存使用爆炸。我有点不确定python gc如何与信号/插槽和qt的父/子内存清理交互

我正在编写的应用程序很小,因此最好使用较小的自包含解决方案(可能没有通用性/功能性)或可以从中提取/复制代码的小型bsd/mit库

这是我到目前为止所做的,尽管我有点不确定它是否没有bug

#!/usr/bin/python
#
from __future__ import print_function
from PyQt4 import QtCore
from PyQt4 import QtGui
import sys
from time import sleep

def identity_function(x):
    return x


def data_bind(model_get_prop, model_set_prop,
              get_widget_prop, set_widget_prop,
              model_prop_changed, window_prop_changed,
              transform_func=identity_function,
              transform_back_func=identity_function):
    set_widget_prop(transform_func(model_get_prop()))

    def set_m():
        if model_get_prop() != get_widget_prop():
            model_set_prop(transform_back_func(get_widget_prop()))
    window_prop_changed.connect(set_m)

    def set_w_prop():
        if get_widget_prop() != model_get_prop():
            set_widget_prop(transform_func(model_get_prop()))
    model_prop_changed.connect(set_w_prop)

class ValueModel(QtCore.QObject):
    model_changed = QtCore.pyqtSignal()

    def __init__(self, value):
        super(ValueModel, self).__init__()
        self.__value = value
    @property
    def value(self):
        return self.__value
    @value.setter
    def value(self, value):
        if self.__value != value:
            self.__value = value
            self.model_changed.emit()


def gui_main():
    app = QtGui.QApplication([])
    s_model = ValueModel("yo")

    w = QtGui.QWidget()
    vbox = QtGui.QVBoxLayout()

    t = QtGui.QTextEdit()
    vbox.addWidget(t)
    t2 = QtGui.QTextEdit()
    vbox.addWidget(t2)
    w.setLayout(vbox)
    data_bind(lambda: s_model.value, lambda v: setattr(s_model, 'value', v), t.toPlainText, t.setPlainText, s_model.model_changed, t.textChanged)
    data_bind(lambda: s_model.value, lambda v: setattr(s_model, 'value', v), t2.toPlainText, t2.setPlainText, s_model.model_changed, t2.textChanged)

    l1 = QtGui.QLineEdit()
    l2 = QtGui.QLineEdit()

    lm1 = ValueModel(2)
    lm2 = ValueModel(1)

    vbox.addWidget(l1)
    vbox.addWidget(l2)

    lm1.model_changed.connect(lambda: print("l1 + l2 is " + str(lm1.value+lm2.value)))
    lm2.model_changed.connect(lambda: print("l1 + l2 is " + str(lm1.value+lm2.value)))
    data_bind(lambda: lm1.value, lambda v: setattr(lm1, 'value', v), l1.text, l1.setText, lm1.model_changed, l1.textChanged, str, int)
    data_bind(lambda: lm2.value, lambda v: setattr(lm2, 'value', v), l2.text, l2.setText, lm2.model_changed, l2.textChanged, str, int)

    w.show()
    t.setText("a")
    print(s_model.value)
    sys.exit(app.exec_())

gui_main()

我想你想要的是
QDataWidgetMapper

简而言之,它允许您将模型列的值映射到小部件的显示属性(如标签或lineedit)。如果您更新小部件或模型中的值,则另一个将被更新

您还可以单步遍历模型的行,这将把所有映射的小部件更新为模型中下一行的内容(这可能比您需要的要多,所以您只需要在模型中有一行)


有关更多详细信息,请参阅Qt文档:

我认为您需要的是
QDataWidgetMapper

简而言之,它允许您将模型列的值映射到小部件的显示属性(如标签或lineedit)。如果您更新小部件或模型中的值,则另一个将被更新

您还可以单步遍历模型的行,这将把所有映射的小部件更新为模型中下一行的内容(这可能比您需要的要多,所以您只需要在模型中有一行)


有关更多详细信息,请参阅Qt文档:

我认为您需要的是
QDataWidgetMapper

简而言之,它允许您将模型列的值映射到小部件的显示属性(如标签或lineedit)。如果您更新小部件或模型中的值,则另一个将被更新

您还可以单步遍历模型的行,这将把所有映射的小部件更新为模型中下一行的内容(这可能比您需要的要多,所以您只需要在模型中有一行)


有关更多详细信息,请参阅Qt文档:

我认为您需要的是
QDataWidgetMapper

简而言之,它允许您将模型列的值映射到小部件的显示属性(如标签或lineedit)。如果您更新小部件或模型中的值,则另一个将被更新

您还可以单步遍历模型的行,这将把所有映射的小部件更新为模型中下一行的内容(这可能比您需要的要多,所以您只需要在模型中有一行)


有关更多详细信息,请参阅Qt文档:

此问题中有几个未完成的句子。你在问什么?这个问题有几个未完成的句子。你在问什么?这个问题有几个未完成的句子。你在问什么?这个问题有几个未完成的句子。你在问什么?