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

How do I make a GUI with key events?

Started by Kadecamz, 13 October 2012 - 10:39 PM
Kadecamz #1
Posted 14 October 2012 - 12:39 AM
Alright, I already know how to do key readings

event, p1 = os.pullEvent()
if event == "key" and p1 == "keycode here" then

But I wanna know how to be able to use them to make those awesome GUI menus, where you press the up/down arrow key to move the selector.

Can somebody teach me how?

Also, I'm wondering how you could do rednet.receive() and os.pullEvent("eventhere") at the same time, say if I was making a rednet broadcasting monitor but also wanted to be able to broadcast something if a key was detected.
Tiin57 #2
Posted 14 October 2012 - 12:52 AM
There are a few menu apis out there. I can't look them up, since my phone dislikes even trying to post this, but they're there. Look through their code, perhaps.
Kadecamz #3
Posted 14 October 2012 - 12:54 AM
Or link me to them, i can't find any.
Fatal_Exception #4
Posted 14 October 2012 - 01:01 AM
Each time you detect a up/down keypress, increment or decement a variable that indicates which menu item you've selected.

As for receiving and detecting other events at the same time:

local event, arg1, arg2, arg3 = os.pullEvent()
if event == "rednet_message" then
  -- arg1 is senderid
  -- arg2 is message
  -- arg3 is distance
elseif event == "key" then
  -- arg1 is keycode
end
remiX #5
Posted 14 October 2012 - 01:10 AM
I have a menu function which I use for my codes - I sort of have a clue how it works but I just know it works well :)/>/>


local function menu(...)
    local sel = 1
    local list = {...}
    local offX,offY = term.getCursorPos()
    local curX,curY = term.getCursorPos()
    while true do
        if sel > #list then sel = 1 end
	    if sel < 1 then sel = #list end
        for i = 1,#list do
            term.setCursorPos(offX,offY+i-1)
		    if sel == i then
                print("["..list[i].."]") -- very customisible example print(">"..list[i])
		    else
                print(" "..list[i].." ") -- very customisible
		    end
        end
	    while true do
            local e,e1,e2,e3,e4,e5 = os.pullEvent()
            if e == "key" then
                if e1 == 200 then -- up key
                    sel = sel-1
                        break
                end
                if e1 == 208 then -- down key
                    sel = sel+1
                        break
                end
                if e1 == 28 then
                    term.setCursorPos(curX,curY)
                    return list[sel],sel
                end
		    end
	    end
    end
end

Then when you want to have text in the menu you use this:


while true do
    local selection = menu(
    "Option 1",
    "Option 2",
    "Option 3")
    if selection == "Option 1" then
   	 Option1()
    elseif selection == "Option 2" then
   	 Option2()
    elseif selection == "Option 3" then
   	 Option3()
    end
end
Kadecamz #6
Posted 14 October 2012 - 01:31 AM
can you put it into one section of code please, just so I can test it.

Also, Fatal.

How would you get the id, msg and distance with the rednet message event?

Would it just be
id, msg = if event == "rednet_message" then
remiX #7
Posted 14 October 2012 - 01:36 AM
This should be fine.


local function menu(...)
	local sel = 1
	local list = {...}
	local offX,offY = term.getCursorPos()
	local curX,curY = term.getCursorPos()
	while true do
		if sel > #list then sel = 1 end
		if sel < 1 then sel = #list end
		for i = 1,#list do
			term.setCursorPos(offX,offY+i-1)
			if sel == i then
				print("["..list[i].."]") -- very customisible example print(">"..list[i])
			else
				print(" "..list[i].." ") -- very customisible
			end
		end
		while true do
			local e,e1,e2,e3,e4,e5 = os.pullEvent()
			if e == "key" then
				if e1 == 200 then -- up key
					sel = sel-1
						break
				end
				if e1 == 208 then -- down key
					sel = sel+1
						break
				end
				if e1 == 28 then
					term.setCursorPos(curX,curY)
					return list[sel],sel
				end
			end
		end
	end
end

function Option1()
  print("You have selected option 1!")
  sleep(3)
end

function Option2()
  print("You have selected option 2!")
  sleep(3)
end

function Option3()
  print("You have selected option 3!")
  sleep(3)
end

while true do
	local selection = menu(
	"Option 1",
	"Option 2",
	"Option 3")
	if selection == "Option 1" then
   	 Option1()
	elseif selection == "Option 2" then
   	 Option2()
	elseif selection == "Option 3" then
   	 Option3()
	end
end
Kadecamz #8
Posted 14 October 2012 - 01:51 AM
Can you please add a note to every single line of code?
just to help me learn.
remiX #9
Posted 14 October 2012 - 02:01 AM
Can you please add a note to every single line of code?
just to help me learn.

As I said in my one post I 'sort of' know how it works… but I'll tell you what I can I guess :)/>/>


local function menu(...)
	local sel = 1
	local list = {...}
	local offX,offY = term.getCursorPos()
	local curX,curY = term.getCursorPos()
	while true do
		if sel > #list then sel = 1 end
		if sel < 1 then sel = #list end
		for i = 1,#list do
			term.setCursorPos(offX,offY+i-1)
			if sel == i then
				print("["..list[i].."]") --[[ The characters between the quotation marks are the characters used to show which option is active ]]--
			else
				print(" "..list[i].." ")
			end
		end
		while true do
			local e,e1,e2,e3,e4,e5 = os.pullEvent() --[[ Pulls the event for when a key is pressed ]]--
			if e == "key" then
				if e1 == 200 then --[[ This detects when the up arrow is pressed, it will then move one up. If you click it when you have the first option active, it will return to the bottom ]]--
					sel = sel-1
						break
				end
				if e1 == 208 then --[[ This detects when the down arrow is pressed, it will then move one down. If you click it when you have the last option active, it will return to the top ]]--
					sel = sel+1
						break
				end
				if e1 == 28 then  --[[ This is when the enter key is pressed. It returns which ever option in the selection is active ]]--
					term.setCursorPos(curX,curY)
					return list[sel],sel
				end
			end
		end
	end
end

function Option1()   --[[ Option1, Option2, Option3 are the functions for each option in the menu. You don't have to do this, I just do it because it looks cleaner. ]]--
  print("You have selected option 1!")
  sleep(3)
end

function Option2()
  print("You have selected option 2!")
  sleep(3)
end

function Option3()
  print("You have selected option 3!")
  sleep(3)
end

while true do
	local selection = menu(	--[[ This is what is displayed on the screen. Separate each with a comma ]]--
	"Option 1",
	"Option 2",
	"Option 3")
	if selection == "Option 1" then		 --[[ If the selected option is this one after clicking enter it would call Option1 function. and so on... ]]--
   	 Option1()
	elseif selection == "Option 2" then
   	 Option2()
	elseif selection == "Option 3" then
   	 Option3()
	end
end

That is actually all I know. If I studied it more I would understand it better but I do not worry because it works fine and I dont need to know how it works. You could ask other people how it works, im sure there are others that understand this code better.
Fatal_Exception #10
Posted 14 October 2012 - 02:33 AM
How would you get the id, msg and distance with the rednet message event?

If you look at the example I gave, you already have them. arg1, arg2, arg3.
Zoinky #11
Posted 14 October 2012 - 03:29 AM
I tried to make a simple one. But, I'm not exactly the best coder :S

Spoiler

local tOptions = {"Stuff #1", "Stuff #2", "Stuff #3"} -- Add menu options here.
local selection = 1

function cPrint(value)
scrap,y = term.getCursorPos()
x, scrap = term.getSize()
x = (x-#value)/2
term.setCursorPos(x,y)
print(value)
end


function pasteMenu()
term.clear()
x,y = term.getSize()
y = (y - #tOptions)/2
term.setCursorPos(x,y)
for i = 1, #tOptions do
  if i == selection then
   cPrint(">> "..tOptions[i].." <<")
  else
   cPrint(tOptions[i])
  end
end
end

function watchKeys()
event, key = os.pullEvent("key")
if key == 208 or key == 31 then
  selection = selection + 1
end
if key == 200 or key == 17 then
  selection = selection - 1
end
if selection > #tOptions then
  selection = 1
end
if selection < 1 then
  selection = #tOptions
end
pasteMenu()
end

pasteMenu()

while true do
watchKeys()
end

I think it's pretty easy to understand. If you need me to explain it just ask :)/>/>

EDIT: Oh and.. You'll need to add code to make it run the tasks. It just pastes the menu atm. Sorry! :)/>/>
remiX #12
Posted 14 October 2012 - 04:18 AM
I tried to make a simple one. But, I'm not exactly the best coder :S

Spoiler

local tOptions = {"Stuff #1", "Stuff #2", "Stuff #3"} -- Add menu options here.
local selection = 1

function cPrint(value)
scrap,y = term.getCursorPos()
x, scrap = term.getSize()
x = (x-#value)/2
term.setCursorPos(x,y)
print(value)
end


function pasteMenu()
term.clear()
x,y = term.getSize()
y = (y - #tOptions)/2
term.setCursorPos(x,y)
for i = 1, #tOptions do
  if i == selection then
   cPrint(">> "..tOptions[i].." <<")
  else
   cPrint(tOptions[i])
  end
end
end

function watchKeys()
event, key = os.pullEvent("key")
if key == 208 or key == 31 then
  selection = selection + 1
end
if key == 200 or key == 17 then
  selection = selection - 1
end
if selection > #tOptions then
  selection = 1
end
if selection < 1 then
  selection = #tOptions
end
pasteMenu()
end

pasteMenu()

while true do
watchKeys()
end

I think it's pretty easy to understand. If you need me to explain it just ask :)/>/>

EDIT: Oh and.. You'll need to add code to make it run the tasks. It just pastes the menu atm. Sorry! :)/>/>

Nice thing I like about mine is that it's all in one function :)/>/> where as yours needs 3
Zoinky #13
Posted 14 October 2012 - 08:09 AM
I tried to make a simple one. But, I'm not exactly the best coder :S

Spoiler

local tOptions = {"Stuff #1", "Stuff #2", "Stuff #3"} -- Add menu options here.
local selection = 1

function cPrint(value)
scrap,y = term.getCursorPos()
x, scrap = term.getSize()
x = (x-#value)/2
term.setCursorPos(x,y)
print(value)
end


function pasteMenu()
term.clear()
x,y = term.getSize()
y = (y - #tOptions)/2
term.setCursorPos(x,y)
for i = 1, #tOptions do
  if i == selection then
   cPrint(">> "..tOptions[i].." <<")
  else
   cPrint(tOptions[i])
  end
end
end

function watchKeys()
event, key = os.pullEvent("key")
if key == 208 or key == 31 then
  selection = selection + 1
end
if key == 200 or key == 17 then
  selection = selection - 1
end
if selection > #tOptions then
  selection = 1
end
if selection < 1 then
  selection = #tOptions
end
pasteMenu()
end

pasteMenu()

while true do
watchKeys()
end

I think it's pretty easy to understand. If you need me to explain it just ask :)/>/>

EDIT: Oh and.. You'll need to add code to make it run the tasks. It just pastes the menu atm. Sorry! :)/>/>

Nice thing I like about mine is that it's all in one function :)/>/> where as yours needs 3

Spoiler

local tOptions = {"Stuff #1", "Stuff #2", "Stuff #3"} -- Add menu options here.
local selection = 1

while true do
term.clear()
x,y = term.getSize()
y = (y - #tOptions)/2
term.setCursorPos(x,y)
for i = 1, #tOptions do
  if i == selection then
   scrap,y = term.getCursorPos()
   x, scrap = term.getSize()
   x = (x-#tOptions[i])/2 - 3
   term.setCursorPos(x,y)
   print(">> "..tOptions[i].." <<")
  else
   scrap,y = term.getCursorPos()
   x, scrap = term.getSize()
   x = (x-#tOptions[i])/2
   term.setCursorPos(x,y)
   print(tOptions[i])
  end
end
event, key = os.pullEvent("key")
if key == 208 or key == 31 then
  selection = selection + 1
end
if key == 200 or key == 17 then
  selection = selection - 1
end
if selection > #tOptions then
  selection = 1
end
if selection < 1 then
  selection = #tOptions
end
end

It doesn't need 3. It's just tidier with 3.