Tkinter text-widget insertion of images - python-3.x

I made a text widget to write questions. I want to insert images when add image button is pressed. How can I do that? When I choose another image the first one is deleted. Right now I am able to add one image using the code:
import tkinter as tk
root = tk.Tk()
root.geometry('800x520+0+0')
global img
img = tk.PhotoImage(file="quiz.gif")
def add_img():
T.image_create(tk.INSERT, image=img)
tk.Button(root, text="Add Image", font=('Verdana',8),
command=add_img).place(x=690, y=0)
T = tk.Text(root, width=65, height=17, padx=10, pady=10, font=('Verdana',
14), wrap='word')
T.place(x=0, y=0)
root.mainloop()
I want to add different images when chosen using tk-listbox.
Thanks for the help.

I used dictionary to solve the problem.
import tkinter as tk, glob
root = tk.Tk()
root.geometry('800x520+0+0')
Images = {}
for infile in glob.glob('*.gif'):
img = infile[:-4]
if img not in Images:
Images[img] = tk.PhotoImage(file=infile)
def add_img():
global listbox
listbox = tk.Listbox(root, font=('Verdana',9), width=12)
listbox.place(x=60,y=2)
for infile in glob.glob('*.gif'):
listbox.insert(tk.END, infile[:-4])
listbox.bind('<<ListboxSelect>>',CurSelet)
def CurSelet(event):
fn = listbox.get(tk.ANCHOR)
listbox.destroy()
T.image_create(tk.INSERT, image=Images[fn])
tk.Button(root, text="Add Image", font=('Verdana',8),
command=add_img).place(x=690,y=0)
T = tk.Text(root, width=65, height=17, padx=10, pady=10, font=('Verdana',
14), wrap='word')
T.place(x=0, y=50)
root.mainloop()

Related

Make multiple tk.Toplevel windows embedded/unified in main tk window

So I'm trying to create a program which uses multiple tk.Toplevel windows. The problem with this is, that all windows show up seperated as their "own App", so when you alt tab, you switch between the toplevel windows.
The pseudocode would look something like this:
import tkinter as tk
top_levels = {}
def open_toplevel():
top_level = tk.Toplevel(root)
top_level.geometry("300x200+0+0")
top_levels.update({f"toplevel{len(top_levels.keys())}" : top_level})
root = tk.Tk()
button = tk.Button(root, command= open_toplevel)
button.place(x=0, y=0)
root.mainloop()
So my question, is: is there a way to unify them into "one window"?
If you want all of them to unify into one window then tk.Frame is a better widget to use instead of tk.Toplevel
The purpose of tk.Toplevel is to create a new temporary window, not an extra part of the window. But frames are a really good way to organise stuff.
This code below creates new frame every time you click the button. This is just a simple example. You can also use grid for widgets in a frame. I also put a border so you can see where the frames are located.
from tkinter import *
def open_frame():
frame = Frame(root, highlightbackground="black", highlightthickness=2)
lbl1 = Label(frame, text=f"Frame {len(frames) + 1} label 1")
lbl2 = Label(frame, text=f"Frame {len(frames) + 1} label 2")
lbl1.pack()
lbl2.pack()
frame.pack(padx=5, pady=5)
frames.append(frame)
root = Tk()
frames = []
btn = Button(root, text="Open Frame", command=open_frame)
btn.pack()
root.mainloop()
I hope this solution is helpful
EDIT
Use this code here to move the frames:
from tkinter import *
def open_frame():
global frame, frames
frame = Frame(root, highlightbackground="black", highlightthickness=2)
lbl1 = Label(frame, text=f"Frame {len(frames) + 1} label 1")
lbl2 = Label(frame, text=f"Frame {len(frames) + 1} label 2")
lbl1.pack()
lbl2.pack()
frame.pack(padx=5, pady=5)
frame_number = len(frames)
lbl1.bind('<B1-Motion>', lambda event: MoveWindow(event, frame_number))
lbl2.bind('<B1-Motion>', lambda event: MoveWindow(event, frame_number))
frame.bind('<B1-Motion>', lambda event: MoveWindow(event, frame_number))
frames.append(frame)
labels.append(lbl1)
labels.append(lbl2)
def MoveWindow(event, frame_number):
global root, frames
root.update_idletasks()
f = frames[frame_number]
x = f.winfo_width()/2
y = f.winfo_height()*1.5
f.place(x=event.x_root-x, y=event.y_root-y)
root = Tk()
root.geometry("500x500")
frames = []
labels = []
btn = Button(root, text="Open Frame", command=open_frame)
btn.pack()
root.mainloop()

Please help me find the error in the code?

I am trying to put a frame inside another frame in tkinter. Can someone explain why it isn't working? I am just starting to learn Tkinter.
from tkinter import *
from PIL import *
if __name__=="__main__":
root = Tk()
root.title("Sales")
root.geometry("1440x855")
root.resizable(0, 0)
Label(root, text = 'Tax Invoice').pack(side = TOP, pady = 6)
frame1 = Frame(root,bg="black",width=1400,height=780).pack()
frame2 = Frame(frame1,bg="green",width=100,height=100).pack()
top.mainloop()
Try this:
import tkinter as tk
if __name__ == "__main__":
root = Tk()
root.title("Sales")
root.geometry("1440x855")
root.resizable(False, False)
label = tk.Label(root, text="Tax Invoice")
label.pack(side="top", pady=6)
frame1 = Frame(root, bg="black", width=1400, height=780)
frame1.pack()
frame2 = Frame(frame1, bg="green", width=100, height=100)
frame2.pack()
root.mainloop()
Basically applying what #Ramesh and I said in the comments.

name 'main_window' is not defined

from tkinter import *
def create_main_window():
global main_window
main_window = Toplevel()
main_window.update()
entrance_window = Tk()
first_text_label = Label(entrance_window, text="you are in:").grid(row=0, column=0)
place_entry = Entry(entrance_window).grid(row=0, column=1)
submit_button = Button(entrance_window, text="Submit", command=create_main_window).grid(row=1, column=0, columnspan=2)
Label(main_window, text=f"{place_entry}").pack()
entrance_window.mainloop()
the program should open a new window with the text from the entry box from the first window but it either shows None if I write
Label(main_window, text=f"{place_entry}").pack()
in the create_main_window or it gives me an error saying that main_window is not defined if I write it after the button code.
Can someone help with this?
Try this:
from tkinter import *
def create_main_window():
global main_window
main_window = Toplevel(main_window)
label = Label(main_window, text=f"{place_entry.get()}")
label.pack()
# main_window.update() # This is useless
entrance_window = Tk()
first_text_label = Label(entrance_window, text="You are in:")
first_text_label.grid(row=0, column=0)
place_entry = Entry(entrance_window)
place_entry.grid(row=0, column=1)
submit_button = Button(entrance_window, text="Submit", command=create_main_window)
submit_button.grid(row=1, column=0, columnspan=2)
entrance_window.mainloop()
I moved the label creation inside create_main_window. Also please note that using var = a().b(), saves what ever b() returns inside var. That is why when you use var = Entry(...).pack(...), var is always None.
This is because you are trying to add a Label to an object that doesn't exist. Move the Label function to the create_main_window() function, like below:
from tkinter import *
def create_main_window():
global main_window, entrance_window
main_window = Toplevel()
place_entry = Entry(entrance_window).grid(row=0, column=1)
Label(main_window, text=f"{place_entry}").pack()
main_window.update()
entrance_window = Tk()
first_text_label = Label(entrance_window, text="you are in:").grid(row=0, column=0)
submit_button = Button(entrance_window, text="Submit", command=create_main_window).grid(row=1, column=0, columnspan=2)
entrance_window.mainloop()

How do I overlay these buttons on top of an image for a background in Python Tkinter

Currently, I'm attempting to create a simple main menu for a game using Tkinter as a simple GUI since it's a simple RPG game and Python however the image overlays the buttons in all circumstances.
I've tried using some other solutions like placing them or creating a window but I can't find a straight answer of how to make that either.
import tkinter
from tkinter import *
from PIL import ImageTk, Image
(PIL is from when I was using a JPG before.)
root = Tk()
content = ttk.Frame(root)
root.geometry("600x600")
background = ImageTk.PhotoImage(Image.open("bred.png"))
canvas = tkinter.Canvas(root, width=580, height=600)
content.grid(column=0, row=0)
Btn1 = Button(content, text="Play", width=5, height=1)
Btn2 = Button(content, text="Kill me", width=7, height=1, command =
root.quit)
backgroundlabel = tkinter.Label(root, image=background)
backgroundlabel.image = background
backgroundlabel.place(x=0, y=0, relwidth=1, relheight=1)
Btn1.grid(row=1, column=2, padx=(130))
Btn1.columnconfigure(1, weight=1)
Btn1.rowconfigure(1, weight=1)
Btn2.grid(row=1, column=3, pady=(130))
Btn2.columnconfigure(3, weight=1)
Btn2.rowconfigure(1, weight=1)
root.mainloop()
Currently your background's master is set to root while your buttons are set to a frame. The first thing you need to do is set both to the same master, i.e. changing background master to content:
backgroundlabel = tk.Label(content, image=background)
Next you need to deal with the stacking order. You can call widget.lift() to raise the buttons to top:
Btn1.grid(row=1, column=2, padx=(130))
...
Btn1.lift()
Btn2.grid(row=1, column=3, pady=(130))
...
Btn2.lift()

Multiple line text entry box in python

In python i have been making a text editor like Microsoft word but i don't know how to make a text entry box for the user to put input. Here is my code! (ps thank you!)
from tkinter import *
import sys
def doNothing():
print("Test")
root = Tk()
root.title("TextEditor")
root.geometry("300x200")
menu = Menu(root)
root.config(menu=menu)
subMenu = Menu(menu)
menu.add_cascade(label="File", menu=subMenu)
subMenu.add_command(label="New Project...", command =doNothing)
subMenu.add_command(label="Save", command=doNothing)
subMenu.add_separator()
editMenu = Menu(menu)
menu.add_cascade(label="Edit", menu=editMenu)
editMenu.add_command(label="Undo",command=doNothing)
root.mainloop()
You can do that like this:
TextArea = Text()
TextArea.pack(expand=YES, fill=BOTH)
If you want a scrollbar with it:
TextArea = Text()
ScrollBar = Scrollbar(root)
ScrollBar.config(command=TextArea.yview)
TextArea.config(yscrollcommand=ScrollBar.set)
ScrollBar.pack(side=RIGHT, fill=Y)
TextArea.pack(expand=YES, fill=BOTH)
Hope this helped, good luck!
It is an old question but currently following is a very good method for scrollable multiline text entry:
ScrolledText(mainwin, width=50, height=5).pack()
Full program:
from tkinter import *
from tkinter.scrolledtext import ScrolledText
mainwin = Tk()
ScrolledText(mainwin, width=50, height=5).pack()
mainwin.mainloop()
Following demo application shows its usage further and comparison with entry box (for python3):
from tkinter import *
from tkinter.scrolledtext import ScrolledText
mainwin = Tk()
Label(mainwin, text="An Entry Box:").grid(row=0, column=0)
ent = Entry(mainwin, width=70); ent.grid(row=0, column=1)
Button(mainwin, text="Print Entry", command=(lambda: print(ent.get()))).grid(row=0, column=2, sticky="EW")
Label(mainwin, text="ScrolledText Box:").grid(row=1, column=0)
st = ScrolledText(mainwin, height=5); st.grid(row=1, column=1)
Button(mainwin, text="Print Text", command=(lambda: print(st.get(1.0, END)))).grid(row=1, column=2, sticky="EW")
Button(mainwin, text="Exit", command=sys.exit).grid(row=2, column=0, columnspan=3, sticky="EW")
mainwin.mainloop()

Resources