How to pass a class with Toplevel widget in Tkinter - python

I have a readymade game(2048), where the game starts without a welcome window, so, I have just made a welcome window with a bunch of buttons like New Game and AI mode, now when I click the New Game button, I expect to get a new window where the game can be played. However, the game displays at the bottom of the main window, and another window that is supposed to display the actual game displays nothing.
# mainwindow.py file:
from tkinter import *
from PIL import ImageTk, Image
import game_2048
root = Tk()
root.iconbitmap('unnamed.ico')
root.title('2048')
bg = ImageTk.PhotoImage(Image.open("welcome.png"))
my_canvas = Canvas(root, width=780, height=550)
my_canvas.grid()
my_canvas.create_image(0, 0, image=bg, anchor=NW)
button1 = Button(root, text="New Game", fg="black", bg="#ddf0d0", padx=3,
pady=3, font=('Helvetica', '12', 'bold'), activebackground="#94d3c3", command=lambda: game_2048.mains(root)
)
button2 = Button(root, text="AI Mode", fg="black", bg="#ddf0d0",
padx=3, pady=3, font=('Helveica', '12', 'bold'), activebackground="#94d3c3")
button1_window = my_canvas.create_window(10, 10, anchor=NW, window=button1)
button2_window = my_canvas.create_window(120, 10, anchor=NW, window=button2)
root.mainloop()
And I have tried to modify the game_2048 file i.e. 2048 game like this:
def mains(root):
Top = Toplevel(root)
l1 = Button(Top, command=lambda:Game())
l1.pack()
class Game(tkinter.Frame):
def __init__(self):
tkinter.Frame.__init__(self)
self.grid()
self.master.title('2048')
self.main_grid = tkinter.Frame(
self, bg=c.GRID_COLOR, bd=3, width=400, height=400)
self.main_grid.grid(pady=(80, 0))
self.make_GUI()
self.start_game()
self.master.bind("<Left>", self.left)
self.master.bind("<Right>", self.right)
self.master.bind("<Up>", self.up)
self.master.bind("<Down>", self.down)
self.mainloop()
if __name__ == "__main__":
mains()
I am pretty sure that I have made some mistakes in the mains() function as a result of which I am not getting the desired output. So my question is what should I do to rectify these mistakes?

Here are the changes I made to your code:
Removed import mainwindow from game_2048.py, as it will lead to circular import calling the functions twice.
You created a class inheriting from a Frame, this frame is just like any other tkinter widget, requires to be placed in the window using geometric manager, like pack()/grid()/place(), you did not do that
I also destroyed the root window before creating another new root window. Also note that instead of using Toplevel, I used Tk. This is done, so that closing the game window will close the app. But if using Toplevel, you will have to close the menu window too.
from tkinter import *
import tkinter
import random
import colors as c
def mains(root):
root.destroy()
root = Tk()
def init(root):
l1.destroy()
game = Game(root)
game.pack()
l1 = Button(root, text='Start Game',command=lambda: init(root))
l1.pack()
class Game(tkinter.Frame):
def __init__(self, parent):
tkinter.Frame.__init__(self, parent)
.......
But if you were to ask me, I would not go for such structure, but this will work here too. Understand this, work on it, implement your own structure that does not call more than one Tk().

Related

Tkinter with Python [duplicate]

This question already has an answer here:
How do I create child windows with Python tkinter?
(1 answer)
Closed 5 years ago.
I am quite new to Python and started learning Tkinter yesterday. I am creating a banking system and I have a Menu made out of the buttons. The problem that I have is that I do not know how to open an additional window when the button is clicked. I have tried with top=Toplevel(), but it only opens two windows on top of each other. What I need is for the additional window to open only when it is activated with a button(event). Can someone help me because I am really stuck as I have about six buttons?
My code so far is:
root.minsize(width=400, height=400)
root.maxsize(width=400, height=400)
root.configure(background='#666666')
label = Frame(root).pack()
Lb = Label(label, text='Welcome to Main Menu',bg='#e6e6e6', width=400).pack()
menu = Frame(root,).pack()
btn_1 = Button(menu, text='Make Deposit', width=15, height=2).pack(pady=5)
btn_2 = Button(menu, text='Withdrawal', width=15, height=2).pack(pady=5)
btn_3 = Button(menu, text='Accounts', width=15, height=2).pack(pady=5)
btn_4 = Button(menu, text='Balance', width=15 ,height=2).pack(pady=5)
btn_5 = Button(menu, text='Exit', width=15, height=2).pack(pady=5)
root.mainloop()
Thank you for the help in advance
Maybe this could work:
from Tkinter import *
class firstwindow:
def __init__(self):
#Variables
self.root= Tk()
self.switchbool=False
#Widgets
self.b = Button(self.root,text="goto second window",command= self.switch)
self.b.grid()
self.b2 = Button(self.root,text="close",command= self.root.quit)
self.b2.grid()
self.root.mainloop()
#Function to chage window
def switch(self):
self.switchbool=True
self.root.quit()
self.root.destroy()
class secondwindow:
def __init__(self):
self.root= Tk()
self.b2 = Button(self.root,text="close",command= self.root.quit)
self.b2.grid()
self.root.mainloop()
one = firstwindow()
if one.switchbool:
two = secondwindow()
Take a look to the Tkinter reference. Check all universal methods and widgets methods. You can do anything you want.
Below is a small example of how you can open a window by clicking on a button. When the user clicks on the button, the function open_window, which was passed to the command option of the button, is called.
import tkinter as tk
def open_window():
top = tk.Toplevel(root)
tk.Button(top, text='Quit', command=top.destroy).pack(side='bottom')
top.geometry('200x200')
root = tk.Tk()
tk.Button(root, text='Open', command=open_window).pack()
tk.Button(root, text='Quit', command=root.destroy).pack()
root.mainloop()

Python 3.4 tkinter button

My program should destroy btn1 and create it again after one second in loop. I don't no why but my program only destroy btn1 and don't show this again. Anyone have idea why?
from tkinter import *
import random
def hide():
btn1.destroy()
btn1.after(2000,hide)
def show():
btn1 = Button(root, bd=c, text="Hello\nWorld", relief="ridge", cursor="trek")
btn1.grid(row=0,column=0)
btn1.after(3000,show)
root = Tk()
root.geometry("350x150+400+400")
c=random.randint(20,40)
btn1 = Button(root, bd=c, text="Hello\nWorld", relief="ridge", cursor="trek")
btn1.grid(row=0,column=0)
btn1.after(2000,hide)
btn1.after(3000,show)
root.mainloop()
It will work if you use grid_forget instead of creating a new object each time. Note that what happens at multiples of 6 seconds (2000 X 3000) depends on which one is the last one to execute.
def hide():
btn1.grid_forget()
btn1.after(2000,hide)
def show():
btn1.grid(row=0,column=0)
btn1.after(3000,show)
root = Tk()
root.geometry("350x150+400+400")
c=random.randint(20,40)
btn1 = Button(root, bd=c, text="Hello\nWorld",
relief="ridge", cursor="trek")
btn1.grid(row=0,column=0)
btn1.after(2000,hide)
btn1.after(3000,show)
root.mainloop()

Adding or deleting tkinter widgets from within other modules

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).

Tkinter - How would I create buttons in a new window, which has been created by a function being called? Python 3

from tkinter import *
def begin():
root = Tk()
root.title("main window")
root.geometry("1920x1080")
return #How would a button be placed in this window made by this function?
root = Tk()
root.title("Start up page")
root.geometry("1920x1080")
BeginButton = Button(app, text = "Begin", command=begin, bg="green")
BeginButton.grid(column = 2, row = 2, sticky = W)
BeginButton.config(height = 10, width = 30 )
root.mainloop()
How would I create new buttons in the new window, if the new window is being made by, in this case a function known as "begin".
Any response would be much appreciated!
I believe what you want to do is to modify the root window rather than create a new one. Here is a minimal working example:
from tkinter import *
root = Tk()
class App:
def __init__(self):
root.title("Start up page")
root.geometry("1920x1080")
self.beginB = Button(root, text="Begin", command=self.begin,
bg="green", height=10, width=30)
self.beginB.grid(sticky = W)
def begin(self):
root.title("main window")
self.beginB.destroy()
del self.beginB
self.goB = Button(root, text='Go on', command=self.go_on,
bg='red')
self.goB.grid(sticky=E)
def go_on(self):
self.label = Label(root, text="you have continued")
self.label.grid(row=1, sticky=S)
App()
root.mainloop()
An advantage of defining a class is that you can make forward references. In your code, you had to define the begin function before you create the begin button. With a class, I could put it after init, which to me is a more natural order. It is ofter the case that the initialization code calls or binds more than one function.

tkinter canvas image is not displayed in class

I am trying to display an image in python using the tkinter canvas option. However, if I input it in a class, like below, it doesn't give an error but also doesn't show my image. The buttons are displayed correctly though. Also, if I take the code for generating this image out of the class it works correctly. I can't seem to find out what the problem is.
import Tkinter as tk
from Tkinter import *
class Board(tk.Frame):
def __init__(self,parent):
frame = Frame(parent)
frame.pack()
tk.Frame.__init__(self,parent)
frame2 = Frame(frame)
frame2.pack()
c=Canvas(frame2)
c.pack(expand=YES,fill=BOTH)
background=PhotoImage(file='Board.gif')
c.create_image(100,100,image=background,anchor='nw')
button = Button(frame, text="Next turn", command=self.next_turn)
button.pack()
button = Button(frame, text="Roll the dice", command=self.roll)
button.pack()
....
root = Tk()
board = Board(root)
board.pack()
root.mainloop()
You have to keep a reference to the PhotoImage. This is just and example (you can also use self.background instead of c.background):
c = Canvas(frame2)
c.pack(expand=YES,fill=BOTH)
c.background = PhotoImage(file='Board.gif')
c.create_image(100,100,image=c.background,anchor='nw')

Categories

Resources