Skip to main content
 首页 » 编程设计

python之tkinter root.mainloop 与 While True 循环

2025年05月04日15lyj

我正在使用 tkinter 根据我正在读取的电压显示一些标签。但是,它会在一次读取后停止执行。我发现这是由于 root.mainloop()。但我无法修复它。我已经包含了我的代码。 root.mainloop() 正好位于 while True 的末尾。

from Tkinter import * 
import spidev 
import time 
import os 
import RPi.GPIO as GPIO 
import numpy 
 
GPIO.cleanup() 
GPIO.setmode(GPIO.BOARD) 
GPIO.setup(7, GPIO.OUT) 
GPIO.setup(11, GPIO.OUT) 
GPIO.setup(13, GPIO.OUT) 
GPIO.setup(15, GPIO.OUT) 
GPIO.setup(12, GPIO.OUT) 
adcvolt = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 
batvolt = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] 
 
root = Tk() #Makes the window 
w,h = root.winfo_screenwidth(), root.winfo_screenheight() 
root.overrideredirect(1) 
root.geometry("%dx%d+0+0"%(w,h)) 
 
labelFont = ("times",15 ,"bold", "italic") 
labelText1 = StringVar() 
labelText2 = StringVar() 
labelText3 = StringVar() 
labelText4 = StringVar() 
labelText5 = StringVar() 
labelText6 = StringVar() 
 
labelText1.set("Battery Management System") 
label1 = Label(root, textvariable=labelText1, height=3, anchor="center") 
label1.config(font=labelFont) 
label1.pack() 
labelText2.set("Wait") 
label2 = Label(root, textvariable=labelText2, height=3, anchor="center") 
label2.config(font=labelFont) 
label2.pack() 
labelText3.set("Wait") 
label3 = Label(root, textvariable=labelText3, height=3, anchor="center") 
label3.config(font=labelFont) 
label3.pack() 
labelText4.set("Wait") 
label4 = Label(root, textvariable=labelText4, height=3, anchor="center") 
label4.config(font=labelFont) 
label4.pack() 
labelText5.set("Wait") 
label5 = Label(root, textvariable=labelText5, height=3, anchor="center") 
label5.config(font=labelFont) 
label5.pack() 
labelText6.set("Wait") 
label6 = Label(root, textvariable=labelText6, height=3, anchor="center") 
label6.config(font=labelFont) 
label6.pack() 
#root.wm_title("Window Title") #Makes the title that will appear in the top left 
#root.config(background = "#FFFFFF") #sets background color to white 
 
 
# Open SPI bus 
spi = spidev.SpiDev() 
spi.open(0,0) 
 
# Function to read SPI data from MCP3008 chip 
# Channel must be an integer 0-7 
def ReadChannel(channel): 
  adc = spi.xfer2([1,(8+channel)<<4,0]) 
  data = ((adc[1]&3) << 8) + adc[2] 
  return data 
 
#Function to select multiplexer channel on 74HCT4067 chip 
#Channel must be an integer 0-15 
def MuxSelect(muxchannel): 
    if muxchannel == 0: 
        GPIO.output(7,0) 
        GPIO.output(11,0) 
        GPIO.output(13,0) 
        GPIO.output(15,0) 
    elif muxchannel == 1: 
        GPIO.output(7,0) 
        GPIO.output(11,0) 
        GPIO.output(13,0) 
        GPIO.output(15,1) 
    elif muxchannel == 2: 
        GPIO.output(7,0) 
        GPIO.output(11,0) 
        GPIO.output(13,1) 
        GPIO.output(15,0) 
    elif muxchannel == 3: 
        GPIO.output(7,0) 
        GPIO.output(11,0) 
        GPIO.output(13,1) 
        GPIO.output(15,1) 
    elif muxchannel == 4: 
        GPIO.output(7,0) 
        GPIO.output(11,1) 
        GPIO.output(13,0) 
        GPIO.output(15,0) 
    elif muxchannel == 5: 
        GPIO.output(7,0) 
        GPIO.output(11,1) 
        GPIO.output(13,0) 
        GPIO.output(15,1) 
    elif muxchannel == 6: 
        GPIO.output(7,0) 
        GPIO.output(11,1) 
        GPIO.output(13,1) 
        GPIO.output(15,0) 
    elif muxchannel == 7: 
        GPIO.output(7,0) 
        GPIO.output(11,1) 
        GPIO.output(13,1) 
        GPIO.output(15,1) 
    elif muxchannel == 8: 
        GPIO.output(7,1) 
        GPIO.output(11,0) 
        GPIO.output(13,0) 
        GPIO.output(15,0) 
    elif muxchannel == 9: 
        GPIO.output(7,1) 
        GPIO.output(11,0) 
        GPIO.output(13,0) 
        GPIO.output(15,1) 
    elif muxchannel == 10: 
        GPIO.output(7,1) 
        GPIO.output(11,0) 
        GPIO.output(13,1) 
        GPIO.output(15,0) 
    elif muxchannel == 11: 
        GPIO.output(7,1) 
        GPIO.output(11,0) 
        GPIO.output(13,1) 
        GPIO.output(15,1) 
    elif muxchannel == 12: 
        GPIO.output(7,1) 
        GPIO.output(11,1) 
        GPIO.output(13,0) 
        GPIO.output(15,0) 
    elif muxchannel == 13: 
        GPIO.output(7,1) 
        GPIO.output(11,1) 
        GPIO.output(13,0) 
        GPIO.output(15,1) 
    elif muxchannel == 14: 
        GPIO.output(7,1) 
        GPIO.output(11,1) 
        GPIO.output(13,1) 
        GPIO.output(15,0) 
    elif muxchannel == 15: 
        GPIO.output(7,1) 
        GPIO.output(11,1) 
        GPIO.output(13,1) 
        GPIO.output(15,1) 
 
 
 
# Function to convert data to voltage level, 
# rounded to specified number of decimal places.  
def ConvertVolts(data,places): 
  volts = (data * 3.3) / 1023 
  volts = round(volts,places) 
  return volts 
 
# Define sensor channels 
voltage_channel = 0 
 
 
# Define delay between readings 
delay = 2 
 
 
 
 
while True: 
  count = 0 
 
  while count<15: 
    MuxSelect(count) 
 
    # Read the voltage sensor data 
    voltage_level = ReadChannel(voltage_channel) 
    voltage_volts = ConvertVolts(voltage_level,2) 
    adcvolt[count] = voltage_volts 
    batvolt[count] = adcvolt[count] * 2.842 
 
    #print adcvolt[count] 
    #print batvolt[count] 
    #print count 
    count = count + 1 
    #time.sleep(delay) 
  labelText2.set('Cell1= '+str(batvolt[0])+'V  Cell2= ' +str(batvolt[1])+'V  Cell3= '+str(batvolt[2])) 
  #root.update() 
  labelText3.set('Cell4= '+str(batvolt[3])+'V  Cell5= ' +str(batvolt[4])+'V  Cell6= '+str(batvolt[5])) 
 # root.update() 
  labelText4.set('Cell7= '+str(batvolt[6])+'V  Cell8= ' +str(batvolt[7])+'V  Cell9= '+str(batvolt[8])) 
#  root.update() 
  labelText5.set('Cell10= '+str(batvolt[9])+'V  Cell11= ' +str(batvolt[10])+'V  Cell12= '+str(batvolt[11])) 
#  root.update() 
  labelText6.set('Cell13= '+str(batvolt[12])+'V  Cell14= ' +str(batvolt[13])+'V  Cell15= '+str(batvolt[14])) 
  root.update() 
  print "shit"   
 
  medianvolt = numpy.median(batvolt) 
  maxvolt = max(batvolt) 
  minvolt = min(batvolt) 
  diff1 = maxvolt-medianvolt 
  diff2 = medianvolt-minvolt 
 
  if diff1>0.02 or diff2>0.02: 
    GPIO.output (12,1) 
    time.sleep(120) 
    GPIO.output (12,0) 
 
 
    # Wait before repeating loop 
    time.sleep(delay) 
 
  root.update() 
 
  root.mainloop() #start monitoring and updating the GUI. Nothing below here runs. 

请您参考如下方法:

tkinter 需要 mainloop() 才能正常工作 - 它使用它一次又一次地调用所有需要的函数 - 即。从系统获取键/鼠标事件,将它们发送到小部件,更新值,并在窗口中(重新)绘制小部件。

在 tkinter 中不要使用永远运行(或运行更长时间)的 while True 因为它会阻塞 mainloop() 在 tkinter 并且它无法更新窗口中的项目,看起来像卡住了。

同样的问题使 sleep() - 它可以阻止 tkinter 中的 mainloop()。

您可以使用 root.after(time_ms, function_name_without_brackets )(在 mainloop() 之前)
延迟运行一些函数 - 所以它可以像 sleep() 一样使用。如果函数将运行相同的 after(...) 那么它将像循环一样工作。这样 tkinter 将有时间更新窗口中的小部件。


因此,将 while True 中的所有代码(mainloop() 除外)放入函数中,并使用 after() 调用它。
并使用第二个 after() 代替 sleep()。

import tkinter as tk 
 
master = tk.Tk() 
 
def my_mainloop(): 
    print "Hello World!" 
    master.after(1000, my_mainloop)  # run again after 1000ms (1s) 
 
master.after(1000, my_mainloop) # run first time after 1000ms (1s) 
 
master.mainloop() 

如果您不能转换 while 循环并使用 after(),那么您可能必须在单独的线程中运行循环。但是 tkinter(与许多其他 GUI 一样)` 不喜欢在第二个线程中工作,并且 GUI 中的所有更改都必须在主线程中进行。