简体   繁体   中英

Tkinter button executing script throws NameError

I have a Tkinter GUI with three buttons running a separate script each. Two of them load fine, however the third one throws up a NameError, saying one of my names isn't defined. However when I run the script not through the GUI, it runs fine.

This is the GUI code:

import sys
import os
import tkinter
import cv2
from tkinter.filedialog import askopenfilename
from tkinter import messagebox
import numpy as np 
import matplotlib.pyplot as plt 

top=tkinter.Tk()
top.geometry("300x350")
top.config(background='black')
top.title('Test')
top.resizable(height=False, width=False)

def thresholdCallBack():
    exec(open('motionindexthreshold.py').read())

def autoremoveCallBack():
    exec(open('motionindexgenerator.py').read())

def videoTaggingCallBack():
    exec(open('stepthrough.py').read())

def quitCallBack():
    top.destroy()

M = tkinter.Message(top, text='Test', width=280, background='black', foreground='white', font=('Courier', 28))
B = tkinter.Button(top,text="Define Motion Index Threshold",command= thresholdCallBack)
C = tkinter.Button(top,text="Autoremove Nonmovement Video Segments",command= autoremoveCallBack)
D = tkinter.Button(top,text="Tag Video Frames",command= videoTaggingCallBack)
E = tkinter.Button(top,text="Quit", command=quitCallBack)
B.config(height=5, width=80, background='red')
C.config(height=5, width=80, background='blue', foreground='white')
D.config(height=5, width=80, background='yellow')
E.config(height=5, width=80, background='green')
M.pack()
B.pack()
C.pack()
D.pack()
E.pack()
top.mainloop()

And this is the python script that crashes when a keypress is registered:

import cv2
import tkinter as tk
from tkinter.filedialog import askopenfilename
from tkinter import messagebox
import numpy as np 
import os
import matplotlib.pyplot as plt 
import sys


framevalues = []
count = 1

root = tk.Tk()
root.withdraw()

selectedvideo = askopenfilename()
selectedvideostring = str(selectedvideo)
cap = cv2.VideoCapture(selectedvideo)
length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))


def stanceTag():    
    framevalues.append('0' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length) 
    print(framevalues)

def swingTag():
    framevalues.append('1' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length)
    print(framevalues) 

def unsureTag():
    framevalues.append('-1' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length) 
    print(framevalues)

def rewindFrames():
    cap.set(1,((int(cap.get(1)) - 2)))
    print (int(cap.get(1)), '/', length) 
    framevalues.pop()
    print(framevalues)  



while (cap.isOpened()): 
    ret, frame = cap.read()

    # check if read frame was successful
    if ret == False:
            break
    # show frame first
    cv2.imshow('frame',frame)

    # then waitKey
    frameclick = cv2.waitKey(0) & 0xFF

    if frameclick == ord('a'):
        swingTag()

    elif frameclick == ord('r'):
        rewindFrames()

    elif frameclick == ord('s'):
        stanceTag()

    elif frameclick == ord('d'):
        unsureTag()

    elif frameclick == ord('q'):
        with open((selectedvideostring + '.txt'), 'w') as textfile:
            for item in framevalues:
                textfile.write("{}\n".format(item))
        break

    else:
        continue

cap.release()
cv2.destroyAllWindows()

Does anyone have any ideas how to solve this issue?

Thanks

If you need to run code from another python script, then you should use an import to get the other script and run a function in the other script. This will be a problem with your code since you have the core of your program outside of a function, so it would run as soon as it's imported. For the reason (and others) you should have all of your code in functions. You can detect if the code was imported or not by checking the __main__ attribute.

I restructured your code to move all the code into functions, then import it and call the appropriate function from the GUI buttons.

This is what your GUI code should look like:

import tkinter

import motionindexthreshold
import motionindexgenerator
import stepthrough

def main():
    top=tkinter.Tk()
    top.geometry("300x350")
    top.config(background='black')
    top.title('Test')
    top.resizable(height=False, width=False)

    M = tkinter.Message(top, text='Test', width=280, background='black', foreground='white', font=('Courier', 28))
    B = tkinter.Button(top,text="Define Motion Index Threshold",command=motionindexthreshold.main)
    C = tkinter.Button(top,text="Autoremove Nonmovement Video Segments",command=motionindexgenerator.main)
    D = tkinter.Button(top,text="Tag Video Frames",command=stepthrough.main)
    E = tkinter.Button(top,text="Quit", command=top.destroy)
    B.config(height=5, width=80, background='red')
    C.config(height=5, width=80, background='blue', foreground='white')
    D.config(height=5, width=80, background='yellow')
    E.config(height=5, width=80, background='green')
    M.pack()
    B.pack()
    C.pack()
    D.pack()
    E.pack()
    top.mainloop()

if __name__ == '__main__':
    main()

And this is what your module code should look like:

import cv2
import tkinter as tk
from tkinter.filedialog import askopenfilename

def stanceTag(cap, framevalues):    
    framevalues.append('0' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length) 
    print(framevalues)

def swingTag(cap, framevalues):
    framevalues.append('1' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length)
    print(framevalues) 

def unsureTag(cap, framevalues):
    framevalues.append('-1' + ' ' + '|' + ' ' + str(int(cap.get(1))))
    print (str(int(cap.get(1))), '/', length) 
    print(framevalues)

def rewindFrames(cap, framevalues):
    cap.set(1,((int(cap.get(1)) - 2)))
    print (int(cap.get(1)), '/', length) 
    framevalues.pop()
    print(framevalues)  


def main():
    framevalues = []
    count = 1

    selectedvideo = askopenfilename()
    selectedvideostring = str(selectedvideo)
    cap = cv2.VideoCapture(selectedvideo)
    length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))

    while (cap.isOpened()): 
        ret, frame = cap.read()

        # check if read frame was successful
        if ret == False:
                break
        # show frame first
        cv2.imshow('frame',frame)

        # then waitKey
        frameclick = cv2.waitKey(0) & 0xFF

        if frameclick == ord('a'):
            swingTag(cap, framevalues)

        elif frameclick == ord('r'):
            rewindFrames(cap, framevalues)

        elif frameclick == ord('s'):
            stanceTag(cap, framevalues)

        elif frameclick == ord('d'):
            unsureTag(cap, framevalues)

        elif frameclick == ord('q'):
            with open((selectedvideostring + '.txt'), 'w') as textfile:
                for item in framevalues:
                    textfile.write("{}\n".format(item))
            break

        else:
            continue

    cap.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    # this is called if this code was not imported ... ie it was directly run
    # if this is called, that means there is no GUI already running, so we need to create a root
    root = tk.Tk()
    root.withdraw()
    main()

Obviously this is a guess; I have no way to test if this solves your issue, but I think it will.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM