how to pass more then one parameter in pop up box

2019-06-11 07:12发布

问题:

user.py

import kivy

kivy.require('1.9.0')  # replace with your current kivy version !
import sqlite3 as lite
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty,NumericProperty
from kivy.lang import Builder

from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window



Window.size = (500, 500)

#con = lite.connect('fact.db')
#con.text_factory = str
#cur = con.cursor()

class TextInputPopup(Popup):
    obj = ObjectProperty(None)
    obj_text = StringProperty("")

    #print(obj);
    def __init__(self, obj, **kwargs):
        super(TextInputPopup, self).__init__(**kwargs)
        self.obj = obj
        self.obj_text = obj.text

class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
                                  RecycleGridLayout):
    ''' Adds selection and focus behaviour to the view. '''


class SelectableButton(RecycleDataViewBehavior, Button):
    ''' Add selection support to the Button '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableButton, self).refresh_view_attrs(rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableButton, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected


    def on_press(self,*args):
        popup = TextInputPopup(self)
        popup.open()

    def update_changes(self):
        self.text = txt


class RV(BoxLayout):
    data_items = ListProperty([])

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

    def get_users(self):
        #cur.execute("SELECT * FROM `users` order by id asc")
        #rows = cur.fetchall()
        '''This result retrieve from database'''
        rows = [(1, 'Yash', 'Chopra'),(2, 'amit', 'Kumar')]

        for row in rows:
            for col in row:
                self.data_items.append(col)


class ListUser(App):
    title = "Users"

    def build(self):
        self.root = Builder.load_file('user.kv')
        return RV()



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

user.kv

    #:kivy 1.10.0

<TextInputPopup>:
    title: "Update State"
    size_hint: None, None
    size: 350, 350
    auto_dismiss: False

    BoxLayout:
        orientation: "vertical"
        TextInput:
            id: txtinput
            text: root.obj_text
        Button:
            size_hint: 1, 0.4
            text: "Save Changes"
            on_release:
                root.obj.update_changes(txtinput.text)
                root.dismiss()
        Button:
            size_hint: 1, 0.4
            text: "Cancel Changes"
            on_release: root.dismiss()


<SelectableButton>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
        Rectangle:
            pos: self.pos
            size: self.size

<RV>:
    BoxLayout:
        orientation: "vertical"

        GridLayout:
            size_hint: 1, None
            size_hint_y: None
            height: 25
            cols: 3

            Label:
                text: "ID"
            Label:
                text: "First Name"
            Label:
                text: "Last Name"

        BoxLayout:
            RecycleView:
                viewclass: 'SelectableButton'
                data: [{'text': str(x)} for x in root.data_items]
                SelectableRecycleGridLayout:
                    cols: 3
                    default_size: None, dp(26)
                    default_size_hint: 1, None
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'
                    multiselect: True
                    touch_multiselect: True

Now my first window showing Like this -First Screen

Now my second window showing Like this - Second Screen

But i want to my second window screen like this -Second Screen

I am new to kivy/python.
I am retrieving data from database and showing in list.Now i am clicking on any column then it shows only self column value like this 2: https://i.stack.imgur.com/Ieiut.jpg.I couldn't pass three variable.

I want to pass row value like third screenshot 3: https://i.stack.imgur.com/UIyV5.jpg.But i don't know how to do?Please anyone can suggest me how do i do this.

回答1:

Please refer to the explanations, and example for details.

Click A Row - Show All Columns

The view in RecycleView is generatad by processing the data which is essentially a list of dicts. Firstly, we will hook up to the RecycleView's data.

def apply_selection(self, rv, index, is_selected):
    ''' Respond to the selection of items in the view. '''
    self.selected = is_selected
    self.rv_data = rv.data

Secondly, we will determine the start point of the row when any button in the row is pressed, as follow. We will pass self to the Edit class.

def on_press(self):
    self.start_point = 0
    end_point = MAX_TABLE_COLS
    rows = len(self.rv_data) // MAX_TABLE_COLS
    for row in range(rows):
        # check index is in column range
        if self.index in list(range(end_point)):
            break
        self.start_point += MAX_TABLE_COLS
        end_point += MAX_TABLE_COLS

    popup = Edit(self)
    popup.open()

Thirdly, in the Edit class (popup widget), we defined the popup's content as a container (BoxLayout). Inside the BoxLayout, there is a GridLayout (containing Labels and TextInput), and two Buttons (Save, and Cancel). We extract the start point and the column data as follow:

class Edit(Popup):
    start_point = NumericProperty(0)
    col_data = ListProperty(["?", "?", "?"])

    def __init__(self, obj, **kwargs):
        super(Edit, self).__init__(**kwargs)
        self.start_point = obj.start_point
        self.col_data[0] = obj.rv_data[obj.start_point]["text"]
        self.col_data[1] = obj.rv_data[obj.start_point + 1]["text"]
        self.col_data[2] = obj.rv_data[obj.start_point + 2]["text"]

Example

main.py

import kivy

kivy.require('1.10.0')  # replace with your current kivy version !
import sqlite3 as lite
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.lang import Builder

from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window


Window.size = (500, 500)

MAX_TABLE_COLS = 3

con = lite.connect('company.db')
# con.text_factory = str
cur = con.cursor()


class Edit(Popup):
    start_point = NumericProperty(0)
    col_data = ListProperty(["?", "?", "?"])

    def __init__(self, obj, **kwargs):
        super(Edit, self).__init__(**kwargs)
        self.start_point = obj.start_point
        self.col_data[0] = obj.rv_data[obj.start_point]["text"]
        self.col_data[1] = obj.rv_data[obj.start_point + 1]["text"]
        self.col_data[2] = obj.rv_data[obj.start_point + 2]["text"]

    def package_changes(self, fname, lname):
        self.col_data[1] = fname
        self.col_data[2] = lname


class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
                                  RecycleGridLayout):
    ''' Adds selection and focus behaviour to the view. '''


class SelectableButton(RecycleDataViewBehavior, Button):
    ''' Add selection support to the Button '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)
    rv_data = ObjectProperty(None)
    start_point = NumericProperty(0)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableButton, self).refresh_view_attrs(rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableButton, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        self.rv_data = rv.data

    def on_press(self):
        self.start_point = 0
        end_point = MAX_TABLE_COLS
        rows = len(self.rv_data) // MAX_TABLE_COLS
        for row in range(rows):
            # check index is in column range
            if self.index in list(range(end_point)):
                break
            self.start_point += MAX_TABLE_COLS
            end_point += MAX_TABLE_COLS

        popup = Edit(self)
        popup.open()


class RV(BoxLayout):
    data_items = ListProperty([])

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

    def get_users(self):
        '''This result retrieve from database'''

        cur.execute("SELECT * FROM Users ORDER BY UserID ASC")
        rows = cur.fetchall()

        # create data_items
        for row in rows:
            for col in row:
                self.data_items.append(col)

    def update_changes(self, obj):
        # update data_items
        # obj.start_point + 1 --- skip UserID
        for index in range(obj.start_point + 1, obj.start_point + MAX_TABLE_COLS):
            self.data_items[index] = obj.col_data[index - obj.start_point]

        # update Database Table
        cur.execute("UPDATE Users SET FirstName=?, LastName=? WHERE UserID=?", (obj.col_data[1], obj.col_data[2], obj.col_data[0]))
        con.commit()


class ListUser(App):
    title = "Users"

    def build(self):
        self.root = Builder.load_file('test.kv')
        return RV()


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

test.kv

#:kivy 1.10.0

<Edit>:
    title: "Update State"
    size_hint: None, None
    size: 350, 350
    auto_dismiss: False

    BoxLayout:
        orientation: "vertical"
        GridLayout:
            cols: 2
            Label:
                text: "UserID"
            Label:
                id: userid
                text: root.col_data[0]
            Label:
                text: "First Name"
            TextInput:
                id: fname
                text: root.col_data[1]
            Label:
                text: "Last Name"
            TextInput:
                id: lname
                text: root.col_data[2]
        Button:
            size_hint: 1, 0.4
            text: "Save Changes"
            on_release:
                root.package_changes(fname.text, lname.text)
                app.root.update_changes(root)    # pass obj
                root.dismiss()
        Button:
            size_hint: 1, 0.4
            text: "Cancel Changes"
            on_release: root.dismiss()


<SelectableButton>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
        Rectangle:
            pos: self.pos
            size: self.size

<RV>:
    BoxLayout:
        orientation: "vertical"

        GridLayout:
            size_hint: 1, None
            size_hint_y: None
            height: 25
            cols: 3

            Label:
                text: "ID"
            Label:
                text: "First Name"
            Label:
                text: "Last Name"

        BoxLayout:
            RecycleView:
                viewclass: 'SelectableButton'
                data: [{'text': str(x)} for x in root.data_items]
                SelectableRecycleGridLayout:
                    cols: 3
                    default_size: None, dp(26)
                    default_size_hint: 1, None
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'
                    multiselect: True
                    touch_multiselect: True

Output



回答2:

Here is a Popup which takes a list as parameter in its open method. You only need to pass that parameter in your code.

py:

class MyPopup(Popup):
    text1 = StringProperty()
    text2 = StringProperty()
    text3 = StringProperty()

    def open(self, text, **kwargs):
        self.text1 = text[0]
        self.text2 = text[1]
        self.text3 = text[2]
        super(MyPopup, self).open(**kwargs)

kv:

#:import F kivy.factory.Factory

<MyPopup>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text: 'Close me!'
            on_release: root.dismiss()
        TextInput:
            text: root.text1
        TextInput:
            text: root.text2
        TextInput:
            text: root.text3

This is the whole code for a minimum working example. Do not forget the factory part.

from kivy.app import App
from kivy.uix.popup import Popup
from kivy.lang import Builder
from kivy.properties import StringProperty


class MyPopup(Popup):
    text1 = StringProperty()
    text2 = StringProperty()
    text3 = StringProperty()

    def open(self, text, **kwargs):
        self.text1 = text[0]
        self.text2 = text[1]
        self.text3 = text[2]
        super(MyPopup, self).open(**kwargs)

class Testapp(App):

    def build(self):
        return Builder.load_string('''
#:import F kivy.factory.Factory

<MyPopup>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text: 'Close me!'
            on_release: root.dismiss()
        TextInput:
            text: root.text1
        TextInput:
            text: root.text2
        TextInput:
            text: root.text3

Button:
    on_press: F.MyPopup().open(['Palim1', 'Palim2', 'Palim3'])

    ''')

Testapp().run()