ArthurSonzogni/FTXUI

Dynamically adding elements to Checkboxes

dr-mrsthemonarch opened this issue · 5 comments

I'm working on a hardware controller emulator, which has UDP, and TCPServer elements, basically when a remote client connects to this controller, they should be able to send it commands, and the device will respond over a network, this works great. It's possible for multiple clients to connect, and interact with it, like the real thing.
I can start the servers, display responses, connections of clients, etc, like so

image

This server was developed so I can in actuality develop the client, of which I also want to use FTXUI. The client and server both need to add and remove found controllers/clients on the network.

Unfortunately, I have two issues that happen, either the container stays empty, and never updates dynamically the elements as they are pushed back to it ( I guess because this needs to be done at runtime?) or the entire program crashes when I start the TCPserver with a segmentation fault, or odd random text showing up.

My initial code of the checkbox being:

std::array<bool, 10> states;
    
    auto checkboxes = Container::Vertical({});
    for (int i = 0; i < clientVec.vec.size(); ++i) {
        states[i] = false;
        checkboxes->Add(Checkbox(clientVec.vec[i],
                                 &states[i]) );
    }
    Component checkframe = Renderer(checkboxes, [&] {
        return checkboxes->Render() | vscroll_indicator | frame |
        size(HEIGHT, LESS_THAN, 5) | border | color(Color::Default);
    });

    checkframe=Wrap("To be Done",checkframe);

and the relevent code for the starting of the loop:

// -- Layout -----------------------------------------------------------------
    auto layout = Container::Vertical({
        checkframe,
        //        toggle,
        input_add,
        udpbuttons,
        tcpbuttons
    }) | size(HEIGHT, GREATER_THAN, 40);
    
    auto component = Renderer(layout, [&] {
        return vbox({
            checkframe->Render(),
            separator() | color(Color::Default),
            udpbuttons->Render(),
            separator() | color(Color::Default),
            tcpbuttons->Render()
        }) | size(WIDTH, GREATER_THAN, 30) | borderStyled(ROUNDED,Color::Default);
        
    });
    
    auto topwindows = Container::Horizontal({
        component,
        output | yflex,
    });
    
    auto layoutmain = Container::Vertical({
        topwindows,
        cliArea | flex,
    });
    
    
    auto renderer = Renderer(layoutmain, [&] {
        return layoutmain->Render() ;
    }); //main render for the entire interface.
    
    //create a new thread to run the output continously/force redraw. Required for the output window to update on it's own instead of waiting for an event.
    
    auto screenRedraw = std::thread([&](){
        while(running){
            screen.PostEvent(ftxui::Event::Custom);
            std::this_thread::sleep_for(std::chrono::milliseconds(50)); // Prevent High CPU Usage.
        }
    });
    
    screen.Loop(renderer);
    
    screenRedraw.join();
}

I had assumed that when I constantly redraw the the screen on a seperate thread, it would update the client list, as things changed, but it remains empty unfortuantely.

clientVec.vec is a structure like so to ensure thread safety, if you're curious.

struct SharedVector {
    std::vector<std::string> vec;
    std::mutex vecMutex;
};

and I have a server class that pushes back entries when clients connect to clientVec.vec, that the checkbox should read from.

Is it possible to dynamically add elements/children to checkmarks like this?

Is it possible to dynamically add elements/children to checkmarks like this?

Yes it is possible.


I will take a look later today.
Maybe you can upload a video or a terminal record reproducing what you are seeing? In particular the crash?

Absolutely. It is random generally, but I happened to capture it in the first try. Usually it happens immediately, but in this case, it took some tries.

You can find the source code here: source If you want to look further in depth of my implementation, beyond the code I posted here.

and here is the recording. terminal record

Here's a link to the asciinema to play it, if the above recording doesn't work correctly:
[recording](
the animator)