I am trying to make a program that will launch both a view window (console) and a command line. In the view window, it would show constant updates, while the command line window would use raw_input()
to accept commands that affect the view window. I am thinking about using threads for this, but I have no idea how to launch a thread in a new console window. How would I do that?

- 912
- 2
- 8
- 23
-
3Not sure if you can at all, but there are huge differences between platforms. Most importantly, the Windows console is different from UNIX terminals. What platform are you on? – Martijn Pieters Jul 29 '12 at 20:29
-
I would like how to do it on both Windows and UNIX/Linux/Mac, and use sys.platform to be portable. – elijaheac Jul 29 '12 at 20:38
-
Where does the program that writes the updates come from. Can you control it? – jfs Jul 29 '12 at 20:54
-
You can use multiple processes and named pipes? If you go with the multiple processes strategy, then there is alot of interprocess strategies. which platform do you use? – Mads Buch Jul 29 '12 at 20:39
-
I would like to know how to do it on both Windows and UNIX/Linux/Mac. – elijaheac Jul 29 '12 at 20:40
-
What do you mean by "the multiple processes strategy"? – elijaheac Jul 29 '12 at 20:40
-
Yes, I wrote it. I was intending for them both to be the same script, just different threads within it, but it doesn't matter. – elijaheac Jul 29 '12 at 21:11
3 Answers
I agree with @stark a GUI is the way.
Purely for illustration here's a not recommended non-GUI way that shows how to do it using a thread, a subprocess, and a named pipe as IPC.
There are two scripts:
entry.py
: accept commands from a user, do something with the command, pass it to the named pipe given at the command-line:#!/usr/bin/env python import sys print 'entry console' with open(sys.argv[1], 'w') as file: for command in iter(lambda: raw_input('>>> '), ''): print ''.join(reversed(command)) # do something with it print >>file, command # pass the command to view window file.flush()
view.py
: Launch the entry console, print constant updates in a thread, accept input from the named pipe and pass it to the updates thread:#!/usr/bin/env python import os import subprocess import sys import tempfile from Queue import Queue, Empty from threading import Thread def launch_entry_console(named_pipe): if os.name == 'nt': # or use sys.platform for more specific names console = ['cmd.exe', '/c'] # or something else: console = ['xterm', '-e'] # specify your favorite terminal # emulator here cmd = ['python', 'entry.py', named_pipe] return subprocess.Popen(console + cmd) def print_updates(queue): value = queue.get() # wait until value is available msg = "" while True: for c in "/-\|": minwidth = len(msg) # make sure previous output is overwritten msg = "\r%s %s" % (c, value) sys.stdout.write(msg.ljust(minwidth)) sys.stdout.flush() try: value = queue.get(timeout=.1) # update value print except Empty: pass print 'view console' # launch updates thread q = Queue(maxsize=1) # use queue to communicate with the thread t = Thread(target=print_updates, args=(q,)) t.daemon = True # die with the program t.start() # create named pipe to communicate with the entry console dirname = tempfile.mkdtemp() named_pipe = os.path.join(dirname, 'named_pipe') os.mkfifo(named_pipe) #note: there should be an analog on Windows try: p = launch_entry_console(named_pipe) # accept input from the entry console with open(named_pipe) as file: for line in iter(file.readline, ''): # pass it to 'print_updates' thread q.put(line.strip()) # block until the value is retrieved p.wait() finally: os.unlink(named_pipe) os.rmdir(dirname)
To try it, run:
$ python view.py

- 399,953
- 195
- 994
- 1,670
-
I think I've understood the gist of your code. So to be sure, when you launched the subprocess `p = launch_entry_console(named_pipe)` and then started reading the file using `with open(named_pipe) as file`, is this reading done as `p` is running in the background? As in, I can already use this scheme if I want to terminate `p` when a certain text 'stop' is read with the open pipe. – Apr 15 '16 at 10:32
-
-
In Windows, you would use `console = ["cmd.exe", "/c", "start"]`. The `start` makes Windows open a new window. Also, I prefer to reference the COMSPEC environment variable and use capital letters, as in `console = [os.environ.get("COMSPEC", "CMD.EXE"), "/C", "START"]`, but that's just my style. Of course, I agree that a GUI would be a better solution than all of this. – wecsam Jul 18 '17 at 12:10
Rather than use a console or terminal window, re-examine your problem. What you are trying to do is create a GUI. There are a number of cross-platform toolkits including Wx and Tkinter that have widgets to do exactly what you want. A text box for output and an entry widget for reading keyboard input. Plus you can wrap them in a nice frame with titles, help, open/save/close, etc.

- 12,615
- 3
- 33
- 50
UPDATED ANSWER:
import subprocess
command = "dir"
subprocess.run(["cmd.exe", "/c", "start", f"{command}"], timeout=15)
"cmd.exe" - if using Windows, Windows ONLY recognizes double quotes.
"/c" - says 'send the Return' after we send the 'dir'(for example) string.
"start" - says open new console window...even if debugging in Pycharm :)
f"command" - I use f-strings to send assemble strings Python3.6+
(timeout optional)

- 39
- 2