Python Forum
Tkinter widgets not fully loading
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tkinter widgets not fully loading
#1
Can someone please help me troubleshoot this problem.
I have a top level window that asks a user to scan a RFID card and asks how long to activate the card for. Problem is, the window displays the buttons but they can not be pressed until the called function scanCardLoop has return a value. This is a problem as the close window button, and the window 'x' button can not be activated:

	def activateCard():

		#Instantiate a Toplevel window
		activateCardWindow = Toplevel()
		TopLevelWindow(activateCardWindow, 300, 300, "Activate Card")
		
		label = Label(activateCardWindow, text="Scan to activate:", height=0, width=100)
		label.pack(side='top')
		
		#Entry box for the returned value of the RFID card
		scancard = Entry(activateCardWindow)
		scancard.pack(side = TOP)
		
		#Buttons requesting how long to activate for
		hourBtn = Button(activateCardWindow, text="1 hour", width=20)
		halfDayBtn = Button(activateCardWindow, text="Half day", width=20)
		allDayBtn = Button(activateCardWindow, text="All day", width=20)
		allDayBtn.pack(side='bottom', pady=5)
		halfDayBtn.pack(side='bottom')
		hourBtn.pack(side='bottom', pady=5)
		
		#For some reason this update has to be called otherwise the calling root window will not load this window
		activateCardWindow.update()
		
		#Call the scanCardLoop and place the returned value into tagID
		tagID = scanCardLoop()
		
		#Please tagID into entry box
		scancard.insert(END, tagID)

	def scanCardLoop():
		waitingForScan = True
		
		while waitingForScan == True:
			# Scan for cards    
			(status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)
			# If a card is found
			#if status == MIFAREReader.MI_OK:
				#print("Card detected")
			# Get the UID of the card
			(status,uid) = MIFAREReader.MFRC522_Anticoll()
			# If we have the UID, continue
			if status == MIFAREReader.MI_OK:
				# Store tag ID
				#global rftagID
				rftagID.set("%s,%s,%s,%s" % (uid[0], uid[1], uid[2], uid[3]))
				# Print UID
				print("Card read UID: %s,%s,%s,%s" % (uid[0], uid[1], uid[2], uid[3]))
				waitingForScan = False

		return rftagID.get()
I suspect that there is some update issue going on.
Reply
#2
(Mar-27-2018, 03:16 PM)nortski Wrote: # Print UID
print("Card read UID: %s,%s,%s,%s" % (uid[0], uid[1], uid[2], uid[3]))
waitingForScan = False

return rftagID.get()
[/python]

I suspect that there is some update issue going on.
maybe
            # Print UID
            print("Card read UID: %s,%s,%s,%s" % (uid[0], uid[1], uid[2], uid[3]))
            waitingForScan = False
        root.update_idletasks()
    return rftagID.get() 
would fix it. ( Not that I have tried it)
Reply
#3
It is a design problem. A while loop hogs the processor as it is always running, which doesn't allow for anything else to happen. You should seriously consider using a class for this so you can use instance objects for rftagID and anything else you want to keep. This also allows you to use after() instead of a while loop, which means you can do other things while scanCardLoop() is running.

""" A simple example that uses a counter to print to the screen
    from a function repeatedly called by after{}
    You can also enter data into the Entry while the counter function is running to show
     that other things can happen simultaneously
"""
import sys
if sys.version_info[0] < 3:
    import Tkinter as tk     ## Python 2.x
else:
    import tkinter as tk     ## Python 3.x

class TestClass():

   def __init__(self):
      self.top = tk.Tk()
      self.top.title("Test of After")
      self.top.geometry("200x150+10+10")

      tk.Label(self.top, text="Timer Test ").pack(side="left" )
      entry_1 = tk.Entry(self.top, width=10)
      entry_1.pack(side="left")
      entry_1.focus_set()

      ## self.ctr is an instance object, so retains it's value
      self.ctr = 1
      self.printit()
      self.top.mainloop()

   def printit(self):
      print("print 1", self.ctr)
      self.ctr += 1

      ## simulate if a condition is True
      if self.ctr < 100:
          self.top.after(100, self.printit)
      else:
          print("\nloop ended")
          self.top.quit()

##====================================================================
if __name__ == '__main__':
    CT=TestClass() 
    ## tkinter has exited. This shows how to get the value of a variable.
    print("\ncounter's value is %d" % (CT.ctr))
Reply
#4
(Mar-28-2018, 04:11 PM)woooee Wrote: It is a design problem. A while loop hogs the processor as it is always running, which doesn't allow for anything else to happen. You should seriously consider using a class for this so you can use instance objects for rftagID and anything else you want to keep. This also allows you to use after() instead of a while loop, which means you can do other things while scanCardLoop() is running.

""" A simple example that uses a counter to print to the screen
    from a function repeatedly called by after{}
    You can also enter data into the Entry while the counter function is running to show
     that other things can happen simultaneously
"""
import sys
if sys.version_info[0] < 3:
    import Tkinter as tk     ## Python 2.x
else:
    import tkinter as tk     ## Python 3.x

class TestClass():

   def __init__(self):
      self.top = tk.Tk()
      self.top.title("Test of After")
      self.top.geometry("200x150+10+10")

      tk.Label(self.top, text="Timer Test ").pack(side="left" )
      entry_1 = tk.Entry(self.top, width=10)
      entry_1.pack(side="left")
      entry_1.focus_set()

      ## self.ctr is an instance object, so retains it's value
      self.ctr = 1
      self.printit()
      self.top.mainloop()

   def printit(self):
      print("print 1", self.ctr)
      self.ctr += 1

      ## simulate if a condition is True
      if self.ctr < 100:
          self.top.after(100, self.printit)
      else:
          print("\nloop ended")
          self.top.quit()

##====================================================================
if __name__ == '__main__':
    CT=TestClass() 
    ## tkinter has exited. This shows how to get the value of a variable.
    print("\ncounter's value is %d" % (CT.ctr))

I ended up removing the infinite while loop and used the after() method instead. Works fine now thanks!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  make widgets disappear from tkinter jacksfrustration 12 940 Feb-06-2024, 03:58 PM
Last Post: deanhystad
  [PyQt] Determine whether text in QTableView cell is fully visible or not random_nick 0 957 Oct-27-2022, 09:29 PM
Last Post: random_nick
  .get() from generated Entry widgets in tkinter snakes 4 4,157 May-03-2021, 11:26 PM
Last Post: snakes
  [Tkinter] Loading Images to Tkinter with Pillow Tomli 2 12,883 Jun-18-2020, 03:26 AM
Last Post: Tomli
  Using Tkinter widgets on child window chewy1418 8 7,098 Feb-27-2020, 10:34 PM
Last Post: Marbelous
  Make a fully functional program as a library frequency 3 2,589 Dec-26-2018, 12:18 PM
Last Post: frequency
  [Tkinter] Tkinter widgets driving Arduino uno output pins woodcncwnc 3 4,496 Jan-29-2018, 08:21 PM
Last Post: woodcncwnc
  Tkinter widgets not appearing (3.x) RSAngryfiend 1 9,197 Jul-05-2017, 09:13 PM
Last Post: nilamo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020