#Trouble getting XML UI to update *onload*

1 messages · Page 1 of 1 (latest)

green cliff
#

I wanted a counter that I can change by clicking on it (just a simple +1/-1) and I found
https://steamcommunity.com/sharedfiles/filedetails/?id=1552081476
.. which works very well, but it's a little crowded. I got rid of all the buttons I didn't need/want to get something that just does the +1/-1 on left/right-click. No problems so far, the script still works fine.

However, moving the counter without clicking the button is a little hard, so I decided to also show its value on the other side, with a XML UI Text element and included

self.UI.setAttribute("FrontVal","text",val)
to add_subtract, the buttons click_function, so keep it updated. This also works fine.

However, a problem arises whenever the object is loaded, copied, pulled from a bag, etc. Then, the XML UI Text element isn't updated. It shows the original XML UI Text's value ("front") instead. So I think: alright, I just need to update the XML whenever the object loads as well, so I add:

self.UI.setAttribute("FrontVal","text",val)
to the onload function. This results in an error: "object reference not set to an instance of an object". AFAICT that means that the object doesn't exist, causing the "self." reference to return nil. I'm puzzled about this, because the script, before that, executes several self.createButton() functions with no problem at all.

So, WTF and how do I get around this?

near ingot
#

Have you added a frame or two delay as a possible solution?

#
Wait.frames(function()
  -- code here runs after 2 frames
end, 2)
#

to explain why this happens, you can't set xml and set an attribute of that xml in the same frame.

#

it takes one frame (usually) to re-draw the xml and allow you to then use .setAttribute() and other methods on it

green cliff
#

I replaced it with print(self.guid..'loaded.') and got the same error, so I didn't think that was the problem, but yes, I did try that. To make sure I just tried it again:

Wait.frames(updateXML(), 10)

function updateXML()
self.UI.setAttribute("FrontVal","text",val)
print(self.guid..' XML set to '..tostring(val)..'.')
end

Same error "Object reference not set to an instance of an object".

woeful whale
#

please post the code on the object, because this is getting into guessing teritory

green cliff
#

How do I make that nice box-thingy?

near ingot
#
Wait.frames(updateXML(), 10)

no call, just reference the function:

Wait.frames(updateXML, 10)
green cliff
#

same result, that was actually my first try

near ingot
#

then your error isn't there, as Eldin said, code please :)

green cliff
#
MIN_VALUE = 0
MAX_VALUE = 30

function onload(saved_data)
    light_mode = false
    tooltip_show = true
    val = 0

    if saved_data ~= "" then
        local loaded_data = JSON.decode(saved_data)
        light_mode = loaded_data[1]
        val = loaded_data[2]
        tooltip_show = loaded_data[3]
    end
    createAll()
    Wait.frames(updateXML, 10)
    --Wait.time(function() print(self.guid..'Loaded!') end, 5)
end

function updateSave()
    local data_to_save = {light_mode, val, tooltip_show}
    saved_data = JSON.encode(data_to_save)
    self.script_state = saved_data
end

function createAll()
    s_color = {0.5, 0.5, 0.5, 95}

    if light_mode then
        f_color = {0.9,0.9,0.9,95}
    else
        f_color = {0.1,0.1,0.1,100}
    end

    self.createButton({
      label=tostring(val),
      click_function="add_subtract",
      tooltip=ttText,
      function_owner=self,
      position={0,0.05,-0.2},
      height=600,
      width=1000,
      alignment = 3,
      scale={x=1.5, y=1.5, z=1.5},
      font_size=600,
      font_color=f_color,
      color={0,0,0,0}
      })

    self.createButton({
        label="[ Reset ]",
        tooltip="[ Reset ]",
        click_function="reset_val",
        function_owner=self,
        position={0,-0.05,1.4},
        rotation={180,180,0},
        height=250,
        width=1200,
        scale={x=1, y=1, z=1},
        font_size=250,
        font_color=s_color,
        color={0,0,0,0}
        })

    setTooltips()
    
    --updateXML()
    --Wait.frames(updateXML, 10)
end
#
function removeAll()
    self.removeInput(0)
    self.removeInput(1)
    self.removeButton(0)
    self.removeButton(1)
    self.removeButton(2)
    self.removeButton(3)
end

function reloadAll()
    removeAll()
    createAll()
    setTooltips()
    updateSave()
    updateXML()
end

function swap_fcolor(_obj, _color, alt_click)
    light_mode = not light_mode
    reloadAll()
end

function swap_align(_obj, _color, alt_click)
    center_mode = not center_mode
    reloadAll()
end

function swap_tooltip(_obj, _color, alt_click)
    tooltip_show = not tooltip_show
    reloadAll()
    setTooltips()
end

function editName(_obj, _string, value) 
    self.setName(value)
    setTooltips()
end

function add_subtract(_obj, _color, alt_click)
    mod = alt_click and -1 or 1
    new_value = math.min(math.max(val + mod, MIN_VALUE), MAX_VALUE)
    if val ~= new_value then
        val = new_value
        updateVal()
        updateSave()
        updateXML()
    end
end

function updateVal()
    if tooltip_show then
        ttText = "     " .. val .. "\n" .. self.getName()
    else
        ttText = self.getName()
    end

    self.editButton({
        index = 0,
        label = tostring(val),
        tooltip = ttText
        })
end

function reset_val()
    val = 0
    updateVal()
    updateSave()
    updateXML()
end

function setTooltips()
    if tooltip_show then
        ttText = "     " .. val .. "\n" .. self.getName()
    else
        ttText = self.getName()
    end

    self.editInput({
        index = 0,
        value = self.getName(),
        tooltip = ttText
        })
    self.editButton({
        index = 0,
        value = tostring(val),
        tooltip = ttText
        })
end

function null()
end

function keepSample(_obj, _string, value) 
    reloadAll()
end

function updateXML()
    self.UI.setAttribute("FrontVal","text",val)
    print(self.guid..' XML set to '..tostring(val)..'.')    
end
#

lot of stuff in there that I know I can probably delete, but I didn't want to cause any additional bugs.

near ingot
#

... and your xml?

green cliff
#
<Text
  id="FrontVal"
  interactable="false"
  text="front"
  rotation="0 180 180"
  position="0 0 7"
  fontSize="150"  
  textcolor="Red"
  fontStyle="bold"
  textAlignment="MiddleCenter"
>
</Text>

actually works just fine afaict though

woeful whale
#

Wait.frames(updateXML(), 10)
is wrong. Lose the parenthesis after the functionname

near ingot
#
function updateXML()
    self.UI.setAttribute("FrontVal","text",val)
    print(self.guid..' XML set to '..tostring(val)..'.')    
end

val here is nil no?

green cliff
#

all the other functions on the object use val with no issue

near ingot
#

then I don't see the problem but I can't test it ingame at the moment sorry

green cliff
#

Well, at least I'm not going crazy then...
I like a good puzzle, it's a nice way to learn if you have to figure something out by yourself, but his time, the more I learn, the more puzzled I get.

green cliff
# woeful whale val is a global

I'm a bit new to the object oriented thing (no programming experience since `1992), especially terminology. Global here means native to the object, right? There's multiple of those objects so it's can't be global tot the entire mod.

woeful whale
#

(my counter maker is based on these same counters :D)

woeful whale
green cliff
#

Great (so I got the right idea, I was worried again for a sec).

green cliff
# woeful whale this is the problem

It's not:

function onload(saved_data)
    light_mode = false
    tooltip_show = true
    val = 0

    if saved_data ~= "" then
        local loaded_data = JSON.decode(saved_data)
        light_mode = loaded_data[1]
        val = loaded_data[2]
        tooltip_show = loaded_data[3]
    end
    createAll()
        Wait.frames(updateXML, 10)
        --Wait.time(function() print(self.guid..'Loaded!') end, 5)
end

same error

woeful whale
#

it was in the code you linked.
And all you added was the Wait.frames line and the function it calls?

#

What is the exact error message?

green cliff
#

Hm.. yes? (I deleted 3-4 self.createbutton functions first, but as I said, no issues with just that)
Exact error message:

Error in Script (Counter - 1d1ec4) function <onload> Object reference not set to an instance of an object

I tried it with an self-made XML button and function as well. I can get that to work, except when loading. I re-did it based on this mod just to make sure I didn't screw up my own coding in some creative way.

#

I uploaded the work in progress to the workshop... figuring out how to share that now

near ingot
#

I doubt this is the issue, but onload() is deprecated, use onLoad()

#

if you don't know the error line, it's worth putting print/log statements in to figure out which was the last run line, which helps narrow down the cause

near ingot
#

here's an example of a vertical scroll view from the Middara mod I work on:

        <VerticalScrollView width="700" height="440" rectAlignment="LowerCenter">
            <VerticalLayout width="640" height="4400" rectAlignment="UpperLeft" childAlignment="UpperLeft" padding="8,4,4,4" spacing="4">
                <Text/>
                <Text/>

I removed the unimportant parts.

woeful whale
#

and you posted it in the wrong thread 😄

near ingot
#

🤒

green cliff
#

That last suggestion is a good idea...

...something unexpected happened!.

I was already inserting print messaged into the code, but it never occurred to me that I could get better information that way than I got from the error message (when it wasn't reporting a specific line).

It turns out that removing a call to setTooltips() in onLoad solves it.

function setTooltips()
    print('this works 1')
    if tooltip_show then
        ttText = "     " .. val .. "\n" .. self.getName()
    else
        ttText = self.getName()
    end
    print('this works 2')
    self.editInput({
        index = 0,
        value = self.getName(),
        tooltip = ttText
        })
    print('this works 3')
    self.editButton({
        index = 0,
        value = tostring(val),
        tooltip = ttText
        })
    print('this works 4')
end

This only gets to "This works 2". Not sure but maybe trying to edit a button that's not there broke it?
I did some testing and I think I broke it when deleting stuff (i.e I didn't delete enough), missed the interim error, then assumed it was caused by what I added instead of what I took away.
Honestly... 😳 Thanks for letting me waste some of your time.