I'm trying to write my fisrt script in python & tkinter.
I block to display a new frame from a function (def onDisplay) when a click is made from menu bar button, but nothing append.
No error is display :-(
The new frame is made with dynamic checkboxes from text files:
txt file:
item1
item2
...
item100
A screen of the GUI:
Here my code:
from tkinter import Tk, Frame, Menu, Checkbutton, Text, TOP, BOTH, X, N, LEFT, BooleanVar
from tkinter.ttk import Frame, Label, Entry
import glob
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
#self.display_srv()
def initUI(self):
self.master.title("Submenu")
menubar = Menu(self.master)
self.master.config(menu=menubar)
fileMenu = Menu(menubar)
submenu = Menu(fileMenu)
submenu.add_command(label="lst1", command=self.onDisplay)
submenu.add_command(label="lst2")
submenu.add_command(label="lst3")
fileMenu.add_cascade(label='Listing', menu=submenu, underline=0)
fileMenu.add_separator()
fileMenu.add_command(label="Exit", underline=0, command=self.onExit)
menubar.add_cascade(label="File", underline=0, menu=fileMenu)
#The frame i tried to display
def onDisplay(self):
self.master.title("display it")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack(fill=X)
path = '/root/liste/*.txt'
files=glob.glob(path)
count = 0
for file in files:
with open(file, 'r') as lst_file:
for item in lst_file:
# Need to split all item by 10
Checkbutton(self, text=item.rstrip()).grid(row=count//10, column=count%10)
count += 1
def onClick(self):
if self.var.get() == True:
self.master.title("Checkbutton")
else:
self.master.title("")
def onExit(self):
self.quit()
def main():
root = Tk()
root.geometry("850x550+300+300")
app = Example()
root.mainloop()
if __name__ == '__main__':
Many thanks for any help
Regards,
The main problem is that you're mixing grid and pack in the same parent container. You are calling pack on frame1 but you are calling grid on the checkbuttons, and they both have a master or parent of self.
That can't work, because each of grid and pack will try to resize the container according to it's rules, triggering the other one to reconfigure according to it's rules, and so on until the end of time.
So, simply changing your call of .grid(...) to .pack(...) on the checkbuttons will fix that problem.
My guess is that you intended to put the checkbuttons inside frame1. If that's the case, you need to specify frame1 as the master for the checkbuttons. For readability and ease of debugging I also recommend placing the call to grid on a separate line. With that, you can continue to use grid for the checkbuttons and pack for everything else.
cb = Checkbutton(frame1, text=item.rstrip())
cb.grid(row=count//10, column=count%10)
I posted the correct code:
from tkinter import Tk, Frame, Menu, Checkbutton, Text, TOP, BOTH, X, N, LEFT, BooleanVar
from tkinter.ttk import Frame, Label, Entry
import glob
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
#self.display_srv()
def initUI(self):
self.master.title("Submenu")
menubar = Menu(self.master)
self.master.config(menu=menubar)
fileMenu = Menu(menubar)
submenu = Menu(fileMenu)
submenu.add_command(label="lst1", command=self.onDisplay)
submenu.add_command(label="lst2")
submenu.add_command(label="lst3")
fileMenu.add_cascade(label='Listing', menu=submenu, underline=0)
fileMenu.add_separator()
fileMenu.add_command(label="Exit", underline=0, command=self.onExit)
menubar.add_cascade(label="File", underline=0, menu=fileMenu)
def onDisplay(self):
self.master.title("display it")
self.pack(fill=BOTH, expand=True)
frame1 = Frame(self)
frame1.pack(fill=X)
path = '/root/liste/*.txt'
files=glob.glob(path)
count = 0
for file in files:
with open(file, 'r') as lst_file:
for item in lst_file:
cb = Checkbutton(frame1, text=item.rstrip())
cb.grid(row=count//10, column=count%10)
count += 1
def onClick(self):
if self.var.get() == True:
self.master.title("Checkbutton")
else:
self.master.title("")
def onExit(self):
self.quit()
def main():
root = Tk()
root.geometry("850x550+300+300")
app = Example()
root.mainloop()
if __name__ == '__main__':
main()
Related
I have created a menu bar and a textbox, in the textbox I like to show the info in the variable that belongs to the chooice that been made in the menu.
But I can not figure out how.
Heres what I managed to put together by different guides on the web. Im verry new to python and Im still struggeling with the concept on objects and classes so any help at all will be greatly appriciated.
from tkinter import Tk, Frame, Menu
from tkinter import *
class Example(Frame):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.master.title("syntax explenation for shopfloor")
menubar = Menu(self.master)
self.master.config(menu=menubar)
syntaxMenu = Menu(menubar, tearoff=False)
submenu = Menu(syntaxMenu)
syntaxMenu.add_cascade(label='Math', menu=submenu, underline=0)
submenu.add_command(label="abs()", command=self.onSyntaxabs)
submenu.add_command(label="cos()", command=self.onSyntaxcos)
submenu.add_command(label="sin()", command=self.onSyntaxsin)
submenu.add_cascade(label="log()", command=self.onSyntaxlog)
submenu = Menu(syntaxMenu)
syntaxMenu.add_cascade(label='Inqurie', menu=submenu, underline=0)
submenu.add_command(label="inqiureText()", command=self.onSyntaxinquire)
menubar.add_cascade(label="Syntax", underline=0, menu=syntaxMenu)
def onSyntaxabs():
info="Convert to absolute value, abs(-10) will respond with 10."
def onSyntaxcos():
info="Returns cosinus value in decimal degrees"
def onSyntaxcos():
info="Returns cosinus value in decimal degrees"
def onSyntaxlog():
info="Returns the natural logarithm"
def onSyntaxinquire():
info="Creates a pop-up box that you can enter text in."
def main():
root = Tk()
root.geometry("500x600")
app = Example()
S = Scrollbar(root)
T = Text(root, height=20, width=60, bg="lightblue")
S.pack(side=RIGHT, fill=Y)
T.pack(side=LEFT, fill=BOTH)
T.pack(side=RIGHT, fill=BOTH)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
info=?
T.insert(END, info)
mainloop( )
if __name__ == '__main__':
main()
Here's a little push forward:
from tkinter import Tk, Frame, Menu, Scrollbar, Text
from tkinter import RIGHT, LEFT, BOTH, END, Y
from tkinter import StringVar
class Example(Frame):
def __init__(self, master):
super().__init__(master)
self.pack(fill=BOTH, expand=True)
self.initUI()
def initUI(self):
self.master.title("syntax explenation for shopfloor")
menubar = Menu(self.master)
self.master.config(menu=menubar)
syntaxMenu = Menu(menubar, tearoff=False)
submenu = Menu(syntaxMenu)
syntaxMenu.add_cascade(label='Math', menu=submenu, underline=0)
submenu.add_command(label="abs()", command=self.onSyntaxabs)
submenu.add_command(label="cos()", command=self.onSyntaxcos)
submenu.add_command(label="sin()", command=self.onSyntaxsin)
submenu.add_cascade(label="log()", command=self.onSyntaxlog)
submenu = Menu(syntaxMenu)
syntaxMenu.add_cascade(label='Inqurie', menu=submenu, underline=0)
submenu.add_command(label="inqiureText()", command=self.onSyntaxinquire)
menubar.add_cascade(label="Syntax", underline=0, menu=syntaxMenu)
S = Scrollbar(self) # Should probably be an instance member as well
self.text = Text(self, height=20, width=60, bg="lightblue")
S.pack(side=RIGHT, fill=Y)
self.text.pack(side=LEFT, fill=BOTH)
self.text.pack(side=RIGHT, fill=BOTH)
S.config(command=self.text.yview)
self.text.config(yscrollcommand=S.set)
self.setText("?")
def setText(self, text):
self.text.delete(1.0,END)
self.text.insert(END, text)
def onSyntaxabs(self):
self.setText("Convert to absolute value, abs(-10) will respond with 10.")
def onSyntaxsin(self):
self.setText("Returns sinus value in decimal degrees")
def onSyntaxcos(self):
self.setText("Returns cosinus value in decimal degrees")
def onSyntaxlog(self):
self.setText("Returns the natural logarithm")
def onSyntaxinquire(self):
self.setText("Creates a pop-up box that you can enter text in.")
def main():
root = Tk()
root.geometry("500x600")
app = Example(master=root)
app.mainloop()
if __name__ == '__main__':
main()
In general, I'd try to avoid importing all those symbols and just do something like
import tkinter as tk
then where you write Frame or RIGHT you'd use tk.Frame or tk.RIGHT.
Also, I moved all your widget creation inside of the class. So now your Text widget is a class member (self.text) and can be accessed and controlled easily from within the class -- all of your onSyntax___ methods call setText (another class method) which sets the Text widget's contents.
Hope it helps.
Thank you all for your input.
And I'll will continue to work with your post jedward.
I'll look in to Eclipse and Py Charm since I really need something like that.
I'm trying to create a login with a tkinter Entry.
Compare the input with the password and if it is correct you are supposed to get access to more stuff in the menu bar.
If I understand correctly I need to update the window in order for the menu to update, but I cant figure out how.
And the variable "moberg" don't seems to update to True. Might be that one is global(?) and the other one belongs to a class. But I cant figure out how to make that work either.
Here is a sample of what I've done so far.
from tkinter import *
moberg="no"
class PCMsyntax(Frame):
def update():
print("updated") #only for visual, remove later
app.mainloop.after(1, update)
def __init__(self, master):
super().__init__(master)
self.pack(fill=BOTH, expand=True)
self.initUI()
def initUI(self):
menubar = Menu(self.master)
self.master.config(menu=menubar)
syntaxMenu = Menu(menubar, tearoff=False)
submenu = Menu(syntaxMenu)
syntaxMenu.add_cascade(label='Arithmetic Exp', underline=0, command='')
syntaxMenu.add_cascade(label='Assign & Compare', underline=0, command='')
syntaxMenu.add_separator()
syntaxMenu.add_cascade(label='Math', menu=submenu, underline=0)
submenu.add_command(label="abs()", command='')
if moberg == True:
syntaxMenu.add_cascade(label='No public access', menu=submenu, underline=0)
submenu.add_command(label="onlyForLabTech()")
menubar.add_cascade(label="Syntax", underline=0, menu=syntaxMenu)
menubar.add_cascade(label="Login", underline=0, command=self.onLogin)
def onLogin(self):
self.newWindow = Toplevel(self.master)
self.app = Password(self.newWindow)
class Password():
def __init__(self, master):
self.master = master
self.frame = Frame(self.master)
self.pwd = Entry(self.master, width=30, bg="whitesmoke", foreground="whitesmoke")
self.pwd.pack()
self.verifyButton = Button(self.frame, text = 'Verify', width = 25, command = self.verify_password)
self.verifyButton.pack()
self.frame.pack()
def verify_password(self):
user_entry = self.pwd.get()
if str(user_entry) == "test":
moberg=True
print(moberg) #only for visual, remove later
PCMsyntax.update
self.master.destroy()
else:
moberg=False
print(moberg) #only for visual, remove later
self.master.destroy()
def main():
root = Tk()
root.geometry("560x600")
app = PCMsyntax(master=root)
app.mainloop()
if __name__ == '__main__':
main()
You could achieve something like what you're looking for with the below:
from tkinter import *
class App:
def __init__(self, root):
self.root = root
self.public = Frame(self.root, borderwidth=1, relief="solid") #public, visible frame
self.hidden = Frame(self.root, borderwidth=1, relief="solid") #hidden, private frame
self.label1 = Label(self.public, text="This text and everything over here is public.") #this is inside the public frame and so is visible
self.entry1 = Entry(self.public) #so is this
self.label2 = Label(self.hidden, text="This text and everything over here is hidden and only appears after login.") #this one is in the hidden frame and so is private before login
self.button1 = Button(self.public, text="Login", command=self.command) #this is in the public frame
self.public.pack(side="left", expand=True, fill="both") #we pack the public frame on the left of the window
self.label1.pack() #then we pack all the widgets for both frames here and below
self.entry1.pack()
self.label2.pack()
self.button1.pack()
def command(self): #whenever the login button is pressed this is called
if self.button1.cget("text") == "Login" and self.entry1.get() == "password": #we check if the button is in login state or not and if the password is correct
self.hidden.pack(side="right", expand=True, fill="both") #if it is we pack the hidden frame which makes it and it's contents visible
self.button1.configure({"text": "Logout"}) #we then set the button to a logout state
elif self.button1.cget("text") == "Logout": #if the button is in logout state
self.hidden.pack_forget() #we pack_forget the frame, which removes it and it's contents from view
self.button1.configure({"text": "Login"}) #and then we set the button to login state
root = Tk()
App(root)
root.mainloop()
This is fairly self explanatory and where it isn't I've explained what's happening.
This is just one way of many of achieving what it is you're looking for.
I'd also like to point out that login systems are complicated and if you're looking to use this for anything serious or as a package to sell then the way I have done this is not secure.
I'd recommend looking at other ways people handle sensitive information in tkinter.
So I have started a minor text editor project in python 3 and I have managed to add a save button with a function to save the document, but I want to add the options of choosing between .txt, .png and other for the save command. How could I do that?
from tkinter import * # Imports everything from tkinter
import tkinter
from tkinter import filedialog
class Window(Frame): # Frame is a class in tkineter and we are creating a
frame or a window
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master #Mainframe or main window
self.init_window()
def init_window(self): #
self.master.title("GUI") #windows title is GUI
self.pack(fill=BOTH, expand=1) # Adjust window as we want, but also
fill up the window as a defult
menu =Menu(self.master)
self.master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Open File')
file.add_command(label='New File')
file.add_command(label='Save as')
file.add_command(label='Save', command=self.file_save)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='Undo')
edit.add_command(label='Redo')
menu.add_cascade(label='Edit', menu=edit)
def file_save(self):
f = filedialog.asksaveasfile(mode='w', defaultextension=".txt")
if f is None:
return
text2save = str(text.get(1.0, END))
f.write(text2save)
f.close()
def client_exit(self):
exit()
root = Tk() #
root.geometry("400x300") #Specify the dimention of the window as 400 by
300
app = Window(root)
root.mainloop() # Generates our window for us
If you look at the documentation for asksaveasfile you can see there's a filetypes parameter. Simply fill that with a list of the file types you want.
filetypes_choices = [('Text file', '*.txt'), ('PNG Image File', '*.png')]
f = filedialog.asksaveasfile(mode='w', defaultextension=".txt", filetypes=filetypes_choices)
This is my Copy&Paste program:
from tkinter import *
import Pmw
class CopyTextWindow(Frame):
def __init__(self):
Frame.__init__(self)
Pmw.initialise()
self.pack(expand=YES, fill=BOTH)
self.master.title("ScrolledText Demo")
self.frame1=Frame(self, bg="White")
self.frame1.pack(expand=YES, fill=BOTH)
self.text1=Pmw.ScrolledText(self, text_width=25, text_height=12, text_wrap=WORD,
hscrollmode="static", vscrollmode="static")
self.text1.pack(side=LEFT, expand=YES, fill=BOTH, padx=5, pady=5)
options = ["Copy", "Paste"]
self.selectedOption = StringVar()
self.menu = Menu(self.frame1, tearoff=0)
for option in options:
self.menu.add_radiobutton( label=option, variable=self.selectedOption,
command=self.ExecuteOption)
self.text1.bind("<Button-3>", self.popUpMenu)
def popUpMenu(self, event):
self.menu.post(event.x_root, event.y_root)
def ExecuteOption(self):
if self.selectedOption.get()=="Copy":
self.CopiedText=self.text1.get(SEL_FIRST, SEL_LAST)
else:
self.text1.settext( self.text1.get()+self.CopiedText)
def main():
CopyTextWindow().mainloop()
if __name__=="__main__":
main()
In this program, I want to make a GUI, that in it you can copy and paste text that you have selected. when you press the right mouse button, a little menu with the Copy and Paste options.
The program opens up, but when I press the right mouse button, no menu appears. Python also doesn't complain with an error.
I need to understand my mistake in this code.
For a reason I ignore, the event doesn't seem to be triggered when the bind is on the Text or on the Frame, but it works when it's on the main window:
from tkinter import *
import Pmw
class CopyTextWindow(Frame):
def __init__(self, master=None):
# I've added a master option to pass to the frame
Frame.__init__(self, master)
Pmw.initialise()
self.pack(expand=YES, fill=BOTH)
self.master.title("ScrolledText Demo")
self.frame1=Frame(self, bg="White")
self.frame1.pack(expand=YES, fill=BOTH)
self.text1=Pmw.ScrolledText(self, text_width=25, text_height=12, text_wrap=WORD,
hscrollmode="static", vscrollmode="static")
self.text1.pack(side=LEFT, expand=YES, fill=BOTH, padx=5, pady=5)
options = ["Copy", "Paste"]
self.selectedOption = StringVar()
self.menu = Menu(self.frame1, tearoff=0)
for option in options:
self.menu.add_radiobutton( label=option, variable=self.selectedOption,
command=self.ExecuteOption)
def popUpMenu(self, event):
print("ok")
self.menu.post(event.x_root, event.y_root)
def ExecuteOption(self):
if self.selectedOption.get()=="Copy":
self.CopiedText=self.text1.get(SEL_FIRST, SEL_LAST)
else:
self.text1.settext( self.text1.get()+self.CopiedText)
def main():
# main window
root = Tk()
ctw = CopyTextWindow(root)
# bind on the main window
root.bind("<Button-3>", ctw.popUpMenu)
root.mainloop()
if __name__=="__main__":
main()
I'm trying to create a fairly simple e-reader, and I've managed to use tkinter to create something akin to one. But what I can't seem to work out is how to create a scrollbar to allow the user to scroll through the text at will. I can get it working in other pieces of coding, but I can't make it work within this program and I can't work out what the problem is. I've put my simple e-reader, without the attempted scrollbar below.
from Tkinter import *
import tkFileDialog
import ScrolledText
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("File dialog")
self.pack(fill=BOTH, expand=1)
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="Open", command=self.onOpen)
menubar.add_cascade(label="File", menu=fileMenu)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
def onOpen(self):
ftypes = [('Python files', '*.py'), ('All files', '*')]
dlg = tkFileDialog.Open(self, filetypes = ftypes)
fl = dlg.show()
if fl != '':
text = self.readFile(fl)
self.txt.insert(END, text)
def readFile(self, filename):
f = open(filename, "r")
text = f.read()
return text
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
def main():
root = Tk()
ex = Example(root)
root.geometry("300x250+300+300")
root.mainloop()
if __name__ == '__main__':
main()
Adding a scrollbar to a text widget requires you to do two things in addition to creating the actual widgets:
you must set the yscrollcommand attribute of the text widget to point to the set method of the scrollbar
you must set the command attribute of the scrollbar to point to the yview method of the text widget
For example:
self.text.configure(yscrollcommand=self.scrollbar.set)
self.scrollbar.configure(command=self.text.yview)
I've long wondered whether this could really be the answer to your question, but after the discussion in the comments, it seems it is: You just put the code creating the ScrolledText in the wrong place!
Try moving these three lines (that are now outside of the class, causing a NameError for self)
self.txt = ScrolledText(self, undo=True)
self.txt['font'] = ('consolas', '12')
self.txt.pack(expand=True, fill='both')
to where these lines are in your initUI method (replace these lines)
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
With other words, in your initUI method, instead of creating a Text widget, create a ScrolledText. Also, change import ScrolledText to from ScrolledText import ScrolledText so that ScrolledText is the actual widget, and not the module defining the widget.