tkinter insert into output text field (output.insert()) is not working - python-3.x

I have a Tkinter GUI, Where i have a input text field and output text field and
a button. User typying anything in text field and clicking the button then it have to be printed in the output field. But here the input values are not inserting into the output field.
from tkinter import *
base = Tk()
base.title('Demo')
base.geometry("400x500")
base.resizable(width=FALSE, height=FALSE)
outputwindow = Text(base, bd=0, bg="white", height="8", width="50", font="Arial",)
# outputwindow.insert(END, "Connecting to your partner..\n")
outputwindow.config(state=DISABLED)
#Bind a scrollbar to the Chat window
scrollbar = Scrollbar(base, command=outputwindow.yview, cursor="heart")
outputwindow['yscrollcommand'] = scrollbar.set
EntryBox = Text(base, bd=0, bg="white",width="29", height="5", font="Arial")
def ClickAction():
input=EntryBox.get("1.0",END)
print(input)
EntryBox.delete('1.0',END)
outputwindow.insert(END, input)
SendButton = Button(base, font=30, text="Send", width="12", height=5,bd=0, bg="lightgray", command=ClickAction)
#Place all components on the screen
scrollbar.place(x=376,y=6, height=386)
outputwindow.place(x=6,y=6, height=386, width=370)
EntryBox.place(x=128, y=401, height=90, width=265)
SendButton.place(x=6, y=401, height=90)
base.mainloop()
I have tried other programs for this same purpose, it works fine. But here i can't process and i can't find the issue.(i'm just learning tkinter)

When a text widget is disabled you can't put text in it, not even with .insert() or .delete(). To modify the text you need to change the state to normal, insert your text and then change the state back to disabled:
outputwindow.config(state=NORMAL)
outputwindow.insert(END, input)
outputwindow.config(state=DISABLED)

Related

How to remove focus from Text block by clicking outside it

I want to create a program using tkinter. The goal is to remove the focus from Text widget by clicking somewhere outside it. I've tried this:
import tkinter as tk
root = tk.Tk()
txt = tk.Text(root)
txt.pack()
root.bind('<Button-1>', lambda event: root.focus_set())
#txt.bind('<Button-1>', lambda event: txt.focus_set()) <- it doesn't work with this too
root.mainloop()
But this just sets focus to root every time i press B1 (in both variants). Help, please!
You could detect the current widget under the mouse coordinates and use this to determine if you should focus on root or not:
def click_event(event):
x,y = root.winfo_pointerxy() # get the mouse position on screen
widget = root.winfo_containing(x,y) # identify the widget at this location
if (widget == ".text_widget") == False: # if the mouse is not over the text widget
root.focus() # focus on root
text_widget = tk.Text(root, name="text_widget")
text_widget.pack()
root.bind("<Button-1>", click_event)

How can I change the state of a menu with a button inside tkinter?

I want to make a unit converter in tkinter. I made two drop-down menus; the first one allows the user to select the unit they want to convert from, and the second one allows them to choose the unit they want to convert to. I want to disable all the options that do not make sense in the second menu after they have selected an option in the first one (if they want to convert kilograms it would not make sense to choose centimeters in the second menu)
I have tried to use a StringVar() to change the state of the menu, but it is not working. I have no idea of what to do next. I have been using the documentation of Tutorialspoint, but I cannot find anything that works (first time using tkinter).
import tkinter as tk
root = tk.Tk()
root.geometry('600x600')
my_var = tk.StringVar()
my_var.set('active')
unit_1 = tk.Menubutton(root,text='This is the first menu button',bg='white',activebackground='#2E64FE',activeforeground='#FFFFFF')
menu_1 = tk.Menu(unit_1)
unit_1.config(menu=menu_1)
menu_1.add_command(label='Inches',command= lambda: my_var.set('disabled') )
menu_1.add_command(label='Kilograms')
unit_2 = tk.Menubutton(root,text='This is the second menu button',bg='white',activebackground='#2E64FE',activeforeground='#FFFFFF')
menu_2 = tk.Menu(unit_2)
unit_2.config(menu=menu_2)
menu_2.add_command(label='Centimeters')
menu_2.add_command(label='Pounds',state= my_var.get())
unit_1.place(relx=0.03,rely=0.08,relheight=0.04,relwidth=0.45)
unit_2.place(relx=0.52,rely=0.08,relheight=0.04,relwidth=0.45)
root.mainloop()
Here I am trying to make the button 'Inches' in the first menu to disable the button 'Pounds' in the second menu, but when I click on 'Inches' nothing happens to 'Pounds'.
tk.StringVar() is used to change text on something, for example if you want to have a button with dynamic text, you may want to use a tk.StringVar() for that.
What you want to do is something different; you want to change the configuration of a label. So you need to find the element and adjust its state:
import tkinter as tk
root = tk.Tk()
root.geometry('600x600')
my_var = tk.StringVar()
my_var.set('active')
unit_1 = tk.Menubutton(root,text='This is the first menu button',bg='white',activebackground='#2E64FE',activeforeground='#FFFFFF')
menu_1 = tk.Menu(unit_1)
unit_1.config(menu=menu_1)
menu_1.add_command(label='Inches', command=lambda: disable_pounds())
menu_1.add_command(label='Kilograms', command=lambda: disable_centimeters())
unit_2 = tk.Menubutton(root,text='This is the second menu button',bg='white',activebackground='#2E64FE',activeforeground='#FFFFFF')
menu_2 = tk.Menu(unit_2)
unit_2.config(menu=menu_2)
menu_2.add_command(label='Centimeters')
menu_2.add_command(label='Pounds',state= my_var.get())
unit_1.place(relx=0.03,rely=0.08,relheight=0.04,relwidth=0.45)
unit_2.place(relx=0.52,rely=0.08,relheight=0.04,relwidth=0.45)
def disable_pounds():
menu_2.entryconfig("Pounds", state="disabled")
menu_2.entryconfig("Centimeters", state="active")
def disable_centimeters():
menu_2.entryconfig("Pounds", state="active")
menu_2.entryconfig("Centimeters", state="disabled")
root.mainloop()

How to enter text into two text widgets by just entring into same widget

I want a method from which I can insert text into two widgets by entering text into single text widget. Simply in programming is I want to bind all functions and events of text widget to another text widget.
i had tried
txt=Text(root,height=300,width=300)
txt.pack()
text=Text(root,height=300,width=300)
text.pack()
def func(event):
text.delete("1.0","end")
text.insert(INSERT,txt.get("1.0","end"))
txt.bind(func,<Any-KeyPress>)
but it is not a good option because it is taking time and it shows some delay, and some long delay when the text goes long.
If you want the contents of the two text widgets to be identical, the text widget has a little-used feature known as peer widgets. In effect, you can have multiple text widgets that share the same underlying data structure.
The canonical tcl/tk documentation describes peers like this:
The text widget has a separate store of all its data concerning each line's textual contents, marks, tags, images and windows, and the undo stack.
While this data store cannot be accessed directly (i.e. without a text widget as an intermediary), multiple text widgets can be created, each of which present different views on the same underlying data. Such text widgets are known as peer text widgets.
Unfortunately, tkinter's support of text widget peering is not complete. However, it's possible to create a new widget class that makes use of the peering function.
The following defines a new widget, TextPeer. It takes another text widget as its master and creates a peer:
import tkinter as tk
class TextPeer(tk.Text):
"""A peer of an existing text widget"""
count = 0
def __init__(self, master, cnf={}, **kw):
TextPeer.count += 1
parent = master.master
peerName = "peer-{}".format(TextPeer.count)
if str(parent) == ".":
peerPath = ".{}".format(peerName)
else:
peerPath = "{}.{}".format(parent, peerName)
# Create the peer
master.tk.call(master, 'peer', 'create', peerPath, *self._options(cnf, kw))
# Create the tkinter widget based on the peer
# We can't call tk.Text.__init__ because it will try to
# create a new text widget. Instead, we want to use
# the peer widget that has already been created.
tk.BaseWidget._setup(self, parent, {'name': peerName})
You use this similar to how you use a Text widget. You can configure the peer just like a regular text widget, but the data will be shared (ie: you can have different sizes, colors, etc for each peer)
Here's an example that creates three peers. Notice how typing in any one of the widgets will update the others immediately. Although these widgets share the same data, each can have their own cursor location and selected text.
import tkinter as tk
root = tk.Tk()
text1 = tk.Text(root, width=40, height=4, font=("Helvetica", 20))
text2 = TextPeer(text1, width=40, height=4, background="pink", font=("Helvetica", 16))
text3 = TextPeer(text1, width=40, height=8, background="yellow", font=("Fixed", 12))
text1.pack(side="top", fill="both", expand=True)
text2.pack(side="top", fill="both", expand=True)
text3.pack(side="top", fill="both", expand=True)
text2.insert("end", (
"Type in one, and the change will "
"appear in the other."
))
root.mainloop()
The quickest way to update text in a 2nd box that I have found is to use replace() and get(). That said after testing your example I am not really seeing a noticeable delay.
We can use the Modified event to manage our updates and after each modification we can tell text1 that Modified is False so we get an update on every change.
Let me know if this was what you were looking for.
Try this:
import tkinter as tk
def update_text2(_=None):
text2.replace('1.0', 'end', text1.get('1.0', 'end'))
text1.edit_modified(False)
root = tk.Tk()
text1 = tk.Text(root)
text2 = tk.Text(root)
text1.pack()
text2.pack()
text1.bind('<<Modified>>', update_text2)
root.mainloop()

Display and Hide PNG image in Tkinter Python3

Like the topic,
how can I display a .png image and hide it? And what is the difference between canvas and photoimage?
I wrote a bit of code which hides/shows an image on the click of a button. You can edit it to fit your needs.
NOTE: At the moment, I'm using pack(), and pack_forget(), if you want to use grid or place, you must use grid_forget() or place_forget()
import tkinter
def hideBG():
global state
if state == "Hidden":
background_label.pack()
state = "Showing"
elif state == "Showing":
background_label.pack_forget()
state = "Hidden"
window = tkinter.Tk()
background_image=tkinter.PhotoImage(file="BG.png")
background_label = tkinter.Label(window, image=background_image)
hideBttn = tkinter.Button(window, text="Hide Background", command=hideBG)
state = "Showing"
hideBttn.pack()
background_label.pack()
window.mainloop()
This creates an image within a label, and a button. The button takes the current "state" of the image (whether it is hidden or showing), and changes it to the opposite, by calling the hideBG function when the button is pressed.
Hope this helps!

Getting text from a entry window in Python graphics

from graphics import *
win = GraphWin("Hangman", 600, 600)
win.setBackground("yellow")
textEntry = Entry(Point(233,200),10)
textEntry.draw(win)
text = textEntry.getText()
testText = Text(Point(150,15), text)
testText.draw(win)
exitText = Text(Point(200,50), 'Click anywhere to quit')
exitText.draw(win)
win.getMouse()
win.close()
I'm trying to obtain text from the user in Python graphics and be able to use that input, such as manipulate it, search for it in a list, etc. To test that, I created a entry window in graphics and tried to obtain the text from that entry window and simply display it in the window, just to check if it sucessfully obtained the text.
Unfortunately, it isn't working, it just shows the 'Click anywhere to quit' and then the empty window and despite writing text in it it does nothing. What am I doing wrong?
The following comes from the documentation.
The way the underlying events are hidden in graphics.py, there is no signal when the user is done entering text in an Entry box. To signal the program, a mouse press is used above. In this case the location of the mouse press is not relevant, but once the mouse press is processed, execution can go on and read the Entry text.
You're getting the text right after you draw the Entry, so it will be empty. You need to wait for a signal, then read the Entry. This excerpt from the documentation says to wait for a mouse click then read the Entry.
So try to add the
win.getMouse()
to your code as follows
from graphics import *
win = GraphWin("Hangman", 600, 600)
win.setBackground("yellow")
textEntry = Entry(Point(233,200),50)
textEntry.draw(win)
# click the mouse to signal done entering text
win.getMouse()
text = textEntry.getText()
testText = Text(Point(150,15), text)
testText.draw(win)
exitText = Text(Point(200,50), 'Click anywhere to quit')
exitText.draw(win)
win.getMouse()
win.close()
Here's what the output looks like. Note: I made the Entry 50 wide.

Resources