kivy.uix.screenmanager.ScreenManagerException: ScreenManager accepts only Screen widget. Error - python

I'm trying to add these two screens to the screenmanager but i'm getting this error. What am i doing wrong? I know there are other ways to use the screen manager but i want to know how i could use it with the builder method with these seperate kv files.
The codes that i wrote for the screens:
Python
from kivy.uix.screenmanager import Screen
class Screen2(Screen):
def buttFunc2(self):
print("Screen2")
from kivy.uix.screenmanager import Screen
class Screen1(Screen):
def buttFunc(self):
print("Screen1")
KV
<Screen2>:
name: "screen2"
BoxLayout:
Button:
text: "Screen 2"
on_release: root.buttFunc2()
Button:
text: "Go To Screen1"
#on_release: i also want this function to change the screen to the other one
<Screen1>:
name: "screen1"
BoxLayout:
Button:
text: "Screen 1"
on_release: root.buttFunc()
Button:
text: "Go To Screen2"
#on_release: i also want this function to change the screen to the other one
Main.py Python file:
from kivy.core.window import Window
from kivy.lang.builder import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager
from screen1 import Screen1
class MyApplication(MDApp):
def build(self):
Window.size = 300,600
sm = ScreenManager()
sm.add_widget(Builder.load_file("screen1.kv"))
sm.add_widget(Builder.load_file("screen1.kv"))
return sm
if __name__ == "__main__":
MyApplication().run()
I also would like to go between screens by a button but i dont't know how to do it using these files.

Need to import custom Screen classes just like other scripts:
main.py:
from kivy.core.window import Window
from kivy.lang.builder import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager,Screen
from sc1 import Screen1
from sc2 import Screen2
class MyApplication(MDApp):
def build(self):
Window.size = 300, 600
sm = ScreenManager()
sm.add_widget(Screen1())
sm.add_widget(Screen2())
return sm
if __name__ == "__main__":
MyApplication().run()
sc1.py:
from kivy.uix.screenmanager import Screen
from kivy.lang.builder import Builder
class Screen1(Screen):
Builder.load_file('screen1.kv')
def buttFunc(self):
print("Screen1")
sc2.py:
from kivy.uix.screenmanager import Screen
from kivy.lang.builder import Builder
class Screen2(Screen):
Builder.load_file('screen2.kv')
def buttFunc2(self):
print("Screen2")
screen1.kv:
<Screen1>:
name: "screen1"
BoxLayout:
Button:
text: "Screen 1"
on_release: root.buttFunc()
Button:
text: "Go To Screen2"
on_release: app.get_running_app().root.current = 'screen2'
screen2.kv:
<Screen2>:
name: "screen2"
BoxLayout:
Button:
text: "Screen 2"
on_release: root.buttFunc2()
Button:
text: "Go To Screen1"
on_release: app.get_running_app().root.current = 'screen1'

Related

Not able to save data instantly after clicking save button- kivy

I am trying to write in a text file after getting an input through TextInput in kivy. The problem is the data gets saved only after i close the app but i want the data to get saved as soon as I leave the specific screen and go to another screen. I am trying to input in add_staff and get it saved in the app through save() function.
import kivymd
import kivy
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
Builder.load_string('''
<MenuScreen>:
nm:nm_input
BoxLayout:
TextInput:
id:nm_input
Button:
text: 'Add New Staff'
on_press: root.manager.current = 'add_staff'
Button:
text: 'View Staff Profile'
Button:
text: 'Salary report'
<Add_new_staff>:
nam: str(name_input)
job: job_input
GridLayout:
cols: 2
Label:
text: 'Name'
TextInput:
id: name_input
multiline: False
Label:
text: 'Job'
TextInput:
id: job_input
Label:
text: 'Salary'
TextInput:
Label:
text: 'Date of Joining'
TextInput:
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
Button:
text: 'Save'
on_press: root.save(name_input.text, job_input.text);root.manager.current = 'menu'
''')
class MenuScreen(Screen):
pass
class Add_new_staff(Screen):
def save(self, name, job):
fob = open('testi.txt','a')
fob.write(name + "\n")
fob.write(job)
fob.close()
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(Add_new_staff(name='add_staff'))
return sm
def lo(self,nm):
f=open('log.txt','a')
f.write(nm)
f.close()
if __name__ == '__main__':
TestApp().run()

Kivy: Navigation bar on all screens

I want to keep the Navigationbar on all my screen, I am able to switch screen and display what I want but I don't seem to keep the Navigationbar.
Also for some reason my side menu seems to appear twice, overlapping each other and I'm not sure why, I've tried refactoring the code and it just seems to appear again
Can anyone offer any help?
*.py
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.core.window import Window
from kivymd.app import MDApp
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel
class FirstWindow(Screen):
pass
class ThirdWindow(Screen):
def on_pre_enter(self):
anchor = AnchorLayout(size=(1,1))
test = "This is the new window"
card = MDCard(orientation='vertical',padding="8dp",size_hint=(1,0.5),pos_hint={'top': 0.1,'right':1},radius=[5, ])
card.test = test
card.add_widget(MDLabel(text=test, halign="center"))
anchor.add_widget(card)
self.anchorID.add_widget(anchor)
class WindowManager(ScreenManager):
pass
class NearMeApp(MDApp):
def build(self):
self.theme_cls.theme_style ="Dark"
self.theme_cls.accent_palette = "Red"
self.theme_cls.primary_palette = "Purple"
self.root = Builder.load_file('NearMe.kv')
if __name__ == '__main__':
NearMeApp().run()
*.kv
#:import hex kivy.utils.get_color_from_hex
#:kivy 1.10.1
WindowManager:
FirstWindow:
ThirdWindow:
<FirstWindow>:
name:"FirstWindow"
Screen:
MDNavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "NearMe Application"
elevation: 10
left_action_items: [['menu', lambda x: nav_drawer.set_state("open")]]
Widget:
MDNavigationDrawer:
id: nav_drawer
BoxLayout:
orientation:'vertical'
Button:
text:"ThirdWindow"
on_release: root.manager.current = "ThirdWindow"
<ThirdWindow>:
name:"ThirdWindow"
anchorID:anchorID
AnchorLayout:
id:anchorID
canvas.before:
Color:
rgba: .2, .2, .2, 1
Rectangle:
pos: self.pos
size: self.size
Your md toolbar needs to be above the main windowmanager.
With your mdtoolbar as a child of firstwindow (child of windowmanager), your windowmanager acts on it and the other children of firstwindow at same during change in current window. By moving the mdtoolbar out of firstwindow and above windowmanager the mdtoolbar will remain present.
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.screenmanager import Screen
class FirstWindow(Screen):
pass
class ThirdWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = """
Screen:
MDNavigationDrawer:
id: nav_drawer
BoxLayout:
orientation:'vertical'
Button:
text:"ThirdWindow"
on_release: root.ids.manager.current = "ThirdWindow"
StackLayout:
MDToolbar:
title: "NearMe Application"
size_hint: (1, 0.1)
elevation: 10
left_action_items: [['menu', lambda x: nav_drawer.set_state("open")]]
WindowManager:
id: manager
FirstWindow:
ThirdWindow:
<FirstWindow>:
name:"FirstWindow"
Screen:
BoxLayout:
orientation: 'vertical'
Widget:
<ThirdWindow>:
name:"ThirdWindow"
anchorID:anchorID
AnchorLayout:
id:anchorID
canvas.before:
Color:
rgba: .2, .2, .2, 1
Rectangle:
pos: self.pos
size: self.size
"""
class Test(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = Builder.load_string(kv)
def build(self):
return self.screen
the_app = Test()
the_app.run()
The above removes the toolbar from your FirstWindow and places it on its own. In your example the toolbar is a child of FirstWindow so when you change the current window (screen) to ThirdWindow the toolbar disappears with its parent (FirstWindow). Now the toolbar is not a child of either window.

How would I switch screens from a .py file while the screens are managed in a main .kv file?

I have three codes, I am confused with how I would navigate to the next screen in my Organize.kv from my login.py, I have the main kv file that has all the screens saved and the login python and kv file that manages the login screen, the login kv file balances two different tabs, so far I have the create tab that sends you to the create class of the login python file which is connected to mysql, how would I switch screens to the Main Menu which is in the main Organize.kv file from the login python file? Sorry if this doesn't make sense, I'm super warn out from trying to figure this out.
Anything helps, thank you
The main Organize.kv that has all the screens
#:import organize organize
#:import navigation_screen_manager navigation_screen_manager
#:import anchorlayout_with_action_bar anchorlayout_with_action_bar
#:import sharpen_skills sharpen_skills
#:import login login
<MainMenu#BoxLayout>:
orientation: "vertical"
padding: "40dp"
spacing: "20dp"
size_hint: .7, .9
pos_hint: {"center_x": .5}
Button:
text: "Organize"
on_press: app.manager.push("screen2")
Button:
text: "Journal"
on_press: app.manager.push("screen3")
Button:
text: "Sharpen Skills"
on_press: app.manager.push("SkillsExamplesTabs")
Button:
text: "Exit"
on_press: app.stop()
<MyScreenManager>:
Screen:
name: "Login"
title: "login"
LoginTabs:
Screen:
name: "MainMenu"
MainMenu:
Screen:
name: "screen2"
AnchorLayoutWithActionBar:
title: "Organize"
Screen:
name: "screen3"
AnchorLayoutWithActionBar:
title: "Journal"
Screen:
name: "SkillsExamplesTabs"
AnchorLayoutWithActionBar:
title: "Sharpen Skills"
SkillsExamplesTabs:
My login.kv file
<LoginTabs#TabbedPanel>:
do_default_tab: False
TabbedPanelItem:
text: "Create Account"
Create:
TabbedPanelItem:
text: "Login"
Login:
and finally my login.py file
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager
from kivy.uix.stacklayout import StackLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.graphics import Color, Rectangle
import mysql.connector
import navigation_screen_manager
from kivy.uix.screenmanager import ScreenManager, Screen
from navigation_screen_manager import NavigationScreenManager
Builder.load_file("login.kv")
Builder.load_file("Organize.kv")
sm = ScreenManager()
class MyScreenManager(NavigationScreenManager):
pass
class Create(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.orientation = "vertical"
self.build()
def build(self):
self.warning = Label(text="", pos_hint={'center_x': .5, 'center_y': .5})
user_label = Label(text="Username", size_hint=(.5, .5),
pos_hint={'center_x': .5, 'center_y': .5})
self.user_textinput = TextInput(text='Enter Username')
pas_label = Label(text="Password", size_hint=(.5, .5),
pos_hint={'center_x': .5, 'center_y': .5})
self.pas_textinput = TextInput(text="enter Password")
enter_button = Button(text="Create")
with user_label.canvas:
Color(0, .25, 1, .25)
enter_button.bind(on_press=self.Add)
self.add_widget(self.warning)
self.add_widget(user_label)
self.add_widget(self.user_textinput)
self.add_widget(pas_label)
self.add_widget(self.pas_textinput)
self.add_widget(enter_button)
def Add(self, btn):
print("Working")
t1 = self.user_textinput.text
t2 = self.pas_textinput.text
print(f"T1 = {t1} and {t2}")
conn = mysql.connector.connect(
user='root',
password='*******',
host='127.0.0.1',
database='Usersdb')
mycursor = conn.cursor()
try:
sql = "INSERT INTO user_info (user_name, user_pass) VALUES (%s, %s)"
val = (t1,t2)
mycursor.execute(sql,val)
conn.commit()
except:
self.warning = "Username Already Taken"
class Login(StackLayout):
pass
And finally my App class
from kivy.app import App
from kivy.uix.label import Label
from kivy.metrics import dp
from kivy.properties import StringProperty, BooleanProperty, ObjectProperty
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.widget import Widget
from navigation_screen_manager import NavigationScreenManager
class MyScreenManager(NavigationScreenManager):
pass
class Organizer(App):
manager = ObjectProperty(None)
def build(self):
self.manager = MyScreenManager()
return self.manager
Organizer().run()
And my Navigation Screen Manager
from kivy.uix.screenmanager import ScreenManager
class NavigationScreenManager(ScreenManager):
screen_stack = []
def push(self, screen_name):
self.screen_stack.append(self.current)
self.transition.direction = "left"
self.current = screen_name
def pop(self):
if len(self.screen_stack) > 0:
screen_name = self.screen_stack[-1]
del self.screen_stack[-1]
self.transition.direction = "right"
self.current = screen_name
Good day. You must access your screen manager in order to set the current screen which is your active screen. In your App class, I recommend saving your screen manager as an attribute via the on_start function.
class MyApp(App):
def on_start(self):
screen_manager = self.root
From there, you could set your current screen using callback methods in kivy or python.
#in kv
on_release: setattr(app.screen_manager, 'current', 'the next screen name')
#in python
def set_screen_callback(self, instance *args):
app.screen_manager.current = "the next screen name"
Your post does not include your App class, so a specific answer is impossible. The fact that you have multiple kv files is irrelevant once those kv files are loaded. In general, you just set the current property of the ScreenManager to the name of the Screen that you want displayed.
Again, the fact that you have multiple kv files is irrelevant once those kv files are loaded. So in any of the kv files, I believe that you should be able to use:
app.manager.push("MainMenu")
or:
app.manager.current = "MainMenu"
to get to the MainMenu Screen.

how to show plot in other screen kivy

i tried to show a plot in second screen after i clicked the button in the first screen.
this is the code that i tried.
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
from kivy.uix.widget import Widget
from pandas import read_excel
import matplotlib.pyplot as plt
plt.plot([1, 23, 2, 4])
plt.ylabel('some numbers')
class MainWindow(Screen):
def btn(self):
print("name: ",self.name2.text)
self.ids.destination.add_widget(FigureCanvasKivyAgg(plt.gcf()))
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("my.kv")
class MyMainApp(App):
def build(self):
return kv
if __name__=="__main__":
MyMainApp().run()
#:kivy 1.9.1
WindowManager:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
name2: name2
GridLayout:
cols:1
size: root.width, root.height
GridLayout:
cols:2
Label:
text:"name: "
TextInput:
id: name
multinline:False
Label:
text:"name2: "
TextInput:
id: name2
multinline:False
Button:
text:"Submit"
on_release:
root.btn()
app.root.current = "second"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "second"
GridLayout:
cols:1
BoxLayout:
id: destination
Button:
text: "Go Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
but i got error says 'super' object has no attribute '__getattr__' and i don't know what it means. please help me.
The problem is that you are trying to use an id that is defined in a different Screen. The destination is defined in SecondWindow, so MainWindow knows nothing about it. So, you can reference that id by going through SecondWindow like this:
class MainWindow(Screen):
def btn(self):
print("name: ",self.name2.text)
self.manager.get_screen('second').ids.destination.add_widget(FigureCanvasKivyAgg(plt.gcf()))

Kivy content sizes adjustment

I have been started to work in kivy recently. The thing what I am doing now is, i have a blank page with a button, when I click that button it navigates to an user input screen. It works fine, but the content comes in a very small input boxes and text as in the picture.
My question is that I want it bigger and centred.
Here is my code:
In python:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.lang import Builder
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text="Username:"))
self.username = TextInput(multiline=False)
self.add_widget(self.username)
self.add_widget(Label(text="Password:"))
self.password = TextInput(multiline=False, password=True)
self.add_widget(self.password)
self.add_widget(Label(text="Two Factor Auth:"))
self.tfa = TextInput(multiline=False)
self.add_widget(self.tfa)
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("screen.kv")
class SimpleKivy(App):
def build(self):
return presentation
if __name__ == "__main__":
SimpleKivy().run()
In kv:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
Button:
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.2
text: "Click"
on_release: app.root.current = "other"
pos_hint: {"right":1, "top":1}
<AnotherScreen>:
name: "other"
GridLayout:
LoginScreen
In your screen.kv, you have the LoginScreen inside a GridLayout. Since the LoginSCreen is a GridLayout, you do not need that extra GridLayout.
Just change:
<AnotherScreen>:
name: "other"
GridLayout:
LoginScreen
to:
<AnotherScreen>:
name: "other"
LoginScreen:

Categories