This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
menz's profile picture

menu table help

Started by menz, 23 November 2012 - 07:31 AM
menz #1
Posted 23 November 2012 - 08:31 AM
ok so im modifying this original code (thanks grim) to have menus within menus
Spoiler– Basic Menu written by PaymentOption –
–[[
We'll be using tables to achieve this menu. Tables are much better for
creating a menu because the methods we'll be writing to manipulate the menu
won't require any modifications if we add more options to the menu. This might
not make sense immediately, but hopefully you'll understand a little better
once we write the code.
]]–

– First, we'll start with declaring the variables we know we'll need.
– We'll be creating a 1 level menu with 3 selections.

local bRunning = true
– The above is the boolean value (true/false) that tells the loop at the bottom of
– this program to keep running the code inside it. If this variable was false, the
– loop would stop executing and our program would end.

local nScreenWidth, nScreenHeight = term.getSize()
– The above is the x and y dimensions of the screen we're currently working with.
– These numbers will help us with drawing our text to the right positions of the screen.

local nSelection = 1
– The above is our current selection. This variable will help us keep track of
– what option we've got currently selected in the menu.

local tMainMenu = {
[1] = { sTitle = "First Option", fAssociatedFunction = FirstOption },
[2] = { sTitle = "Second Option", fAssociatedFunction = SecondOption },
[3] = { sTitle = "Exit", fAssociatedFunction = function() bRunning = false end }
}
– The above is our main menu table.
– It consists of 3 sub tables keyed at 1, 2, and 3.
– Each contains two variables: sTitle and fAssociatedFunction.
– sTitle is the name of the option, or the name we'll print out when the program is run.
– fAssociatedFunction is the identifier, or name, of the function this option will be linked to.
– In other words, if we select this option it will run the function assigned to fAssociatedFunction.

– Now that we've got our variables declared, we'll right our methods, or functions.
– I like to keep my methods orgainzed by purpose. If I have methods that draw stuff,
– they'll be under draw methods. If I have methods that do networking stuff, they'll
– be under networking methods.

– Drawing Methods –

– PrintCentered is a function that prints the text we give it to the exact center of the terminal.
– Its two parameters are the height, or y coordinate, on the screen we want to print to, and the
– text that we want to print there.
function PrintCentered( nHeight, sString )
term.setCursorPos( nScreenWidth/2 - string.len( sString )/2, nHeight )
– The above line positions the cursor on the center of the screen on the given height.
– It accomplishes this, if you're interested, by taking the width of the screen and dividing it in 2,
– so we're now at the center of the screen, then dividing the length of the text we want to print by 2
– then subtracting that number from the screen width divided by 2 to get the exact center of the screen.
term.write( sString )
– The above statement simply prints the string on the current position of the cursor.
end

– ClearScreen is a simple function that clears the screen of all text and reset
– the position of the cursor to the upper left hand corner of the screen.
function ClearScreen()
term.clear()
– The above statement clears the screen of all text.
term.setCursorPos( 1, 1 )
– The above statement repositions the cursor to the coordinates 1,1 (the upper left hand corner).
end

– PrintMenu simply prints out all of the options in the menu passed
– in the center of the screen starting at the given y value.
– !WARNING!
– This method assumes that the menu table passed has the format we used above:
– tMenu[n] = { sTitle, fAssociatedFunction }
function PrintMenu( tMenu, nStartHeight )
– We'll loop through the table to make sure we print every option.
– This is where tables come in handy: if we just use a bunch of if
– statements then we'd have to add a new if every time we added an
– option. This loop and table method will handle all of that for you!
for index = 1, #tMenu do
– Start the iterator at 1 and we'll use it as our index.
– Run this loop as many times as there are indexes in the tMenu table.

– If the iterator has reached the option that is currently selected in the table
– we want to signal to the user somehow that it is selected. We'll do this here
– by drawing brackets around the option, while leaving the other options without
– brackets.
if index == nSelection then
PrintCentered( nStartHeight + ( index - 1 ), "[" .. tMenu[index].sTitle .. "]" )
else
PrintCentered( nStartHeight + ( index - 1 ), " " .. tMenu[index].sTitle .. " " )
end
end
end

– End Drawing Methods –

– Key Handling Methods –

– HandleKeyPress takes a key code, or value, and
– carries out the appropriate action. For example,
– if we pressed enter then this method would execute the
– associated function of the selected option.
function HandleKeyPress( nKey, tMenu )
– I like to use the key codes instead of the keys API, so bare with me.
– This is another place that a table as a menu comes in handy!
– Instead of having to check for each individual enter press on which option,
– we can just run the associated function for that selection in the table!

– If the enter key is pressed then run the associated function of the selected option.
if nKey == 28 then
tMenu[nSelection].fAssociatedFunction()
– If the up key is pressed and the selection is greater than 1 then move the selection up once.
– We check the current selection to make sure we don't move off of the menu when pressing keys.
elseif nKey == 200 and nSelection > 1 then
nSelection = nSelection - 1
– If the down key is pressed and the selection is less than the amount of selections in the given table.
elseif nKey == 208 and nSelection < 3 then
nSelection = nSelection + 1
end
end

– End Key Handling Methods –

– Associated Functions –

– FirstOption is the method that is run when
– the first option is selected and enter is pressed
– on the menu.
function FirstOption()
ClearScreen() – Clear the screen.
PrintCentered( 5, "First option selected." ) – Notify the user that they just pressed the first option.
sleep( 2 ) – Sleep for a couple seconds so the text isn't printed then instantly cleared.
end

– Second option works just like FirstOption.
function SecondOption()
ClearScreen() – Clear the screen.
PrintCentered( 5, "Second option selected." ) – Notify the user that they just pressed the second option.
sleep( 2 ) – Sleep for a couple seconds so the text isn't printed then instantly cleared.
end

– End Associated Functions –

– Main Program Loop –

– Loop this code until bRunning is not true (the program has been exited).

while bRunning do
ClearScreen() – Wipe the screen so we can update it with the newest frame.
PrintMenu( tMainMenu, 5, nSelect ) – Print the main menu starting on line 5.

local sEvent, nKey = os.pullEvent( "key" ) – Wait for any key presses so we can update the menu.
HandleKeyPress( nKey, tMainMenu ) – Perform the appropriate actions for the key pressed.
end

– End Main Program Loop –
and have tried several options, and decided to nest the menu system into a table for use, but i cant figure out what im doing wrong with this table.

local tMainMenu = {
  [1] = {
    [1] = { sTitle = "Go to location", fAssociatedFunction = FirstOption },
    [2] = { sTitle = "Second Option", fAssociatedFunction = SecondOption },
    [3] = { sTitle = "Exit", fAssociatedFunction = function() bRunning = false end }
  }
  [2] = {
    [1] = { sTitle = "Go to saved position", fAssociatedFunction = testOne },
    [2] = { sTitle = "Go to specified X, Y, Z", fAssociatedFunction = testTwo },
    [3] = { sTitle = "Go Back", fAssociatedFunction = testTwo }
  }
}
or is there a better way to go about this?

oh, ive also tried this:

local tMainMenu = {
    [1] = { sTitle = "Go to location", fAssociatedFunction = function() menuselect = tGotoMenu end },
    [2] = { sTitle = "Second Option", fAssociatedFunction = SecondOption },
    [3] = { sTitle = "Exit", fAssociatedFunction = function() bRunning = false end }
  }
 local tGotoMenu = {
    [1] = { sTitle = "Go to saved position", fAssociatedFunction = testOne },
    [2] = { sTitle = "Go to specified X, Y, Z", fAssociatedFunction = testTwo },
    [3] = { sTitle = "Go Back", fAssociatedFunction = testTwo }
  }

any help is appreciated
Tiin57 #2
Posted 23 November 2012 - 09:37 AM
No one can help unless you post errors.
menz #3
Posted 23 November 2012 - 10:19 AM
ok,

attempting to define a tabel produces this error: bios:338 [string "tab"] :7: '}' expected (to close '{' at line 1)

when defining this tabel

local tMainMenu = {
  [1] = {
	[1] = { sTitle = "Go to location", fAssociatedFunction = FirstOption },
	[2] = { sTitle = "Second Option", fAssociatedFunction = SecondOption },
	[3] = { sTitle = "Exit", fAssociatedFunction = function() bRunning = false end }
  }
  [2] = {
	[1] = { sTitle = "Go to saved position", fAssociatedFunction = testOne },
	[2] = { sTitle = "Go to specified X, Y, Z", fAssociatedFunction = testTwo },
	[3] = { sTitle = "Go Back", fAssociatedFunction = testTwo }
  }
}

or if i do it this way
Spoiler

local menuSelect
local nSelection = 1
local bRunning = true
local nScreenWidth, nScreenHeight = term.getSize()



function ClearScreen()
	term.clear()
	term.setCursorPos( 1, 1 )
end

function PrintCentered( nHeight, sString )
	term.setCursorPos( nScreenWidth/2 - string.len( sString )/2, nHeight )
	term.write( sString )
end

function PrintMenu( tMenu, nStartHeight )
	for index = 1, #tMenu do
		if index == nSelection then
			PrintCentered( nStartHeight + ( index - 1 ), "[" .. tMenu[index].sTitle .. "]" )
		else
			PrintCentered( nStartHeight + ( index - 1 ), " " .. tMenu[index].sTitle .. " " )
		end
	end
end

function HandleKeyPress( nKey, tMenu )
	if nKey == 28 then
		tMenu[nSelection].fAssociatedFunction()
	elseif nKey == 200 and nSelection > 1 then
		nSelection = nSelection - 1
	elseif nKey == 208 and nSelection < 3 then
		nSelection = nSelection + 1
	end
end

function FirstOption()
	ClearScreen()
	PrintCentered( 5, "First option selected." )
	sleep( 2 )
end

-- Second option works just like FirstOption.
function SecondOption()
	ClearScreen()
	PrintCentered( 5, "Second option selected." )
	sleep( 2 )
end

local tMainMenu = {
	[1] = { sTitle = "Go to location", fAssociatedFunction = function() menuSelect = tGotoMenu end },
	[2] = { sTitle = "Second Option", fAssociatedFunction = SecondOption },
	[3] = { sTitle = "Exit", fAssociatedFunction = function() bRunning = false end }
  }
local tGotoMenu = {
	[1] = { sTitle = "Go to saved position", fAssociatedFunction = FirstOption },
	[2] = { sTitle = "Go to specified X, Y, Z", fAssociatedFunction = SecondOption },
	[3] = { sTitle = "Go Back", fAssociatedFunction = function() menuSelect = tMainMenu end }
  }

menuSelect = tMainMenu
-------------------------------
while bRunning do
	ClearScreen()
	PrintMenu( menuSelect, 5, nSelect )
	
	local sEvent, nKey = os.pullEvent( "key" )
	HandleKeyPress( nKey, menuSelect )
end

i get tab:19: attempt to get lenght of nil when selecting the first option

again thanks for the help
Grim Reaper #4
Posted 23 November 2012 - 10:32 AM
ok,

attempting to define a tabel produces this error: bios:338 [string "tab"] :7: '}' expected (to close '{' at line 1)

when defining this tabel

local tMainMenu = {
  [1] = {
	[1] = { sTitle = "Go to location", fAssociatedFunction = FirstOption },
	[2] = { sTitle = "Second Option", fAssociatedFunction = SecondOption },
	[3] = { sTitle = "Exit", fAssociatedFunction = function() bRunning = false end }
  } -- You don't have a comma here. The interpreter thinks that you are trying to close the tMainMenu table.
  [2] = {
	[1] = { sTitle = "Go to saved position", fAssociatedFunction = testOne },
	[2] = { sTitle = "Go to specified X, Y, Z", fAssociatedFunction = testTwo },
	[3] = { sTitle = "Go Back", fAssociatedFunction = testTwo }
  }
}



i get tab:19: attempt to get lenght of nil when selecting the first option

again thanks for the help

You forgot to put commas after your super tables containing the sub tables.
Here's how you would fix that:

local tMainMenu = {
  [1] = {
	[1] = { sTitle = "Go to location", fAssociatedFunction = FirstOption },
	[2] = { sTitle = "Second Option", fAssociatedFunction = SecondOption },
	[3] = { sTitle = "Exit", fAssociatedFunction = function() bRunning = false end }
  }, -- Comma goes here.
  [2] = {
	[1] = { sTitle = "Go to saved position", fAssociatedFunction = testOne },
	[2] = { sTitle = "Go to specified X, Y, Z", fAssociatedFunction = testTwo },
	[3] = { sTitle = "Go Back", fAssociatedFunction = testTwo }
  }