I am having a problem with curses library in Python. Consider the following code:
def main(stdscr):
print('Hello World!!')
create_screen()
curses.endwin()
if __name__ == "__main__":
curses.wrapper(main)
The problem is every text printed by "print" function is messed up even before calling "create_screen()" function which initiates the screen by "curses.initscr()"
You can use print and input normally before and after your program uses curses. Also, you do not have to put all your code into main, and you don't have to pass the main function to curses, either. main is just a function like any other. Check out this simple example:
import curses, time
def incurses(stdscr):
stdscr.addstr(0, 0, "Exiting in ")
stdscr.addstr(2, 0, "Hello World from Curses!")
for i in range(5, -1, -1):
stdscr.addstr(0, 11, str(i))
stdscr.refresh()
time.sleep(1)
curses.endwin()
def main():
print('Hello World!!')
choice = input("Start Curses Program? ")
if choice == "yes":
curses.wrapper(incurses)
print("After curses")
if __name__ == "__main__":
main()
This prints and asks for user input, then shows a curses screen, then goes back into "normal" printing mode.
Related
I'm trying to make a dead-simple bot according to this video: https://www.youtube.com/watch?v=5Jwd69MRYwg
The main function that is supposed to be called when a part of the screen changes color simply is not being run at all.
I've tried ending the program with
"main()"
and
"if __name__ == '__main__':
main()"
respectively. Neither have allowed the code to run
def restart_game():
time.sleep(1)
pyautogui.click(Coordinates.replayBtn)
def image_grab():
box = (290, 465, 305, 487)
image = image_grab_lib.grab(box)
grey = ImageOps.grayscale(image)
a = array(grey.getcolors())
print(a.sum())
return a.sum()
def main():
restart_game()
print("blip")
if image_grab() != 577:
print("Jump")
press_space()
time.sleep(1)
restart_game()
if __name__ == '__main__':
main()
I expect the main function to run and give print "blip" and "jump", currently running all the other code and entirely skipping the main function.
shows what the warning looks like in PyCharm - image
Your code is unreachable because you have an infinite while loop before main() definition. It's a good practice in applications that require while loop to put it inside if name == 'main' condition after all variables are declared.
Like this:
if __name__ == '__main__':
while True:
do_something()
Note: I want to do this without using any external packages, like PyGame, etc.
I am attempting to capture individual keypresses as they arrive and perform an action for specific characters, whether I simply want to "re-echo" the character, or not display it at all and do something else.
I have found a cross-platform (though not sure about OS X) getch() implementation because I do not want to read a whole line like input() does:
# http://code.activestate.com/recipes/134892/
def getch():
try:
import termios
except ImportError:
# Non-POSIX. Return msvcrt's (Windows') getch.
import msvcrt
return msvcrt.getch
# POSIX system. Create and return a getch that manipulates the tty.
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
[Attempt 1]
I first tried a simple while-true loop to poll getch, but if I type too fast, characters go missing. Reducing the sleep time makes it worse. The debug statements only print on press of the enter key and not consistently in time nor position. (It appears there might be some line buffering going on?) Taking out the loop and sleep lets it work once but perfectly.
#!/usr/bin/env python3
import sys
import tty
import time
def main():
while True:
time.sleep(1)
sys.stdout.write(" DEBUG:Before ")
sys.stdout.write(getch())
sys.stdout.write(" DEBUG:After ")
if __name__ == "__main__":
main()
[Attempt 2]
I got an example for using a threaded approach (https://stackoverflow.com/a/14043979/2752206) but it "locks up" and won't accept any input (including Ctrl-C, and etc)..
#!/usr/bin/env python3
import sys
import tty
import time
import threading
key = 'Z'
def main():
threading.Thread(target=getchThread).start()
while True:
time.sleep(1)
sys.stdout.write(" DEBUG:Before ")
sys.stdout.write(key)
sys.stdout.write(" DEBUG:After ")
def getchThread():
global key
lock = threading.Lock()
while True:
with lock:
key = getch()
if __name__ == "__main__":
main()
Does anyone have any advice or guidance? Or more importantly, can someone explain why the two attempts do not work? Thanks.
First off, I don't really thing you need multithreading. You'd need that if you, for example, wanted to do some tasks like drawing on screen or whatever and capturing keys while you do this.
Let's consider a case where you only want to capture keys and after each keypress execute some action: Exit, if x was pressed, otherwise just print the character. All you need for this case is simple while loop
def process(key):
if key == 'x':
exit('exitting')
else:
print(key, end="", flush=True)
if __name__ == "__main__":
while True:
key = getch()
process(key)
Notice absence of sleep(). I am assuming you thought getch() won't wait for user input so you set 1s sleep time. However, your getch() waits for one entry and then returns it. In this case, global variable is not really useful, so you might as well just call process(getch()) inside the loop.
print(key, end="", flush=True) => the extra arguments will ensure pressed keys stay on one line, not appending newline character every time you print something.
The other case, where you'd want to execute different stuff simultaneously, should use threading.
Consider this code:
n = 0
quit = False
def process(key):
if key == 'x':
global quit
quit = True
exit('exitting')
elif key == 'n':
global n
print(n)
else:
print(key, end="", flush=True)
def key_capturing():
while True:
process(getch())
if __name__ == "__main__":
threading.Thread(target=key_capturing).start()
while not quit:
n += 1
time.sleep(0.1)
This will create global variable n and increment it 10 times a second in main thread. Simultaneously, key_capturing method listens to keys pressed and does the same thing as in previous example + when you press n on your keyboard, current value of the global variable n will be printed.
Closing note: as #zondo noted, you really missed braces in the getch() definition. return msvcrt.getch should most likely be return msvcrt.getch()
I am testing out the curses module for python and I encountered this error while trying a simple script:
NameError: global name 'addstr' is not defined
Here is my code:
#!/usr/bin/env python
import curses, sys
from curses import *
def main():
stdscr = initscr()
addstr("Hello")
endwin()
if __name__ == "__main__":
main()
I don't know what Newbie mistake I made, I am following a guide for curses on python.
Thanks in advance.
You need to call addstr() on stdscr, since that is the window object. Here's an example of a curses application:
import curses
import time
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.addstr("Hello World")
stdscr.refresh()
try:
while True:
time.sleep(0.001)
except KeyboardInterrupt:
pass
curses.nocbreak()
curses.echo()
curses.endwin()
Note that the while loop is simply so the curses terminal is displayed until you hit Ctrl-C, otherwise you won't really see much.
I have a little Python program that uses keyboard input to run certain commands.
I setup everything in one main program loop but now I'm wondering, do I even need a main loop?
Here is what I mean:
mainProgramLoop = 1
while mainProgramLoop == 1:
print ("\nType in the command. ")
keyBoardInput= input("command:")
if keyBoardInput == "a":
#do this
elif keyBoardInput == "b":
#do this
Do I actually need that while loop?
Thanks!
No, you do not need a main loop if you use the cmd.Cmd class included with Python:
#! /usr/bin/env python3
import cmd
class App(cmd.Cmd):
prompt = 'Type in a command: '
def do_a(self, arg):
print('I am doing whatever action "a" is.')
def do_b(self, arg):
print('I am doing whatever action "b" is.')
if __name__ == '__main__':
App().cmdloop()
The documentation for the cmd module includes an example near the bottom to help get you started.
I'm struggling with a issue for some time now.
I'm building a little script which uses a main loop. This is a process that needs some attention from the users. The user responds on the steps and than some magic happens with use of some functions
Beside this I want to spawn another process which monitors the computer system for some specific events like pressing specif keys. If these events occur then it will launch the same functions as when the user gives in the right values.
So I need to make two processes:
-The main loop (which allows user interaction)
-The background "event scanner", which searches for specific events and then reacts on it.
I try this by launching a main loop and a daemon multiprocessing process. The problem is that when I launch the background process it starts, but after that I does not launch the main loop.
I simplified everything a little to make it more clear:
import multiprocessing, sys, time
def main_loop():
while 1:
input = input('What kind of food do you like?')
print(input)
def test():
while 1:
time.sleep(1)
print('this should run in the background')
if __name__ == '__main__':
try:
print('hello!')
mProcess = multiprocessing.Process(target=test())
mProcess.daemon = True
mProcess.start()
#after starting main loop does not start while it prints out the test loop fine.
main_loop()
except:
sys.exit(0)
You should do
mProcess = multiprocessing.Process(target=test)
instead of
mProcess = multiprocessing.Process(target=test())
Your code actually calls test in the parent process, and that call never returns.
You can use the locking synchronization to have a better control over your program's flow. Curiously, the input function raise an EOF error, but I'm sure you can find a workaround.
import multiprocessing, sys, time
def main_loop(l):
time.sleep(4)
l.acquire()
# raise an EOFError, I don't know why .
#_input = input('What kind of food do you like?')
print(" raw input at 4 sec ")
l.release()
return
def test(l):
i=0
while i<8:
time.sleep(1)
l.acquire()
print('this should run in the background : ', i+1, 'sec')
l.release()
i+=1
return
if __name__ == '__main__':
lock = multiprocessing.Lock()
#try:
print('hello!')
mProcess = multiprocessing.Process(target=test, args = (lock, ) ).start()
inputProcess = multiprocessing.Process(target=main_loop, args = (lock,)).start()
#except:
#sys.exit(0)