Kivy, ScreenManager says no screen while switching to previous screen - python

Now I'm already using ScreenManager in a different project where it works with no issues. But amazingly same setup doesn't work in any other projects. Simply can't figure out why my screen can only be switched to a new screen (which was not displayed before) and not to any previous screens. I'm posting a simple code to show this phenomenon. Please advice what am I seriously missing. Thank you.
screenmanager_test.py
import kivy
kivy.require('1.11.0')
import os
os.environ['KIVY_GL_BACKEND'] = 'gl'
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen, ScreenManager, FadeTransition
from kivy.clock import Clock
class MainScreen(Screen):
def setName(self,*args):
FirstPopup().open()
class SecondScreen(Screen):
pass
class FirstPopup(Popup):
pass
class MyScreenManager(ScreenManager):
pass
class SmTestApp(App):
def build(self):
sm = MyScreenManager()
sm = ScreenManager(transition=FadeTransition())
sm.add_widget(MainScreen(name="main_scr"))
sm.add_widget(SecondScreen(name="second_scr"))
return sm
SmTestApp().run()
smtest.kv
#: kivy 1.11.0
<MainScreen>:
name: 'main_scr'
BoxLayout:
orientation: 'vertical'
padding: 100,100
spacing: 50
Label:
text: 'Welcome to Main Screen'
font_size: 35
Button:
text: 'Options'
font_size: 15
on_release: root.setName(*args)
Button:
text: 'Next Screen'
font_size: 15
on_release: app.root.current = 'second_scr'
<SecondScreen>:
name: 'second_scr'
BoxLayout:
orientation:'vertical'
padding:100,100
spacing:50
Label:
text: 'This is your second screen'
font_size: 35
Button:
text: 'Back'
font_size: 25
on_release: app.root.current = 'main_scr'
<FirstPopup>:
title: 'Options Window'
size_hint: None, None
size: 400,370
BoxLayout:
orientation : 'vertical'
Label:
text : "Checkbox options listed here"
Button:
text: "OK"
on_release: root.dismiss()

Ok. Here is what I have found. I removed that FadeTransition effect and things came back to normal. I checked all other available transition methods and found that out of 8 , 4 transition style causes the program to exit. The effects which are causing this error are Fade, Wipe, FallOut and RiseIn.
If this is caused due to some other wrongly set paramenter, I don't know. If anyone can give an explanation then that would be fine. If not any how the cause has been identified. Thank you #John Anderson.

Related

Clock warning when using MDRectangleFlatButton and MDRaisedButton

I am making a desktop application using kivy & kivymd and when creating the settings screen for the app I used two MDRectangleFlatButon and MDRaisedButtons but to make them scalable, I gave both of them a size_hint_x of .5 for each to take up half of the screen. However, as soon as the program starts I get this warning from kivy:
[CRITICAL] [Clock ] Warning, too much iteration done before the next frame. Check your code, or increase the Clock.max_iteration attribute
the interesting part is that if I switch the current screen to the one that I defined them inside of it, the warning stops. Why am I getting this warning and how can I stop it? My python file:
from kivy.config import Config
Config.set('graphics', 'width', '850')
Config.set('graphics', 'height', '530')
Config.set('graphics', 'minimum_width', '850')
Config.set('graphics', 'minimum_height', '530')
from kivy.lang import Builder
from kivymd.uix.card import MDCard
from kivymd.uix.tab import MDTabsBase
from kivymd.app import MDApp
class SettingsTab(MDCard, MDTabsBase):
pass
class Example(MDApp):
def __init__(self, **kwargs):
super(Example, self).__init__(**kwargs)
self.kv = Builder.load_file("design.kv")
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Blue"
self.theme_cls.accent_palette = "Teal"
return self.kv
if __name__ == '__main__':
Example().run()
My kv file:
#:kivy 2.0.0
<SettingsTab>:
orientation: "vertical"
size_hint: .95, .95
pos_hint: {"center_x": .5, "center_y": .5}
border_radius: 5
radius: [5]
elevation: 20
BoxLayout:
MDNavigationRail:
color_active: app.theme_cls.primary_color
MDNavigationRailItem:
icon: "list-status"
on_release:
screens.current = "downloads_screen"
MDNavigationRailItem:
icon: "cog"
on_release:
screens.current = "settings"
MDNavigationRailItem:
icon: "information"
on_release:
screens.current = "activity_log"
ScreenManager:
id: screens
Screen:
name: "downloads_screen"
Screen:
name: "activity_log"
Screen:
name: "settings"
MDTabs:
SettingsTab:
title: "DOWNLOAD"
SettingsTab:
title: "COLOR"
MDBoxLayout:
adaptive_height: True
orientation: "vertical"
padding: 10
MDLabel:
text: "Theme Manager: "
font_style: "H5"
padding_y: 10
size_hint_y: None
height: self.texture_size[1]
MDBoxLayout:
adaptive_height: True
spacing: 10
MDRectangleFlatButton:
text: "See Current Palette"
size_hint_x: .5
MDRaisedButton:
text: "Open Theme Picker"
size_hint_x: .5
SettingsTab:
title: "INFO"
EDIT: Just to mention, I do not just want the warning go away, I want to stop the performance drop. Even if I didn't add size_hint to any of the buttons (which doesn't cause the error anymore), the app becomes very sluggish and slow. When resizing the program there is a huge delay and when the program starts it is really doing a number on my cpu and it won't change until I switch to that frame.
If you change the order of your Screens definition, so that the "settings" Screen is the first listed under ScreenManager in your kv, then the error messages go away. Then adding to the Example class definition:
def on_start(self):
self.kv.ids.screens.transition = NoTransition()
self.kv.ids.screens.current = 'downloads_screen'
self.kv.ids.screens.transition = SlideTransition()
makes the downloads_screen appear first.

kivy popup question. How do I get a popup to show up on kivy module?

I'm trying to have my python and kivy file to open a popup. It says my Boxlayout object has no attribute 'open_popup'
Here is my python code:
from kivy.app import App
from kivy.properties import BooleanProperty, ListProperty
from kivy.modules import inspector
from kivy.core.window import Window
from kivy.uix.popup import Popup
class CustomPopup(Popup):
pass
class MPMS(App):
def build(self):
inspector.create_inspector(Window, self)
def show_config_popup(self, popup):
pass
def open_popup(self):
the_popup = CustomPopup()
the_popup.open()
if __name__ == '__main__':
app = MPMS()
app.run()
and here is my kivy
BoxLayout:
orientation: 'vertical'
Label:
text: 'MPMS'
BoxLayout:
orientation: 'horizontal'
size_hint: (1, 0.25)
BoxLayout:
orientation: 'vertical'
Button:
id: 'screening_button_mainmenu'
text: 'Screening'
BoxLayout:
orientation: 'vertical'
Button:
id: 'configuration_button_mainmenu'
text: 'Configuration'
on_press: root.open_popup()
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: "The Popup"
BoxLayout:
orientation: 'horizontal'
Label:
text: 'popup has appeared'
I tried looking up videos on youtube and whatnot but I couldn't see it helping me because I couldn't apply it to my situation. Please help me out. thanks in advance
That's because your are doing on_press: root.open_popup(), and root in that case is your BoxLayout (the root of that kv rule). What you want is
on_press: app.open_popup()
Because the open_popup() method is in your App.

kivy multiscreen can not find the id

all, i can not pass the goi into the function submit_goi in class VQCIA in my kivy code. i'd appreciate if some one can fix the code. print self.goi.text() sentence reports a problem, and it says AttributeError: 'NoneType' object has no attribute 'text'. that is really weird.
# ---------- vqcia.py ----------
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<HelloVQCIA>:
BoxLayout:
Button:
text: "Welcome to VQCIA"
on_press:
# You can define the duration of the change
# and the direction of the slide
root.manager.transition.direction = 'left'
root.manager.transition.duration = 1
root.manager.current = 'screen_two'
<VQCIA>:
BoxLayout:
orientation: "vertical"
goi: g_o_i
padding: 10
spacing: 10
size: 400, 200
pos: 200, 200
size_hint:None,None
BoxLayout:
Label:
text: "Enter gene of interest with TAIR ID:"
font_size: '25sp'
BoxLayout:
TextInput:
id: g_o_i
hint_text: 'AT3G20770'
multiline: False
font_size: '25sp'
BoxLayout:
Button:
text: "Submit"
size_hint_x: 15
on_press:
root.submit_goi()
""")
class HelloVQCIA(Screen):
pass
class VQCIA(Screen):
# Connects the value in the TextInput widget to these
# fields
goi = ObjectProperty()
def submit_goi(self):
print self.goi.text
# The ScreenManager controls moving between screens
screen_manager = ScreenManager()
# Add the screens to the manager and then supply a name
# that is used to switch screens
screen_manager.add_widget(HelloVQCIA(name="screen_one"))
screen_manager.add_widget(VQCIA(name="screen_two"))
class VQCIAApp(App):
def build(self):
return screen_manager
dbApp = VQCIAApp()
dbApp.run()
I want to make a multiscreen app and the first page is a welcome page. and the second page is the main page that user can submit a form. thank you.
In kv file, move goi: g_o_i to after class rule, <VQCIA>:
<VQCIA>:
goi: g_o_i
BoxLayout:
orientation: "vertical"

Linking a Kivy Button to Function

There is something in kivy I do not understand, and am hoping that someone could shed light. I have done a lot of reading in this topic but it just doesn't seem to be connecting in my head.
My issue comes from linking a function to a kivy button.
Right now I am trying to learn how to do a simple function:
def Math():
print 1+1
What I would like to do something more complex:
def Math(a,b):
print a^2 + b^2
Where a and b are input labels from kivy, and upon clicking a button the answer will be printed.
This is what I have so far:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
#######``Logics``#######
class Math(FloatLayout):
def add(self):
print 1+1
#######``Windows``#######
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("GUI_Style.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
This is my kivy language file:
import NoTransition kivy.uix.screenmanager.NoTransition
ScreenManagement:
transition: NoTransition()
MainScreen:
AnotherScreen:
<MainScreen>:
name: "main"
FloatLayout:
Button:
on_release: app.root.current = "other"
text: "Next Screen"
font_size: 50
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.2
pos_hint: {"right":1, "top":1}
<AnotherScreen>:
name: "other"
FloatLayout:
Button:
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.2
text: "add"
pos_hint: {"x":0, "y":0}
on_release: root.add
Button:
color: 0,1,0,1
font_size: 25
size_hint: 0.3,0.2
text: "Back Home"
on_release: app.root.current = "main"
pos_hint: {"right":1, "top":1}
<AnotherScreen>:
name: "other"
FloatLayout:
Button:
...
on_release: root.add <-- here *root* evaluates to the top widget in the rule.
Which is an AnotherScreen instance, but it doesn't have an add method.
class Math(FloatLayout):
def add(self):
print 1+1
Here you have declared a Math class by inheriting from the FloatLayout, which is a uix component -a widget-. And you defined a method on this class add. Still you haven't used it. In the kv file you used FloatLayout.
Now in order for you to access a function in kv, most of the time you'll acces it as a method of a uix component, by using either root/self or app, you can also import it e.g:
#: import get_color_from_hex kivy.utils.get_color_from_hex
<ColoredWidget>:
canvas:
Color:
rgba: get_color_from_hex("DCDCDC")
Rectangle:
size: self.size
pos: self.pos
So you can't do it like this:
<AnotherScreen>:
name: "other"
Math:
id: math_layout
Button:
...
on_release: math_layout.add()
or like this:
class AnotherScreen(Screen):
def add(self):
print(1+1)
If you still have problems conserning this topic, i'll be glad to provide more help .

I'm having some trouble with Kivy's ListView

So I've been having a little trouble with ListView. What I have been trying to do is make an API call to ebay. Then I setup a ListView with the results. However, here's the issue. The first time I do a search and it brings me to the results page, it only shows one result. If I scroll way down I will see another result or two pop up, but they disappear right away. Then I will go back to the main page and do the exact same search, however, this time when it goes to the results page, it lists a lot more content. If I scroll down everything seems fine at first, but then the spacing will mess up, there will be a huge gap of nothingness, then the results will be closer together. Here are a few pictures to better explain the issue (sorry I threw the code together real quick to test it.. been trying forever to fix this issue though)
kv file
#: import ListItemLabel kivy.uix.listview.ListItemLabel
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import CompositeListItem kivy.uix.listview.CompositeListItem
#: import AsyncImage kivy.uix.image.AsyncImage
#: import SelectableView kivy.uix.listview.SelectableView
#: import BoxLayout kivy.uix.boxlayout.BoxLayout
#: import main main
ScreenManagement:
<ScreenManagement>:
SearchForm
ResultPage
<SearchForm>:
name: "search_screen"
search_box:search_box
search_button:search_button
BoxLayout:
orientation: 'vertical'
Label:
text: "FLEA MARKET FLIP"
font_size: 45
pos_hint: {"center_x":0.5, "center_y":1}
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: '100dp'
TextInput:
id: search_box
text: ""
size_hint_x: 0.5
pos_hint: {"center_x":0.5, "center_y":0.5}
Button:
text: "Price It!"
id:search_button
on_release:
root.manager.get_screen("result_page").results_list.adapter.data.clear()
root.manager.get_screen("result_page").results_list.adapter.data.extend([s for s in app.root.ebay(search_box.text)])
root.manager.get_screen("result_page").do_layout()
root.manager.get_screen("result_page").results_list._trigger_reset_populate()
app.root.current = "result_page"
<ResultPage>:
name: "result_page"
orientation: 'vertical'
results_list:results_list
ListView:
padding:(100,110)
id: results_list
adapter: ListAdapter(data=[], cls=main.Ebay_Item, args_converter=root.args_converter, allow_empty_selection=False)
FloatLayout:
Button:
size_hint: [0.2,0.1]
spacing: 50
pos_hint: {"x":0, "y":0}
text: "Back"
on_release:
app.root.current = "search_screen"
<Ebay_Item>:
orientation: "vertical"
cols: 3
#spacing: 60
row_force_default: True
row_default_height: 40
Label:
text: root.results[0]
size: self.texture_size
text_size: self.width, self.height
Label:
text: root.results[1]
size: self.texture_size
AsyncImage:
allow_stretch: True
size_hint_y: None
size_hint_x: None
source: root.results[2]
size: self.texture_size
main.py
from kivy.uix.gridlayout import GridLayout
from kivy.properties import ListProperty
from scripts.ebay import ebay_search
from kivy.uix.listview import SelectableView
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.app import App
class PriceItApp(App):
pass
class ScreenManagement(ScreenManager):
def ebay(self, data):
return ebay_search(data)
class SearchForm(Screen):
pass
class ResultPage(Screen):
def args_converter(self, index, data_item):
title, price, picture = data_item
return {"results": [title, price, picture]}
class Ebay_Item(SelectableView, GridLayout):
results = ListProperty()
if __name__ == "__main__":
PriceItApp().run()

Categories

Resources