How to rewrite this working C++ code in Rust (Qt, GUI, Borrow errors, lifetime errors)

Hello

This is what I want to do: I want a Qt-GUI application which has multiple uses/options. For example one option to add something to a database, another option to delete something from a database,...

On the startscreen of the application there are several buttons with the text 'Add to database', 'Delete from database',...
Clicking on a button deletes all the current labels and buttons in the window, and calls a function building new labels and buttons to for example add something to a database.

For this to work I basically need to be able to do the following things:

  • Having a sort of 'global variable', or being able to pass the same variable to the different build_functions by reference
  • Call the functions in the UserInterface class to build different userinterface-views

I was able to code this in C++:

#include <QApplication>
#include <QPushButton>
#include <QAbstractButton>
#include <QLabel>
#include <QFont>
#include <QVBoxLayout>
#include <QMessageBox>

//Class handling all the UI in this Application
class UserInterface {
    public:
        //Build the initial UI the user sees
        void build_start_screen(QWidget& window) {
            //Calling reset function to delete all the childs in QVBoxLayout
            this->reset(this->layout);

            //Make new QVBoxLayout for this startscreen UI
            this->layout = new QVBoxLayout(&window);

            //Label 'Cat Manager'
            QLabel* label_a = new QLabel();
            label_a->setText("Cat Manager");
            label_a->setFont(*new QFont("Sans Serif", 24, QFont::Bold));

            //Label 'Your favourite...'
            QLabel* label_b = new QLabel();
            label_b->setText("Your favourite application to manage your best friends!");
            label_b->setFont(*new QFont("Sans Serif", 16, QFont::Normal));
            
            //Button to go to Option A-screen
            QPushButton* option_a_btn = new QPushButton("Go option A");
            QObject::connect(option_a_btn, &QPushButton::clicked, [this, &window](){
                this->build_option_a_screen(window);
            });

            //Add labels and button to QVBoxLayout
            layout->addWidget(label_a);
            layout->addWidget(label_b);
            layout->addWidget(option_a_btn);
        }

        //Build the screen for option A
        void build_option_a_screen(QWidget& window) {
            //Call the reset function to delete all the childs in QVBoxLayout
            this->reset(this->layout);

            //Make new QVBoxLayout for this option a UI
            this->layout = new QVBoxLayout(&window);

            //Label 'Cat Manager'
            QLabel* label_a = new QLabel();
            label_a->setText("Rofllllllll");
            label_a->setFont(*new QFont("Sans Serif", 24, QFont::Bold));

            //Add label to QVBoxLayout
            layout->addWidget(label_a);
        }

    private:
        //Function to reset the layout
        void reset(QLayout* layout) {
            if (layout == nullptr)
                return;

            QLayoutItem* child;
            while (layout->count() > 0) {
                child = layout->takeAt(0);
                if (child->layout() != 0) {
                    reset(child->layout());
                } else if (child->widget() != 0) {
                    delete child->widget();
                }
                
                delete child;
            }

            delete layout;
        }

        //Properties
        QVBoxLayout* layout;
};

int main(int argc, char **argv) {
    QApplication app (argc, argv);
   
    //Initialize Window
    QWidget Window;
    Window.resize(400, 250);     

    //Create new UserInterface object
    //This will allow us to create different user-interfaces
    //depending on the function we call
    UserInterface* ui = new UserInterface();
    ui->build_start_screen(Window);
    Window.show();

    return app.exec();
}

As you can see I have one QWidget variable defined in the main-function called Window.
After the class UserInterface is initiated I pass that Window variable by reference to the function build_start_screen(). In that function different labels and buttons get added to a QVBoxLayout which is linked to Window. Now when option_btn_a gets clicked the related function for Option A gets executed and the Window variable gets passed with it as reference. Because I pass it as reference the Window will get altered by the new labels and options needed for the Option A screen.
QVBoxLayout variable 'layout' is a class property so it's also shared between the different functions in the class.

I tried to replicate this in Rust:

#![windows_subsystem = "windows"]

use qt_widgets::{
    cpp_core::{CppBox, MutPtr},
    qt_core::QString,
    qt_core::Slot,
    QApplication, QLineEdit, QMessageBox, QPushButton, QVBoxLayout, QWidget,
    QLabel,
    qt_gui::QFont,
    qt_core::QObject,
};

//Userinterface handling all the possible UserInterface-screens
//Each function is to build a specific userinterface (depending on e.g
//selected option)
struct UserInterface {
    layout: Option<CppBox<QVBoxLayout>>,
}
impl UserInterface {
    //Constructor
    pub fn new() -> UserInterface {
        UserInterface {
            layout: None,
        }
    }

    //Build the labels, buttons,... for the startscreen
    pub fn build_start_screen(&mut self, window: &mut CppBox<QWidget>) {
        unsafe {
            //Make the new QVBoxLayout for this UI
            self.layout = Some(QVBoxLayout::new_1a(window));

            //Big fat font
            let mut big_font : CppBox<QFont> = QFont::new();
            big_font.set_family(&QString::from_std_str("Sans Serif"));
            big_font.set_point_size(24);
            big_font.set_weight(400);

            //Label 'Cat Manager'
            let mut label_a : CppBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Cat Manager"));
            label_a.set_font(&big_font);

            //Label 'Your favourite...'
            let mut label_b : CppBox<QLabel> = QLabel::new();
            label_b.set_text(&QString::from_std_str("Your favourite application to manage your best friends!"));

            //Button to go to Option A-screen
            let mut option_a_btn : CppBox<QPushButton> = QPushButton::new();
            option_a_btn.set_text(&QString::from_std_str("Go option A"));
           
            //When button option_a_btn is clicked we need to toggle the screen
            //to the Option A-userinterface
            let option_a_btn_clicked = Slot::new(move || {
             // [BORROW ERROR]  self.build_option_a_screen(window);
            });
            option_a_btn.clicked().connect(&option_a_btn_clicked);

            //Add all the widgets to the layout
            //  [BORROW_ERROR]  self.layout.unwrap().add_widget(&mut label_a);
            //  [BORROW_ERROR]  self.layout.unwrap().add_widget(&mut label_b);
            //  [BORROW_ERROR]  self.layout.unwrap().add_widget(&mut option_a_btn);

        }
    }

    //Build labels, options,... for the screen which shows when Option A gets selected
    pub fn build_option_a_screen(&mut self, window: &mut CppBox<QWidget>) {
        unsafe {
            /*
            //Make the new QVBoxLayout for this UI
            self.layout = Some(QVBoxLayout::new_1a(window));

            //Label 'Cat Manager'
            let mut label_a : CppBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Option A selected!"));
          
            //  [BORROW_ERROR]  self.layout.unwrap().add_widget(&mut label_a);
            */
        }
    }

    pub fn reset(&mut self, layout: &mut CppBox<QVBoxLayout>) {
        /*
         * Function to remove all buttons, labels,.. from user interface
         * so other screen can be build on a clean window.
         */
    }
}

fn main() {
    QApplication::init(|_app| unsafe {
        let mut window : CppBox<QWidget> = QWidget::new_0a();
        //window.resize(400, 250);

        let mut ui : UserInterface = UserInterface::new();
        ui.build_start_screen(&mut window);

        window.show();

        QApplication::exec()
    })
}

This code will compile but will only display an empty window. This because I am not able to add labels to my QVBoxLayout, and am not able to launch another function from my struct when a button gets clicked with QWidget as parameter.

I marked the lines of code where the errors occur by labeling them with 'BORROW_ERROR' in the comments. When I uncomment those lines with BORROW_ERROR (e.g line 55 and 61) these are the errors:

error[E0382]: use of moved value: `window`
  --> src/main.rs:54:50
   |
28 |     pub fn build_start_screen(&mut self, window: &mut CppBox<QWidget>) {
   |                                          ------ move occurs because `window` has type `&mut cpp_core::cpp_box::CppBox<qt_widgets::QWidget>`, which does not implement the `Copy` trait
...
31 |             self.layout = Some(QVBoxLayout::new_1a(window));
   |                                                    ------ value moved here
...
54 |             let option_a_btn_clicked = Slot::new(move || {
   |                                                  ^^^^^^^ value used here after move
55 |              self.build_option_a_screen(window);
   |                                         ------ use occurs due to use in closure

error[E0507]: cannot move out of `self.layout` which is behind a mutable reference
  --> src/main.rs:60:13
   |
60 |             self.layout.unwrap().add_widget(&mut label_a);
   |             ^^^^^^^^^^^
   |             |
   |             move occurs because `self.layout` has type `std::option::Option<cpp_core::cpp_box::CppBox<qt_widgets::QVBoxLayout>>`, which does not implement the `Copy` trait
   |             help: consider borrowing the `Option`'s content: `self.layout.as_ref()`

error[E0382]: use of moved value: `self`
  --> src/main.rs:60:13
   |
28 |     pub fn build_start_screen(&mut self, window: &mut CppBox<QWidget>) {
   |                               --------- move occurs because `self` has type `&mut UserInterface`, which does not implement the `Copy` trait
...
54 |             let option_a_btn_clicked = Slot::new(move || {
   |                                                  ------- value moved into closure here
55 |              self.build_option_a_screen(window);
   |              ---- variable moved due to use in closure
...
60 |             self.layout.unwrap().add_widget(&mut label_a);
   |             ^^^^^^^^^^^ value used here after move

How do I fix these errors? How to rewrite the working C++ code in Rust? The lifetime/borrow things in Rust are causing my trouble to write a GUI.

Thanks!

PS.
Qmake.pro file for C++:

TEMPLATE += app
QT += gui widgets
SOURCES += main.cpp

Cargo.toml file for Rust:

[package]
name = "Qt-rs"
version = "0.1.0"
authors = ["ONiel"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
qt_core = "0.4.1"
qt_gui = "0.4.1"
qt_widgets = "0.4.1"
qt_ui_tools = "0.4.1"
qt_3d_core = "0.4.1"
qt_3d_render = "0.4.1"
qt_3d_input = "0.4.1"
qt_3d_logic = "0.4.1"
qt_3d_extras = "0.4.1"
qt_charts = "0.4.1"

cpp_core = "0.5.1"

Qt Version is 5.14.

I suppose you just need read manual about: Option in std::option - Rust

unwrap is defined like this:

unwrap(self) -> T

so to use it without destroying, you need convert it into something that you can destroy,
like self.layout.as_mut().unwrap().add_widget
but this looks like bad code, I mean bunch of unwrap,
why not use layout directly and only then convert it into Option.

1 Like

Okay thanks! I'm one step closer.
This line now compiles:

self.layout.as_mut().unwrap().add_widget(&mut label_a);

But the window is still empty even though I've added label_a?

And what exactly do you mean with 'using layout directly'? I've wrapped it in an Option because I had to initialize it to None in the constructor of UserInterface. How could I do that better than?

With current code like this:

//pub fn build_start_screen(&mut self, window: &mut CppBox<QWidget>)
 let mut layout = QVBoxLayout::new_1a(window);
 layout.add_widget(
 layout.add_widget(
 ...
 self.layout = Some(layout);

But I don't see why you need it, there is:

so you don't need to duplicate this as data member in your code.

1 Like

Okay thanks. I've implemented your tips and have removed the data member from the class. Now I use window.layout() to retrieve the QVBoxLayout.

It's linked to each other in my main like this:

        let mut window : CppBox<QWidget> = QWidget::new_0a();
        window.resize_2a(400, 250);

        let mut layout : CppBox<QVBoxLayout> = QVBoxLayout::new_1a(&mut window);

Function code:

    //Build the labels, buttons,... for the startscreen
    pub fn build_start_screen(&mut self, window: &mut CppBox<QWidget>) {
        unsafe {
            //Big fat font
            let mut big_font : CppBox<QFont> = QFont::new();
            big_font.set_family(&QString::from_std_str("Sans Serif"));
            big_font.set_point_size(24);
            big_font.set_weight(400);

            //Label 'Cat Manager'
            let mut label_a : CppBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Cat Manager"));
            label_a.set_font(&big_font);

            //Label 'Your favourite...'
            let mut label_b : CppBox<QLabel> = QLabel::new();
            label_b.set_text(&QString::from_std_str("Your favourite application to manage your best friends!"));

            //Button to go to Option A-screen
            let mut option_a_btn : CppBox<QPushButton> = QPushButton::new();
            option_a_btn.set_text(&QString::from_std_str("Go option A"));
           
            //When button option_a_btn is clicked we need to toggle the screen
            //to the Option A-userinterface
            let option_a_btn_clicked = Slot::new(move || {
                self.build_option_a_screen(window);
            });
            option_a_btn.clicked().connect(&option_a_btn_clicked);

            //Add all the widgets to the layout
            window.layout().add_widget(&mut label_a);
            //layout.add_widget(&mut label_b);
            //layout.add_widget(&mut option_a_btn);
            
            //self.layout = Some(layout);

        }
    }

Error:

error[E0382]: borrow of moved value: `window`
  --> src/main.rs:57:13
   |
28 |     pub fn build_start_screen(&mut self, window: &mut CppBox<QWidget>) {
   |                                          ------ move occurs because `window` has type `&mut cpp_core::cpp_box::CppBox<qt_widgets::QWidget>`, which does not implement the `Copy` trait
...
51 |             let option_a_btn_clicked = Slot::new(move || {
   |                                                  ------- value moved into closure here
52 |                 self.build_option_a_screen(window);
   |                                            ------ variable moved due to use in closure
...
57 |             window.layout().add_widget(&mut label_a);
   |             ^^^^^^ value borrowed here after move

I tried window.as_mut() to not let it get 'destroyed' but .as_mut() is not found for window.

The closure needs to have window moved into it, but you can't move it, since it's behind a reference (window: &mut CppBox<QWidget>). You can use as_mut_ptr to get a MutPtr<QWidget> and then move it into the closure instead.

            let window_ptr = window.as_mut_ptr();
            let option_a_btn_clicked = Slot::new(move || {
                self.build_option_a_screen(window_ptr);
            });

However, you will have the same issue with usage of self in the slot. If you really need to access the whole self in the slot, you will have to wrap it into Rc (or event Rc and RefCell) to allow shared access. Alternatively, find the specific fields the slot needs and move them into the closure instead of moving self.

1 Like

In Qt there is QPointer it is like Weak,
so I suppose you cat create QPointer for each QObject that should be used inside signal handler. Though I have no idea is there wrapper for QPointer in Rust binding.

1 Like

I was able to get the code running:

#![windows_subsystem = "windows"]

use qt_widgets::{
    cpp_core::{CppBox, MutPtr},
    qt_core::QString,
    qt_core::Slot,
    QApplication, QLineEdit, QMessageBox, QPushButton, QVBoxLayout, QWidget,
    QLabel,
    qt_gui::QFont,
    qt_core::QObject,
};

//Userinterface handling all the possible UserInterface-screens
//Each function is to build a specific userinterface (depending on e.g
//selected option)
struct UserInterface {
  //  layout: Option<CppBox<QVBoxLayout>>,
}
impl UserInterface {
    //Constructor
    pub fn new() -> UserInterface {
        UserInterface {
//            layout: None,
        }
    }

    //Build the labels, buttons,... for the startscreen
    pub fn build_start_screen(&mut self, window: cpp_core::MutPtr<QWidget>) {
        unsafe {
            //Big fat font
            let mut big_font : CppBox<QFont> = QFont::new();
            big_font.set_family(&QString::from_std_str("Sans Serif"));
            big_font.set_point_size(24);
            big_font.set_weight(400);

            //Label 'Cat Manager'
            let mut label_a : CppBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Cat Manager"));
            label_a.set_font(&big_font);

            //Label 'Your favourite...'
            let mut label_b : CppBox<QLabel> = QLabel::new();
            label_b.set_text(&QString::from_std_str("Your favourite application to manage your best friends!"));

            //Button to go to Option A-screen
            let mut option_a_btn : CppBox<QPushButton> = QPushButton::new();
            option_a_btn.set_text(&QString::from_std_str("Go option A"));
           
            //When button option_a_btn is clicked we need to toggle the screen
            //to the Option A-userinterface
            //let window_ptr = window.as_mut_ptr();
            let option_a_btn_clicked = Slot::new(move || {
                self.build_option_a_screen(window);
            });
            option_a_btn.clicked().connect(&option_a_btn_clicked);

            //Add all the widgets to the layout
            window.layout().add_widget(&mut label_a);
            //layout.add_widget(&mut label_b);
            //layout.add_widget(&mut option_a_btn);
            
            //self.layout = Some(layout);

        }
    }

    //Build labels, options,... for the screen which shows when Option A gets selected
    pub fn build_option_a_screen(&mut self, window: cpp_core::MutPtr<QWidget>) {
        unsafe {
            /*
            //Make the new QVBoxLayout for this UI
            self.layout = Some(QVBoxLayout::new_1a(window));

            //Label 'Cat Manager'
            let mut label_a : CppBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Option A selected!"));
          
            //  [BORROW_ERROR]  self.layout.unwrap().add_widget(&mut label_a);
            */
        }
    }

    pub fn reset(&mut self, layout: &mut CppBox<QVBoxLayout>) {
        /*
         * Function to remove all buttons, labels,.. from user interface
         * so other screen can be build on a clean window.
         */
    }
}

fn main() {
    QApplication::init(|_app| unsafe {
        let mut window : CppBox<QWidget> = QWidget::new_0a();
        window.resize_2a(400, 250);

        let mut layout : CppBox<QVBoxLayout> = QVBoxLayout::new_1a(&mut window);

        let mut ui : UserInterface = UserInterface::new();
        let window_ptr = window.as_mut_ptr();
        ui.build_start_screen(window_ptr);

        window.show();

        QApplication::exec()
    })
}

However, it just shows an empty blank window... I've added a label on line 58 though!

QPointer is not currently available from Rust. For now, you can just use MutPtr, but you'll have to manually ensure that the referred object is still alive when you access it.In the next rust_qt release, QPointer-based pointers (QPtr and QBox) will become the default way to deal with QObject-based objects, so tracking alive and dead pointers will become easier.

Your label is stored in a CppBox, which will delete it when dropped, so when build_start_screen() ends, the label is destroyed. You should prevent this by using into_ptr:

window.layout().add_widget(label_a.into_ptr());

This also applies to any other objects you create locally. This ergonomic flaw will also be solved by the introduction of QBox in the next release.

1 Like

Okay, thank a lot for the help so far!

I'm close. The only thing I'm still struggling with is resetting the layout (See reset function. I'm trying to mimic the delete keyword from C++ by using drop(). To delete all children in the layout).

Next for some reason when I call build_option_a_screen() the label defined and added to the layout in that function is not displayed. I've used into_ptr() though like you said.

#![windows_subsystem = "windows"]

use qt_widgets::{
    cpp_core::{CppBox, MutPtr},
    qt_core::QString,
    qt_core::Slot,
    QApplication, QLineEdit, QMessageBox, QPushButton, QVBoxLayout, QWidget,
    QLabel,
    qt_gui::QFont,
    qt_core::QObject,
    QLayoutItem,
};

//Userinterface handling all the possible UserInterface-screens
//Each function is to build a specific userinterface (depending on e.g
//selected option)
struct UserInterface {
  //  layout: Option<CppBox<QVBoxLayout>>,
}
impl UserInterface {
    //Constructor
    pub fn new() -> UserInterface {
        UserInterface {
//            layout: None,
        }
    }

    //Build the labels, buttons,... for the startscreen
    pub fn build_start_screen(&mut self, window: cpp_core::MutPtr<QWidget>) {
        unsafe {
            //Big fat font
            let mut big_font : CppBox<QFont> = QFont::new();
            big_font.set_family(&QString::from_std_str("Sans Serif"));
            big_font.set_point_size(24);
            big_font.set_weight(400);

            //Label 'Cat Manager'
            let mut label_a : CppBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Cat Manager"));
            label_a.set_font(&big_font);

            //Label 'Your favourite...'
            let mut label_b : CppBox<QLabel> = QLabel::new();
            label_b.set_text(&QString::from_std_str("Your favourite application to manage your best friends!"));

            //Button to go to Option A-screen
            let mut option_a_btn : CppBox<QPushButton> = QPushButton::new();
            option_a_btn.set_text(&QString::from_std_str("Go option A"));
           
            //When button option_a_btn is clicked we need to toggle the screen
            //to the Option A-userinterface
            //let window_ptr = window.as_mut_ptr();
            let option_a_btn_clicked = Slot::new(move || {
                self.build_option_a_screen(window);
            });
            option_a_btn.clicked().connect(&option_a_btn_clicked);

            //Add all the widgets to the layout
            window.layout().add_widget(label_a.into_ptr());
            window.layout().add_widget(label_b.into_ptr());
            window.layout().add_widget(option_a_btn.into_ptr());
            
            //self.layout = Some(layout);

        }
    }

    //Build labels, options,... for the screen which shows when Option A gets selected
    pub fn build_option_a_screen(&mut self, window: cpp_core::MutPtr<QWidget>) {
        unsafe {
            self.reset(window);

            //Label 'Cat Manager'
            let mut label_a : CppBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Option A selected!"));
          
            window.layout().add_widget(label_a.into_ptr());
        }
    }

    pub fn reset(&mut self, window: cpp_core::MutPtr<QWidget>) {
        unsafe {
            while (window.layout().count() > 0) {
                let child : cpp_core::MutPtr<QLayoutItem> = window.layout().take_at(0);
                std::mem::drop(child);
            }

        
        }
    }
}

fn main() {
    QApplication::init(|_app| unsafe {
        let mut window : CppBox<QWidget> = QWidget::new_0a();
        window.resize_2a(400, 250);

        let mut layout : CppBox<QVBoxLayout> = QVBoxLayout::new_1a(&mut window);

        let mut ui : UserInterface = UserInterface::new();
        let window_ptr = window.as_mut_ptr();
        ui.build_start_screen(window_ptr);

        window.show();

        QApplication::exec()
    })
}

You can use QObject::deleteLater. But this is really strange code, why you don't use QStackedLayout Class | Qt Widgets 5.15.10 or QStackedWidget Class | Qt Widgets 5.15.10 , so for each screen you will have one parent widget, and you need remove one widget when screen changed ? I suppose QStackedWiget/QStackedLayout were designed just for case like this.

In a real application I'd use a stackedlayout for sure. But for now I was just experimenting a bit and trying to just convert that C++ code into rust to get the hang of pointers and references to complex objects in Rust.

I think there is a problem with line 53. It compiles, but the code won't execute when the button is clicked.

You can import the cpp_core::CppDeletable trait and call object.delete() to delete the object explicitly. drop on MutPtr doesn't do anything because it's a non-owning pointer and so it doesn't delete its content when dropped. Only CppBox deletes the object when dropped. Also note that QLayout::takeAt returns a QLayoutItem, and deleting a layout item doesn't delete the widget it contains. You would need to delete the widget as well.

The label is not added because build_option_a_screen function is not called at all. This is because you didn't store the Slot that calls it. When the scope ends, the slot object is deleted, so it won't invoke the closure anymore. You have to ensure the slot object is not deleted while you need it to work, but it also must not outlive the objects referenced by the closure (in this case, self). (Again, this will be improved in the next version where slots will be able to have parent QObjects that take care of their deletion.)

1 Like

Seems like the only option to do it than is to make a property in the UserInterface struct holding the slot? Or how'd I keep the Slot alive?

Tried this:

struct UserInterface {
  //  layout: Option<CppBox<QVBoxLayout>>,
    slot: Option<qt_core::Slot<'a>>,
}

but that causes a chain of lifetime errors...

That won't work because Slot references closure, which references self, so this would be a self-referential struct. The slot should have the 'static lifetime to avoid lifetime errors. But it can only have static lifetime if it doesn't borrow anything, so replacing self with an Rc seems to be the only practical way to do this.

An alpha version of the new release is out now, so I suggest you to try it out. The slot ergonomics have greatly improved there. Take a look at this example. It shows how to use self methods as slots.

The alpha version looks really nice and promising, but seems it ain't backward compatible.
I think that with that new release it's possible to code what I want though.

Code:

#![windows_subsystem = "windows"]

/*
use qt_widgets::{
    cpp_core::{QBox, Ptr},
    cpp_core,
    qt_core::QString,
    qt_core::slot, qt_core::SlotNoArgs,
    QApplication, QLineEdit, QMessageBox, QPushButton, QVBoxLayout, QWidget,
    QLabel,
    qt_gui::QFont,
    qt_core::QObject,
    QLayoutItem,
    qt_core,
};

use std::rc::Rc;
*/


use cpp_core::{Ptr, StaticUpcast};
use qt_core::{
    q_init_resource, qs, slot, CheckState, ItemDataRole, QBox, QObject, QPtr,
    QSortFilterProxyModel, SlotNoArgs, QString,
};
use qt_gui::{QStandardItem, QStandardItemModel, QFont};
use qt_ui_tools::ui_form;
use qt_widgets::{QApplication, QListView, QPushButton, QRadioButton, QWidget, QLabel, QLayoutItem, QVBoxLayout, };
use std::collections::BTreeSet;
use std::rc::Rc;



//Userinterface handling all the possible UserInterface-screens
//Each function is to build a specific userinterface (depending on e.g
//selected option)
struct UserInterface {
  //  layout: Option<QBox<QVBoxLayout>>,
  //  slot: Option<qt_core::slot>,
   // switch_btn: Option<>
}
impl UserInterface {
    //Constructor
    pub fn new() -> Rc<Self> {
        Rc::new(UserInterface {
//            layout: None,
//            slot: None,
        })
    }

    //Build the labels, buttons,... for the startscreen
    pub fn build_start_screen(self: Rc<Self>, window: cpp_core::Ptr<QWidget>) {
        unsafe {
            //Big fat font
            let mut big_font = QFont::new();
            big_font.set_family(&QString::from_std_str("Sans Serif"));
            big_font.set_point_size(24);
            big_font.set_weight(400);

            //Label 'Cat Manager'
            let mut label_a : QBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Cat Manager"));
            label_a.set_font(&big_font);

            //Label 'Your favourite...'
            let mut label_b : QBox<QLabel> = QLabel::new();
            label_b.set_text(&QString::from_std_str("Your favourite application to manage your best friends!"));

            //Button to go to Option A-screen
            let mut option_a_btn : QBox<QPushButton> = QPushButton::new();
            option_a_btn.set_text(&QString::from_std_str("Go option A"));
           
            //self.slot = option_a_btn_clicked;
            option_a_btn.clicked().connect(&self.option_a_btn_clicked(window));
            

            //Add all the widgets to the layout
            window.layout().add_widget(label_a.into_ptr());
            window.layout().add_widget(label_b.into_ptr());
            window.layout().add_widget(option_a_btn.into_ptr());
            
            //self.layout = Some(layout);

        }
    }

    //Build labels, options,... for the screen which shows when Option A gets selected
    pub fn build_option_a_screen(&mut self, window: cpp_core::Ptr<QWidget>) {
        unsafe {
            self.reset(window);

            //Label 'Cat Manager'
            let mut label_a : QBox<QLabel> = QLabel::new();
            label_a.set_text(&QString::from_std_str("Option A selected!"));
          
            window.layout().add_widget(label_a.into_ptr());
        }
    }

    pub fn reset(&mut self, window: cpp_core::Ptr<QWidget>) {
        unsafe {
            while window.layout().count() > 0 {
                //Following gives a funny Error:
                //let child : cpp_core::ptr::Ptr<QLayoutItem> = window.layout().take_at(0);
                let child = window.layout().take_at(0);
                window.layout().delete_later();
            }

        
        }
    }

    //OnClick Function
    #[slot(SlotNoArgs)]
    unsafe fn option_a_btn_clicked(self: &Rc<Self>, window: cpp_core::Ptr<QWidget>) {
        self.build_option_a_screen(window);
    }
}   

fn main() {
    QApplication::init(|_app| unsafe {
        let mut window : QBox<QWidget> = QWidget::new_0a();
        window.resize_2a(400, 250);

        let mut layout : QBox<QVBoxLayout> = QVBoxLayout::new_1a(&mut window);

        let mut ui : Rc<UserInterface> = UserInterface::new();
        let window_ptr = window.as_raw_ptr();
        ui.build_start_screen(window_ptr);

        window.show();

        QApplication::exec()
    })
}

Tons of errors:

   Compiling Qt-rs2 v0.1.0 (/Users/niel/School/Rust/rust_gui/Qt-rs2)
warning: unused imports: `Ptr`, `StaticUpcast`
  --> src/main.rs:21:16
   |
21 | use cpp_core::{Ptr, StaticUpcast};
   |                ^^^  ^^^^^^^^^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: unused imports: `CheckState`, `ItemDataRole`, `QObject`, `QPtr`, `QSortFilterProxyModel`, `q_init_resource`, `qs`
  --> src/main.rs:23:5
   |
23 |     q_init_resource, qs, slot, CheckState, ItemDataRole, QBox, QObject, QPtr,
   |     ^^^^^^^^^^^^^^^  ^^        ^^^^^^^^^^  ^^^^^^^^^^^^        ^^^^^^^  ^^^^
24 |     QSortFilterProxyModel, SlotNoArgs, QString,
   |     ^^^^^^^^^^^^^^^^^^^^^

warning: unused imports: `QStandardItemModel`, `QStandardItem`
  --> src/main.rs:26:14
   |
26 | use qt_gui::{QStandardItem, QStandardItemModel, QFont};
   |              ^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^

warning: unused import: `qt_ui_tools::ui_form`
  --> src/main.rs:27:5
   |
27 | use qt_ui_tools::ui_form;
   |     ^^^^^^^^^^^^^^^^^^^^

warning: unused imports: `QLayoutItem`, `QListView`, `QRadioButton`
  --> src/main.rs:28:32
   |
28 | use qt_widgets::{QApplication, QListView, QPushButton, QRadioButton, QWidget, QLabel, QLayoutItem, QVBoxLayout, };
   |                                ^^^^^^^^^               ^^^^^^^^^^^^                   ^^^^^^^^^^^

warning: unused import: `std::collections::BTreeSet`
  --> src/main.rs:29:5
   |
29 | use std::collections::BTreeSet;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0277]: the trait bound `&(): qt_core::connect::AsReceiver` is not satisfied
  --> src/main.rs:74:44
   |
74 |             option_a_btn.clicked().connect(&self.option_a_btn_clicked(window));
   |                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `qt_core::connect::AsReceiver` is not implemented for `&()`

error[E0277]: the trait bound `cpp_core::ptr::Ptr<qt_core::QObject>: cpp_core::convert::CastFrom<cpp_core::ptr::Ptr<UserInterface>>` is not satisfied
      --> src/main.rs:114:5
       |
114    |     #[slot(SlotNoArgs)]
       |     ^^^^^^^^^^^^^^^^^^^ the trait `cpp_core::convert::CastFrom<cpp_core::ptr::Ptr<UserInterface>>` is not implemented for `cpp_core::ptr::Ptr<qt_core::QObject>`
       |
      ::: /Users/niel/.cargo/registry/src/github.com-1ecc6299db9ec823/qt_core-0.5.0-alpha.2/src/lib.rs:249066:22
       |
249066 |         parent: impl ::cpp_core::CastInto<::cpp_core::Ptr<crate::QObject>>,
       |                      ----------------------------------------------------- required by this bound in `qt_core::SlotNoArgs::new`
       |
       = help: the following implementations were found:
                 <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<&'a cpp_core::cpp_box::CppBox<U>>>
                 <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<&'a qt_core::q_box::QBox<U>>>
                 <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<&'a qt_core::q_ptr::QPtr<U>>>
                 <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<*const U>>
               and 5 others
       = note: required because of the requirements on the impl of `cpp_core::convert::CastInto<cpp_core::ptr::Ptr<qt_core::QObject>>` for `cpp_core::ptr::Ptr<UserInterface>`

error[E0593]: closure is expected to take 0 arguments, but it takes 1 argument
   --> src/main.rs:114:5
    |
114 |     #[slot(SlotNoArgs)]
    |     ^^^^^^^^^^^^^^^^^^^
    |     |
    |     expected closure that takes 0 arguments
    |     takes 1 argument

error[E0277]: the trait bound `cpp_core::ptr::Ptr<qt_widgets::QWidget>: cpp_core::convert::CastFrom<&mut qt_core::q_box::QBox<qt_widgets::QWidget>>` is not satisfied
     --> src/main.rs:125:46
      |
125   |         let mut layout : QBox<QVBoxLayout> = QVBoxLayout::new_1a(&mut window);
      |                                              ^^^^^^^^^^^^^^^^^^^ the trait `cpp_core::convert::CastFrom<&mut qt_core::q_box::QBox<qt_widgets::QWidget>>` is not implemented for `cpp_core::ptr::Ptr<qt_widgets::QWidget>`
      |
     ::: /Users/niel/.cargo/registry/src/github.com-1ecc6299db9ec823/qt_widgets-0.5.0-alpha.2/src/lib.rs:38163:22
      |
38163 |         parent: impl ::cpp_core::CastInto<::cpp_core::Ptr<crate::QWidget>>,
      |                      ----------------------------------------------------- required by this bound in `qt_widgets::QVBoxLayout::new_1a`
      |
      = help: the following implementations were found:
                <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<&'a cpp_core::cpp_box::CppBox<U>>>
                <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<&'a qt_core::q_box::QBox<U>>>
                <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<&'a qt_core::q_ptr::QPtr<U>>>
                <cpp_core::ptr::Ptr<T> as cpp_core::convert::CastFrom<*const U>>
              and 5 others
      = note: required because of the requirements on the impl of `cpp_core::convert::CastInto<cpp_core::ptr::Ptr<qt_widgets::QWidget>>` for `&mut qt_core::q_box::QBox<qt_widgets::QWidget>`

error[E0308]: mismatched types
   --> src/main.rs:129:31
    |
129 |         ui.build_start_screen(window_ptr);
    |                               ^^^^^^^^^^ expected struct `cpp_core::ptr::Ptr`, found *-ptr
    |
    = note:   expected struct `cpp_core::ptr::Ptr<qt_widgets::QWidget>`
            found raw pointer `*const qt_widgets::QWidget`

error: aborting due to 5 previous errors

Some errors have detailed explanations: E0277, E0308, E0593.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `Qt-rs2`.

To learn more, run the command again with --verbose.

Cargo.toml:

[package]
name = "Qt-rs2"
version = "0.1.0"
authors = ["Niel"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
qt_widgets = "0.5.0-alpha.2"
qt_core = "0.5.0-alpha.2"
cpp_core = "0.5.0-alpha.2"
qt_ui_tools = "0.5.0-alpha.2"
qt_gui = "0.5.0-alpha.2"


Tried fixing those errors but that seems a lost effort/impossible mission.
Next week I'll try to do the same starting from scratch and by basing me more on the example you posted.

But I don't know man... It's really a thousand times more complicated than C++.

Working code for people with the same question reading this thread via Google:

Related questions:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.