第一步:
安装qt,需要使用其中的qmake,将qmake路径放置环境变量中。
如果vscode或者idea中的终端不识别qmake但是在系统的powershell中可以,注意使用管理模式运行
第二步:创建rust项目
cargo new qt_rust_dome
第三步:在项目中创建build.rs
use semver::Version; fn main() { eprintln!("cargo:warning={:?}", std::env::vars().collect::<Vec<_>>()); let qt_include_path = std::env::var("DEP_QT_INCLUDE_PATH").unwrap(); let qt_library_path = std::env::var("DEP_QT_LIBRARY_PATH").unwrap(); let qt_version = std::env::var("DEP_QT_VERSION") .unwrap() .parse::<Version>() .expect("Parsing Qt version failed"); let mut config = cpp_build::Config::new(); if cfg!(target_os = "macos") { config.flag("-F"); config.flag(&qt_library_path); } if qt_version >= Version::new(6, 0, 0) { config.flag_if_supported("-std=c++17"); config.flag_if_supported("/std:c++17"); } config.include(&qt_include_path).build("src/lib.rs"); for minor in 7..=15 { if qt_version >= Version::new(5, minor, 0) { println!("cargo:rustc-cfg=qt_{}_{}", 5, minor); } } let mut minor = 0; while qt_version >= Version::new(6, minor, 0) { println!("cargo:rustc-cfg=qt_{}_{}", 6, minor); minor += 1; } }
第四步:修改Cargo.toml
[package] name = "qml_rust_dome" version = "0.1.0" edition = "2018" build="build.rs" // 注意这句话要添加上 [dependencies] qmetaobject="*" // qmetaobject qttypes = { version = "0.2.2", features = [ "qtquick" ] } cstr="0.2" cpp = "0.5" [build-dependencies] cpp_build = "0.5" // 部分内容需要cpp编译? semver="1.0.3"
第五步:创建qml文件
//main.qml import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 //这里引入模板 import Greeter 1.0 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") //写一个qml的信号 signal qml_Signal_btnTest_Clicked() Button { id: btnTest x: 251 y: 187 text: qsTr("btnTest") onClicked: { // 使用rust中的Greeter qobj.name="btnTest set the name" console.log("qml 调用Greeter中的add函数返回:",qobj.add(10,20)) // Greeter中的方法 qml_Signal_btnTest_Clicked() //qml发送信号,Greeter接收 } } //定义qml中的槽函数 function slot_name_changed(){ console.log(‘qml slot_name_changed 收到 onSignal_name_changed 的信号‘) } Greeter{ id:qobj // 可以如此关联信号和槽,也可以在Component.onCompleted中关联 // 如果同时关联,就同时执行 onSignal_name_changed:{ console.log(‘qml Greeter组件收到 onSignal_name_changed 信号‘) } } //组件加载完成后 关联信号和槽 Component.onCompleted: { //Qml对象的信号关联到Greeter的槽函数 qml_Signal_btnTest_Clicked.connect(qobj.slot_btnTest_Clicked) //把Greeter的信号关联到Qml qobj.onSignal_name_changed.connect(slot_name_changed) } }
最后main.rs
//main.rs extern crate qmetaobject; use qmetaobject::*; use cstr::cstr; // 配置资源文件 // as前面的qml是文件目录,as后面的是虚拟路径 qrc!(my_resource, "qml" as "qml" { "main.qml", }, ); #[derive(QObject,Default)] struct Greeter{ //todo base是什么? base:qt_base_class!(trait QObject), // 定义一个属性,属性改变时发送 slot_name_changed 信号 name:qt_property!(QString; NOTIFY signal_name_changed), // 定义一个信号 signal_name_changed:qt_signal!(), // 定义一个槽 slot_btnTest_Clicked:qt_method!(fn slot_btnTest_Clicked(&self){ println!("--> slot_btnTest_Clicked:{}",self.name); }), // qml也可以直接调用 add:qt_method!(fn add(&self,a:i32,b:i32)->i32{ a+b }), } fn main() { // 注册资源文件 my_resource(); // 将Greeter注册到qml中 qml_register_type::<Greeter>(cstr!("Greeter"), 1, 0, cstr!("Greeter")); // 创建一个QML engine let mut engine=QmlEngine::new(); engine.load_file("qrc:/qml/main.qml".into()); engine.exec(); }