Adding an array to Scrollview HaxeUI

Hello!

I’m fairly new to haxe development and came upon this GUI tool, haxeUI, and was wondering if it’s possible to add an array to the scrollview and how to add it? So far I’ve been following an example where it used a finite number of haxe components to add to the scrollview.

Sample code:

     sendButton.onClick = function(e) {
        if(!textfield.empty && count < 20) {

            var newMsgLabel = function(i: Int) {
                var msgLabel = new Label();
                msgLabel.text = textfield.text;
                msgLabel.color = 255;
                return msgLabel;
            }
            scrollView.addComponent(newMsgLabel(count));

            textfield.text = "";
            count+  +;
        }
    }

I’m trying to create a chat feature that accepts 20 messages and follows the ‘first in first out’ rule and thought that an array would be able to do this easily.

Hi,

which backend are you using, this seems to work fine for me:

<vbox style="padding: 5px;">
    <scrollview id="scrollview" width="100" height="100" />
</vbox>
class Main {
    public static function main() {
        var app = new HaxeUIApp();
        app.ready(function() {
            var main:Component = ComponentMacros.buildComponent("assets/main.xml");
            app.addComponent(main);

            var scrollView:ScrollView = main.findComponent("scrollview");

            var newMsgLabel = function(i: Int) {
                var msgLabel = new Label();
                msgLabel.text = "Item " + i;
                msgLabel.color = 255;
                return msgLabel;
            }

            for (i in 0...20) {
                scrollView.addComponent(newMsgLabel(i));
            }
            
            app.start();
        });
    }
}

image

Hello Ian!

Thank you for the reply. What do you mean by backend? Are you referring to the engine?
As for the code snippet, it also works on my end but is there a way to update the values in newMsgLabel? My aim is something like: a user enters a text as many as they want and it is displayed on the scrollview but the scrollview only accepts 20 text labels so it will remove the older entries and replace them with the newly entered ones.

Hi,

well, you would have to maintain the logic to only allow 20 items in the scrollview yourself - threre is nothing inbuild in haxeui for that type of thing.

Alternatively, you could probably also use a ListView with a datasource, eg:

            var listview:ListView = main.findComponent("listview");
            var ds = listview.dataSource;
            
            function addMessage(i:Int) {
                var message = "Item " + (i + 1);
                ds.add( { value: message } );
                while (ds.size > 20) {
                    ds.remove(ds.get(0));
                }
            }

            for (i in 0...40) {
                addMessage(i);
            }

The listview comes with a basic itemrenderer if you dont supply one, but you could also add your own with something like:

    <listview id="listview" width="300" height="200">
        <itemrenderer width="100%">
            <vbox width="100%">
                <label text="Header" width="100%" style="background-color: red;color:white;" />
                <hbox width="100%">
                    <image resource="haxeui-core/styles/default/haxeui_small.png" />
                    <vbox style="vertical-align:center;">
                        <label id="value" style="font-size: 18px;color: blue;" />
                        <label text="Just some fake subtext" style="color: #AAAAAA;" />
                    </vbox>      
                </hbox>
                <label text="Footer" width="100%" style="background-color: yellow" />
            </vbox>
        </itemrenderer>
    </listview>    

(Its a stupid renderer, but you get the idea).

haxeui-html5:
image

haxeui-hxwidgets (native):
image

Hi Ian,

I updated my code to implement the logic that I wanted, which is to remove the first or previous components, but it doesn’t update the scroll view.

Sample code:

    sendButton.onClick = function(e) {
        scrollView.addComponent(newMsgLabel(count));
        textfield.text = "";

        if(count >= 20) {
            scrollView.removeComponent(newMsgLabel(toBeDeleted), true, true);
            scrollView.vscrollPos = 0;
            scrollView.hscrollPos = 0;
            count = 0;
        }
        count++;

I tried manually adding scrollView.invalidateLayout() but it still doesn’t update the scroll view.

I also haven’t tried using list view yet, so that’s something I’ll have to look forward to.

isnt newMsgLabel() going to be creating a new Label component?

Wouldnt you need something like scrollview.removeComponent(scrollview.childComponents[0])

?

Yes I’m creating a new label component to display on the scroll view after removing the old labels. Unfortunately scrollView.removeComponent(scrollView.childComponent[0]) removes all the label entries on the scrollView and I can’t add new labels from newMsgLabel(). It still was not able to remove a single label from the scroll view. Can I edit the value of the label inside scroll view? Like instead of me removing a label, I’ll just edit its values. Would that be possible?

well, if you really want to use a ScrollView and maintain labels, this would work (its just off the top of my head):

<vbox style="padding: 5px;" width="200" height="300">
    <scrollview id="messages" width="100%" height="100%" />
    <hbox width="100%">
        <textfield id="message" width="100%" placeholder="Enter message"/>
        <button id="addMessage" text="Add" />
    </hbox>
</vbox>
class Main {
    private static var ui:Component;
    
    public static function main() {
        var app = new HaxeUIApp();
        app.ready(function() {
            ui = ComponentMacros.buildComponent("assets/main.xml");
            app.addComponent(ui);

            ui.findComponent("addMessage", Button).onClick = function(e) {
                addMessage(ui.findComponent("message", TextField).text);
            }
            
            // lets just fill it up for simplicity
            for (i in 0...40) {
                addMessage("Message " + (i + 1));
            }
            
            app.start();
        });
    }
    
    private static function addMessage(msg:String) {
        var messages:ScrollView = ui.findComponent("messages");
        if (messages.contents.childComponents.length < 20) {
            var label = new Label();
            label.text = msg;
            label.color = Std.random(0x888888) + 0x222222;
            messages.addComponent(label); // could also use messages.contents.addComponent
        } else {
            var i = 0;
            while (i < 19) { // shift them all up by one
                messages.contents.childComponents[i].text = messages.contents.childComponents[i + 1].text;
                i++;
            }
            messages.contents.childComponents[19].text = msg; // add the new item
        }
        
        messages.vscrollPos = 1000; // <--- found a subtle bug here, vscrollMax _should_ have worked
        ui.findComponent("message", TextField).text = "";
    }
}

Personally, i would probably opt for a custom component with a ListView inside it - it gets rid of the ugly “ui.findComponent” stuff and means you have a nice reusable component - but thats probably out out scope / just me.

image

1 Like

Yes! This code displays the output that I want. Thanks so much Ian!

Code reference for anyone who also needs this:

    var newMsgLabel = function(i: Int) {
        var msgLabel = new Label();
        msgLabel.text = nameString+": "+textfield.text;
        msgLabel.color = 255;
        return msgLabel;
    }

    sendButton.onClick = function(e) {
        if(scrollView.contents.childComponents.length < 20) {
            scrollView.addComponent(newMsgLabel(count));
        } else {
            count = 0;
            while(count < 19) {
                scrollView.contents.childComponents[count].text = scrollView.contents.childComponents[count+1].text;
                count++;
            }
            scrollView.contents.childComponents[19].text = nameString+": "+textfield.text;
            scrollView.vscrollPos = 0;
            scrollView.hscrollPos = 0;
        }

        textfield.text = "";
        count++;
    }

I’ll try using list view to see the difference but that’s another topic so I’ll save that for another time. Once again, thank you so much Ian.

1 Like