rust-qt / ritual

Use C++ libraries from Rust
Apache License 2.0
1.24k stars 49 forks source link

attempt at "Hello World!" #57

Closed vandenoever closed 5 years ago

vandenoever commented 7 years ago

I've tried writing a hello world application that shows a message box with 'Hello World!".

Here is the code:

extern crate cpp_utils;
extern crate libc;
extern crate qt_core;
extern crate qt_widgets;

use libc::c_char;
use qt_core::byte_array::ByteArray;
use qt_core::object::Object;
use cpp_utils::StaticCast;
use qt_core::string::String;
use qt_widgets::application::Application;
use qt_widgets::message_box::MessageBox;

/// convert a Rust string to a QString
fn create_string(str: &str) -> String {
    let mut bytearray = ByteArray::new(());
    for b in str.as_bytes() {
        bytearray.append(*b as c_char);
    }
    String::from_utf8(&bytearray)
}

/// connect a signal to a slot
fn connect<A, B>(sender: &mut A, signal: &str, receiver: &mut B, slot: &str)
    where A: StaticCast<Object>,
          B: StaticCast<Object>
{
    let a: *const Object = sender.static_cast_mut();
    let b = receiver.static_cast_mut();
    let si = signal.as_ptr() as *const i8;
    let sl = slot.as_ptr() as *const i8;
    unsafe {
        b.connect((a, si, sl));
    }
}

fn main() {
    Application::create_and_exit(|app| {
        let mut msg_box = MessageBox::new(());
        msg_box.set_text(&create_string("Hello World!"));
        connect(&mut *msg_box,
                "SIGNAL(accepted())",
                &mut *app,
                "SLOT(quit())");
        msg_box.show();
        Application::exec()
    })
}

The signal and slot are not connected. This is the error message on the command-line:

QObject::connect: Use the SIGNAL macro to bind QMessageBox::SIGNAL(accepted())SLOT(quit())
o01eg commented 6 years ago
fn connect<A, B>(sender: &mut A, signal: &str, receiver: &mut B, slot: &str)
...
    let si = signal.as_ptr() as *const i8;

signal and slot are not zero-terminated strings. Could you check if using std::ffi::CString helps?

Riateche commented 6 years ago

The connect function refuses to work because the signal and slot specifiers are incorrect. They should be "2accepted()" and "1quit()" because that's what SIGNAL() and SLOT() macros do:

# define SLOT(a)     qFlagLocation("1"#a QLOCATION)
# define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)

And indeed, Rust strings are not null terminated, so you would need to either use CString or write a null terminated literal, e.g. b"2accepted()\0".

Note that cpp_to_rust generates high-level API for connections. You can see an example at variant_animation2.rs. So there is no need to construct signal and slot specifiers manually.

There are also conversion functions between qt_core::string::String and std::string (called from_std_str and to_std_string).