cannot remove widget in Kivy - python

i cannot remove widget using the screen with kivy python, i dont know why it just does not do anything
the code was suppose to remove textinput with id:name on the first screen but it just does not do anything and no error message.
here is all of the code it is tested on python 3.7.4, kivy 1.11.1 on window.
module_media_player.py
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.core.audio import SoundLoader
from kivy.uix.videoplayer import VideoPlayer
from kivy.uix.screenmanager import ScreenManager,Screen
class Player(Screen):
def press(self):
self.ids.name.text = 'nice'
def remove(self):
self.remove_widget(self.ids.name)
class MediaPlayer(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('my.kv')
class GoodApp(App):
def build(self):
return kv
if __name__ == '__main__':
GoodApp().run()
my.kv
WindowManager:
Player:
MediaPlayer:
<Player>:
name:"player"
BoxLayout:
orientation:"vertical"
size:root.width,root.height
cols:2
TextInput:
id:name
multiline:False
text:"first"
font_size:12
size_hint_y:0.3
Button:
text:"click me"
on_press:root.remove()
Button:
text:"next window"
font_size:14
size_hint_y:0.7
on_release:
app.root.current = "mediaplayer"
root.manager.transition.direction = "left"
<MediaPlayer>:
name:"mediaplayer"
BoxLayout:
orientation:"vertical"
size:root.width,root.height
Label:
text:"second"
font_size:12
Button:
text:"previous window"
font_size:14
on_release:
app.root.current = "player"
root.manager.transition.direction = "right"

Your code:
def remove(self):
self.remove_widget(self.ids.name)
is trying to remove the TextInput from the Player Screen, but that Textinput is not a child of Player. It is actually a child of the BoxLayout. You can fix this by modifying your remove() method:
def remove(self):
textinput = self.ids.name
textinput.parent.remove_widget(textinput) # remove widget from its parent

Related

kivy positioning all items in a single box

I am writing a program that requires a label, a text_input, and a checkbox to be aligned on screen in that order. They should span the width of the screen and be at the same y level.
I have written this code in my .kv file which uses identical pos_hint values, but only the text_input box moves
Below is my .kv code:
<Union>:
BoxLayout:
orientation: "vertical"
BoxLayout:
orientation: "horizontal"
pos_hint_y: {"top":.85}
Label:
text: 'Session Length'
pos_hint: {"x":.3, "top":.85}
TextInput:
id: input
text: "test"
pos_hint: {"x":.5, "top":.85}
size_hint: 0.3, 0.05
background_disabled_normal: ""
disabled: not checkbox.active
on_text: app.return_text()
CheckBox:
id: checkbox
pos_hint: {"x":.7, "top":.85}
and here is my main.py
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen, ScreenManager
Window.size = (309, 555)
class MenuScreen(Screen):
pass
class SetupScreen(Screen):
pass
class drop_content(DropDown):
pass
class UnionScreen(Screen):
class Checkbox_Setup(FloatLayout):
pass
class TheApp(App):
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SetupScreen(name='setup'))
sm.add_widget(UnionScreen(name='union'))
return sm
def return_text(self):
text = self.root.get_screen('union').ids.input.text
print(text)
def main():
Builder.load_file('menu.kv')
app = TheApp()
app.run()
if __name__ == '__main__':
main()
Finally, here is the output I am currently getting, with the label and checkbox in line but underneath the text_input which is in the right place.
I am relatively new to kivy so any help would be greatly appreciated. Thanks in advance!

kivy button calls method of another class

I have a simple problem which keeps me busy in the last days.
In Kivy I have two Windows.
FirstWindow has a method update(), which is triggered by a button press.
On SecondWindow I have only one button, which sends me back to FirsWindow, but I want it to trigger the update() method from FirstWindow and change the label, just like the "update label" button does on FirstWindow, without previously pressing the "update label" button.
Any help, please?
file.py
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, ReferenceListProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen):
my_button = ObjectProperty(None)
my_label = ObjectProperty(None)
def update(self):
self.my_label.text = 'UPDATED'
class SecondWindow(Screen):
def go_first(self):
FirstWindow().update()
class WindowManager(ScreenManager):
pass
class MyTestApp(App):
def build(self):
return Builder.load_file('my_test.kv')
MyTestApp().run()
my_test.kv
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
my_label: my_label_id
BoxLayout:
Label:
id: my_label_id
text:"Label"
font_size:self.width / 5
BoxLayout:
orientation: "vertical"
Button:
text: "next screen"
on_press: root.manager.current = 'second'
Button:
text: "update label"
on_press: root.update()
<SecondWindow>:
name:"second"
Button:
text: "go back and update"
on_press:
root.manager.current = 'first'
root.go_first()
I think critical is this method, whitch needs to be remake, but I have no idea how
def go_first(self):
FirstWindow().update()
You can't directly access another screen which is defined as another class. First, you have to access the ScreenManager i.e. Parent class and then from it get the screen FirstScreen
So the go_first function in your code will look like this:
def go_first(self):
self.parent.get_screen('first').update()
EDIT:
Here's full code:
main.py:
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, ReferenceListProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen):
my_button = ObjectProperty(None)
my_label = ObjectProperty(None)
def update(self):
self.my_label.text = 'UPDATED'
class SecondWindow(Screen):
def go_first(self):
self.parent.get_screen('first').update()
class WindowManager(ScreenManager):
pass
class MyTestApp(App):
def build(self):
return Builder.load_file('my.kv')
MyTestApp().run()
my.kv:
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "first"
my_label: my_label_id
BoxLayout:
Label:
id: my_label_id
text:"Label"
font_size:self.width / 5
BoxLayout:
orientation: "vertical"
Button:
text: "next screen"
on_press: root.manager.current = 'second'
Button:
text: "update label"
on_press: root.update()
<SecondWindow>:
name:"second"
Button:
text: "go back and update"
on_press:
root.manager.current = 'first'
root.go_first()

Why popup dismiss method causes an error? (python kivymd)

I'm trying to make a app. On button click on the bottom right of the screen there appears a dialog window(popup). On "Done" click the popup window is expected to close (close_dialog method), but for some reason there appears AttributeError:
AttributeError: 'grudget4App' object has no attribute 'close_dialog'
Could you please tell me why the code doesn't work and how to fix it. Thanks.
.py code:
from kivy.lang import Builder
from kivy.core.window import Window
from kivymd.app import MDApp
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.scrollview import ScrollView
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.uix.textfield import MDTextField
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.uix.list import TwoLineAvatarListItem
Window.size = (288, 511)
class DialogContent(BoxLayout):
pass
class Container(Screen):
dialog = None
def show_dialog(self, *args):
'''
Create group creation popup
'''
if not self.dialog:
self.dialog = MDDialog(
title="Create new group",
type="custom",
content_cls=DialogContent(),
auto_dismiss=False
)
self.dialog.open()
def close_dialog(self, *args):
'''
Close popup on Done click
'''
self.dialog.dismiss()
class grudget4App(MDApp):
def build(self):
container = Container()
return container
if __name__ == '__main__':
grudget4App().run()
.kv code:
<DialogContent>:
textfield: textfield
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "120dp"
MDTextField:
id: textfield
hint_text: "Group name"
MDFlatButton:
id: btn1
text: "Done"
text_color: self.theme_cls.primary_color
on_release: app.close_dialog()
<Container>:
MDFloatingActionButton:
pos_hint: {'right': 0.95, 'y': 0.05}
icon: "icon.png"
theme_text_color: "Custom"
text_color: app.theme_cls.primary_color
on_release:
root.show_dialog()
Screen:
NavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Demo Application'
left_action_items: [["menu", lambda x: nav_drawer.toggle_nav_drawer()]]
elevation:10
Widget:
MDNavigationDrawer:
id: nav_drawer
The method on_release: app.close_dialog() refers to your grudget4App class, but you want to call the method inside your Container class.
So we need to get the right screen inside your app. Since Container is the only screen there, and also the root, you can use:
on_release: app.root.close_dialog()

Changing the screen and running a function on kivyMD?

I am learning Kivy, but I do not kown how to change a screen and running a funtion at the same time.
Where should I declare my funtion so the button have access to the code and can run the function?
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
screen_helper = """
ScreenManager:
MenuScreen:
FunctionScreen:
<MenuScreen>:
name: 'menu'
MDRectangleFlatButton:
text: 'Function'
pos_hint: {'center_x':0.5,'center_y':0.5}
on_press: root.manager.current = 'function screen'
<FunctionScreen>:
name: 'function screen'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class FunctionScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(FunctionScreen(name='function'))
class DemoApp(MDApp):
def build(self):
screen = Builder.load_string(screen_helper)
return screen
# def funtion(self):
# do stuff and then go to menu screen
DemoApp().run()
Should I try maybe, add the on_opress atribute in the build function?
Can you guys help me?
There are several convenient places to place the function(). One is in the MenuScreen, and in that case, it would be referenced in the kv files as:
root.function()
Another convenient place is in the DemoApp, and in that case, the reference would be:
app.function()
So, here is a version of your code tht puts the function() in the App:
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen
screen_helper = """
ScreenManager:
MenuScreen:
FunctionScreen:
<MenuScreen>:
name: 'menu'
MDRectangleFlatButton:
text: 'Function'
pos_hint: {'center_x':0.5,'center_y':0.5}
on_press:
root.manager.current = 'function screen'
app.function()
<FunctionScreen>:
name: 'function screen'
MDRectangleFlatButton:
text: 'Back'
pos_hint: {'center_x':0.5,'center_y':0.1}
on_press: root.manager.current = 'menu'
"""
class MenuScreen(Screen):
pass
class FunctionScreen(Screen):
pass
class DemoApp(MDApp):
def build(self):
sm = Builder.load_string(screen_helper)
return sm
def function(self):
# do stuff and then go to menu screen
print('in function')
DemoApp().run()
Note that the lines of your code that built a ScreenManager have been deleted as they are unnecessary.

Kivy - Adding Buttons To Screen Through Python

I am trying to make a screen view with buttons. The problem is that the amount of buttons needed each time will change, therefore I am not able to use the kv file to make theses buttons. I am having trouble adding buttons through the normal python code. Any help is appreciated.
import kivy
import webbrowser
import MSQLHandler
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Label
from kivy.uix.widget import Widget
from kivy.uix.listview import ListItemButton
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition, CardTransition, SwapTransition, FadeTransition, WipeTransition, FallOutTransition, RiseInTransition, NoTransition
from kivy.lang import Builder
from kivy.uix.button import Button
class Login_Failed(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Loged_In(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Registers(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Login_Screen(Screen):
teacher_connect_image = ObjectProperty()
username_text_input = ObjectProperty()
password_text_input = ObjectProperty()
teacherid_text_input = ObjectProperty()
def LoginButton(self):
if self.teacherid_text_input.text == "":
Number = 0
else:
Number = int(self.teacherid_text_input.text)
MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number)
def changeScreen(self, next_screen):
self.manager.current = next_screen
if MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number) is True:
print("Returns True")
changeScreen(self, "Loged_In")
elif MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number) is False:
print("Returns False")
changeScreen(self, "Login_Failed")
else:
print("Null")
class ScreenManagerr(ScreenManager):
pass
class MainKivyFrameApp(App):
def build(self):
Registers().add_widget(Button(text="Helpp"))
return ScreenManagerr()
mainFrame = MainKivyFrameApp()
mainFrame.run()
If you look to where the app is being built, you will see: Registers().add_widget(Button(text="Helpp"))
This is where I have tried to add a Button to the screen of Registers. This doesn't give me any errors, but it still does not show the button.
Solution
In the kv file, add an event (on_enter or on_pre_enter) in each screen and bind it to a callback method as shown in the following snippets and example. Remember to remove the widgets that were added dynamically before leaving the current screen, by adding an event (on_leave or on_pre_leave).
Snippets
<Registers>:
on_pre_enter: self.add_buttons(n)
on_leave: self.remove_buttons()
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.properties import ObjectProperty, NumericProperty
class MyScreenManager(ScreenManager):
total_button = NumericProperty(2)
class Login(Screen):
login = ObjectProperty(None)
def on_pre_enter(self):
Window.size = (400, 300)
def check_password(self, instance, password):
if password == "pwd":
instance.current = "registers"
class Registers(Screen):
container = ObjectProperty(None)
def on_pre_enter(self):
Window.size = (800, 600)
def add_buttons(self, n):
print("Registers: n={}".format(n))
for i in range(n):
self.container.add_widget(Button(text="Button #{}".format(i), id=str(i)))
def remove_buttons(self, *args):
for child in [child for child in self.container.children]:
self.container.remove_widget(child)
class Welcome(Screen):
pass
class TestApp(App):
title = "ScreenManager - Add Widgets Dynamically"
def build(self):
return MyScreenManager()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
#:import SwapTransition kivy.uix.screenmanager.SwapTransition
<MyScreenManager>:
transition: SwapTransition()
Login:
Registers:
on_pre_enter:
self.add_buttons(app.root.total_button)
on_leave:
self.remove_buttons()
Welcome:
<Login>:
id: login
name: "login"
login: login
GridLayout:
size_hint: (0.5, 0.5)
pos_hint: {"center_x": 0.5, "center_y": 0.6}
rows: 3
padding: 20
Label:
size_hint: (0.2, 0.2)
text:"Password:"
font_size: 30
halign: "center"
valign: "middle"
TextInput:
id: password
size_hint: (0.2, 0.06)
cursor_blink: True
font_size: 20
multiline: False
password: True
Button:
text: "Continue"
size_hint: (0.2, 0.08)
on_release:
root.login.check_password(root.manager, password.text)
<Registers>:
name:'registers'
container: container
BoxLayout:
orientation: 'vertical'
Button:
text: 'Return to Login'
on_press: root.manager.current = 'login'
Button:
text: 'Next Screen'
on_press: root.manager.current = 'welcome'
BoxLayout:
id: container
orientation: 'vertical'
<Welcome>:
name:'welcome'
BoxLayout:
Label:
text: 'Welcome!'
Button:
text: 'Return to Registers'
on_press:
app.root.total_button = 5
root.manager.current = 'registers'
Output

Categories

Resources