How to place a button on the TopLevel window in tkinter python? - python-2.7

Answer as pointed out down for other innocent newbies like me
in python2, we have Tkinter
In python3, we have tkinter.
Notice the difference in casing. Thats the reason, why error was coming up.
I have two screens: window(child) and root(master)
I am trying to place a button on the "window" screen created by the method: command(). I have written this piece of code.
from tkinter import *
root = Tk()
def writeText():
print "hello"
def command():
window=Toplevel(root)
Button(window,text="Button2",command=writeText).grid()
Label(window,text="hello").grid()
button = Button(root, text="New Window", command=command)
button.grid()
root.mainloop()
But this button2 is not appearing on the second screen. Meanwhile, Label is appearing on this screen. And the control is going into the writeText() function.
And when I remove the command argument from the Button of window screen, the button appears.
Can anyone please help me with this?

Here is my suggestion.
From your question you have put from tkinter import * however in your tags you put Python 2.7. This is contradictory because tkinter(all lower case) is used in Python 3.x and Tkinter should instead be used for python 2.x. That said try fixing your import first. If you are in fact using Python 3 then you will need to correct your print statement to include brackets. print("hello")
2nd I would try to follow PEP8 more closely however in this case I don't see anything out of the ordinary that would cause this issue.
Take my below example and let me know if you are still having the same problem.
Python 2.x example:
import Tkinter as tk # Upper case T in Tkinter for Python 2.x
root = tk.Tk()
def write_text():
print "hello"
def command():
window = tk.Toplevel(root)
tk.Button(window,text="Button2",command=write_text).grid()
tk.Label(window,text="hello").grid()
button = tk.Button(root, text="New Window", command=command)
button.grid()
root.mainloop()
Python 3.x example:
import tkinter as tk # all lowercase tkinter for Python 3.x
root = tk.Tk()
def write_text():
print("hello") # Python 3.x requires brackets for print statements.
def command():
window = tk.Toplevel(root)
tk.Button(window,text="Button2",command=write_text).grid()
tk.Label(window,text="hello").grid()
button = tk.Button(root, text="New Window", command=command)
button.grid()
root.mainloop()
If you are still having problems can you tell me if you are using Windows, Linux or Mac?

Have you guys ever tried button with image on Toplevel? It seems it cannot be work with code below on Toplevel(Prompt out windows). Root level is ok.
tp = Toplevel()
tp.geometry("400x400")
btnphotoAdd=PhotoImage(file="32adduser.png")
btnAdd = Button(tp, text="Add User", font="Helvetica 20 bold", image=btnphotoAdd,compound=TOP)
btnAdd.grid(row=10, column=0, sticky=W)

Related

Tkinter: Text in Frame in Nootbook tab not painted

OS is Win7 64bit, Python is 2.7.16 64bit. I have a simple Tkinter GUI: Root containing a Notebook with two tabs. First tab contains a Frame which contains a Button. Second tab contains a Frame which contains a Text. The command bound to the Button spawns a thread with sets the content of the Text.
import Tkinter
import ttk
import threading
r = Tkinter.Tk()
n = ttk.Notebook(r)
n.pack(expand=1, fill="both")
control = ttk.Frame(n)
info = ttk.Frame(n)
tInfo = Tkinter.Text(info)
tInfo.pack(expand=1, fill="both")
n.add(control, text='Control')
n.add(info, text='Info')
infoMutex = threading.Lock()
def doGuiTest():
try:
infoMutex.acquire()
tInfo.config(state='normal')
tInfo.delete('1.0', Tkinter.END)
tInfo.insert(Tkinter.END, 'Test')
tInfo.config(state='disabled')
finally:
infoMutex.release()
def workerThread():
doGuiTest()
def execute():
worker=threading.Thread(target=workerThread)
worker.start()
bExecute=Tkinter.Button(control, text='Execute', command=execute)
bExecute.pack()
r.mainloop()
Expected result: The Text is reliably visible with the set content after the Button is clicked.
Actual result: The Text is only visible when the tab containing the Text has been manually brought to the foreground before the Button is clicked.
When I set the content of the Text directly from the Button's command everything works as expected. Sadly, in the real application I am working on the functionality triggered by the Button will be running for several minutes so using another thread is a must.
What am I missing to achieve a consistent behavior?

Tkinter - Multiple windows opening

Like the title says I'm having a problem with multiple windows being able to open. New window (same window) every time I click the button. I haven't been able to find an answer to this specific scenario. I've even tried disabling the button after opening window (which led to the problem of re-enabling).
Below is enough code to work with, you can see the problem by clicking the button a few times. I am hoping for a somewhat easy solution as I am fairly new to Tkinter. Also, the smaller window needs to resize (expand) with the main window, so I dont think a Toplevel window would work.
There may be others having this same problem, and thanks in advance!
Note: I'm using Python 2.7 (Tkinter)
#!/usr/bin/python
import os
import sys
import Tkinter as tk
from Tkinter import *
from ScrolledText import *
import tkFileDialog
import tkMessageBox
# Main
root = tk.Tk(className = "tex")
root.geometry("500x300")
root.title("tex")
tex = ScrolledText(root, padx=2, pady=2, undo=True, font=('Arial 11'))
def note_area():
btn_frame = Frame()
note = LabelFrame(tex, bd=1, relief='ridge')
tx = Text(note, width=18, relief='flat', padx=2, pady=2)
tx.insert('1.0', "Notes..")
tx.pack(side='top', fill=BOTH, expand=True)
note.pack(side='right', fill=Y)
btn_frame.pack(side='bottom', fill=Y)
# ToolBar Button (should only open one instance of note_area)
toolbar = Frame(root, bd=2, relief='groove')
b4 = Button(toolbar, text="Notes", width=4, command=note_area)
b4.pack(side=RIGHT, padx=4, pady=2)
toolbar.pack(side=TOP, fill=X)
tex.pack(fill="both", expand=True)
root.mainloop()
You just need make up a variable to keep track of if you have a note window open or not.
tex.notes_open = False
def note_area():
if tex.notes_open:
return # abort the function, notes already open
else:
tex.notes_open = True # set the flag for the next time
# rest of your code

Why does Python crash when my PyQt window becomes inactive/is resized?

While playing around with different ways to show a webcam feed (obtained using imageio/ffmpeg) in a PyQt4 window, I stumbled upon this answer. After implementing this in Python 2.7 as an ImageDisplayWidget class (as summarized below), everything seems to work just fine: A window opens, showing my webcam feed without a glitch. If I close the window, everything is stopped and closed neatly.
But... Whenever I click anywhere outside this PyQt window (while it is showing the webcam feed), causing it to lose focus, Python.exe crashes with an unhandled win32 exception. The same happens when I try to resize the window.
I am probably making some kind of exceedingly silly beginner's mistake, but I just don't see it. Can anyone point me in the right direction? Am I breaking some basic rule of (Py)Qt or even Python?
Here's a minimal example:
import sys
import numpy
from PIL import Image, ImageQt # pillow
from PyQt4 import QtGui, QtCore
class DummyVideoGrabber(QtCore.QTimer):
signal_image_available = QtCore.pyqtSignal(QtGui.QImage)
def __init__(self):
super(DummyVideoGrabber, self).__init__()
self.timeout.connect(self.update_image)
self.counter = 0
def update_image(self):
# Dummy rgb image (in reality we get a numpy array from imageio's Reader)
self.counter += 1
numpy_image = numpy.zeros(shape=(480, 640, 3), dtype=numpy.int8)
numpy_image[:, :, self.counter%3] = 255
qt_image = ImageQt.ImageQt(Image.fromarray(numpy_image, mode='RGB'))
# Emit image
self.signal_image_available.emit(qt_image)
class ImageDisplayWidget(QtGui.QWidget):
"""
Custom widget that displays an image using QPainter.
Mostly copied from: https://stackoverflow.com/a/22355028/4720018
"""
def __init__(self, size_wxh=None, parent=None):
super(ImageDisplayWidget, self).__init__(parent)
self.image = QtGui.QImage()
def set_image(self, qimage, resize_window=False):
self.image = qimage
self.repaint()
def paintEvent(self, QPaintEvent):
if not self.image:
return
painter = QtGui.QPainter(self)
painter.drawImage(self.rect(), self.image, self.image.rect())
app = QtGui.QApplication(sys.argv)
# instantiate a display object
display = ImageDisplayWidget()
display.resize(640, 480)
display.show()
# instantiate a grabber object
grabber = DummyVideoGrabber()
grabber.signal_image_available.connect(display.set_image)
grabber.start(100) # timer interval in ms
# start the event loop
app.exec_()
I found that the crash can be prevented by adding a wasActiveWindow flag (initialized to True in the constructor) and encapsulating the drawImage() call in some logic like so:
if self.isActiveWindow():
if self.wasActiveWindow:
painter.drawImage(self.rect(), self.image, self.image.rect())
self.wasActiveWindow = True
else:
self.wasActiveWindow = False
However, resizing the window still crashes python.
Problem solved by keeping a reference to the qt_image as self.qt_image:
...
# Emit image
self.qt_image = ImageQt.ImageQt(Image.fromarray(numpy_image, mode='RGB'))
self.signal_image_available.emit(self.qt_image)
...
This way it works as it should. Don't need the self.wasActiveWindow workaround anymore.
Still not sure why not keeping a reference would lead to a low-level python crash though...

Closing Tkinter GUI from another function A and passes Tkinter variable to function A

This question is about programming in Python 2.7.x
I wanted to code a programme where there are two functions exist: one of those is a method to get input from the user, and the other one is to show the input. Both are supposed to be done in GUI. Let's call the first function as GET TEXT function, and the second as SHOW TEXT function; my strategy is to open a GUI, show a text box, and put a button to go to SHOW TEXT function. Then, the first line of the SHOW TEXT function is to close the window opened by the GET TEXT function, get the value of the input text, and print it in another GUI.
So, I tried doing this,
from Tkinter import *
import tkMessageBox
def texttobeenteredhere():
application = Tk()
textbox = Text(application)
textbox.pack()
submitbutton = Button(application, text="OK", command=showinputtext)
submitbutton.pack()
application.mainloop()
def showinputtext():
application.quit()
thetext = textbox.get()
print "You typed", thetext
texttobeenteredhere()
I got errors that I could not comprehend, but I hope you get my idea even though my explanation could be really bad. Please suggest a solution to my problem, where the GET TEXT function and SHOW TEXT function have to exist separately in the code.
EDIT:
Thanks Josselin for introducing the syntax class in python. What I actually wanted to say was, I want the programme to open a window to get input from the user, and then close the window, and finally open another window to show the input text. I am honestly new to this, but through my prior knowledge and guessing, I tried to modify the code to meet my expectation.
import Tkinter as tk
global passtext
class application(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.textbox = tk.Text(self)
self.textbox.pack()
self.submitbutton = tk.Button(self, text="OK", command=self.showinputtext)
self.submitbutton.pack()
self.mainloop()
def showinputtext(self):
self.thetext = self.textbox.get("1.0", "end-1c")
print "You typed:", self.thetext
self.destroy()
class showtext(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.setthetext = tk.StringVar()
self.setthetext.set(passtext)
self.showthetext = tk.Label(self, textvariable=self.setthetext)
self.showthetext.pack()
self.submitbutton = tk.Button(self, text="OK", command=self.destroy)
self.submitbutton.pack()
self.mainloop()
# Launch the GUI
app = application()
# Access the entered text after closing the GUI
passtext = app.thetext
text = showtext()
My English can sometimes be not understandable, but this question is answered. Thank you very much.
There are 2 main problems in your code:
First, in your showinputtext function, you want to access elements of your GUI, but they are not defined within the scope of the function.
Second, when reading the content of a tk.Text widget, the .get() method takes 2 arguments (see this link).
To fix the first problem, the best is to define your application as a class, with an inner function taking the class instance self as input argument, such that application widgets can be called within the function.
Code:
import Tkinter as tk
class application(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.textbox = tk.Text(self)
self.textbox.pack()
self.submitbutton = tk.Button(self, text="OK", command=self.showinputtext)
self.submitbutton.pack()
self.mainloop()
def showinputtext(self):
self.thetext = self.textbox.get("1.0", "end-1c")
print "You typed:", self.thetext
self.destroy()
# Launch the GUI
app = application()
# Access the entered text after closing the GUI
print "you entered:", app.thetext

Is there a message box which displays copy-able text in Python 2.7?

I'm trying to write a Python program that gets a string as input and displays the string in a message box with the last letter removed from each word.
I've successfully written the code to remove the last letter from each word and I came to know about the tkinter module.
But the text isn't copy-able from tk message box.
Is there any other way to display a message box with copy-able text?
If there's no way to display such message boxes, is there any way to display the output in a copy-able form without displaying a message box?
Additional (useless) information:
The name of this language is fromonk(In case you were wondering why the var name fromonk_text)
Smileys should be displayed in whole.(Including the last letter).Hence the if-else block.
The code I've written:
import tkMessageBox
line="foo"
while line!="exit":
fromonk_text=""
line=raw_input()
words=line.split()
for word in words:
if word.startswith(":"):
fromonk_text+=word+" "
else:
fromonk_text+=word[0:len(word)-1]+" "
tkMessageBox.showinfo("Fromonk",fromonk_text)
There is nothing built-in. You can create your own popup dialog with a Toplevel widget that contains a Text widget and some Button widgets, or you can use tkSimpleDialog
Some documentation can be found here: http://effbot.org/tkinterbook/tkinter-dialog-windows.htm
Here's a simple working example. It allows the text to be edited, but you can disable that if you want.
import Tkinter as tk
import tkSimpleDialog
class CustomDialog(tkSimpleDialog.Dialog):
def __init__(self, parent, title=None, text=None):
self.data = text
tkSimpleDialog.Dialog.__init__(self, parent, title=title)
def body(self, parent):
self.text = tk.Text(self, width=40, height=4)
self.text.pack(fill="both", expand=True)
self.text.insert("1.0", self.data)
return self.text
def show_dialog():
fromonk_text = "this is an example"
CustomDialog(root, title="Example", text=fromonk_text)
root = tk.Tk()
button = tk.Button(root, text="Click me", command=show_dialog)
button.pack(padx=20, pady=20)
root.mainloop()