I don't know how to change active (selected) segment of MDSegmentedControl
in KivyMD without touching it (e.g. after loading data from db and opening a screen). I can set current_active_segment
property to one of the MDSegmentedControlItem
s but it has no impact on UI. Example code below:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.metrics import dp
from kivy.input.providers.mouse import MouseMotionEvent
from kivy.clock import Clock
kvFloatLayout = """
MDScreen:
id: mdscr
MDBoxLayout:
orientation: "vertical"
adaptive_height: True
pos_hint: {"top": 1}
spacing: "12dp"
MDTopAppBar:
id: top_app_bar
pos_hint: {"top": 1}
title: "Test App"
elevation: 4
MDBoxLayout:
orientation: "vertical"
adaptive_height: True
pos_hint: {"top": 1}
padding: "12dp", "0dp", "12dp", "12dp"
spacing: "12dp"
MDRaisedButton:
id: btn_resize
text: "Resize"
on_release: app.seg_resize()
MDRaisedButton
id: btn_change
text: "Change selection"
on_release: app.seg_change_selection()
MDSegmentedControl:
id: seg_options
MDSegmentedControlItem:
id: sci_option1
text: "Option left"
MDSegmentedControlItem:
id: sci_option2
text: "Option right"
"""
class TestApp(MDApp):
def build(self):
return Builder.load_string(kvFloatLayout)
def seg_resize(self):
#Workaround from stackoverflow (size not working in .kv - https://stackoverflow.com/questions/74999000/kivymd-mdsegmentedcontrol-size)
self.root.ids.seg_options.ids.segment_panel.width = (Window.width - dp(24))
def seg_change_selection(self):
sc = self.root.ids.seg_options
print("---sc:")
print(sc)
sci = self.root.ids.sci_option2
print("---sci:")
print(sci)
print("---sc.current_active_segment before:")
print(sc.current_active_segment)
sc.current_active_segment = sci
print("---sc.current_actilve_segment after:")
print(sc.current_active_segment.text)
#A poor workaround with mouse click:
#Clock.schedule_once(self.simulate_mouse_click, 1)
def simulate_mouse_click(self, *args):
x = 0.75*Window.width
y = Window.height - \
self.root.ids.top_app_bar.height - \
self.root.ids.btn_resize.height - \
self.root.ids.btn_change.height - \
dp(12) * 3 - 40
touch = MouseMotionEvent(None, 0, (x,y)) # args are device, id, spos
touch.button = 'left'
touch.pos = (x,y)
touch.x = touch.px = touch.ox = x
touch.y = touch.py = touch.oy = y
print("---touch")
print(str(touch))
Window.dispatch('on_touch_down', touch)
#1/0
TestApp().run()
Any ideas or workarounds?
The only way I was able to make it work was scheduling a mouse click over the right segment item but of course this is far from being a good and reliable solution. It is this part of code:
#Clock.schedule_once(self.simulate_mouse_click, 1)
Unfortunately, it does not appear that the designers of the MDSegmentedControl
did not allow for the utility that you want. Another way to trick the MDSegmentedControl
into thinking that it has been clicked on is to create a FakeTouch
class:
class FakeTouch(object):
pass
And then, use that class in your seg_change_selection()
method:
def seg_change_selection(self):
sc = self.root.ids.seg_options
print("---sc:")
print(sc)
sci = self.root.ids.sci_option2
print("---sci:")
print(sci)
print("---sc.current_active_segment before:")
print(sc.current_active_segment)
# sc.current_active_segment = sci
touch = FakeTouch()
touch.x = sci.center_x
touch.y = sci.center_y
sc.on_press_segment(sci, touch)
print("---sc.current_actilve_segment after:")
print(sc.current_active_segment.text)
# A poor workaround with mouse click:
# Clock.schedule_once(self.simulate_mouse_click, 1)
Similar to your simulated mouse click, but perhaps a but simpler.