I am trying to make a menubar for my GUI. I get this error:
`NameError: name 'Menu' is not defined`
I am not sure why this is happening, could someone please help me? My apologies, I am a beginner at python and tkinter.
from tkinter import Tk, BOTH
from tkinter.ttk import Frame, Button, Style
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.parent.title("xcal file.ics")
self.pack(fill=BOTH, expand=1)
self.centerWindow()
self.createMenuBar()
def centerWindow(self):
w = 500
h = 500
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
x = (sw - w)/2
y = (sh - h)/2
self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y))
def createMenuBar(self):
menubar = Menu(Frame) #ERROR
menubar.add_command(label="Hello!", command=hello)
Frame.config(menu=menubar)
def main():
root = Tk()
ex = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
Menu is in the module tkinter, so you need to import it:
from tkinter import Tk, BOTH, Menu
Related
I'm trying to enter a file name into your graphics window and then read that file and display the file in a graphics window using a file menu. When I press new another window opens to ask for a name and displays it in the main window, but I can't get the new window to open and do the rest. I have the TopLevel to open a new window, but I get NameError: name 'TopLevel' is not defined and can't continue from there. What can I do to make it work?
from tkinter import Tk, Frame, Menu
from tkinter.ttk import *
from tkinter import filedialog as fd
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Simple menu")
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="New", command=self.onNew)
menubar.add_cascade(label="File", menu=fileMenu)
def onNew(self):
print("do New")
top = TopLevel()
Label(self, text='Enter Your Name').grid(row=0)
e1 = Entry(self)
e1.grid(row=0, column=1)
def main():
root = Tk()
root.geometry("250x150+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
The problem is simply that you're not defining or importing anything named Toplevel. The way you're importing tkinter makes this an easy problem to have.
My recommendation is to remove these statements:
from tkinter import Tk, Frame, Menu
from tkinter.ttk import *
... and replace them with these:
import tkinter as tk
from tkinter import ttk
From then on, you have access to almost everything in the tkinter and ttk packages. You simply need to add a tk. or ttk. prefix to everything you use from those packages.
This keeps global namespace pollution at a minimum (ie: you only add two names to the global namespace), and makes your code more self-documenting.
class Example(tk.Frame):
def __init__(self, parent):
ttk.Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Simple menu")
menubar = tk.Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = tk.Menu(menubar)
fileMenu.add_command(label="New", command=self.onNew)
menubar.add_cascade(label="File", menu=fileMenu)
def onNew(self):
print("do New")
top = tk.TopLevel()
ttk.Label(self, text='Enter Your Name').grid(row=0)
e1 = ttk.Entry(self)
e1.grid(row=0, column=1)
def main():
root = tk.Tk()
root.geometry("250x150+300+300")
app = Example(root)
root.mainloop()
from tkinter import *
import tkinter as tk
root = tk.Tk()
def add_many_songs():
# Loop thru to fill list box
for song in range(11):
playlist_box.insert(END, song)
playlist_box =tk.Listbox(root,bg="black", fg="green", width=60, selectbackground="green", selectforeground='black',font = 20)
playlist_box.grid(row=0, column=0)
add_many_songs()
class DragDropListbox(tk.Listbox):
""" A Tkinter listbox with drag'n'drop reordering of entries. """
def __init__(self, master, **kw):
kw['selectmode'] = tk.SINGLE
tk.Listbox.__init__(self, master, kw)
self.bind('<Button-1>', self.setCurrent)
self.bind('<B1-Motion>', self.shiftSelection)
self.curIndex = None
def setCurrent(self, event):
self.curIndex = self.nearest(event.y)
def shiftSelection(self, event):
i = self.nearest(event.y)
if i < self.curIndex:
x = self.get(i)
self.delete(i)
self.insert(i+1, x)
self.curIndex = i
elif i > self.curIndex:
x = self.get(i)
self.delete(i)
self.insert(i-1, x)
self.curIndex = i
##I found this code that does drag and drop features within tkinter list. I got it to work with the example code. However, I am not able to get it to work within the attached code. I am still learning Python.
You should use the class DragDropListbox instead of tk.Listbox when creating playlist_box:
import tkinter as tk
def add_many_songs():
# Loop thru to fill list box
for song in range(11):
playlist_box.insert(tk.END, song)
class DragDropListbox(tk.Listbox):
""" A Tkinter listbox with drag'n'drop reordering of entries. """
def __init__(self, master, **kw):
kw['selectmode'] = tk.SINGLE
tk.Listbox.__init__(self, master, kw)
self.bind('<Button-1>', self.setCurrent)
self.bind('<B1-Motion>', self.shiftSelection)
self.curIndex = None
def setCurrent(self, event):
self.curIndex = self.nearest(event.y)
def shiftSelection(self, event):
i = self.nearest(event.y)
if i < self.curIndex:
x = self.get(i)
self.delete(i)
self.insert(i+1, x)
self.curIndex = i
elif i > self.curIndex:
x = self.get(i)
self.delete(i)
self.insert(i-1, x)
self.curIndex = i
root = tk.Tk()
playlist_box = DragDropListbox(root,bg="black", fg="green", width=60, selectbackground="green", selectforeground='black',font = 20)
playlist_box.grid(row=0, column=0)
add_many_songs()
root.mainloop()
Note that it is not recommended to import tkinter like below:
from tkinter import *
import tkinter as tk
Just use import tkinter as tk.
I want to show the plot canvas in the top right side of UI (using Tkinter python3). I wrote the following code but I got the following error:
canvas = FigureCanvasTkAgg(fig, master=root) NameError: name 'root' is not defined
My code is:
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import *
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import sys
class GUI(tk.Frame):
def __init__(self, master = None):
self.root = tk.Tk()
self.root.geometry("500x500")
tk.Frame.__init__(self, master)
self.createWidgets()
def start(self):
self.root.mainloop()
def createWidgets(self):
fig = plt.figure(figsize=(8, 8))
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().grid(row=0, column=1)
canvas.show()
def main():
appstart = GUI()
appstart.start()
if __name__ == "__main__":
main()
I made some changes to your code, deleting some unnecessary
references such as:
import tkinter.ttk as ttk
from tkinter import *
from matplotlib.figure import Figure
import sys
self.root = tk.Tk()
tk.Frame.__init__(self, master)
that you dont' use and I think only confuse yourself.
I've even simplified your script and add this code below to show to you wath is "self"
print(type(self))
for item in dir(self):
print(type(item),item)
I've add even a toolbar to the plot and some data to plot something.
Regards
import tkinter as tk
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import numpy as np
class GUI(tk.Tk):
def __init__(self):
super().__init__()
self.title("Hello World")
self.geometry("500x500")
self.createWidgets()
print(type(self))
for item in dir(self):
print(type(item),item)
def createWidgets(self):
t = np.arange(0, 3, .01)
f0 = tk.Frame()
fig = plt.figure(figsize=(8, 8))
fig.add_subplot(111).plot(t, 2 * np.sin(2 * np.pi * t))
canvas = FigureCanvasTkAgg(fig, f0)
toolbar = NavigationToolbar2Tk(canvas, f0)
toolbar.update()
canvas._tkcanvas.pack(fill=tk.BOTH, expand=1)
f0.pack(fill=tk.BOTH, expand=1)
def main():
appstart = GUI()
appstart.mainloop()
if __name__ == "__main__":
main()
In your code you should use self.root if your intent is to use the root window:
canvas = FigureCanvasTkAgg(fig, master=self.root)
... or maybe just self, if your intent is to have it appear inside the frame. I'm not entirely sure what you are intending to do
canvas = FigureCanvasTkAgg(fig, master=self)
Somewhat unrelated, if you're explicitly creating a root window, you should be passing that to tk.Frame.__init__ rather than master.
tk.Frame.__init__(self, self.root)
I have modified the answer given here as written below. The code is basically creating pushbuttons with a counter as pushButton_0, pushButton_1..
Here, I know that when I press to self.addButton I am creating widgets named like self.pushButton_0, self.pushButton_1 etc. So, my question is, how I'm supposed to use this pushbuttons? Because when I'm trying to do something like self.pushButton_0.clicked.connect(self.x), it' s telling me that "there is no attribute named 'pushButton_0'".
Thanks!
from PyQt4 import QtGui, QtCore
import sys
class Main(QtGui.QMainWindow):
def __init__(self, parent = None):
super(Main, self).__init__()
self.GUI()
def GUI(self):
self.count = 0
# main button
self.addButton = QtGui.QPushButton('button to add other widgets')
self.addButton.clicked.connect(self.addWidget)
# scroll area widget contents - layout
self.scrollLayout = QtGui.QFormLayout()
# scroll area widget contents
self.scrollWidget = QtGui.QWidget()
self.scrollWidget.setLayout(self.scrollLayout)
# scroll area
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setWidget(self.scrollWidget)
# main layout
self.mainLayout = QtGui.QVBoxLayout()
# add all main to the main vLayout
self.mainLayout.addWidget(self.addButton)
self.mainLayout.addWidget(self.scrollArea)
# central widget
self.centralWidget = QtGui.QWidget()
self.centralWidget.setLayout(self.mainLayout)
# set central widget
self.setCentralWidget(self.centralWidget)
def addWidget(self):
self.scrollLayout.addRow(Test(self))
self.count = self.count + 1
print(self.count)
class Test(QtGui.QWidget):
def __init__( self, main):
super(Test, self).__init__()
self.Main = main
self.setup()
def setup(self):
print(self.Main.count)
name = "pushButton_"+str(self.Main.count)
print(name)
self.name = QtGui.QPushButton('I am in Test widget '+str(self.Main.count))
layout = QtGui.QHBoxLayout()
layout.addWidget(self.name)
self.setLayout(layout)
app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()
After hours, I found the problem!
You have to declare the signal while creating the pushbutton!
To fix this, I rewrote the setup function as below;
def setup(self):
print(self.Main.count)
name = "pushButton_"+str(self.Main.count)
print(name)
self.name = QtGui.QPushButton('I am in Test widget '+str(self.Main.count))
self.name.clicked.connect(self.x) # self.x is any function
layout = QtGui.QHBoxLayout()
layout.addWidget(self.name)
self.setLayout(layout)
So know, you will run function x whenever you push the new created pushbuttons!
I was reading http://infohost.nmt.edu/tcc/help/pubs/tkinter/tkinter.pdf
and started playing around with "54.7. The extra arguments trick" located towards the end of the document. If I understand it correctly, I can create widgets in a list, so that when the widget is clicked on, the callback should be able to display information stored in the instantiated class, I get the widget to display, but the callback is not displaying the info that I expected. IE the attributes of the object created - Hopefully someone can help. thanks in advance
here is the code
from tkinter import *
class Component(object):
def __init__(self, image=None, Number=None, Name=None):
self.image=image
self.Number=Number
self.Name=Name
ComponentList = [] #array of componenents
def FeederCB(event):
print(event.widget.Number, event.widget.Name)
root = Tk()
test=Frame(root, bg='white')
test.grid()
for x in range(0, 2):
print(x)
ComponentList.append(Component(None, str(x),"Poly 23"))
Temp=Label(test, text=ComponentList[-1].Name)
Temp.configure(bg='white', font='times 12')
Temp.grid(row=0, column=x, sticky=S)
ComponentList[-1].image = (Label(test, text='test'))
ComponentList[-1].image.configure(bg='white')
ComponentList[-1].image.bind("<Button-1>",FeederCB)
ComponentList[-1].image.grid(row=1, column=x)
print('Lenght of Component List ', len(ComponentList))
root.mainloop()
I think I got it
from tkinter import *
class Component(object):
def __init__(self, image=None, Number=None, Name=None):
self.image=image
self.Number=Number
self.Name=Name
ComponentList = [] #array of componenents
#ComponentList.append(Class object,class attibutes)
#example ComponentList.append(Virgin("1", "materialtype", "Name", "Setpoint"))
#print(ComponentList[0].Name)
def __FeederCB(event, x):
print(ComponentList[x].Number, ComponentList[x].Name)
root = Tk()
test=Frame(root, bg='white')
test.grid()
for x in range(0, 2):
print(x)
ComponentList.append(Component(None, str(x),"Poly 23"))
Temp=Label(test, text=ComponentList[-1].Name)
Temp.configure(bg='white', font='times 12')
Temp.grid(row=0, column=x, sticky=S)
ComponentList[-1].image = (Label(test, text='test'))
ComponentList[-1].image.configure(bg='white')
def FeederCB(event, x=x):
return __FeederCB(event, x)
ComponentList[-1].image.bind("<Button-1>",FeederCB)
ComponentList[-1].image.grid(row=1, column=x)
print('Lenght of Component List ', len(ComponentList))
root.mainloop()