Python qml 实现跟py代码的双向绑定,类似wpf的mvvm和 vue的开发模式

学习pyqt第二天,研究了一整天这个模式,各种搜索,并没有太多这方面的资料!

经过自己不断的修改和试错。最终得出了这种方式,如果大家有更优的方式,希望大家能评论告诉我一下!

好,废话不多说,贴代码!首先是定义相当于WPF中ViewModel类,PYQT5和PYQT6代码一样

from PyQt6.QtQuick import QQuickView
from PyQt6.QtQml import qmlRegisterType,QQmlApplicationEngine
from PyQt6.QtCore import *
from PyQt6.QtCore import QCoreApplication, Qt, QUrl,pyqtProperty
from PyQt6.QtWidgets import QApplication
import sys 

#viewModel类,这边写属性以及窗体事件代码
class MainWindowViewModel(QObject):
    
    def __init__(self, parent=None):
        super().__init__(parent)

    #-------------定义属性开始-------------------

    #私有变量,用来操作和初始化值
    _userName = '我是初始值'

    #定义pyqtSignal,跟pyqtProperty的类型需要一直
    userNameChanged = pyqtSignal(str)

    #定义pyqtProperty属性,第一个是属性的类型,第二个是notify
    @pyqtProperty(str,notify=userNameChanged)
    def userName(self):
        return self._userName

    #定义属性改变事件,py代码改变属性值将调用这个方法
    @userName.setter
    def userName(self, value):
        self._userName = value
        #将属性值更新到qml中
        self.userNameChanged.emit(value)

    #-------------定义属性结束------------------------

    #-------------这边开始定义事件--------------------

    #使用pyqtSlot来定义返回值,如无返回值则可以不设置
    @pyqtSlot(result=str)
    def outputString(self):
        print(self.userName)
        return 'success'

    #带参数的事件或者方法,定义参数类型就行,可以有多个参数类型,需要与py方法的参数对应
    @pyqtSlot(str,int,result=str)
    #self是必须带上的,放在第一个
    def setString(self,name,val):
        self.userName='我被py代码改变'
        print(name+":"+ str(val))

    #-------------定义事件结束--------------------

然后在main函数中设置对象

if __name__ == '__main__':
    app = QApplication(sys.argv)

    #-------------------从这边开始设置-----------------------
    view = QQuickView()
    #实例化ViewModel类
    viewModel = MainWindowViewModel()

    context = view.rootContext()
    #将ViewModel绑定到qml代码中的viewModel变量,qml通过这个来调用相关属性和方法
    context.setContextProperty("viewModel",viewModel)
    
    view.setSource(QUrl('main.qml'))

    #-------------------到这边设置完成-----------------------

    view.engine().quit.connect(app.quit)
    #设置窗体标题
    view.setTitle('例子')
    view.show()

    sys.exit(app.exec())

接下来是QML的写法,这边属性的双向绑定我捉摸出了2种写法,大家自行选择就行

TextField {
                    id: txt_userName
                    placeholderText: "请输入账号"
                    color: "#D9000000"

                    //------------------------关键绑定代码开始-----------------------------


                    //这句话可以将qml属性值绑定到py变量
                    onEditingFinished: viewModel.userName=text
                    //这句代码py变量绑定到qml属性
                    text: viewModel.userName

                    /* 第二种写法
                    Binding {
                        property: "text"
                        target: txt_userName
                        value: viewModel.userName
                    }
                    Binding {
                        property: "userName"
                        target: viewModel
                        value: txt_userName.text
                    }
                    */


                    //------------------------关键绑定代码结束-----------------------------
                    width: 120
                    background: Rectangle
                    {
                        border.color: "#26000000"
                    }
            }
        }

接下来是事件的写法

Button {
        width: 60
        height: 30
        font.family: "Microsoft YaHei"
        text: "测试调用"
        //事件
        onClicked: {
            viewModel.outputString()
            //直接调用ViewModel中定义的方法就行
            viewModel.setString('设置参数', 1)
            //获取属性
            console.log(viewModel.userName)
        }
    }

以上就是我今天研究出来的方法,经过自己的多次测试与修改!

以下是我写的VsCode快捷代码片段,有需要的可以导入使用

{
	"qmlwindow": {
		"prefix": "qml",
		"body": [
			"import QtQuick 2.7",
			"import QtQuick.Window 2.0",
			"import QtQuick.Controls 2.5",
			"import QtQuick.Layouts 1.12",
			"",
			"Rectangle {",
			"   visible: true",
			"   $0",
			"}"

		],
		"description": "qml窗体控件代码"
	},
	"QMLPyFile": {
		"prefix": "qmlwindow",
		"body": [
			"from PyQt6.QtQuick import QQuickView",
			"from PyQt6.QtQml import qmlRegisterType,QQmlApplicationEngine",
		   "from PyQt6.QtCore import *",
		   "from PyQt6.QtCore import QCoreApplication, Qt, QUrl,pyqtProperty",
		   "from PyQt6.QtWidgets import QApplication",
		   "import sys ",
		   "",
		   "",
		   "class $1ViewModel(QObject):",
		   "    def __init__(self, parent=None):",
		   "        super().__init__(parent)",
		   "",
		   "   $0",
		   "",
		   "#-------------提示开始-------------------",
		   "#1、属性使用propqml",
		   "#2、事件使用eventqml",
		   "#-------------提示结束-------------------",
		   "",
		   "",
		   "",
		   "",
		   "if __name__ == '__main__':",
		   "    app = QApplication(sys.argv)",
		   "    view = QQuickView()",
		   "    viewModel = $1ViewModel()",
		   "    context = view.rootContext()",
		   "    context.setContextProperty(\"$2\",viewModel)",
		   "    view.setSource(QUrl('$3.qml'))",
		   "    view.engine().quit.connect(app.quit)",
		   "    view.setTitle('$4')",
		   "    view.show()",
		   "    sys.exit(app.exec())"
		],
		"description": "qml py代码"
	},
	"propqml": {
		"prefix": "propqml",
		"body": [
			"    _$1 = None",
			"    $1Changed = pyqtSignal($2)",
			"    @pyqtProperty($2,notify=$1Changed)",
			"    def $1(self):",
			"        return self._$1",
			"",
			"    @$1.setter",
			"    def $1(self, value):",
			"        self._$1 = value",
			"        self.$1Changed.emit(value)",
			"$0",
			"",
		],
		"description": "qml绑定属性"
	},
	"eventqml": {
		"prefix": "eventqml",
		"body": [
			"    @pyqtSlot(result=$1)",
			"    def $2(self):",
			"        $0",
		],
		"description": "qml绑定事件"
	},
}

转载请注明出处就行!

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值