2017-06-20 75 views
1

我正在編寫一個Python程序,用於監聽RFID輸入,並且只在出現有效令牌時才運行。該程序還有一個我想用TkInter構建的GUI。如果調用另一個函數,TkInter框架不會加載

拼圖的兩個部分都可以很好地隔離,但是因爲它似乎可以選擇其中之一 - 但不能同時兼得!我可以很好地畫出我的TkInter窗口,但是如果我調用該函數開始監聽RFID輸入,然後該位運行正常並且可以正常工作...則不需要GUI。

代碼如下。你可以看到我的調試工作,到目前爲止我的打印輸出到終端...

 
    #!/usr/bin/env python3 
    import sys 
    import MySQLdb 

    if sys.version_info[0] == 2: 
     from Tkinter import * 
     import Tkinter as ttk 
    else: 
     from tkinter import * 
     import tkinter as ttk 

    class Fullscreen_Window: 
     def __init__(self): 
      self.tk = Tk() 
      self.frame = Frame(self.tk) 
      self.frame.pack() 
      ttk.Button(self.tk, text="hello world").pack() 

      self.tk.attributes('-zoomed', True) 
      self.state = False 
      self.tk.bind("<F11>", self.toggle_fullscreen) 
      self.tk.bind("<Escape>", self.end_fullscreen) 

      print("init running") 
      self.listen_rfid() # Commenting this out makes the GUI appear, uncommenting means no GUI :(

     def toggle_fullscreen(self, event=None): 
      self.state = not self.state # Just toggling the boolean 
      self.tk.attributes("-fullscreen", self.state) 
      print("Toggling") 
      return "break" 

     def end_fullscreen(self, event=None): 
      self.state = False 
      self.tk.attributes("-fullscreen", False) 
      return "break" 

     def listen_rfid(self): 
      print("Main loop running") 
      dbHost = 'localhost' 
      dbName = 'python' 
      dbUser = 'python' 
      dbPass = 'PASSWORD' 

      dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName) 
      cur = dbConnection.cursor(MySQLdb.cursors.DictCursor) 

      with open('/dev/stdin', 'r') as tty: 
       while True: 
        RFID_input = tty.readline().rstrip() 
        cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (RFID_input)) 

        if cur.rowcount != 1: 
         print("ACCESS DENIED") 
        else: 
         user_info = cur.fetchone() 
         print("Welcome %s!!" % (user_info['name'])) 


      tty.close() 
      listen_rfid() 

    if __name__ == '__main__': 
     w = Fullscreen_Window() 
     w.tk.mainloop() 

我敢肯定,這是很簡單的東西,但因爲我一個Python/Tkinter的的n00b它的毆打我和我所有的完成谷歌搜索。任何幫助感激地收到:)

+0

「Fulscreen_Window.listen_rfid」調用定義的函數「listen_rfid」在哪裏?那應該是'self.listen_rfid'? – FamousJameous

+0

在定義「end_fullscreen」函數之後,它在第38行定義。 –

+0

那麼你的意思是'self.listen_rfid'? – FamousJameous

回答

1

Tkinter(和所有圖形用戶界面)有一個無限循環稱爲主循環,保持GUI活躍和響應。當你進行另一個無限循環(while True)時,你會阻塞Tkinter的主循環;並且GUI失敗。您需要將您的循環放在單獨的線程中,或者使用Tkinter的主循環來完成您的工作。由於您正在使用阻止readline,因此該線程是最佳途徑。作爲一個猜測,用這個替換你的電話:

from threading import Thread 
t = Thread(target=self.listen_rfid) 
t.daemon = True # this line tells the thread to quit if the GUI (master thread) quits. 
t.start() 

編輯:順便說一句,你的進口是非常糟糕的。 「ttk」是tkinter的一個子集,不是別名,別名「tk」通常用於tkinter,通配符導入不好,應該避免。這是你的Tkinter進口應該是什麼樣子:

try: 
    # python 2 
    import Tkinter as tk 
    import ttk 
except ImportError: 
    # python 3 
    import tkinter as tk 
    from tkinter import ttk 

然後使用適當的前綴:

self.tk = tk.Tk() 
self.frame = tk.Frame(self.tk) 
+0

非常感謝,現在工作非常好。謝謝你的解釋。理解起來非常合理:) –

+0

雖然他們現在都在工作,但listen_rfid函數似乎只能監聽並響應輸入,而終端(從運行程序的位置)擁有焦點。如果GUI框架具有焦點,則它不響應輸入。 我已經改變了「訪問被拒絕」/「歡迎」消息輸出到幀,如果終端有焦點,他們會很好地完成,但如果幀被聚焦,則不會。任何指針? –

1

你應該使用after運行listen_rfid。問題在於listen_rfid正如你所寫的那樣會永遠運行,這意味着mainloop永遠不會啓動。如果你這樣做:

#!/usr/bin/env python3 
import sys 
import select 
import MySQLdb 

if sys.version_info[0] == 2: 
    from Tkinter import * 
    import Tkinter as ttk 
else: 
    from tkinter import * 
    import tkinter as ttk 

class Fullscreen_Window: 
    def __init__(self): 
     self.tk = Tk() 
     self.frame = Frame(self.tk) 
     self.frame.pack() 
     ttk.Button(self.tk, text="hello world").pack() 

     self.tk.attributes('-zoomed', True) 
     self.state = False 
     self.tk.bind("<F11>", self.toggle_fullscreen) 
     self.tk.bind("<Escape>", self.end_fullscreen) 

     print("init running") 
     # Schedule self.listen_rfid to run after the mainloop starts 
     self.tk.after(0, self.listen_rfid)  

    def toggle_fullscreen(self, event=None): 
     self.state = not self.state # Just toggling the boolean 
     self.tk.attributes("-fullscreen", self.state) 
     print("Toggling") 
     return "break" 

    def end_fullscreen(self, event=None): 
     self.state = False 
     self.tk.attributes("-fullscreen", False) 
     return "break" 

    def listen_rfid(self): 
     print("Main loop running") 
     dbHost = 'localhost' 
     dbName = 'python' 
     dbUser = 'python' 
     dbPass = 'PASSWORD' 

     dbConnection = MySQLdb.connect(host=dbHost, user=dbUser, passwd=dbPass, db=dbName) 
     cur = dbConnection.cursor(MySQLdb.cursors.DictCursor) 

     # readline is blocking so check that there is input 
     # before attempting to read it. 
     r, w, x = select.select([sys.stdin], [], [], 0) 
     if r: 
      # There is available input, so read a line. 
      RFID_input = sys.stdin.readline().rstrip() 
      cur.execute("SELECT * FROM access_list WHERE rfid_code = '%s'" % (RFID_input)) 

      if cur.rowcount != 1: 
       print("ACCESS DENIED") 
      else: 
       user_info = cur.fetchone() 
       print("Welcome %s!!" % (user_info['name'])) 

     # keep running every 500 milliseconds for as long as 
     # the mainloop is active. 
     self.tk.after(500, self.listen_rfid) 

if __name__ == '__main__': 
    w = Fullscreen_Window() 
    w.tk.mainloop() 

將第二檢查每半是否有在命令行中輸入一些並處理它。

+0

'readline'被阻塞。它不會「檢查」,它會等待(鎖定程序),直到出現一些輸入。 – Novel

+0

這就是爲什麼我首先使用'select'檢查輸入。 – FamousJameous

+0

啊我錯過了,對不起。 – Novel

相關問題