मैं RecycleView का उपयोग करके अजगर kivy में एक स्क्रॉल करने योग्य तालिका बना रहा हूँ। तालिका में लगभग 1100 पंक्तियाँ और 10 स्तंभ होने चाहिए... RecycleView आलसी-लोडिंग कर रहा है... वास्तव में बहुत धीमा।

कोई जानता है कि प्रक्रिया को कैसे तेज किया जाए? शायद RecycleView उपयुक्त नहीं है?

धन्यवाद!

      BoxLayout:
            RecycleView:
                viewclass: 'background_example'
                data: [{'text': str(x)} for x in range(10000]
                RecycleGridLayout:
                    cols: 10
                    size_hint: 1, None
                    default_size: None, dp(20)
                    default_size_hint: 1, None
                    height: self.minimum_height
                    width: self.minimum_width
0
Gatt88 18 अप्रैल 2020, 14:03
कृपया एक न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य उदाहरण पोस्ट करें जो समस्या को प्रदर्शित करता है।
 – 
John Anderson
18 अप्रैल 2020, 16:28
हैलो जॉन, अभी पोस्ट किया गया
 – 
Gatt88
18 अप्रैल 2020, 18:23

3 जवाब

सबसे बढ़िया उत्तर

मुझे आपके कोड में दो समस्याएं दिखाई देती हैं:

  1. आप 10000 वस्तुओं की वह बड़ी सूची दो बार बना रहे हैं। एक बार on_pre_enter() विधि में Screen_2 और फिर kv कोड में Screen_2
  2. आप मुख्य धागे पर वह बड़ी सूची बना रहे हैं, जो आपके जीयूआई को जमा देता है।

पहली समस्या को संभालने के लिए, आप kv को Screen_2 के लिए बदल सकते हैं:

<Screen_2>:
    BoxLayout:
        RecycleView:
            viewclass: 'Sfondo_tabella'
            # data: [{'text': str(x)} for x in root.data_items]
            data: root.data_items  # just reference the list instead of recreating it
            RecycleGridLayout:
                cols: 10
                size_hint: 1, None
                default_size: None, dp(20)
                default_size_hint: 1, None
                height: self.minimum_height
                width: self.minimum_width

दूसरी समस्या का समाधान करने के लिए, Screen_2 में डेटा निर्माण करने के लिए Thread का उपयोग करें:

class Screen_2(Screen):
    data_items = ListProperty([])

    def on_pre_enter(self, *args):
        # start the thread
        Thread(target=self.build_data).start()

    def build_data(self):
        x = 0
        # break the data build into 20 pieces
        for i in range(20):
            tmp_data = []
            for j in range(500):
                # create data entry for the current x and save it in tmp_data
                tmp_data.append({'text': str(x)})
                x += 1
            # add this block of data to the data_items on the main thread
            Clock.schedule_once(partial(self.load_data, tmp_data))

    def load_data(self, tmp_data, dt):
        self.data_items.extend(tmp_data)
1
John Anderson 18 अप्रैल 2020, 20:23
धन्यवाद जॉन! मुझे आपके समाधान को वास्तविक स्थिति में लागू करने के लिए कुछ मदद चाहिए.. कृपया, नीचे पढ़ें
 – 
Gatt88
21 अप्रैल 2020, 18:15

यहाँ एक न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य उदाहरण है:

जब तक हमारे पास सिर्फ 1.000 सेल न हों, टेबल 2 या 3 सेकंड में बन जाती है।

यदि 1.000 के बजाय मैं लूप के लिए 10.000 लिखता हूं, तो मेरे पीसी को 10.000 कोशिकाओं द्वारा बनाई गई तालिका बनाने के लिए लगभग 50 सेकंड की आवश्यकता होती है .. यह स्वीकार्य नहीं है।

अस्थायी:

from kivy.uix.screenmanager import Screen
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.properties import BooleanProperty
from kivy.properties import ListProperty

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

class Screen_1(Screen):
    pass

class Screen_2(Screen):
    data_items = ListProperty([])
    def on_pre_enter(self, *args):
        for x in range(1000):
            self.data_items.append(x)

class TempApp(App):
    pass

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

अस्थायी केवी:

ScreenManager:
    id: screen_manager
    name: "screen_manager"

    Screen_1:
        id: screen_1
        name: "Screen_1"
        manager: screen_manager

    Screen_2:
        id: screen_2
        name: "Screen_2"
        manager: screen_manager

<Sfondo_tabella>:
    # Draw a background to indicate selection
    color: 0,0,0,1
    font_size:  self.height * 0.5
    text_size: self.width, None
    valign: 'top'
    halign: 'center'

    canvas.before:
        Color:
            rgba: (1, 1, 1, 1)
        Rectangle:
            pos: self.pos
            size: self.size
    canvas:
        Color:
            rgba:0,0,0,1
        Line:
            width:0.5
            rectangle:(self.x,self.y,self.width,self.height)


<Screen_1>:
    Button:
        text: "Create table"
        on_press:
            root.manager.transition.direction = 'up'
            root.manager.current = 'Screen_2'

<Screen_2>:

    BoxLayout:
        RecycleView:
            viewclass: 'Sfondo_tabella'
            data: [{'text': str(x)} for x in root.data_items]
            RecycleGridLayout:
                cols: 10
                size_hint: 1, None
                default_size: None, dp(20)
                default_size_hint: 1, None
                height: self.minimum_height
                width: self.minimum_width

0
Gatt88 18 अप्रैल 2020, 18:19

मैंने आपके समाधान का परीक्षण किया है और बहुत अच्छा काम करता है। धन्यवाद..

बस एक और सवाल:

एक वास्तविक मामले में अपने समाधान को लागू करने के लिए, अगर हमें पोस्टग्रेज का उपयोग करके तालिका से डेटा आयात करना है, यह जाने बिना कि मुझे कितने आइटम बनाने हैं, कोड को कैसे अनुकूलित करें? (मान लें कि तालिका में 1000 पंक्तियाँ 10 कॉलम हैं)

मैंने केवल 'build_data' फ़ंक्शन को संपादित किया है, कोड का 10 गुना तेज निष्पादन (50 सेकंड से 5 सेकंड तक) प्राप्त कर रहा है, लेकिन यह अभी भी बहुत धीमा है फिर आपके द्वारा पोस्ट किया गया कोड (1,5 सेकंड), मुझे लगता है क्योंकि मैं ' मैं डेटा को 1000 टुकड़ों (पंक्तियों) में तोड़ रहा हूं, 20 नहीं ...

    def build_data(self):
        self.data_items = ''

        stato_maschere = psycopg2.connect(dsn)
        cur = stato_maschere.cursor()

        cur.execute("SELECT col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8, col_9, col_10 "
                    "FROM table_1 "
                    "WHEREcol_1 != '' ")

        rows = cur.fetchall()

        for row in rows:
            tmp_data = []
            for x in row:
                tmp_data.append({'text': str(x)})
            Clock.schedule_once(partial(self.load_data, tmp_data))
0
Gatt88 21 अप्रैल 2020, 18:12
मैं आपको कोई सटीक अनुशंसा नहीं दे सकता, लेकिन मैं कुछ प्रयोग करने का सुझाव दूंगा। सबसे पहले, कुछ print स्टेटमेंट डालें जो आपके कोड को db से कनेक्ट करने और क्वेरी परिणाम प्राप्त करने में लगने वाले समय को प्रिंट करते हैं, मूल रूप से build_data की शुरुआत से लेकर for कुंडली। इससे आपको न्यूनतम समय मिलेगा जिसके लिए आप शूटिंग कर सकते हैं।
 – 
John Anderson
21 अप्रैल 2020, 19:00
फिर, प्रयोग करें कि आप कितनी बार load_data को कॉल कर रहे हैं। अभी आप इसे हर पंक्ति के लिए कह रहे हैं, वह एक अति है। संपूर्ण डेटा सेट के लिए केवल एक बार कॉल करना दूसरी चरम सीमा है। सबसे अच्छा प्रदर्शन कहीं बीच में होने की संभावना है। आप केवल कुछ परीक्षण करके ही इसका पता लगा सकते हैं।
 – 
John Anderson
21 अप्रैल 2020, 19:01