import sys
import time
import tkinter
from tkinter import *
import tkinter.messagebox as tm
from tkinter.filedialog import *
from sys import exit
class AppUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master, relief=SUNKEN, bd=2)
self.menubar = Menu(self)
filemenu = Menu(self.menubar, tearoff=0)
filemenu.add_command(label="New", command=self.NewFile)
filemenu.add_command(label="New", command=self.OpenFile)
self.menubar.add_cascade(label="File", menu=filemenu)
menu = Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Edit", menu=menu)
menu.add_command(label="Cut")
menu.add_command(label="Copy")
menu.add_command(label="Paste")
def OpenFile():
name = askopenfilename
askopenfilename()
def NewFile():
tm.showerror("ERROR", "Cannot Open New File!")
try:
self.master.config(menu=self.menubar)
except AttributeError:
self.master.tk.call(master, "config", "-menu", self.menubar)
self.canvas = Canvas(self, bg="white", width=400, height=400,
bd=0, highlightthickness=0)
self.canvas.pack()
root = Tk()
app = AppUI(root)
app.pack()
root.mainloop()
I can't seem to work this .py file, I am new-ish to coding with python, I have asked and looked about, but I can't seem to find the answer. I have tried to make a class with a menu in it, but the error seems to always say "self is not defined"
Thanks
You see nothing because your frame has a default size of 0x0 since there is nothing inside.
Frame.__init__(self, master, relief=SUNKEN, bd=2, width=200, height=200)
should make it visible. Furthermore, I advise you to make your AppUI class inherit from Tk or Toplevel instead of Frame so that you can directly use self.configure(menu=self.menubar) to display the menu.
Also, def OpenFile(): should be replaced by def OpenFile(self): otherwise you will get the error TypeError: OpenFile() takes 0 positional arguments but 1 was given when you call self.OpenFile() (and the same is true for NewFile).
Related
I am trying to call multiple definitions and have each print their results to the ScrolledText.
If I define ScrolledText in the class MainPage, then the button OpenFile works fine , but the Menus commands do not with the 'scroll' is not defined error.
If I define ScrolledText in the class SampleApp, then the Menu OpenFile works fine , but the button commands do not with the 'scroll' is not defined error.
If I define both, then I get two scrolls that both work only in their own class.
How do I pass the scroll object between the 2 classes to use the same scroll in both class SampleApp and class MainPage?
#!/usr/bin/env python
# Python3.7.0
# Tkinter
import tkinter as tk # python 3
#from tkinter import ttk, font as tkfont, messagebox as mb, filedialog # python 3
from tkinter import ttk
import tkinter.scrolledtext as tkst
from tkinter.ttk import *
# Global scope
FilePath = "C:\Myfiles"
ScrollMsg = ""
# window definitions ----------------------------------
# Menu definitions ----------------------------------
def OpenFile(scroll): # Add a filedialog (file & directory chooser)
global FilePath, ScrollMsg
FilePath = "C:\Myfiles\file.txt"
print("filedialog path & file :\n", FilePath)
ScrollMsg = "filedialog path & file : " + FilePath
print ("SCROLL MESSAGE")
print ( ScrollMsg +"\n")
scroll.insert(tk.INSERT,ScrollMsg )
# ------------------------------------------------------
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.replace_frame(MainPage)
# scrolledtext
scroll = tkst.ScrolledText(self,width=90,height=15)
scroll.grid(column=0,row=15, columnspan = 6, sticky='W')
scroll.insert(tk.INSERT," OK here" +"\n")
# Menu for all frames ----------------------------------
menubar = tk.Menu(self)
# File
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label='Open', command=lambda: OpenFile(scroll))
menubar.add_cascade(label='File', menu=filemenu)
self.config(menu=menubar)
def replace_frame(self, frame_class):
"""Destroys current frame and replaces it with a new one."""
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.grid()
# FRAME CLASSES --------------------------------------
class MainPage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
lbl1 = tk.Label(self, text="File selection: ")
lbl1.grid(column=0, row=1)
lbl2 = tk.Label(self, text="File Path")
lbl2.grid(column=0, row=2)
_FP_ = Entry(self,width=30)
_FP_.insert(0,FilePath) #set the item
_FP_.grid(column=1, row=2)
btn = Button(self, text='OpenFile', command=lambda: OpenFile(scroll))
btn.grid(column=0, row=4)
# scrolledtext
'''
scroll = tkst.ScrolledText(self,width=90,height=15)
scroll.grid(column=0,row=15, columnspan = 6, sticky='W')
scroll.insert(tk.INSERT," OK here" +"\n")
'''
_FP_.focus() # Place cursor into File Name Entry
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I'm not sure I understand exactly what you're trying to accomplish, but think I can answer your question about having a ScrolledText that will work with both of the classes — SampleApp and MainPage — at the same time.
To do this I've added another class named SingleScroll which is what is known as a "singleton" class, because it restricts the number of instances of it that can be created to just a "single" one.
It's used by both SampleApp and MainPage just like a regular class, and the object returned from calling it is passed to the OpenFile() function as an argument for the Menu or Button commands in the respective classes.
import tkinter as tk # python 3
#from tkinter import ttk, font as tkfont, messagebox as mb, filedialog # python 3
from tkinter import ttk
import tkinter.scrolledtext as tkst
from tkinter.ttk import *
# Global scope
FilePath = r"C:\Myfiles"
ScrollMsg = ""
# window definitions ----------------------------------
# Menu definitions ----------------------------------
def OpenFile(scroll): # Add a filedialog (file & directory chooser)
global FilePath, ScrollMsg
FilePath = r"C:\Myfiles\file.txt"
print("filedialog path & file :\n", FilePath)
ScrollMsg = "filedialog path & file : " + FilePath
print("SCROLL MESSAGE")
print(ScrollMsg + "\n")
scroll.insert(tk.INSERT, ScrollMsg + "\n" )
# SHARED SCROLL CLASS (ADDED) --------------------------
class SingleScroll:
""" Singleton ScrolledText object. """
def __new__(cls, master):
if '_inst' not in vars(cls): # Create instance?
scroll = tkst.ScrolledText(master, width=90, height=15)
scroll.grid(column=0, row=15, columnspan=6, sticky='W')
scroll.insert(tk.INSERT, " OK here\n")
cls._inst = scroll
return cls._inst
# ------------------------------------------------------
class SampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self._frame = None
self.replace_frame(MainPage)
scroll = SingleScroll(self) # ScrolledText
# Menu for all frames ----------------------------------
menubar = tk.Menu(self)
# File
filemenu = tk.Menu(menubar, tearoff=0)
filemenu.add_command(label='Open', command=lambda: OpenFile(scroll))
menubar.add_cascade(label='File', menu=filemenu)
self.config(menu=menubar)
def replace_frame(self, frame_class):
"""Destroys current frame and replaces it with a new one."""
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.grid()
# FRAME CLASSES --------------------------------------
class MainPage(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
lbl1 = tk.Label(self, text="File selection: ")
lbl1.grid(column=0, row=1)
lbl2 = tk.Label(self, text="File Path")
lbl2.grid(column=0, row=2)
_FP_ = Entry(self,width=30)
_FP_.insert(0,FilePath) #set the item
_FP_.grid(column=1, row=2)
scroll = SingleScroll(master) # ScrolledText
btn = Button(self, text='OpenFile', command=lambda: OpenFile(scroll))
btn.grid(column=0, row=4)
_FP_.focus() # Place cursor into File Name Entry
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
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.
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'd like to know how I can add or delete widgets from within an imported module. I fail to access them correctly. I know, using OOP would make it easier, but I tried to grasp OOP and while the principles are easy I can't get my head around the details, so since I lack a proper teacher, I need a procedural solution.
This is the main script:
#!/usr/bin/python
try:
# Python2
import Tkinter as tk
except ImportError:
# Python3
import tkinter as tk
import os
import sys
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
import target
def myfunction(event):
canvas.configure(scrollregion=canvas.bbox("all"),width=300,height=200)
def test():
target.secondWindow()
root = tk.Tk()
root.geometry("600x350+30+50")
myframe = tk.Frame(root,relief="groove",bd=1)
myframe.place(x=20, y=30, width=560, height=200 )
canvas = tk.Canvas(myframe)
frame = tk.Frame(canvas)
myscrollbar=tk.Scrollbar(myframe, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side="right", fill="y")
canvas.pack(side="left")
canvas.create_window((0,0), window=frame, anchor='nw')
allMissions = {
"1":{"name":"go"},
"2":{"name":"see"},
"3":{"name":"win"},
"4":{"name":"party"}} # this would be a text file
for a in allMissions.keys():
mn = allMissions[a]["name"]
tk.Label(frame, text=mn, justify="left").grid(row=int(a), column=0)
# what's bind really doing?
frame.bind("<Configure>", myfunction)
test = tk.Button(root, command=test, text="TEST")
test.place(x = 20, y = 250, width=580, height=40)
tk.mainloop()
and this is the imported module: target.py
try:
# Python2
import Tkinter as tk
except ImportError:
# Python3
import tkinter as tk
def changeMainWindow():
# here's where I'm stuck
print("What do I have to do to add a new")
print("label in the main window from here?")
print("Or to delete it?")
def secondWindow():
amWin = tk.Toplevel()
amWin.geometry("300x200+720+50")
button = tk.Button(amWin, text="OK", command=changeMainWindow)
button.place(x = 20, y = 80, width=260, height=30)
#amWin.mainloop() comment noticed (:
You do it by passing the memory address of whatever widget to the second program. There is no reason to import Tkinter again as you can just pass a pointer to the existing instance. If you are going to be doing anything more than simple experimenting with Tkinter, then it is well worth the time to learn classes first at one of the online sites like this one http://www.greenteapress.com/thinkpython/html/thinkpython016.html More here https://wiki.python.org/moin/BeginnersGuide/NonProgrammers
You aren't going to get many answers with the way the program is structured because most programmers use the class structure AFAIK, so do not know how to pound the code into a non-class environment, so will not have any answers. If the first program below used classes then the second program's class could be inherited, and the functions would become part of the first program's class and could be accessed in the same way as the existing classes, so no passing of pointers, or any other hack, would be necessary.
## I deleted some code for simplicity
def myfunction(event):
canvas.configure(scrollregion=canvas.bbox("all"),width=300,height=200)
def test():
TG.secondWindow()
root = tk.Tk()
root.geometry("600x350+30+50")
myframe = tk.Frame(root,relief="groove",bd=1)
myframe.place(x=20, y=30, width=560, height=200 )
canvas = tk.Canvas(myframe)
frame = tk.Frame(canvas)
myscrollbar=tk.Scrollbar(myframe, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=myscrollbar.set)
myscrollbar.pack(side="right", fill="y")
canvas.pack(side="left")
canvas.create_window((0,0), window=frame, anchor='nw')
# what's bind really doing?
frame.bind("<Configure>", myfunction)
test = tk.Button(root, command=test, text="TEST", bg="lightblue")
test.place(x = 20, y = 250, width=580, height=40)
tk.Button(root, text="Quit All", command=root.quit,
bg="orange").place(x=20, y=300)
""" instance of the class in the imported program
a pointer to the root window and the Tk instance are passed
"""
TG=target.Target(tk, root)
tk.mainloop()
And target.py. Notice there are no imports.
class Target():
def __init__(self, tk, root):
self.tk=tk
self.root=root
def changeMainWindow(self):
# here's where I'm stuck
self.tk.Label(self.amWin, bg="yellow", text =""""What do I have to do to add a new
label in the main window from here?
Or to delete it?""").place(x=50,y=20)
def secondWindow(self):
self.amWin = self.tk.Toplevel(self.root)
self.amWin.geometry("300x200+720+50")
button = self.tk.Button(self.amWin, text="Add Label",
command=self.changeMainWindow)
button.place(x = 20, y = 90, width=260, height=30).
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.