Basically I'm working on a Kivy app that consists of multiple screens. Recently I decided to give my app a little Refresh
button that refreshes the widgets and reread the savefile for sorta debugging purpose, and then I of course stole the code from this question's answer, like how every programmer would do. It worked, but there's one slight problem: every time I press the refresh button, for whatever reason the widgets got duplicated and placed on top of each other(even though the restart function cleared the former widgets beforehand). Here's my code, simplified:
test.py
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen
from kivy.config import Config
Config.set("kivy", "exit_on_escape", 0)
class First(Screen):
pass
class Second(Screen):
pass
class Test(MDApp):
def restart(self):
self.root.clear_widgets()
self.stop()
Test().run()
Test().run()
test.kv
ScreenManager:
First:
Second:
<First>:
MDFloatLayout:
MDTextField:
size_hint: 0.8, 0.2
pos_hint: {'center_x': 0.5, 'top': 0.9}
hint_text: 'owo uwu test im a furry yes'
MDRectangleFlatButton:
text: 'Restart'
size_hint: 0.15, 0.1
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
on_release: app.restart()
<Second>:
Also note that the reason to why I used screens in this example app although there's no way to access the Second
screen, is because I did some tests and the result is that the "bug" only occurs with the ScreenManager
being the root class, others like FloatLayout
works properly. Secondly the reason why I used KivyMD in this example is that it's easier to detect the duplication of widgets using MDTextField
because of the animation of the hint text.
Does anyone know what's the cause behind the problem, as well as the solution to this? Any help would be appreciated.
Edit: Here are images for demonstration:
Before restarting:
After restarting:
Th problem is that your test.kv
file is getting loaded twice due to Kivy doing its automatic loading based on the file name. The fix is to control the kv
file loading yourself. To do that, change the name of your kv
file to anything other than test.kv
, perhaps not_test.kv
. Then create a build()
method in your Test
App
:
class Test(MDApp):
def build(self):
from kivy.resources import resource_find
filename = 'not_test.kv'
filename = resource_find(filename) or filename
if filename in Builder.files:
Builder.unload_file(filename)
return Builder.load_file(filename)
This code unloads the kv
file if it has already been loaded, then loads it again in order to get the root widget.