0

So I am trying to create an expense tracking application. I'm building the UI in Slint. For backend I will be using Rust.

The most basic function is to accept the item name and item cost from the user. I built a decent layout for the elements. Here it is: (I will be highlighting the functions and code that I have written in an attempt to achieve my target with a '//##')

slint::slint!{

import { Button, LineEdit} from "std-widgets.slint";
export component Box inherits Window {
    width: 400px;
    height: 300px;
    background: #f0f0f0;
    in-out property <string> amt;     //##
    in-out property <string> name;    //##

    //## (This function is created to act as a callback to the backend, 
     built in Rust, but is currently of no use, as the values input by the user aren't
     being collected at once as of yet.)
    callback clicked <=> submitBtn.clicked;


    //## (This whole function)
    function submit() {
        name.setName();
        amt.setCost();
        txt.text = "Name: " + root.name + ", Cost: " + root.amt;
    }

    //## (I added this element to see if I could make changes in here directly)
    //## (Doesn't work)
    txt := Text {
        text: "Name: " + root.name + ", Cost: " + root.amt;
        font-size: 16px;
        color: #000;
        horizontal-alignment: center;
        vertical-alignment: center;
        y: 250px;
    }
    VerticalLayout { 
        Rectangle {
            width: parent.width;
            height: 20px;
            background: #ccc;
        }

        Text{
            text: "Hello";
            font-size: 24px;
            color: #333;
            horizontal-alignment: center;
            vertical-alignment: center;
        }

        Text {
            text: "Enter expense information below:";
            font-size: 20px;
            vertical-alignment: center;
            horizontal-alignment: center;
        }

        HorizontalLayout {
            alignment: center;
            spacing: 66px;
            VerticalLayout {
                Text{
                    text: "Name";
                    font-size: 16px;
                    color: #555;
                    horizontal-alignment: center;
                }
                name:= LineEdit {
                    placeholder-text: "Enter name";
                    width: 101px;
                    horizontal-alignment: center;
                    
                    //## (This function, attempt to update name variable)
                    function setName() {
                        root.name = name.text;
                    }
                }
            }
            VerticalLayout {
                Text{
                    text: "Cost";
                    font-size: 16px;
                    color: #555;
                    horizontal-alignment: center;
                }
                amt:= LineEdit {
                    placeholder-text: "Enter cost";
                    width: 101px;
                    horizontal-alignment: center;

                    //## (Successful attempt at checking whether root variable 'amount'
                     is accessible by this 'amt' element -- part of debugging)
                    // text: root.amt;

                    //## (This function, attempt to update amount variable)
                    function setCost() {
                        root.amt = amt.text;
                    }
                }
            }
            
        }
        spacing: 10px;
        //## (This button is defined so that the callback can be created at root level)
        submitBtn:= Button { 
            text: "Click me"; 
            width: 100px;
            height: 40px;
            x: 150px;
            clicked => {
                //## (This loophole was created because elements and their properties
                such as 'text' can only be accessed by the child or their parents.
                I think this button falls in the *uncle* category.
                root.submit();
            }
        }

   
        // padding: 20px;
        Rectangle {
            width: parent.width;
            height: 20px;
            background: #cccfcc;
        }

        
    }
    
    
}

}

So, in the end, what's happening is that considering how elements and their properties can only be accessed by the child or the parent, I thought of creating a loop, where

  1. the button when clicked ->
  2. Calls the 'submit' function at root ->
  3. calls both setName and setAmt functions in 'name' and 'amt' elements, which update the value of 'amt' and 'name' properties of the root element.

However, this approach is not working for me. What could be the issue? Do you have a simpler solution? I would really prefer that.

1 Answer 1

0

The code is actually correct, all or most of the other methods which I was using for testing were also correct. The issue was that the function 'clicked' was being overridden in the backend using Rust.

Thus, the pre-written code in the function definition within the Slint code was not being executed. I resolved the issue by adjusting the code in the backend.

This was the from where the issue originated

    //## (This function is created to act as a callback to the backend, 
     built in Rust, but is currently of no use, as the values input by the user aren't
     being collected at once as of yet.)
    callback clicked <=> submitBtn.clicked;

Apparently the code which I was ignoring was the reason why I was having issues! hahah.

As a better explanation,

The callback function 'clicked' which is marked as an alias of the 'submitBtn.clicked' using the '<=>' operator, is being implemented at the backend in the following way:

fn main() {

    Box::new().unwrap().run().unwrap();

    let obox = Box::new().unwrap();
    //let weak_box = obox.as_weak();
    obox.on_clicked(move || {
        println!("Button clicked!");

    });
    obox.run().unwrap();

}

I intended to make changes to this function later on as I assumed the function on the slint side will be executed first and then this. However, that was not the case. I later discovered ways with which I could collect the data from the input fields directly. I also added a functionality to reset the data.

So, it's simple. I added the 'changed' property within the LineEdit elements 'name' and 'amt' (as can be seen in the question)

changed text => {
    root.name = name.text;
}
--------------------------------
changed text => {
    root.amt = amt.text;
}

This ensures that whenever the text is entered, root properties are updated. Once the button is clicked, properties can be called. See this:

fn main() {

    let obox = Box::new().unwrap();
    // Creates a strong instance of the box

    let weak_box = obox.as_weak();
    // Creates a weak instance of the box

    obox.on_clicked(move || {
        println!("Button clicked!");

        let in_box = weak_box.upgrade().unwrap();
        //As directed in documentation

        println!("Name: {}, Amount: {}", in_box.get_name(), in_box.get_amt());
        // get_ and set_ are automatically defined methods for properties in Rust.

        in_box.invoke__resetData();
        // A function I created in the Box component that 
        // resets the amt.text and name.text
        // invoke__ is another built-in function - 
        // but I haven't found documentation for it anywhere yet.

    });
    obox.run().unwrap();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.