pythonuser-interfacewxpythonnfc-p2p

how to run nfcpy card reader system on wxPython GUI application


I am new to wxPython GUI application

i want to create my python script as GUI application

This is my sample script

import binascii
import nfc

class MyCardReader(object):

   def on_connect(self, tag):
      print "touched"
      self.idm = binascii.hexlify(tag.idm)
      return True

   def read_id(self):
      clf = nfc.ContactlessFrontend('usb')
      try:
         clf.connect(rdwr={'on-connect': self.on_connect})
      finally:
         clf.close()

if __name__ == '__main__':
  cr = MyCardReader()
  while True:
    print "touch card:"
    cr.read_id()
    print "released"
    print cr.idm

how to run the above script as GUI app using wxPython, i was already try but it doesnt work, what is wrong in my code.

#-*- encoding: utf-8 -*-
import wx
import nfc
import binascii
class MyFrame(wx.Frame):

   def __init__(self, parent, title):
      wx.Frame.__init__(self, parent, title=title, size=(400, 500))
      panel = wx.Panel(self)
      self.Show(True)
      while True:
        clf = nfc.ContactlessFrontend('usb')
        clf.connect(rdwr={'on-connect': self.on_connect})
        self.text = wx.StaticText(panel, label='i want to print the return value here', pos=(100, 100))

  def on_connect(self, tag):
      self.idm = binascii.hexlify(tag.idm)
      return self.idm

app = wx.App(False)
frame = MyFrame(None, 'card reader app')
app.MainLoop()

Solution

  • The nfc.ContactlessFrontend.connect() method operates within the callers thread context, thus not returning before at least a tag has been connected (and if the 'on-connect' callback returns True it will further wait until the tag is gone). The wx.App.mainLoop() does also run within the callers thread context to dispatch window events. The correct way is thus to run the tag discovery within a separate thread and send events to the render frame. Below is an example that shows the tag identifier whenever a tag is close to the reader.

    #!/usr/bin/env python
    import wx
    import wx.lib.newevent
    import nfc
    import threading
    from binascii import hexlify
    
    ShowCardEvent, SHOW_CARD_EVENT = wx.lib.newevent.NewEvent()
    GoneCardEvent, GONE_CARD_EVENT = wx.lib.newevent.NewEvent()
    
    
    class TagReader(threading.Thread):
        def __init__(self, wx_frame):
            super(TagReader, self).__init__(name="TagReader")
            self.terminate = False
            self.wx_frame = wx_frame
    
        def run(self):
            clf = nfc.ContactlessFrontend('usb')
            rdwr_options = {
                'on-connect': self.on_tag_connect,
                'on-release': self.on_tag_release
            }
            while not self.terminate:
                clf.connect(rdwr=rdwr_options, terminate=lambda: self.terminate)
    
        def on_tag_connect(self, tag):
            wx.PostEvent(self.wx_frame, ShowCardEvent(tag=tag))
            return True
    
        def on_tag_release(self, tag):
            wx.PostEvent(self.wx_frame, GoneCardEvent())
    
    
    class Frame(wx.Frame):
        def __init__(self, title):
            super(Frame, self).__init__(None, title=title, size=(500, 200))
            self.text = wx.StaticText(wx.Panel(self), pos=(100, 100))
            self.Bind(SHOW_CARD_EVENT, self.show_card_event)
            self.Bind(GONE_CARD_EVENT, self.gone_card_event)
            self.Bind(wx.EVT_CLOSE, self.close_window_event)
            wx.PostEvent(self, GoneCardEvent())
            self.Show()
    
        def close_window_event(self, event):
            self.Destroy()
    
        def show_card_event(self, event):
            self.text.SetLabel("Card ID {}".format(hexlify(event.tag.identifier)))
    
        def gone_card_event(self, event):
            self.text.SetLabel("no card")
    
    
    app = wx.App()
    reader = TagReader(Frame('card reader app'))
    reader.start()
    app.MainLoop()
    reader.terminate = True  # tell the reader to terminate
    reader.join()  # and wait for the reader thread to finish