[Closed] getFilenamePath on load problem?
that is what you had to start from. to show the code…
you could save your time… and main… and Bobo’s…
you don’t need global scape at all:
rollout rr "Untitled" width:597 height:498
(
local scriptname = getThisScriptFilename()
local scriptpath = getFilenamePath Scriptname
local bmp = openbitmap (scriptpath + "\\Textures\\Rock 1_COLOR.jpg")
bitmap bmp1 "Bitmap" pos:[27,14] width:527 height:398 bitmap:bmp
)
createdialog rr
Sorry, the code is huge, so had to get to the very basic explanation of problem (which I didn’t know).
Other way it would be total mess.
However, still the function IS needed (for purpose*), so I’m trying to fix (Test (with function).ms. Another script worked since beginning, but it doesn’t do what’s needed for whole script.
- The script has few different loads. The one we fixing is opening the file that always exists.
Another way is a custom selection.
The whole load code is about 40 lines. And for both ways (onload and custom button) its the same, except the paths. That’s why the function is needed, so not to rewrite everything all the time.
the thing that i know for sure now is that the problem is your code.
try to isolate the problem… 40 lines of code is one 10th of average mxs script. so you script is small and easy.
Don’t worry about whole code –
The error already exists in this peace of code:
global Scriptname = getThisScriptFilename()
global Scriptpath = (getFilenamePath Scriptname)
global configfilepath = Scriptpath as string+"\Textures\Rock 1_COLOR.jpg"
rollout rr "Untitled" width:597 height:498
(
bitmap bmp1 "Bitmap" pos:[27,14] width:527 height:398
on rr open do loadpic (configfilepath)
)
createdialog rr
fn loadpic p =
(
rr.bmp1.filename = p
)
So what I’m trying to achieve is to leave the structure the same (so function exists), preferably still get the path vie function parameter (as this is most clean way), but just get rid of the error that appears on the first load.
*The whole load code is about 40 lines. – It’s the part of script that loads the file.
If you insist on using this code structure, try to run the above in your head and see where it makes no sense! You are defining the rollout which has an event that calls the function loadpic() when the rollout is open. BUT the function is NOT defined when the rollout is evaluated, so MAXScript creates a local variable called loadpic instead. THEN you define the function and depending on whether the code looks exactly like this (no outer parentheses) or not, you will get either a global function called loadpic, or a local one that is one scope higher than the implicit local loadpic. In both cases, the event handler will NOT see your function but undefined!
After the first run though, the function loadpic() will already be defined in global scope, so when the line ‘on rr open do loadpic (configfilepath)’ is evaluated, the variable loadpic will be found in the global scope and the existing pointer to it will be used. Thus running the script twice will work.
Once again, with passion:
*You EITHER have to pre-declare in a higher scope any variable you intend to use before it is defined to ensure you get the right pointer to it, or
*Force the search in the global scope using ::
You might want to read this old blog post here:
http://lotsofparticles.blogspot.ca/2009/09/lost-gems-in-maxscript-forcing-global.html
The code below would work, assuming it is all in global scope, so the loadpic function ends up there too. The only change is the :: prefix. Alternatively, you need to pre-declare loadpic right after ‘global configurepath’ so when rr comes along, its event handler can find a pre-existing, elbeit undefined variable and set its pointer to it…
global Scriptname = getThisScriptFilename()
global Scriptpath = (getFilenamePath Scriptname)
global configfilepath = Scriptpath as string+"\Textures\Rock 1_COLOR.jpg"
rollout rr "Untitled" width:597 height:498
(
bitmap bmp1 "Bitmap" pos:[27,14] width:527 height:398
on rr open do ::loadpic (configfilepath)
)
createdialog rr
fn loadpic p =
(
rr.bmp1.filename = p
)
Thanks Bobo for very informative answer.
It really makes sense, that on evaluation the function still wasn’t read by engine, therefore doesn’t exist in memory.
But, here’s another test – I’ve added a button, so the function called much later than evaluation of whole script happens. And it does the same error.
Here’s a code:
global Scriptname = getThisScriptFilename()
global Scriptpath = (getFilenamePath Scriptname)
global configfilepath = Scriptpath as string+"\Textures\Rock 1_COLOR.jpg"
rollout rr "Untitled" width:597 height:498
(
bitmap bmp1 "Bitmap" pos:[27,14] width:527 height:398
button btn1 "Button" pos:[187,431] width:128 height:42
on btn1 pressed do
::loadpic (configfilepath)
)
createdialog rr
fn loadpic p =
(
rr.bmp1.filename = p
)
When I run your script (and replace the image and the path to it with an existing one here so it can find it), it runs ok the first time and shows the image when I press the button.
Are you sure you are getting the SAME error message?
Your script has another error:
global configfilepath = Scriptpath as string+"\Textures\Rock 1_COLOR.jpg"
should be
global configfilepath = Scriptpath +"\\Textures\\Rock 1_COLOR.jpg"
This is because is the escape code for the Tab character, so a string “\Textures” is read as “(Tab) extures” and will fail to load the image.
I think you still did not understand what I wrote in my previous posts – it is not about when in time an action is executed (opening the rollout vs. pressing the button). It is about when it time a variable is encountered while evaluating the script line by line.
MAXScript parses the code and processes each line top to bottom as you have written them. So the line numbers in MAXScript represent a time line, too! So if you mention a variable name on, say, line 10 and that variable is defined on line 20 for example, on line 10 there will be no knowledge of that variable’s existence. MAXScript goes looking through the current local scope, all parent local scopes and finally in the global scope. If no variable with that name is found anywhere, a new local variable is created in the local scope and line 10 will point at it. The initial value of this variable is ‘undefined’.
Then on line 20 MAXScript encounters the same variable name, goes looking for it in the current scope and ALSO does not find it (because the previous occurrence on line 10 was in a lower scope that is not active on line 20). So MAXScript creates a new variable with the same name but a different memory location, and line 20 points at it. So the two are independent.
Then the evaluation (compiling) of the code ends and the execution (run-time) starts – the code starts running and when it reaches whatever operation is performed on line 10, it finds a variable with a value of undefined and chokes on it.
Now if you would put a declaration in a higher scope on line 1 for example that creates the variable, it makes it visible to both lines 10 and 20 and suddenly both will SHARE the same memory address – 10 will be ready to access it, 20 will be ready to define its value. So when line 10 is executed, the value will be the one set during evaluation by line 20.
Alternatively, if you don’t pre-declare earlier, but prefix line 10 with :: and line 20 is in global scope, the two will meet again in memory because line 10 is skipping local scopes and going straight to global, thus creating the memory location during evaluation, and 20 fills in the value during evaluation. Thus at run-time, 10 sees what 20 wrote there and the value is not undefined anymore.
So when I am talking about order of evaluation and execution, I mean the timeline of MAXScript, not your user perspective of pushing buttons. You have to learn to “evaluate and run” the code in your head to figure out what MAXScript would see and do to avoid these problems…
SOLVED!!!
Sorry guy for very long discussion. But you really helped me to get to the source of the problem and prevent one more to happen.
Here’s all explanation:
After last test I published (with button) it was very clear that the problem lies in
global configfilepath = Scriptpath as string+”\Textures\Rock 1_COLOR.jpg”
and it’s definitely it is in its format (like: filename, string, float).
Since the beginning I thought it should be a “filename” as that’s what he had problems with converting to (in error log). Always was thinking that it looses format, due to sending it as parameter. But somehow on the second run it was managing to do that.
The problem was that it never wanted a filename at all.
It this part of code:
fn loadpic p =
(
rr.bmp1.filename = p
)
P had to be a string (not a filename). That where all problem was going from.
So solution is so, damn, simple as this:
global configfilepath = Scriptpath as string+"\Textures\Rock 1_COLOR.jpg" as String
All was needed is to add “as String” after path, to convert it to string.
But again thanks for pointing on function position in script!
That would be next problem that gives the same type of error.
So the solution is also very simple here:
Just move load () function in script at very top (before Rollout starts). In this case on evaluation the Max loads the function before it gets called.
Unfortunately, another solution offered – to add “::” before function – didn’t work in this case.
Thanks Bobo,
I was updating my previous answer while you added yours.
I’ve added that simplest solution is just to move function to the top of the script, so it’s gets into memory before called.
Your script has another error:
Code:
global configfilepath = Scriptpath as string+”\Textures\Rock 1_COLOR.jpg”should be
Code:
global configfilepath = Scriptpath as string+”\Textures\Rock 1_COLOR.jpg”This is because is the escape code for the Tab character, so a string “\Textures” is read as “(Tab) extures” and will fail to load the image.
Thanks for that, now it explains few things I’ve noticed in Listener – there was a major skip in line and were no letter T. Now it makes sense.
Also I think (I hope I did) I understood it correctly about creation of new local variable in case if it didn’t find existing one. It make sense. Will keep looking for those things more carefully.
Final structure of script:
global Scriptname = getThisScriptFilename()
global Scriptpath = (getFilenamePath Scriptname)
global configfilepath = Scriptpath as string+"\Textures\Rock 1_COLOR.jpg" as String
rollout rr "Untitled" width:597 height:498
(
bitmap bmp1 "Bitmap" pos:[27,14] width:527 height:398
fn loadpic p =
(
rr.bmp1.filename = p
)
on rr open do loadpic (configfilepath)
)
createdialog rr