ARTICLE AD BOX
I don't know if I resolve all problems but I describe what I found.
It seems MDButton works different than other widgets.
Here is original MDButton.__init__
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) Clock.schedule_once(self.adjust_width, 0.2) Clock.schedule_once(self.adjust_pos, 0.2)It uses Clock to run self.adjust_width after 0.2 seconds to create button with minimal width - so it doesn't allow to use self.width at once in own __init__ because it will be replaced by width calculated in self.adjust_width
(by the way: as I remember __init__ can't calculate it directly because Kivy creates real objects later, sets values from files .kv, and after that code can change sizes - and this is why it has to use Clock to run code later)
I see two methods for this:
use also Clock to run own function which will change width little later from kivy.clock import Clock class mkbtn(MDButton): def __init__(...): # ... code ... Clock.schedule_once(self.update_later, 0.2) def update_later(self, args): self.width = dp(120) replace adjust_width with own function - empty code - and it will not calculate own width class mkbtn(MDButton): def __init__(...): # ... code ... self.width = dp(120) def adjust_width(self, args): passResult on desktop Linux
I also centered text on button (but text+icon may need different method)
#from kivy.clock import Clock # if you put this before class mkbtn then you can use `func=dummy_func` def dummy_func(x="", y=""): pass class mkbtn(MDButton): def __init__( self, text, style="elevated", # radius=[20, 20, 20, 20], icon=None, # func=lambda x: dummy_func(x), func=dummy_func, **kwargs ): super().__init__(**kwargs) self.style = style self.radius = radius self.size_hint_x = None # self.adaptive_width=True # self.size_hint_min_x = 0.3 # self.wide = dp(120) self.width = dp(120) if icon: self.add_widget(MDButtonIcon(icon)) self.add_widget(MDButtonText(text=text)) self.bind(on_release=func) # center text on button - has to be after `add_widget(MDButtonText(..>))` self._button_text.pos_hint = {"center_x": 0.5, "center_y": 0.5} # center button # self.pos_hint = {"center_x": 0.5, "center_y": 0.5} # center Y # Clock.schedule_once(self.update_later, 0.2) # def update_later(self, args): # self.width = dp(120) def adjust_width(self, args): passIf in Button and TextField you use pos_hint = {"cente_y": 0.5} then both widgets will looks like in one line.
#from kivy.clock import Clock class TxtField(MDTextField): def __init__(self, ilen=7, htxt="", shintx=0.7, **kwargs): super().__init__(**kwargs) self.mode = "outlined" # "filled" self.size_hint_x = 0.5 # center textfield in layout (Box) self.pos_hint = {"center_x": 0.5, "center_y": 0.5} # center Y self.input_filter = lambda s, u: ( s if (len(self.text) < ilen and s.isdigit()) else "" ) if not htxt: htxt = "input:" self.add_widget(MDTextFieldHintText(text=htxt)) # if you put this before class mkbtn then you can use `func=dummy_func` def dummy_func(x="", y=""): pass class mkbtn(MDButton): def __init__( self, text, style="elevated", # radius=[20, 20, 20, 20], icon=None, # func=lambda x: dummy_func(x), func=dummy_func, **kwargs ): super().__init__(**kwargs) self.style = style self.radius = radius self.size_hint_x = None # self.adaptive_width=True # self.size_hint_min_x = 0.3 # self.wide = dp(120) self.width = dp(120) if icon: self.add_widget(MDButtonIcon(icon)) self.add_widget(MDButtonText(text=text)) self.bind(on_release=func) # center text on button - has to be after `add_widget(MDButtonText(..>))` self._button_text.pos_hint = {"center_x": 0.5, "center_y": 0.5} # center button in layout (Box) self.pos_hint = {"center_x": 0.5, "center_y": 0.5} # center Y # Clock.schedule_once(self.update_later, 0.2) # def update_later(self, args): # self.width = dp(120) def adjust_width(self, args): passIf you add background color in MDBoxLayout then you see how it is centered
self.hlay5 = MDBoxLayout( orientation="horizontal", padding=[5, 5, 5, 5], spacing=dp(10), md_bg_color=[1, 0, 0, 1], )Before centering:
After centering:
To reduce height in rows I have to use size_hint_y=None in every hlay* and bind function which will calculates minimal height for every hlay*
self.hlay4.bind(minimum_height=self.hlay4.setter("height")) class MainScreen(MDScreen): def __init__(self, **kwargs): super().__init__(**kwargs) self.md_bg_color = [1, 1, 1, 1] # md_bg_color: self.theme_cls.secondaryContainerColor self.main_layout = MDBoxLayout(orientation="vertical") self.app_bar = MDTopAppBar(type="small") self.abtitle = MDTopAppBarTitle( text="WOS Squad Ratio (Bear/CJ)", halign="center" ) self.app_bar.add_widget(self.abtitle) self.content_layout = MDBoxLayout( orientation="vertical", padding=[5, 5, 5, 5], spacing=dp(10), ) self.hlay1 = MDBoxLayout( orientation="horizontal", padding=[5, 5, 5, 5], spacing=dp(10), size_hint_y=None, ) self.bdctf = TxtField(htxt="Bear DC", ilen=6) self.prof_btn = mkbtn("Profiles", icon="triangle-small-down") self.hlay1.add_widget(self.bdctf) self.hlay1.add_widget(self.prof_btn) self.hlay1.bind(minimum_height=self.hlay1.setter("height")) ### self.hlay2 = MDBoxLayout( orientation="horizontal", padding=[5, 5, 5, 5], spacing=dp(10), size_hint_y=None, ) self.cdctf = TxtField(htxt="CJ DC", ilen=6) self.aprof_btn = mkbtn("Add Profiles") self.hlay2.add_widget(self.cdctf) self.hlay2.add_widget(self.aprof_btn) self.hlay2.bind(minimum_height=self.hlay2.setter("height")) ### self.hlay3 = MDBoxLayout( orientation="horizontal", padding=[5, 5, 5, 5], spacing=dp(10), size_hint_y=None, ) self.titf = TxtField(htxt="Total Infantry", ilen=7) self.cb_btn = mkbtn("Calc Bear") self.hlay3.add_widget(self.titf) self.hlay3.add_widget(self.cb_btn) self.hlay3.bind(minimum_height=self.hlay3.setter("height")) ### self.hlay4 = MDBoxLayout( orientation="horizontal", padding=[5, 5, 5, 5], spacing=dp(10), size_hint_y=None, ) self.tltf = TxtField(htxt="Total Lancer", ilen=7) self.cc_btn = mkbtn("Calc CJ") self.hlay4.add_widget(self.tltf) self.hlay4.add_widget(self.cc_btn) self.hlay4.bind(minimum_height=self.hlay4.setter("height")) ### self.hlay5 = MDBoxLayout( orientation="horizontal", padding=[5, 5, 5, 5], spacing=dp(10), md_bg_color=[1, 0, 0, 1], size_hint_y=None, ) self.tmtf = TxtField(htxt="Total Lancer", ilen=7) self.sd_btn = mkbtn("Save Data") self.hlay5.add_widget(self.tmtf) self.hlay5.add_widget(self.sd_btn) self.hlay5.bind(minimum_height=self.hlay5.setter("height")) ### self.tlbl = MDLabel( halign="left", role="large", padding=[5, 0, 0, 500], text="", ) def cng_lbl(txt): self.tlbl.text = txt ### self.content_layout.add_widget(self.hlay1) self.content_layout.add_widget(self.hlay2) self.content_layout.add_widget(self.hlay3) self.content_layout.add_widget(self.hlay4) self.content_layout.add_widget(self.hlay5) self.content_layout.add_widget( MDWidget( # size_hint_y=1, # doesn't need this md_bg_color=[0, 1, 0, 1], ) ) ### self.main_layout.add_widget(self.app_bar) self.main_layout.add_widget(self.content_layout) ### self.add_widget(self.main_layout)It keeps sizes after resizing window.
but problem is when window is too small to keep all elements







