Кнопки графического интерфейса Python не будут выполняться

Я пишу базовую программу военного вождения. Я заставил его зациклить команду, чтобы подтянуть все точки беспроводного доступа поблизости. Проблема в том, что моя кнопка остановки не работает, и я не могу обновить метку (я даже не уверен, смогу ли я обновить метку).

import sys, os, subprocess, re
from Tkinter import *

missionGO = 0
count = 0

class App:

def __init__(self, master):

    frame = Frame(master)
    frame.pack()

    self.start = Button(frame, text="Start", fg="green",
                        command=self.startButtonClick)
    self.start.grid(row=3)

    self.stop = Button(frame, text="Stop", fg="red",
                       command=self.stopButtonClick)
    self.stop.grid(row=3, column=1)

    self.totalSSIDLabel = Label(frame, text="Current Access Points: ")
    self.totalSSIDLabel.grid(row=0)

    self.totalSSID = Label(frame, text=count)
    self.totalSSID.grid(row=0, column=1)

def startButtonClick(self):
    missionGO = 1
    while (missionGO == 1):
        wlan = getAccessPoints()
        x = numberOfAccessPoints(wlan)
        print x
    return

def stopButtonClick(self):
    missionGO = 0
    return

def stop(event):
    missionGO = 0

# Finds all wireless AP
def getAccessPoints():
    X = subprocess.check_output("netsh wlan show network mode=Bssid",
                                shell=True)
    return X

def numberOfAccessPoints(file):
    count = 0
    words = file.split()

for line in words:
    if re.match('SSID', line):
        count = count + 1
    return count

#Main
root = Tk()
app = App(root)
root.mainloop()

person iFetus    schedule 29.03.2012    source источник
comment
пожалуйста, сделайте отступ прямо, так как это жизненно важно в Python.   -  person Constantinius    schedule 29.03.2012
comment
извините, все смешалось, когда я скопировал это в вопрос.   -  person iFetus    schedule 29.03.2012


Ответы (3)


Tkinter является однопоточным. Это означает, что пока вы находитесь в цикле while внутри startButtonClick, никакие другие события не обрабатываются. Кнопка остановки не будет вызывать свою команду, пока функция startButtonClick не завершит работу.

Вы должны помнить, что ваша программа уже выполняет глобальный бесконечный цикл: цикл событий. Нет причин помещать в него еще один бесконечный цикл. Когда вы хотите, чтобы что-то работало вечно, трюк состоит в том, чтобы поместить одну итерацию в цикл событий, а затем, когда оно запускается, оно помещает еще одну итерацию в цикл событий.

Другим ключом к этому является обеспечение того, чтобы одна итерация цикла была быстрой — она должна быть значительно меньше секунды (скорее менее 100 мс), иначе пользовательский интерфейс станет лагать.

Логика выглядит примерно так:

def startButtonClick(self):
    self.missionGO = 1
    self._do_one_iteration()

def _do_one_iteration(self):
    if self.missionGO == 1:
        wlan = getAccessPoints()
        x = numberOfAccessPoints(wlan)
        print x
        # this adds another iteration to the event loop
        self.after(10, self._do_one_iteration)

def stopButtonClick(self):
    self.missionGO = 0
person Bryan Oakley    schedule 29.03.2012
comment
Я получаю AttributeError: Экземпляр приложения не имеет атрибута «после». Есть идеи, о чем это? - person iFetus; 30.03.2012
comment
@iFetus: я должен был сказать, что вышеприведенное предполагает, что self является экземпляром Tkinter.Tk. В вашем случае вам нужно использовать master.after или self.master.after или что-то еще. after — это метод Tkinter, общий для всех виджетов. - person Bryan Oakley; 30.03.2012

Я думаю, что основной поток висит в цикле while нажатия кнопки запуска. Поскольку он занят, он даже не заметит, что была нажата кнопка остановки.

person katzenversteher    schedule 29.03.2012
comment
Вот что я думаю, но есть ли где-нибудь вокруг этого? - person iFetus; 29.03.2012
comment
Да. Вы можете обрабатывать события пользовательского интерфейса в другом потоке (или выполнять работу в другом потоке). Вы также можете проверить, предлагает ли tkinter альтернативу mainloop, чтобы вы могли написать свой собственный mainloop, который обрабатывает события пользовательского интерфейса и вашу работу в одном потоке. - person katzenversteher; 29.03.2012

Я не могу сказать вам точно, почему ваша кнопка остановки не работает, но я думаю, что понял идею вашей программы. Мое предложение состоит в том, чтобы установить два потока. Первый поток для пользовательского интерфейса, а второй для постоянной проверки беспроводных сетей с заданным интервалом (ваш текущий код проверяет как можно скорее — плохая практика, вы должны сделать паузу в цикле.

Поскольку я не имел дело с многопоточностью в Tkinter, могу предоставить вам только точки входа:

Удачи!

person f4lco    schedule 29.03.2012