1 个不稳定版本
0.1.0 | 2023年7月28日 |
---|
#277 in #widgets
13KB
133 代码行
qt-cb
为 rust-qt 提供了多个便利的回调函数。
理由
尽管 Qt 的信号和槽机制非常强大,允许编写非常动态的代码和编程模型,但并非总是需要,尤其是对于简单的功能。
在 C++ 和 Rust 中,定义信号和槽有时可能变得冗长,Qt 本身也支持在 C++ 端使用 lambda 函数。
例如,比较以下两个程序的可读性和编写舒适性。这两个程序执行相同的功能,第一个程序没有使用回调,它为所需的信号定义了槽。第二个程序使用了这个包,并使用回调而不需要在单独的对象中定义槽,也不需要 derive SlotNoArgs/SlotOfBool/SlotOfQString 等样板代码。
第一个程序(无回调)
// no callbacks
use cpp_core::{Ptr, Ref, StaticUpcast};
use qt_core::{qs, slot, QBox, QObject, QString, SlotNoArgs, SlotOfBool, SlotOfQString};
use qt_widgets::{
QApplication, QCheckBox, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, QWidget,
};
use std::rc::Rc;
struct Form {
win: QBox<QWidget>,
ed: QBox<QLineEdit>,
checkbox: QBox<QCheckBox>,
button: QBox<QPushButton>,
}
impl StaticUpcast<QObject> for Form {
unsafe fn static_upcast(ptr: Ptr<Self>) -> Ptr<QObject> {
ptr.win.as_ptr().static_upcast()
}
}
impl Form {
fn new() -> Rc<Form> {
unsafe {
let win = QWidget::new_0a();
win.set_fixed_size_2a(400, 300);
let vbox = QVBoxLayout::new_1a(&win);
let ed = QLineEdit::new();
ed.set_placeholder_text(&qs("Enter name"));
vbox.add_widget(&ed);
let hbox = QHBoxLayout::new_0a();
vbox.add_layout_1a(&hbox);
let checkbox = QCheckBox::new();
hbox.add_widget(&checkbox);
checkbox.set_text(&qs("Check me!"));
let button = QPushButton::new();
hbox.add_widget(&button);
button.set_text(&qs("Greet!"));
win.show();
let this = Rc::new(Self {
win,
ed,
checkbox,
button,
});
this.init();
this
}
}
unsafe fn init(self: &Rc<Self>) {
self.ed
.text_changed()
.connect(&self.slot_on_lineedit_text_changed());
self.button
.pressed()
.connect(&self.slot_on_button_pressed());
self.checkbox
.clicked()
.connect(&self.slot_on_checkbox_clicked());
}
#[slot(SlotNoArgs)]
unsafe fn on_button_pressed(self: &Rc<Self>) {
println!("Hello {}", self.ed.text().to_std_string());
}
#[slot(SlotOfBool)]
unsafe fn on_checkbox_clicked(self: &Rc<Self>, checked: bool) {
println!(
"{} is {}checked",
self.checkbox.text().to_std_string(),
if checked { "" } else { "un" }
);
}
#[slot(SlotOfQString)]
unsafe fn on_lineedit_text_changed(self: &Rc<Self>, txt: Ref<QString>) {
println!("current lineedit text: {}", txt.to_std_string());
}
}
fn main() {
QApplication::init(|_| unsafe {
let _form = Form::new();
QApplication::exec()
})
}
第二个程序(有回调)
// with callbacks
use qt_cb::prelude::*;
use qt_core::qs;
use qt_widgets::{
QApplication, QCheckBox, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, QWidget,
};
fn main() {
QApplication::init(|_| unsafe {
QApplication::set_style_q_string(&qs("Fusion"));
let win = QWidget::new_0a();
win.set_fixed_size_2a(400, 300);
let vbox = QVBoxLayout::new_1a(&win);
let ed = QLineEdit::new();
ed.set_placeholder_text(&qs("Enter name"));
ed.on_text_changed(|_ed, txt| {
println!("current lineedit text: {}", txt.to_std_string());
});
vbox.add_widget(&ed);
let hbox = QHBoxLayout::new_0a();
vbox.add_layout_1a(&hbox);
let checkbox = QCheckBox::new();
hbox.add_widget(&checkbox);
checkbox.set_text(&qs("Check me!"));
checkbox.on_clicked(|b, checked| {
println!(
"{} is {}checked",
b.text().to_std_string(),
if checked { "" } else { "un" }
);
});
let button = QPushButton::new();
hbox.add_widget(&button);
button.set_text(&qs("Greet!"));
button.on_pressed(move |_b| {
println!("Hello {}", ed.text().to_std_string());
});
win.show();
QApplication::exec()
})
}
注意
ed.on_text_changed(|_ed, txt| {
println!("current lineedit text: {}", txt.to_std_string());
});
checkbox.on_clicked(|b, checked| {
println!(
"{} is {}checked",
b.text().to_std_string(),
if checked { "" } else { "un" }
);
});
button.on_pressed(move |_b| {
println!("Hello {}", ed.text().to_std_string());
});
而不是
self.ed
.text_changed()
.connect(&self.slot_on_lineedit_text_changed());
self.button
.pressed()
.connect(&self.slot_on_button_pressed());
self.checkbox
.clicked()
.connect(&self.slot_on_checkbox_clicked());
#[slot(SlotNoArgs)]
unsafe fn on_button_pressed(self: &Rc<Self>) {
println!("Hello {}", self.ed.text().to_std_string());
}
#[slot(SlotOfBool)]
unsafe fn on_checkbox_clicked(self: &Rc<Self>, checked: bool) {
println!(
"{} is {}checked",
self.checkbox.text().to_std_string(),
if checked { "" } else { "un" }
);
}
#[slot(SlotOfQString)]
unsafe fn on_lineedit_text_changed(self: &Rc<Self>, txt: Ref<QString>) {
println!("current lineedit text: {}", txt.to_std_string());
}
使用方法
[dependencies]
qt-cb = "0.1.0"
# the rest of the dependencies or rust-qt
需求
此包需要 C++17 编译器和可以从您的 shell 中调用的 qmake 可执行文件(即在 PATH 中)。安装 Qt5(基本上与 rust-qt 的要求相同)。rust-qt 还需要 CMake。在 Linux 上,您可以通过包管理器安装 Qt(假设使用 Debian)
sudo apt-get install -y qtbase5-dev libqt5widgets5
在 Windows msys2/mingw64 上
pacman -S $MINGW_PACKAGE_PREFIX-qt5-base
无运行时依赖
~195KB