1

What I would like to achieve is something like a self-checkout Kiosk.

So I would like to scan some barcodes. And have kivy screen show the list of item scanned. And when I have no more barcodes to scan, be able to press a button and calculate the price of all the items scanned.

I thought the best way to go about it is a while loop that keeps asking for inputs from the barcode scanner. And be able to break it by pressing a button on screen.

The problem is: when the loop is listening for input, all the buttons on screen hangs and cannot be pressed. So let's say I have no more barcode to scan but because the loop is still listening for input, the whole screen hangs. And i can't do anything except to terminate the whole script on terminal.

How should i go about resolving this problem?

How do these self checkout kiosks work? How are their codes like?

I read some suggestion about kivy clock. But even then when it reaches the part of the code that asks for input, it hangs.

What about "select", "subprocessing" or "threading"? Do you think it will resolve my problem? However, even after reading up on it, i have no clue how to implement it. If it is the right way to go about it, might you suggest some example code, pls?

I am using a mac, python 2.7, eventually would be running it on raspberry pi with LCD screen.

Here is my loop:

def getItem():
    while True:
        answer = input('What is the box ID? ')
        if answer == 999:   # to break out from loop
            break
        elif type(answer) == int:
            display on kivy screen
        else:
            print('Sorry I did not get that')

here's what it looks like on kivy:

kivy screen

Updated code:

this is in the kv file:

<ScreenTwo>:
    member_status: memberStatus
    box_no: boxNo
    text_in: textIn
    BoxLayout:
        Label:
            id: memberStatus
            text: '' 
        GridLayout:
            rows: 3
            padding: [100,500]
            spacing: 10
            BoxLayout:
                Label:
                    id: boxNo
                    text: ''
            BoxLayout:
                TextInput:
                    id: textIn
                    write_tab: False
                    multiline: False
                    on_text_validate:
                        root.sayHello()
                        self.text = ""
                        self.focus = True
                        #also tried root.inputFocus()
            BoxLayout:
                CustButton:
                    text: "Done"
                    on_press:
                        root.manager.transition.direction = "right"
                        root.manager.current = 'menu'
                        root.clearField()

this is in the py file:

class ScreenTwo(Screen):
    text_in = ObjectProperty(None)

    def inputFocus(self):
        self.manager.screen_two.text_in.focus = True
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Julliard
  • 523
  • 1
  • 6
  • 23
  • Why do you use the terminal and do not use a TextInput? – eyllanesc May 24 '18 at 08:16
  • @eyllanesc will it solve the issue? – Julliard May 24 '18 at 08:18
  • Obviously, my question is why use such archaic and ugly things: **input()** if the GUI offers modern and beautiful things: **TextInput()**. the input is blocking since they prevent the program from advancing and does not let the GUI follow its event loop. The event loop is necessary to check other events such as the mouse. The one who gave you the Clock solution does not know how a GUI should work or is forcing a bad solution. – eyllanesc May 24 '18 at 08:21
  • @eyllanesc Hahaha because I am a novice. Ok I am kinda understanding you. But can i clarify: With textinput column, when the barcode scans into the textinput, can it detect that there's an input and runs a function by automatically? – Julliard May 24 '18 at 08:27
  • 1
    Yes, the barcode scanner generates as an enter ("\n") at the end of execution, so the input() works for you, you must use the on_text_validate event but for this you must set the multiline property to False, for more information read the following: https://stackoverflow.com/questions/12037379/tab-enter-and-other-keystrokes-handling-in-kivys-textinput-widgets – eyllanesc May 24 '18 at 08:32
  • As I say the best way to learn is practice, write a small code and try it. – eyllanesc May 24 '18 at 08:33
  • Thank you that was very helpful! I hope to be able to clarify things with you after I try it out :) – Julliard May 24 '18 at 08:36
  • @eyllanesc It's working! However I am facing one issue. Right now, I have to click on the TextInput box every time I want to scan a new barcode. Is there anyway to have the TextInput box constantly/ automatically receive my scanner's input without me pressing on the box beforehand? – Julliard May 24 '18 at 09:27
  • Have you used the on_text_validate event? – eyllanesc May 24 '18 at 09:28
  • @KwokWenJian Please read [docs](https://kivy.org/docs/api-kivy.uix.textinput.html) first. – Kacperito May 24 '18 at 09:29
  • @eyllanesc Yes, I did use on_text_validate to run another function after it validates an input, and that works fine. However, the issue i am facing is I have to click on the empty TextInput box again before the scanner can input the next scanned code there. – Julliard May 24 '18 at 09:34
  • but then on_text_validate cleans the TextInput text – eyllanesc May 24 '18 at 09:36
  • on_text_validate doesn't clean the TextInput text by itself, but I did put "self.text = """ after on_text_validate. Does my problem has to do with focus? – Julliard May 24 '18 at 09:41
  • that's obvious, I did not say to clean it, but you must clean it as you did. in the same method, set it with `self.focus = True`after clean, for more information read: https://stackoverflow.com/questions/33176228/automatic-focus-of-textinput-kivy – eyllanesc May 24 '18 at 09:47
  • @eyllanesc I did come across that information. I tried self.focus = True, also tried making it into a function then calling it. but it doesn't work :/ – Julliard May 24 '18 at 09:58
  • You could show the code in which you are advancing in your question to check where the error is or give you alternatives. – eyllanesc May 24 '18 at 10:01
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/171680/discussion-between-kwok-wen-jian-and-eyllanesc). – Julliard May 24 '18 at 10:10

1 Answers1

1

You should not force things, input() is a blocking function that does not allow the GUI to run in an event loop, the event loop allows the GUI the ability to review other events and perform other tasks such as the mouse, so Your application is frozen.

Why use input() if you can use a TextInput? You must use what the GUI provides you since it is made to work with the GUI.

The Barcode Scanners send an enter at the end of establishing the text, that must be used through the event on_text_validate, in that event you must set the text in the Label, then clean the text and at the end the focus, for this last task you must do with a Clock that does it in the next iteration.

In the next section I show a minimal example.

import kivy

from kivy.app import App
from kivy.lang import Builder

from kivy.clock import Clock

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen

Builder.load_string('''
<ScreenTwo>:
    text_in: text_in
    memberStatus: memberStatus
    BoxLayout:
        orientation: 'vertical'
        Label: 
            id: memberStatus
        TextInput:
            id: text_in
            multiline: False
            on_text_validate:
                root.process_barcode()
    ''')

class ScreenTwo(Screen):
    def process_barcode(self):
        self.memberStatus.text = self.text_in.text
        self.text_in.text = ""
        Clock.schedule_once(lambda *args: setattr(self.text_in, 'focus', True))

class MyApp(App):
    def build(self):
        sm = ScreenManager()
        sm.add_widget(ScreenTwo(name="screen_two"))
        return sm

if __name__ == '__main__':
    MyApp().run()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241