scrollbar tutorials?

Started by wmbuRn, 15 July 2013, 03:46:29

wmbuRn

Maybe i am becoming pain in the *** ? :) But there are no tutorials online that shows usage of scrollbar. Even code included in 0.6-dev [example "FulExample"] only displays scrollbar. Which i can do :). But lets say i want to display 10 pictures in a column. they are 80x80, so only about 4 or 5 fit on resolution 800x600. iI want to use scrollbar to scroll down to see other pictures. How to do that? Simple code :). Also after all these questions i asked, i will make tutorial code and if texus allow will be displayed on site or shipped with "examples" dir. So new users will have more tutorials nad wont ask questions like me :)

Thanks in advance
wmbuRn

netrick

I agree that if someone doesn't have experience with scrollbar, they are a bit hard to understand at first. I think some example code would be good and should be written.

texus

#2
If you want to write a tutorial, be my guest.
It takes too much time to do everything myself.

Here is the example code:
Code (cpp) Select
#include <TGUI/TGUI.hpp>

void scrollbarValueChanged(const tgui::Callback& callback)
{
    tgui::Container* gui = callback.widget->getParent();

    // Reposition the pictures
    for (int i = 0; i < 10; ++i)
    {
        tgui::Picture::Ptr pic = gui->get(tgui::to_string(i));
        pic->setPosition(0, (i - callback.value) * 150);
    }
}

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

    // Create 10 images displayed below each other
    for (unsigned int i = 0; i < 10; ++i)
    {
        tgui::Picture::Ptr pic(gui, tgui::to_string(i));
        pic->load("image" + tgui::to_string(i) + ".png");
        pic->setSize(200, 150);
        pic->setPosition(0, i * 150);
    }

    // Create the scrollbar
    tgui::Scrollbar::Ptr scrollbar(gui, "Scrollbar");
    scrollbar->load("TGUI/widgets/Black.conf");
    scrollbar->setLowValue(4); // 4 images fit inside the window
    scrollbar->setMaximum(10); // 10 images in total
    scrollbar->setSize(20, 600);
    scrollbar->setPosition(200, 0);
    scrollbar->bindCallbackEx(scrollbarValueChanged, tgui::Scrollbar::ValueChanged);

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

            gui.handleEvent(event);
        }

        window.clear();
        gui.draw();
        window.display();
    }
}


If you want smooth scrolling however, instead of seeing the images jump, then you have to make a few changes to that code.
- LowValue should become 600 (instead of 4), because you are now counting the pixels instead of the images.
- Maximum should become 1500 (instead of 10), because that is the amount of pixels that all images take together in this example.
- The pictures should be set to an y value of "i * 150 - callback.value", instead of "(i - callback.value) * 150".

If you have space inbetween the images or images from other sizes then these values will obviously change. Just keep in mind that LowValue are the visible pixels and Maximum the total number of pixels that you will be able to see.

Although this will look a lot better, there is a limitation in tgui. Because the arrows of the scrollbar always change the value by 1, they will only move the images one pixel and are thus useless.

And I just noticed a bug that when scrolling the mouse wheel on top of the scrollbar, no callback is being send. I'll fix that later today.

wmbuRn

Thank you. Will writte tutorials after i learn tgui. Which will be a week. To master it will take some time. I will writte tutorial you just review the code and if its professional level post it or do whatet you feel like :)

Thank you for your answer :)

wmbuRn

#4
Managed to add scrollbar in screen with pictures. Managed to add space between pictures. But i cant add labels [ if i add labels pictures uses label->setPosition, and they change their position.] Cant add Buttons, checkboxes, editBoxes.. I cant add anything other than pictures.Please  point me to direction what to read to have container that holds everything. :)


why scrollbar?
- Lets say i need to display 40 "users", so every user have 4 editboxes, 12 checkboxes, and 1 picture. If 4 "users" can be displayed on screen, means i will need 10 screens. Lets say i need 10 groups (400 "users" in total). Thats abaout 100 screens. Which can be solved with scrollbar easily. That would be 10 screen, 40 "users" per screen. Without scrollbar i will need 28.900 lines of code to do what i planned. So please point me somewhere, 28k lines is something i can do in 2 days, but i am looking for better solution  :)

here is the pic that will explain better:
https://s11.postimg.org/ocjzs4c1f/Swing_studio_info.png

About Project:
Small project for my friend. He has dancing group [ one of best Europe] and he needs a simple program so he can writte down names and info about his crew members.And how much Training each of his member went to. I know i could do that in Excel in 15 mins but that wont help me to learn tGui and SFML. I will sell this program for money that doesnt exist in my country since 1999. :) Worth of that money in 1999 was about 0.01$ [yup that much] now is just 0$ becouse the money is worthless for the past 14 years :) Program will be able to save info into file, [.txt.] in the beggining until my C/SQL developer gets back from vacation. :)

with respect
wmbuRn

texus

Just create the picture, buttons, etc. widgets and place them like they should be when the scrollbar is at the top.

In my example code above you should then change the scrollbarValueChanged function to this:
Code (cpp) Select
void scrollbarValueChanged(const tgui::Callback& callback)
{
    tgui::Container* gui = callback.widget->getParent();

    // Reposition the object
    std::vector<tgui::Widget::Ptr> widgets = gui->getWidgets();
    std::vector<sf::String> widgetNames = gui->getWidgetNames();
    for (unsigned int i = 0; i < widgets.size(); ++i)
    {
        // Don't move the scrollbar
        if (widgetNames[i] != "Scrollbar")
            widgets[i]->setPosition(0, i * 150.0f - callback.value);
    }
}


That will move any object except for the scrollbar.

If there are other widgets that don't need to move then you will need a slightly different approach. You should place all widgets that have to move in a Panel and then just move all widgets of the panel (instead of all widgets of the whole gui).

PS: You should have better made another post instead of editing the previous one. I got no notification about it nor does the forum marks the topic as unread. You're lucky that I noticed your new question.

wmbuRn

#6
All widgets needs to move when scrollbar value changes. So i dont need diferent approach :) will test your code, and hopefully i will make to work what i planned :) . Thank you again. :)

Ok i make it

#include <TGUI/TGUI.hpp>


void scrollbarValueChanged(const tgui::Callback& callback)
{
    tgui::Container* gui = callback.widget->getParent();

    // Reposition the object
    std::vector<tgui::Widget::Ptr> widgets = gui->getWidgets();
    std::vector<sf::String> widgetNames = gui->getWidgetNames();
    for (unsigned int i = 0; i < widgets.size(); ++i)
    {
        // Don't move the scrollbar
        if (widgetNames[i] != "Scrollbar")
            widgets[i]->setPosition(0, i * 110.0f - callback.value);
    }
}

void Group1( tgui::Gui& gui )
{
    tgui::Panel::Ptr Group1(gui, "Group1");
    Group1->setSize(800, 4500);
   
// Create 40 images displayed below each other
    for (unsigned int i = 1; i <= 40; ++i)
    {
       
        tgui::Picture::Ptr pic(*Group1, tgui::to_string(i));
        pic->load("Data/Ucenik" + tgui::to_string(i) + ".png");
        pic->setSize(80, 80);
        pic->setPosition(20, i * 110);
    }

        tgui::Button::Ptr button(*Group1);
        button->load("/home/xwm/Black.conf");
        button->setSize(80, 40);
        button->setText("Button");
        button->setPosition(150, 110);

        tgui::Button::Ptr button2(*Group1);
        button2->load("/home/xwm/Black.conf");
        button2->setSize(80, 40);
        button2->setText("Button");
        button2->setPosition(300, 220);

}

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

    // Create the scrollbar
    tgui::Scrollbar::Ptr scrollbar(gui, "Scrollbar");
    scrollbar->load("Black.conf");
    scrollbar->setLowValue(600); // 4 images fit inside the window
    scrollbar->setMaximum(4500); // 10 images in total
    scrollbar->setSize(15, 600);
    scrollbar->setPosition(785, 0);
    scrollbar->bindCallbackEx(scrollbarValueChanged, tgui::Scrollbar::ValueChanged);

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

            gui.handleEvent(event);
        }

        window.clear(sf::Color::White);
        gui.draw();
        window.display();
    }
}

but here is the catch >  Group1->setSize(800, 4500);  [y is 4500 so it will display all 40 pictures]. I want that size to be >  Group1->setSize(800, 530); [ y = 530] so i have 800x70 pixels free to make buttons that wont move. But when i use code >  Group1->setSize(800, 530); only 4 pictures are shown and i scrolldown to emepty whitte screen. :) How to make scrollable area to be (800x530) and to have 800x70 free pixels for other buttons. :)

texus

Your scrolling the whole gui, including the panel. You can easily see this when you give the panel a background color. You should only be scrolling the contents of the panel.
Code (cpp) Select
void scrollbarValueChanged(const tgui::Callback& callback)
{
    tgui::Panel::Ptr panel = callback.widget->getParent()->get("Group1");

    // Reposition the object
    std::vector<tgui::Widget::Ptr> widgets = panel->getWidgets();
    std::vector<sf::String> widgetNames = panel->getWidgetNames();


Also if you don't want the buttons to move then you should just add them to the gui (pass 'gui' as parameter instead of '*Group1' when creating them).

wmbuRn

#8
Yes, when i switch tgui::Button::Ptr button(*Group1); into >> tgui::Button::Ptr button(gui); they dont scroll, they stick on given position. Which is great. But using your code [with buttons being (*Group1) cause all the widgets to change positions to X:0 , Y:0 and buttons come to the last place [after pictures] with same X:0 and Y:0 coordinates.

edit: I solved position changing, but buttons come to the last place. So i believe if i have more widgets they will all move after pictures. So only thing that changes position is this line :

for (unsigned int i = 0; i < widgets.size(); ++i)
    {
        // Don't move the scrollbar
        if (widgetNames[i] != "Scrollbar")
            widgets[i]->setPosition(20, i * 110.0f - callback.value);
    }


Also when program is loaded pictures are displayed as they should [including the button location] but when i scroll down after first picture and scroll back my 1st picture have X:20 and Y:0 position, and not as they had when the program loaded. They had [X:20, Y:110]

texus

You should just fix your setPosition formula. You set all widgets to x=20, so obviously the buttons will change their original position.

The trick is to keep all objects on their starting position minus the scrollbar value.

For this you will also need the old scrollbar value, so you'll have to store that.
In the example code, you could make a global variable scrollbarValue (int) and set its value to 0.
Then at the end of your scrollbarValueChanged function, you set it to "callback.value".

The setPosition line would then have to become:
Code (cpp) Select
widgets[i]->move(0, scrollbarValue - callback.value);

That should solve all problems.

Also, the scrollbar isn't part of the panel I guess, so you no longer have to check the widget name against "Scrollbar" as that will never match.

wmbuRn


#include <TGUI/TGUI.hpp>

int scrollbarValue = 0;

void Group1( tgui::Gui& gui )
{
    tgui::Panel::Ptr Group1(gui, "Group1");
    Group1->setSize(800, 530);
    for (unsigned int i = 1; i <= 40; ++i)
    {
        tgui::Picture::Ptr pic(*Group1, tgui::to_string(i));
        pic->load("Data/Ucenik" + tgui::to_string(i) + ".png");
        pic->setSize(80, 80);
        pic->setPosition(20, i * 110.0f);
    }
        tgui::Button::Ptr button(*Group1);
        button->load("/home/xwm/Black.conf");
        button->setSize(80, 40);
        button->setText("Button");
        button->setPosition(150, 110);

        tgui::Button::Ptr button2(*Group1);
        button2->load("/home/xwm/Black.conf");
        button2->setSize(80, 40);
        button2->setText("Button");
        button2->setPosition(300, 220);

}
void scrollbarValueChanged(const tgui::Callback& callback)
{
tgui::Panel::Ptr panel = callback.widget->getParent()->get("Group1");

    // Reposition the object
    std::vector<tgui::Widget::Ptr> widgets = panel->getWidgets();
    std::vector<sf::String> widgetNames = panel->getWidgetNames();
    for (unsigned int i = 0; i < widgets.size(); ++i)
    {
            widgets[i]->move(0, scrollbarValue - callback.value);
    }
}



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



    // Create the scrollbar
    tgui::Scrollbar::Ptr scrollbar(gui, "Scrollbar");
    scrollbar->load("Black.conf");
    scrollbar->setLowValue(600); // 4 images fit inside the window
    scrollbar->setMaximum(4500); // 10 images in total
    scrollbar->setSize(15, 530);
    scrollbar->setPosition(785, 0);
    scrollbar->bindCallbackEx(scrollbarValueChanged, tgui::Scrollbar::ValueChanged);

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

            gui.handleEvent(event);
        }

        window.clear(sf::Color::White);
        gui.draw();
        window.display();
    }
}

I declared global variable even with variable.cpp and variable.h [ extern int scrollbarValue ] but things get worse than they were :)

texus

You missed something in my previous message.
QuoteThen at the end of your scrollbarValueChanged function, you set it to "callback.value".

Adding "scrollbarValue = callback.value;" at the end of scrollbarValueChanged makes it work.

wmbuRn

yup it makes it to work. Thank you very much :) i owe you a beer :)

texus

Too bad that I don't drink beer :)

wmbuRn

#14
More beer for me :)

So

tgui::Scrollbar::Ptr scrollbar(*Group1);

Doesnt work, when i change values of scrollbar [with mouse or mouse scroll] program crashes with

/usr/local/include/TGUI/SharedWidgetPtr.hpp:271: T* tgui::SharedWidgetPtr<T>::operator->() const [with T = tgui::Panel]: Assertion `m_WidgetPtr != __null' failed.
Aborted (core dumped)

So i will figure it out.

with

tgui::Scrollbar::Ptr scrollbar(gui, "Scrollbar");

works flawlesly, except i see scrollbar in panel where i dont need scrollbar :)

Also

for (unsigned int i = 1; i <= 40; ++i)
    {
        tgui::EditBox::Ptr Name(*Group1, tgui::to_string(i));
        Name->load("Data/Buttons/Black.conf");
        Name->setMaximumCharacters(15);
        Name->setSize(120, 15);
        Name->setPosition(20, (i * 110) - 40);
    }

Need to figure out how to access each editBoxes to read it values, and to modify them. Will learn it eventualy. Never used "to_string(i)" before, nor "c_str" since i never needed them. :)