python - tkinter 窗口在被破坏后不会消失
问题描述
我正在编写一个 python 脚本来显示图像、播放音乐并在触发输入时在树莓派上显示视频。当我在做这个项目时,我决定在脚本中添加一个网络摄像头。我使用了不同的网络摄像头流媒体,直到我发现 MPlayer 似乎具有最快的帧速率并且使用的资源最少。问题是,MPlayer gui 隐藏在我用来显示图像的 tkinter 窗口后面。我尝试了几种不同的方法来将 MPlayer 窗口放在前面并使 tkinter 窗口消失,但似乎没有任何效果。这是我的代码:
import sys
import os
import time
import subprocess
import RPi.GPIO as GPIO
if sys.version_info[0] == 2:
import Tkinter
tkinter = Tkinter
else:
import tkinter
from PIL import Image, ImageTk
import board
import neopixel
x=1
GPIO.setmode(GPIO.BCM)
pixels = neopixel.NeoPixel(board.D10, 38)
pixels.fill((0, 0, 0))
GPIO.setwarnings(False)
GPIO.setup(17,GPIO.OUT)
GPIO.setup(18,GPIO.OUT)
GPIO.setup(27,GPIO.OUT)
GPIO.setup(22,GPIO.OUT)
GPIO.setup(24,GPIO.OUT)
GPIO.setup(25,GPIO.OUT)
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(5, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.output(17,GPIO.LOW)
GPIO.output(18,GPIO.LOW)
GPIO.output(27,GPIO.LOW)
GPIO.output(22,GPIO.LOW)
GPIO.output(24,GPIO.LOW)
GPIO.output(25,GPIO.LOW)
def showPIL(pilImage, exVar = 0):
try:
root.withdraw()
root.destroy()
root.update()
except:
pass
root = tkinter.Toplevel()
if x == 1:
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
else:
w, h = 100, 100
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
#root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
imgWidth, imgHeight = pilImage.size
if imgWidth > w or imgHeight > h:
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(w/2,h/2,image=image)
root.update()
showPIL(Image.open("Data/blank.png"))
while not GPIO.input(4):
pass
music = subprocess.Popen(['cvlc', '/home/pi/Desktop/Data/music.mp3'])
showPIL(Image.open("Data/trophy.png"))
time.sleep(1)
GPIO.output(22,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(27,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(18,GPIO.HIGH)
time.sleep(0.5)
GPIO.output(17,GPIO.HIGH)
time.sleep(1)
showPIL(Image.open("Data/poison.png"))
pixels.fill((0, 255, 0))
os.system("pkill tk")
x=0
showPIL(Image.open("Data/blank.png"))
x=1
camera = subprocess.Popen(['mplayer', '-fs', 'tv://'])
os.system("wmctrl -a MPlayer")
time.sleep(8)
camera.kill()
os.system("omxplayer -b '/home/pi/Desktop/Data/movie.mp4'")
showPIL(Image.open("Data/gun.png"))
GPIO.output(24,GPIO.HIGH)
GPIO.output(25,GPIO.HIGH)
while not GPIO.input(23):
pass
pixels.fill((0, 0, 0))
showPIL(Image.open("Data/dumbell.png"))
time.sleep(1)
showPIL(Image.open("Data/pipe.png"))
time.sleep(1)
showPIL(Image.open("Data/noose.png"))
time.sleep(1)
music.kill()
showPIL(Image.open("Data/blank.png"))
end = subprocess.Popen(['cvlc', '/home/pi/Desktop/Data/end.wav'])
time.sleep(8)
end.kill()
解决方案
好的,这里有几个关键问题。
一个大问题是你的try/except
陈述。
你的尝试除了总是会做的pass
。永远不会有你可以destroy()
做某事然后调用update()
它的时候。这将始终导致错误,因此pass
将运行 except 语句。
接下来root = tkinter.Toplevel()
是一个问题。因为您从未定义 tkinter 实例,或者root
您应该创建一个顶层窗口,这将导致 tkinter 的实例被打开但没有变量名可以使用。这里所说的 root 仅在函数本地定义,因此任何时候再次调用函数时,函数都不会尝试销毁 root 的记录,因为据函数所知,它还没有被创建。您需要将您的根定义为这样的global
变量。
即使这对您有用,也应该有两个问题。一个是显示的额外空白窗口,2 是当您关闭顶层窗口时该窗口不会自行关闭。
接下来,您尝试sleep
在运行 tkinter 实例的同时使用。如果不使用线程,这些东西是不兼容的,因此您需要在其中使用线程,或者最好学习如何使用after()
. After()
是 tkinter 如何管理定时事件。
而不是在Toplevel()
这里使用你需要使用Tk()
. 而不是破坏和重建你的 GUI 每次更新你应该只更新你的窗口。在您尝试做的事情的范围内,您可能应该更多地使用 tkinter 并在尝试 raspberry pi 项目之前了解事件管理器的工作原理。一旦您掌握了 Tkinter GUI 及其基于事件的过程,您将能够更轻松地完成更复杂的事情。
推荐阅读
- angular - Angular 中的锚标签——它们是如何工作的?
- java - 如何在 SPRING REST API 中使用 SQL 查询处理“ALL”?
- python - matplotlib 以两种不同的方式打印图像
- cordova - 如何编辑 config.xml 以在 phonegap 构建中启用 android 调试?
- javascript - 为什么数字从 Object.prototype 继承时不是 Object 的实例?
- mysql - 错误消息:无法连接到数据库服务器
- javascript - 在 AngularJS 应用程序上使用 google API then() 函数
- java - 为什么每次调用 SpringMVC 服务中的简单方法都比静态方法慢?
- java - 在每次仪器测试之前重置/清除应用程序 (Android Studio)
- vue.js - 如何将表单数据从父组件传递给子组件?