How to open python software only once - python

i Have developed python application with tkinter framework which is working well on windows platform but the challenge am having is that i can open this application several times as it is shown in the image attached.
I want the application to open only once. If the app is opened and the user clicks on the icon on the desktop to open it again it shouldn't open because it is already being opened.
I want to achieve this function as it works in apps like Teamviewer , pycharm and etc.
Your suggestions are welcome to achieve this.
EDIT
This the how am trying to terminate the but after adding this to the code the executable doesn't runned again;
import psutil
import tkinter as tk
root = tk.Tk()
root.geometry("400x400")
b = tk.Button(root, text="hello world button", command=None)
b.place(x=200, y=100)
PROCNAME = "myapp.exe"
for proc in psutil.process_iter():
# check whether the process name matches
if proc.name() == PROCNAME:
print("Running, exit(1).")
exit(1)
else:
print("not running, continue to startup.")
root.mainloop()
root.mainloop()

Question: How to open python software only once
My Comment,
Find running processes using psutil and terminate.
should be written
Find running processes using psutil and exit.
if __name__ == "__main__":
PROCNAME = "myapp.exe"
for proc in psutil.process_iter():
# check whether the process name matches
if proc.name() == PROCNAME:
print("Running, exit(1).")
exit(1)
print("not running, continue to startup.")
App().mainloop()

Related

My multithread tkinter code only works when I run it on Pycharm, not in an .exe. It opens an unwanted window, even with __name__ == "__main__"

I have multiple files in this project, and, in this particular case, I call a function from another file.
from botmain import Execute
def EXECUTE_BOT(first_line, last_line, filename, padrao_comunicacao, concentrador, varredura, eventos, osci, param, ons,
empresa, grpparam, cnldgt, addparams):
time.sleep(5)
Execute(first_line,
last_line,
filename,
padrao_comunicacao,
concentrador,
varredura,
eventos,
osci,
param,
ons,
empresa,
grpparam,
cnldgt,
addparams)
if __name__ == '__main__':
root = Tk()
root.grab_set()
root.resizable = False
frm = ttk.Frame(root, padding=20)
frm.grid()
ttk.Button(frm, text="EXECUTAR", command=lambda: EXECUTE_BOT(wdg_firstLine.get(),
wdg_lastLine.get(),
wdg_sheetdirectory.cget("text"),
wdg_padrao_comunicacao.get(),
wdg_conc.get(),
radio_var.get(),
radio_eve.get(),
radio_osc.get(),
radio_param.get(),
radio_ons.get(),
wdg_empresa.get(),
wdg_grpParam.get(),
wdg_cnlDgt.get(),
converAddParam(addparam_list))).grid(column=5, row=22)
This code works just fine when I run it on Pycharm, but when I make it a .exe with pyinstaller, it stops working, and it opens another window every time I click on that button. I fixed this error by putting my code inside name == "main", but when I make it an .exe, it gets the same error than when I didn't have that.
Heeeeelp!!!
I had a similar issue, but when my multithread function was called it created a new root for each process. multiprocessing freeze_support() was the answer, read the docs here
if __name__ == '__main__':
multiprocessing.freeze_support() # to stop exe popups when threaded

How to write sentence in notepad using keyboard python package

I want to write the output in a separate notepad or ms word using python package keyboard.
import keyboard
keyboard.write('The quick brown fox jumps over the lazy dog.')
but it writes these sentence in the command prompt, where I run the script, not in notepad.
How can I make it to control the other software?
You need to give your other application focus.
When searching for a method I found this blog post which shows how it can done in Windows:
https://www.blog.pythonlibrary.org/2014/10/20/pywin32-how-to-bring-a-window-to-front/
import win32gui
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
if __name__ == "__main__":
results = []
top_windows = []
win32gui.EnumWindows(windowEnumerationHandler, top_windows)
for i in top_windows:
if "notepad" in i[1].lower():
print i
win32gui.ShowWindow(i[0],5)
win32gui.SetForegroundWindow(i[0])
break
After the application has focus, you can use your simulated key presses.
You can use pywinauto package which is more efficient and friendly:
from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')
# describe the window inside Notepad.exe process
window = app.UntitledNotepad # or app['Untitled - Notepad'], its the same
# wait till the window is really open
window_ready = window.wait('visible')
# Write in some text
app.UntitledNotepad.Edit.type_keys("Hello world", with_spaces = True)
NOTE: Some lines are adapted from the documentation

Pywinauto unable to find/close pop-up window

Source code
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
app = Application(backend='uia').start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
win = app['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.wait('ready')
win.menu_select("Setup->Refresh Serial and Ethernet")
win.top_window().print_control_identifiers(filename="file.txt")
# win.top_window().OKButton.click_input() ---------This is what I hope to do
else
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
Problem Statement
I had to run this application with elevation rights. The above is my code. The problem is I can't identify the window (view in output image) that pops up after selection from menu. I need to close the window. Please excuse the line
win.top_window().print_control_identifiers(filename="file.txt")
It was meant write the identifiers into a text file because the structure of this code does not display the outputs for me to view. However, since nothing is appended, I guess pywinauto couldn't identify the dialog.
For a clearer understanding, please view the image (input) of when it selects the menu.
Input
Now, it pops up with this dialog (output)
Output
I've also used spy to identify the caption and it gives:
(Handle: 004E07D4,
Caption: Information,
Class: #32770(Dialog),
Style: 94C801C5)
Other things I've tried:
Besides using win.topwindow() to identify the dialog, I've used
win[Information].OKButton.click_input()
win[Information].OK.click_input()
win[Information].OK.close()
win[Information].OK.kill(soft=false)
win.Information.OKButton.click_input()
win.Information.OK.click_input()
win.Information.OK.close()
win.Information.OK.kill(soft=false)
app[Information] ...... curious if I could discover the new window from original application
I've also send keys like enter, space, esc & alt-f4 to close the dialog with libraries like keyboard, pynput & ctypes. It still doesn't work.
Link to download the same application: http://downloadt.advantech.com/download/downloadsr.aspx?File_Id=1-1NHAMZX
Any help would be greatly appreciated !
I finally found a thread that demonstrated the way multi thread works to solve this issue. I tried it myself and it works. It's a little different as a few parts of the code have depreciated. Here is the link to the solution:
How to stop a warning dialog from halting execution of a Python program that's controlling it?
Here are the edits I made to solve the problem:
def is_admin():
try:
return ctypes.windll.shell32.IsUserAnAdmin()
except:
return False
if is_admin():
def __init__(self, window_name, quit_event):
threading.Thread.__init__(self)
self.quit_event = quit_event
self.window_name = window_name
def run(self):
while True:
try:
handles = windows.find_windows(title=self.window_name)
except windows.WindowNotFoundError:
pass
else:
for hwnd in handles:
app = Application()
app.connect(handle=hwnd)
popup = app[self.window_name]
popup.close()
if self.quit_event.is_set():
break
time.sleep(1)
quit_event = threading.Event()
mythread = ClearPopupThread('Information', quit_event)
mythread.start()
application = Application(backend="uia").start("C:\\Program Files (x86)\\Advantech\\AdamApax.NET Utility\\Program\\AdamNET.exe")
time.sleep(2)
win = application['Advantech Adam/Apax .NET Utility (Win32) Version 2.05.11 (B19)']
win.menu_select("Setup->Refresh Serial and Ethernet")
quit_event.set()
else:
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
The best thing is this solution works for every other dialog that halts the main script from working & I could use them to do different actions like clicking buttons, inserting values, by adding more multi threads.

run command from Python and then close

I am trying to build a small shell application, which runs a command from a GUI application. When I press the "off" button, the console for the command should be closed. I have two questions:
When I run the command, the command is running on the same console as my Python script. How can I open the command in a new console?
How can I stop the command? I mean like if the command is working in the same process as the GUI, I can just use exit(), but then the entire program will be terminated.
This is my code so far:
from tkinter import *
import subprocess
import os
top = Tk()
def turnOn():
p = subprocess.Popen("ping stackoverflow.com")
def turnOff():
pass
#should i do: p.close() of something?
on = Button(top, text = "on", command = turnOn)
off = Button(top, text = "off", command = turnOff)
on.grid()
off.grid()
top.mainloop()
You can stop the command by calling the subprocess's .terminate method. Here's a crude example that uses a global variable to store the Popen object; it would be better to wrap the GUI in a class, and store proc as an instance attribute of that class.
import tkinter as tk
import subprocess
top = tk.Tk()
proc = None
def turnOn():
global proc
if proc is None:
print('Starting ping')
proc = subprocess.Popen(["ping", "example.com"])
def turnOff():
global proc
if proc is not None:
print('Stopping ping')
proc.terminate()
proc = None
on = tk.Button(top, text = "on", command = turnOn)
off = tk.Button(top, text = "off", command = turnOff)
on.grid()
off.grid()
top.mainloop()
The if proc is None: line prevents the ping command from being re-launched if it's already running.
1)when i run command, the cmd command is running on the same cmd that my
pythoh script is work. how can i open the the command in another cmd window?
I assume you are trying to say that you need to run the process on another
shell. You should use the "shell" parameter of the subprocess functions:
subprocess.call(cmd, shell=True)
If instead you only need another command prompt window, just Popen another Windows cmd.
2)how can i stop the command? i mean like if the command is work on the same
window that the gui work i can just use in exit(), but then the all programm
will be stop.
The subprocess Popen object has a terminate method. You can call this sending a SIGTERM signal but is not always reliable. So there are several options depending from your OS and the nature of your process
(a little note: Popen object has a pid attribute with process pid):
os.kill(pid, signal) => to kill a simple process on a Posix/Windows OS
os.killpg(pgid, signal) => to kill a process as a group on a Unix OS
subprocess.Popen("taskkill /F /T /PID %i" % pid, shell=True) => to kill a process on windows
signal is a posix/windows signal depending from the OS. I.e. :
os.killpg(self.pid, signal.SIGKILL) # Posix
os.kill(self.pid, signal.CTRL_C_EVENT) # Windows
The os.kill call is not always reliable on Windows. This is the reason
for using the third option.

Tkinter Toplevel - strange behavior as built windows exe

I'm using tk for a project's GUI. I have some very strange behavior with it, but only as a built executable on windows. Essentially I have a function launches a new process and needs to update some GUI elements after it completes. This works fine on OS X and Windows running interpreted. It works fine as a OS X binary. But as a Windows binary, the code causes a second main window to appear for unknown reason.
The app is launched via:
root = tk.Tk()
root.withdraw()
app = impy()
root.mainloop()
where
class impy(tk.Toplevel):
Then sometime later a user clicks a button which causes this to run:
dialog = Progress_Dialog()
dialog.set_text('Implosion generation...')
dialog.update_idletasks()
# Use helper function:
parent_conn, child_conn = Pipe()
p = Process(target=ImplosionRunner.run, args=(child_conn,))
self.processes.append(p)
# start the process and send implosion:
p.start()
try:
parent_conn.send(self.imp)
except:
raise Exception('Implosion object passed to ImplosionRunner is not pickleable!')
obj = None
# Loop while the process is active:
def callback():
nonlocal dialog, p, parent_conn
if dialog.cancelled:
dialog.withdraw()
p.terminate()
return
# Try to receive from the Pipe:
if parent_conn.poll():
# Update the progress, or end otherwise:
obj = parent_conn.recv()
if isinstance(obj, Exception):
from tkinter.messagebox import showerror
showerror('Error!', 'A problem occurred generating the implosion (class '+self.imp.name()+')\n'+obj.__str__())
dialog.withdraw()
p.terminate()
return
elif isinstance(obj, float):
dialog.set(100*obj)
elif isinstance(obj, Implosion):
# Pass info back to the main app:
self.imp = obj
self.after(10, self.__postImplosion__)
dialog.withdraw()
p.terminate()
return
self.after(25, callback)
self.after(10, callback)
The callback loop eventually completes via the elif isinstance(obj, Implosion) clause. Then those functions are all called. Something that they do causes a second Toplevel window to appear which is essentially a clone of the main window. The UI operations are applied to the clone. The __postImplosion__ method is just:
for key in self.modControlChecks.keys():
self.modControlChecks[key].configure(state=tk.NORMAL)
# Run any modules that were already checked in refresh mode
for key in self.modControlChecks.keys():
self.modRedisplay[key] = (self.modControlVars[key].get() == 1)
for mod in allModules():
if self.modRedisplay[mod.name()]:
self.__runModule__(mod.name())
it just has to loop over some check boxes and enable them. I'm pretty baffled since this is only a problem with Windows binaries. Any thoughts?
Update: Some more troubleshooting: The extra main window appears immediately after p.start() is called. So this seems to be some weird behavior. Why can't I launch a process without an extra Tk window appearing?
OK, as usual, the solution is that I should have RTFM. According to the docs there is a magic function that must be called to fix weird problems with multiprocessing when frozen on Windows.
if __name__ == "__main__":
freeze_support()
root = tk.Tk()
root.withdraw()
app = impy()
root.mainloop()

Categories

Resources