1

I'm creating a game, and I am using tkinter to build the GUI.

In this game, I want the user to start with a window, filled by a Canvas, with an image as background, and some buttons in some sort of item windows. And this Canvas is the home Canvas of the game.

The problem is that I want the user to click on a Button to land on other Canvas, who will host other things like the map or others buttons for others actions. Actually, I would like to superimpose several canvas (as in the Z-index method), and put a canvas on the top of the list, when I want it (if I click on a button for example).

I already searched and I had to change my mind several times, and now I really don't know how to do it.

I find the following code here on Stack Overflow, but it is coded for Python 2 (I think), and I'm starting coding in Python 3, so I am not able to translate it to Python 3 and solve my problem.

import Tkinter as tk

class SampleApp(tk.Tk):

   def __init__(self, *args, **kwargs):
       tk.Tk.__init__(self, *args, **kwargs)
       self.frame = tk.Frame(self)
       self.frame.pack(side="top", fill="both", expand=True)
       self.label = tk.Label(self, text="Hello, world")
       button1 = tk.Button(self, text="Click to hide label",
                           command=self.hide_label)
       button2 = tk.Button(self, text="Click to show label",
                           command=self.show_label)
       self.label.pack(in_=self.frame)
       button1.pack(in_=self.frame)
       button2.pack(in_=self.frame)

    def show_label(self, event=None):
        self.label.lift(self.frame)

    def hide_label(self, event=None):
        self.label.lower(self.frame)


if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()

My code using grid :

from tkinter import *

fenetre = Tk()
fenetre.title(my game)

# acceuil
# variable acceuil
largeur = 700
hauteur = 430

BG_acceuil = PhotoImage(file="BG_acceuil.gif")
acceuil = Canvas(fenetre, width=largeur, height=hauteur)
acceuil.create_image(0, 0, anchor=NW, image=BG_acceuil)
acceuil.grid(row=0)
acceuil.pack()

# fond
fond = PhotoImage(file="BG_acceuil.gif")
acceuil2 = Canvas(fenetre, width=largeur, height=hauteur)
acceuil2.create_image(0, 0, anchor=NW, image=fond)
acceuil2.pack()

# variable bt_jouer
x0 = 80
y0 = 230


class hide_me():

    def hide_me(event, widget, pos):
        widget.grid_forget()

    def show_me(event, widget, pos):
        widget.grid(row=pos)


# Boutton jouer
BT_jouer = Button(acceuil, text="Jouer", command=hide_me())
BT_jouer.configure(width=10, activebackground="#33B5E5", relief=GROOVE)
BT_jouer_window = acceuil.create_window(x0, y0, window=BT_jouer,)
BT_jouer.bind('<Button-1>', lambda event: hide_me(event, BT_jouer, 1))
BT_jouer.grid(row=1)

# Bouton règle
BT_regle = Button(acceuil2, text="Règles", command=fenetre.destroy)
BT_regle.configure(width=10, activebackground="#33B5E5", relief=FLAT,    bd=0)
BT_regle_window = acceuil2.create_window(x0, y0 + 50, window=BT_regle)

# Boutton quitter
BT_quit = Button(acceuil, text="Quitter", command=fenetre.destroy)
BT_quit.configure(width=10, activebackground="#33B5E5", relief=FLAT)
BT_quit_window = acceuil.create_window(x0, y0 + 100, window=BT_quit)

fenetre.mainloop()
nbro
  • 15,395
  • 32
  • 113
  • 196
Djabadours
  • 23
  • 1
  • 4

1 Answers1

1

The answer is very easy: To convert to Python3, change Tkinter to tkinter, and it works!

import tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self, *args, **kwargs):
       tk.Tk.__init__(self, *args, **kwargs)
       self.frame = tk.Frame(self)
       self.frame.pack(side="top", fill="both", expand=True)
       self.label = tk.Label(self, text="Hello, world")
       button1 = tk.Button(self, text="Click to hide label",
                           command=self.hide_label)
       button2 = tk.Button(self, text="Click to show label",
                           command=self.show_label)
       self.label.pack(in_=self.frame)
       button1.pack(in_=self.frame)
       button2.pack(in_=self.frame)

    def show_label(self, event=None):
        self.label.lift(self.frame)

    def hide_label(self, event=None):
        self.label.lower(self.frame)

def main():
    app = SampleApp()
    app.mainloop()  
    return 0

if __name__ == '__main__':
    main()

Note: You are not really hiding the label - it still occupies space on the canvas. The following code, from this entry, really removes the item. It can then be recalled with a pack() call:

from Tkinter import *

def hide_me(event):
    event.widget.pack_forget()

root = Tk()
btn=Button(root, text="Click")
btn.bind('<Button-1>', hide_me)
btn.pack()
btn2=Button(root, text="Click too")
btn2.bind('<Button-1>', hide_me)
btn2.pack()
root.mainloop()

I did some testing, and made an equivalent program to yours... The only problem is that the unhidden widget is always packed at the end:

from tkinter import *

def hide_me(event, widget):
    widget.pack_forget()

def show_me(event, widget):
    widget.pack()

root = Tk()
lbl = Label(root, text="Victim")

btn = Button(root, text="Hide the victim")
btn.bind('<Button-1>', lambda event: hide_me(event, lbl))
btn.pack()

btn2 = Button(root, text="Show the victim")
btn2.bind('<Button-1>', lambda event: show_me(event, lbl))
btn2.pack()

lbl.pack()

root.mainloop()

A better version uses the grid() packer. Here you can actually restore the 'forgotten' widget to its original position. Only slightly more complicated :)

from tkinter import *

def hide_me(event, widget, pos):
    widget.grid_forget()

def show_me(event, widget, pos):
    widget.grid(row = pos)

root = Tk()
lbl = Label(root, text="Victim")
lbl.grid(row = 0)

btn = Button(root, text="Hide the victim")
btn.bind('<Button-1>', lambda event: hide_me(event, lbl, 0))
btn.grid(row = 1)

btn2 = Button(root, text="Show the victim")
btn2.bind('<Button-1>', lambda event: show_me(event, lbl, 0))
btn2.grid(row = 2)


root.mainloop()

EDIT: Another observation from the comments: Bryan Oakley commented that if you use .grid_remove() instead of .grid_forget(), then the coordinates will not be lost, and a simple .grid() will restore the widget at its location.

Community
  • 1
  • 1
jcoppens
  • 5,306
  • 6
  • 27
  • 47
  • You mean by this that I can't interact with the last object of the stack, once the above objects are hidden ? In this case, I would at least unabled them right ? And when you say that an object can be remove and recall, is it destroyed and recreate ? Because, I am trying not to destroy any objects. – Djabadours May 25 '15 at 14:25
  • Comments I read is that the object remains on stack, and that pack() alone should be able to restore a .pack_forget() should be able to restore it. I tried it, and it does not work quite right. This is probably because pack() is sequential - it doesn't store its position. Try grid(), where you specify the actual row position. There's a grid_forget() to hide and grid() should restore. – jcoppens May 25 '15 at 14:29
  • Edited the above reply: It's possible to restore the 'forgotten' widget to its original position, if you actually tell it where. – jcoppens May 25 '15 at 14:36
  • Ok, thanks to your previous edit I have a more precise idea of how I can do it. The point is that i'd like the button that is on the canvas to disapear whit it, instead of this, without any action of my part, I get the second canvas, and the button that is supposed to call it, stand on the top of the window.. I'll edit my question. – Djabadours May 25 '15 at 15:43
  • 2
    If you use `grid_remove` rather than `grid_forget`, you can just call `.grid()` with no parameters, and the previous parameters will be remembered. This makes your code easier to maintain, because a change in the original layout doesn't require a corresponding change in any other code. – Bryan Oakley May 25 '15 at 15:57