tkinter меняет stringvar в цикле, но не влияет на окно - PullRequest
0 голосов
/ 12 мая 2018

Я хочу менять метку каждую секунду, когда я нажимаю кнопку в ТК:

# --coding:utf-8 -----
from Tkinter import *
import time
import random

def test(a):
    begin =time.time()
    end =time.time()
    while True:
        ran = random.random()
        after = time.time()
        if(after-begin >1):
            a.set(str(ran))
            print a.get()
            begin =after
        if(after-end>10):
            a.set('over')
            break


t = Tk()
a = StringVar()
a.set('0')
b = Label(t,textvariable = a)
b.pack()
Button(t,text ='test',command = lambda x=a:test(a)).pack()


t.mainloop()

Мой вывод на консоль правильный, но он не влияет на Windows. ПОЧЕМУ?

Ответы [ 2 ]

0 голосов
/ 12 мая 2018

Создание поведения, которое должно выполняться в течение определенного периода времени, является частой проблемой; Вы можете заняться этим с выделенным классом Waiter; это позволяет избежать использования потоков, которые плохо поддерживаются tkinter.

В следующем примере открывается окно с меткой и кнопкой. При нажатии кнопки метка будет обновляться каждые 10 секунд, а затем останавливаться.
Повторное нажатие кнопки в течение 10 секунд не имеет никакого эффекта; после этого он перезапускает процесс еще на 10 секунд.

import Tkinter as tk    # tkinter if python >= 3 

import time
import random


class Waiter(object):

    def __init__(self, waiting_time):
        """
        :param waiting_time: int, in seconds
        """
        self.waiting_time = waiting_time
        self.expiring_time = time.time() + self.waiting_time
        self.waiting = True
        # print('waiter started')

    def stop(self):
        # print('waiter stopping')
        self.expiring_time = None
        self.waiting = False

    def is_waiting(self):
        """returns True while waiting, false otherwise"""
        if time.time() > self.expiring_time:
            self.stop()
        return self.waiting


def atest():
    global waiter
    if waiter is None:
        waiter = Waiter(10)
        _atest()


def _atest():
    """ equivalent to: 
    while the waiter is waiting, 
    change the label every second),
    then destroy the waiter
    """
    global waiter
    if waiter.is_waiting():
        a.set(random.random())
        # print(time.time())
        t.after(1000, _atest)
    else:
        waiter = None


if __name__ == '__main__':

    waiter = None
    t = tk.Tk()
    a = tk.StringVar()
    a.set('0')
    tk.Label(t, textvariable=a).pack()
    tk.Button(t, text='test', command=atest).pack()

    t.mainloop()

Примечание:

Вы могли бы сделать _atest внутренней функцией atest, но, возможно, ее легче понять, как есть?

использование import Tkinter as tk вместо from Tkinter import * предотвращает загромождение пространства имен и, возможно, делает код более понятным.
Возможно, вам следует рассмотреть возможность использования Python 3.

0 голосов
/ 12 мая 2018

Вы можете запустить функцию test () в отдельном потоке, например:

# --coding:utf-8 -----
from Tkinter import *
import time
import random
import threading

def startThread(a):
    threading.Thread(target=test, args=(a,)).start()

def test(a):
    begin =time.time()
    end =time.time()
    while True:
        ran = random.random()
        after = time.time()
        if(after-begin >1):
            a.set(str(ran))
            print a.get()
            begin =after
        if(after-end>10):
            a.set('over')
            break


t = Tk()
a = StringVar()
a.set('0')
b = Label(t,textvariable = a)
b.pack()
Button(t,text ='test',command = lambda x=a:startThread(a)).pack()


t.mainloop()

Тем не менее, поток не закончится до конца 10 секунд, даже если вы закроете окно,Вам нужно будет найти код для цикла while, чтобы проверить, запущено ли приложение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...