Search code examples
pythonkivykivy-languagetouch-eventkivymd

Can I get the word index of a MDTextField using on_touch_up function in KivyMD?


I have an MDTextField with a long string of text and I need to know the word the user clicks on.

Also inversely, I'll need to move the cursor or the selection to x word in the same text, with the ability to iterate through all the text on a word-by-word basis.

py file


# This functions are inside the main MDApp class

def OpenText():
    # some code that opens a file and reads text.
    pp = "large text"
    tf = MDTextField(
        active_line=False,
        line_anim=False,
        mode="fill",
        multiline=True,
        readonly= True,
        text=str(pp), # pp = long string of text
        on_touch_up=lambda *x: self.ClickText())
    self.root.ids.grid_pager.add_widget(tf)

def ClickText(self, *kwargs):
    # Here I need to know what number of word was clicked.
    # For example, if the text was: "Debating me breeding be answered an he. Spoil event was words her off cause any. Tears woman which no is world miles woody."
    # And I click on the word "event" I should receive "8"

kv file

MDScreen:
    MDNavigationLayout:
        x: TopBar.height
        size_hint_y: 1.0 - TopBar.height/root.height
        MDScreenManager:
            id: screen_manager
            MDScreen:
                name: "reader"
                MDGridLayout:
                    id: readerx
                    pos_hint: {"top": 1}
                    cols: 1
                    MDBoxLayout:
                        padding: "10dp"
                        adaptive_height: True
                        MDProgressBar:
                            id: p_bar
                            value: 20
                            pos_hint: {"top": 1}
                            size_hint: .8, None
                    MDLabel:
                        id: pager
                        text: "speed reader"
                        size_hint_y: None
                        pos_hint: {"top": 1}
                    ScrollView:
                        id: scroll_pager
                        padding: [dp(20), dp(20), dp(20), dp(50)]
                        MDGridLayout:
                            id: grid_pager
                            adaptive_height: True
                            size_hint_y: None
                            cols: 1
                            padding: [dp(20), dp(20), dp(20), dp(50)]
                            md_bg_color: .3, .35, .35, 1

I don't have much experience, and I'm doing a project for a course and for myself. I've spent a lot of time developing this app but I got stuck here and the only way to do it I know of would be to use another gui.

If that's the only way I would accept recommendations of which one to use. I choose kivy because I saw it as fairly easy to understand and it has the possibility to compile the app for windows, Linux, and android. But I didn't really know its capabilities and limitations.

I tried getting the values of all these functions but the only thing I've got is a coordinate that gives me the (character - line) and a bound method that I don't know what is it.

The coordinates point to the line and character where the cursor is clicked, but it changes according to the size of the window so it isn't a fixed value and I can't extract the word index from there.



print("T01", self.root.ids.grid_pager.children[0].get_cursor_from_index)
print("T02", self.root.ids.grid_pager.children[0].get_cursor_from_xy)
print("T03", self.root.ids.grid_pager.children[0].cursor_index)
print("T04", self.root.ids.grid_pager.children[0].cursor_offset)
print("T05", self.root.ids.grid_pager.children[0].cursor_pos)
print("T06", self.root.ids.grid_pager.children[0].cursor_row)
print("T07", self.root.ids.grid_pager.children[0].cursor_col)
print("T08", self.root.ids.grid_pager.children[0].cursor)
print("T09", self.root.ids.grid_pager.children[0]._get_line_from_cursor)
print("T10", self.root.ids.grid_pager.children[0]._get_cursor)
print("T11", self.root.ids.grid_pager.children[0]._get_cursor_col)
print("T12", self.root.ids.grid_pager.children[0]._get_cursor_pos)
print("T13", self.root.ids.grid_pager.children[0]._get_cursor_row)
print("T14", self.root.ids.grid_pager.children[0]._cursor)
print("T15", self.root.ids.grid_pager.children[0]._check_cursor)

Solution

  • @MST Thank you for replying! I even asked on the official discord and no one replied, but I kept digging and finally got it. I solved it with this:

    def ClickText(self, *kwargs):
       global old_index
        index = self.root.ids.grid_pager.children[0].cursor_index(self.root.ids.grid_pager.children[0].cursor)
        if index != old_index:
            old_index = index
            print("CHARACTERS: ", self.root.ids.grid_pager.children[0].cursor_index(self.root.ids.grid_pager.children[0].cursor))
            cut = texted_book[:index]
            words = len(cut.split())
            print("WORDS: ", words)
            print("COORDINATES: ", self.root.ids.grid_pager.children[0].get_cursor_from_index(index))
    

    The only methods that I found only give the coordinates, so I had to use another function to get the index of the character in that coordinate, and then get the number of words from there.

    Also, the click on the text triggers the function twice so I filtered the second one.

    And another problem that I see is that the text rearranges itself when you resize the window and so the coordinates change for the same length of characters, so every time the size changes it would be necessary to recalculate the coordinates according to the last value of the index acquired.