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

Clickable buttons in CC

Started by Engineer, 11 March 2013 - 09:18 AM
Engineer #1
Posted 11 March 2013 - 10:18 AM
Hello and welcome to my first tutorial ever. This is about creating buttons as title tells you. :P/>/>

So you want to create buttons?
We first have to collect some information before continueing:
xMin = the first position on the horizontal axis
xMax = the last postion on the horizontal axis

yMin = the first position on the vertical axis
yMax = the second position on the vertical axis

Here is a tool-program to help you out, it is straight forward what you should do..
The program ( Obviously run on an advanced computer ) can be downloaded here. Or you can do pastebin get ywa52Eh4

Now you have your values you have to think ifyou want to get multiple buttons. If you want multiple buttons you need their values as well.
If I look at myself, I use multiple buttons or none, so I will start with multiple buttons.

Note: If you are making one button, also read multiple buttons because I am recalling items from them

Multiple buttons
Let's go and process your values. I like them to put them in a table so you have later an easier way of determining which button is clicked.
So I tend als to use a "template" so you can easily look up what you have done

local tCoords = {
  -- xMin, xMax, yMin, yMax, representable string
  -- That string is easier for debugging, thats for later
  [1] = { 12, 16, 8, 10, "X" }, -- button 1: xMin = 12, xMax = 16, yMin = 8, yMax = 10, representable string = X
  [2] = { 1, 2, 1, 19, "OK" },
  -- etc..
}

What you always have to do next is use this:

local evt, button, x, y = os.pullEvent("mouse_click")  -- In the terminal
local evt, side, x, y = os.pullEvent("monitor_touch")   -- on your monitor

You have to do this because it sits and wait until you touch the monitor or click your terminal. You also get your values to compare with of this.

So now we have our values and we can see our positions we clicked or touched on, we can start determining wich button we actually clicked.
So first we want to do a for-loop, and that for the length of the table tCoords. We will do this because then we can get all values of all the current buttons.
You get the length of a table by doing:

#<your table name>

If you don't know how to do a for-loop, here it is:

for i = 1, #tCoords do
   --code
end
The variable i is the most used variable for this. Than you say from <number>, <tonumber>, <step or default 1> do myCode end
So in our for-loop we loop through number 1 to 2, because we have 2 buttons in our table.

This is the total code we will use for determining our button, I will explain the loop later.


local tCoords = {
  -- xMin, xMax, yMin, yMax, representable string
  -- That string is easier for debugging, thats for later
  [1] = { 12, 16, 8, 10, "X" }, -- button 1: xMin = 12, xMax = 16, yMin = 8, yMax = 10, representable string = X
  [2] = { 1, 2, 1, 19, "OK" },
  -- etc..
}

local evt, button, x, y = os.pullEvent("mouse_click")  -- In the terminal

for i = 1, #tCoords do
	 if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
			button = i
			break
	 end
end

So basicly we say in the for loop:
if the x is bigger or equal than our xMin and smaller or equal to our xMax ( also for yMin and yMax )
then we say, our button is the current loopnumber if that makes sense
so we break out of this loop because we have found our button.

If no button has been found then nothing happens. Then we have not found our button.

Now for debugging, now we have variable button ( if we found a button that matches our xMin, xMax, yMin, yMax ) so we can easily fill in button:

if debug and button then -- only if button is not nil and debug is enabled
	print( "Found button: " .. tCoords[button][5] )
end
And at this point the representable string makes sense, right? :)/>/>

A good example is my Basic Calculator, it uses the same code for determining buttons! You can check the code overthere.

Single button
This time we don't have to put our values in a table, we can use an good old if statement. So your code should look like this:

local evt, button, x, y = os.pullEvent("mouse_click")
if x >= [your xMin] and x <= [your xMax] and y >= [your yMin] and y <= [your yMax] then
   -- your code
end

Well I should not have to explain much about this, because you have read multiple buttons aswell right?

This should wrap up my tutorial,

If you find any spelling errors or if you have a question post it below!
Also feedback is appreciated.


Engineer

Also check out LBPHacker's button API, now you know the logic behind it and can use this:
http://www.computerc...9382#entry99382
Edited on 28 May 2013 - 12:33 PM
Genclone #2
Posted 12 March 2013 - 04:20 AM
Thanks this will help a lot with my Os since i was wondering how to do something like this. :D/>
Engineer #3
Posted 12 March 2013 - 05:04 AM
Thanks this will help a lot with my Os since i was wondering how to do something like this. :D/>

Im glad I could help :)/>
Spongy141 #4
Posted 17 March 2013 - 06:36 AM
After reading your tutorial I tried to make mutilple button options for my OS, and the multuple buttons don't work, and end up over lapping them sleves, how to you prevent buttons end function to interact with the other. Like

local tCoords = {
  [1] = {1, 2, 3, 4, "Login" },
  [2] = {10, 20 , 30 , 40, "Create Account" },
}

for i = 1, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
	button = i
	login()  --the function were my login feature is.
	break
  end
end

for i = 2, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
	button = i
	setup()  --the function were my setup feature is.
	break
  end
end
And everytime they either cancel each other out, or when I click login, it goes to the setup function… How do I fix it?
LBPHacker #5
Posted 17 March 2013 - 07:48 AM
Try this - It's more portable


local tCoords = {
  [1] = {1, 2, 3, 4, "Login", func = login}, -- hooks up "login" function to this button
  [2] = {10, 20 , 30 , 40, "Create Account", func = setup}, -- hooks up "setup" function to this button
}

for i = 1, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
		tCoords[i].func() -- executes the function hooked to the button
		break
  end
end
cant_delete_account #6
Posted 17 March 2013 - 10:17 AM
Try this - It's more portable


local tCoords = {
  [1] = {1, 2, 3, 4, "Login", func = login}, -- hooks up "login" function to this button
  [2] = {10, 20 , 30 , 40, "Create Account", func = setup}, -- hooks up "setup" function to this button
}

for i = 1, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
		tCoords[i].func -- executes the function hooked to the button
		break
  end
end
You forgot the parentheses at the end of .func, it should be:

tCoords[i].func()
Yopu #7
Posted 17 March 2013 - 10:43 AM
Very nice work. I've been trying to wrap my brain around this kind of thing for a while.
Engineer #8
Posted 17 March 2013 - 10:52 AM
After reading your tutorial I tried to make mutilple button options for my OS, and the multuple buttons don't work, and end up over lapping them sleves, how to you prevent buttons end function to interact with the other. Like

local tCoords = {
  [1] = {1, 2, 3, 4, "Login" },
  [2] = {10, 20 , 30 , 40, "Create Account" },
}

for i = 1, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
	button = i
	login()  --the function were my login feature is.
	break
  end
end

for i = 2, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
	button = i
	setup()  --the function were my setup feature is.
	break
  end
end
And everytime they either cancel each other out, or when I click login, it goes to the setup function… How do I fix it?
Try this - It's more portable


local tCoords = {
  [1] = {1, 2, 3, 4, "Login", func = login}, -- hooks up "login" function to this button
  [2] = {10, 20 , 30 , 40, "Create Account", func = setup}, -- hooks up "setup" function to this button
}

for i = 1, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
		tCoords[i].func -- executes the function hooked to the button
		break
  end
end
Try this - It's more portable


local tCoords = {
  [1] = {1, 2, 3, 4, "Login", func = login}, -- hooks up "login" function to this button
  [2] = {10, 20 , 30 , 40, "Create Account", func = setup}, -- hooks up "setup" function to this button
}

for i = 1, #tCoords do
  if x >= tCoords[i][1] and x <= tCoords[i][2] and y >= tCoords[i][3] and y <= tCoords[i][4] then
		tCoords[i].func -- executes the function hooked to the button
		break
  end
end
You forgot the parentheses at the end of .func, it should be:

tCoords[i].func()

Seems that fixed itself xD


Very nice work. I've been trying to wrap my brain around this kind of thing for a while.

Thank you!
LBPHacker #9
Posted 17 March 2013 - 01:13 PM
You forgot the parentheses at the end of .func, it should be:

tCoords[i].func()

ohhcrap :D/> sorry, and thanx, thesbros - fixed
Spongy141 #10
Posted 18 March 2013 - 05:07 PM
Thanks guys. And great tutorial, it REALLY helped me. Now my programs are not so boring.
thegreatstudio #11
Posted 19 March 2013 - 04:07 AM
THX BRO!!
thegreatstudio #12
Posted 19 March 2013 - 04:12 AM
it is not working!! it just show a blank text on he bottom of the screen
Engineer #13
Posted 19 March 2013 - 04:14 AM
it is not working!! it just show a blank text on he bottom of the screen
Give me some code so I can try to fix it?
thegreatstudio #14
Posted 19 March 2013 - 05:28 AM
local tCoords = {


[1] = {10, 20, 30, 40, "edit", func = edit}
[2] = {6, 7, 8, 9, 10, "start", func = startup}


}


local evt, button, x, y = os.pullEvent("mouse_click")


for i = 1, #tCoords do
if x >= tCoords[1] and x <= tCoords[2] and y >= tCoords [3] and y <=tCoords[4] then
tCoords.func()
break
end
end

if debug and button then
print( "Found Button: ".. tCoords[button][1] )
end


—- HERE Engineer
Engineer #15
Posted 19 March 2013 - 05:43 AM
local tCoords = {


[1] = {10, 20, 30, 40, "edit", func = edit}
[2] = {6, 7, 8, 9, 10, "start", func = startup}


}


local evt, button, x, y = os.pullEvent("mouse_click")


for i = 1, #tCoords do
if x >= tCoords[1] and x <= tCoords[2] and y >= tCoords [3] and y <=tCoords[4] then
tCoords.func()
break
end
end

if debug and button then
print( "Found Button: ".. tCoords[button][1] )
end


—- HERE Engineer
edit and startup are no functions. For that you have to do:

shell.run( tCoords[i].func )
Also, edit needs an argument: ex.:

shell.run( tCoords[i].func .. " myprogram" )

Do not blame my code, for others including myself it worked fine. Please look at your own code before even blaming me.
And for the future, please head to ask a pro if you cant work out your func.

If this is not what you meant, please head to ask a pro, this is a tutorial, not solving your problems thread.
thegreatstudio #16
Posted 19 March 2013 - 05:06 PM
oh….

the problem is the buttons is not showing..
Engineer #17
Posted 20 March 2013 - 03:01 AM
oh….

the problem is the buttons is not showing..
You have to do that yourself, now you have you buttons clickable, there is nothing in this code to show the button itself
Ristyo #18
Posted 21 March 2013 - 04:50 AM
Thanks dude, it also make my Os GUI not boring, haven't written the code yet *facepalm*
PixelToast #19
Posted 21 March 2013 - 05:10 AM
most of the time i use custom if statements for each button
good tutorial though
theoriginalbit #20
Posted 21 March 2013 - 05:15 AM
most of the time i use custom if statements for each button
How very cumbersome, unreadable, error prone, and inefficient of you…
PixelToast #21
Posted 21 March 2013 - 05:46 AM
> not unreadable to me at least
> not error prone
> more efficient than looping through a table every time you click v_v
> my method is more dynamic
thegreatstudio #22
Posted 21 March 2013 - 03:52 PM
Yeah hey. My os is now gui! Thanks for helping me theOriginalbit and engineer.
Ristyo #23
Posted 22 March 2013 - 03:09 AM
im still confused how to make the buttons show up though
PixelToast #24
Posted 22 March 2013 - 04:01 AM
im still confused how to make the buttons show up though
you have to make them yourself

term.setCursorPos(2,2)
term.write("I'm a button!")

EDIT: or do what the original bit said
theoriginalbit #25
Posted 22 March 2013 - 04:09 AM
im still confused how to make the buttons show up though
Since the tutorial gets you to put x, y and text into a table

term.setBackgroundColor(colors.blue)
term.setTextColor(colors.white)
for i = 1, #buttons_table do
  local button = buttons_table[i]
  for y = 1, button[4] do
	for x = 1, button[3] do
	  term.setCursorPos( button[1] + x, button[2] + y )
	  write(' ')
	end
  end
  term.setCursorPos( button[1], button[2] )
  write( button[5] )
end
the above code would print them all out.
ScruffyRules #26
Posted 29 March 2013 - 08:24 PM
local evt, button, x, y = os.pullEvent("mouse_click")
if x >= [your Xmin] and x <= [your xMax] and y >= [your yMin] and y <= [your yMax] then
– your code
end

If you find any spelling errors or if you have a question post it below!
Also feedback is appreciated.
Engineer #27
Posted 30 March 2013 - 12:39 AM
local evt, button, x, y = os.pullEvent("mouse_click")
if x >= [your Xmin] and x <= [your xMax] and y >= [your yMin] and y <= [your yMax] then
– your code
end

If you find any spelling errors or if you have a question post it below!
Also feedback is appreciated.
Thanks, edited out :)/>
CtrlAltElite #28
Posted 27 May 2013 - 07:32 PM
Multiple buttons
Let's go and process your values. I like them to put them in a table so you have later an easier way of determiningwich which button is clicked.
Engineer #29
Posted 28 May 2013 - 02:32 PM
Multiple buttons
Let's go and process your values. I like them to put them in a table so you have later an easier way of determiningwich which button is clicked.
Thank you, edited it out!
EpicPigChops #30
Posted 01 June 2013 - 07:52 PM
How would you output the buttons to a monitor?
Engineer #31
Posted 01 June 2013 - 08:32 PM
You would use os.pullEvent('monitor_touch') instead of os.pullEvent('mouse_click')
And for your information, this tutorial is about making a button and not about displaying a button.
Nytohan #32
Posted 03 June 2013 - 06:41 AM
I wish I had come here and read through the forums sooner, but I muddled through and came up with a reasonable method of getting clickable buttons on my advanced monitors.

I actually wrote a set of mini-operating systems that work together for the purpose of replacing the wireless redstone mod that will be leaving FTB if redpower doesn't get updated, and so far it's working splendidly!


Now, right off the bat I do not claim to be a world-class programmer. What I do claim to be is someone who can set a goal and make it happen, albeit sloppily, so if my code offends you, please keep the criticism constructive!

First off. this is a small screen sample of the final product:
http://dev.extrabit.ca/minecraft/cc/nOS/screenshots/Small%20Terminal%20Display.png

It does adjust automatically, and on the fly, so you can place more screens and everything remains clickable without rebooting.

This is the configuration file for adding more buttons:
http://dev.extrabit.ca/minecraft/cc/nOS/screenshots/Small%20Display%20buttons.config.png

You don't have to hard-code any coordinates, it will generate the button and keep track of its position for you.
The syntax here is Label: server event|state

The label is what you see on the screen, the server optional but it's where you want to send the command to with the channel number that server listens on in a separate config, and with an optional 't' before the servers name if the button is a toggle (can be turned on or off)

The event is the command name to send to that server, for the purposes of differentiation (one server can handle multiple clients which themselves deal directly with machines) and the state is the default starting state of the button.

True and false are pretty obvious, pulse means when the command reaches its client, the redstone pulses on for 1 second, then off (I use it to play music.)
and ~true and ~false are used when you want to have the button show the opposite of the redstone state.

For example, my witch spawner is off by default, but that means the restone is ON to prevent them from spawning. I want the computer to show that they are not spawning with the button being red(off) so I use ~false so that the display will show false but the redstone will be set to true.

For anyone who wants to peek at the code, it's available here:

http://dev.extrabit.ca/minecraft/cc/nOS/buttons.lua

With the draw code being in my gui file.

If anyone has some ideas as to how I could improve this code, I'd welcome it, and if you would like to try the OS out, PM me and I will gladly share install instructions.
Nytohan #33
Posted 03 June 2013 - 03:38 PM
> not unreadable to me at least
> not error prone
> more efficient than looping through a table every time you click v_v
> my method is more dynamic

I'm a tad confused, if you're using custom statements for your buttons, you still need a loop somewhere to determine which button was clicked, don't you?
Are you placing each one as a possible if…then inside your main program loop?
Also, how is it "more dynamic", what's the advantage of your buttons over the tutorials buttons?
Would you be willing to share a code sample?
cory1234567 #34
Posted 07 June 2013 - 09:24 AM
a video of this tutorial would be very helpful
Engineer #35
Posted 11 June 2013 - 06:50 AM
a video of this tutorial would be very helpful
I am going to leave that to others, since Im not that good in pronouncing English..