Make Jython JFrame that cannot be closed - python

I'm writing a little script for TopSpin, a program to acquire and process NMR data. While the script is running the user should not select a different dataset in TopSpin. Therefore I wanted to open a Popup screen displaying a message.
The script we are talking about, will take some time to finish it's task, so if a user closes the popup, the message will not be visible anymore and another staff member could - unknowingly - cause some problems by selecting different datasets. That's the reason why I had the idea of implementing a popup window that cannot be closed by the user.
When the script starts it's task it will run popup.show() and after having finished it will run popup.hide(). How could I do this in Jython?
from javax.swing import *
def test():
frame = JFrame("Hello StackOverflow")
frame.setSize(300, 300)
frame.setLocationRelativeTo(None)
frame.show()
# Do some work
frame.hide()
test()

Related

Interrupt (NOT prevent from starting) screensaver

I am trying to programmatically interrupt the screensaver by moving the cursor like this:
win32api.SetCursorPos((random.choice(range(100)),random.choice(range(100))))
And it fails with the message:
pywintypes.error: (0, 'SetCursorPos', 'No error message is available')
This error only occurs if the screensaver is actively running.
The reason for this request is that the computer is ONLY used for inputting data through a bluetooth device (via a Python program). When the BT device sends data to the computer the screensaver is not interrupted (which means I cannot see the data the BT device sent). Thus, when the Python program receives data from the BT device it is also supposed to interrupt the screensaver.
I have seen several solution on how to prevent the screensaver from starting (which are not suitable solutions in my case), but none on how to interrupt a running screensaver. How can I do this, using Windows 10 and Python 3.10?
The Windows operating system has a hierarchy of objects. At the top of the hierarchy is the "Window Station". Just below that is the "Desktop" (not to be confused with the desktop folder, or even the desktop window showing the icons of that folder). You can read more about this concept in the documentation.
I mention this because ordinarily only one Desktop can receive and process user input at any given time. And, when a screen saver is activated by Windows due to a timeout, Windows creates a new Desktop to run the screen saver.
This means any application associated with any other Desktop, including your Python script, will be unable to send input to the new Desktop without some extra work. The nature of that work depends on a few factors. Assuming the simplest case, a screen saver that's created without the "On resume, display logon screen", and no other Window Station has been created by a remote connection or local user login, then you can ask Windows for the active Desktop, attach the Python script to that Desktop, move the mouse, and revert back to the previous Desktop so the rest of the script works as expected.
Thankfully, the code to do this is easier than the explanation:
import win32con, win32api, win32service
import random
# Get a handle to the current active Desktop
hdesk = win32service.OpenInputDesktop(0, False, win32con.MAXIMUM_ALLOWED);
# Get a handle to the Desktop this process is associated with
hdeskOld = win32service.GetThreadDesktop(win32api.GetCurrentThreadId())
# Set this process to handle messages and input on the active Desktop
hdesk.SetThreadDesktop()
# Move the mouse some random amount, most Screen Savers will react to this,
# close the window, which in turn causes Windows to destroy this Desktop
# Also, move the mouse a few times to avoid the edge case of moving
# it randomly to the location it was already at.
for _ in range(4):
win32api.SetCursorPos((random.randint(0, 100), random.randint(0, 100)))
# Revert back to the old desktop association so the rest of this script works
hdeskOld.SetThreadDesktop()
However, if the screen saver is running on a separate Window Station because "On resume, display logon screen" is selected, or another user is connected either via the physical Console or has connected remotely, then connecting to and attaching to the active Desktop will require elevation of the Python script, and even then, depending on other factors, it may require special permissions.
And while this might help your specific case, I will add the the core issue in the general case is perhaps more properly defined as asking "how do I notify the user of the state of something, without the screen saver blocking that notification?". The answer to that question isn't "cause the screen saver to end", but rather "Use something like SetThreadExecutionState() with ES_DISPLAY_REQUIRED to keep the screen saver from running. And show a full-screen top-most window that shows the current status, and when you want to alert the user, flash an eye-catching graphic and/or play a sound to get their attention".
Here's what that looks like, using tkinter to show the window:
from datetime import datetime, timedelta
import ctypes
import tkinter as tk
# Constants for calling SetThreadExecutionState
ES_CONTINUOUS = 0x80000000
ES_SYSTEM_REQUIRED = 0x00000001
ES_DISPLAY_REQUIRED= 0x00000002
# Example work, show nothing, but when the timer hits, "alert" the user
ALERT_AT = datetime.utcnow() + timedelta(minutes=2)
def timer(root):
# Called every second until we alert the user
# TODO: This is just alerting the user after a set time goes by,
# you could perform a custom check here, to see if the user
# should be alerted based off other conditions.
if datetime.utcnow() >= ALERT_AT:
# Just alert the user
root.configure(bg='red')
else:
# Nothing to do, check again in a bit
root.after(1000, timer, root)
# Create a full screen window
root = tk.Tk()
# Simple way to dismiss the window
root.bind("<Escape>", lambda e: e.widget.destroy())
root.wm_attributes("-fullscreen", 1)
root.wm_attributes("-topmost", 1)
root.configure(bg='black')
root.config(cursor="none")
root.after(1000, timer, root)
# Disable the screen saver while the main window is shown
ctypes.windll.kernel32.SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED)
root.mainloop()
# All done, let the screen saver run again
ctypes.windll.kernel32.SetThreadExecutionState(ES_CONTINUOUS)
While more work, doing this will solve issues around the secure desktop with "On resume, display logon screen" set, and also prevent the system from going to sleep if it's configured to do so. It just generally allows the application to more clearly communicate its intention.
SetCursorPos is failing because the cursor is probably set to NULL while the screensaver is running.
Instead of moving the cursor, try to find the current screensaver executable path and just kill the process. I think, this will be a fine solution.
you can check the Windows Registry record to obtain a filename of the screensaver (HKEY_USERS\.DEFAULT\Control Panel\Desktop\SCRNSAVE.EXE (msdn)
or you can check currently running processes list to find the one with .scr extension
Then just kill the process using TerminateProcess or just os.system('taskkill /IM "' + ProcessName + '" /F')
This is a classic XY problem: Say, you manage to stop the screensaver from turning up on your machine/test setup. But there are further questions:
What happens if your program runs on a terminal server that doesn't have an UI session?
Does your solution work if the power saving settings are set in such a way that they put the computer to sleep after a certain amount of time?
Will it work with future windows versions? With different subproducts? (the creative "look at this undocumented registry key and then kill some random process" solution seems destined for this)
Who knows and definitely hard to test.
What you really need is a way to tell the OS "hey I'm busy and keep the session active even if your normal heuristics would tell you that the user is away". This is a standard problem which video players and presentation software faces all the time.
The standard solution is to use SetThreadExecutionState with something along the lines of ES_DISPLAY_REQUIRED | ES_CONTINUOUS (and possibly other flags as well - the documentation is quite reasonable there) at the start of the program.
Raymond Chen has written about this in the past (no surprise there).
Note that this doesn't stop an already active screensaver - this is generally not a problem, because you can set the flag at startup (or when the intended action is triggered). It also doesn't stop the user from putting the computer manually to sleep, but that's something you shouldn't generally disable.

Tkinter-based app keeps running in the background if the window is closed abruptly

I've created a tkinter app designed to let users create and take quizzes locally. Unfortunately, if a user closes the window by hitting the 'x' in the corner instead of hitting the "quit" button on the main menu, the window is destroyed but the process remains in the background. It isn't a huge deal as it stops using any CPU and only holds on to about 40mb of memory per instance, but this just seems pretty sloppy for an app that I'd like to deploy.
I have no idea what specifically is refusing to exit when the window is closed, and as it could be coming from almost anywhere in my 1700 lines of code, I'm instead looking for some more general tips for identifying what's still running or for killing any remaining processes when the window is closed. I'm happy to provide my code if anyone thinks it would help, though I reiterate that it's quite long given that I can't identify the source of the particular problem.
You can use state() from Tk to check if the window is open or not. When the window is open it should return 'normal' and if the window isn't open it will return something else.
What I would do is add something that checks the state of the window and exit the app when it's closed.
while app_is_running:
if root.state() != 'normal':
sys.exit(0)

Python GUI using os.system to run python script cause main GUI "Not Responding"

StackOverflow community.
I am writing a python GUI to monitor another program's data in OSX environment and at one point I decide to click one button to open another python script that I wrote. It does work but it also causes a lag problem of the main GUI program as soon as I click the button. For the lag problem I mean the GUI window is "Not Responding" and I need to force quit. The method I use to run the new script is,
def create_html():
os.system('python realtime.py')
My program doesn't have the multiple class structure, just the simple canvas, and framework. I wonder if this is also the problem to cause my program running slow.
The problem is you are using os.system, which is a blocking call. It will not return control to your main code until python realtime.py is done executing and returned.
You need to use a call that will not block the rest of your program, such as subprocess.Popen.
You can also see this QA for further information

How to hard quit a Tkinter program

My Python program consists of two parts, one gets user credentials through an Tkinter and passes it to the other script which then processes them.
It works fine but the only problem is that although my GUI passes data and then the processing script starts its work, The GUI starts not-responding and causes havoc as it freezes until the download completes (which could potentially take hours)
I create an object of the Interface class in the processing script by importing the GUI script
root = Tk.Tk()
root.title('Coursera-dl')
root.geometry("345x100")
app = GUI.Interface(root)
app.mainloop()
This is my GUI script's destruct method defined in a Class which is executed automatically after the data has been received by the processing script: However when the user clicks 'OK' the GUI freezes and doesn't exit and If I force quit it, the processing script also ends as python.exe is terminated
*code*
....................................
def destruct(self):
if tkMessageBox.askokcancel(title=None,message='Download would start upon closing the Interface, If any changes are to be made to the credentials Please do so by selecting Cancel'):
self.quit()
How can I make my program so that when the user clicks on 'OK' the GUI quits safely and the processing script does its work
root.quit() just Bypasses the root.mainloop() i.e root.mainloop() will still be running in background if quit() command is executed.
Use root.destroy()
this will stop root.mainloop() itself but it wont close the python program and everything will still be ran just without the GUI

python script takes long time and window seems to freeze [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Simple pygtk and threads example please
I have this "problem" with my python script.
I make window with pygtk (with one text field) and then my script performs a database query and prepare the data for storage into a txt file. Everything works great but there is only one thing I am facing - this function runs approx. 2-4 minutes and during this time my program window is not "responding", so it looks like program window freezed (but the script is running and window is "live" again after finish).
How could I treat this behaviour? I would like to have my window responsive all time. For example: have a textfield "working...".
You need to use threading in your application. Any time you have a long running process you need to put that work into a separate thread and send progress updates to the main thread. I've answered a similar question before you can find a working example here. A shorter just dummy kind of example is provided below.
example
import gtk, gobject, urllib, time, threading
def run():
for i in range(50):
gobject.idle_add(button.set_label, '%s/50 complete' % i)
time.sleep(0.1)
def clicked(button):
threading.Thread(target=run).start()
gtk.gdk.threads_init()
win = gtk.Window()
button = gtk.Button(label="Start")
button.connect('clicked', clicked)
win.add(button)
win.show_all()
gtk.main()

Categories