GUI program with toggable console? - python

I've seen some apps allow you to show/hide the console when you need to read log messages. For example Blender3D allows that (blender.org).
I was wondering if this can be done in Python and how.
My main window is a Panda3D (panda3d.org) window.
I've read somewhere that one option is to hide the "real" console (pythonw) and create another console and just redirect everything from the "real" one to it, every time you want to "show" the "real" console. No idea how this can be done.
Or at least a way to choose whether to start the program with the console or without it by reading a configuration file or something.

I'm assuming you are talking about Windows because this console toggling in blender is Windows exclusive. I'm guessing Blender uses GetConsoleWindow and ShowWindow on Windows.
This is how you could do it in python with pywin32:
import win32gui, win32console, win32api, win32con
import time
console_window = win32console.GetConsoleWindow()
time.sleep(1)
win32gui.ShowWindow(console_window, win32con.SW_HIDE)
time.sleep(1)
win32gui.ShowWindow(console_window, win32con.SW_SHOW)
time.sleep(1)
If you run this program with python and not pythonw it will show the console, sleep for a second, hide the console, sleep for another second and then hide it again.
Mind that this code only works on Windows. On other platforms silly stuff like this is not necessary because if you want a program to show a console then you run it from the console.

Related

How to use subprocess to run a program without a window showing?

I am using subprocess.call() to programatically launch a software on my PC (the Meta Trader platform for forex trading, to be exact). The call works fine, the terminal is launched properly, however I now want to improve the experience by removing the popping up Meta Trader window. I know that in web scraping it is possible to use a headless browser, enabling that scraping be done without an actual(ly visible) web browser window showing on the screen. I was wondering if there is some way to achieve the same functionality using subprocess.call() (or else).
There doesn't seem to be built-in support on other platforms, but it's possible on Windows by passing a STARTUPINFO instance to the Popen constructor.
The following example starts the Notepad editor in the background. Its window is hidden, but the program is running as the Task Manager would show. Pressing Ctrl+C stops the program and terminates the background process.
import subprocess
from time import sleep
process = subprocess.Popen(
'notepad',
startupinfo=subprocess.STARTUPINFO(
dwFlags=subprocess.STARTF_USESHOWWINDOW,
wShowWindow=subprocess.SW_HIDE,
),
)
try:
while process.poll() is None:
sleep(1)
except KeyboardInterrupt:
process.kill()
Note that this may not work for more complex applications that start their own subprocesses, such as the Chrome browser to name but one example. One may then have to go through the Windows API in order to hide the application windows after they were created.

why does subprocess launch an "extra" application?

I wrote a Python script to detect a Print Screen keypress, and launch the Snipping Tool. The script uses subprocess.call to handle the application launch.
The problem I am facing is that when I am done with Snipping Tool and close the application, I get an "extra" application being launched. For example, if I took a snip of a PowerPoint presentation, then when I close Snipping Tool I get a new / blank instance of Power Point being launched automatically. I do not want this to happen, and just want the Snipping Tool to close without any additional action.
Can someone please help explain what I am missing in my code?
# https://stackoverflow.com/questions/24072790/detect-key-press-in-python
# https://pypi.org/project/keyboard/
# https://github.com/boppreh/keyboard#api
import keyboard #pip install keyboard
import time
import subprocess
while True:
if keyboard.is_pressed('print screen'):
subprocess.call(r'SnippingTool.exe') # blocking; waits until open
keyboard.press_and_release('ctrl+N')
#elif keyboard.is_pressed('ctrl+print screen'): # not recognizing "print screen" here
elif keyboard.is_pressed('ctrl+esc'):
print 'killing it now'
break
else:
time.sleep(0.1)
I'm guessing (and I'm not on Windows), but I think that the subprocess.call waits until you have finished with Snipping Tool, and so the keyboard.press_and_release('ctrl+N') is going to PowerPoint.

Python time.sleep interrupted after click on terminal

I am building a command line tools using Python script. it's a loop to check data and print out some stuff after some delay seconds. It works fine until I click anything or selecting text by mouse on the terminal without keyboard event. it doesn't do anything after that, doesn't print and recheck
import time
import sys
print('some thing')
for remaining in range(10, 0, -1):
sys.stdout.write("\r")
sys.stdout.write("recheck in {:2d}.".format(remaining))
sys.stdout.flush()
time.sleep(1)
sys.stdout.write("\rComplete! \n")
input()
My environment is anaconda 64bit on windows 10
The console is blocking in the Windows SDK function WriteConsole because the console window is in a mode called QuickEdit mode.
To fix the issue, go to the properties option in the upper left corner menu of the console.
Then uncheck QuickEdit mode.
QuickEdit mode is there to help with copying and pasting text from the console. So when the console is in that mode, it stops all writing to the console so that the text isn't moving while you are trying to select and copy/paste.
Python significantly changed its system signal handling in Python 3.5. https://www.python.org/dev/peps/pep-0475/
It used to throw an InterruptedError whenever a signal interrupted a system call. Now the system call wrapper code upon signal interruption will recall the system call recalculating any timeouts if necessary. A bug at this level could recall the system call with an absurdly long value.
Attach a debugger and see where the process is at when it is stuck.
EDIT: after attaching windbg to stuck console. I discovered that this isn't the problem. I posted the real solution in a new answer.

How do i pass on control on to different terminal tab using perl?

I am trying to automate a scenario in which, I have a terminal window open with multiple tabs open in it. I am able to migrate between the tabs, but my problem is how do i pass control to another terminal tab while i run my perl script in a different tab.
Example: I have a terminal open with Tab1,Tab2,Tab3,Tab4 open in the same terminal, i run the perl script in Tab3 and i would want to pass some commands onto Tab1. Could you please tell me how can i do this ??
I use GUI tool to switch between tabs X11::GUITest and use keyboard shortcuts to switch between tabs, any alternative suggestion is welcome, my ultimate aim is to pass control on to a different tab.
The main thing to understand is that each tab has a different instance of terminal running, more importantly a different instance of shell (just thought I would mention as it didnt seem like you were clear about that from your choice of words). So "passing control" in such a scenario could most probably entail inter-process communication (IPC).
Now that opens up a range of possibilities. You could, for example, have a python/perl script running in the target shell (tab) to listen on a unix socket for commands in the form of text, which the script can then execute. In Python, you have modules subprocess (call, Popen) and os (exec*) for this. If you have to transfer control back to the calling process, then I would suggest using subprocess as you would be able to send back return codes too.
Switching between tabs is a different action and has no consequences on the calling/called processes. And you have already mentioned how you intend on doing that.

What magic prevents Tkinter programs from blocking in interactive shell?

Note: This is somewhat a follow-up on the question: Tkinter - when do I need to call mainloop?
Usually when using Tkinter, you call Tk.mainloop to run the event loop and ensure that events are properly processed and windows remain interactive without blocking.
When using Tkinter from within an interactive shell, running the main loop does not seem necessary. Take this example:
>>> import tkinter
>>> t = tkinter.Tk()
A window will appear, and it will not block: You can interact with it, drag it around, and close it.
So, something in the interactive shell does seem to recognize that a window was created and runs the event loop in the background.
Now for the interesting thing. Take the example from above again, but then in the next prompt (without closing the window), enter anything—without actually executing it (i.e. don’t press enter). For example:
>>> t = tkinter.Tk()
>>> print('Not pressing enter now.') # not executing this
If you now try to interact with the Tk window, you will see that it completely blocks. So the event loop which we thought would be running in the background stopped while we were entering a command to the interactive shell. If we send the entered command, you will see that the event loop continues and whatever we did during the blocking will continue to process.
So the big question is: What is this magic that happens in the interactive shell? What runs the main loop when we are not doing it explicitly? And why does it need to halt when we enter commands (instead of halting when we execute them)?
Note: The above works like this in the command line interpreter, not IDLE. As for IDLE, I assume that the GUI won’t actually tell the underlying interpreter that something has been entered but just keep the input locally around until it’s being executed.
It's actually not being an interactive interpreter that matters here, but waiting for input on a TTY. You can get the same behavior from a script like this:
import tkinter
t = tkinter.Tk()
input()
(On Windows, you may have to run the script in pythonw.exe instead of python.exe, but otherwise, you don't have to do anything special.)
So, how does it work? Ultimately, the trick comes down to PyOS_InputHook—the same way the readline module works.
If stdin is a TTY, then, each time it tries to fetch a line with input(), various bits of the code module, the built-in REPL, etc., Python calls any installed PyOS_InputHook instead of just reading from stdin.
It's probably easier to understand what readline does: it tries to select on stdin or similar, looping for each new character of input, or every 0.1 seconds, or every signal.
What Tkinter does is similar. It's more complicated because it has to deal with Windows, but on *nix it's doing something pretty similar to readline. Except that it's calling Tcl_DoOneEvent each time through the loop.
And that's the key. Calling Tcl_DoOneEvent repeatedly is exactly the same thing that mainloop does.
(Threads make everything more complicated, of course, but let's assume you haven't created any background threads. In your real code, if you want to create background threads, you'll just have a thread for all the Tkinter stuff that blocks on mainloop anyway, right?)
So, as long as your Python code is spending most of its time blocked on TTY input (as the interactive interpreter usually is), the Tcl interpreter is chugging along and your GUI is responding. If you make the Python interpreter block on something other than TTY input, the Tcl interpreter is not running and the your GUI is not responding.
What if you wanted to do the same thing manually in pure Python code? You'd of need to do that if you want to, e.g., integrate a Tkinter GUI and a select-based network client into a single-threaded app, right?
That's easy: Drive one loop from the other.
You can select with a timeout of 0.02s (the same timeout the default input hook uses), and call t.dooneevent(Tkinter.DONT_WAIT) each time through the loop.
Or, alternatively, you can let Tk drive by calling mainloop, but use after and friends to make sure you call select often enough.

Categories