简体   繁体   English

kivy 点击按钮加载相机(zbarscan)

[英]kivy load camera (zbarscan) on click button

I've just started my first kivy app.我刚刚启动了我的第一个 kivy 应用程序。 The app is intended to start with button "Start Scan" and then show up the QR scanner built with ZBarCam.该应用程序旨在从“开始扫描”按钮开始,然后显示使用 ZBarCam 构建的 QR 扫描仪。

I'm using Screens with the ScreenManager to change from the button view to the camera view (with zbarcam), the problem is that I realized that the camera is initialized from the beginning, so before clicking on the button the camera is already on (I know it because the led from the camera is on).我正在使用带有ScreenManager的屏幕从按钮视图更改为相机视图(使用 zbarcam),问题是我意识到相机是从一开始就初始化的,所以在点击按钮之前相机已经打开(我知道是因为相机的指示灯亮着)。

I don't know if Screen should not be used in this case, or if is there a way to tell the app to do not initialize all screens.我不知道在这种情况下是否不应使用 Screen,或者是否有办法告诉应用程序不要初始化所有屏幕。

The code I'm using is the following:我使用的代码如下:

QrApp.py: QrApp.py:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen


class QrReader(Screen):
    pass

class ScanButton(Screen):
    pass

class QrApp(App):
    pass

if __name__ == '__main__':
    QrApp().run()

qrapp.kv: qrapp.kv:

ScreenManager:
    id: screen_manager
    ScanButton:
        id: scan_btn
        name: 'scan_btn'
        manager: 'screen_manager'
    QrReader:
        id: qr_reader
        name: 'qr_reader'
        manager: 'screen_manager'


<ScanButton>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text:'Start Scan'
            font_size:"50sp"
            color: [0, 255, 255, .67]
            on_press: app.root.current = 'qr_reader'

<QrReader>:
    #:import ZBarCam kivy_garden.zbarcam.ZBarCam
    BoxLayout:
        orientation: 'vertical'
        ZBarCam:
            id:qrcodecam
        Label:
            size_hint: None, None
            size: self.texture_size[0], 50
            text: ' '.join([str(symbol.data) for symbol in qrcodecam.symbols])

Thanks!谢谢!

==== ALTERNATIVE BASED IN A COMMENT (still fails) ==== ==== 基于评论的备选方案(仍然失败)====

Based on the comment from n4321d I tried to add the ZBarCam as widget in the QrReader Screen.根据n4321d评论,我尝试将 ZBarCam 添加为QrReader屏幕中的小部件。 While I can now initiate the camera when the widget is added, I don't see how I can get the symbols that is, the text read from the QR.虽然我现在可以在添加小部件时启动相机,但我看不到如何获取symbols ,即从 QR 读取的文本。

This alternative code is the following:此替代代码如下:

QrApp.py: QrApp.py:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen


class QrReader(Screen):
    def on_enter(self):
        from kivy_garden.zbarcam import ZBarCam
        zbarcam = ZBarCam()
        self.add_widget(zbarcam)
        self.add_widget(Label(
            text='PRINT SYMBOLS', #' '.join([str(symbol.data) for symbol in zbarcam.symbols] does not work
            size_hint=(None,None),
            size=(Window.width*0.1, Window.height*0.1),
            center=(Window.width*0.3, Window.height*0.5)))

class ScanButton(Screen):
    pass

class QrApp(App):
    pass

if __name__ == '__main__':
    QrApp().run()

qrapp.kv qrapp.kv

ScreenManager:
    id: screen_manager
    ScanButton:
        id: scan_btn
        name: 'scan_btn'
        manager: 'screen_manager'
    QrReader:
        id: qr_reader
        name: 'qr_reader'
        manager: 'screen_manager'

<ScanButton>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text:'Start Scan'
            font_size:"50sp"
            color: [0, 255, 255, .67]
            on_press:
                app.root.current = 'qr_reader'


<QrReader>:
    BoxLayout:
        orientation: 'vertical'

====== SOLUTION ======== ======解决方案========

My workaround solution is posted as an answer to this question here我的变通解决方案作为此问题的答案发布在此处

Thanks to answer from n4321d I finally found a solution.感谢n4321d回答,我终于找到了解决方案。

I also struggled releasing the camera, as zbarcam.stop() stops zbarcam but camera was apparently still open (led was on).我也很难释放相机,因为zbarcam.stop()停止 zbarcam 但相机显然仍然打开(led 亮着)。 After digging a lot, I found this workaround which seems to work well to release the camera.经过大量挖掘后,我发现这种解决方法似乎可以很好地释放相机。

I also merged the button and qr reader in the same Class and I no longer use kv file, in this example.在本例中,我还将按钮和 qr 阅读器合并到同一个类中,并且不再使用kv文件。 The final code is the following:最终代码如下:

QrApp.py: QrApp.py:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy_garden.zbarcam import ZBarCam

class QrScanner(BoxLayout):
    def __init__(self, **kwargs):
        super(QrScanner, self).__init__(**kwargs)
        btn1 = Button(text='Scan Me',  font_size="50sp")
        btn1.bind(on_press=self.callback)
        self.add_widget(btn1)

    def callback(self, instance):
        """On click button, initiate zbarcam and schedule text reader"""
        self.remove_widget(instance) # remove button
        self.zbarcam = ZBarCam()
        self.add_widget(self.zbarcam)
        Clock.schedule_interval(self.read_qr_text, 1)

    def read_qr_text(self, *args):
        """Check if zbarcam.symbols is filled and stop scanning in such case"""
        if(len(self.zbarcam.symbols) > 0): # when something is detected
            self.qr_text = self.zbarcam.symbols[0].data # text from QR
            Clock.unschedule(self.read_qr_text, 1)
            self.zbarcam.stop() # stop zbarcam
            self.zbarcam.ids['xcamera']._camera._device.release() # release camera



class QrApp(App):
    def build(self):
        return QrScanner()

if __name__ == '__main__':
    QrApp().run()

There is no way to lazy-load kivy Screen s.没有办法延迟加载 kivy Screen s。 Try this as a workaround: Do not let ScreenManager know about all Screen s.试试这个作为一种解决方法:不要让ScreenManager知道所有Screen s。 Use switch_to to remove the current screen and load the desired one instead.使用switch_to删除当前屏幕并加载所需的屏幕。 Check Kivy docs to learn how to use it.查看Kivy 文档以了解如何使用它。

First: I would also add an on_leave function where you remove your cam widget otherwise you will keep adding new widgets every time you load it.首先:我还将添加一个 on_leave 函数,您可以在其中删除 cam 小部件,否则每次加载时您都会不断添加新的小部件。

I dont have a working cam now , so i cannot test your code.我现在没有工作凸轮,所以我无法测试你的代码。 Looking at your code I think you have to bind the text in your Label to the text in zbarcam.symbols with a function: self.label = Label(....);查看您的代码,我认为您必须使用以下函数将 Label 中的文本绑定到 zbarcam.symbols 中的文本: self.label = Label(....); zbarcam.bind(symbols=lambda *x: setattr(self.label, "text", str(x[1]))) or somethign like that. zbarcam.bind(symbols=lambda *x: setattr(self.label, "text", str(x[1]))) 或类似的东西。

Here is an example using a random text generator instead of ZBarCam (since i cannot run that).这是一个使用随机文本生成器而不是 ZBarCam 的示例(因为我无法运行它)。

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ListProperty
import random
from kivy.clock import Clock


kv_str = """
ScreenManager:
    id: screen_manager
    ScanButton:
        id: scan_btn
        name: 'scan_btn'
        manager: 'screen_manager'
    QrReader:
        id: qr_reader
        name: 'qr_reader'
        manager: 'screen_manager'

<ScanButton>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text:'Start Scan'
            font_size:"50sp"
            color: [0, 255, 255, .67]
            on_press:
                app.root.current = 'qr_reader'


<QrReader>:
    BoxLayout:
        orientation: 'vertical'
"""

class ZBarCam(Label):
    symbols = ListProperty([])
    
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_interval(self.gen_rand_text, 1)

    def gen_rand_text(self, *args):
        self.text = random.choice(['aaaaa', 'bbbbb', 'ccccc'])
        self.symbols.append(self.text)
        if len(self.symbols) > 3:
            del self.symbols[0]


class QrReader(Screen):
    def on_enter(self):
        self.zbarcam = ZBarCam()
        self.add_widget(self.zbarcam)
        self.label = Label(
            text='PRINT SYMBOLS', #' '.join([str(symbol.data) for symbol in zbarcam.symbols] does not work
            size_hint=(None,None),
            size=(Window.width*0.1, Window.height*0.1),
            center=(Window.width*0.3, Window.height*0.5))
        self.add_widget(self.label)
        self.zbarcam.bind(symbols = lambda *x: setattr(self.label, "text", str(x[1])))
    
    def on_leave(self, *args):
        self.remove_widget(self.zbarcam)
        self.remove_widget(self.label)

class ScanButton(Screen):
    pass

class QrApp(App):
    def build(self):
        return Builder.load_string(kv_str)

if __name__ == '__main__':
    QrApp().run()

if it still does not work you might have to call self.zbarcam.start() too in the on_enter method after adding it如果它仍然不起作用,您可能必须在添加后在 on_enter 方法中调用 self.zbarcam.start()

hope this helps希望这可以帮助

Maybe so?也许是这样?

from kivy_garden.zbarcam import ZBarCam
from kivymd.uix.textfield import MDTextField

class MenuScreen(MDScreen):
    zbarcam: ZBarCam = ObjectProperty()
    qrfield: MDTextField = ObjectProperty()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.__cam_release()

    def scan(self, instance):
        self.__cam_release()

    def on_touch_down(self, touch):
        if self.zbarcam.collide_point(*touch.pos):
            self.__cam_open()
        return super().on_touch_down(touch)

    def __cam_release(self):
        if self.zbarcam.xcamera._camera._device.isOpened():
            self.zbarcam.stop()
            self.zbarcam.xcamera._camera._device.release()

    def __cam_open(self):
        if not self.zbarcam.xcamera._camera._device.isOpened():
            self.zbarcam.xcamera._camera._device.open(0)
            self.zbarcam.start()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM