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

[Lua][Error] Problem with classes and gui

Started by Xkonti, 20 March 2013 - 07:57 PM
Xkonti #1
Posted 20 March 2013 - 08:57 PM
[Lua][Error] Problem with classes and gui

Hello everyone!
I'm writing simple API to draw and manage UI in advanced monitors. Everything was nice till I run nearly "release" version of API in simple test program.

I'm new to lua so I did what I can to try to solve this by myself. I think the problem is in case on using some kind of classes, but I don't know what's wrong.
Every time when I run program I get only debug message and error:

--DRAWING--
monitorXAPI:211: attempt to index ? (a nil value)

Now the source code.
Program:
Spoiler

os.loadAPI("textXAPI")
os.loadAPI("monitorXAPI")
btnFill = colors.lightGray
btnText = colors.black
btnDisFill = colors.gray
btnDisText = colors.black
mainPage = {}
mainPage[1] = monitorXAPI.StatusBar:new
	  { pathLength = 54,
	   timeLength = 25,
	   path = "path",
	   pathFillColor = colors.gray,
	   pathTextColor = colors.white,
	   timeFillColor = colors.lightGray,
	   timeTextColor = colors.black
	  }
mainPage[2] = monitorXAPI.Button:new
	  { x = 2,
	   y = 3,
	   size = 2,
	   length = 25,
	   text = "Touch to set path",
	   enabled = true,
	   visible = true,
	   enabledFillColor = colors.black,
	   enabledTextColor = colors.lightGray,
	   disabledFillColor = colors.black,
	   disabledTextColor = colors.gray,
	   onclickFunction = function() mainPage[1].path = "Zmieniono tytul!" end
	  }
monitorXAPI.monitorSetup("right", 0.5, colors.black)
monitorXAPI.uiEvents(mainPage, 1)

monitorXAPI:
Spoiler

-----------------
-- monitorXAPI --
--  by Xkonti  --
-----------------
---- External APIs ----
-- You have to include:
--  - textXAPI
-----------------------
-------------------
-- GLOBAL VARIABLES
local XApiMonitor -- peripheral
local XApiBkgColor -- default color for screen cleaning
--
-------------------
--
------ Utilities ------
--
function monitorSetup(side, textScale, backgroundColor)
XApiMonitor = peripheral.wrap(side)
XApiMonitor.setTextScale = textScale
XApiBkgColor = backgroundColor
clear(XApiBkgColor)
end
-- Clear screen
function clear(color)
XApiMonitor.setBackgroundColor(color)
XApiMonitor.clear()
end
--
------ Text ------
--
-- Draw text
function drawText(x, y, text, bkgColor, txtColor)
XApiMonitor.setBackgroundColor(bkgColor)
XApiMonitor.setTextColor(txtColor)
XApiMonitor.setCursorPos(x, y)
XApiMonitor.write(text)
end
-- Draw centered text
function drawCenteredText(x, y, text, length, backgroundColor, textColor)
drawText(x + textXAPI.offsetToCenter(text, length), y, text, backgroundColor, textColor)
end
-- Draw right-aligned text
function drawRightAlignedText(x, y, text, length, backgroundColor, textColor)
drawText(x + textXAPI.offsetToRight(text, length), y, text, backgroundColor, textColor)
end
--
------ Shapes ------
--
-- Colored Filled Rectangle with Stroke
function drawCFRectangle(x1, y1, x2, y2, strokeColor, fillColor)
XApiMonitor.setBackgroundColor(strokeColor)
local x, y
-- Top line
XApiMonitor.setCursorPos(x1, y1)
for x=x1, x2, 1 do

  XApiMonitor.write(" ")

end
-- Bottom line
XApiMonitor.setCursorPos(x1, y2)
for x=x1, x2, 1 do

  XApiMonitor.write(" ")

end
-- Left line
for y=y1+1, y2-1, 1 do

  XApiMonitor.setCursorPos(x1, y)
  XApiMonitor.write(" ")

end
-- Right line
for y=y1+1, y2-1, 1 do

  XApiMonitor.setCursorPos(x2, y)
  XApiMonitor.write(" ")

end
drawCSRectangle(x1+1, y1+1, x2-1, y2-1, fillColor)
end
-- Colored Solid Rectangle
function drawCSRectangle(x1, y1, x2, y2, color)
XApiMonitor.setBackgroundColor(color)
local x, y
for y=y1, y2, 1 do

  monitor.setCursorPos(x1, y)

  for x=x1, x2, 1 do

   monitor.write(" ")

  end

end
end
-- Draw edit box
function drawEditBox(x, y, size, length, text, strokeColor, fillColor, textColor)
drawCFRectangle(x, y, x+length+(2*size), y+(2*size), strokeColor, fillColor)
drawText(x+size, y+size, text, fillColor, textColor)
end
-- Draw button
function drawButton(x, y, size, length, text, fillColor, textColor)
drawCSRectangle(x, y, x+length+(2*size), y+(2*size), fillColor)
drawCenteredText(x+size, y+size, text, length, fillColor, textColor)

end
-- Draw statusbar
function drawStatusBar(pathLength, timeLength, path, pathFillColor, pathTextColor, timeFillColor, timeTextColor)
drawCSRectangle(1, 1, pathLength, 1, pathFillColor)
drawCSRectangle(pathLength + 1, 1, pathLength + timeLength, 1, timeFillColor)
drawText(1,1, path, pathFillColor, pathTextColor)
timeHour = textutils.formatTime(os.time(), true)
timeDay = tostring(os.day())
drawRightAlignedText(pathLength + 1, 1, timeHour.." of "..timeDay.." MC day", timeLength, timeFillColor, timeTextColor)
end
--
------ Classes ------
--
-----------------------
--- StatusBar class ---
-- StatusBar declaration
StatusBar = { pathLength = 54,
	timeLength = 25,
	path = "path",
	pathFillColor = colors.gray,
	pathTextColor = colors.white,
	timeFillColor = colors.lightGray,
	timeTextColor = colors.black
   }
-- Constructor
function StatusBar:new(object)
object = object or { pathLength = 54,
	   timeLength = 25,
	   path = "path",
	   pathFillColor = colors.gray,
	   pathTextColor = colors.white,
	   timeFillColor = colors.lightGray,
	   timeTextColor = colors.black
	  }
setmetatable(object, self)
self.__index = self
return object
end
-- StatusBar draw function
function StatusBar:draw()
drawStatusBar(self.pathLength, self.timeLength, self.path, self.pathFillColor, self.pathTextColor, self.timeFillColor, self.timeTextColor)
end
-- StatusBar touch function
function StatusBar:touch()
end
--------------------
--- Button class ---
-- Button declaration
Button = { x = 1,
   y = 1,
   size = 1,
   length = 5,
   text = "text",
   enabled = true,
   visible = true,
   enabledFillColor = colors.lightGray,
   enabledTextColor = colors.black,
   disabledFillColor = colors.gray,
   disabledTextColor = colors.black,
   onClickFunction = function() end
   }
-- Constructor
function Button:new(object)
object = object or { x = 1,
	   y = 1,
	   size = 1,
	   length = 5,
	   text = "text",
	   enabled = true,
	   visible = true,
	   enabledFillColor = colors.black,
	   enabledTextColor = colors.lightGray,
	   disabledFillColor = colors.black,
	   disabledTextColor = colors.gray,
	   onclickFunction = function() end
		}
setmetatable(object, self)
self.__index = self
return object
end
-- Button draw function
function Button:draw()
if self.visible then
  if self.enabled then
   drawButton(self.x, self.y, self.size, self.length, self.text, self.enabledFillColor, self.enabledTextColor)
  else
   drawButton(self.x, self.y, self.size, self.length, self.text, self.disabledFillColor, self.disabledTextColor)
  end
end
end
-- When clicked function - checks if button was clicked and starts onClickFunction - returns true or false
function Button:touch(x, y)
if self.enabled then
  if x >= self.x then
   if x <= (self.x + self.length + (2 * self.size)) then

	if y >= self.y then
	 if y <= (self.y + (2 * self.size)) then
  
	  self.onClickFunction()
	  return true
	
	 else
	 return false
	 end
	else
	return false
	end
   else
   return false
   end
  else
  return false
  end
else
return false
end
end
-- Set Button position
function Button:setPos(x, y)
self.x = x
self.y = y
end
--
------ UI functions ------
--
function uiDraw(components)
print("--DRAWING--") -- debug
for i=1, table.maxn(components) do
  components[i].draw()
end
end
-- Event handling
function uiEvents(components, refreshRate)
os.startTimer(refreshRate)  -- Start refreshing screen
while true do
  local event, param1, param2, param3 = os.pullEvent()  -- event handler

  if event == "timer" then   -- time to refresh?

   os.startTimer(refreshRate)  -- start new timer
   uiDraw(components)	-- refresh UI

  elseif event == "monitor_touch" then -- touched?

   uiTouch(components, param2, param3) -- check what was touched

  end

end
end
-- Check what was clicked
function uiTouch(components, x, y)
print("--TOUCHING--") -- debug
for i=1, table.maxn(components) do
  if components[i].touch(x, y) then
   break
  end
end
end

textXAPI
Spoiler

-----------------
--  textXAPI   --
--  by Xkonti  --
-----------------
function offsetToCenter(text, length)
local offset
offset = math.floor( (length - string.len(text) ) / 2)
return offset
end
function offsetToRight(text, length)
local offset = math.floor( length - string.len(text) )
return offset
end

What can I do to make it work? Where is my mistake?
Lyqyd #2
Posted 21 March 2013 - 06:30 AM
Split into new topic.
LBPHacker #3
Posted 21 March 2013 - 07:36 AM
First of all :D/> Upload the API to pastebin cuz this forum gives no line numbers in code boxes, and we can't count to 211 (I mean we won't).

Anyways, I'm pretty sure your function you want to call with .onClickFunction (that's nil) is stored in .onclickFunction (note the lower-case C). You know, Lua is case-sensitive. Check every instance of onClickFunction in the code.
Xkonti #4
Posted 21 March 2013 - 08:29 AM
I uploaded to pastebin and corrected typo in .onClickFunction, but error is still te same :/

Program:
http://pastebin.com/VceQT0tF

monitorXAPI:
http://pastebin.com/HFt317ib

textXAPI:
http://pastebin.com/pvKLx3M6
LBPHacker #5
Posted 21 March 2013 - 09:11 AM
Ohhh… Notepad++ said at ~211st line you call .onClickEvent, I thought the problem would be there (That was before you uploaded it to pastebin - I just copypasted it from the code box…).

Oh! Maybe line 319:
components[i].draw() -- this way .draw gets no "self" object
Shouldn't it be
components[i]:draw()
?
Xkonti #6
Posted 21 March 2013 - 10:18 AM
Thanks a lot! That was it! And the same mistake was in line 354 ;)/> There was some other stupid mistakes, but hey! Thanks again ;)/>