So I was debugging some of my code today and noticed a new message in the output:
can't invoke "event" command: application has been destroyed
while executing
"event generate $w <<ThemeChanged>>"
(procedure "ttk::ThemeChanged" line 6)
invoked from within
"ttk::ThemeChanged"
I looked at the questions regarding it on SO but they did't relate to this instance of the error. As for the ttk widget, I have not used ttk once in my code, a search for the string "ttk" in my code yields none.
Chunk of code that outputs this:
def GoToEvent(self, controller, driver):
wait = WebDriverWait(driver, 600)
var = Vars()
entertain = var.GetVars("Link")
if type(entertain) == type(""):
event = var.GetVars("Event")
entertain = driver.find_element_by_partial_link_text(event)
entertain.click()
try:
# we have to wait for the page to refresh, the last thing that seems to be updated is the title
wait.until(EC.title_contains("Entertain"))
finally:
# the page is ajaxy so the title is originally this:
msg = driver.title
label = tk.Label(self, text=msg, cursor='spinning', font="courier 24", bg="#c63f17")
label.place(x=self.winfo_width()/2, y=self.winfo_height()/2, anchor="center")
self.update() # <--- This is where the problem is
label.destroy()
This doesn't seem to actually throw any errors, and my code runs absolutely fine. I can't give enough code to replocate the problem as it is just simply too much code before this, but I can tell you all the testing I did if that helps. I debugged this code block and found that adding a breakpoint at label.destroy() would still give this error, but placing one anywhere before and stepping over to label.destroy() would not print this, leading me to believe it was some type of timing error with self.update(), but when I placed time.sleep(5) before and after self.update() the error was still there. So stepping through the code did not show the error but time.sleep() still showed the error. This puzzles me, I don't know why it would be behaving this way, I have been writing this program for 2 weeks and this is the first time this has happened. If no one knows it's fine, the code still runs perfectly, I'm just curious as to what this means and why it is happening. Thanks!
Beginning of code:
# !/usr/bin/python
# coding: utf-8
'''
Created on Jun 23, 2017
#author: jacob <---------------- Line 6
'''
from selenium import webdriver
#from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.ui import WebDriverWait # available since 2.4.0
from selenium.webdriver.support import expected_conditions as EC # available since 2.26.0
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import os
import platform
import pwd
import re
import time
#import datetime
from time import strftime
import Tkinter as tk
import tkFont as tkfont
from Tkinter import Entry, Menu, Menubutton, Canvas
So this was a very hard error to find, as debugging never pointed to the right area of code I had to read through the code to try to find something off. So the program gets user input for a keyword, a website is then searched for the events containing this keyword, they are then put into a drop down menu. If there is only one or none occurrence of the keyword then there is no menu displayed and it either clicks the event or it prompts the user with a suggested event that is closest to their keyword. This seemed like the probable area where this error was happening because it only occurred when no menu was displayed. Code from this:
if (len(options) > 1):
button6 = tk.Button(selectMenu, text="Enter",
cursor='pointinghand', command=lambda: self.GetSelection(str(var.GetVars("Selection")), links, options, selectMenu, controller))
msg = "Which one would you like to attend?"
label = tk.Label(selectMenu, text=msg, font="Helvedica 14")
label.pack(side='top', pady=10)
menbutton.pack(side="top", pady=10)
button6.pack(pady=10)
self.Progress()
selectMenu.attributes('-topmost', True)
selectMenu.mainloop()
elif options:
var.SendVars("selLink", links[0])
selectMenu.destroy()
self.Progress()
else:
var.SendVars("Link", 'NO-LINK-FOUND')
selectMenu.destroy()
self.Progress()
It turns out that this error was caused by a Menubutton being created in a tk window but never reaching the mainloop, even though it was destroyed. The error is thrown when the mainloop of another tk window is reached. So to fix this you move the creation of the Menubutton to a place where it will reach it's mainloop as below.
Related
I have a tkinter GUI, and am interested in adding a threading component to prevent my program from freezing. Here is my code:
from tkinter import *
import os
import threading
root = Tk()
root.title('Calculation Program')
root.geometry('700x525')
def param_log_export():
to_discover = disc_mode_choice.get()
def RunCalculation():
os.system('python command_center.py')
def combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
run_click_frame= Canvas(root, width= 450, height= 525)
save_button = Button(run_click_frame, width=450,height=1,text='Run Analysis!',fg='white',relief='flat',borderwidth=5,
bg='#2F4FAA',font=(Font_tuple,15),command = threading.Thread(target=combine_funcs(param_log_export,RunCalculation)).start())
save_button.pack(side=BOTTOM)
root.mainloop()
Essentially when the button is clicked, another script is called, and that script calls all of the smaller scripts for a certain calculation:
from target_list_create import mh_table
from ion_list_format import ion_mod_full
from theo_list_generation import theo_list_record
from precursor_fragment_matching import precursor_matches
Previously, I was just using command=combine_functs(param_log_export,RunCalculation), which worked fine, other than beginning to freeze as the size of my calculations grows. So, now I am trying the threading approach using the above code, but before I even have the opportunity to click the button which would command the threaded script, the program is running as though the button was clicked immediately. The console returns: UnboundLocalError: local variable 'fdr_algorithm_report' referenced before assignment, which indicates that there is a leak and the program triggers the combine_functs function as soon as the GUI is executed.
If anyone could help me understand what the issue is, so that when I click the button it executes the command without freezing the program, I would be very appreciative.
Why does in the code below button1 hang until the time.sleep(10) has completed.
I can only assume tKinter is waiting for the click event to finish before updating it's paint function.
I want on button1 click the state to change to DISABLED as in the code straight away, not when mainformbutton1press() has finished.
I have put time.sleep(10) to mimic rest of code functions - but the actual programme will be many minutes instead.
EDIT! - sleep is just there to show how tkinter hangs. My real programme has lots more code and no sleep function - and it takes a long time to process data with the hung GUI as mentioned. No more sleep suggestions please :)
import tkinter as tk
from tkinter import ttk
from tkinter.constants import DISABLED, NORMAL
import time
# ==================================================
class App:
def __init__(self, tk, my_w):
self.button1 = tk.Button(my_w, text="START", width=34, command = self.mainformbutton1press)
self.button1.grid(columnspan=3, row=6, column=1,padx=10,pady=20, ipadx=20, ipady=20)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def mainformbutton1press(self):
self.button1.config(text="PLEASE WAIT...")
self.button1['state'] = DISABLED
# DO REST OF PROCESSING
# TO MIMIC THIS:
time.sleep(10)
print("doing...")
# ==================================================
if __name__ == "__main__":
my_w = tk.Tk()
my_w.geometry("430x380")
my_w.resizable(False, False)
app = App(tk, my_w)
my_w.mainloop() # Keep the window open
Tk.mainloop is a sort of while loop. time.sleep() stops the loop for a particular period of time. That makes the window unresponsive. You might use .after function:
class App:
def __init__(self, tk, my_w):
self.my_w=my_w
....
def continue_next(self):
print("Doing")
....
def mainformbutton1press(self):
self.button1.config(text="PLEASE WAIT...")
self.button1['state'] = DISABLED
# DO REST OF PROCESSING
# TO MIMIC THIS:
self.my_w.after(10000,self.continue_next)
The only change you need to make to your code is to insert an update to your button.
The 10 second delay might need to be shortened (10 seconds is a long time to wait)
self.button1.config(text="PLEASE WAIT...")
self.button1['state'] = DISABLED
# INSERT UPDATE HERE
self.button1.update()
# DO REST OF PROCESSING
# TO MIMIC THIS:
time.sleep(1)
print("doing...")
I'm having trouble linking B.py script functions in the MAIN.py graphics window. This is a test of Tkinter's graphics window to check if the scraping (for the purpose of my personal and didactic study) was successful or there were errors. B.py is the script (works fine, okay) for scraping and error detection, while MAIN.py is the graphical test window. I have problems with Main.py
I write in order the steps I would like to obtain. I wrote their code (below), but something is wrong. I think they are very simple, but I searched the web and couldn't solve:
I open the MAIN.py graphics window and click the Start button. The B.py file is executed
If the scraping was successful, the small blue image / icon "boh.png" is replaced with the green (ok) image contained in /home/mypc/Desktop/Folder/img/green.png
If the scraping was not successful and there is an error, I get the red icon contained in /home/mypc/Desktop/Folder/img/red.png which replaces the blue one.
In case of errors, besides the image replacement, I would like to display the related 3 error (expect 1, expect 2 or if records_added_Resultati == 0) instead of the label "Message"
ERROR and PROBLEMS: After scraping, the blue icon is not replaced by the red or green icon. Also, the error message (except 1, or expect 2, or if ....) is not displayed in the Messages label.
MAIN.PY (graphics window)
from tkinter import *
from tkinter import ttk
import tkinter as tk
import tkinter.font as tkFont
from PIL import ImageTk, Image
from File import B
def draw_graph():
test_scraping=tk.Toplevel()
test_scraping.title("Test")
test_scraping.geometry("800x600")
test_scraping.configure(bg='#282828')
testN1 = Label(test, text="TEST N.1", bg="#282828", foreground='white')
testN1.place(x=6, y=12)
image_blu= Image.open("/home/mypc/Desktop/Folder/File/img/blu.png")
render1 = ImageTk.PhotoImage(image_blu)
image_blu = Label(test, image=render1, bg='#282828')
image_blu.place(x=76, y=12)
message = Label(test, text="Message ", bg="#282828", foreground='white')
message.place(x=156, y=12)
def do_scraping():
msg = B.scraping()
if msg:
message.configure(text=msg)
image_red= Image.open("/home/mypc/Desktop/Folder/File/img/error.png")
render7 = ImageTk.PhotoImage(image_red)
image_red = Label(test_scraping, image=render7, bg='#282828')
image_red.place(x=400, y=12)
else:
image_green= Image.open("/home/mypc/Desktop/Folder/File/img/ok.png")
render8 = ImageTk.PhotoImage(image_green)
image_green = Label(test_scraping, image=render8, bg='#282828')
image_green.place(x=400, y=12)
button = Button(test, text="Avvia", bg='#e95420', foreground='white', command=do_scraping)
button.place(x=6, y=112)
test.mainloop()
B.PY
from tkinter import *
from tkinter import ttk
import tkinter as tk
import sqlite3
from selenium.common.exceptions import NoSuchElementException
def scraping:
#Code Tor Connection. Useless to write it down. not important for the purposes of the example
try:
#Serie A
driver.get("link")
driver.close
SerieA=driver.find_element_by_class_name("teamHeader__name")
SerieA_text = SerieA.text
print(SerieA.text)
#Serie B
driver.get("link")
driver.close
SerieB=driver.find_element_by_class_name("teamHeader__name")
SerieB_text = SerieB.text
print(SerieB.text)
except NoSuchElementException:
return "FAILED: Error class name html"
except ValueError:
return "FAILED: Error ValueError"
if records_added_Risultati == 0:
raise ValueError("FAILED: 0 record scraping")
#Code for insert in database
You hadn't actually placed label in right place. You had place it in x=400 and I think that's the reason you are not seeing that label(image) in right place. Try to change that label in x=76 where that blue image is located. And try to destroy blue image label before placing other label.
Edit1:
You can replace image doing :
from tkinter import *
from tkinter import ttk
import tkinter as tk
import tkinter.font as tkFont
from PIL import ImageTk, Image
from File import B
def draw_graph():
test_scraping=tk.Toplevel()
test_scraping.title("Test")
test_scraping.geometry("800x600")
test_scraping.configure(bg='#282828')
testN1 = Label(test, text="TEST N.1", bg="#282828", foreground='white')
testN1.place(x=6, y=12)
image_blu= Image.open("/home/mypc/Desktop/Folder/File/img/blu.png")
render1 = ImageTk.PhotoImage(image_blu)
image_blu = Label(test, image=render1)
image_blu.place(x=76, y=12)
message = Label(test, text="Message ", bg="#282828", foreground='white')
message.place(x=156, y=12)
image_green= Image.open("/home/mypc/Desktop/Folder/File/img/ok.png")
render8 = ImageTk.PhotoImage(image_green)
image_red= Image.open("/home/mypc/Desktop/Folder/File/img/error.png")
render7 = ImageTk.PhotoImage(image_red)
def do_scraping():
msg = B.scraping()
if msg:
message.configure(text=msg)
image_blu.config(image=render7)
else:
image_blu.config(image=render8)
button = Button(test, text="Avvia", bg='#e95420', foreground='white', command=do_scraping)
button.place(x=6, y=112)
test.mainloop()
Instead of making new label/image. Replacing that existing label will be efficient.
Edit2:
records_added_Risultati == 0 if this condition is true then, there is no way. User can know what is going on without looking on terminal. So, It should return something, so that user will get the red icon and know, scraping was not successful.
from tkinter import *
from tkinter import ttk
import tkinter as tk
import sqlite3
from selenium.common.exceptions import NoSuchElementException
def scraping:
#Code Tor Connection. Useless to write it down. not important for the purposes of the example
try:
#Serie A
driver.get("link")
driver.close
SerieA=driver.find_element_by_class_name("teamHeader__name")
SerieA_text = SerieA.text
print(SerieA.text)
#Serie B
driver.get("link")
driver.close
SerieB=driver.find_element_by_class_name("teamHeader__name")
SerieB_text = SerieB.text
print(SerieB.text)
except NoSuchElementException:
return "FAILED: Error class name html"
except ValueError:
return "FAILED: Error ValueError"
if records_added_Risultati == 0:
return "FAILED: 0 record scraping"
I have a scraping script of where im using tkinter for ui. When i build the exe(with pyinstaller) and open it it working well, But When i close it, it opens multiple instance of tkinter Window. I cant paste the full code. So i pasted all the tkinter code i am using.
Here is the Full code Github Gist here
import requests
from lxml import html
from tkinter import *
import tkinter as ttk
import re
import datetime
import os
from firebase import firebase
import hashlib
#import App as App
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
#Region Tk
root = Tk()
root['height'] = 400
root['width'] = 600
global firebase
firebase = firebase.FirebaseApplication('#######URL####',None)
f1 = Frame(root)
f1["height"] = root["height"]
f1["width"] = root["width"]
root.title("JD Scraper - Gear Up Studio ")
Label(f1,text = "Input Url : Example : https://www.justdial.com/Ahmedabad/Gyms ").grid(row=0,column = 0,)
def getBool(event):
print(boolvar.get())
#Check Button
global boolvar
boolvar = BooleanVar()
boolvar.set(False)
boolvar.trace('w', lambda *_: print("The value was changed"))
cb = Checkbutton(f1, text = "Tele Phone number", variable = boolvar)
cb.bind("<Button-1>", getBool)
cb.grid(row=1, column=1)
global key_filled
key_filled = Entry(f1,width=50)
key_filled.grid(row=2,column=0)
key_filled.focus_set()
global activate_button
activate_button = Button(f1 , text="Active Now")
activate_button.bind("<Button-1>",activate_key)
activate_button.grid(row=2, column=1)
result = Label(f1, width=50)
result.grid(row=1,column=2)
global submit_button
submit_button = Button(f1 , text="Scrape Now")
submit_button.bind("<Button-1>",button_clicked)
submit_button.grid(row=1, column=0)
submit_button.config(state=NORMAL)
key_validation()
f1.pack()
root.mainloop()
Demo Video here
i was facing the exact the same problem with firebase and pyqt5. After many tries i examine the firebase library. In init there is close_process_pool() function which is called when program exits and close all the multiprocessing pools. In tkinter and pyqt case we dont need this function as all the process is the childs of main GUI thread so simple removing that function resolves the problem.
Change the init file to this will resolve the issue.
import atexit
#from .async import process_pool
from firebase import *
'''
#atexit.register
def close_process_pool():
"""
Clean up function that closes and terminates the process pool
defined in the ``async`` file.
"""
process_pool.close()
process_pool.join()
process_pool.terminate()
'''
I can see cmd window pops when run your exe to remove that use this command -w and also to compile as onefile into dist folder use -F to compile it as a single file, do this to resolve the issue
pyinstaller -w -F replace this with your script name.py
It will compile the file as one file for you and the use will be res
I'm really stuck on a basilary things: I have this code
from tkinter import *
import sys
import subprocess
import tkinter as tk
def cd():
f=(subprocess.check_output("net view"))
e=(f.decode(sys.stdout.encoding))
label1=Label(text=e).pack()
def mainscreen():
mainscreen=Tk()
mainscreen.title("Terfysgol's kit V 2.0")
frame1=Frame(mainscreen)
frame1.pack()
puls1=Button(frame1,text="List of device", borderwidth= "2",command= cd).pack()
mainscreen()
When I run it all the time that I press the button it create a new label but I only want to update the text of the label1.
This is what you are after:
def cd():
f=(subprocess.check_output("net view"))
e=(f.decode(sys.stdout.encoding))
label1.config(text = e)
and then at the top of your program after your imports you need to put:
label1 = Label()
label1.pack()
Please note that I'm not suggesting this is good program structure, but that is up to you to sort out. This answer is just a quick fix to provide you with enough information to work out the rest of what you need.
Also you can remove the import tkinter as tk line already imports tkinter.