local function getArraySize(array)
local count = 0
for _ in ipairs(array) do
count=count+1
end
return count
end
local function numbersOnly(pre)
local x,y=term.getCursorPos()
num={}
while true do
if pre then write(pre) end
for _,v in ipairs(num) do
write(v)
end
--write(' <')
_,key=os.pullEvent('key')
if key == 2 or key == 79 then
table.insert(num,1)
elseif key == 3 or key == 80 then
table.insert(num,2)
elseif key == 4 or key == 81 then
table.insert(num,3)
elseif key == 5 or key == 75 then
table.insert(num,4)
elseif key == 6 or key == 76 then
table.insert(num,5)
elseif key == 7 or key == 77 then
table.insert(num,6)
elseif key == 8 or key == 71 then
table.insert(num,7)
elseif key == 9 or key == 72 then
table.insert(num,8)
elseif key == 10 or key == 9 then
table.insert(num,9)
elseif key == 11 or key == 82 then
table.insert(num,0)
elseif key == 14 then
table.remove(num, getArraySize(num))
elseif key == 28 then
final=0
size=getArraySize(num)
for i,v in ipairs(num) do
final=final+(v*10^(size-i))
end
print()
return final
end
term.setCursorPos(x,y)
term.clearLine()
end
end
I can add a stationary cursor, but since I don't know how to time out an event, I can't make it blink. Any suggestions?
This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Add blinking cursor to a numbers only input function
Started by Himself12794, 04 February 2014 - 03:16 PMPosted 04 February 2014 - 04:16 PM
I wrote a function that only accepts numbers as an input, and was quite pleased when it worked on the first try. However, I now want to add a blinking cursor so the user knows they are able to input something. Here's what I have so far:
Posted 04 February 2014 - 04:25 PM
Cursor blinking is implemented inside of ComputerCraft, You don't need to make it by yourself. The cursor's blinks at where the actual cursor (set with term.setCursorPos) is. For all ComputerCraft APIs just visit the APIs page in the Wiki.
Sidenote to myself: don't put that many links in one post.
Edit: Just had a read through your code and I have some suggestions and tips:
You check for specific keys, if they were pressed. That's not very good IMO (In My Opinion). I suggest using 'char' event. 'char' event returns the actual writable character that was pressed, so you don't have to check for specific key presses.
Also note that it will always return a string, so if you want that string to become a number just use tonumber(StringThatIsANumber) function:
But what if the user pressed 'e' or any other non-number character/key? If you give a non-number value to tonumber it will return nil (nothing):
Another tip is about getting table's length. You can use # in front of your table's variable's name to get it's length:
And finally, looks like you know how to use local variables, then why didn't you localized your event and it's returnings, and the num table and a few other variables?
Sidenote to myself: don't put that many links in one post.
Edit: Just had a read through your code and I have some suggestions and tips:
You check for specific keys, if they were pressed. That's not very good IMO (In My Opinion). I suggest using 'char' event. 'char' event returns the actual writable character that was pressed, so you don't have to check for specific key presses.
local event, char = os.pullEvent("char")
print("You pressed '" .. char .. "' character.") --// If you would press 'e' -->> You pressed 'e' character.
Also note that it will always return a string, so if you want that string to become a number just use tonumber(StringThatIsANumber) function:
local text = "123" --// We want this text to become a number
print(type(text)) -->> string
local number = tonumber(text) --// Convert that text to a number
print(type(number)) -->> number
--// Note: function type() returns the type of the variable, ex.: string, number, table, etc.
But what if the user pressed 'e' or any other non-number character/key? If you give a non-number value to tonumber it will return nil (nothing):
local notANumber = "test string"
if tonumber(notANumber) ~= nil then --// If tonumber() didn't return nil
print("It's a valid number!")
else
print("It's not a number!")
end
--// Note: You can use this instead:
if tonumber(notANumber) then
--// Because every value non-nil or non-false value evaluates to true
Another tip is about getting table's length. You can use # in front of your table's variable's name to get it's length:
local myTable = {1, 2, 3}
print(#myTable) -->> 3
And finally, looks like you know how to use local variables, then why didn't you localized your event and it's returnings, and the num table and a few other variables?
num = {}
...
_,key=os.pullEvent('key')
...
final=0
size=getArraySize(num)
Edited on 04 February 2014 - 03:56 PM
Posted 04 February 2014 - 11:22 PM
Cursor blinking is implemented inside of ComputerCraft, You don't need to make it by yourself. The cursor's blinks at where the actual cursor (set with term.setCursorPos) is. For all ComputerCraft APIs just visit the APIs page in the Wiki.
Sidenote to myself: don't put that many links in one post.
Edit: Just had a read through your code and I have some suggestions and tips:
You check for specific keys, if they were pressed. That's not very good IMO (In My Opinion). I suggest using 'char' event. 'char' event returns the actual writable character that was pressed, so you don't have to check for specific key presses.local event, char = os.pullEvent("char") print("You pressed '" .. char .. "' character.") --// If you would press 'e' --&gt;&gt; You pressed 'e' character.
I'm still quite perplexed on adding the cursor though.
Also note that it will always return a string, so if you want that string to become a number just use tonumber(StringThatIsANumber) function:local text = "123" --// We want this text to become a number print(type(text)) --&gt;&gt; string local number = tonumber(text) --// Convert that text to a number print(type(number)) --&gt;&gt; number --// Note: function type() returns the type of the variable, ex.: string, number, table, etc.
But what if the user pressed 'e' or any other non-number character/key? If you give a non-number value to tonumber it will return nil (nothing):local notANumber = "test string" if tonumber(notANumber) ~= nil then --// If tonumber() didn't return nil print("It's a valid number!") else print("It's not a number!") end --// Note: You can use this instead: if tonumber(notANumber) then --// Because every value non-nil or non-false value evaluates to true
Another tip is about getting table's length. You can use # in front of your table's variable's name to get it's length:local myTable = {1, 2, 3} print(#myTable) --&gt;&gt; 3
And finally, looks like you know how to use local variables, then why didn't you localized your event and it's returnings, and the num table and a few other variables?num = {} ... _,key=os.pullEvent('key') ... final=0 size=getArraySize(num)
For the local statements, some of them don't have them because this was my first version of the code, and I wasn't really too worried about them the moment. Also, I'm not just trying to get only a number, but I was setting it so the only keys that could be pressed were the numbers.
I didn't know about the char event and getting the length of a table the easy way, will definitely implement it as soon as I get around to modifying the code.
Since the when I want the cursor is actually during os.pullEvent() and not read(), it doesn't show up and that's why I'm looking for a way to add it.
Thanks for the tips!
Edit:
Thanks to your comments, I have dramatically decreased the size and complexity of the function:
local function numbersOnly(pre)
local x,y=term.getCursorPos()
local num={}
while true do
if pre then write(pre) end
for _,v in ipairs(num) do
write(v)
end
local event,key=os.pullEvent()
if event=='char' then
if tonumber(key) then
key=tonumber(key)
if key>=0 and key<10 then
table.insert(num,tonumber(key))
end
end
elseif event=='key' then
if key==14 then
table.remove(num, #num)
elseif key==28 then
final=0
size=#num
for i,v in ipairs(num) do
final=final+(v*10^(size-i))
end
print()
return final
end
end
term.setCursorPos(x,y)
term.clearLine()
end
end
Edited on 04 February 2014 - 11:20 PM
Posted 04 February 2014 - 11:30 PM
term.setCursorBlink( boolean state )
if you want people to type only numbers you could also check the key code returned from the key event and make sure that it is between keys.one (code 2) and keys.zero (code 11). Additionally depending on requirements also allowing keys.period (code 52) and keys.minus (code 12). Key codes.
if you want people to type only numbers you could also check the key code returned from the key event and make sure that it is between keys.one (code 2) and keys.zero (code 11). Additionally depending on requirements also allowing keys.period (code 52) and keys.minus (code 12). Key codes.
Posted 05 February 2014 - 12:23 AM
Yes, thank you. I've done something like that, making my code much simpler.term.setCursorBlink( boolean state )
if you want people to type only numbers you could also check the key code returned from the key event and make sure that it is between keys.one (code 2) and keys.zero (code 11). Additionally depending on requirements also allowing keys.period (code 52) and keys.minus (code 12). Key codes.
This is why I like to get feedback on my work from the forums. I always find there is a simpler way, and I learn much.
I guess the real question I'm asking is, How do I do a timeout event on os.pullEvent()?
Edited on 04 February 2014 - 11:22 PM
Posted 05 February 2014 - 12:31 AM
Make use of timers.I guess the real question I'm asking is, How do I do a timeout event on os.pullEvent()?
Posted 05 February 2014 - 12:33 AM
I think I've found the solution. By messing around with os.startTimer(), I think I have my answer. Now I just need to mess with timing to get perfect blinking rate.
Edited on 04 February 2014 - 11:34 PM
Posted 05 February 2014 - 12:38 AM
Why not just stick with the default blink rate? :huh:/>Now I just need to mess with timing to get perfect blinking rate.
Posted 05 February 2014 - 12:50 AM
So I have one problem after implementing this. Everything works fine, and the cursor blinks as desired, until I use backspace, when it then starts behaving erratically. Perhaps this has to do with how I remove a value from the list? Here's the code:
local function numbersOnly(pre)
local cursor = true
local x,y=term.getCursorPos()
local num={}
while true do
if pre then write(pre) end
for _,v in ipairs(num) do
write(v)
end
if cursor then write('_') end--else write(' ') end
local myTimer = os.startTimer(0.25)
local event,key=os.pullEvent()
if event=='char' then
if tonumber(key) then
key=tonumber(key)
if key>=0 and key<10 then
table.insert(num,key)
end
end
elseif event=='timer' then
cursor = not cursor
elseif event=='key' then
if key==14 then
num[#num]=nil
elseif key==28 then
final=0
size=#num
for i,v in ipairs(num) do
final=final+(v*10^(size-i))
end
term.setCursorPos(x,y)
term.clearLine()
if pre then write(pre) end
for _,v in ipairs(num) do
write(v)
end
print()
return final
end
end
term.setCursorPos(x,y)
term.clearLine()
end
end
Because I am making a psuedo read() method that accepts only numbers as input, and using os.pullEvent() does not show the cursor.Why not just stick with the default blink rate? :huh:/>Now I just need to mess with timing to get perfect blinking rate.
Edited on 04 February 2014 - 11:50 PM
Posted 05 February 2014 - 12:53 AM
you're not setting the cursor position back a space.
honestly though using a table to make your number is definitely inefficient!
honestly though using a table to make your number is definitely inefficient!
Posted 05 February 2014 - 01:01 AM
You should try using term.setCursorBlink(true) as mentioned earlier in the post.
Posted 05 February 2014 - 01:02 AM
The reason I had to use a table was because if I used a variable, even if I designated the value as a string, if it is a number, it would treat it as an integer and add the values instead of adding to the end of the string.you're not setting the cursor position back a space.
honestly though using a table to make your number is definitely inefficient!
Posted 05 February 2014 - 01:06 AM
Is it possible that you post this code up? 'cause it definitely wouldn't do that.The reason I had to use a table was because if I used a variable, even if I designated the value as a string, if it is a number, it would treat it as an integer and add the values instead of adding to the end of the string.
Posted 05 February 2014 - 01:06 AM
Wow… I just realized what you guys were all saying. I thought you had misunderstood me when I had misunderstood you. I feel so dense now. Really sorry for that guys. I did not know that doing that would make the cursor blink no matter what was going on.You should try using term.setCursorBlink(true) as mentioned earlier in the post.
Again, I am sorry for being so dense.
Problem solved!
Posted 05 February 2014 - 01:20 AM
Again, I'm feeling quite foolish. I was mixing up python with lua and tried to use c=a+b to add strings instead of ".." Still, using tables is still the easiest way to remove a value from the end. Here's what I'm left with, using strings instead of a table, but haven't cooked up a way to remove the last value beyond converting it to a number and messing with it there.Is it possible that you post this code up? 'cause it definitely wouldn't do that.The reason I had to use a table was because if I used a variable, even if I designated the value as a string, if it is a number, it would treat it as an integer and add the values instead of adding to the end of the string.
local function numbersOnly(pre)
term.setCursorBlink(true)
local x,y=term.getCursorPos()
local num=''
while true do
if pre then write(pre) end
write(num)
local event,key=os.pullEvent()
if event=='char' then
if tonumber(key) then
if tonumber(key)>=0 and tonumber(key)<10 then
num=num..key
end
end
elseif event=='key' then
if key==14 then
num[#num]=nil
elseif key==28 then
return tonumber(num)
end
end
term.setCursorPos(x,y)
term.clearLine()
end
end
Posted 05 February 2014 - 01:21 AM
take a look at this example I just whipped together, uses strings instead of a tableThe reason I had to use a table was because if I used a variable, even if I designated the value as a string, if it is a number, it would treat it as an integer and add the values instead of adding to the end of the string.
example code
local function readNumber( pre )
--# turn the blinking cursor on
term.setCursorBlink(true)
--# this is the variable to hold the users input
--# it should be noted that :match("(%d+)") is used to remove any non-number character from the initial input
local input = pre and pre:match("(%d+)") or ""
--# initial location of cursor
local sx, sy = term.getCursorPos()
--# draw the initial input
term.setCursorPos(sx, sy)
write(input)
term.setCursorPos(sx + #input, sy)
--# loop
while true do
--# wait for an event
local event, code = os.pullEvent()
--# if the event was a character event, and the character is a number
if event == "char" and tonumber(code) then
--# append it to the end of the input
input = input..tonumber(code)
--# redraw the input to the screen
term.setCursorPos(sx, sy)
write(input)
term.setCursorPos(sx + #input, sy)
--# if the event was a key event
elseif event == "key" then
--# if enter was pressed exit the loop
if code == keys.enter then
break
--# if backspace was pressed
elseif code == keys.backspace then
--# set the input to what it is currently minus the backspaced character
input = input:sub(1, #input-1)
--# redraw input to the screen with a blank space on the end to remove the old character
term.setCursorPos(sx, sy)
write(input..' ')
term.setCursorPos(sx + #input, sy)
end
end
end
--# turn off the cursor blinking
term.setCursorBlink(false)
--# return the users input back to the calling function making sure to convert it to a number
return tonumber(input)
end
test code
local num = readNumber('123')
print(num)
print(type(num))
local num = readNumber('123abc') --# note, because of the :match("(%d+)") the 'abc' is removed from this
print(num)
print(type(num))
Edited on 05 February 2014 - 12:23 AM
Posted 05 February 2014 - 01:29 AM
Oh I'm sorry, I should use comments more. The argument 'pre' is supposed to stand for prefix, and it is just there to print a little header in front of the number input.take a look at this example I just whipped together, uses strings instead of a tableThe reason I had to use a table was because if I used a variable, even if I designated the value as a string, if it is a number, it would treat it as an integer and add the values instead of adding to the end of the string.example code
local function readNumber( pre ) --# turn the blinking cursor on term.setCursorBlink(true) --# this is the variable to hold the users input --# it should be noted that :match("(%d+)") is used to remove any non-number character from the initial input local input = pre and pre:match("(%d+)") or "" --# initial location of cursor local sx, sy = term.getCursorPos() --# draw the initial input term.setCursorPos(sx, sy) write(input) term.setCursorPos(sx + #input, sy) --# loop while true do --# wait for an event local event, code = os.pullEvent() --# if the event was a character event, and the character is a number if event == "char" and tonumber(code) then --# append it to the end of the input input = input..tonumber(code) --# redraw the input to the screen term.setCursorPos(sx, sy) write(input) term.setCursorPos(sx + #input, sy) --# if the event was a key event elseif event == "key" then --# if enter was pressed exit the loop if code == keys.enter then break --# if backspace was pressed elseif code == keys.backspace then --# set the input to what it is currently minus the backspaced character input = input:sub(1, #input-1) --# redraw input to the screen with a blank space on the end to remove the old character term.setCursorPos(sx, sy) write(input..' ') term.setCursorPos(sx + #input, sy) end end end --# turn off the cursor blinking term.setCursorBlink(false) --# return the users input back to the calling function making sure to convert it to a number return tonumber(input) end
test code
local num = readNumber('123') print(num) print(type(num)) local num = readNumber('123abc') --# note, because of the :match("(%d+)") the 'abc' is removed from this print(num) print(type(num))
Posted 05 February 2014 - 01:30 AM
Ah, well in any case, you should be able to see what you need to do in order to get it to work.Oh I'm sorry, I should use comments more. The argument 'pre' is supposed to stand for prefix, and it is just there to print a little header in front of the number input.
Posted 05 February 2014 - 01:45 AM
I do, and I have. I ended up with this:Ah, well in any case, you should be able to see what you need to do in order to get it to work.Oh I'm sorry, I should use comments more. The argument 'pre' is supposed to stand for prefix, and it is just there to print a little header in front of the number input.
local function numbersOnly(pre)
term.setCursorBlink(true)
local x,y=term.getCursorPos()
local num=''
while true do
if pre then write(pre) end
write(num)
local event,key=os.pullEvent()
if event=='char' and tonumber(key) then
num=num..key
elseif event=='key' then
if key==14 then
num=string.sub(num, 1, -2)
elseif key==28 then
print()
term.setCursorBlink(false)
return tonumber(num)
end
end
term.setCursorPos(x,y)
term.clearLine()
end
end
Thanks for all the help!