How to make a messagebox auto close in several seconds by Python? - python

I already know how to make a Messagebox by Python:
import ctypes
ctypes.windll.user32.MessageBoxW(0, 'test', "Reminding", 0)
However, I want it to be closed by itself in several seconds after it shows up.
Is there any method to realize it?
Psuedo code:
def AutoCloseMessageBoxW(text, title, close_until_seconds)
I have found a lot of methods to realize this by other language such as C# and Java.
But I just can't find any method to realize it by Python.

import ctypes
import threading
import time
#ctypes.windll.user32.MessageBoxA(0, 'test', "Reminding", 0)
def worker(title,close_until_seconds):
time.sleep(close_until_seconds)
wd=ctypes.windll.user32.FindWindowA(0,title)
ctypes.windll.user32.SendMessageA(wd,0x0010,0,0)
return
def AutoCloseMessageBoxW(text, title, close_until_seconds):
t = threading.Thread(target=worker,args=(title,close_until_seconds))
t.start()
ctypes.windll.user32.MessageBoxA(0, text, title, 0)
AutoCloseMessageBoxW('112','TEST_CLOSE',3)

Use pyautogui
import pyautogui as py # pip install pyautogui
# It is automatically terminated after three seconds. If automatically ends, return "Timeout" returns.
def show_message():
res = py.confirm(text='Message...', buttons=['Yes', 'No'], timeout=3000)
print(res)

Related

Python, how to execute a line of code without it stopping the rest of the code from executing?

first of all, im a beginner.
Want i want to accomplish is that music plays while the script is executing.
What it does right now it plays the music, waits until the music is over and then executes the rest of the code. That is not what i want. Here my Code:
import os
import subprocess
import multiprocessing
import threading
from playsound import playsound
CurrentPath = os.path.dirname(os.path.normpath(__file__))
os.chdir(CurrentPath)
def music():
Music = "Music.mp4"
#subprocess.run(["ffplay", "-nodisp", "-autoexit", "-hide_banner", Music])
playsound("Music.mp4")
def other_things():
print("Hello World")
#musicp = multiprocessing.Process(target=music())
#restp = multiprocessing.Process(target=other_things())
musicp = threading.Thread(target=music())
restp = threading.Thread(target=other_things())
restp.start()
musicp.start()
LIke you can see i even tried multithreading but it still waits until the music is over before it goes to the rest of the code.
Don't call the functions in the target parameter of the Thread function - delete the brackets to reference the function, not its return value
musicp = threading.Thread(target=music) # instead of music()
restp = threading.Thread(target=other_things) # instead of other_things()

Gtk.Spinner in Python GTK while importing large library

I have a GTK application in C that will spawn a Python GTK process to embed a matplotlib figure into a window in the C process using GtkSocket/GtkPlug (uses XEmbed Protocol). The problem I am having is that the import of the matplotlib library takes about 2.5 seconds and during that time the socket widget is simply transparent. I would like to place a Gtk.Spinner in the plug (so the Python side) before the matplotlib import and have the spinner animate asynchronously during the process of importing the matplotlib library. The problem is that in order for the widget to be placed in the plug, and subsequently, for the Gtk.Spinner to animate, it requires iterations of the GTK main loop. I have approached this from a ton of different angles:
(1) Using a thread. The first attempt was trying to run Gtk.main_iteration() via the thread, however, GTK can only be run on the main thread and this does not work. It stalls the program.
(2) Then I tried to use GObject.idle_add from the thread, where the main loop iterations would run from the idle function (apparently the function called via idle is done on the main thread?), but this didn't work either.
(3) Then I tried to import the modules on the thread, while the main thread runs the Gtk.main_iteration()'s to allow the spinner to spin while the imports are taking place. The idea was once the imports are complete, a boolean flag would change to trigger a break from the loop of main iterations. In this case the spinner appears and spins but the plot never shows up. I get an X Server error:
Gdk-WARNING **: master: Fatal IO error 104 (Connection reset by peer) on X server :0.
(4) In lieu of threading, I tried to use GObject.timeout_add to call a function regularly that would perform the Gtk.main_iteration()'s, but doing that results in the original behavior where the socket/plug is transparent until the plot shows up (i.e. no spinner appears nor spins).
I have run out of ideas and now I am coming here hoping for an assist. They key idea is to get the Gtk.Spinner spinning while the Python script is loading the matplotlib library, and once that is done, replace the spinner widget with the figure (while all of this is taking place in a GtkSocket/Plug). I have not created a minimal reproducible example for this since it would be rather complex given the circumstances, but if anyone that is willing to help requests one I could come up with it. However, the relevant code section is below (with previous attempts commented out):
import sys
import gi
import time
import threading
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject
from gi.repository import Pango as pango
if sys.platform != "win32":
GObject.threads_init()
Gdk.threads_init()
# Open socket ID file, read Socket ID into variable, close file
socketFile = open('resources/com/gtkSocket', 'r+')
gtkSock = socketFile.read()
print("The ID of the sockets window in Python is: ", int(gtkSock))
socketFile.close()
# Create plug, create GTK box, add box to plug, add spinner to box
spin_plug = Gtk.Plug.new(int(gtkSock))
socketbox = Gtk.Box()
spin_plug.add(socketbox)
spinner = Gtk.Spinner()
socketbox.pack_start(spinner, expand=True, fill=True, padding=False)
spinner.start()
finished = False
def thread_run():
time.sleep(4)
'''
# Loop for four seconds checking if gtk events are pending, and if so, main loop iterate
t_end = time.time() + 4
while time.time() < t_end:
if (Gtk.events_pending()):
Gtk.main_iteration()
print("Events Pending...")
'''
'''
import argparse
import collections
import csv
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.lines as mlines
from collections import defaultdict
from enum import Enum
from matplotlib.backend_bases import MouseEvent
from matplotlib.pyplot import draw
from matplotlib.widgets import SpanSelector
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FC
from matplotlib.backends.backend_gtk3 import NavigationToolbar2GTK3
'''
# You cannot run GTK Code on a separate thread from the one running the main loop
# Idle add allows scheduling code to be executed on the main thread
GObject.idle_add(cleanup)
def cleanup():
# Note: Trying to add the Gtk Main Iterations to the idle add function did not work...
print("Closing Spinner Thread...")
spinner.stop()
finished = True
thread.join()
# start a separate thread and immediately return to main loop
#thread = threading.Thread(target=thread_run)
#thread.start()
spin_plug.show_all()
def spin():
busy_wait = 0
while (Gtk.events_pending() or busy_wait < 10):
Gtk.main_iteration()
if (not Gtk.events_pending()):
busy_wait = busy_wait + 1
print("Spin Call complete.")
return True
GObject.timeout_add(50, spin)
'''
# We cannot simply run an infinite Gtk.main() loop, so iterate until the plug has been filled
busy_wait = 0
while (Gtk.events_pending() or busy_wait < 10):
if (finished):
break
print("Busy Wait: %d" % busy_wait)
Gtk.main_iteration()
if (not Gtk.events_pending()):
busy_wait = busy_wait + 1
print("Gtk Main Loop iterations complete.")
'''
Any pointers or ideas would be greatly appreciated.
The solution was performing the imports on a thread while allowing the main thread to do the main loop iterations. Simply doing "import " did not work. Some previous Stack Overflow posts that were useful are here:
Python thread for pre-importing modules
import a module from a thread does not work
Import python modules in the background in REPL
The solution looks like this:
GObject.threads_init()
Gdk.threads_init()
# Open socket ID file, read Socket ID into variable, close file
socketFile = open('resources/com/gtkSocket', 'r+')
gtkSock = socketFile.read()
print("The ID of the sockets window in Python is: ", int(gtkSock))
socketFile.close()
# Create plug, create GTK box, add box to plug, add figure to box
spin_plug = Gtk.Plug.new(int(gtkSock))
socketbox = Gtk.Box()
spin_plug.add(socketbox)
# Create a spinner, pack it, and start it spinning
spinner = Gtk.Spinner()
socketbox.pack_start(spinner, expand=True, fill=True, padding=False)
spinner.start()
spinner.show()
# Flag to break from the Gtk.events_pending() loop
finished = False
# This will load modules on a thread. A simple "import module" does not work
def do_import(module_name):
thismodule = sys.modules[__name__]
module = importlib.import_module(module_name)
setattr(thismodule, module_name, module)
print(module_name, 'imported')
# Use the last module being imported so we know when to break from the Gtk.events_pending()
if (module_name == "matplotlib.pyplot"):
global finished
finished = True
spin_plug.show_all()
modules_to_load = ['argparse', 'collections', 'csv', 'matplotlib', 'matplotlib.pyplot']
# Loop through and create a thread for each module to import from the list
for module_name in modules_to_load:
thread = threading.Thread(target=do_import, args=(module_name,))
thread.start()
# We cannot simply run an infinite Gtk.main() loop, so iterate until the plug has been filled
# Busy wait continues to allow the spinner to spin until the computer loads the modules. Since
# each computer will have a different loading speed, a busy wait of 300 should cover slower
# machines. We can break out of the loop early once the last module is loaded.
busy_wait = 0
while (Gtk.events_pending() or busy_wait < 300):
#print("Busy Wait: %d" % busy_wait)
#print ("finished: %d" % finished)
if (finished):
break
Gtk.main_iteration()
if (not Gtk.events_pending()):
busy_wait = busy_wait + 1

Python GUI freezes or closes while trying to update the button label text

I am trying to read a string from the ubuntu terminal and set that string as a label of a button. It works perfectly for some iteration and then freezes or closes with error. I couldn't find any pattern about when it freezes or closes. I am using gtk libraries and python 2.7.
A screenshot of the UI after it has frozen can be seen below.
As seen in the above screenshot, it has successfully updated the value 234, 56 and then exited with error after receiving 213 string. You can also observe that the button in the UI also has 213 value.
Sometimes the UI just freezes without displaying any errors or exiting.
I have used the below codes
1. thread.py ( main program called from terminal )
import thread
import time
import gui2
import vkeys1
import os
try:
thread.start_new_thread( vkeys1.main, ( ) )
thread.start_new_thread( gui2.main, ( ) )
except:
print "Error: unable to start thread"
# To stop this script from closing
os.system("mkfifo d1 2> error.log")
fd = os.open('d1', os.O_RDONLY)
ch = os.read(fd,1) # No writer
2. vkeys1.py ( It reads the input from terminal and calls textinit() )
import gui2
def main() :
while True:
try :
gui2.ch = str(input('\nInput a string : '))
gui2.textinit()
except :
print(" \n\n Exception!! \n\n")
3. gui2.py ( Updates the button label )
from gi.repository import Gtk, GdkPixbuf, Gdk, GLib
import Image
import os, sys
import time
import vkeys1
import threading
global ch # ch is used at vkeys1.py to store the input
ch = 'dummy content'
button0 = Gtk.Button(label="Initially empty")
class TableWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="String retrieval widget")
self.set_size_request(500,200)
self.connect_after('destroy', self.destroy)
self.main_box=Gtk.VBox()
self.main_box.set_spacing(5)
self.label = Gtk.Label(" ")
table = Gtk.Table(7,4, True)
self.add(self.main_box)
self.main_box.pack_start(self.label, False, False, 0)
self.main_box.pack_start(table, False, False, 0)
table.attach(button0, 0, 4, 0, 1)
self.show_all()
def destroy(window, self):
Gtk.main_quit()
def textinit(): # called from vkeys1.py
class Thrd(threading.Thread) :
def __init__(self) :
threading.Thread.__init__(self)
print('\nReceived string')
print(str(ch))
print('\n')
button0.set_label(str(ch)) # Button label updated here
Thrd2 = Thrd()
Thrd2.start()
return
def main():
app=TableWindow()
app.set_keep_above(True)
app.set_gravity(Gdk.Gravity.SOUTH_WEST)
Gtk.main()
if __name__ == "__main__":# for any error exit
sys.exit(main())
The above codes can be run by typing python thread.py (after creating the above 3 files off-course). Please suggest any solution to overcome this freezing problem.
The most likely cause of the crash is that your code invokes GTK code from threads other than the thread that runs the main loop, which the documentation states is not allowed.
To resolve the issue, replace the call of gui2.textinit() with GLib.idle_add(gui2.textinit) (note the lack of parentheses after textinit).
Several remarks about the code:
The generic exception handler is masking exceptions that occur. Remove it, and you will see a useful traceback when something goes wrong.
If you are running under Python 2, you probably want to change input to raw_input, otherwise the code chokes on any input that is not a valid Python expression.
textinit creates a thread object that never runs an actual thread. When inheriting from threading.Thread, one must override the run function, which will be invoked in the new thread once start() is called. Doing the work in the constructor accomplishes nothing.
thread.start_new_thread is a low-level API that should not be used in normal circumstances and that is demoted to _thread in Python 3. Instead of thread.start_new_thread(fn, ()), use threading.Thread(target=fn), which has the same meaning, and also returns a Thread object.

Python Serial Port with threading - freezing computer

Okay, time for another question/post...
So currently i am trying to develop a simple python program that has a webkit/ webpage view and a serial port interface.. Not that it should matter, but this is also running on a raspberry pi.
The following code works fine.. But it will freeze the system as soon as i uncomment the serial port line that you can see commented out.
The day has been long and this one for some reason has my brain fried.. Python is not my strongest point, but mind you this is just a quick test script for now... Yes i have used google and other resources...
#!/usr/bin/env python
import sys
import serial
import threading
import time
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *
sURL = ""
sURL2 = ""
objSerial = serial.Serial(0)
def SerialLooper():
global objSerial
if objSerial.isOpen() == True:
print("is_responding")
#objSerial.write("is_responding")
time.sleep(10)
SerialLooper()
class TestCLASS(object):
def __init__(self):
global sURL
global sURL2
global objSerial
objSerial = serial.Serial(0)
sURL = "http://localhost/tester"
app = QApplication(sys.argv)
webMain = QWebView()
webMain.loadFinished.connect(self.load_finished)
webMain.load(QUrl(sURL))
webMain.show()
thread = threading.Thread(target=SerialLooper)
thread.start()
sys.exit(app.exec_())
def load_finished(boolNoErrors):
global sURL
print("Url - " + sURL)
#something here
#something else here
newObjClass = TestCLASS()
EDIT
Futher on this, it appears its not the multithreading but the serial.write()
It has been a while since I used serial, but IIRC it is not threadsafe (on Windows at least). You are opening the port in the main thread and performing a write in another thread. It's a bad practice anyway. You might also consider writing a simple single-threaded program to see if the serial port is actually working.
PS Your program structure could use some work. You only need one of the global statements (global objSerial), the rest do nothing. It would be better to get rid of that one, too.
And the recursive call to SerialLooper() will eventually fail when the recursion depth is exceeded; why not just use a while loop...
def SerialLooper():
while objSerial().isOpen(): # Drop the == True
# print something
# write to the port
# Sleep or do whatever

Prevent OS X from going to sleep with Python?

Is there a way to prevent a computer running OS X from going to sleep from within a Python script?
You can use the built-in caffeinate command.
subprocess.Popen('caffeinate')
This is how I use it:
import sys
import subprocess
if 'darwin' in sys.platform:
print('Running \'caffeinate\' on MacOSX to prevent the system from sleeping')
subprocess.Popen('caffeinate')
You can also run caffeinate in an external terminal window and leave it open to achieve what the OP wants.
open a terminal
type caffeinate
press Enter
Once you have done this, your Mac will stay awake for as long as you leave the Terminal running.
You can minimize or hide it, and your Mac will not go to sleep until you use the keyboard shortcut Ctrl+C to interrupt the command.
source
Since OS 10.6, you have to make use of the IOPMAssertion family of functions, available in Cocoa. This is really well explained there.
Then, you will have to call it from Python. I'm not sure that there're already specific bindings for Cocoa in Python, but you can call Objective-C functions. It is really well described here.
There is a Python utility that illustrates how to raise the required assertions in Python directly: https://github.com/minrk/appnope
Another alternative would be to run the below script with
python <location/of/my/script.py> <hour until I want the PC to be awake>
e.g.
python /Users/johndee/Downloads/keep_awake.py 18:30
The script, which is to be saved locally:
#!/usr/bin/env python3
import random
import sys
import time
from datetime import datetime
from tkinter import Tk
import pyautogui
CHECK_STATUS_ONCE_IN = 120
WAIT_FOR_POSITION_CHANGE = 10
def current_position():
tkinter = Tk()
return [tkinter.winfo_pointerx(), tkinter.winfo_pointery()]
def mouse_is_moving():
pos1 = current_position()
time.sleep(WAIT_FOR_POSITION_CHANGE)
pos2 = current_position()
return not pos1 == pos2
def keep_awake():
# Shake the mouse a lil bit
initial_x, initial_y = current_position()
try:
for _ in range(random.randint(1, 10)):
# Mouse
pyautogui.moveTo(random.randint(1, 1000), random.randint(1, 1000))
# Keys
pyautogui.press("shift")
# Restore controls
pyautogui.moveTo(initial_x, initial_y)
except pyautogui.FailSafeException as e:
print(e)
def inspect_activity_until(time_to_stop: datetime):
time_to_stop = datetime.now().replace(
hour=time_to_stop.hour, minute=time_to_stop.minute
)
while datetime.now() < time_to_stop:
if not mouse_is_moving():
keep_awake()
time.sleep(CHECK_STATUS_ONCE_IN)
print(f"Stopping at {datetime.now()}")
if __name__ == "__main__":
given_time = sys.argv[1]
date_time_obj = datetime.strptime(given_time, "%H:%M")
inspect_activity_until(date_time_obj)

Categories

Resources