SFML drawing into a child window

Started by RitoonL, 25 May 2020, 18:31:07

RitoonL

Hello,

I'm new to TGUI and kind of rookie in programming, so please be kind !

i'm searching how to draw some SFML stuff into a tgui child window, i understood how to create the child window widget, adding widgets to a parent widget, so i have my child window on screen. sfml graphics are ready and i can display them in sfml main window.

What i want to do is an interface with multiple windows that can dock together like magnetic links. Most of the windows will have SFML draws inside. The windows will have to be inside the main sfml window. Any clue with that ? or Tgui child windows can only contain tgui widgets ? I like how i can configure Child windows with TGUI so i would prefer to be able to draw inside than create multiple ugly sfml windows.

Thanks for your answers

regards,

RitoonL

texus

You would have to use the Canvas widget for this.

The canvas acts like a RenderTexture (it's actually just a wrapper around a RenderTexture), so you use the clear(), draw() and display() functions on it to draw your SFML stuff on the canvas.
Since the canvas is a tgui widget, you can add it to the child window and it will display the last thing you rendered to it.
You only need to update the canvas when the SFML rendering changes, so if what you render is static then you don't have to redraw to the canvas every frame.

RitoonL

#2
thanks, i will try that and keep the thread updated if i have questions.

***EDIT***

Now that i experimented the canva and successfully drawn and displayed a vertex array in the canva, i'm having hard time to pass the vertex array by reference from function to another function.

What i want to do is have the vertex array in a different place. I know it's more a general c++ question, i can pass some values by reference but have no idea how to pass the vertex.

here is the minimal code :

Code (cpp) Select
void test_draw(sf::RenderTarget& target)
{
    sf::Vertex vertex;
    sf::VertexArray test(sf::Quads, 4);

    test[0].position = sf::Vector2f(0, 0);
    test[1].position = sf::Vector2f(50, 0);
    test[2].position = sf::Vector2f(50, 70);
    test[3].position = sf::Vector2f(0, 70);

    // this is where is the trouble ... how do i say Test is the target ? ... i can do it with an int but
    // target = test; will not work
}


then i will have to retrieve the target in the other function:

Code (cpp) Select
void channels_window(sf::RenderWindow &window, tgui::Gui& gui) // this will be called in the main
{
sf::RenderTarget *target; // not sure if i can declare the render target like this
//it won't let me declare something else than a pointer

auto canva= tgui::Canvas::create();
gui.add(canva);

//this is where i a missing something, how do i retrieve the vertex
testdraw(target); //???
canva->draw(target); // if the target is retrieved, it should draw fine.
}



this is a bit messy but i removed a lot of things in the code, just to go to essentials. I know that's a real noob question and that i should go back to my C++ class but, i don't have one and i'm self learning. Books and internet classes don't give all the answers.

Thanks by advance

RitoonL

RitoonL

Sorry i have to !up the subject because i edited previous one ... oh yeah i hate double posts too !

Kvaz1r

Why not define class and keep your objects there?

RitoonL

#5
Well,

in facts there is a class ready with the drawings that i've created before, this can be displayed in sf::rendererWindow, but now that i'm constructing the GUI, i want it displayed in the canva. I'm just trying to do it step by step because there is already a lot of code ready that i don't want to breack, that's why i want to know how to pass this renderTarget by reference.

I might be wrong but if  i can do from function to function,  i can do  from class to function the same way. The funny thing is that it should be like using the renderWindow, but i don't know why, i'm stalling on this one.

I feel like i want to plug an aspirator on the kitchen sink ...

just for info, here it my class ... i'm not waiting other people do things for me but i need help for this one ... not showing the .h :

Code (cpp) Select
#include <SFML/Graphics.hpp>
#include <string>
#include <sstream>
#include "Channel.h"

using namespace std;
using namespace sf;
//sf::Font font;
//sf::Text ch;
//sf::Text lvl;

static sf::Font font;
extern vector <uint16_t> selected_chan;

bool Channel::Init(const std::string& fontFile)
{
    return font.loadFromFile(fontFile);
}

Channel::Channel(uint16_t channel_number):
    _channel_number(channel_number),
    _level(0),
    _channel_mode(true),
    _display_level(0)
{

}

Channel::~Channel()
{
        //a faire imperativement !
}
//-------------------------------------------------

void Channel::draw_channel(sf::RenderWindow &window,uint16_t x,uint16_t y)
//void Channel::draw_channel(sf::RenderTarget &Canvas,uint16_t x,uint16_t y)

{
    //int x=100,y=0;
    //font.loadFromFile("kimberley_bl.ttf");



    ostringstream chnbr; // channel number into a string
    chnbr<<_channel_number;
    ostringstream lvlstr; // channel level into a string (can't be uint_8t)
    lvlstr<< _display_level;

    sf::Vertex vertex;
    //vertex.position = sf::Vector2f(0, 0);
    sf::VertexArray ch_quad(sf::Quads, 16);

    bool selected=false;
    for(uint16_t i=0; i<selected_chan.size() ;i++)
    {
        if(selected_chan[i]==_channel_number)
        {
            selected=true;
        }
    }

    // Draws under quad supposed to be outline (draw order)
    ch_quad[0].position = sf::Vector2f(0, 0);
    ch_quad[1].position = sf::Vector2f(50, 0);
    ch_quad[2].position = sf::Vector2f(50, 70);
    ch_quad[3].position = sf::Vector2f(0, 70);

    if(selected == false) //color of outline for selection
    {
        ch_quad[0].color = sf::Color(20, 30, 60);
        ch_quad[1].color = sf::Color(20, 30, 60);
        ch_quad[2].color = sf::Color(20, 30, 60);
        ch_quad[3].color = sf::Color(20, 30, 60);
    }
    if(selected == true)
    {
        ch_quad[0].color = sf::Color(255, 255, 255, 255);
        ch_quad[1].color = sf::Color(255, 255, 255, 255);
        ch_quad[2].color = sf::Color(255, 255, 255, 255);
        ch_quad[3].color = sf::Color(255, 255, 255, 255);
    }

    //draws the inside under quad ad sets the color (black)
    ch_quad[4].position = sf::Vector2f(1,1);
    ch_quad[5].position = sf::Vector2f(49,1);
    ch_quad[6].position = sf::Vector2f(49,69);
    ch_quad[7].position = sf::Vector2f(1,69);
    ch_quad[4].color = sf::Color(0, 0, 0);
    ch_quad[5].color = sf::Color(0, 0, 0);
    ch_quad[6].color = sf::Color(0, 0, 0);
    ch_quad[7].color = sf::Color(0, 0, 0);
    //draws the channel strip
    ch_quad[8].position = sf::Vector2f(1,1);
    ch_quad[9].position = sf::Vector2f(49,1);
    ch_quad[10].position = sf::Vector2f(49,17);
    ch_quad[11].position = sf::Vector2f(1,17);
    ch_quad[8].color = sf::Color(20, 30, 60);
    ch_quad[9].color = sf::Color(20, 30, 60);
    ch_quad[10].color = sf::Color(20, 30, 60);
    ch_quad[11].color = sf::Color(20, 30, 60);
    //draws the info strip
    ch_quad[12].position = sf::Vector2f(1,50);
    ch_quad[13].position = sf::Vector2f(49,50);
    ch_quad[14].position = sf::Vector2f(49,69);
    ch_quad[15].position = sf::Vector2f(1,69);
    ch_quad[12].color = sf::Color(20, 30, 60);
    ch_quad[13].color = sf::Color(20, 30, 60);
    ch_quad[14].color = sf::Color(20, 30, 60);
    ch_quad[15].color = sf::Color(20, 30, 60);

    sf::Transform pos;
    pos.translate(x, y);

    //window.draw(ch_quad, pos);
    window.draw(ch_quad, pos);

    // Channel number text
    ch.setFont(font);
    //ch.setString(std::string("ch ") + chnbr.str());
    ch.setString(chnbr.str());
    ch.setCharacterSize(12);
    ch.setLetterSpacing(0.3);
    ch.setFillColor(sf::Color(255, 255, 255));
    ch.setPosition(x+2, y+2);
    window.draw(ch);
    // Level Text
    if(_level>0)
    {
        lvl.setFont(font);
        lvl.setString(std::string("") + lvlstr.str());
        lvl.setCharacterSize(18);
        lvl.setLetterSpacing(0.3);
        if(_channel_mode == false)
            lvl.setFillColor(sf::Color(255, 255, 255));
        else
            lvl.setFillColor(sf::Color(255, 255, 100));
        lvl.setPosition(x+4, y+8);
        window.draw(lvl);
    }

}
//-------------------------------------------------

void Channel::set_channel_number(uint16_t channel_number)//Channel.set_channel_number
{
    _channel_number = channel_number;
}
//-------------------------------------------------

uint16_t Channel::get_channel_number()
{
    return _channel_number;
}
//-------------------------------------------------

void Channel::set_level(uint16_t level)//devenu void
{
    _level = level;
    display_level();
}
//-------------------------------------------------

uint16_t Channel::get_level()
{
    return _level;
}
//-------------------------------------------------

void Channel::change_mode(bool channel_mode)
{
    _channel_mode=channel_mode;
}
//-------------------------------------------------

bool Channel::get_mode()
{
    return _channel_mode;
}
//-------------------------------------------------

void Channel::display_level()
{
    if (_channel_mode==false)
    {
        _display_level = (_level/2.55);
    }
    else
    _display_level = _level;
}

texus

There is no problem in double posting if it makes sense to do so. If you asked a question for which there was no answer yet then it might be better to edit than to make many posts (I don't really care about one post more or less though, it's fine as long as you don't create 5 in a row). In this case your original response didn't contain a question though. I considered this topic close after reading your response, and editing doesn't send me a notification, so I never found out that you had another question until you posted another reply.

The issues seem to originate from not fully understanding what sf::RenderTarget is.

Quotetarget = test; will not work
One is an sf::VertexArray, the other is a sf::RenderTarget, those are 2 completely different things.
The RenderTarget is what you draw on, it is a common base class of both RenderTexture and RenderWindow.
The VertexArray is a drawable. It is something you can draw on top of a RenderTarget.
If you intended to draw the vertex array to the render target then it should have been "target.draw(test)".
If you just want to pass the "sf::VertexArray" as a reference then you might be over-complicating things, why not just make the parameter "sf::VertexArray&" instead of "sf::RenderTarget&"?

Quotesf::RenderTarget *target; // not sure if i can declare the render target like this
You cannot create a RenderTarget object, it is an abstract class. You either have to create a RenderTexture or a RenderWindow.
By making it a pointer, you have a variable that is supposed to point to a RenderTexture or RenderWindow, but if you don't set a value for the pointer then it points to a random location in memory so trying to use it will just crash (in the best case scenario).

Quotecanva->draw(target); // if the target is retrieved, it should draw fine.
Lines like these should always be in the form of "RenderTarget.draw(Drawable)". The canvas is a RenderTarget-like type, so you can call draw on it, but "target" isn't a drawable, so it cannot be passed to the draw function.

What I think you want to do is this:
Code (cpp) Select
void test_draw(sf::VertexArray& test)
{
    // Replace the contents of "test" (which was an empty vertex array until now) with a new vertex array that contains 4 points.
    // Alternatively, you could have written "test->setPrimitiveType(sf::Quads)" and "test->resize(4)".
    test = sf::VertexArray(sf::Quads, 4);

    test[0].position = sf::Vector2f(0, 0);
    test[1].position = sf::Vector2f(50, 0);
    test[2].position = sf::Vector2f(50, 70);
    test[3].position = sf::Vector2f(0, 70);
}

sf::VertexArray arr; // create an empty vertex array that will be initialized by test_draw
test_draw(arr);
canva->draw(arr);


Alternatively, you can just return the VertexArray as return value:
Code (cpp) Select
sf::VertexArray test_draw()
{
    sf::VertexArray test(sf::Quads, 4);
    test[0].position = sf::Vector2f(0, 0);
    test[1].position = sf::Vector2f(50, 0);
    test[2].position = sf::Vector2f(50, 70);
    test[3].position = sf::Vector2f(0, 70);
    return test;
}

sf::VertexArray arr = test_draw();
canva->draw(arr);

RitoonL

#7
Hello Texus,

Many thanks for this, once again very accurate answer, you were right i did not understood what a renderTarget is.

last question before i'm done with this thread, because i now have a better view of what i can do :

My final objective is to render what i have in my class

Drawing section of my class :

Code (cpp) Select
void Channel::draw_channel(sf::RenderWindow &window,uint16_t x,uint16_t y)
//void Channel::draw_channel(sf::RenderTarget &Canvas,uint16_t x,uint16_t y)

{
    ostringstream chnbr; // channel number into a string
    chnbr<<_channel_number;
    ostringstream lvlstr; // channel level into a string (can't be uint_8t)
    lvlstr<< _display_level;

    sf::Vertex vertex;
    //vertex.position = sf::Vector2f(0, 0);
    sf::VertexArray ch_quad(sf::Quads, 16);

    bool selected=false;
    for(uint16_t i=0; i<selected_chan.size() ;i++)
    {
        if(selected_chan[i]==_channel_number)
        {
            selected=true;
        }
    }

    // Draws under quad supposed to be outline (draw order)
    ch_quad[0].position = sf::Vector2f(0, 0);
    ch_quad[1].position = sf::Vector2f(50, 0);
    ch_quad[2].position = sf::Vector2f(50, 70);
    ch_quad[3].position = sf::Vector2f(0, 70);

    if(selected == false) //color of outline for selection
    {
        ch_quad[0].color = sf::Color(20, 30, 60);
        ch_quad[1].color = sf::Color(20, 30, 60);
        ch_quad[2].color = sf::Color(20, 30, 60);
        ch_quad[3].color = sf::Color(20, 30, 60);
    }
    if(selected == true)
    {
        ch_quad[0].color = sf::Color(255, 255, 255, 255);
        ch_quad[1].color = sf::Color(255, 255, 255, 255);
        ch_quad[2].color = sf::Color(255, 255, 255, 255);
        ch_quad[3].color = sf::Color(255, 255, 255, 255);
    }

    //draws the inside under quad ad sets the color (black)
    ch_quad[4].position = sf::Vector2f(1,1);
    ch_quad[5].position = sf::Vector2f(49,1);
    ch_quad[6].position = sf::Vector2f(49,69);
    ch_quad[7].position = sf::Vector2f(1,69);
    ch_quad[4].color = sf::Color(0, 0, 0);
    ch_quad[5].color = sf::Color(0, 0, 0);
    ch_quad[6].color = sf::Color(0, 0, 0);
    ch_quad[7].color = sf::Color(0, 0, 0);
    //draws the channel strip
    ch_quad[8].position = sf::Vector2f(1,1);
    ch_quad[9].position = sf::Vector2f(49,1);
    ch_quad[10].position = sf::Vector2f(49,17);
    ch_quad[11].position = sf::Vector2f(1,17);
    ch_quad[8].color = sf::Color(20, 30, 60);
    ch_quad[9].color = sf::Color(20, 30, 60);
    ch_quad[10].color = sf::Color(20, 30, 60);
    ch_quad[11].color = sf::Color(20, 30, 60);
    //draws the info strip
    ch_quad[12].position = sf::Vector2f(1,50);
    ch_quad[13].position = sf::Vector2f(49,50);
    ch_quad[14].position = sf::Vector2f(49,69);
    ch_quad[15].position = sf::Vector2f(1,69);
    ch_quad[12].color = sf::Color(20, 30, 60);
    ch_quad[13].color = sf::Color(20, 30, 60);
    ch_quad[14].color = sf::Color(20, 30, 60);
    ch_quad[15].color = sf::Color(20, 30, 60);

    sf::Transform pos;
    pos.translate(x, y);

    //window.draw(ch_quad, pos);
    window.draw(ch_quad, pos);

    // Channel number text
    ch.setFont(font);
    //ch.setString(std::string("ch ") + chnbr.str());
    ch.setString(chnbr.str());
    ch.setCharacterSize(12);
    ch.setLetterSpacing(0.3);
    ch.setFillColor(sf::Color(255, 255, 255));
    ch.setPosition(x+2, y+2);
    window.draw(ch);
    // Level Text
    if(_level>0)
    {
        lvl.setFont(font);
        lvl.setString(std::string("") + lvlstr.str());
        lvl.setCharacterSize(18);
        lvl.setLetterSpacing(0.3);
        if(_channel_mode == false)
            lvl.setFillColor(sf::Color(255, 255, 255));
        else
            lvl.setFillColor(sf::Color(255, 255, 100));
        lvl.setPosition(x+4, y+8);
        window.draw(lvl);
    }

}


I was passing this directly to the sf::renderWindow, but it's not anymore what i want to do.
As you can see, these graphics are made of 1 vertex array of 16 vertexes, and some text that is dynamically updating.

do you think i shall pass each of the component of my drawing and draw them in the function where i create the canva, or pre-rendering it direcly in the class (in a renderTexture, if i did understand well what you said before) and passing the texture to my function. Does it makes sense to do this? What would be better for display performance ? ... you maybe want to know that the class can have several instances (might be between 1 to 4000 instances).

***EDIT*** Or Even maybe making a sprite in the class and pass it ?

Thanks by advance,

RitoonL

Kvaz1r

Interesting topic, I (too?) not understand how to draw on tgui::Canvas.

I thought this code :

#include <TGUI/TGUI.hpp>

sf::VertexArray test_draw()
{
    sf::VertexArray test(sf::Quads, 4);
   
    test[0].position = sf::Vector2f(0, 0);
    test[0].color = sf::Color::Red;
    test[1].position = sf::Vector2f(50, 0);
    test[1].color = sf::Color::Red;
    test[2].position = sf::Vector2f(50, 70);
    test[2].color = sf::Color::Red;
    test[3].position = sf::Vector2f(0, 70);
    test[3].color = sf::Color::Red;
    return test;
}

int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "TGUI window");
tgui::Gui gui(window);

    auto panel = tgui::Panel::create();

    auto canvas = tgui::Canvas::create();
    canvas->clear();
    canvas->draw(test_draw());
    canvas->display();
    panel->add(canvas);

    gui.add(panel);

while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();

gui.handleEvent(event); // Pass the event to the widgets
}

window.clear();
gui.draw(); // Draw all widgets
        //window.draw(test_draw()); //draw fine
window.display();
}
}


will draw red square but it doesn't draw anything. What am I missing?
Drawing via window (commented line) works fine. 

RitoonL

i might be wrong as i am myself a bit not sure of what i'm doing, but you might try to give a size to your canva. It should be because you canvas size is 0

Kvaz1r

Yes, it exactly the reason, thank you.

texus

I would just treat the Canvas as you previously treated the RenderWindow: change your draw_channel function to
Code (cpp) Select
void Channel::draw_channel(tgui::Canvas::Ptr &canvas,uint16_t x,uint16_t y)
and replace "window.draw" with "canvas->draw" inside the function.

Pre-rendering to a RenderTexture first is going to be marginally slower since you would be doing an extra draw call. If you would use a RenderTexture then you would also have to create it somewhere. Creating it is a "slow" operation, so you wouldn't want to use a single RenderTexture for each Channel object. You would end up with a single RenderTexture that you create once and pass around everywhere in your code, but that is exactly what you would do when you just pass the Canvas everywhere (Canvas is nothing more than a widget containing a RenderTexture).

Making a sprite in the class is the same option as creating a RenderTexture. You can't draw things to a sprite and you can't draw a RenderTexture to the canvas, you need both the RenderTexture and Sprite to make a drawing buffer. The only way to use RenderTexture and Sprite is to create a RenderTexture, draw on that render texture, create a sprite from the texture and drawing the sprite to the canvas. But again, that is just doubling the effort as this is what Canvas already does (it creates a RenderTexture, lets you draw on it with the clear(), draw() and display() function, creates a sprite from the texture and later draws that sprite to the window).

Whether your object should contain a draw function so that it can draw itself, or whether you have the rendering code outside the object is a design decision that might depend on how the code is used. But you actually already made this design decision. When drawing to the RenderWindow, you chose to keep the drawing code inside the Channel object, so there is no reason why you would suddenly do it another way just because you need to render to a canvas.

RitoonL

Hello Texus,

Thanx for your answer, it's usefull again.

You really told me exactly what i was seeking without haveing to ask. Passing the already drawn entitys ... i'll do that.

I have to write the refreshing routine of the canva, i will maybe have questions about that later, but for now, i'm happy, i can pass what i need.

We're trying to optimize display as much as we can, so we're really seeking every opportunity to refresh only what we need and not everything every frame, because we want the software to run on Raspberry pi also. We compiled on a Raspi 3 today with success ... it could not run on a Raspi 2. It's still a previous version of the work that is not using tgui yet, but we're trying to keep in mind every opportunity to optimize display.

Well, i must thank you really much for your work and for your precious help also, be sure that i will ask more in the future !

Regards,

RitoonL




texus

Quotewe're really seeking every opportunity to refresh only what we need
we're trying to keep in mind every opportunity to optimize display
By coincidence I actually fixed an issue today related to this ability. If you were to only draw the screen after you received an event (to minimize the amount of times you need to redraw the screen) then the cursor in edit box would for example stop to blink. Since there was no way to know when the cursor appears and disappears, you would still need to regularly draw the gui even when not receiving events (and you would waste CPU usage as most of the frames nothing would change).

In the 0.8 branch on github, I just made a change that allows you to know when a widget requires the screen to be refreshed (the change was already made in 0.9-dev last week, but I just backported it now). You would need to first call the following to decouple updating time and drawing in TGUI:
Code (cpp) Select
gui.setDrawingUpdatesTime(false);

Then every frame, update the time:
Code (cpp) Select
bool screenNeedsUpdate = gui.updateTime();

The screenNeedsUpdate variable will become true when something changes in the gui. It almost always will return false, but when an edit box or text box is focused it will return true twice per second so that you can update the screen to show the blinking cursor without having to refresh the screen more than you have to. If you use the showWithEffect or hideWithEffect functions in widget then the update function will return true the whole time while the animation plays, so you would still want to limit the amount of frames being rendered some other way if you want to use those functions.

RitoonL

#14
the features you just add seems very interesting, we'll look at it...

I tought i finished with this canvas code, but i'm struggling again with one thing.

I guess i'm not structuring my code correctly.

Code (cpp) Select
void channel_sorting(tgui::Canvas::Ptr &canvas)  // the fuction can't be called in the main because it's waiting &canvas as argument
{
    int displayed_channels=0;
    for(uint16_t i=0;i<1025;i++)
        {
            uint16_t column = (displayed_channels%10 );
            uint16_t row = (displayed_channels/10);
        if(address_channel[i]>0)
        {
            ch(i) draw_channel(canvas,column*52,row*72);//ch(i) is #define ch(x) tab_Channel[address_channel[x]]->
            displayed_channels++;
        }
     canvas->display();
    }
}


void channels_window(sf::RenderWindow &window, tgui::Gui& gui)
{
    auto channels = tgui::ChildWindow::create();
    channels->setTitle("Channels");
    channels->setTitleAlignment(tgui::ChildWindow::TitleAlignment::Left);
    channels->setResizable(true);//(tgui::ChildWindow::setResizable=true);
    channels->getRenderer()->setBackgroundColor(sf::Color::Black);
    channels->getRenderer()->setTitleBarHeight(15);
    channels->getRenderer()->setTitleColor(sf::Color::White);
    channels->getRenderer()->setTitleBarColor(sf::Color(20, 30, 60));
    channels->getRenderer()->setBorders(1);
    channels->getRenderer()->setMinimumResizableBorderWidth(3);
    channels->getRenderer()->setBorderColor(sf::Color(20, 30, 60));

    auto scrollbar = tgui::Scrollbar::create();
    scrollbar->getRenderer()->setTrackColor(sf::Color(20, 30, 60));
    scrollbar->getRenderer()->setThumbColor(sf::Color(70, 70, 70));
    scrollbar->getRenderer()->setThumbColorHover(sf::Color(70, 70, 70));
    scrollbar->getRenderer()->setArrowBackgroundColor(sf::Color(20, 30, 60));
    scrollbar->getRenderer()->setArrowBackgroundColorHover(sf::Color(20, 30, 60));
    scrollbar->getRenderer()->setArrowColor(sf::Color(70, 70, 70));
    scrollbar->getRenderer()->setArrowColorHover (sf::Color(70, 70, 70));
    scrollbar->setSize({10, bindHeight(channels)});
    scrollbar->setPosition({"100% - width", 0});

    auto channel_canvas= tgui::Canvas::create();
    channel_canvas->setSize(350,1000);

    sf::VertexArray channel_quad;

    gui.add(channels);
    channels->add(scrollbar);
    channels->add(channel_canvas);
    channel_sorting(channel_canvas);
}


in void channel_sorting

i'm creating the objects and formatting them. if i create 20 channels objects, they will be displayed in 2 colums of 10. columns and rows will adapt the size of the window in the future.

in void channels_window

i'm creating the channel window, 1 child window, 1 scroll bar and 1 canva (channel_canva), i will do an adaptative code later for the size of the canva, depending on how many channels are displayed, the scrollbar will be in relation of the canva to scroll channels out of the child window, but tis is not the problem i have now.

when the program starts, channels objects are not created. They are created by the user and the user can create more at anytime, it also have dynamic texts and colors. This part of the program works great.

the main problem is that i can't figure how to update the canva. i tried many solutions but the only way i found to update the canva is calling void channel_window() in the main loop wich duplicates all the GUI object each time the loop executes, but i can see my channels well sorted in the canvas, wich prove that i draw on it.

i copied the canva to channel_canva, i'm not proud of that, but if i use (tgui::Canvas::Ptr &canvas) as argument of the fuction, wich prevent copying the canvas, i can't use the function in the main.

I know that i must use canva->display() in my main or in a fuction called in the main, but i don't know how to do as the compiler wants the canvas to be declared . I think i'm lacking of knowledge in C++ to do what i want, but as you know me now, i'm fast learner if someone can put me on good rails.

Edit : I tried to declare
tgui::Canvas::Ptr canvas;
in the main and passig it to the functions, it compiles with no error but crashes when i execute the program.

thanks by advance
RitoonL