Python 2.7 Tkinter не отвечает при запуске программы

Я абсолютный новичок в Python Tkinter. Моя программа имеет последовательный порт и соединение с клиентским сокетом TCP (выполняется в потоке). Он хорошо работает в консольном приложении, но не работает в графическом интерфейсе Tkinter.

count = 0
initialState = True

def initState(reader, ReaderName, readerType, serialport, baud, databit, readerPacket):
    global count
    global initialState
    if initialState:
        while not reader.SettingReader(ReaderName, readerType, serialport, baud, databit, readerPacket):
            count += 1
        count = 0
        labelSearching.place(x=290, y=260)
        labelReaderSetting.configure(image=readerSettingSuccess)
        app.update_idletasks()

        labelSearching.grid_forget()
        labelReaderConnect.place(x=290, y=260)
        app.update_idletasks()

        labelReaderConnect.configure(image=readerConnected)
        labelServerConnect.place(x=290, y=320)
        app.update_idletasks()

        while not reader.StartServer():
            count += 1
        count = 0
        labelServerConnect.configure(image=serverConnected)
        app.update_idletasks()

        labelContainer.grid_forget()
        labelReaderSetting.configure(image=readerSettingSuccessSmall)
        labelReaderSetting.place(x=80, y=200)
        labelReaderSetting.lift()
        labelReaderConnect.configure(image=readerConnectedSmall)
        labelReaderConnect.place(x=80, y=260)
        labelReaderConnect.lift()
        labelServerConnect.configure(image=serverConnectedSmall)
        labelServerConnect.place(x=80, y=320)
        labelServerConnect.lift()
        labelWaitingTap.place(x=460, y=260)
        labelLeft.grid(row=1, column=0)
        labelRight.grid(row=1, column=1)
        app.update_idletasks()
        reader.SaveSettingToFile()
        initialState = False
    else:
        runnMainProgram(reader)
    app.update()
    app.after(1000, functools.partial(initState, reader, ReaderName, readerType, serialport, baud, databit, readerPacket))

def runnMainProgram(reader):
    try:
        check = reader.StartReader(reader._CARDANDPASSWORD)
        app.update_idletasks()
        if check == True:
            print "Open the door"
            check = ""
            print "Ready..."
            app.update_idletasks()
        elif check == False:
            print "Doesn't Open The Door"
            check = ""
            print "Ready..."
            app.update_idletasks()
        elif check == 2:
            print "Reader disconnect"
            print "Reconnecting to Reader"
            reader.ClosePort()
            while not reader.OpenPort():
               count += 1
               count = 0
            check = ""
            print "Ready..."
            app.update_idletasks()
    except KeyboardInterrupt:
        exit()
    app.after(10, functools.partial(runnMainProgram, reader))

app = Tk()
app.title("Access Control")
app.geometry('800x610+200+50')
app.protocol('WM_DELETE_WINDOW', closewindow)
updateGUIThread = threading.Thread(target=updateGUI)

app.minsize('800', '610')
app.maxsize('800', '610')

"I'm create Tkinter widget here."

reader = Readers()
settingList = list()
readerType = ""
readerPacket = ""
try:
    for line in fileinput.FileInput("Setting.txt", mode='r'):
        settingList.append(line)
        if str(line).find("DF760MSB", 0, len(str(line))) >= 0:
            readerType = reader._DF760MSB
        elif str(line).find("DF760LSB", 0, len(str(line))) >= 0:
            readerType = reader._DF760LSB
        else:
            readerType = reader._DF760MSB

        if str(line).find("SINGLEPACKET", 0, len(str(line))) >= 0:
            readerPacket = reader.SINGLEPACKET
        elif str(line).find("MULTIPACKET", 0, len(str(line))) >= 0:
            readerPacket = reader.MULTIPACKETS
        else:
           readerPacket = reader.SINGLEPACKET

    ReaderName = str(settingList[0]).rstrip()
    baud = int(settingList[1])
    databit = int(settingList[2])

    HOST = str(settingList[3]).rstrip()
    PORT = int(settingList[4])
    TIMEOUT = int(settingList[5])
except:
    ReaderName = "R001"
    baud = 19200
    databit = 8
    HOST = "10.50.41.81"
    PORT = 43
    TIMEOUT = 10
serialport = 'COM3'
reader.SettingServer(HOST, PORT, TIMEOUT)
app.after(100, functools.partial(initState, reader, ReaderName, readerType, serialport, baud, databit, readerPacket))
app.mainloop()

когда я запускаю этот код, графический интерфейс пользователя зависает, но последовательный порт и клиентский сокет TCP все еще работают. Я пытаюсь решить эту проблему (ищу везде), но у меня ничего нет. Есть идеи? Большое спасибо.


person Mysterylz    schedule 23.01.2015    source источник
comment
Tkinter — это однопоточный модуль. Попробуйте использовать after   -  person Alok    schedule 23.01.2015
comment
Да, я делаю, но не работает.   -  person Mysterylz    schedule 23.01.2015


Ответы (1)


Способ решить эту проблему — вызвать app.after(100, <methodName>) из принимающего потока. Это предотвращает блокировку основного потока ожиданием сигнала, но также означает, что tkinter также может обновляться мгновенно, поскольку метод, помещенный в .after, будет выполняться в основном потоке. Указав 100 в качестве временного интервала, он изменится почти мгновенно, поскольку переданный аргумент — это количество миллисекунд.

person Benjamin James Drury    schedule 23.01.2015
comment
after(1,...) сомнительный совет. Если вы работаете каждую миллисекунду, вы будете голодать в цикле событий. Он будет настолько занят выполнением вашей функции 1000 раз в секунду, что ему будет трудно обрабатывать любые события. - person Bryan Oakley; 23.01.2015
comment
Верно, но я думаю, это зависит от того, как часто программа получает данные. Там, где я применял эту технику в прошлом, она работала нормально, но опять же, это должно было происходить только при случайном нажатии клавиши, то есть примерно раз в секунду или две. Я не вижу другого пути решения проблемы, хотя? - person Benjamin James Drury; 23.01.2015
comment
Я думаю, вы неправильно интерпретируете мой комментарий. after великолепен и решает многие проблемы, которые люди пытаются решить с помощью потоков. Я использую after почти в каждой программе tkinter, которую пишу. Проблема заключается в использовании аргумента 1. Обычно вы должны выбрать большее число, которое ближе к тому, что необходимо. Если вы делаете что-то каждую секунду или две, проверка условия 1000 раз в секунду является расточительной и потенциально может иметь негативные побочные эффекты. - person Bryan Oakley; 23.01.2015
comment
О, я вижу, да, я неправильно понял, что вы сказали изначально. Я отредактировал свой оригинальный ответ. - person Benjamin James Drury; 23.01.2015
comment
Всем спасибо, ребята. Я сделаю все, что вы мне сказали. - person Mysterylz; 24.01.2015