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

Trouble with Classes

Started by Neander_King, 04 April 2015 - 01:42 PM
Neander_King #1
Posted 04 April 2015 - 03:42 PM
So I'm trying to make a button api for computer terminals, using Lua's metatable/class system. However, when I try to get the object's text, it returns the error:

classTest:15: attempt to index ? (a nil value)
I expect the getText function to return the object's instance of Button's text variable.

Button = {data={
  text = "Button",
  tColor = colors.blue,
  bColor = colors.white,
  id = 1,
}}
function Button.__init__(data)
  local self = {data=data}
  setmetatable(self,{__index=Button})
  return self
end
function Button:getText(self)
  return self.data.text
end
local customButton = Button.__init__()
customButton:getText()
SquidDev #2
Posted 04 April 2015 - 03:46 PM
The trouble is this line:

local customButton = Button.__init__()

You should be passing data there like:


local customButton = Button.__init__({ text = "Button", tColor = colors.blue, bColor = colors.white, id = 1, })
Neander_King #3
Posted 04 April 2015 - 04:05 PM
The trouble is this line:

local customButton = Button.__init__()

You should be passing data there like:


local customButton = Button.__init__({ text = "Button", tColor = colors.blue, bColor = colors.white, id = 1, })

Is there a way to make the object inherit any fields that I don't specify? Like if I did:

local customButton = Button.__init__({text = "Example"})
SquidDev #4
Posted 04 April 2015 - 04:13 PM
-snip-

If you just remove the data key:


Button = {
  text = "Button",
  tColor = colors.blue,
  bColor = colors.white,
  id = 1,
}
function Button.__init__(self)
  return setmetatable(self,{__index=Button})
end

function Button:getText(self)
  return self.text
end
Neander_King #5
Posted 04 April 2015 - 04:24 PM
I got rid of the data table, but now if I do:

local customButton = Button.__init__()
It says bad argument, table expected, got nil. But when I add a table of values like so:

local customButton = Button.__init__({text = "Hello", id = 3,})
It gives an attempt to index ? error when returning self.text.
SquidDev #6
Posted 04 April 2015 - 04:38 PM
I got rid of the data table, but now if I do:

local customButton = Button.__init__()
It says bad argument, table expected, got nil. But when I add a table of values like so:
For this you can do:

setmetatable(self or {},{__index=Button})
The self or {} effectively sets the default value to be {}.


local customButton = Button.__init__({text = "Hello", id = 3,})
It gives an attempt to index ? error when returning self.text.
This function:

function Button:getText(self)
  return self.text
end
has a colon between the Button and getText. This means you don't need the self argument as well. So

function Button:getText()
  return self.text
end
will work fine.
Edited on 04 April 2015 - 02:38 PM
Neander_King #7
Posted 05 April 2015 - 11:09 PM
This is the beginning of a button api I'm writing. I want the user to be able to press a button and trigger a specific function that's stored inside the button object.


os.loadAPI("gui")
--Button Class
Button = {
  text = "Default",
  tColor = colors.white,
  bColor = colors.black,
  borderColor = colors.gray,
  onPressedColor = colors.lightGray,
  func = nil,
  x1 = 1,
  x2 = 10,
  y1 = 1,
  y2 = 10,
}
function Button.__init__(self)
  return setmetatable(self or {},{__index = Button})
end
function Button:draw()
  gui.borderBox(self.x1,self.y1,self.x2,self.y2,self.bColor,self.borderColor)
  gui.writeCentered(self.text,((self.x2-self.x1)/2)+self.x1,((self.y2-self.y1)/2)+self.y1,self.tColor,self.bColor)
end
function Button:setText(newText)
  self.text = newText
end

--Testing Objects
local testButton1 = Button.__init__({
  text="Test",
  tColor=colors.blue,
  bColor=colors.white,
  func = function x() return Button:setText("Hello") end,
  x1=20,
  x2=30,
  y1=1,
  y2=5,
})
local testButton2 = Button.__init__({
  text="Test 2",
  tColor=colors.green,
  bColor=colors.red,
  x1=31,
  x2=50,
  y1=1,
  y2=5,
})
testButton1:draw()
testButton2:draw()
os.sleep(3)
testButton1.func()

The code doesn't work now, because it gives a BIOS:366: [string "button"]:34: '(' expected.
How would I store a function in testButton1.func, and activate it?
To test it, here's the pastebin for my gui api: QzBSawh6
valithor #8
Posted 05 April 2015 - 11:14 PM
On line 34 I am assuming you want the func variable to equal the function that follows it. If that is the case you do not need to declare the function the way it is being declared.

func = function() return Button:setText("Hello") end,
Neander_King #9
Posted 05 April 2015 - 11:19 PM
That seems to work, but when I use testButton1.draw after testButton1.func() it gives an error: button:22: attempt to index ?.

Edit:
When I tested this, the function isn't actually getting called, because before and after I do testButton1.func() the text field stays the same, when it should be set to "Hello".
Edited on 05 April 2015 - 09:25 PM
valithor #10
Posted 05 April 2015 - 11:34 PM
I have not used self much, so I really can not help anymore, but what I have found is your function setText is changing the text variable inside of the Button table to "hello" when you call it inside of testButton1. Also you would have to redraw the button in order for any changes to be visible either way.
Neander_King #11
Posted 05 April 2015 - 11:55 PM
I am trying to make a button api, where the user can create button objects, including setting up functions for the buttons to execute when activated.

os.loadAPI("gui")
--Button Class
Button = {
  text = "Default",
  tColor = colors.white,
  bColor = colors.black,
  borderColor = colors.gray,
  onPressedColor = colors.lightGray,
  func = nil,
  x1 = 1,
  x2 = 10,
  y1 = 1,
  y2 = 10,
}
function Button.__init__(self)
  return setmetatable(self or {},{__index = Button})
end
function Button:draw()
  gui.borderBox(self.x1,self.y1,self.x2,self.y2,self.bColor,self.borderColor)
  gui.writeCentered(self.text,((self.x2-self.x1)/2)+self.x1,((self.y2-self.y1)/2)+self.y1,self.tColor,self.bColor)
end
function Button:setText(text)
  self.text = text
end

--Creating Objects for testing
local testButton1 = Button.__init__({
  text="Test",
  tColor=colors.blue,
  bColor=colors.white,
  func = function() Button:setText("Hello world") end,
  x1=20,
  x2=30,
  y1=1,
  y2=5,
})
local testButton2 = Button.__init__({
  text="Test 2",
  tColor=colors.green,
  bColor=colors.red,
  x1=31,
  x2=50,
  y1=1,
  y2=5,
})
print(testButton1.text)
testButton1.func()
print(testButton1.text)

This code just ends up changing the Button class itself as opposed to the testButton1 object. How do I make it so that I can have a function inside of the object that calls a function from the class to change one of the object's fields?
Here is the gui api if you want to test: QzBSawh6
KingofGamesYami #12
Posted 06 April 2015 - 12:21 AM

  func = function() Button:setText("Hello world") end,

Should be

  func = function() testButton1:setText("Hello world") end,
Neander_King #13
Posted 06 April 2015 - 02:02 AM
That doesn't work though, it returns attempt to index ?
Dragon53535 #14
Posted 06 April 2015 - 02:19 AM
Post the full message. The full message gives us the line number so we can know where it happens.
KingofGamesYami #15
Posted 06 April 2015 - 02:22 AM
I see what happened, you'll have to do something along the lines of this:

local testButton1 = Button.__init__({
  text="Test",
  tColor=colors.blue,
  bColor=colors.white,
  x1=20,
  x2=30,
  y1=1,
  y2=5,
})
  testButton1.func = function() testButton1:setText("Hello world") end
Lyqyd #16
Posted 06 April 2015 - 05:53 AM
Threads merged. Please stick to one topic per program, so that it is easier for those helping you to track what's going on and reduce duplicated effort.