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

Add a Button in a Loop Without Breaking it

Started by DeBrates, 20 January 2016 - 02:55 AM
DeBrates #1
Posted 20 January 2016 - 03:55 AM
Still writing my Big Reactors program. I have a few things drawn on the monitor. All of these things update in a loop that sleeps for 1 second. If I check for an event within that loop, it stops the loop there until the event, essentially freezing it. My goal is to make the Activate and De-Activate text I drew up a button. You can see this in my code commented as "–Activation Button Display" near the bottom. I know the Big Reactor API, but what I don't know is how to format and/or position the os.pullEvent() for my button. I can do this without other things in the loop updating on the screen. However, I am not sure how to do both on the same screen simultaneously. Also, a nice thing to learn how to do would be to change the background color for only the button.

http://pastebin.com/07qtTQq1

Any help is appreciated!
valithor #2
Posted 20 January 2016 - 04:07 AM
You can either use a timer, or coroutines (can probably do it with timers, but this is always an alternative) to do what you are wanting to do.

Going to only show timer for now, as it is much simplier and it is likely the solution you should use. So, the trick is not to do these two things simultaneously, but just do it to where the computer has something throwing the pullEvent every few moments, so you can update other things on the screen. This is where the timers come in.

while true do
  local myTimer = os.startTimer (.05) --# starting a timer for .05 of a second this time can be customized
  local event = {os.pullEvent()} --# just catching the event in a table, it really isn't important just easier for the example
  if event[1] == "timer" and event[2] == myTimer then --# making sure it is a timer event, and it is the timer event we created
	--# the event that was caught was the timer, so check to see if you need to update anything on the screen, or do anything else
  elseif event[1] == "some reactor event" then --# checking to see if it is the reactor event you were looking for
	--# the event was a reactor event so do reactor related stuff
	os.cancelTimer(myTimer) --# you need to cancel the timer that we created earlier since it was not the event that was caught
  end
end

This is a rather basic example, but I do not know the mod, or where exactly you would need the event to be pulled. If you can not figure out where or how you would implement this, then could you post the script with the pullEvent in it to where it would freeze the script? Also going to point out that with this setup you will not need to use sleep in your script.
Edited on 20 January 2016 - 03:11 AM
DeBrates #3
Posted 20 January 2016 - 04:49 AM
You can either use a timer, or coroutines (can probably do it with timers, but this is always an alternative) to do what you are wanting to do.

Going to only show timer for now, as it is much simplier and it is likely the solution you should use. So, the trick is not to do these two things simultaneously, but just do it to where the computer has something throwing the pullEvent every few moments, so you can update other things on the screen. This is where the timers come in.

while true do
  local myTimer = os.startTimer (.05) --# starting a timer for .05 of a second this time can be customized
  local event = {os.pullEvent()} --# just catching the event in a table, it really isn't important just easier for the example
  if event[1] == "timer" and event[2] == myTimer then --# making sure it is a timer event, and it is the timer event we created
	--# the event that was caught was the timer, so check to see if you need to update anything on the screen, or do anything else
  elseif event[1] == "some reactor event" then --# checking to see if it is the reactor event you were looking for
	--# the event was a reactor event so do reactor related stuff
	os.cancelTimer(myTimer) --# you need to cancel the timer that we created earlier since it was not the event that was caught
  end
end

This is a rather basic example, but I do not know the mod, or where exactly you would need the event to be pulled. If you can not figure out where or how you would implement this, then could you post the script with the pullEvent in it to where it would freeze the script? Also going to point out that with this setup you will not need to use sleep in your script.
I believe I understand. I will try it out soon. If not, Ill post the script with my button loop in it so you can see the freeze. Thanks!
Edited on 20 January 2016 - 03:51 AM
DeBrates #4
Posted 20 January 2016 - 05:56 AM
You can either use a timer, or coroutines (can probably do it with timers, but this is always an alternative) to do what you are wanting to do.

Going to only show timer for now, as it is much simplier and it is likely the solution you should use. So, the trick is not to do these two things simultaneously, but just do it to where the computer has something throwing the pullEvent every few moments, so you can update other things on the screen. This is where the timers come in.

while true do
  local myTimer = os.startTimer (.05) --# starting a timer for .05 of a second this time can be customized
  local event = {os.pullEvent()} --# just catching the event in a table, it really isn't important just easier for the example
  if event[1] == "timer" and event[2] == myTimer then --# making sure it is a timer event, and it is the timer event we created
	--# the event that was caught was the timer, so check to see if you need to update anything on the screen, or do anything else
  elseif event[1] == "some reactor event" then --# checking to see if it is the reactor event you were looking for
	--# the event was a reactor event so do reactor related stuff
	os.cancelTimer(myTimer) --# you need to cancel the timer that we created earlier since it was not the event that was caught
  end
end

This is a rather basic example, but I do not know the mod, or where exactly you would need the event to be pulled. If you can not figure out where or how you would implement this, then could you post the script with the pullEvent in it to where it would freeze the script? Also going to point out that with this setup you will not need to use sleep in your script.

So this is what I came up with. It doesn't completely work, and I was hoping you or someone could spot why.
I made the timer near the bottom under "–Button Timer".

http://pastebin.com/uCMV5bvW

What is now happening is that the buttons work, but the rest of the loop only updates when I physically use the buttons. That being said I tried removing the timer, and there was no change in this effect. So I must be using the timer incorrectly here, because the timer is useless in how the script runs at this point. How might I use this timer correctly without disturbing the rest of the loop? I also removed the 1 second sleep at the end of the loop which I'm not sure about.
valithor #5
Posted 20 January 2016 - 01:16 PM
Snip

On line 63 you use a filter in os.pullEvent to where it only listens for monitor events, which causes it to skip the timer event that you are creating with the timer. Just remove the filter on line 63, and add a check on line 64 and 66 to make sure it is a monitor event.

Internally the sleep function just used timers, so you using timers is very similar to just calling sleep(0.05) (or whatever amount you are doing your timer for).
Edited on 20 January 2016 - 12:17 PM
DeBrates #6
Posted 20 January 2016 - 06:11 PM

Indeed that was the issue, I figured it out, and it works flawlessly. Having the timer at 0.05 was making the screen all jittery, so I just changed it to my original sleep time of 1 second and it works as before.
Thank you for all the help kind sir! I appreciate it!