Replacing GIF with another GIF using a button in tkinter - python

I am trying to create a program then when started, shows a gif and a button that says: "Turn off system". When clicked, I want the gif to change to another gif and the button to be replaced with a button that says "Turn on system".
I made exactly this but when I click the button, the first GIF remains on the screen. You can however see the second GIF popping in and out when clicking rapidly.
EDIT* Due to a formatting issue I had to redefine my code, the def main(): you see in my code should not exist.
Here is my code:
import tkinter as tk
from PIL import Image, ImageTk
from tkinter import *
from tkinter import ttk
root = tk.Tk()
root.title('Camera System')
def update(ind):
frame = stgImg[ind]
ind += 1
if ind == frameCnt:
ind = 0
label.configure(image=frame)
root.after(100, update, ind)
def SystemOn():
stgImg = PhotoImage(file=(filename1.gif))
label.configure(image=stgImg)
label.image = stgImg
global b3
b3=tk.Button(root,text="Turn Off System",command=lambda:SystemOff())
b3.pack()
b1.pack_forget()
b2.pack_forget()
def SystemOff():
stgImg = PhotoImage(file=(filename2.gif))
label.configure(image=stgImg)
label.image = stgImg
global b2
b2=tk.Button(root,text="Turn On System",command=lambda:SystemOn())
b2.pack()
b1.pack_forget()
b3.pack_forget()
def main():
frameCnt = 12
root.geometry('1010x740+200+200')
stgImg = [PhotoImage(file=(filename1.gif),
format = 'gif -index %i' %(i)) for i in range(frameCnt)]
label=ttk.Label(root)
label.pack()
root.after(0, update, 0)
global b1
b1=tk.Button(root,text="Turn Off System",command=lambda:SystemOff())
b1.pack()
root.mainloop()

Here is a small program that achieves the affects described.
I've set up filedialog to load the two images and defined a button with message.
Two functions work together to replace the image and text.
import tkinter as tk
from tkinter import filedialog as fido
master = tk.Tk()
imageon = fido.askopenfilename(title ="Pick a Picture")
on = tk.PhotoImage(file = imageon)
imageoff = fido.askopenfilename(title ="Pick a Picture")
off = tk.PhotoImage(file = imageoff)
def turnOn():
button.config(image = on, text = "Turn on system", command = turnOff)
def turnOff():
button.config(image = off, text = "Turn off system", command = turnOn)
button = tk.Button(master, image = off, compound = "top")
button.grid(sticky = tk.NSEW)
turnOff()
master.mainloop()

Related

Buttons getting misplaced after using background image in Tkinter

Whenever I run this code with a background Image the button grid gets misplaced and pushed towards the bottom. Fortunately, it works as intended when no background is added .I want them to cover the background when executed. Pictures for reference are added below. Your help is highly appreciated.
# importing the module
import tkinter.messagebox
from tkinter import *
import random
# importing the module
# initialising tkinter
class window(Frame):
def __init__(self,master = None):
Frame.__init__(self,master)
self.master = master
# initialising tkinter
# creating the window
root = Tk()
app = window(root)
root.geometry("630x630")
root.title('Odd Even Game')
C = Canvas(root, bg="blue", height=250, width=300)
filename = PhotoImage(file = "BG.png")
background_label = Label(root,image=filename)
background_label.place(x=0, y=0, relwidth=1, relheight=1)
C.pack()
frame = Frame(root)
frame.pack()
# creating the window
# image
level_1e = "p1.png"
level_1o = "pe.png"
level_2e = "r1.png"
level_2o = "re.png"
# image
def create_cards(odd_image,even_image,next_level,fno,order,suc,err,w,h):
rx = random.randint(0,order-1)
ry = random.randint(0,order-1)
for i in range(0,order):
for j in range(0,order):
if i == rx and j == ry:
create_button(i,j,suc,odd_image,next_level,fno,odd_image,w,h)
else:
create_button(i,j,err,even_image,next_level,fno,odd_image,w,h)
def second_level(fno):
fno.pack_forget()
frame2 = Frame(root)
frame2.pack()
suc = "Congratulations! You have cleared level 2..Keep Going Buddy!"
err = "Wrong Answer..Don't give up yet!"
create_cards(level_2o,level_2e,final_level,frame2,4,suc,err,157.5,157.5)
def final_level(fno):
fno.pack_forget()
root.geometry("700x700")
ap = App(root)
# creating a button function
def create_button(x,y,msg,picture,next_level,fno,odd,w,h):
if picture == odd:
image = PhotoImage(file=picture)
click = Button(fno, image=image, width= w, height=h, bd = 0,command = lambda : [score_update(),next_level(fno),tkinter.messagebox.showinfo( "Odd One Out Project",msg)])
click.image = image
click.grid( row = x, column = y)
else:
image = PhotoImage(file=picture)
click = Button(fno, image=image, width= w, height=h, bd = 0,command = lambda : [next_level(fno),tkinter.messagebox.showinfo( "Odd One Out Project",msg)])
click.image = image
click.grid( row = x, column = y)
# creating a button function
def create_frame(fno):
root.geometry("630x630")
fno.pack_forget()
frame = Frame(root)
frame.pack()
suc = "Congratulations! You have cleared level 1..Time to increas[![enter image description here][1]][1]e the difficulty!"
err = "Wrong Answer..Please Try again !!"
create_cards(level_1o,level_1e,second_level,frame,3,suc,err,200,200)
def intro():
root.geometry("630x630")
frame0 = Frame(root)
frame0.pack()
click = Button(frame0,text="Start!" ,command = lambda [create_frame(frame0),tkinter.messagebox.showinfo( "Odd One Out Project","The game has begun!!")])
click.pack()
intro()
# starting the widget
root.mainloop()
# starting the widget
The first image is the error. Second Image is the required output.
Note: I'm still a beginner in Python and Tkinter hence various terms and methods might be something out of my scope. Would be appreciated if taken into consideration.
In case needed, you might know that this is a tkinter project for picking the odd one out image out of A*A grid.
I got the answer myself so will be sharing for future use.
C = Canvas(root, bg="blue", height=250, width=300)
This part draws a canvas of 250*300 dimensions hence does not let the buttons draw over it.
just change it to,
C = Canvas(root, bg="blue", height=0, width=0)
for the desired result

Title bar menu in tkinter

I think most of us must have seen the command prompt(windows) and how when we open it and click on it's icon and it shows a menu. Can we do a similar thing with tkinter? This is not the normal menubar.
Here is an illustration of the command prompt one.
This is just an exampel of a work around without the need of doing all your window management by your own. Of course it will need improvements but as a start: Popup stolen from
import tkinter as tk
from PIL import Image, ImageTk
def popup(event):
popup_menu.tk_popup(event.x_root, event.y_root, 0)
def set_icon():
global top, popup
top = tk.Toplevel(root)
top.overrideredirect(1)
top.attributes('-topmost',True)
offset = 30
x,y = root.winfo_rootx(),root.winfo_rooty()-offset
width, height = offset,offset
top.geometry("%dx%d+%d+%d" % (width,height, x,y))
my_label = tk.Label(top, image=photo)
my_label.pack(fill='both')
global popup_menu
popup_menu = tk.Menu(top, tearoff=0)
popup_menu.add_command(label="Delete",
command=lambda :print('del'))
popup_menu.add_command(label="Select All",
command=lambda :print('sel'))
top.bind("<Button-1>", popup)
def grab(event):
top.geometry(f'+{event.x+10}+{event.y+2}')
root=tk.Tk()
ico = Image.open('prac_img/p2.png')
photo = ImageTk.PhotoImage(ico)
root.iconphoto(False,photo)
#root.wm_iconphoto(False,photo)
root.bind('<Configure>',grab)
root.update_idletasks()
set_icon()
root.mainloop()
Another way would be to code your own titlebar and the use of overrideredirecr(1) which will undecorate your window by the window manager of your system.

How to get the entry text and display in another entry?

I just want that when I type my name inside the entry box then appears in another entry with some add text. The idea is type in the entry below and after that it showed in the big entry.I was looking for this solution, but just found place in Label. I don't want in Label. The window is more big, must drag to show the entry. There's is a picture that i use in this script:
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
cat = Entry(root)
cat.place(x=48, y=25, width= 350, height=140)
user = Entry(root)
user.place(x=75, y=550)
btn = Button(root, text='START')
btn.place(x=220, y=410)
root.mainloop()
#
Ok, It works the way you told me,thank you!
But now i'm facing another problem.
The problem is when i insert the function of the game in the second window. I tested in one window and it works, but when i place the function in the second window gives an error when i press the "Start" button:
'''user_try = int(txt.get())
NameError: name 'txt' is not defined'''
When i press reset button gives another error:
'''user_try = int(txt.get())
NameError: name 'txt' is not defined'''
So i know that is missing definition, but i don't know how to make a reference for this command that it's in the second window. Like i said running with just one window the program works.
Maybe i should make using class, i don't know, but i wish to make this way that i started. However if there's no other way to do as i'm doing, let's go.
I just simplify the script here, actualy the main script is more bigger, so my idea is when open the program, there is a window and the user read the instructions about the game and proceed open the second window. The window have pictures and some hidden buttons in the next picture, so there will be an interactivity with the environment.
The guess number is just the beggining. After that there will be new challeges.
I'm very excited doing this, but i'm stuck in this point. The part one i finished, the pictures, the hidden buttons it's exacly the way i want, but the challenge stops here in this problem.
from tkinter import *
from PIL import Image, ImageTk, ImageSequence
import random
from tkinter import messagebox
pc = random.randint(1,10)
def reset():
global pc
pc = random.randint(1,10)
cat['text'] = 'Ok! Lets Try Again!'
def openwin2():
win1.withdraw()
win2 = Toplevel()
win2.geometry('350x300+180+100')
win2.title('second window')
txt = Entry(win2)
txt.place(x=10,y=10)
cat = Label(win2,wraplength=300)
cat.place(x=10,y=50)
cat.config(text='Hi! I Am thinking a number between 1 and 10.')
btn = Button(win2,text='start',command=check)
btn.place(x=30, y=150)
btn2 = Button(win2, text='reset', command=reset)
btn2.place(x=110,y=150)
win2.mainloop()
def check():
user_try = int(txt.get())
if user_try < pc:
msg = 'Hmmmm... the number, which I thought of, is greater than this.'
elif user_try > pc:
msg = 'How about trying a smaller number ?!'
elif user_try == pc:
msg = 'Well Done! You guessed! It was %s the number!' % user_try
else:
msg = 'Something Went Wrong...'
cat['text'] = msg
win1 = Tk()
win1.title('First Window')
win1.geometry('350x300')
user = Label(win1,text='first window')
user.place(x=10,y=10)
btn1 = Button(win1,text='Open Window 2', command=openwin2)
btn1.place(x=10,y=50)
win1.mainloop()
There are multiple ways to do this in tkinter, here's a rework of your code using StringVar objects set to the textvariable properties of your Entry objects:
import tkinter as tk
def doit():
out_string.set("Hello " + in_string.get())
root = tk.Tk()
in_string = tk.StringVar()
out_string = tk.StringVar()
cat = tk.Entry(root, textvariable=in_string)
cat.place(x=20, y=25, width=100)
user = tk.Entry(root, textvariable=out_string)
user.place(x=20, y=75)
btn = tk.Button(root, text='START', command=doit)
btn.place(x=20, y=150)
root.mainloop()
Per #Mike-SMT, here's a different approach using Entry.get() and Entry.insert(). It augments the text when the user clicks the button:
import tkinter as tk
def doit():
user.insert(tk.END, cat.get())
root = tk.Tk()
cat = tk.Entry(root)
cat.place(x=20, y=25, width=100)
user = tk.Entry(root)
user.place(x=20, y=75)
user.insert(0, "Hello ")
btn = tk.Button(root, text='START', command=doit)
btn.place(x=20, y=150)
root.mainloop()
However, you'll see that subsequent button clicks keep appending the text. When working with Entry.insert(), you need to work with Entry.delete() and/or other Entry methods to properly manipulate the text.

Message is not printed Tkinter

When the user didn't chose any option, the code going into else, in if_button_ispressed function, and then I want to print an error message on the screen. I think I did all correct but the message is not shown on the screen.
import sys
from Tkinter import *
import Image, ImageTk
import ShareScreen
import Menu_WatchAnothersScreen
def if_button_is_pressed():
global user_selection, mGui
if(user_selection.get() == 1): # if the user want to share his screen
mGui.destroy()
ShareScreen.run()
#menu()
if(user_selection.get() == 2): # if the user want to watch another`s screen
mGui.destroy()
Menu_WatchAnothersScreen.run()
#menu()
else: # if the user didn`t chose any option <--------------- HERE IS MY PROBLEM
error_message = "Please select one of the options" #<--------------- HERE IS MY PROBLEM
error_label = Label(mGui, textvariable=error_message).pack(anchor=CENTER) # prints error message <--------------- HERE IS MY PROBLEM
def close(): # close the window
exit()
def menu():
global user_selection,mGui
mGui = Tk()
user_selection = IntVar()
menubar = Menu(mGui) # menu
filemenu = Menu(menubar, tearoff=0) # menu works
filemenu.add_command(label="Close", command=close)
menubar.add_cascade(label="File", menu=filemenu)
mGui.geometry('450x300+500+300')
mGui.title('Nir`s ScreenShare') # top of window
canvas = Canvas(mGui, width=500, height=150)
canvas.pack(pady = 10)
pilImage = Image.open("logo5.png")
image = ImageTk.PhotoImage(pilImage)# puts ScreenirShare`s logo on the menu
imagesprite = canvas.create_image(0, 0, image=image, anchor="nw")
Radiobutton(mGui, text="Share My Screen ", variable=user_selection, value=1).pack(anchor=CENTER) # 1 - FIRST OPTION - Share My Screen
Radiobutton(mGui, text="Watch Another`s Screen", variable=user_selection, value=2).pack(anchor=CENTER, pady = 7.5)# 2- SECOND OPTION - Watch Another`s Screen
start_button = Button(mGui, text='Start', command=if_button_is_pressed).pack() # Start Button
mGui.config(menu=menubar) # menu helper
mGui.mainloop()
menu()
If you are going to use plain string, you should use text option of label not textvariable.
Label(mGui, text=error_message)
If you want to use textvariable, you need StringVar, IntVar etc.
Also, packing on same line returns None, so you should pack after you create it if you want to use it again later.
error_label = Label(mGui, textvariable=error_message)
error_label.pack(anchor=CENTER)

can we code time in text widget?

Is it possible to code time HH:MM:SS using text widget?
I know we can do this with label widget. My code deals with text widget and want to display time at any corner on the TKinter window.
If possible how to delete and insert the text using label widgets. Text widget has the following methods default.
delete(startindex [,endindex])
This method deletes a specific character or a range of text.
insert(index [,string]...)
This method inserts strings at the specified index location.
In my code the text has to be deleted and inserted all the time.
thanks.
delete from 1.0 to end.
import datetime
text.delete('1.0', 'end')
text.insert('end', datetime.datetime.now().strftime('%H:%M:%S')) # text.insert('end', label['text'])
label['text'] = datetime.datetime.now().strftime('%H:%M:%S')
Display Entry on bottom right
import datetime
from Tkinter import * # from tkinter import * # Python 3.x
root = Tk()
root.geometry('500x500')
frame = Frame(root)
frame.pack(side=BOTTOM, fill=BOTH)
entry = Entry(frame)
entry.pack(side=RIGHT)
entry.insert(END, datetime.datetime.now().strftime('%H:%M:%S'))
root.mainloop()
def __init__(self):
tk.Tk.__init__(self)
self.geometry("1360x750")
frameLabel = tk.Frame(self)
self.text = tk.Text(frameLabel)
frameLabel.pack(side=BOTTOM, fill=BOTH)
self.text.pack(side=RIGHT)
self.text.insert('end', 'TEST')
self.queue = Queue.Queue()
thread = SerialThread(self.queue)
thread.start()
self.process_serial()
UPDATE2
import datetime
from Tkinter import * # from tkinter import * # Python 3.x
root = Tk()
root.geometry('500x500')
frame = Frame(root)
frame.pack(side=BOTTOM, fill=BOTH)
label = Label(frame)
label.pack(side=RIGHT)
label['text'] = datetime.datetime.now().strftime('%H:%M:%S')
root.mainloop()

Categories

Resources