Moony Posted March 5, 2020 Share Posted March 5, 2020 Hello, everybody! I'm following this tutorial to make a GUI with a car spawning function. Copy/pasting everything works up until the gridlist. The click doesn't. Could there be a mistake? I recreated the script on my own following step by step: - Client-side - Spoiler local vehiclesTable = { ["Sparrow"] = 469, ["Stuntplane"] = 513, ["BF-400"] = 581, ["Freeway"] = 463, ["Speeder"] = 452, ["Jester"] = 559, ["Sabre"] = 475, ["Police Ranger"] = 599, ["Utility Van"] = 552, ["Tug"] = 583 } function vehSelection() vehList = guiCreateWindow(0.06, 0.33, 0.31, 0.30, "Vehiculos", true) guiWindowSetSizable(vehList, false) botonCrear = guiCreateButton(149, 260, 101, 31, "Crear", false, vehList) lista = guiCreateGridList(0.06, 0.12, 0.87, 0.69, true, vehList) guiGridListAddColumn(lista, "Coches", 0.9) guiSetVisible(vehList,false) populateGridlist() end addEventHandler ("onClientResourceStart", getRootElement(), vehSelection) function showVehicleSelection() if (guiGetVisible(vehList) == false) then guiSetVisible (vehList, true) showCursor (true) else guiSetVisible (vehList, false) showCursor (false) end end addCommandHandler("veh",showVehicleSelection) function populateGridlist() -- loop through the table for name,vehicle in pairs(vehiclesTable) do -- add a new row to the gridlist local row = guiGridListAddRow(lista) -- set the text in the first column to the vehicle name guiGridListSetItemText(lista,row,1,name,false,false) -- set the text in the second column to the vehicle type guiGridListSetItemText(lista,row,2,getVehicleType(vehicle),false,false) -- set the data for gridlist slot as the vehicle id guiGridListSetItemData(lista,row,1,tostring(vehicle)) end end function createVehicleHandler(button,state) if button == "left" and state == "up" then -- get the selected item in the gridlist local row,col = guiGridListGetSelectedItem(lista) -- if something is selected if row and col and row ~= -1 and col ~= -1 then -- get the vehicle id data from the gridlist that is selected local selected = guiGridListGetItemData(lista,row,col) -- make sure the vehicle id is a number not a string selected = tonumber(selected) -- get the players position and rotation local rotz = getPedRotation(getLocalPlayer()) local x,y,z = getElementPosition(getLocalPlayer()) -- find the position directly infront of the player x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3) y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3) if selected and x and y and z then -- trigger the server triggerServerEvent("createVehicleFromGUI",getRootElement(),selected,x,y,z) -- hide the gui and the cursor guiSetVisible(windowVehicleSelection,false) showCursor(false,false) else outputChatBox("Invalid arguments.") end else -- otherwise, output a message to the player outputChatBox("Please select a vehicle.") end end end And here is the problematic part: Spoiler function createVehicleHandler(button,state) if button == "left" and state == "up" then -- get the selected item in the gridlist local row,col = guiGridListGetSelectedItem(lista) -- if something is selected if row and col and row ~= -1 and col ~= -1 then -- get the vehicle id data from the gridlist that is selected local selected = guiGridListGetItemData(glista,row,col) -- make sure the vehicle id is a number not a string selected = tonumber(selected) -- get the players position and rotation local rotz = getPedRotation(getLocalPlayer()) local x,y,z = getElementPosition(getLocalPlayer()) -- find the position directly infront of the player x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3) y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3) if selected and x and y and z then -- trigger the server triggerServerEvent("createVehicleFromGUI",getRootElement(),selected,x,y,z) -- hide the gui and the cursor guiSetVisible(lista,false) showCursor(false,false) else outputChatBox("Invalid arguments.") end else -- otherwise, output a message to the player outputChatBox("Please select a vehicle.") end end end The GUI elements are the same. The only thing that changes are the names. Naturally, it should work by simply replacing the names. However, I believe there might be a mistake on the original script. With everything as it is, I can show and hide the GUI, and click on any vehicle. If I purposely trigger an output, nothing happens. So, waddaya think? Link to comment
The_GTA Posted March 5, 2020 Share Posted March 5, 2020 Dear Moony, let me ask you a simple question because I have not yet tried this amazing tutorial (it is pretty long but looks thorough, thx for sharing!). Do you have the following script line after your createVehicleHandler function definition: addEventHandler("onClientGUIDoubleClick",lista,createVehicleHandler,false) 1 Link to comment
Moony Posted March 5, 2020 Author Share Posted March 5, 2020 10 minutes ago, The_GTA said: Do you have the following script line after your createVehicleHandler function definition: addEventHandler("onClientGUIDoubleClick",lista,createVehicleHandler,false) Though I did forget to add the event handler (which is actually 'onClientGUIClick'), adding it doesn't fix the issue. addEventHandler("onClientGUIClick", botonCrear, "up", createVehicleHandler,false) DB 3: expected element at argument 2 is nil. Line number is the event handler I just added. I tried removing the "up" argument, but nothing changes. Link to comment
The_GTA Posted March 5, 2020 Share Posted March 5, 2020 Sorry for not investigating this tutorial that thoughly but you have to add the code inside the vehSelection function. Otherwise it does not work because the GUI has not been created yet. -- Put createVehicleHandler here. -- Put populateGridlist here -- Etc. function vehSelection() vehList = guiCreateWindow(0.06, 0.33, 0.31, 0.30, "Vehiculos", true) guiWindowSetSizable(vehList, false) botonCrear = guiCreateButton(149, 260, 101, 31, "Crear", false, vehList) lista = guiCreateGridList(0.06, 0.12, 0.87, 0.69, true, vehList) guiGridListAddColumn(lista, "Coches", 0.9) guiSetVisible(vehList,false) populateGridlist() addEventHandler("onClientGUIClick",botonCrear,createVehicleHandler,false) end -- Etc. Explanation: if you put code inside the onClientResourceStart event handler then the code is called after all scripts have been loaded/executed. This is useful if you want to wait until MTA has loaded all custom resource functions into _G before starting your code. Putting code into the event handler is not a requirement but a recommendation. 1 Link to comment
Moony Posted March 6, 2020 Author Share Posted March 6, 2020 It works now. I have a doubt. I have a very basic script that pops up a help memo (similar to the F9 help menu): function openHelp (key, keystate) if (guiGetVisible(helper) == false) then guiSetVisible (helper, true) showCursor (true) else guiSetVisible (helper, false) showCursor (false) end end bindKey("F9", "down", openHelp) Above it, the elements: helper = guiCreateWindow(0.19, 0.20, 0.63, 0.64, "-- 'El Final de la Bala' --", true) guiWindowSetSizable(helper, false) tabs = guiCreateTabPanel(0.03, 0.05, 0.94, 0.91, true, helper) welcomeTab = guiCreateTab("Bienvenido", tabs) welcomeMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, welcome, true, welcomeTab) guiMemoSetReadOnly (welcomeMemo, true) rulesTab = guiCreateTab("Reglas", tabs) rulesMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, rules, true, rulesTab) guiMemoSetReadOnly (rulesMemo, true) functionsTab = guiCreateTab("Funciones", tabs) functionsMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, functions, true, functionsTab) guiMemoSetReadOnly (functionsMemo, true) locationsTab = guiCreateTab("Locaciones", tabs) locationsMemo = guiCreateMemo(0.01, 0.04, 0.98, 0.93, locations, true, locationsTab) guiMemoSetReadOnly (locationsMemo, true) guiSetVisible(helper, false) These elements are placed as seen: without a 'function' header, nor any kind of event handler. However, this works just fine. The player can click through each tab and open/close the memo. Why is it not the same with the spawn panel? Why does it fail when the 'onClientGUIClick' is outside the creation function? I still don't quite get the difference. I had imagined that the event call would be called regardless of its position. Link to comment
The_GTA Posted March 6, 2020 Share Posted March 6, 2020 (edited) 41 minutes ago, Moony said: These elements are placed as seen: without a 'function' header, nor any kind of event handler. However, this works just fine. The player can click through each tab and open/close the memo. Why is it not the same with the spawn panel? Why does it fail when the 'onClientGUIClick' is outside the creation function? I still don't quite get the difference. I had imagined that the event call would be called regardless of its position. Great to hear that it works now Let me try to explain to you the difference between the creation function and without a 'function' header. First, let's see the facts. The creation function is called when the "onClientResourceStart" event is triggered. Your placed elements outside of a function are executed when the script is loaded. I think you have to understand that the GUI variables ("lista", etc) are only available after the creation code has been executed. If you want to convert the tutorial script to your approach without a 'function' header, you can do the following (edited your script from the top post): local vehiclesTable = { ["Sparrow"] = 469, ["Stuntplane"] = 513, ["BF-400"] = 581, ["Freeway"] = 463, ["Speeder"] = 452, ["Jester"] = 559, ["Sabre"] = 475, ["Police Ranger"] = 599, ["Utility Van"] = 552, ["Tug"] = 583 } function showVehicleSelection() if (guiGetVisible(vehList) == false) then guiSetVisible (vehList, true) showCursor (true) else guiSetVisible (vehList, false) showCursor (false) end end addCommandHandler("veh",showVehicleSelection) function populateGridlist() -- loop through the table for name,vehicle in pairs(vehiclesTable) do -- add a new row to the gridlist local row = guiGridListAddRow(lista) -- set the text in the first column to the vehicle name guiGridListSetItemText(lista,row,1,name,false,false) -- set the text in the second column to the vehicle type guiGridListSetItemText(lista,row,2,getVehicleType(vehicle),false,false) -- set the data for gridlist slot as the vehicle id guiGridListSetItemData(lista,row,1,tostring(vehicle)) end end function createVehicleHandler(button,state) if button == "left" and state == "up" then -- get the selected item in the gridlist local row,col = guiGridListGetSelectedItem(lista) -- if something is selected if row and col and row ~= -1 and col ~= -1 then -- get the vehicle id data from the gridlist that is selected local selected = guiGridListGetItemData(lista,row,col) -- make sure the vehicle id is a number not a string selected = tonumber(selected) -- get the players position and rotation local rotz = getPedRotation(getLocalPlayer()) local x,y,z = getElementPosition(getLocalPlayer()) -- find the position directly infront of the player x = x + ( math.cos ( math.rad ( rotz+90 ) ) * 3) y = y + ( math.sin ( math.rad ( rotz+90 ) ) * 3) if selected and x and y and z then -- trigger the server triggerServerEvent("createVehicleFromGUI",getRootElement(),selected,x,y,z) -- hide the gui and the cursor guiSetVisible(windowVehicleSelection,false) showCursor(false,false) else outputChatBox("Invalid arguments.") end else -- otherwise, output a message to the player outputChatBox("Please select a vehicle.") end end end -- Create the GUI here. do vehList = guiCreateWindow(0.06, 0.33, 0.31, 0.30, "Vehiculos", true) guiWindowSetSizable(vehList, false) botonCrear = guiCreateButton(149, 260, 101, 31, "Crear", false, vehList) lista = guiCreateGridList(0.06, 0.12, 0.87, 0.69, true, vehList) guiGridListAddColumn(lista, "Coches", 0.9) guiSetVisible(vehList,false) populateGridlist() addEventHandler("onClientGUIClick", botonCrear, createVehicleHandler, false) end Both ways have no significant differences in the functionality. You could say that too many event handlers pollute the event system. It is good practice to try to implement it both ways. But I usually resort to without a 'function' header in my code. Then you have to put global functions in a specific order: if function A depends on function B, then function B has to be written earlier in the code than function A. I hope that my explanation has helped you understand more of Lua and MTA Edited March 6, 2020 by The_GTA 1 Link to comment
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now