Python - How to switch frames in a Tkinter window - python-3.x

I want to switch frames in a Tkinter window but the previous frame always stays visible in the background.
This is the code I have:
from tkinter import *
class frame(Frame):
def __init__(self,display):
Frame.__init__(self,display)
l = Label(self,text="frame1")
l.pack()
class frame2(Frame):
def __init__(self,display):
Frame.__init__(self,display)
l = Label(self,text="frame2")
l.pack()
class test(Tk):
def __init__(self):
Tk.__init__(self)
f = frame(self)
f.grid(row=0)
f2 = frame2(self)
f2.grid(row=0)
f.tkraise()
t = test()
t.mainloop()
This works if the layout of the two frames is the same but if I add another label to the second frame, it will still be visible in the Background. Is there a way to switch frames so that only elements from the raised frame are visible?

As requested, this is what I used to fix my problem:
from tkinter import *
class frame(Frame):
def __init__(self,display):
Frame.__init__(self,display)
l = Label(self,text="frame1")
l.pack()
class frame2(Frame):
def __init__(self,display):
Frame.__init__(self,display)
l = Label(self,text="frame2")
l.pack()
class test(Tk):
def __init__(self):
Tk.__init__(self)
f2 = frame2(self)
f2.grid(row=0)
#To raise the first frame, I used the following
frame2.grid_remove()
f = frame(self)
f.grid(row=0)
t = test()
t.mainloop()

Related

Tkinter Label class not appearing when used within a class

I am creating a basic GUI with multiple, but similar, label structures. However, when I created a class to help minimize the text, and placed it within a label frame, the label frame does not appear. This only happens when I use the class within a class, and if I use the regular label and label frame classes everything works out well. I'm trying to figure out as to why this is the case.
My code:
main.py
from tkinter import *
def main():
main_window = Tk()
app = First(main_window)
main_window.mainloop()
class GPULabel(Label):
def __init__(self, master, varText):
varText = varText
super().__init__()
self["text"] = varText
self["anchor"] = "w"
self["width"] = 25
class First:
def __init__(self, root):
self.root = root
self.root.title('First Window')
self.myFrame = LabelFrame(self.root, text="frame")
self.myFrame.pack()
label1 = GPULabel(self.myFrame, "label")
lable1.pack()
if __name__ == '__main__'
main()
This opens a window but it is completely empty. However, if I swap to a regular Label(self.myFrame...) then the window pops up correctly. Why is that? And is there a way to make my original method work?

Drag Drop List in Tkinter

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.

Tkinter gives me a second window

I am writing code for a tkinter gui using a class, however I notice that when I run there is a second window besides the main one I made. I've tried a number of things but they either break the code or the window is black. See code below.
import tkinter as gui
class loginWindow(gui.Frame):
def __init__(self):
super(loginWindow, self).__init__()
self.logUI()
def logUI(self):
self.mainWindow = gui.Tk()
self.mainWindow.title("GLSC IT Inventory")
self.mainWindow.minsize(400, 150)
self.mainWindow.maxsize(400, 150)
self.mainWindow.geometry("400x150")
self.greet_label = gui.Label(self.mainWindow, text="Welcome!!!")
self.greet_label.place(x=180, y=5)
self.uname_label = gui.Label(self.mainWindow, text="Username:")
self.uname_label.place(x=10, y=24)
self.uname_input = gui.StringVar()
self.uname_field = gui.Entry(self.mainWindow, bd=4, textvariable=self.uname_input)
self.uname_field.place(x=80, y=25, width=160)
self.pwd_label = gui.Label(self.mainWindow, text="Password:")
self.pwd_label.place(x=10, y=54)
self.pwd_input = gui.StringVar()
self.pwd_field = gui.Entry(self.mainWindow, bd=4, textvariable=self.pwd_input, show="\u2022")
self.pwd_field.place(x=80, y=55, width=160)
self.login_button = gui.Button(self.mainWindow, text="Login", command=None)
self.login_button.place(x=180, y=95)
my_app = loginWindow()
my_app.mainloop()
When you create instance of loginWindow(), an instance of Tk() is required but there is none, so it will be created implicitly for you.
Then another instance of Tk() is created inside logUI(). So there are two instances of Tk().
One way to fix it is loginWindow not inherited from Frame:
class loginWindow:
def __init__(self):
self.logUI()
def logUI(self):
...
# add for calling tkinter.mainloop()
def mainloop(self):
self.mainWindow.mainloop()

Tkinter display class list text

I have the following piece of code: I am trying to get the text from function showText to actually appear in the window
from tkinter import *
import wikipedia
from nltk.tokenize import sent_tokenize, word_tokenize
import time
subject = wikipedia.page("Assembly language")
#print(p.url)
#print(p.title)
plain_text = subject.content
plain_text_words = word_tokenize(plain_text)
class Window(Frame):
def __init__(self, master= None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title('Test')
self.pack(fill=BOTH, expand =1)
quitButton = Button(self, text = 'Exit', command=self.client_exit)
quitButton.place(x=500, y=300)
menu = Menu(self.master)
self.master.config(menu=menu)
file = Menu(menu)
menu.add_cascade(label='File', menu=file)
file.add_command(label='Run', command=self.showText)
file.add_command(label='Exit', command=self.client_exit)
help_menu = Menu(menu)
menu.add_cascade(label='Help', menu=help_menu)
help_menu.add_command(label='About')
def showText(self):
for i in range (0, len(plain_text_words)):
words = [i]
time.sleep(3)
words.pack()
def client_exit(self):
exit()
root = Tk()
w = 600 # width of the window
h = 370 # height of the window
# get screen width and height
ws = root.winfo_screenwidth()
hs = root.winfo_screenheight()
# calculate x and y coordinates for the Tk root window
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
The piece that's causing me grief is this bit:
def showText(self):
for i in range (0, len(plain_text_words)):
words = [i]
time.sleep(3)
words.pack()
I am trying to get each piece of text to show as individual words on the window but no matter how I try and do it, I get an error. I have tried various things such as converting to lists etc Hoping someone can help..
PS: You will need to download the nltk dataset before this code will run
First of all, your pack function misses the brackets.
Second, your var words is a list. Not a tkinter widget. You can only pack tkinter widgets.
To solve it you need to add the list to a text widget for example.

how to display a random point every second in kivy

I try to display a random point every second in kivy.
Here is my code. I know how to display the point, an ellipse in this case. But I don't know how to make its position to update every second.
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.widget import Widget
from kivy.graphics import Ellipse
import time
import numpy as np
class RandomPoint(Widget):
def __init__(self,dimension):
super(RandomPoint,self).__init__()
self.d = dimension
self.point = Ellipse(pos=list(np.random.randint(0,1000,2)),size = (self.d, self.d))
def update(self, *args):
self.point = Ellipse(pos=list(np.random.randint(0,1000,2)),size = (self.d, self.d))
class TimeApp(App):
def build(self):
wid = Widget()
with wid.canvas:
p = RandomPoint(25)
Clock.schedule_interval(p.update, 1)
return wid
TimeApp().run()
How would you do that ?
Putting the Clock.schedule_interval call in the canvas block won't satisfy the requirement of these calls to happen in a canvas block. They are executed later, when the code exited the with block long ago. What you can do is use the same construction, but inside both __init__ and update, around your Ellipse instructions.
Also, at no point do you add your RandomPoint widget, to your root widget, so it won't be visible at all, whatever happens with its instructions.
class RandomPoint(Widget):
def __init__(self,dimension):
super(RandomPoint,self).__init__()
self.d = dimension
self.points = []
with self.canvas:
self.point.append(Ellipse(pos=list(np.random.randint(0,1000,2)),size = (self.d, self.d)))
def update(self, *args):
with self.canvas:
self.points.append(Ellipse(pos=list(np.random.randint(0,1000,2)),size = (self.d, self.d)))
class TimeApp(App):
def build(self):
wid = Widget()
p = RandomPoint(25)
wid.add_widget(p)
Clock.schedule_interval(p.update, 1)
return wid
TimeApp().run()

Resources