I am currently developing a program to try an xml file. However I encounter a problem that has been blocking me for a few days now and I can rack my brains my beginner level in python and my many research does not help me to get over it.
I first try to retrieve 1 element from my xml file. I can do it well only the graphics window that should normally display it does not generate and I have the following error message:
The error :
window.fenetre_text(Acte_D) NameError: name 'Acte_D' is not defined`
well my code is :
import tkinter as tk
from tkinter import *
from tkinter import messagebox
from tkinter.filedialog import askopenfilename
from xml.dom import minidom`
global file
global Acte_D
global element_A
global lines
class fenetreM(Tk):
#GUI
def __init__(self, master=None,*args, **kwargs):
Tk.__init__(self,master, *args, **kwargs)
self.menu_bar()
self.title("EssaiV1.0.1")
self.geometry("800x400")
self.minsize(380,140)
self.config(background='#F0F0F2')
#New_frame=Frame(fenetreM, bg='#abd7f4')`
def menu_bar(self):
menu_bar = Menu(self)
menu_file = Menu(menu_bar, tearoff=0)
menu_file.add_command(label="Open", underline=0, command=self.open_file)
menu_file.add_command(label="Affichage",underline=0,command=self.do_something)
menu_file.add_separator()
menu_file.add_command(label="Exit",underline=1,command=self.quit)
menu_bar.add_cascade(label="File",underline=0, menu=menu_file)
menu_help = Menu(menu_bar, tearoff=0)
menu_help.add_command(label="About", command=self.do_about)
menu_bar.add_cascade(label="Help",underline=0, menu=menu_help)
self.config(menu=menu_bar)
valid = False
return(valid)
def open_file(self):
types = [("All Files",".*")]
file = askopenfilename(title="File to open : ", filetypes=types)
print("Copy")
doc = minidom.parse(file)
print(doc.nodeName)
print(doc.firstChild.tagName)
Acte_D = doc.getElementsByTagName("ActeDescription")
print("\n")
element_A = (f" we have {Acte_D.length} element \n Version : ")
for i in Acte_D:
screen_1=(i.getAttribute("version"))
print(screen_1)
print("\n")
return (Acte_D)
def fenetre_text(self,Acte_D):
tk=Text(fenetreM, height = 10, width =100)
Fenetre_A=tk.inset(END,textvariable=self.element_A+Acte_D)
Fenetre_A.pack(side="top", fill="x", expand=True)
return(Acte_D)
window = fenetreM()
window.fenetre_text(Acte_D)
window.mainloop()
Can someone explain my mistake to me?
Thanks
I tried to graphically display the result of Acte_D in my window defined in my method fenetre_text.
But I can't.
Related
First of all to kick it off,
I'm not great at programming,
I have difficulty with understanding most basics,
I always try doing my uterly best to solve things like this myself.
I'm trying to create a simple gui that makes json files. Everything works fine. Fine in the sense that I'm able to create the files.
Now I wanted to get my code cleaned up and to the next level. I have added tabs to the tkinter screen and that is where the troubles starts. Because when I'm, on a differend tab, the function doesn't get the current selected items, so I added buttons to save that list and then move to different tab.
I have a function(Save_List_t), which looks at the selected items from the listbox(a_lsb1) and saves them to a list(choice_list_t). This function runs when I press button(a_button).
After doing that I got a problem, I don't want to use "global" but I need the list in a other function(Mitre_Gen_Techs) to generate the files. This function runs when I press a button on the third tab.(c.button1)
To tackel this problem, I saw a post where someone uses a class to fix it. However even after reading to the documentation about classes I still don't truely get it.
Now I'm stuck and get the error. Which I don't find that strange, it makes sense to me why it gives the error but what am I doing wrong or how do I solve this issue.
The error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\thans\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
TypeError: Save_List_t() missing 1 required positional argument: 'self'
The code I wrote:
from tkinter import *
from attackcti import attack_client
from mitretemplategen import *
from tkinter import ttk
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mitre ATT&Ck
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ac = attack_client()
groups = ac.get_groups()
groups = ac.remove_revoked(groups)
techs = ac.get_enterprise_techniques()
techs = ac.remove_revoked(techs)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Tkinter screen setup
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
root = Tk()
root.title("Mitre Att&ck")
root.minsize(900, 800)
root.wm_iconbitmap('')
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Functions / classes
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class Screen(object):
def __init__(self):
self.choice_list_t = []
self.choice_list_g = []
def Save_List_t(self):
for item in a_lsb2.curselection():
self.choice_list_t.append(a_lsb2.get(item))
print(self.choice_list_t)
def Save_List_g(self):
choice_list_g = []
for item in b_lsb1.curselection():
self.choice_list_g.append(b_lsb1.get(item))
print(self.choice_list_g)
def Mitre_Gen_Techs(self):
# Gen the json file
# mitre_gen_techs(self.choice_list_t, techs)
#testing class
print(self.choice_list_t)
def Mitre_Gen_Groups(self):
# Gen the json file
# mitre_gen_groups(self.choice_list_g, groups)
#testing class
print(self.choice_list_g)
def main():
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# First Tkinter tab
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
rows = 0
while rows < 50:
root.rowconfigure(rows, weight=1)
root.columnconfigure(rows, weight=1)
rows += 1
# Notebook creating tabs
nb = ttk.Notebook(root)
nb.grid(row=1, column=0, columnspan=50, rowspan=50, sticky='NESW')
# Create the differend tabs on the notebook
tab_one = Frame(nb)
nb.add(tab_one, text='APG')
tab_two = Frame(nb)
nb.add(tab_two, text='Actors')
tab_gen = Frame(nb)
nb.add(tab_gen, text='test')
# =-=- First Tab -=-=
# List box 1
a_lsb1 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
# List with techs
a_lsb2 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
for t in techs:
a_lsb2.insert(END, t['name'])
# Save list, to later use in Screen.Mitre_Gen_Techs
a_button = Button(tab_one, text="Save selected", command=Screen.Save_List_t)
# =-=- Second Tab -=-=
# List with TA's
b_lsb1 = Listbox(tab_two, height=30, width=30, selectmode=MULTIPLE)
for g in groups:
b_lsb1.insert(END, g['name'])
# Save list, to later use in Screen.Mitre_Gen_Groups
b_button = Button(tab_two, text="Save selected", command=Screen.Save_List_g)
# =-=- Third tab -=-=
c_button = Button(tab_gen, text="Print group json", command=Screen.Mitre_Gen_Groups)
c_button1 = Button(tab_gen, text="Print techs json", command=Screen.Mitre_Gen_Techs)
# Placing the items on the grid
a_lsb1.grid(row=1, column=1)
a_lsb2.grid(row=1, column=2)
b_lsb1.grid(row=1, column=1)
a_button.grid(row=2, column=1)
b_button.grid(row=2, column=1)
c_button.grid(row=2, column=1)
c_button1.grid(row=2, column=2)
root.mainloop()
# If main file then run: main()
if __name__ == "__main__":
main()
The application:
Image
I found someone who explained what was wrong.
Credits to Scriptman ( ^ , ^ ) /
simply adding:
sc = Screen()
And changing:
Button(tab_apg, text="Save selected", command=sc.Save_List_t)
Resolved the issue.
I am using python 3.4.4 and tkinter ttk..currently trying to implement line number widget with my ttk notebook widget but not giving me error neither printing line number..its working fine with single Text widget... I surely made a mistake but I am not able to fix it thanks for helping me.
main.py
import tkinter.ttk as ttks
from tkinter import LEFT,RIGHT,X,Y,BOTH
class MainUI:
def __init__(self,master):
self.master = master
self.txs = []
self.linenumber = ttks.tkinter.Canvas(self.master,border=0,width=25,bg="#808b96")
self.linenumber.pack(side=LEFT,fill=Y)
self.nb = ttks.Notebook(self.master)
self.nb.pack(fill='both',expand=1)
self.add_tabs()
self._orig = self.txs[self.nb.index('current')]._w +"_orig"
self.master.call("rename",self.txs[self.nb.index('current')]._w,self._orig)
self.master.createcommand(self.txs[self.nb.index('current')]._w,self._proxy)
self.master.bind('<Control-n>',self.add_tabs)
def add_tabs(self,event=None):
self.page_name = ttks.Frame(self.nb)
self.tx = ttks.tkinter.Text(self.page_name)
self.txs.append(self.tx)
self.tx.pack(fill=BOTH,expand=1)
self.nb.add(self.page_name,text="pagename")
def redraw(self):
self.linenumber.delete("all")
i = self.txs[self.nb.index('current')].index("#0,0")
while True:
dline = self.txs[self.nb.index('current')].dlineinfo(i)
if dline is None: break
y = dline[1]
linenum = str(i).split(".")[0]
self.linenumber.create_text(2,y,anchor="nw",text=linenum)
i = self.txs[self.nb.index('current')].index("%s+1line"%i)
def _proxy(self,*args):
try:
cmd = (self._orig,)+args
result = self.master.call(cmd)
if (args[0] in ("insert","replace","delete") or
args[0:3] in ("mark","set","insert") or
args[0:2] in ("xview","moveto") or
args[0:2] in ("xview","scroll") or
args[0:2] in ("yview","moveto") or
args[0:2] in ("yview","scroll")
):
self.txs[self.nb.index('current')].event_generate("<<Change>>",when="tail")
return result
except:
pass
def Onchange(self,event):
self.redraw()
I forgot to Bind Onchange method.
self.txs[self.nb.index('current')].bind("<<Change>>",self.Onchange)
self.txs[self.nb.index('current')].bind("<Configure>",self.Onchange)
I have the following code :
from tkinter import *
class GUI:
def __init__(self,master):
self.ip_word = Label(master,text="Input Path")
self.ip_word.grid(row=0,sticky=E)
self.ip_path_field = Entry(master)
self.ip_path_field.grid(row=0,column=1,sticky=W)
self.op_word = Label(master,text="Output Path")
self.op_word.grid(row=2,sticky=E)
self.op_path_field = Entry(master)
self.op_path_field.grid(row=2,column=1,sticky=W)
self.filename_word=Label(master,text="Output Filename ")
self.filename_word.grid(row=4,sticky=E)
self.filename =Entry(master)
self.filename.grid(row=4,column=1,sticky=W)
self.Submit = Button(master,text="Submit",fg="black",bg="white",command=self.Scraper(ip_path_field,op_path_field,filename) )
self.Submit.grid(row=5,columnspan=2)
"""
def printMessage(self):
str1=ip_path_field
str2=op_path_field
str3=filename
Scraper(str1,str2,str3)"""
def Scraper(self,ip_path_field,op_path_field,filename):
import pandas as pd
import os
# "C:/Users/chowdhuryr/Desktop/first automation/MAIN RESEARCH DATA.xlsx"
user_input =ip_path_field#input("Enter the input file path of your file: ")
if os.path.exists(user_input):
df = pd.read_excel(user_input, sheetname='Sheet1')
print("File Found and We are Processing !")
else:
print ("Input Directory does not exists.")
#"C:/Users/chowdhuryr/Desktop/first automation/OUTPUT DATA.xlsx"
user_output =op_path_field#input("Enter the output file path of your file: ")
#if os.path.exists(user_input):
#df = pd.read_excel(user_input, sheetname='Sheet1')
#--------------------------------------------------------------------------------------------------------------------------------------
#setting up the path
import os
os.chdir('C:/Users/chowdhuryr/Desktop/first automation')
df=df[0:5]
#--------------------------------------------------------------------------------------------------------------------------------------
#importing necessary packages
from selenium import webdriver
#from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException
#---------------------------------------------------------------------------------------------------------------------------------------
#Setting up Chrome webdriver
#chrome_options = webdriver.ChromeOptions()
options = webdriver.ChromeOptions()
options.add_argument("--headless") #making the window work in the background
options.add_argument('window-size=1200x850')
#declaring a list to store the messages
Message=list()
Tier=list()
Wirecentre=list()
#---------------------------------------------------------------------------------------------------------------------------------------
#iteration to access the url and and retriving the Tier Locations
for i in range(0,df.shape[0]): #(0,df.shape[0]):
driver = webdriver.Chrome(executable_path='C:/Users/chowdhuryr/Desktop/first automation/chromedriver', chrome_options=options) #openning chrome
#driver.maximize_window() #maximizing the window
driver.get('https://clec.att.com/facilitiescheck/facilities_chk.cfm') #openning the url
street_address=driver.find_element_by_xpath('/html/body/form/table/tbody/tr[2]/td[2]/table/tbody/tr[1]/td[2]/input') #accessing the street address field
street_address.send_keys(df['CIRCUIT_LOC_ADDR'][i].split(',')[0]) #passing the values to street_address location
city=driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[2]/td[2]/input') #accessing the city to street address field
city.send_keys(df['CIRCUIT_LOC_ADDR'][i].split(',')[1]) #passing the values to the city location
state=driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[4]/td[2]/select') #accessing the state field
state.send_keys(df['CIRCUIT_LOC_ADDR'][i].split(',')[2]) #passing the values to the state field
checkbox=driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[8]/td[1]/input') #accessing the checkbox
checkbox.click() #clicking on the check box
search_button=driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[8]/td[1]/input') #accessing the submit button
search_button.submit() #clicking the submit button
#try-except block in case if radio button appears
try:
Address=driver.find_element_by_xpath('/html/body/form/table[2]/tbody/tr[1]/td[2]/b') #taking the xpath of the address block
if (Address): #checking if it contains any radio button or not
Radio_button=driver.find_element_by_xpath('/html/body/form/table[2]/tbody/tr[2]/td[1]/input') #getting the xpath of radio button
Radio_button.click() #clicking the radio button
submit_button=driver.find_element_by_xpath('/html/body/form/table[3]/tbody/tr[2]/td/input') #getting the submit button
submit_button.submit()
except NoSuchElementException:
print('no such element found')
message_body= driver.find_element_by_xpath('//*[#id="msg"]/table/tbody/tr/td').text #Extracting the Message from the message box
Message.append(message_body[14:]) #putting the message into a text
str = message_body.split() #splitting the message
if any ("Tier"in s for s in str):
j=str.index('Tier')
Tier.append(str[j+1])
else:
Tier.append("NULL")
if any ("AT&T"in s for s in str):
j=str.index('AT&T')
Wirecentre.append(str[j+1])
else:
Wirecentre.append("NULL")
#saving the screenshot
str=df['STRIP_EC_CIRCUIT_ID'][i]
filename="C:\\Users\\chowdhuryr\\Desktop\\first automation\\"+str+".png" #Taking the circuit id name
driver.get_screenshot_as_file(filename)
driver.close() #closiing the driver
#------------------------------------------------------------------------------------------------------------------------------------------
#putting the back thenew columns into the dataframe and storing it into an excel sheet
df['Tier']=Tier #putting the Tier column back into the dataset
df['Wirecentre']=Wirecentre #putting the Wirecentre column back into the dataset
df['Message']=Message #putting the Message column back into the dataset
if os.path.exists(user_output):
user_output="user_output"+filename+".xlsx"
writer = pd.ExcelWriter(user_output) #writing the dataframe down into a new excel file
df.to_excel(writer,'sheet1',index=False) #to_excel(writer,'Sheet1')
writer.save()
else:
print ("Output Directory does not exists.")
#-------------------------------------------------------------------------------------------------------------------------------------------
#Generating pop up window at the end of the process
popup_driver=webdriver.Chrome()
popup_driver.maximize_window()
popup_driver.execute_script(" window.alert('Process is Completed');") #generating the pop up """
root =Tk()
b=GUI(root)
#b.Scraper(ip_path_field,op_path_field,filename)
root.mainloop()
Now what I want to do is this :
I want to pass the variables ip_path_field,op_path_field,filename as arguments to the function named scraper . Now ip_path_field,op_path_field,filename are all user inputs and not hard coded strings. Now whenever I run the following code, I get the GUI opened and whenever I provide my inputs in the required edit boxes and press the submit button I get the following error name 'ip_path_field' is not defined. My purpose of this code is to pass the user defined file paths to the function called scraper() as defined in the code above.
You need to create a callback that gets the values, and then passes them to the function that does the work.
Example:
class GUI:
def __init__(self,master):
...
self.Submit = Button(..., command=self.handle_submit)
...
def handle_submit(self):
ip_path = self.ip_path_field.get()
op_path = self.op_path_field.get()
filename = self.filename.get()
self.Scrapper(ip_path_field,op_path_field,filename)
The main problem you are having is related to how you built your method. Instead you should have put the get() calls inside that method. This way you can simple run the command to call scraper without needing to pass arguments. I have taken your code and re-written it to more closely follow the PEP8 standard with the method correction included.
You only need to apply the self. prefix to class attributes/methods. Things like labels/buttons that are not going to be modified later in the code should be left as normal widgets that are not assigned as attributes.
Next I moved all your imports to the top of the code. You only need to import a library one time and it should all be listed at the top of your code. On imports keep in mind it is better to import tkinter as tk instead of using * to prevent any accidental overrides occurring.
I have changed your string concatenation to use the format() method as + is deprecated.
Here is your code with some basic clean up as well.
import tkinter as tk
import pandas as pd
import os
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
class GUI:
def __init__(self,master):
tk.Label(master, text="Input Path").grid(row=0, sticky="e")
tk.Label(master, text="Output Path").grid(row=2, sticky="e")
tk.Label(master, text="Output Filename").grid(row=4, sticky="e")
self.ip_path_field = tk.Entry(master)
self.op_path_field = tk.Entry(master)
self.filename = tk.Entry(master)
self.ip_path_field.grid(row=0, column=1, sticky="w")
self.op_path_field.grid(row=2, column=1, sticky="w")
self.filename.grid(row=4, column=1, sticky="w")
tk.Button(master, text="Submit", fg="black", bg="white",
command=self.scrapper).grid(row=5,columnspan=2)
def scrapper(self): # changed function to a method.
user_input = self.ip_path_field.get(0, "end")
user_output = self.op_path_field.get(0, "end")
filename = self.filename.get(0, "end")
if os.path.exists(user_input):
df = pd.read_excel(user_input, sheetname='Sheet1')
print("File Found and We are Processing !")
else:
print ("Input Directory does not exists.")
os.chdir('C:/Users/chowdhuryr/Desktop/first automation')
df = df[0:5]
options = webdriver.ChromeOptions()
options.add_argument("--headless")
options.add_argument('window-size=1200x850')
message = list()
tier = list()
wirecentre = list()
for i in range(0,df.shape[0]):
driver = webdriver.Chrome(executable_path='C:/Users/chowdhuryr/Desktop/first automation/chromedriver', chrome_options=options)
driver.get('https://clec.att.com/facilitiescheck/facilities_chk.cfm')
street_address = driver.find_element_by_xpath('/html/body/form/table/tbody/tr[2]/td[2]/table/tbody/tr[1]/td[2]/input')
street_address.send_keys(df['CIRCUIT_LOC_ADDR'][i].split(',')[0])
city=driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[2]/td[2]/input')
city.send_keys(df['CIRCUIT_LOC_ADDR'][i].split(',')[1])
state = driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[4]/td[2]/select')
state.send_keys(df['CIRCUIT_LOC_ADDR'][i].split(',')[2])
checkbox = driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[8]/td[1]/input')
checkbox.click()
search_button = driver.find_element_by_xpath('/html/body/form/table[1]/tbody/tr[2]/td[2]/table/tbody/tr[8]/td[1]/input')
search_button.submit()
try:
address = driver.find_element_by_xpath('/html/body/form/table[2]/tbody/tr[1]/td[2]/b')
if (address):
radio_button = driver.find_element_by_xpath('/html/body/form/table[2]/tbody/tr[2]/td[1]/input')
radio_button.click()
submit_button = driver.find_element_by_xpath('/html/body/form/table[3]/tbody/tr[2]/td/input')
submit_button.submit()
except NoSuchElementException:
print('no such element found')
message_body = driver.find_element_by_xpath('//*[#id="msg"]/table/tbody/tr/td').text
message.append(message_body[14:])
strx = message_body.split()
if any ("Tier"in s for s in strx):
j = strx.index('Tier')
tier.append(strx[j+1])
else:
tier.append("NULL")
if any ("AT&T"in s for s in strx):
j = strx.index('AT&T')
wirecentre.append(strx[j+1])
else:
wirecentre.append("NULL")
strx = df['STRIP_EC_CIRCUIT_ID'][i]
filename = "C:\\Users\\chowdhuryr\\Desktop\\first automation\\{}.png".format(strx)
driver.get_screenshot_as_file(filename)
driver.close()
df['Tier'] = tier
df['Wirecentre'] = wirecentre
df['Message'] = message
if os.path.exists(user_output):
user_output="user_output{}.xlsx".format(filename)
writer = pd.ExcelWriter(user_output)
df.to_excel(writer, 'sheet1', index=False)
writer.save()
else:
print ("Output Directory does not exists.")
popup_driver = webdriver.Chrome()
popup_driver.maximize_window()
popup_driver.execute_script(" window.alert('Process is Completed');")
root = tk.Tk()
b = GUI(root)
root.mainloop()
All that said you should try to use a minimal code next time. It is easier to fix issues when you narrow it down to exactly the problem. For example based on your question a Minimal, Complete, and Verifiable example would look something like this.
from tkinter import *
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
class GUI:
def __init__(self,master):
self.ip_path_field = Entry(master)
self.ip_path_field.grid(row=0,column=1,sticky=W)
self.op_path_field = Entry(master)
self.op_path_field.grid(row=2,column=1,sticky=W)
self.filename =Entry(master)
self.filename.grid(row=4,column=1,sticky=W)
self.Submit = Button(master, text="Submit",
command=self.Scrapper(ip_path_field,op_path_field,filename) )
self.Submit.grid(row=5,columnspan=2)
def Scrapper(self,ip_path_field,op_path_field,filename):
user_input = ip_path_field
user_output = op_path_field
filename = filename
root = Tk()
b = GUI(root)
root.mainloop()
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.pack()
self.create_widgets()
def create_widgets(self):
self.hi_there = tk.Button(self)
self.hi_there["text"] = "Done!\n(click me)"
self.hi_there["command"] = self.say_hi
self.hi_there.pack(side="top")
self.entrythingy = tk.Entry()
self.entrythingy2 = tk.Entry()
self.entrythingy.pack()
self.entrythingy2.pack()
# here is the application variable
self.contents = tk.StringVar()
self.contents2 = tk.StringVar()
# set it to some value
self.contents.set("stdio")
self.contents2.set("script name")
# tell the entry widget to watch this variable
self.entrythingy["textvariable"] = self.contents
self.entrythingy2["textvariable"] = self.contents2
self.text = tk.Text()
self.text.pack()
# and here we get a callback when the user hits return.
# we will have the program print out the value of the
# application variable when the user hits return
self.entrythingy.bind('<Key-Return>',
self.print_contents)
self.quit = tk.Button(self, text="QUIT", fg="red",
command=root.destroy)
self.quit.pack(side="bottom")
def say_hi(self):
#print("hi there, everyone!")
self.fn = self.contents2.get()
self.body = self.text.get(1.0, tk.END).split('\n')
#print('Self.body:\n',self.body)
self.libs = self.contents.get().split(' ')
self.make_c()
def make_c(self):
lib_text = ''
for i in self.libs:
lib_text += "#include <lib.h>\n".replace('lib', i)
body_text = "int main() {\n\t"+"\n\t".join(self.body)+"return 0\n}"
print(lib_text+body_text)
with open(self.fn+'.c', 'w+') as f:
f.write(lib_text+body_text)
print('File written!')
from subprocess import call
call(['gcc',self.fn+'.c', '-o', self.fn])
def print_contents(self, event):
print("hi. contents of entry is now ---->",
self.contents.get())
#self.contents.set("")
#def
root = tk.Tk()
app = Application(master=root)
app.mainloop()
Those are the my code, which tries to make a c file and convert it. The problem is, when I convert it once, it is working fine, but when I change the content of the text box, the file doesn't change, and I don't understand why. I am sure that I put in the new file content, because it prints before it writes. Also, it appears that when I try to write files independent from tkinter, it works just the way I want it to.
I think there is some mechanism that I am not aware of in TK, or there is a bug. Please help me out, thanks.
I solved it. It doesn't compile again due to the error in it when I added return 0, without semicolon. So, when I click the executable file, it shows the old program. I added the semicolon, and now it is fine. Thx everyone!
I have a database of objects and you can view the items in the database in a listbox and there's a button to remove an item and to create an item. Creating an item opens a dialog window for the item class and then the item's data is stored in the database. I have reproduced the problem with a very simple duplicate of my set-up (see code below).
Every time I add a new item, the addition is successful (it's there the next time I open up the database dialog), but the listbox doesn't insert the item, and when I close the database dialog I get the following error:
Exception in Tkinter callback Traceback (most recent call last):
File "C:\Python33\lib\tkinter__init__.py", line 1442, in call
return self.func(*args) File "", line 21, in addRecord File "C:\Python33\lib\tkinter__init__.py", line 2604, in insert
self.tk.call((self._w, 'insert', index) + elements)
_tkinter.TclError: invalid command name ".50054760.50055432"
The same problem doesn't come up if I just try to create the object and populate its values without invoking its inputs GUI (which is necessary for the process of inserting things into my database). I've seen a similar error in another thread (sorry, but I can't seem to find it again), where the problem was with multithreading. I'm not aware of any threading that I'm doing and don't want to download yet another package to handle tkinter threading. Any ideas? Workarounds? I'm using Python v3.3 and 64-bit Windows 7, if that helps.
Here's my simplified database code:
import tkinter
import traceback
# Test =========================================================================
class Test:
def __init__(self):
"""A database of objects' IDs and values."""
self.data = {1: 'a', 2: 'b', 3: 'c'}
#---------------------------------------------------------------------------
def addRecord(self):
"""Opens up a new item for editing and saves that ability to the
database."""
print('hi0')
newItem = OtherObject()
newItem.create(self.root)
print('hi1')
self.data[newItem.ID] = newItem.value
print('hi2')
self.listbox.insert(tkinter.END, self.formatItem(newItem.ID))
print('hi3')
#---------------------------------------------------------------------------
def delRecord(self):
"""Removes selected item from the database."""
try:
index = self.listbox.curselection()[0]
selection = self.listbox.get(index)
except:
return
ID = int(selection.split(':')[0])
self.data.pop(ID)
self.listbox.delete(index)
#---------------------------------------------------------------------------
def dataframe(self, master):
"""Assembles a tkinter frame with a scrollbar to view database objects.
(Returns Frame, Scrollbar widget, Listbox widget)
master: (Tk or Toplevel) tkinter master widget."""
frame = tkinter.Frame(master)
# scrollbar
scrollbar = tkinter.Scrollbar(frame)
scrollbar.pack(side=tkinter.LEFT, fill=tkinter.Y)
# listbox
listbox = tkinter.Listbox(frame, yscrollcommand=scrollbar.set)
listbox.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
# fill listbox
for ID in self.data:
listbox.insert(tkinter.END, self.formatItem(ID))
return (frame, listbox, scrollbar)
#---------------------------------------------------------------------------
def destroyLB(self, e):
for line in traceback.format_stack():
print(line.strip())
#---------------------------------------------------------------------------
def formatItem(self, ID):
"""Creates a nice string representation of an item in the database."""
return '{0}:{1}'.format(ID, self.data[ID])
#---------------------------------------------------------------------------
def listboxSelect(self, e):
"""Manages events when the selection changes in the database interface.
e: (Event) tkinter event."""
try:
selection = self.listbox.get(self.listbox.curselection()[0])
except:
return
# set description label
ID = int(selection.split(':')[0])
self.lblstr.set(self.data[ID])
#---------------------------------------------------------------------------
def view(self):
"""Displays database interface."""
self.root = tkinter.Tk()
# listbox frame
self.frame, self.listbox, self.scrollbar = self.dataframe(self.root)
self.frame.grid(column=0, row=0)
self.listbox.bind('<<ListboxSelect>>', self.listboxSelect)
self.listbox.bind('<Destroy>', self.destroyLB)
# record display frame
self.lblstr = tkinter.StringVar()
self.lbl = tkinter.Label(self.root, textvariable=self.lblstr)
self.lbl.grid(column=1, row=0, sticky=tkinter.N)
# buttons frame
self.frame_btn = tkinter.Frame(self.root)
self.frame_btn.grid(row=1, columnspan=2, sticky=tkinter.E+tkinter.W)
# 'create new' button
self.btn_new = tkinter.Button(
self.frame_btn, text='+', command=self.addRecord)
self.btn_new.grid(row=0, column=0)
# 'delete record' button
self.btn_del = tkinter.Button(
self.frame_btn, text='-', command=self.delRecord)
self.btn_del.grid(row=0, column=1)
# display
self.root.mainloop()
# Test =========================================================================
# OtherObject ==================================================================
class OtherObject:
"""An object with an ID and value."""
def __init__ (self):
self.ID = 0
self.value = ''
#---------------------------------------------------------------------------
def create(self, master=None):
"""open a dialog for the user to entry a new object ID and value.
master: (Tk or Toplevel) tkinter master widget."""
self.stuff = tkinter.Toplevel(master)
# ID
tkinter.Label(self.stuff, text='ID: ').grid(row=0, column=0)
self.IDvar = tkinter.StringVar(self.stuff)
self.IDvar.set(self.ID)
IDwidget = tkinter.Entry(self.stuff, textvariable=self.IDvar)
IDwidget.grid(row=0, column=1)
# value
tkinter.Label(self.stuff, text='Value: ').grid(row=1, column=0)
self.valueVar = tkinter.StringVar(self.stuff)
self.valueVar.set(self.value)
valueWidget = tkinter.Entry(self.stuff, textvariable=self.valueVar)
valueWidget.grid(row=1, column=1)
# OK button
tkinter.Button(self.stuff, text='OK', command=self.OK).grid(row=2)
self.stuff.mainloop()
#---------------------------------------------------------------------------
def OK(self):
try: self.ID = int(self.IDvar.get())
except: self.ID = 0
self.value = self.valueVar.get()
self.stuff.destroy()
# OtherObject ==================================================================
Thanks in advance
You are creating more than one instance of Tk. Tkinter is not designed to work like that and you will get unexpected behavior. You need to refactor your code so that you create an instance of Tk only once. If you need multiple windows, create instances of Toplevel.
... time passes ... the code in the question gets updated ...
In the updated version of your question you now are creating one instance of Tk, and then instances of Toplevel. This is good. However, you are also calling mainloop more than once which is a problem. Worse, you're redefining self.root which no doubt is part of the problem. You must call mainloop exactly once over the entirety of your program.
Bryan Oakley guided me to the exact problem that I was encountering:
(1) I created a second Tk object in my OtherObject class.
(2) I called mainloop in my OtherObject class.
Only one Tk object should exist and mainloop should only ever be called once, no matter how many windows are to be displayed.