Trying to connect TextInput and DropDown list

763 views
Skip to first unread message

sergen

unread,
Mar 19, 2021, 5:54:28 AM3/19/21
to Kivy users support
I add a DropDown drop-down list to the TextInput widget. I add the opening of the list to "on_touch_down". When the cursor clicks on TextInput, the list appears, but only for a split second.

from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.base import runTouchApp
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label

class Test(App):
    def build(self):
        box = GridLayout(cols=3, rows=3)
        label = Label(text='LABEL1')
        label2 = Label(text='LABEL2')
        label3 = Label(text='LABEL3')
        button = TextInput(text='Selection', font_size=30, size_hint_y=0.15)
        button.bind(on_touch_down=self.list_open)
        button.bind(on_touch_up= self.test_collide_list)
        box.add_widget(label)
        box.add_widget(label2)
        box.add_widget(label3)
        box.add_widget(button)

        self.dropdown = DropDown()  # Create the dropdown once and keep a reference to it
#        self.dropdown.bind(on_select=lambda instance, x: setattr(button, 'text', x))
#        self.dropdown.text="drop"

        for index in range(10):  # create the buttons once
            btn = Button(text='Value %d' % index, size_hint_y=None, height=44,
                         on_release=lambda btn: print(btn.text))  # bind every btn to a print statement
            btn.text = 'Value %d' % index
            btn.bind(on_release=lambda btn: self.dropdown.select(btn.text))
            self.dropdown.add_widget(btn)
        return box

    def list_open(self, button, *args):
        print("--------",button, args)
        self.dropdown.open(button)  # you need this to open the dropdown

    def test_collide_list(self,*args):
        print("INST ")
        print("point ",*args[1].pos)
        for x in args:
            print("test", x)
        for w in self.dropdown.walk():
            print("Button" in str(w), *args[1].pos, w.collide_point(*args[1].pos), w.pos)
            if "Button" in str(w) and w.collide_point(*args[1].pos):
                print(w.text)

Test().run()


If I add the opening of the list to "on_touch_up". Then an error occurs:

Traceback (most recent call last):
   File "/home/TERRA/PythonExp/kivy_exp/dropdown_test3.py", line 53, in <module>
     Test().run()
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/app.py", line 950, in run
     runTouchApp()
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/base.py", line 573, in runTouchApp
     EventLoop.mainloop()
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/base.py", line 347, in mainloop
     self.idle()
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/base.py", line 391, in idle
     self.dispatch_input()
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/base.py", line 342, in dispatch_input
     post_dispatch_input(*pop(0))
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/base.py", line 308, in post_dispatch_input
     wid.dispatch('on_touch_up', me)
   File "kivy/_event.pyx", line 705, in kivy._event.EventDispatcher.dispatch
   File "kivy/_event.pyx", line 1248, in kivy._event.EventObservers.dispatch
   File "kivy/_event.pyx", line 1172, in kivy._event.EventObservers._dispatch
   File "/home/TERRA/PythonExp/kivy_exp/dropdown_test3.py", line 40, in lista
     self.dropdown.open(button)  # you need this to open the dropdown
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/uix/dropdown.py", line 254, in open
     self._win.add_widget(self)
   File "/home/sergen/.local/lib/python3.8/site-packages/kivy/core/window/__init__.py", line 1305, in add_widget
     raise WidgetException(
 kivy.uix.widget.WidgetException: Cannot add <kivy.uix.dropdown.DropDown object at 0x7f52a1104890> to window, it already has a parent <kivy.core.window.window_sdl2.WindowSDL object at 0x7f52a4cdba50>

I don’t understand why the list automatically disappears and is it possible to fix this effect?
I tried to open the list using the "on_focus" command, but this option does not work.

sergen

unread,
Mar 19, 2021, 5:59:39 AM3/19/21
to Kivy users support
I am using  [Kivy        ] v2.0.0rc3, git-20c14b2, 20200615   on LinuxMint20 and python 3.8.5


пятница, 19 марта 2021 г. в 12:54:28 UTC+3, sergen:

Mr. Mog

unread,
Mar 19, 2021, 9:06:13 AM3/19/21
to kivy-...@googlegroups.com
What task do you want the drop-down list to serve?

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/54093d4a-23ff-445c-a744-d89196105d77n%40googlegroups.com.

sergen

unread,
Mar 19, 2021, 1:35:26 PM3/19/21
to Kivy users support
I need a TextInput to enter text. But sometimes I need to enter fixed text. To add fixed values to the TextInput, I want to add a drop-down list (about 6 positions) from which I can select the desired value.

пятница, 19 марта 2021 г. в 16:06:13 UTC+3, jacobm...@gmail.com:

Elliot Garbus

unread,
Mar 20, 2021, 1:02:45 PM3/20/21
to kivy-...@googlegroups.com

I created a separate class, TI to be your Input, and use the on_touch_down directly. 

Touches get sent to all widgets.  You want to use on_collide_point to test the touch.

 

It would perhaps be more appropriate to create a class that contains both the dropdown and the TextInput.

 

 

from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label


class TI(TextInput):
   
def on_touch_down(self, touch):
       
if self.collide_point(*touch.pos):
           
print('widget touched')
            app = App.get_running_app()
            app.dropdown.open(
self)


class Test(App):

   
def build(self):
        box = GridLayout(
cols=3, rows=3)
        label = Label(
text='LABEL1')
        label2 = Label(
text='LABEL2')
        label3 = Label(
text='LABEL3'
)
        ti = TI(
text='Selection', font_size=30, size_hint_y=0.15)
       
# self.ti.bind(on_touch_down=self.list_open)
        # self.ti.bind(on_touch_up= self.test_collide_list)
       
box.add_widget(label)
        box.add_widget(label2)
        box.add_widget(label3)
        box.add_widget(ti)

       
self.dropdown = DropDown()  # Create the dropdown once and keep a reference to it
       
self.dropdown.bind(on_select=lambda instance, x: setattr(ti, 'text', x))
       
# self.dropdown.text="drop"

       
for index in range(10):  # create the buttons once
           
btn = Button(text='Value %d' % index, size_hint_y=None, height=44,
                        
on_release=lambda btn: print(btn.text))  # bind every btn to a print statement
           
btn.text = 'Value %d' % index
            btn.bind(
on_release=lambda btn: self.dropdown.select(btn.text))
           
self.dropdown.add_widget(btn)
       
return box

   
def list_open(self, button, *args):
       
print("--------",button, args)


       
self.dropdown.open(button)  # you need this to open the dropdown


   
def test_collide_list(self,*args):
       
print("INST ")
       
print("point ",*args[1].pos)
       
for x in args:
           
print("test", x)
       
for w in self.dropdown.walk():
           
print("Button" in str(w), *args[1].pos, w.collide_point(*args[1].pos), w.pos)
           
if "Button" in str(w) and w.collide_point(*args[1].pos):
               
print(w.text)

Test().run()

--

You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.

sergen

unread,
Mar 20, 2021, 3:03:41 PM3/20/21
to Kivy users support
I checked your script in work. The behavior of the drop-down list has not changed, it appears only when the mouse button is pressed and disappears when it is released. This is why I had to add the "test_collide_list" function. It works as follows, I click on the mouse button on the text field, the list opens, then I move the cursor to the desired item in the list and release the mouse button, when the button is released, the "test_collide_list" function is triggered and check which menu item the cursor was on. But this is not convenient and additional problems appear in the interface in the android.
I would like the behavior to be the same as adding the dropdown to the "Button" widget, i.e. after releasing the mouse button, the list remained open until I select the item I need. But this is not possible because an error appears when adding a dropdown menu to "on_press_up".

суббота, 20 марта 2021 г. в 20:02:45 UTC+3, ElliotG:

Elliot Garbus

unread,
Mar 20, 2021, 3:57:39 PM3/20/21
to kivy-...@googlegroups.com

I’m using kivy 2.0, the behavior you describe is not what I see.

When I click in the text box the dropdown opens.  It remains open until an item is selected.

Elliot Garbus

unread,
Mar 20, 2021, 4:05:28 PM3/20/21
to kivy-...@googlegroups.com

I noticed I could not type in the box and made the fix below:

 

from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label


class TI(TextInput):
   
def on_touch_down(self, touch):
       
if self.collide_point(*touch.pos):
           
print('widget touched')
            app = App.get_running_app()
            app.dropdown.open(
self
)
       
return super().on_touch_down(touch)

sergen

unread,
Mar 22, 2021, 8:30:17 AM3/22/21
to Kivy users support
I found out that when I click on the "TextInput" widget with the right mouse button (a red dot appears at the point of clicking), the menu appears and waits for further action. That is, what I need is happening.
But why are the right and left button presses different? Is it possible to pass the behavior of the right button to the left one? On android, touching the screen corresponds to which button?

суббота, 20 марта 2021 г. в 23:05:28 UTC+3, ElliotG:

sergen

unread,
Mar 22, 2021, 8:41:55 AM3/22/21
to Kivy users support
Seems to have found the cause of the wrong left-click behavior.


The link says that:

On linux systems, the mouse provider can be annoying when used with another multitouch provider (hidinput or mtdev). The Mouse can conflict with them: a single touch can generate one event from the mouse provider and another from the multitouch provider.

To avoid this behavior, you can activate the “disable_on_activity” token in the mouse configuration. Then, if any touches are created by another provider, the mouse event will be discarded. Add this to your configuration:

[input] mouse = mouse,disable_on_activity

But I can't figure out how to set the specified option.

понедельник, 22 марта 2021 г. в 15:30:17 UTC+3, sergen:

Elliot Garbus

unread,
Mar 22, 2021, 11:38:17 AM3/22/21
to kivy-...@googlegroups.com

I create a file I call configstartup.py and included it as the first import in the main.py file. It is imported before kivy.app

The resolution of the Icon for Windows and MacOS is different.  The line with exit on escape, turns off the exit on escape capability, and the disable_mulitouch will stop the red dot on a right click.


#configstartup.py

from kivy.config import Config
from kivy.utils import platform


if platform == 'macosx':
    Config.set(
'kivy', 'window_icon','Images/ME-APP-Design-Icon_512.png')
else:
    Config.set(
'kivy', 'window_icon','Images/ME-APP-Design-Icon_64.png'# Windows uses a small png
Config.set('kivy', 'exit_on_escape', 0)
Config.set(
'input', 'mouse', 'mouse,disable_multitouch')

sergen

unread,
Mar 22, 2021, 2:08:27 PM3/22/21
to Kivy users support
My guess turned out to be false. The set parameter "mouse = mouse, disable_on_activity" did not give any result, when the left mouse button is pressed and released, the drop-down menu disappears. There are no more thoughts.
The right mouse button is responsible for multi-touch. On android, too, a drop-down menu opens with a long touch, and a menu item is selected by tapping with a second finger, this is not convenient.

понедельник, 22 марта 2021 г. в 18:38:17 UTC+3, ElliotG:

Elliot Garbus

unread,
Mar 22, 2021, 3:00:47 PM3/22/21
to kivy-...@googlegroups.com
There are attributes to touch that tell you if the touch was a mouse, and if it was the left or right button. 

Sent from my iPhone

On Mar 22, 2021, at 11:09 AM, sergen <2511...@gmail.com> wrote:



sergen

unread,
Mar 23, 2021, 3:38:01 PM3/23/21
to Kivy users support
I figured out the touch attributes.
I turned off the multitouch function for the right button so that it would not be confusing. Now both the right and left buttons work the same. 
And now, when any button is pressed, the drop-down menu appears but is not fixed in the open position, but disappears after the button is released. 
Can someone explain to me why this is happening with the dropdown menu, why it doesn't stay on the screen?

понедельник, 22 марта 2021 г. в 22:00:47 UTC+3, ElliotG:

Elliot Garbus

unread,
Mar 23, 2021, 4:16:26 PM3/23/21
to kivy-...@googlegroups.com

sergen

unread,
Mar 24, 2021, 12:31:23 PM3/24/21
to Kivy users support
The code from the primary question has practically not changed.
Added a line to the file "/home/sergen/.kivy/config.ini" for the same operation of the mouse buttons:
[input]
mouse = mouse, disable_on_activity, multitouch_on_demand

The program code is as follows:
And the code from the primary question has practically not changed.
Added a line to the file "/home/sergen/.kivy/config.ini" for the same operation of the mouse buttons:
[input]
mouse = mouse, disable_on_activity, multitouch_on_demand

The program code is as follows:

#configstartup.py

from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label



class TI(TextInput):
    
    def on_touch_down(self, touch):
        print("<touch> ",touch.button)
        if touch.button == "left":
            app = App.get_running_app()
            app.dropdown.open(self)

вторник, 23 марта 2021 г. в 23:16:26 UTC+3, ElliotG:

Andreas Ecker

unread,
Mar 24, 2021, 1:25:56 PM3/24/21
to kivy-...@googlegroups.com
Looks like you're missing to consume the touch event.

Have you tried to return `True` in the `if touch.button == "left"` branch of your `on_touch_down` method?

```
  def on_touch_down(self, touch):
        print("<touch> ",touch.button)
        if touch.button == "left":
            app = App.get_running_app()
            app.dropdown.open(self)
            return True
```

sergen

unread,
Mar 24, 2021, 2:44:10 PM3/24/21
to Kivy users support
Added the line you suggested, but unfortunately the behavior of the program has not changed.

среда, 24 марта 2021 г. в 20:25:56 UTC+3, aec...@gmail.com:

Elliot Garbus

unread,
Mar 24, 2021, 3:46:59 PM3/24/21
to kivy-...@googlegroups.com

Try this:

 

from kivy.config import Config
Config.set(
'kivy', 'exit_on_escape', 0)
Config.set(
'input', 'mouse', 'mouse,disable_multitouch')


from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label


class TI(TextInput):
   
def on_touch_down(self
, touch):
       
if self.collide_point(*touch.pos) and touch.button == 'left':

           
print('widget touched')
            app = App.get_running_app()
            app.dropdown.open(
self
)
       
return super().on_touch_down(touch)
Reply all
Reply to author
Forward
0 new messages