I am getting the error "Global name 'start' is not defined" from the code snippet below. But the start(panel) call in displayImage(img) causes the image I want to see to be displayed in the GUI; without it no image shows up; it must be doing something. Yet I get the above error. I'm running this program in Ubuntu 12.04. BTW, I am new to both Python and Tkinter. Any way to get rid of this error? Edit: The adding of the image occurs during runtime with a button click that calls loadPicture(file).
import numpy as np
from Tkinter import *
import cv2 as cv
from tkFileDialog import askopenfilename
import tkSimpleDialog as td
import math as mt
from PIL import ImageTk, Image
### General functions #############################################
def raiseFileChooser():
global filename
filename = askopenfilename()
loadPicture(filename)
def loadPicture(file):
# set global variable for other uses
global img
img = cv.imread(file, 1)
img = cv.cvtColor(img, cv.COLOR_RGB2BGR)
displayImage(img, display1)
def displayImage(image, panel):
temp = Image.fromarray(image)
bk = ImageTk.PhotoImage(temp)
bkLabel = Label(display1, image = bk)
bkLabel.place(x=0, y=0, relwidth=1, relheight=1)
start(panel)
### Start App ###########################################
#### get GUI started
root = Tk()
np.set_printoptions(threshold=np.nan) # so I can print entire arrays
### global variables ####################################
relStatus = StringVar()
relStatus.set(None)
text = StringVar()
filepath = StringVar()
filename = "No file chosen"
img = None
gsc = None
eStatus = StringVar()
eStatus.set(None)
display1 = None
display2 = None
### GUI #################################################
root.title("Picture Transformer")
root.geometry("700x600")
app = PanedWindow(root)
app.pack(padx=20, pady=20)
#Button Panel##############
buttonPanel = Frame(app,width=200, height = 400)
buttonPanel.pack(side=LEFT)
chooser = Button(buttonPanel, text="Choose File", height=1, width=9, command=raiseFileChooser)
chooser.pack()
#set up display panels ###########################
display1 = Frame(app, width=900, height=900, bg="#cccccc")
display1.pack(side=LEFT, fill=BOTH, expand=1)
root.mainloop()
Edit:
Stacktrace:
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1413, in __call__
return self.func(*args)
File "hw2.py", line 78, in raiseFileChooser
loadPicture(filename)
File "hw2.py", line 86, in loadPicture
start(panel)
NameError: global name 'start' is not defined
The error is telling you exactly what's wrong -- there is no global start function in your code. In fact, as near as I can tell, there's no start method anywhere, in any object that you are creating. Why do you think you should be calling a function named start? Is there some documentation somewhere that is telling you to do this?
My guess is, you're running in IDLE, and when you call the non-existent start function, the script crashes. When the script crashes it returns to IDLE, and whatever windows you had created to that point are now visible.
The most obvious problem you have in your code is that you aren't creating a root window. Somewhere early in your script, before you create any widgets or instances of StringVar you need to do something like this:
root = Tk()
root.mainloop() in the place of start() works.
Try
panel.start()
Just a guess.Give a try, you might be able to solve the problem.
Related
New to tkinter, I want a short program to:
create a window to take user input, by means of an entry widget and a submit button
capture the input and return it to main, so that I can do something else with it.
The following code creates the window and captures input, but breaks at the next-to-last line.
from tkinter import *
from tkinter import ttk
class TxtEntryWindow:
def __init__(self):
self.root = Tk()
self.frame = ttk.Frame(self.root).pack()
self.box = ttk.Entry(self.frame)
self.box.pack()
self.but = ttk.Button(self.frame, text='Submit', command=self.capture_txt)
self.but.pack()
self.root.mainloop()
def capture_txt(self):
txt = self.box.get()
return txt
win = TxtEntryWindow()
user_input = win.capture_txt()
print(user_input)
Here's a copy of the error message:
Traceback (most recent call last):
File "C:...\wclass.py", line 22, in
user_input = win.capture_txt()
File "C:...\wclass.py", line 17, in capture_txt
txt = self.box.get()
File "C:...\Python\Python310\lib\tkinter_init_.py", line 3072, in get
return self.tk.call(self._w, 'get')
_tkinter.TclError: invalid command name ".!entry"
I have no idea what this means. I suspect that dependence of "txt" on the button event in the class prevents "win.capture_txt()" in main() at the bottom from fetching the user input.
Can anyone shed light?
Consulted Python's official documentation (unintelligible), Tkinter's official tutorial and command reference. Searched numerous analogies on StackOverflow and on youtube. Googled the error message itself. I've tried to strike out on my own and rewrite the critical command about twenty times. Blind intuition leads nowhere. Stabbing in the dark.
The error means that the entry widget (self.box) has been destroyed when the line user_input = win.capture_txt() is executed.
You can use an instance variable to store the input text instead and access this instance variable after the window is destroyed:
from tkinter import *
from tkinter import ttk
class TxtEntryWindow:
def __init__(self):
self.text = "" # initialize the instance variable
self.root = Tk()
self.frame = ttk.Frame(self.root).pack()
self.box = ttk.Entry(self.frame)
self.box.pack()
self.but = ttk.Button(self.frame, text='Submit', command=self.capture_txt)
self.but.pack()
self.root.mainloop()
def capture_txt(self):
# save the user input into the instance variable
self.text = self.box.get()
self.root.destroy()
win = TxtEntryWindow()
print(win.text) # show the content of the instance variable
from PIL import Image
from tkinter import filedialog as fd
import os
import ctypes
import tkinter
class ImageList:
path = ""
dir = ""
top = tkinter.Tk()
canvas = tkinter.Canvas()
canvas.pack()
def __init__(self):
self.path = os.path.expanduser('~/')
def findImage(self):
image = Image.open(self.dir, "rb")
image.show()
def fileExplorer(self, path):
self.canvas.destroy()
self.canvas = tkinter.Canvas()
self.canvas.pack()
obj = os.scandir(path)
for entry in obj:
if entry.is_dir():
#self.path = os.path.abspath(self.path)
b = tkinter.Button(self.canvas, text=entry.name, command=lambda: self.fileExplorer(os.path.abspath(entry).replace('//', '\\')))
b.pack()
elif entry.is_file():
b = tkinter.Button(self.canvas, text=entry.name, command=lambda: print(entry.name))
b.pack()
else:
obj.close()
self.top.mainloop()
As shown in the code above, I am trying to make exe that shows the subdirs and files after C:\Users using buttons in tkinter and repeating it by using recursion.
The first error is that in "os.path.abspath(entry).replace('//', '\')" shows path in a format of "C://Users" and I intended to change that to "C:\Users" using the replace method. However, using "\" doesn't replace "//" and still shows as the original format.
The second error is that after running the code, when I press any button it acts as if I pressed the last button in the tkinter window, meaning that it recursively called the last subdir or the file below "C:\Users".
I'm just getting used to python and this is my first time using stackoverflow. I'm sorry if I did not abide by any of the rules in stackoverflow. Thanks for anyone helping.
Code Part 1
from tkinter import *
from PIL import Image, ImageTk
import threading
c1 = "#262626"
root = Tk()
root.overrideredirect(True)
root.configure(bg=c1)
def destroy():
global root
root.destroy()
def pr():
print("asd")
destroy()
def animation():
threading.Timer(0.01, pr).start()
animation()
root.mainloop()
after the destroy () command has worked, the window is closed, but the program continues to work, you can disable it only with the help of the task manager or CMD, but there's no any errors.
Code Part 2
login = Tk()
img = Image.open(selfDir + "\\ok.png").resize((50, 50), Image.ANTIALIAS)
test = ImageTk.PhotoImage(img)
label1 = Label(login, image=test, bg=c1)
label1.image = test
label1.place(x=330, y=145, width=50, height=50)
login.mainloop()
if I run this part after the first one, I see an error:
tkinter.TclError: can't invoke "image" command: application has been destroyed
but if I run only this part, without the first one, then it works and I can see the photo in the window
So the problem is.
I need to close window after threading.Timer()
Then i need to open window, with an image
i just need to write
root.after(10, pr)
instead of
threading.Timer(0.01, pr).start()
special thanks to Matiiss
I'm trying to show and hide a png (With no frame, margin, or title bar) but can't find a good way to do it. I tried using matplotlib but the code has to be in the main thread so I can't figure out how to use functions to show or hide it. I also tried tkinter but ran into the same problem where calling it from a function the code would just stop when trying to call it from a function.
Is there a simple way to accomplish this?
Below is what I am trying to accomplish though the code doesn't display any image. The code doesn't return an error either, it just stops executing at mainloop without displaying anything unless the code is in the main thread.
#Import modules
import os #For working directory
from pynput import keyboard #For hotkeys
from tkinter import *
from PIL import ImageTk,Image
#Set default directory
os.chdir('C:\\Users\\Username\\Desktop\\Python')
#Define global variables
global img
#Functions
def ExitProgram():
print('test')
#sys.exit(0)
quit() #Will not work in production, switch to sys.exit
return
def ShowImage():
root = Tk()
canvas = Canvas(root, width=300, height=300)
canvas.pack()
img = ImageTk.PhotoImage(Image.open("menu.png"))
canvas.create_image(20, 20, anchor=NW, image=img)
root.overrideredirect(True) # removes title bar
root.mainloop()
print('test')
return
#Define hotkeys
with keyboard.GlobalHotKeys({
'<ctrl>+q': ExitProgram,
'<ctrl>+0': ShowImage}) as h:
h.join()
Below is my code. The code is from within a different program, so a button would be clicked
on another program and initiate this code.I have been struggling with this a while, in short i am trying to a) take an image, save it to a directory, b) display the image on canvas or root a long with a button named "refresh". When refresh is clicked then remove is called deleting the 'file' first taken, takes another picture and refreshes the canvas with the second picture taken and so on and on. I am not seeming to get it to work in this sequence and have used multiple examples etc etc. Can anyone assist please, is my design incorrect perhaps? I have ample other code but the code below details only one function calling global properties etc etc. I would appreciate an answer but also want to learn from the answer to understand what is being done wrong.
import os
import sys
import time
from VideoCapture import Device
impot Image
from PIL import ImageTk, Image
from Tkinter import *
import Tkinter
root = Tk()
root.wm_title("Camera Capture")
root.resizable(0,0)
root.geometry("600x400")
path = ('C:\Users\Public')
os.chdir(path)
def take_picture():
global root
global path
os.chdir(path)
cam = Device()
cam.saveSnapshot('pic.gif')
webcam_pic = Tkinter.PhotoImage(file='./pic.gif')
item = Label(root, anchor = W, image = webcam_pic)
item.pack()
button_take_picture = Button(root, text = "Take picture", command = take_picture(), bg
= 'blue')
button_take_picture.place(relx = .9, rely = .5, anchor = "center")
mainloop()
actually the command should be without this '()'
command =take_picture
button_take_picture = Button(root, text = "Take picture", command = take_picture, bg=blue')