简体   繁体   中英

Hi, I'm bulding a kivy app, how can I use the text input of one class(one window) in another class?

that's my first question here, I'm a total beginner at kivy, I'm trying to build a kivy application with multiple windows, the problem is that at some point I need to get a text input from a user and then use it in a different class, the problem is that I can't access the exact instance of the input, so if I initiate an instance it would be an empty string, someone suggested that I could use a container class and place the class that I wish to have the input from, with the class that I want to use the new input within, in the container class, and use the command App.get_running_app(), I don't want to use the container class since I don't want to display the content of the two classes at the same page, I wonder how can I get an exact instance from a class (the previously used screen) ?

Code: (please ignore the weird names)

Python file:(please ignore the weird names)

from turtle import Screen
import kivy
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from openpyxl import Workbook, load_workbook
from openpyxl.utils import get_column_letter
from tkinter import Label
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from itertools import groupby
from kivy.uix.popup import Popup
import pandas as pd


class Container(Screen):
    pass

class ScanQRCode(Screen):
    first_input = ObjectProperty(None)
    second_input = ObjectProperty(None)

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

    def ui_btn(self):
        print(self.first_input.text)
        print(self.second_input.text)


class GetInfoFromAnotherClass(Screen):
    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        self.app = App.get_running_app()

    def retrieve_info(self):
        print(self.app.root.ids.user_input_box.ids.first_input.text)
        print(self.app.root.ids.user_input_box.ids.second_input.text)

class MyApp(App):
    def build(self):
        return Container()

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

And now the kivy file:

<ScanQRCode>:

    first_input : first_input
    second_input : second_input


    FloatLayout:
        cols: 1

        FloatLayout:
            size: root.width, root.height/2
            Label:
                text: "Scan QRCode"
                size_hint: 0.8, 0.2
                pos_hint: {"x":0.1, "top":1}
                font_size: (root.width**2 + root.height**2) / 14**4

            TextInput:
                id: first_input
                pos_hint: {"x":0.15, "top":0.85}
                size_hint: 0.7, 0.15
                multiline: False
                font_size: (root.width**2 + root.height**2) / 14**4

            Label:
                text: "Repeat Scan"
                size_hint: 0.8, 0.2
                pos_hint: {"x":0.1, "top":0.68}
                font_size: (root.width**2 + root.height**2) / 14**4

            TextInput:
                id: second_input
                pos_hint: {"x":0.15, "top":0.52}
                size_hint: 0.7, 0.15
                multiline: False
                font_size: (root.width**2 + root.height**2) / 14**4

        Button:
            pos_hint:{"x":0.3,"y":0.22}
            size_hint: 0.4, 0.1
            font_size: (root.width**2 + root.height**2) / 14**4
            text: "print from same class"
            on_press: root.ui_btn()


<Container>:
    name: "Scan"
    GridLayout:

        cols: 1
        ScanQRCode:
            id: user_input_box
        GetInfoFromAnotherClass:

<GetInfoFromAnotherClass>:
    BoxLayout:
        Button:
            pos_hint:{"x":0.3,"y":0.22}
            size_hint: 0.4, 0.1
            font_size: (root.width**2 + root.height**2) / 14**4
            text: "Print from different class"
            on_press: root.retrieve_info()

How can I get the same result without using the container class, and without showing the two classes in the same screen ? for example I want the screen ScanQRCode(Screen) to show first and the when I click the button it will transit to the GetInfoFromAnotherClass(Screen) and when I click the button 'print from different class' it would still print the content of the previous input from the ScanQRCode class ?

Also if a function within a class return a list for example, how can I access that exact list from another class without using the kivy file ?

Thank you a lot !!!

Edit1: I added the following code based on the first answer, I wanted to share what I have tried. I still don't know how to make it work tho.

from kivy.app import App
from kivy.uix.screenmanager import Screen,ScreenManager
from kivy.properties import StringProperty,ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.lang.builder import Builder
kv = 
"""
<SM>:
    Page1:
        name: 'page1'
    AnotherClass:
        name: 'page2'
<Page1>:
    BoxLayout:
        orientation: 'vertical'
        CustomLayout:
            id: customlayoutid
        Button:
            text: 'Show Selected List'
            on_release: root.show_selected_list()
        Label:
            text: root.selected_list_text
        Button:
            text: 'Next page'
            on_release: app.root.current = "page2"
<CustomLayout>:
    orientation: 'vertical'
    Label:
        text: "Thats our custom widget class. "
        halign: 'center'
        valign: 'center'
    TextInput:
        id: custom_text
        hint_text: 'Show List Index [1-2]'
<AnotherClass>:
    BoxLayout:
        Button:
            text: 'Click to access previous input'
            on_release: root.access_previous_input()
        Label:
            text: root.previous_input_text
 """
class Page1(Screen):
    selected_list_text = StringProperty('Result will shown here')
    def show_selected_list(self,*args):
        self.selected_list_text = ''
        self.ids.customlayoutid.get_list() 
        for x in self.ids.customlayoutid.selected_list:
            self.selected_list_text += x+'\n'
class SM(ScreenManager):
    pass
class CustomLayout(BoxLayout):
    custom_list = [['1','2','3','4','5'],['10','11','12','13','14']]
    selected_list = ListProperty() 
    def get_list(self,*args):
        if self.ids.custom_text.text == '1': 
            self.selected_list = self.custom_list[0]
        elif self.ids.custom_text.text == '2':
            self.selected_list = self.custom_list[1]
        else:
            print('Invalid Select')
            self.selected_list = []

class AnotherClass(Screen):
    previous_input_text = StringProperty('previous_input')
    def access_previous_input(self,*args):
        App.get_running_app.get_screen('page1').get_list()
        self.previous_input_text = self.selected_list_text



class test(App):
    def build(self):
        Builder.load_string(kv)
        return SM()
if __name__ == '__main__':
    test().run()

Let me show you an example which access another classes and their function from another. So you can convert your own code. If you need more help please share minimal code.

from kivy.app import App
from kivy.uix.screenmanager import Screen,ScreenManager
from kivy.properties import StringProperty,ListProperty #We need to use properties for let kivy update our datas automaticly on screen.
from kivy.uix.boxlayout import BoxLayout
from kivy.lang.builder import Builder
kv = """
<SM>:
    Page1:
        name: 'page1'
<Page1>:
    BoxLayout:
        orientation: 'vertical'
        CustomLayout:
            id: customlayoutid
        Button:
            text: 'Show Selected List'
            on_release: root.show_selected_list()
        Label:
            text: root.selected_list_text
<CustomLayout>:
    orientation: 'vertical'
    Label:
        text: "Thats our custom widget class. Type to see how to access another class"
        halign: 'center'
        valign: 'center'
    TextInput:
        id: custom_text
        hint_text: 'Show List Index [1-2]'
"""
class Page1(Screen):
    selected_list_text = StringProperty('Result will shown here')
    def show_selected_list(self,*args):
        self.selected_list_text = ''
        self.ids.customlayoutid.get_list() #We're using ids to access widget.Also we can call function which owned by this widget.
        for x in self.ids.customlayoutid.selected_list:
            self.selected_list_text += x+'\n'
class SM(ScreenManager):
    pass
class CustomLayout(BoxLayout):
    custom_list = [['1','2','3','4','5'],['10','11','12','13','14']]
    selected_list = ListProperty() 
    def get_list(self,*args):
        if self.ids.custom_text.text == '1': #We use id for access widget under this class
            self.selected_list = self.custom_list[0]
        elif self.ids.custom_text.text == '2':
            self.selected_list = self.custom_list[1]
        else:
            print('Invalid Select')
            self.selected_list = []
class test(App):
    def build(self):
        Builder.load_string(kv)
        return SM()
if __name__ == '__main__':
    test().run()

If you use more screen and need to reach each other, you need that (example): App.get_running_app.get_screen('screenname').function() (You need to define screen names under ScreenManager for call by their name)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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