I'm trying to set up a GUI feature that allows users to click a button, then be quizzed on/input new words in the categories 'nouns,' 'verbs,' 'adjectives,' etc. The program I have set up references .txt files saved in the same directory as the program.
I haven't been able to pass arguments to buttons, and the answers I've found suggest using lambda functions in some simple situations. The program works if I remove all passed arguments and simply assign a specific file (farsi_nouns, etc.) within each function. I'm not able to tell if I'm doing this incorrectly, or if Tkinter is too basic a GUI to pass arguments to functions in this way. Thanks very much for any feedback!
Tkinter ver. 8.5, Python 3.5.2, OSx High Sierra 10.13.4.
file_in_use = 'farsi_words'
def defaultFile(filename):
file_in_use = filename
return file_in_use
bN = Button(f0, text = 'Nouns', command =lambda: defaultFile('farsi_words'))
bN.pack(side='left')
bN.bind("<Button-1>",
bV = Button(f0, text = 'Verbs', command =lambda: defaultFile('farsi_verbs'))
bV.pack(side='left')
bA = Button(f0, text = 'Adjectives', command =lambda: defaultFile('farsi_adjectives'))
bA.pack(side='left')
bP = Button(f0, text = 'Prepositions', command =lambda: defaultFile('farsi_preps'))
bP.pack(side='left')
def commit(file_in_use):
word = e1.get()
definition = e2.get()
appendFile = open(file_in_use, 'a')#was this defined before def?
appendFile.write('\n' + word + ': ' + definition)
appendFile.close()
e1.delete(0, 'end')
e2.delete(0, 'end')
def review(file_in_use):
t1.delete('1.0', END)
readFile = open(file_in_use, 'r')
size = 0
splitList = []
for line in readFile:
splitWord = line.split(':')
splitWord = splitWord[0].strip('\n ')
splitList.append(splitWord)
size += 1
n = random.randint(0, size - 1)
t1.insert(INSERT, splitList[n] + '\n')
readFile.close()
def answer(file_in_use):
word = e3.get()
def1 = t1.get('1.0','end-1c')
def1 = def1.strip('\n')
readFile = open(file_in_use, 'r')
for line in readFile:
splitWord = line.split(': ')
if def1 == splitWord[0].strip('\n'):
if word == splitWord[1].strip('\n'):
t1.insert(INSERT, 'Good job!')
else:
t1.insert(INSERT, 'Not quite! Good try =)')
readFile.close()
def hint(file_in_use):
def1 = t1.get('1.0','2.0')
def1 = def1.strip('\n')
readFile = open(file_in_use, 'r')
for line in readFile:
splitWord = line.split(': ')
if def1 == splitWord[0].strip('\n'):
hint = splitWord[1]
hint1 = t1.get('2.0','end-1c')
lenHint1 = len(hint1)
if lenHint1 >= len(hint):
pass
else:
t1.insert(INSERT, hint[lenHint1])
print (hint1)
readFile.close()
You can pass arguments easily if you put your code in a class. Another thing is the tkinters function .after() you can try. I have made a simple GUI for demonstration of both.
import tkinter as tk
from tkinter import *
class GUI:
def __init__(self, master):
self.file_in_use = 'farsi_words'
self.master = master
self.bN = Button(master, text = 'Nouns', command = self.farsi_words)
self.bN.pack(side='left')
self.bN.bind("<Button-1>")
self.bV = Button(master, text = 'Verbs', command = self.farsi_verbs)
self.bV.pack(side='left')
self.bA = Button(master, text = 'Adjectives', command = self.farsi_adjectives)
self.bA.pack(side='left')
self.bP = Button(master, text = 'Prepositions', command = self.farsi_preps)
self.bP.pack(side='left')
def farsi_words(self, event=None):
self.file_in_use = 'Nouns'
self.master.after(1, self.commit)
def farsi_verbs(self, event=None):
self.file_in_use = 'Verbs'
self.master.after(1, self.commit)
def farsi_adjectives(self, event=None):
self.file_in_use = 'Adjectives'
self.master.after(1, self.commit)
def farsi_preps(self, event=None):
self.file_in_use = 'Prepositiones'
self.master.after(1, self.commit)
def commit(self, event=None):
print(self.file_in_use)
if __name__ == "__main__":
root = Tk()
my_gui = GUI(root)
root.mainloop()
Related
I have the following Notepad class and I need to insert a string to the textbox __thisLinkArea.
import tkinter
import os
from tkinter import *
from tkinter.messagebox import *
from tkinter.filedialog import *
class Notepad:
__root = Tk()
# default window width and height
__thisWidth = 300
__thisHeight = 300
__thisTextArea = Text(__root)
__thisLinkArea = Text(__root)
__thisMenuBar = Menu(__root)
__thisFileMenu = Menu(__thisMenuBar, tearoff=0)
__thisEditMenu = Menu(__thisMenuBar, tearoff=0)
__thisHelpMenu = Menu(__thisMenuBar, tearoff=0)
# To add scrollbar
__thisScrollBar = Scrollbar(__thisTextArea)
__file = None
def __init__(self,**kwargs):
# Set icon
try:
self.__root.wm_iconbitmap("Notepad.ico")
except:
pass
# Set window size (the default is 300x300)
try:
self.__thisWidth = kwargs['width']
except KeyError:
pass
try:
self.__thisHeight = kwargs['height']
except KeyError:
pass
# Set the window text
self.__root.title("Untitled - Notepad")
# Center the window
screenWidth = self.__root.winfo_screenwidth()
screenHeight = self.__root.winfo_screenheight()
# For left-align
left = (screenWidth / 2) - (self.__thisWidth /2)
# For right-align
top = (screenHeight / 2) - (self.__thisHeight /2 )
# For top and bottom
self.__root.geometry('%dx%d+%d+%d' % (self.__thisWidth,
self.__thisHeight,
left, top))
# To make the textarea auto resizable
self.__root.grid_rowconfigure(0, weight=1)
self.__root.grid_columnconfigure(0, weight=1)
# Add controls (widget)
self.__thisTextArea.grid(sticky = N + E + S + W)
self.__thisLinkArea.grid(column = 0, row = 2)
# To open new file
self.__thisFileMenu.add_command(label="New",
command=self.__newFile)
# To open a already existing file
self.__thisFileMenu.add_command(label="Open",
command=self.__openFile)
# To save current file
self.__thisFileMenu.add_command(label="Save",
command=self.__saveFile)
# To create a line in the dialog
self.__thisFileMenu.add_separator()
self.__thisFileMenu.add_command(label="Exit",
command=self.__quitApplication)
self.__thisMenuBar.add_cascade(label="File",
menu=self.__thisFileMenu)
# To give a feature of cut
self.__thisEditMenu.add_command(label="Cut",
command=self.__cut)
# to give a feature of copy
self.__thisEditMenu.add_command(label="Copy",
command=self.__copy)
# To give a feature of paste
self.__thisEditMenu.add_command(label="Paste",
command=self.__paste)
# To give a feature of editing
self.__thisMenuBar.add_cascade(label="Edit",
menu=self.__thisEditMenu)
# To create a feature of description of the notepad
self.__thisHelpMenu.add_command(label="About Notepad",
command=self.__showAbout)
self.__thisMenuBar.add_cascade(label="Help",
menu=self.__thisHelpMenu)
self.__root.config(menu=self.__thisMenuBar)
self.__thisScrollBar.pack(side=RIGHT,fill=Y)
# Scrollbar will adjust automatically according to the content
self.__thisScrollBar.config(command=self.__thisTextArea.yview)
self.__thisTextArea.config(yscrollcommand=self.__thisScrollBar.set)
def __quitApplication(self):
self.__root.destroy()
# exit()
def __showAbout(self):
showinfo("Notepad","Mrinal Verma")
def __openFile(self):
self.__file = askopenfilename(defaultextension=".txt",
filetypes=[("All Files","*.*"),
("Text Documents","*.txt")])
if self.__file == "":
# no file to open
self.__file = None
else:
# Try to open the file
# set the window title
self.__root.title(os.path.basename(self.__file) + " - Notepad")
self.__thisTextArea.delete(1.0,END)
file = open(self.__file,"r")
self.__thisTextArea.insert(1.0,file.read())
file.close()
def __newFile(self):
self.__root.title("Untitled - Notepad")
self.__file = None
self.__thisTextArea.delete(1.0,END)
def __saveFile(self):
if self.__file == None:
# Save as new file
self.__file = asksaveasfilename(initilfile='Untitled.txt',
defaultextension=".txt",
filetypes=[("All Files","*.*"),
("Text Documents","*.txt")])
if self.__file == "":
self.__file = None
else:
# Try to save the file
file = open(self.__file,"w")
file.write(self.__thisTextArea.get(1.0,END))
file.close()
# Change the window title
self.__root.title(os.path.basename(self.__file) + " - Notepad")
else:
file = open(self.__file,"w")
file.write(self.__thisTextArea.get(1.0,END))
file.close()
def __cut(self):
self.__thisTextArea.event_generate("<<Cut>>")
def __copy(self):
self.__thisTextArea.event_generate("<<Copy>>")
def __paste(self):
self.__thisTextArea.event_generate("<<Paste>>")
def append(self,a):
self.__thisLinkArea.insert('1.0',a)
def run(self):
# Run main application
self.__root.mainloop()
but it doesnt insert anything and when i quit the terminal gives the following output:
python3 ~/pp/ecoi.py
Traceback (most recent call last):
File "/home/josquin/pp/ecoi.py", line 13, in <module>
notepad.append('ciao')
File "/home/josquin/pp/editortry1.py", line 195, in append
self.__thisLinkArea.insert('1.0',a)
File "/usr/lib/python3.8/tkinter/__init__.py", line 3738, in insert
self.tk.call((self._w, 'insert', index, chars) + args)
_tkinter.TclError: invalid command name ".!text2"
In this specific case, as you can see, i'm importing Notepad and calling Notepad.append('string') from another script ecoi.py which is in the same path.
Please help me to complete this code. I want make a text editor and when I give a number in the input dialog, some text or some symbol or some numbers insert to my text lines to number in input dialog and starts with 1 to input dialog number ... Below is the code, you can know what I want to do.
Please see the code and tell me how can I do this?
from PyQt5.QtWidgets import (QWidget,QApplication,QTextEdit,
QInputDialog,QPushButton,QVBoxLayout)
import sys
class Tbx(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.vbox = QVBoxLayout()
self.btn = QPushButton('ClickMe',self)
self.btn.clicked.connect(self.dollar)
self.te = QTextEdit(self)
self.vbox.addWidget(self.te)
self.vbox.addWidget(self.btn)
self.setLayout(self.vbox)
self.setGeometry(300,300,400,250)
self.setWindowTitle('Application')
self.show()
def dollar(self):
text_1_int , ok = QInputDialog.getInt(self,'HowMany?','Enter How Many dollar do you want ?')
if not ok:
return
try:
current_lines = self.te.toPlainText().split('\n')
new_lines = list()
for dollar_counter in range(1, text_1_int + 1):
word = '$' * dollar_counter
new_lines += [text + word for text in current_lines]
self.te.setPlainText("\n".join(new_lines))
#I want this:
#...Texts in TextEditor at first:
#Hi
#User
#agent
#========================================================================
#...Text in TextEditor when I press the button and give 3 in InputDialog:
#Hi$
#Hi$$
#Hi$$$
#User$
#User$$
#User$$$
#agent$
#agent$$
#agent$$$
#Hi#
#Hi##
#Hi###
#User#
#User##
#User###
#agent#
#agent##
#agent###
#Hi#
#Hi##
#Hi###
#User#
#User##
#User###
#agent#
#agent##
#agent###
#Hi!
#Hi!!
#Hi!!!
#User!
#User!!
#User!!!
#agent!
#agent!!
#agent!!!
#Hi1
#Hi12
#Hi123
#User1
#User12
#User123
#agent1
#agent12
#agent123
#========================================================================
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Tbx()
sys.exit(app.exec_())
You are replacing the the text in your text edit at each iteration.
The easiest (clearer) way to do that, would be to generate all your lines before trying to add it to the text edit.
For example:
def dollar(self):
text_1_int , ok = QInputDialog.getInt(self,'HowMany?','Enter How Many dollar do you want ?')
if not ok:
return
try:
current_lines = self.te.toPlainText().split('\n')
new_lines = list()
for dollar_counter in range(1, text_1_int + 1):
word = '$' * dollar_counter
new_lines += [text + word for text in current_lines]
self.te.setPlainText("\n".join(new_lines))
except:
error_msg = QMessageBox()
error_msg.setIcon(QMessageBox.Critical)
error_msg.setText('Please Enter Just Number')
error_msg.setWindowTitle("Error")
error_msg.exec_()
If I enter 3 in the text input:
Btw, the dollar_counter increment is useless: it will be handled by the for loop.
In this app I'm trying to execute a popup in which an user can write a date. This popup has to occur after the user clicks a submit button I have already created. The date the user input into this popup has to be saved into a variable which will be used later on on the code. In order to do all this I tried the following:
def CreateOrderPop(self):
def popup():
#contenido = input("Contenido de Orden ")
#diaDeEntregar = input("Dia de Entrega")
self.userentryA = Entry("Dia de Entrega: ")
self.userentryA.pack()
self.userentryAbu = Button(text= "Guardar", command = self.guardarFechaOrden)
self.userentryAbu.pack()
def guardarFechaOrden(self):
global userDate
userDate = self.userentryA.get()
self.destroy()
def submit(self):
result = next(self.counter)
global orderResult
orderResult = str(result)
global contents1
contents1 = ("Nombre: {}".format(self.entry_name.get()))
global contents2
contents2 = ("Email: {}".format(self.entry_email.get()))
global contents3
contents3 = ("Num Cel/Tel: {}".format(self.entry_numtc.get()))
global contents4
contents4 = ("InformaciĆ³n Adicional: {}".format(self.entry_addinf.get(1.0, "end")))
def CreateOrder():
fecha = datetime.now()
fechaDeCreacion = fecha.strftime(" %A, %B %d, %Y" )
#diaDeEntregar = userDate
#global fechaDeEntrega
#fechaDeEntrega = fechaDeCreacion + str(diaDeEntregar)
numOrden = orderResult
return fechaDeCreacion, orderResult
completeOrden = [contents1, contents2, contents3, contents4, CreateOrder()]
completeOrdenEnum = "Orden Num:" + orderResult, completeOrden
Database.mainDatabase.append(completeOrdenEnum)
command = self.CreateOrderPop()
After running the code and clicking the submit button, everything runs normal except I don't get the popup I want.
CHANGES
I added this class to help me create what I was looking for:
class PopOrden:
def __init__(self,master):
self.master = master
top=self.top=Toplevel(master)
self.l=Label(top,text="Fecha de Entrega")
self.l.pack()
self.e=Entry(top)
self.e.pack()
self.b=Button(top,text='Ok',command=self.cleanup)
self.b.pack()
def cleanup(self):
self.value=self.e.get()
self.top.destroy()
def entryValue(self):
return self.w.value
print(self.w.value)
The previous code along with this edited code:
def submit(self):
result = next(self.counter)
print (result)
def controLoo():
if result == 1:
self.CreateOrderPop()
command = controLoo()
global orderResult
orderResult = str(result)
global contents1
contents1 = ("Nombre: {}".format(self.entry_name.get()))
global contents2
contents2 = ("Email: {}".format(self.entry_email.get()))
global contents3
contents3 = ("Num Cel/Tel: {}".format(self.entry_numtc.get()))
global contents4
contents4 = ("InformaciĆ³n Adicional: {}".format(self.entry_addinf.get(1.0, "end")))
def CreateOrder():
fecha = datetime.now()
fechaDeCreacion = fecha.strftime(" %A, %B %d, %Y" )
#diaDeEntregar = PopOrden
#global fechaDeEntrega
#fechaDeEntrega = fechaDeCreacion + str(diaDeEntregar)
numOrden = orderResult
return fechaDeCreacion, orderResult
completeOrden = [contents1, contents2, contents3, contents4, CreateOrder()]
completeOrdenEnum = "Orden Num:" + orderResult, completeOrden
Database.mainDatabase.append(completeOrdenEnum)
command = self.database_window()
self.clear()
messagebox.showinfo(title = "Orden #"+ orderResult, message = "Orden Guardada")
However, I'm NOW having issues with a blank tk popu that's also generated with the popup I want.
I am not sure what you mean by everything runs normal, because your code seems to have some major formatting issues (indentation to say the least). However, 'pop-ups' are usually achieved with Toplevel() widgets. See this useful resource. It is a great resource for all things tkinter in my opinion.
Also, you might find the answer to this question helpful.
Why dont you use a message box directly
from tkinter import *
import tkMessageBox
root = Tk()
def popUp():
result = tkinter.messageBox.popUp("Quiz","Are you ready? ")
# result wil be yes or no
if result == 'yes':
#do something
else:
# do something
submitButton = Button(root,text= "Submit")
submitButton.bind("<Button-1",popup)
# onleft click on submit popup method gets called
submitButton.pack()
I keep on getting an attribute error when trying to changing the text attribute of a tk label.
I declare it and it uses a temp image so it does exist but when I attempt to change it I get the error. If someone knows a better way to change the image or display it in a better method I would greatly like to here.
Here is the relevent code
self.threadLabelImage = tk.Label(self.threadFrame,image=self.threadImage,wraplength=400,padx=20,pady=5).grid(row=7,column=10,sticky = tk.EW)
self.threadFrame.grid(row=0,column=10,sticky=tk.EW,rowspan=8)
self.threadFrame.grid_propagate(0)
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=main.destroy,padx=5, pady=5).grid(row=7)
def updateSelected(self, event):
# getting selected listbox item
i=self.thread_lb.curselection()
# Returns tuple that must be split
x,self.y,z = re.split("\D+",str(i))
self.y=int(self.y)
print(self.threadTitleList[self.y])
print(self.threadPubDateList[self.y])
print(self.threadLinkList[self.y])
print(self.threadDescList[self.y])
self.threadTitle.set(self.threadTitleList[self.y])
self.threadAuth.set(self.threadAuthList[self.y])
self.threadPub.set(self.threadPubDateList[self.y])
self.threadArtLink.set(self.threadLinkList[self.y])
self.threadLink.set(self.threadDescList[self.y])
self.threadImg.set('Will put image here')
if self.threadLinkList[self.y].find('imgur') != -1:
url = self.threadLinkList[self.y]+'.GIF'
imageName=self.threadLinkList[self.y][-11:-4]
urllib.request.urlretrieve(self.threadLinkList[self.y],imageName+'.jpg')
imgfile = Image.open(imageName+'.jpg')
imgfile = imgfile.resize((150,150),Image.ANTIALIAS)
# img = Image.open(file)
self.threadImage = ImageTk.PhotoImage(imgfile)
self.threadLabelImage.config(text = self.threadImage)
self.threadImage.image = imgfile
And here is the entire program so you can run it if need be.import xml.etree.ElementTree as ET
import webbrowser,time,urllib.request,re
import tkinter as tk
import urllib
from PIL import Image,ImageTk
main = tk.Tk()
class Application(tk.Frame):
def __init__(self, master=None):
self.threadTitle = tk.StringVar()
self.threadAuth = tk.StringVar()
self.threadPub = tk.StringVar()
self.threadArtLink = tk.StringVar()
self.threadLink = tk.StringVar()
self.threadImg = tk.StringVar()
self.threadArtLink.set('Click something to display thread info')
photo = Image.open("temp.png")
photo = photo.resize((150,150), Image.ANTIALIAS)
self.threadImage = ImageTk.PhotoImage(photo)
# Intializes tkinter gui framework
tk.Frame.__init__(self, master)
# Packs widgets needed
self.grid()
# Creates the widgets functions
self.createWidgets()
# Intializes the man rss.xml
self.initial()
# self.threadLabelArtLink = None
# self.threadLabelTitle = None
# self.threadLabelThreadLink = None
# self.threadLabelArtLink = None
# self.threadImgLink = None
def createWidgets(self):
# Create entrybox and align to grid
self.send_entry = tk.Entry(self)
self.send_entry.grid(row=0,column=0)
# Create button,allign to grid, get xml
self.change_sub = tk.Button(self,text='Change Subreddit',padx=5, pady=5, command=lambda :self.getXML(self.send_entry.get())).grid(row=0 , column=3)
# Create scrollbar on Y-Axis
self.lb_scrollY = tk.Scrollbar(self,orient=tk.VERTICAL)
# On grid next to Listbox(sticky means fill whole row
self.lb_scrollY.grid(row=1,column=4,sticky=tk.NS,rowspan=6)
# Create Listbox and get Y from scrollbar
self.thread_lb = tk.Listbox(self,yscrollcommand=self.lb_scrollY.set,height=20)
# Calls function whenever a new item is selected
self.thread_lb.bind('<<ListboxSelect>>',self.updateSelected)
self.thread_lb.bind('<Double-Button-1>',self.openPage)
# scrolly will change the view of listbox
self.lb_scrollY['command']=self.thread_lb.yview
self.thread_lb.grid(row=1,column=0,sticky=tk.NS+tk.EW,columnspan=4)
self.threadFrame = tk.LabelFrame(main,text='Reddit',width=450,height=350,labelanchor='n')
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=400,padx=20, pady=5).grid(row=1,column=10,sticky= tk.EW)
self.threadLabelAuth = tk.Label(self.threadFrame, textvariable=self.threadAuth,wraplength=400,padx=20, pady=5).grid(row=2,column=10,sticky = tk.EW)
self.threadLabelPub = tk.Label(self.threadFrame, textvariable=self.threadPub,wraplength=400,padx=20, pady=5).grid(row=3,column=10,sticky = tk.EW)
self.threadLabelArtLink = tk.Label(self.threadFrame, textvariable=self.threadArtLink,wraplength=400,padx=20, pady=5).grid(row=4,column=10,sticky = tk.EW)
self.threadLabelThreadLink = tk.Label(self.threadFrame, textvariable=self.threadLink,wraplength=400,padx=20, pady=5).grid(row=5,column=10,sticky = tk.EW)
self.threadImgLink = tk.Label(self.threadFrame, textvariable=self.threadImg,wraplength=400,padx=20, pady=5).grid(row=6,column=10,sticky = tk.EW)
self.threadLabelImage = tk.Label(self.threadFrame,image=self.threadImage,wraplength=400,padx=20,pady=5).grid(row=7,column=10,sticky = tk.EW)
self.threadFrame.grid(row=0,column=10,sticky=tk.EW,rowspan=8)
self.threadFrame.grid_propagate(0)
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=main.destroy,padx=5, pady=5).grid(row=7)
def updateSelected(self, event):
# getting selected listbox item
i=self.thread_lb.curselection()
# Returns tuple that must be split
x,self.y,z = re.split("\D+",str(i))
self.y=int(self.y)
print(self.threadTitleList[self.y])
print(self.threadPubDateList[self.y])
print(self.threadLinkList[self.y])
print(self.threadDescList[self.y])
self.threadTitle.set(self.threadTitleList[self.y])
self.threadAuth.set(self.threadAuthList[self.y])
self.threadPub.set(self.threadPubDateList[self.y])
self.threadArtLink.set(self.threadLinkList[self.y])
self.threadLink.set(self.threadDescList[self.y])
self.threadImg.set('Will put image here')
if self.threadLinkList[self.y].find('imgur') != -1:
url = self.threadLinkList[self.y]+'.GIF'
imageName=self.threadLinkList[self.y][-11:-4]
urllib.request.urlretrieve(self.threadLinkList[self.y],imageName+'.jpg')
imgfile = Image.open(imageName+'.jpg')
imgfile = imgfile.resize((150,150),Image.ANTIALIAS)
# img = Image.open(file)
self.threadImage = ImageTk.PhotoImage(imgfile)
self.threadLabelImage.config(text = self.threadImage)
self.threadImage.image = imgfile
# # threadTitle = self.threadTitleList[y]
# print(self.threadLabelTitle["text"])
# # self.threadLabelTitle['text']=threadTitle
# self.threadLabelAutPub['text']=self.threadPubDateList[y]
# self.threadImgLink['text']=self.threadLinkList[y]
# self.threadLabelThreadLink['text']=self.threadDescList[y]
# main.update()
def openPage(self,event):
webbrowser.get('windows-default').open_new(self.threadLinkList[self.y])
def descStripper(self,desc):
# Intialize values
l1,l2,l2Start = 0,0,0
t1,t2,t2start = 0,0,0
link = ""
thread = ""
# Where to start looking for each in description element
l1=int(desc.find('<br/> <a href="'))
t1=int(desc.find('</a> <a href="'))
a1=int(desc.find('"> '))
# If both of the tags are found then continue
if l1 != -1 and t1 != -1 and a1 != 1:
# Start looking for end of quotes 16 characters from beginning of tag
l2Start = l1+16
l2=int(desc.find('"',l2Start))
# Link is created from what is in the quotes
link = desc[l1+15:l2]
# Same as above but to find thread link
t2start = t1+15
t2=int(desc.find('"',t2start))
thread = desc[t1+14:t2]
a2start = a1+4
a2 = int(desc.find(' <',a2start))
author = desc[a1+3:a2]
return link,thread,author
else:
# If it can't find one it will return an error
link = "Couldn't find the stuff :("
thread = "Couldn't find the thread link :("
return link, thread
def lbPopulator(self,title,pub,link):
# Delete old entries from listbox
self.thread_lb.delete(0,tk.END)
# Iterate through all the items and append them to the listbox
for item in title:
self.thread_lb.insert(tk.END,item)
def getXmlData(self):
# Intialize lists
self.threadPubDateList = []
self.threadTitleList = []
self.threadLinkList = []
self.threadDescList = []
self.threadThumbNailList = []
self.threadAuthList = []
# Use the downloaded rss.xml for XML parsing
tree=ET.parse('rss.xml')
# define root as the base of the XML parsing tree
root=tree.getroot()
for channel in root:
# Iterate through all the channels
for SubChannel in channel:
# Iterate through all the items in the channel
if SubChannel.tag == 'item':
# If the SubChannel is called item then search for the items below
for threadInfo in SubChannel:
# iterate through all the items in the 'item'
if threadInfo.tag == 'title':
# append the tag from the title to the list
self.threadTitleList.append(threadInfo.text)
if threadInfo.tag == 'pubDate':
# Append the pubdate info to the list but remove excess characters
self.threadPubDateList.append(threadInfo.text[:-6])
if threadInfo.tag == 'description':
# Pass all the information from the description to the stripper to get the useful
# information and links
link,thread,author = self.descStripper(threadInfo.text)
self.threadLinkList.append(link)
self.threadDescList.append(thread)
self.threadAuthList.append(author)
# if threadInfo.tag == ''
# Populate the listbox with the newly generated lists
self.lbPopulator(self.threadTitleList,self.threadPubDateList,self.threadLinkList)
def getXML(self,subreddit):
try:
# Try to download the xml file using the user input subreddit
url = 'http://www.reddit.com'+subreddit+'.rss'
source = urllib.request.urlretrieve(url,'rss.xml')
self.getXmlData()
except urllib.error.HTTPError as err:
# Error caused by reddit API limiting connections
print('Too many requests-Try again')
def initial(self):
try:
# Same as above but downloads the front page
source = urllib.request.urlretrieve('http://www.reddit.com/.rss','rss.xml')
self.getXmlData()
except urllib.error.HTTPError as err:
print('Too many requests-Trying again 3')
# If error occurs program waits 3 seconds and then restarts
time.sleep(3)
self.__init__()
# main.geometry("350x400")
app = Application(master=main)
# Begins the applications GUI loop
app.mainloop()
The grid method of a Tkinter widget always returns None. So, any calls to it must be placed on their own line.
Meaning, all of the lines that are written like this:
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=400,padx=20, pady=5).grid(row=1,column=10,sticky= tk.EW)
need to be rewritten like this:
self.threadLabelTitle = tk.Label(self.threadFrame,textvariable=self.threadTitle,wraplength=400,padx=20, pady=5)
self.threadLabelTitle.grid(row=1,column=10,sticky= tk.EW)
I am using Tkinter to help me build a FTP client, in this client I am trying to get the selected information from a tk listbox. So I have a button that starts the download but what ever the reason is it pops up with the error "
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk/Tkinter.py", line 1410, in __call__
return self.func(*args)
File "/Volumes/LEGO FLASH/ftp.py", line 23, in Download
filename = stuff
NameError: global name 'stuff' is not defined"
Below I have the code for you to look at:
# Import the FTP object from ftplib
from ftplib import FTP
from Tkinter import *
import os
app = Tk()
app.title("FTP")
app.geometry("300x300")
lines = []
#[lines.replace(",", "\n")for lines in lines]
#lines = lines.replace(',','\n')
def handleDownload(block):
file.write(block)
print ".",
def append_line(line):
lines.append(line)
#This is where I am caught------->
def Download():
filename = stuff
file = open(filename, 'wb')
ftp.retrbinary('RETR ' + filename, handleDownload)
ftp.close()
def login():
try:
ftp.login(username.get(),password.get())
except:
error = Label(app, text = "Invalid USERNAME OR PASSWORD")
label2 = Label(app, text = "Welcome to Steam Engine").pack()
username.forget()
password.forget()
button.forget()
app.geometry("800x500")
download = Button(app, text = "Download!!!!!", command = Download)
download.pack(side = "left", pady = "5")
scrollBar.pack(fill = Y, side = "right", padx = "2")
#ftp.cwd('The_Store')
stuff = Listbox(app, height = "700", width = "500")
ftp.retrlines('NLST', append_line)
for i in lines:
stuff.insert(END, i)
stuff.pack(padx = "10", pady = "10")
stuff.config(yscrollcommand = scrollBar.set)
scrollBar.config(command = stuff.yview)
ftp = FTP('sciphigames.com')
label = Label(app, text = "Login").pack(pady = "10")
scrollBar = Scrollbar(app)
username = StringVar(None)
username = Entry(app, text = "Username: ")
username.pack(pady = "2")
password = StringVar(None)
password = Entry(app, text = "Password: ")
password.pack(pady = "2")
button = Button(app, text = "Login!", command = login)
button.pack(pady = "10")
app.mainloop()
Any help would be appreciated!
Thanks!
#This is where I am caught------->
def Download():
filename = stuff
what is stuff here ?? it is not a global variable, it seems to be a parameter of login, but not of Download method.
If you want to do stuff a global variable (probably not the better choice), use the global statement.
# Import the FTP object from ftplib
from ftplib import FTP
from Tkinter import *
import os
# define the global stuff
global stuff
...
def Download():
global stuff
filename = stuff
...
A better way to handle this would be to create an object around all of this ::
class NetworkApp(object):
def login(self):
# here put all the previous code of login
# here we change the callback to self.Download
download = Button(app, text = "Download!!!!!", command = self.Download)
# here we're creating a stuff member
self.stuff = Listbox(app, height = "700", width = "500")
def Download(self):
filename = self.stuff # here we use the stuff member
file = open(filename, 'wb')
ftp.retrbinary('RETR ' + filename, handleDownload)
ftp.close()
#...
net_app = NetworkApp()
button = Button(app, text = "Login!", command = net_app.login)
I am not entirely sure what the purpose is with your stuff variable, but the problems you are experiencing probably stem from the way you are using it.
First, you are using it as argument to login (which, by the way should take no arguments). You assign to this variable from the login function, and refer to another variable with the same name in your Download function.
Again, not being sure what I understand what you want to do with the stuff variable, I would try something like
.....
app.geometry("300x300")
stuff = None # <<<<----
lines = []
.....
#This is where I am caught------->
def Download():
global stuff # <<<<----
filename = stuff
......
ftp.close()
def login():
global stuff # <<<<----
......
stuff = Listbox(app, height = "700", width = "500")
ftp.retrlines('NLST', append_line)
for i in lines:
stuff.insert(END, i)
stuff.pack(padx = "10", pady = "10")
stuff.config(yscrollcommand = scrollBar.set)
scrollBar.config(command = stuff.yview)
......
All you need to do is put "global" in front of the variable
global var1