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

Event intermediate - mouse_click, clickable buttons (more to be added)

Started by KingofGamesYami, 27 May 2014 - 10:49 PM
KingofGamesYami #1
Posted 28 May 2014 - 12:49 AM
mouse_click

The mouse_click event returns the following values:
• The mouse button that was clicked. This is 1 for left, and 2 for right.
• The X-coordinate
• The Y-coordinate

Using just this information, we can construct a simple program to tell us information about the event

while true do
 local event = {os.pullEvent()}
 if event[1] == "mouse_click" then
  print("button "..event[2].." was clicked at ("..event[3]..", "..event[4]..")")
 else
  print("the program received a "..event[1].." event!")
 end
end

Additionally, you can use this to create a better "press any key to continue" program:

print("press any key or click the mouse to continue")
local event
do
 event = {os.pullEvent()}
until event[1] == "mouse_click" or event[1] == "key"
Buttons


Another practical application is creating "buttons."
Buttons do not have to be visible! You can create invisible buttons! This is because they should not be thought about as "objects". They are not objects. There are many ways to create them.
The most popular way of creating a button is using a button api, as most people think they are confusing. In this next section, I will show you how to handle buttons without an api.

First, we need to define a table to keep our buttons in

local buttons = {}

Now that your brain has been strained by this difficult step, we can move on to defining our buttons.

local newbutton = {
  minx = 1,
  maxx = 2,
  maxy = 2,
  miny = 1,
  left = function() print("clicked left!") end,
  right = function() print("clicked right!") end,
}
buttons["testbutton"] = newbutton
Woah. My mind is blown. absolutely nothing shows up on screen! You must have done something wrong!

Now, we want our button to be visible to the user, or they cannot find it! We must write some text on the screen:

term.setCursorPos(1, 1)
term.write("XX")
term.setCursorPos(1, 2)
term.write("XX")

Now, to check our buttons, we are going to need a for loop. Notice I am using in pairs, as to enable "names" on our buttons. You will see there is a purpose for this later on.

event = {os.pullEvent()}
if event[1] == "mouse_click" then
 for k, v in pairs(buttons) do
  if buttons[k].maxx >= event[3] and buttons[k].maxy <= event[3] and buttons[k].maxy >= event[4] and buttons[k].miny <= event[4] then
  if event[2] == 1 then
   buttons[k].left()
  elseif event[2] == 2 then
   buttons[k].right()
  end
 end
else
 print("event "..event[1].."received!")
end
Wow that's a lot of comparisons! Lets break it down a little.

buttons[k].maxx >= event[3] and buttons[k].minx <= event[3]
Here we are checking if the user clicked within the given x values, in my example this means it is between 1 and 2.



buttons[k].maxy >= event[4] and buttons[k].miny <= event[3]
Here we check if the user clicked within the given y values, in my example this is 1 and 2.



if event[2] == 2 then
 buttons[k].left()
elsif event[2] == 1 then
 buttons[k].right()
Here we check which button the user clicked, right or left, and activate the desired function.

Back to the custom names. The reason I would want to do such a thing is so you can remove your buttons later on.

buttons.testbutton = nil
We can of course, use other methods

table.remove(buttons, "testbutton")
You could redefine buttons by overwriting the contents, but this is generally a bad idea and will result in errors if you are not careful.

To test your skills as a button creator, try to create a script that draws a button at 5, 5 that displays "shutdown", calls os.shutdown() when right clicked, and calls os.sleep(1) if left clicked. If you can do this, there is not much you can't do with buttons or mouse_click events.

You may have noticed that I am pulling my events like this:

local event = {os.pullEvent()}
instead of like this

local event, param1, param2, param3, param4, = os.pullEvent()
There is really not much difference, I just feel it is easier to manipulate a table, as you can use the "#" operator to get the number of values.
If you want to use the other method, you can replace the following:

event[1] = event
event[2] = param1
event[3] = param2
event[4] = param3
event[5] = param4

Please note that this code will not work on monitor_touch events, as they do not return whether they were "punched" or "pushed".

This is my first attempt at writing a tutorial, and would like to incorporate any and all constructive criticism.
Edited on 27 May 2014 - 11:08 PM
hbomb79 #2
Posted 03 August 2014 - 07:06 AM
Wow, Thanks this tutorial is actually pretty helpful, I would love more ways of checking buttons… As in whether they checked it using loops and other things, and also how to make the button have a background and text when created.

Other than that, Well done