Rust-qt project compiling issue

Hi,

i am trying to play with the "todo_list" example (https://github.com/rust-qt/examples/tree/master/widgets/todo_list) everything is working fine...but, if i try to add a "QFileDialog" or a "QMessageBox" to one of the slots, for instance :

#[slot(SlotNoArgs)]
    unsafe fn on_add_clicked(self: &Rc<Self>) {
        let filenames = QFileDialog::new();
        filenames.get_open_file_names_4a(None, &qs("Open files"), &qs("./"), &qs("Text files (*.s2p)"));
    }

then i get errors:

error[E0599]: no method named `get_open_file_names_4a` found for struct `QBox<QFileDialog>` in the current scope

63 |         filenames.get_open_file_names_4a(None, &qs("Open files"), &qs("./"), &qs("Python/Text files (*.s2p)"));

   |         ----------^^^^^^^^^^^^^^^^^^^^^^

   |         |         |

   |         |         this is an associated function, not a method

   |         help: use associated function syntax instead: `QFileDialog::get_open_file_names_4a`

The "basic_form" examples uses a "QMessageBox" and everything works fine, so i assume that my problem is that i load the "Form" (QtDesigner ui file) with the ui_tools.

What i am doing wrong here?

I am trying to get it work since two days but until now i did not find the solution...

I thank you very much for your help in advance.

Best Regards.
Olivier.

Did you try following the compiler's suggestion? Replace filenames.get_open_file_names_4a with QFileDialog::get_open_file_names_4a.

Hi,

yes i tried it but i get much stranger errors:

error[E0277]: the trait bound `Ptr<QWidget>: CastFrom<std::option::Option<_>>` is not satisfied

63    |         QFileDialog::get_open_file_names_4a(None, &qs("Open files"), &qs("./"), &qs("Python/Text files (*.s2p)"));

      |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `CastFrom<std::option::Option<_>>` is not implemented for `Ptr<QWidget>`

      |

     ::: C:\Users\o00474597\.cargo\registry\src\github.com-1ecc6299db9ec823\qt_widgets-0.5.0\src\lib.rs:55362:22

      |

55362 |         parent: impl ::cpp_core::CastInto<::cpp_core::Ptr<crate::QWidget>>,

      |                      ----------------------------------------------------- required by this bound in `QFileDialog::get_open_file_names_4a`

      |

      = help: the following implementations were found:

                <Ptr<T> as CastFrom<&'a CppBox<U>>>

                <Ptr<T> as CastFrom<&'a QBox<U>>>

                <Ptr<T> as CastFrom<&'a QPtr<U>>>

                <Ptr<T> as CastFrom<*const U>>

              and 5 others

      = note: required because of the requirements on the impl of `CastInto<Ptr<QWidget>>` for `std::option::Option<_>`

 

error: aborting due to previous error; 4 warnings emitted

Please read Forum Code Formatting and Syntax Highlighting and edit your prior post by using the pencil-shaped edit button under that post. Note that you can specify the language syntax to be used in highlighting by specifying the language at the end of the first row of three backticks. (Rust is the default language if you don't specify toml or c++ or something else.)

Many readers of this forum will ignore code snippets, compiler error reports, etc that do not follow the posting guidelines for new contributors that are pinned to the top of this forum. Even those who do respond may feel that the lack of following the forum posting guidelines is disrespectful of their time. Thanks. :clap:

Hi Tom,

I modified the format according to your recommendation.

Thank you!

Best Regards.
Olivier.

You should use NullPtr instead of None to specify null pointer as an argument. You can see all allowed argument types in the documentation of CastFrom. NullPtr is there, but Option<_> is not, so None cannot be used for an argument of type impl CastInto<_>.

1 Like

Thank you very much ! it's working :slight_smile:
I wish you a great weekend.
Best Regards.
Olivier.

Dear Riateche,

do you eventually have a Qthread working example?

I am stuck now since two weeks trying to do the following:

i try to create a worker (QObject with signal-slots) that i want to "move" into a Qthread.

It looks like this in C++:

class Worker1 : public QObject
{
    Q_OBJECT
public:
    Worker1();
    ~Worker1();

signals:
    void update_plot(std::vector<float>, std::vector<float>);
    void finished();

public slots:
    void doWork();
};

I need to be able to emit signals from the worker to the main thread (GUI) in order to update a QChart.

In C++ i would write somewhere in the main thread:

Thread1 = new QThread;
myWorker1 = new Worker1();
myWorker1->moveToThread(Thread1);

connect(Thread1, SIGNAL(started()), myWorker1, SLOT(doWork())); 

connect(myWorker1, SIGNAL(update_plot(std::vector<float>, std::vector<float>)), this, SLOT(PlotGraph(std::vector<float>, std::vector<float>))); SLOT(PlotGraph(QList<QPointF>)));

connect(myWorker1, SIGNAL(finished()), myWorker1, SLOT(deleteLater()));

connect(Thread1, SIGNAL(finished()), Thread1, SLOT(deleteLater()));

connect(myWorker1, SIGNAL(finished()), this, SLOT(ThreadDone()));

Thread1->start();

and the doWork() function would look like this:

void Worker1::doWork()
{
    while (true)
    {
        GetPoints(x, y);       
        emit update_plot(x,y);
    }
    emit finished();
    x.clear();
    y.clear();
    return;
}

Do you have or could you point me to such an Rust-Qt example?

I thank you very much in advance.
Best Regards.
Olivier.

There is no example for that yet, but it should be possible. The idea is to create a slot wrapper and move it to your thread. For emitting signals, you can use signal wrappers, as usual. Emitting signals in Qt is thread-safe, so you can just do it from any thread.

Good morning Riateche,

i try to follow your indications and i get this code.
(i simplified the program, now i just want to pass and integer value (1 to 10) from a Qthread to the main Thread and update the GUI every time).

#![windows_subsystem = "windows"]

// Includes /////////////////////////////////////
use cpp_core::{Ptr, Ref, StaticUpcast, NullPtr};
use qt_core::{qs, slot, QBox, QObject, QPtr, Signal, SlotNoArgs, SlotOfI64, SignalOfI64, QThread};
use qt_widgets::{QApplication, QLineEdit, QPushButton,QVBoxLayout, QWidget,};
use std::rc::Rc;
use std::{time, thread};
use std::cell::RefCell;


// QT5 GUI definition ////////////////////////////
struct Form {
    widget: QBox<QWidget>,
    lineedit: QBox<QLineEdit>,
    startbutton: QBox<QPushButton>,
    stopbutton: QBox<QPushButton>,
}

impl StaticUpcast<QObject> for Form {
    unsafe fn static_upcast(ptr: Ptr<Self>) -> Ptr<QObject> {
        ptr.widget.as_ptr().static_upcast()
    }
}

impl Form {
    fn new() -> Rc<Form> {
        unsafe {
            let widget = QWidget::new_0a();
            let layout = QVBoxLayout::new_1a(&widget);

            let lineedit = QLineEdit::new();
            layout.add_widget(&lineedit);

            let startbutton = QPushButton::from_q_string(&qs("Start"));
            startbutton.set_enabled(true);
            layout.add_widget(&startbutton);

            let stopbutton = QPushButton::from_q_string(&qs("Stop"));
            stopbutton.set_enabled(false);
            layout.add_widget(&stopbutton);

            widget.show();

            let this = Rc::new(Self {
                widget, startbutton, stopbutton, lineedit,
            });
            this.init();
            this
        }
    }

    unsafe fn init(self: &Rc<Self>) {
        self.startbutton.clicked().connect(&self.slot_on_startbutton_clicked());
        self.stopbutton.clicked().connect(&self.slot_on_stopbutton_clicked());
    }

    #[slot(SlotNoArgs)]
    unsafe fn on_stopbutton_clicked(self: &Rc<Self>) {
        // set quit flag to 1
    }

    #[slot(SlotNoArgs)]
    unsafe fn on_startbutton_clicked(self: &Rc<Self>) {

        self.stopbutton.set_enabled(true);

        // Create QThread, Slots and Signals
        let mythread = QThread::new_0a();

        let updateval_signal = SignalOfI64::new();

        let dowork_slot = SlotNoArgs::new(NullPtr, move || {
            for i in 1..10 {
                updateval_signal.emit(i);
            }
        });

        let updateval_slot = SlotOfI64::new(NullPtr, move |x| {
                self.lineedit.set_text(&qs(x.to_string()));
        });

        // Add slots to new Qthread
        dowork_slot.move_to_thread(&mythread);

        // Connect signals to slots
        mythread.started().connect(&dowork_slot);
        updateval_signal.connect(&updateval_slot);
        mythread.start_0a();
    }


}

// Main Definition ///////////////////////////////
fn main() {
    QApplication::init(|_| unsafe {
        let _form = Form::new();
        QApplication::exec()
    })
}

i still get an error :

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
  --> src\main.rs:79:54
   |
64 |       unsafe fn on_startbutton_clicked(self: &Rc<Self>) {
   |                                              --------- this data with an anonymous lifetime `'_`...
...
79 |           let updateval_slot = SlotOfI64::new(NullPtr, move |x| {
   |  ______________________________________________________^
80 | |                 self.lineedit.set_text(&qs(x.to_string()));
81 | |         });
   | |_________^ ...is captured here...
   |
note: ...and is required to live as long as `'static` here
  --> src\main.rs:79:30
   |
79 |         let updateval_slot = SlotOfI64::new(NullPtr, move |x| {
   |                              ^^^^^^^^^^^^^^

error: aborting due to previous error; 4 warnings emitted
  • Do you know what may be the problem here ?

  • I found in qt_core: SlotNoArgs, SlotOfI64 etc... and SignalOfI64, SignalNoArgs etc... but would it be possible to pass a QVector (or any kind of f64 array) between signal and slot?

  • Is it possible to create a RUST thread instead of using a Qthread? something like:

let updateval_signal = SignalOfI64::new();

let updateval_slot = SlotOfI64::new(NullPtr, move |x| {
                self.lineedit.set_text(&qs(x.to_string()));
        });

updateval_signal.connect(&updateval_slot);

thread::spawn(|| {
        for i in 1..10 {
            updateval_signal.emit(i);
            thread::sleep(Duration::from_millis(1));
        }
    });

Thank you very much in advance!

Best Regards.

Olivier.