Widgets disappear after tkMessageBox in Tkinter - python

Every time I use this code in my applications:
tkMessageBox.showinfo("Test", "Info goes here!")
a message box pops up (like it is supposed to), but after I click OK, the box disappears along with most of the other widgets on the window. How do I prevent the other widgets from disappearing?
Here Is My Code:
from Tkinter import *
import tkMessageBox
root = Tk()
root.minsize(600,600)
root.maxsize(600,600)
p1 = Label(root, bg='blue')
p1.place(width=600, height=600)
b1 = Button(p1, text="Test Button")
b1.place(x="30", y="50")
tkMessageBox.showinfo("Test", Info")
root.mainloop()

Ok, there are a few things going wrong here. First, your label has no string or image associated with it. Therefore, it's width and height will be very small. Because you use pack, the containing widget (the root window) will "shrink to fit" around this widget and any other widgets you pack in the root window.
Second, you use place for the button which means its size will not affect the size of the parent. Not only that, but you place the button inside the very tiny label. Thus, the only thing controlling the size of the parent is the label so the main window ends up being very small.
You have another problem is that you're showing the dialog before entering the event loop. I'm a bit surprised that it even works, but Tkinter sometimes does unusual things under the covers. You should enter the event loop before calling the dialog.
Try this variation of your code as a starting point:
from Tkinter import *
import tkMessageBox
def showInfo():
tkMessageBox.showinfo("Test","Info")
root = Tk()
p1 = Label(root, bg='blue', text="hello")
p1.pack()
b1 = Button(root, text="Test Button", command=showInfo)
b1.pack()
root.mainloop()

Related

How to delete buttons on Tkinter?

I really need to be able to delete a button onscreen into a label. All I need to do is remove the button, and put the label in place of it. However, I do not know how to remove buttons.
I am running Windows 10, Python 3.9.2.
Are you looking for something like this?:
import tkinter as tk
def remove_button():
global label
# Get the grid parameters passed in button when it was created
button_grid_info = button.grid_info()
button.grid_forget()
label = tk.Label(button_grid_info["in"], text="This is a Label widget")
# Put the label exactly where the button was:
label.grid(**button_grid_info)
root = tk.Tk()
button = tk.Button(root, text="Click me", command=remove_button)
button.grid(row=1, column=1)
root.mainloop()
grid_forget removes the widget without destroying it. If you used <button>.pack, use pack_forget. If you used <button>.place, use place_forget.

Prevent scrolledtext from taking up entire parent window disallowing other widgets from showing up

So I am actually writing a simple GUI program which makes use of ScrolledText widget from tkinter.scrolledtext module.
The problem is this ScrolledText widget seems to take up the complete space available in the parent window. It disallows me from putting in any other widget in the same parent window. I have tried using both grid and pack GeoManagers (i know place isn't very useful in all cases), but the other widgets won't show up (neither above the scrolledtext widget nor below it).
HERE IS THE CODE--
import tkinter as tk
import tkinter.scrolledtext as sct
win2 = tk.Tk()
win2.geometry('1150x680')
win2.wm_geometry('+80+20')
txtbox = sct.ScrolledText(win2, width=500, height=350, bg='#fff', fg='#00f')
txtbox.grid(row=0, column=0)
txt = '<ABOUT 60 Lines TEXT HERE>'
txtbox.insert(1.0, txt)
txtbox.configure(state=tk.DISABLED)
tk.Button(win2, text='Got It', command=win2.destroy).grid(row=1, column=0)
This code is actually a part of a static method (i don't think makes a difference). When this is run the only thing visible on the screen is the scrolledtext widget with those 60 lines (i have tried it with 2 lines as well - still doesn't work).
The same happens when using pack().
To my surprise the only thing i could find in documentation is this::
ScrolledText Documentation
I don't know what I am missing here so please suggest me a way around this.
Thanks You :)
Solution with grid
The problem is the configuration of the grid: by default, the grid cells expand to fit the content. In your case the text widget is so big that the button in the row below is out of the screen. To fix that, you need to configure the first row and column to stretch with the GUI:
win2.rowconfigure(0, weight=1)
win2.columnconfigure(0, weight=1)
and make the text widget fill the cell, using the sticky option:
txtbox.grid(row=0, column=0, sticky='ewns')
This way the text widget will adapt to the window size and not the other way around.
Full code:
import tkinter as tk
import tkinter.scrolledtext as sct
win2 = tk.Tk()
win2.geometry('1150x680')
win2.wm_geometry('+80+20')
win2.rowconfigure(0, weight=1)
win2.columnconfigure(0, weight=1)
txtbox = sct.ScrolledText(win2, width=500, height=350, bg='#fff', fg='#00f')
txtbox.grid(row=0, column=0, sticky='ewns')
txt = '<ABOUT 60 Lines TEXT HERE>'
txtbox.insert(1.0, txt)
txtbox.configure(state=tk.DISABLED)
tk.Button(win2, text='Got It', command=win2.destroy).grid(row=1, column=0)
Alternative method, using pack
You can use pack with the options fill='both' and expand=True to achieve the same result as with grid. In this case, the additional trick is to pack the button first to ensure that it has enough space to show in the window. Code:
import tkinter as tk
import tkinter.scrolledtext as sct
win2 = tk.Tk()
win2.geometry('1150x680')
win2.wm_geometry('+80+20')
tk.Button(win2, text='Got It', command=win2.destroy).pack(side='bottom')
txtbox = sct.ScrolledText(win2, width=500, height=350, bg='#fff', fg='#00f')
txtbox.pack(fill='both', expand=True)
txt = '<ABOUT 60 Lines TEXT HERE>'
txtbox.insert(1.0, txt)
txtbox.configure(state=tk.DISABLED)

How to remove focus out of a Text widget in Tkinter, Python

By placing a Text widget in my GUI
from Tkinter import Text
textBox=Text(root, height=20, width=10)
textBox.pack()
whenever I write something in that box, I cant return the focus back to any other place in the window. I have some keys bounded to event, which stop working after I wrote in the Text widget.
Is there a way of redirecting the focus to another place after writing text?
Please press Return-Key to give focus back to window
import tkinter as tk
def onReturn(*event):
root.focus_set()
root = tk.Tk()
textBox= tk.Text(root, height=20, width=10)
textBox.pack()
root.bind("<Return>", onReturn)
root.mainloop()
Is there a way of redirecting the focus to another place after writing text?
Every widget has a method named focus_set which can be used to move keyboard focus to that widget.
For example, to set the focus to the root window you would do:
root.focus_set()

Drawing on tkinter canvas from command line

I read some tutorial (basic) on tkinter and learned how to create a mainloop and add gui elements to that. Also learned how to bind actions to button widgets.
Now I would like to do this:
launch the tkinter canvas
be able to read command from the console and update the canvas after those commands.
example:
I write command with arguments on the console and some graphics elements is being added to the canvas (and canvas is updated after).
Is something possible, maybe threding related?
Can you point me in one direction which you think is the most reasonable to follow?
Here's a simple demo of grabbing user input from the console via the standard input function. This technique is a little clunky, since we have to explicitly tell Tkinter to fetch the input string by clicking on a Button (or some other GUI event), but that might not be a big deal for your application.
import tkinter as tk
root = tk.Tk()
stuff = tk.StringVar()
display = tk.Label(root, textvariable=stuff)
display.pack()
def get_input():
s = input("CMD: ")
stuff.set(s)
tk.Button(root, text="Get input", command=get_input).pack()
root.mainloop()
When you click on the "Get input" Button, the "CMD: " prompt will be printed in the console window. Once the input is entered, the string is copied to the Label. Bad Thingsā„¢ will happen if you click the button again before the input line is entered. :)
Came up with this:
from Tkinter import *
import random
root = Tk()
width = 800
height = 600
def key(event):
s = raw_input("CMD: ")
if s == 'quit':
root.destroy()
if s == 'l':
x1 = random.randint(0,width)
x2 = random.randint(0,width)
y1 = random.randint(0,height)
y2 = random.randint(0,height)
frame.create_line(x1,y1,x2,y2)
frame.focus_force()
frame = Canvas(root, width=width, height=height)
frame.bind("<Key>", key)
frame.pack()
frame.focus_set()
root.mainloop()
In this way it is a bit complicated because before entering something on the console I have to get the focus back clicking on its window. Maybe it would be nicer to read command from Tkinter directly and then opening dialogs for setting up command parameters.

Python Tkinter Toplevel

I am working on a program that requires multiple windows, and the first one to appear is the login window, I used the Toplevel widget in order to make other windows its children, but this code keeps showing two windows instead of one.
from Tkinter import Frame, Toplevel
from ttk import Label, Entry, Button
class loginWindow(Toplevel):
def __init__(self):
Toplevel.__init__(self)
self.title("Title")
self.frame = Frame(self)
self.frame.pack()
self.__make_layout()
self.mainloop()
def __make_layout(self):
self.frame.user_name_label = Label(text="User name:")
self.frame.user_name_text = Entry()
self.frame.user_name_label.grid(row=0, column=0)
self.frame.user_name_text.grid(row=0, column=1)
self.frame.password_label = Label(text="Password:")
self.frame.password_text = Entry()
self.frame.password_label.grid(row=1, column=0)
self.frame.password_text.grid(row=1, column=1)
self.frame.login_button = Button(text="Login")# , command=self.__create_window)
self.frame.login_button.grid(row=2, column=0, columnspan=2)
if __name__ == '__main__':
win1 = loginWindow()
All of the widgets created in _make_layout are created without a parent. This means they're children of the default root. You need to pass a parent to each of them, the same way you do to the Frame. Like this:
self.frame.user_name_label = Label(self.frame, text="User name:")
self.frame.user_name_text = Entry(self.frame)
# etc.
When I run your exact code, I don't get a second window, on any platform I try. The closest I get is on OS X, where an entry for the default root window appears in the Window menu, but the window itself still doesn't appear and the widgets all end up on the Toplevel (although not on the Frame where you wanted them). But it certainly would be legal for Tkinter to show a second window here, and put some or all of your widgets on it.
This must be a platform dependent issue, since abarnert isn't having issues with multiple windows. I use OS X with XQuartz and the following code gives me two windows:
from Tkinter import Toplevel, Tk
Toplevel().mainloop()
However, this code gives me one window:
from Tkinter import Toplevel, Tk
Tk().mainloop()
I believe your first window should be declared Tk() and subsequent windows should be Toplevel().

Categories

Resources