Python как использовать графический интерфейс Tkinter, не вмешиваясь в основной цикл кода

#python #python-3.x #tkinter #raspberry-pi

#python #python-3.x #ткинтеръ #raspberry-pi #tkinter

Вопрос:

Я хотел бы реализовать очень простой графический интерфейс для своего проекта. Ранее я использовал только операторы печати для вывода некоторого текста и данных. Однако это не очень удобно, и поскольку человеку нужно будет управлять устройством, которое я кодирую, он должен четко видеть инструкции, которые я собираюсь отобразить в графическом интерфейсе.

мой код:

 main()
myConnection = mysql.connector.connect( host=hostname, user=username, passwd=password, db=database )
counter = 0

window = tk.Tk()
window.title("GUI")
window.geometry("400x200")

while(1):

    # OPERACIJOS KODAI:
    # 0 - PILDYMAS
    # 1 - KOMPLEKTAVIMAS
    # 2 - NETINKAMAS KODAS
    tk.Label(window,text = "Scan barcode here:").pack()
    entry = tk.Entry(window)
    entry.pack()
    var = tk.IntVar()
    button = tk.Button(window,text="Continue",command = lambda: var.set(1))
    button.pack()
    print("waiting...")
    button.wait_variable(var)
    result = entry.get()
    print("Entry string=",result)
    var.set(0)

    
    operacijos_kodas=Scanning_operation(myConnection,result)
    print("operacijos kodas=",operacijos_kodas)
    if(operacijos_kodas == 0):
        tk.label(window,text = "PILDYMO OPERACIJA:").pack()

        pildymo_operacija(myConnection)
   
        
    elif(operacijos_kodas == 1):
        tk.Label(window,text = "PAKAVIMO OPERACIJA:").pack()

        insertData_komplektacija(myConnection,"fmb110bbv801.csv");
        update_current_operation(myConnection);
        picking_operation();
        
    elif(operacijos_kodas == 2):
        print("Skenuokite dar karta")
        #break
   window.mainloop();
  

Ничего не отображается. Он просто открывает пустое окно графического интерфейса.

Прежде всего, я не уверен, где мне следует вызывать функцию window.mainloop() .

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

Может ли кто-нибудь подсказать мне, подходит ли этот графический интерфейс для моих нужд, или я должен искать альтернативы?

Обновить*********************

Я пытался использовать mainloop:

 print ("Using mysql.connector…")
main()
GPIO_SETUP() 
myConnection = mysql.connector.connect( host=hostname, user=username, passwd=password, db=database )
counter = 0
window = tk.Tk()
window.resizable(False,False)
window_height = 1000
window_width = 1200
#window.attributes('-fullscreen',True)
#window.config(height=500,width=500)
#can = Canvas(window,bg='red',height=100,width=100)
#can.place(relx=0.5,rely=0.5,anchor='center')
window.title("GUI")
screen_width = window.winfo_screenwidth()
screen_height= window.winfo_screenheight()
x = int((screen_width/ 2) - (window_width / 2))
y = int((screen_height/ 2) - (window_height / 2))   
window.geometry("{}x{} {} {}".format(window_width,window_height,x,y))
label1=Label(window,text = "SKENUOKITE BARKODA(GUID) ARBA DAIKTO RIVILINI KODA:")
label1.pack()
entry = Entry(window)
entry.pack()
var = tk.IntVar()
button = Button(window,text="Testi operacija",width = 30,command = lambda: var.set(1))
button.pack()
#button2 = Button(window,text="RESTARTUOTI SISTEMA",width = 30,command = restart_devices())
#button2.pack()
print("waiting...")    
button.wait_variable(var)
Scanned_serial = entry.get()
print("Entry string=",Scanned_serial) 
var.set(0)
label2=Label(window,text = "Vykdoma operacija:")
label2.pack()
window.update()
window.after(1000,Full_operation(Scanned_serial,label2,window))
window.mainloop()
  

Это мой код. Как вы можете видеть. я вызываю функцию Full_operation, а затем window.mainloop()

моя Полная Операция:

 def Full_operation(Scanned_serial,label2,window):
    operacijos_kodas=Scanning_operation(myConnection,Scanned_serial)
    print("operacijos kodas=",operacijos_kodas)
    if(operacijos_kodas == 0):

        label2.config(text = "SPAUSKITE MYGTUKA ANT DEZES KURIA NORITE PILDYTI:")#update the label2
        window.update()#call update to update the label
        pildymo_operacija(myConnection,Scanned_serial,label2,window)
        
    elif(operacijos_kodas == 1):
        insertData_komplektacija(myConnection,"fmb110bbv801.csv");
        update_current_operation(myConnection);
        #label2.config(text = "IMKITE DAIKTUS IS ZALIOS DEZUTES:")#update the label2
        picking_operation(myConnection,label2);
        
    elif(operacijos_kodas == 2):
        print("Skenuokite dar karta")
        label2.config(text = "NUSKENUOTAS NEGALIMAS KODAS:")#update the label2
        window.update()#call update to update the label

  

Как я могу гарантировать, что каждый раз, когда я вхожу в функцию FUll_operation, я снова запускаю чистый графический интерфейс и запускаю другую операцию.

Теперь я могу завершить операцию один раз. После этого графический интерфейс перестает реагировать. Я добавил инструкцию print в начале моей full_operation, и она не выполняется после того, как я завершу ее один раз, поэтому мое mainwindow, похоже, не работает должным образом.

Ответ №1:

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

Mainloop следует вызывать только один раз.

Я бы посоветовал вам перенести все ваши операции сканирования / сохранения в отдельную функцию, которую вы планируете периодически выполнять, используя метод tkinter after .

Например, если вы вызываете свою функцию scan , вы бы запланировали, чтобы это произошло через 1 секунду, используя

 root.after(1000, scan)
  

Более продвинутым методом было бы запустить ваш код сканирования в отдельном потоке.

Кроме того, в настоящее время вы пытаетесь создавать метки каждый раз, когда выполняете цикл while, вместо того, чтобы просто создавать и упаковывать их один раз и обновлять текст меток при выполнении «сканирования». Вы можете обновить текст метки, используя метод config, например

 ## Create a label
label1 = tk.Label(window,text = "PAKAVIMO OPERACIJA:")
##Pack the label
label1.pack()

## Update the text later
label1.config(text="New Text")
  

Вот пример периодического обновления виджетов tkinter из функции.

 import tkinter as tk
import random

def scanning():
    num = random.randint(0,100)
    entryTemperature.delete(0, tk.END) #Delete the current contents
    entryTemperature.insert(0, f"{num} K") #Add new text
    root.after(1000, scanning) #Schedule the function to run again in 1000ms (1 second)


root = tk.Tk()
entryTemperature = tk.Entry(root)
entryTemperature.grid(padx=50,pady=50)

root.after(1000, scanning)
root.mainloop()
    
  

Комментарии:

1. Большое вам спасибо за полезные советы. Я постараюсь прочитать и узнать о tkinter после метода. Самая сложная часть — правильно запустить программу. В начале каждой операции пользователю необходимо отсканировать штрих-код, после этого графическому интерфейсу просто нужно обновить текст на экране, не более того. Итак, если я смогу заставить обновление текста работать, это будет большая часть моего графического интерфейса. Кроме того, имеет ли значение, где я вызываю mainloop, или это не важно, если я вызываю его хотя бы один раз

2. Вы должны выполнить всю свою настройку, создать графический интерфейс и затем вызвать mainloop. Как только вы вызовете mainloop, никакой код за пределами этой строки не будет выполнен, пока графический интерфейс не будет закрыт.

3. Но как я могу использовать свою программу, если никакой код за пределами mainloop не будет выполнен? Потому что мне нужно, чтобы моя программа работала 24/7, поэтому я не могу вызвать mainloop?

4. @Lukas Вы планируете вызывать функции с помощью .after метода. Основной цикл tkinter выполнит это за вас. Создание графического интерфейса — это другой метод программирования, при котором что-то происходит при таких событиях, как нажатие кнопки или ввод текста, или в вашем случае функция, запланированная для периодического выполнения с .after

5. @Lukas Я добавил пример к своему ответу. Надеюсь, это ответит на ваш вопрос, и вы можете рассмотреть возможность его повышения или принятия в качестве принятого ответа.