Why app code does not recognize design code? - kivy

I'm fairly new into programming so this may be lousy question.
I'm watching tutorials of kivy programming (https://youtu.be/k4QCoS-hj-s?list=PLCC34OHNcOtpz7PJQ7Tv7hqFBP_xDDjqg) and I'm stuck at design language code.
Basically, I'm trying to write a design language code (my.kv) for an app enter code here(design.py) which should be connected with this lines in design.py, because of "My" in class:
class MyApp(App):
def build(self):
return MyGridLayout()
Also, line in design.py:
class MyGridLayout(Widget):
is connected to first line in my.kv:
<MyGridLayout>
However, it seems design.py does not recognize it, even though they are saved in the same folder.
I was thinking problem may be in different operating systems (Linux-Windows) because of types of brackets, but I don't know what is the Windows parallel to Linux angle brackets.
Any thoughts?
EDIT
I tried what #NameKhan72 proposed:
from kivy.lang import Builder
class MyApp(App):
def build(self):
kv = Builder.load_file('my.kv')
return MyGridLayout()
but still getting error - "no such file or directory: "my.kv"".
EDIT2
I found the mistake. Of course, it was connected to my experience in programming. I didn't put ":" at the end of "". Now there is no error but after opening app I get a black screen.
I tried everything I found on the web but nothing so far.
This is code:
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.widget import Widget
from kivy.properties import ObjectProperty
class MyGridLayout(Widget):
name = ObjectProperty(None)
pizza = ObjectProperty(None)
color = ObjectProperty(None)
def press(self):
name = self.name.text
pizza = self.pizza.text
color = self.color.text
print("Hello " + name + ", you like " + pizza + "pizza, and your favorite color is " + color + ".")
self.name.text =""
self.pizza.text =""
self.color.text =""
class MyApp(App):
def build(self):
return MyGridLayout()
if __name__ == "__main__":
MyApp().run()
This is design code in my.kv:
<MyGridLayout>:
name:name
pizza:pizza
color:color
GridLayout:
cols:1
size: root.width, root.height
GridLayout:
cols:2
Label:
text: "Name"
TextInput:
id: name
multiline:False
Label:
text: "Favorite pizza"
TextInput:
id: pizza
multiline:False
Label:
text: "Favorite color"
TextInput:
id: color
multiline:False
Button:
text: "Submit"
font_size: 32
on_press: root.press()
Is it typo or what? I rewrited the whole code 2x to be sure but still getting black screen.

You need to load the kv-file into python:
from kivy.lang import Builder
class MyApp(App):
def build(self):
kv = Builder.load_file('my.kv')
return MyGridLayout()

The answer my friend is blowing in the wind.
Nope, my problem was saving in wrong file extension. While saving, I writed my.kv but my PC saved it as my.kv.py. That was the reason why code didn't recognize design code.
Thanks for help, surely it'll help me in the future :)

you should use Builder.load_file("filename.kv") or `Builder.load_string(""
""")but to import it usefrom kivy.lang import Builder`

Related

KivyMD RecycleView has low FPS & lags

I am using Python 3.8.12, Kivy 2.0.0 & KivyMD-0.104.2
I am running my app on PyCharm on Ubuntu 18.04 LTS on a ASUS ROG STRIX GL503VD.
My issue is that every time i use a for loop to generate content in KivyMD BottomNavgation using RecycleView, no matter what content (might be even a for i in range(100)), the app is starting to move very slow (when manually resizing it takes around 10 seconds to resize correctly). Also i have FPS under 50 on the tab in which i generated the data while in the empty ones i get #80 FPS.
The issue doesn't seem to happen when i run lets say for i in range(100) in Kivy 2.0.0, but i would prefer to stick to KivyMD.
I've been looking in the last week on the internet for solutions but no luck and is a bit hard to understand kivy documentation regarding RecycleView.
Below is my code, please correct me if i did something out of "good practice". I just started to learn Kivy and i'm a beginner in Python (#1 year).
Thank you very much.
EDIT: Also when deployed to Android it works below 30 FPS on a Xiaomi Redmi Note8 Pro.
main.py
from kivy.lang import Builder
from kivymd.app import MDApp as md
from kivymd.uix.list import TwoLineListItem
import json as js
#from kivy.utils import platform
from kivy.core.window import Window
'''
if platform == "android":
try:
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE])
except:
pass
'''
class MainApp(md):
def build(self):
Window.size = (491, 1064)
self.theme_cls.primary_palette = 'Red'
self.theme_cls.primary_hue = '50'
layouts = Builder.load_file("layouts.kv")
return layouts
def on_start(self):
for key, value in self.read_list().items():
self.root.ids.container1.add_widget(TwoLineListItem(text=f"{key}", secondary_text="Tests : {}".format(len(value))))
self.fps_monitor_start()
def read_list(self):
with open('tests.json', 'r') as read_test:
#82 lines in test_list dict
test_list = js.load(read_test)
return test_list
if __name__ == '__main__':
MainApp().run()
layouts.kv
<MainLayout>
#:import get_color_from_hex kivy.utils.get_color_from_hex
MDGridLayout:
cols: 3
size_hint: 1, 1
MDBottomNavigation:
panel_color: get_color_from_hex("#008080")
text_color_active: get_color_from_hex("#FFFFFF")
MDBottomNavigationItem:
name: 'Item1'
text: 'item_1'
icon: 'language-python'
MDGridLayout:
cols: 1
RecycleView:
MDList:
id: container1
MDBottomNavigationItem:
name: 'Item2'
text: 'item_2'
icon: 'language-cpp'
MDBoxLayout:
RecycleView:
MDList:
id: container2
MDBottomNavigationItem:
name: 'Item3'
text: 'item_3'
icon: 'language-javascript'
MDBoxLayout:
RecycleView:
MDList:
id: container3
You are not actually using the RecycleView. To use a RecycleView, you must have a RecycleLayout as its child, a viewclass, and a data list that indicates the items in the RecycleLayout.
Here is one way to use the RecycleView in your App. First, modify the kv to indicate the RecycleLayout and the viewclass:
MDGridLayout:
cols: 3
size_hint: 1, 1
MDBottomNavigation:
panel_color: get_color_from_hex("#008080")
text_color_active: get_color_from_hex("#FFFFFF")
MDBottomNavigationItem:
name: 'Item1'
text: 'item_1'
icon: 'language-python'
MDGridLayout:
cols: 1
RecycleView:
id: container1
viewclass: 'TwoLineListItem'
RecycleBoxLayout:
default_size: None, dp(75)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
The above moves the container1 id to the RecycleView and adds the needed properties to allow the RecycleView to operate.
Then the on_start() method can be modified to create the data list for the RecycleView:
def on_start(self):
data = []
for key, value in self.read_list().items():
data.append({'text': f"{key}", 'secondary_text': "Tests : {}".format(len(value))})
self.root.ids.container1.data = data
self.fps_monitor_start()

Invalid data after declaration Kivy Tutorial #5 - Object Properties and .kv Continued

I am brand new to coding and am working my way thru the tech with tim kivy youtube turtorials. I am following his code for the most part but am trying to tailor it to the app I'm trying to develop. I am getting the following error message and have no idea how to fix it.
line 3:
...
1:<MyGrid>
2:
>> 3: FirstName: FirstName
4: LastName: LastName
5: Email: Email
...
Invalid data after declaration
Process finished with exit code 1
This is the code I'm entering. I have no idea how to even look for the problem.
Any advise on debugging or learning is greatly appreciated!
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.bubble import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
class MyGrid(Widget):
FirstName = ObjectProperty(None)
LastName = ObjectProperty(None)
Email = ObjectProperty(None)
Address = ObjectProperty(None)
Bankname = ObjectProperty(None)
AccountNumber = ObjectProperty(None)
RoutingNumber = ObjectProperty(None)
class MyApp(App):
def build(self):
return MyGrid()
if __name__ == "__main__":
MyApp().run()
Make your property names begin with a lowercase letter, and make sure your widget classes begin with an uppercase letter. Kv language uses this to distinguish between them, and by not following that rule you have it looking for a widget named FirstName.

kivy: have tcp event open popup

I'm new to kivy, so apologies if I've missed something really basic here but I am struggling to understand both the behavior I'm getting as well as my inability to get the outcome I'm after.
The goal
The kivy app should be listening for TCP events from an external server, with certain triggers causing various stuffs in the kivy app. In this case, I want the external server to be able to open a popup in the app.
Illustrative Code
I have adopted the following (working) demo code from another SO answer that I can no longer seem to find, so apologies for the plagiarism but it is not intentional.
server.py
import socket
serversocket = socket.socket()
host = 'localhost'
port = 54545
serversocket.bind(('', port))
serversocket.listen(1)
clientsocket,addr = serversocket.accept()
print("got a connection from %s" % str(addr))
while True:
msg = input("> ")
clientsocket.send(msg.encode('utf-8'))
client.py
import socket
class MySocket:
def __init__(self,host="localhost",port=54545):
self.sock = socket.socket()
self.sock.connect((host, port))
def get_data(self):
return self.sock.recv(1024)
main.py
import kivy
from kivy.app import App
from kivy.event import EventDispatcher
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from threading import Thread
from client import *
kivy.require('1.9.1')
class MyEventDispatcher(EventDispatcher):
def __init__(self, **kwargs):
self.register_event_type('on_test')
super(MyEventDispatcher, self).__init__(**kwargs)
def do_something(self, value):
self.dispatch('on_test', value)
def on_test(self, *args):
print('I am dispatched', args)
CustomPopup().open()
class CustomPopup(Popup):
pass
class MainScreen(Label):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.sock = MySocket()
Thread(target=self.get_data).start()
def get_data(self):
while True:
self.text = self.sock.get_data().decode('utf-8').strip()
if self.text == 'click':
MyEventDispatcher().do_something(self.text)
class MyApp(App):
def build(self):
return MainScreen()
if __name__ == "__main__":
MyApp().run()
my.kv
<MainScreen>:
Button:
text: 'I do nothing'
<CustomPopup>:
title: 'Popup window'
size_hint: .5, .5
auto_dismiss: False
GridLayout:
cols: 1
Label:
size_hint: .9, .9
halign: 'center'
valign: 'middle'
text: 'message text goes here'
text_size: self.width, None
Button:
text: 'A: Close'
on_release: root.dismiss()
Button:
text: 'B: Close'
on_release: root.dismiss()
This all works in that I can send the trigger word click from the server and the popup will open, it has multiple placeholder buttons that work. Hooray.
The problem, however, is that I seem to require the dummy button on the main app screen, which I do not want. If I simply eliminate the <MainScreen> bit from the .kv file, sending the click keyword leads to:
I am dispatched ('click',)
Segmentation fault (core dumped)
but I can send any other string and it will display on screen as expected.
So, the basic questions are:
How do I get this to work as desired and
Why does placing a non-functional button on the screen make the popup work?
Thanks!

remove_widget kivy do not remove by name

I have this code, and I can’t remove the widget when I use the name of this widget: MainApp(). m.remove_widget (Butt()).
I understand that I am accessing this widget incorrectly, but I do not understand how to do it correctly.
Tell me how to remove a widget using its name?
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.colorpicker import ColorPicker
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
class Butt(Button):
def add_wid1(self):
MainApp.m.add_widget(Box())
MainApp.m.add_widget(Butt1())
class Butt1(Button):
def on_press(self):
print('111')
MainApp().m.remove_widget(MainApp().m.children[1]) #this code works
MainApp().m.remove_widget(Butt()) #this code not working
class Box (ColorPicker):
size_hint=.50, .25
class Pict (Widget):
pass
class MainApp (App):
m = FloatLayout()
def build (self):
pic = Pict()
MainApp.m.add_widget(pic)
MainApp.m.add_widget(Butt())
return MainApp.m
if __name__ == '__main__':
MainApp().run()
You must use the instance of the Butt that you want to remove. An easy way to do it is to save a reference to that Butt in your build method:
self.butt = Butt()
MainApp.m.add_widget(self.butt)
and then remove it with:
app = App.get_running_app()
MainApp.m.remove_widget(app.butt)

Accessing id/widget of different class from a kivy file (.kv) using Kivy's clock?

I've spent the day working with the code from How to access id/widget of different class from a kivy file (.kv)? I've paired it down to the simplest code I could because what I want to do is use Kivy's Clock function to change the text for me instead of clicking the button.
As best as I can understand the code that changes the text should go on Line 38 of the program but all the code I tried stopped executing because it could not access the text to change it. The clock function is working in the code provided.
I've left the button press active but it's the Clock code that I want to change the text. I was wondering if someone knows the solution.
Thanks in advance.
....brad....
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.properties import ObjectProperty
Builder.load_string("""
<SingleScreen>:
id: single_screen
orientation: 'vertical'
Button:
text: "You Can Change Me By Button Press Here But I Really Want To Be Changed By Kivy's Clock Function"
on_release: root.rooted()
Change_Label:
id: gb
<Change_Label>:
_python_access: ChangeLabel
Label:
id: ChangeLabel
text: "I'm Gonna Change."
""")
class SingleScreen(BoxLayout):
def rooted(self):
self.ids.gb._python_access.text = "I Changed It By Clicking!. But That's Not What I Wanted To Program!"
class Change_Label(BoxLayout):
_python_access = ObjectProperty(None)
class OnlyScreen(App):
def build(self):
Clock.schedule_interval(self.Callback_Clock, 3)
return SingleScreen()
def Callback_Clock(self, dt):
print "Hello, world! I'm the clock working...."
# What code goes here that will change the text via Kivy's clock instead of using the button?
if __name__ == '__main__':
OnlyScreen().run()
Please do the following and refer to my example for details:
Snippet
class OnlyScreenApp(App):
def build(self):
Clock.schedule_interval(self.Callback_Clock, 3)
return SingleScreen()
def Callback_Clock(self, dt):
self.root.ids.gb._python_access.text = "I Changed It By Clock! dt=" + str(dt)
Example
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.properties import ObjectProperty
class SingleScreen(BoxLayout):
pass
class Change_Label(BoxLayout):
_python_access = ObjectProperty(None)
class TestApp(App):
def build(self):
Clock.schedule_interval(self.Callback_Clock, 3)
return SingleScreen()
def Callback_Clock(self, dt):
self.root.ids.gb._python_access.text = "I Changed It By Clock! dt=" + str(dt)
if __name__ == '__main__':
TestApp().run()
test.kv
#:kivy 1.10.0
<SingleScreen>:
id: single_screen
orientation: 'vertical'
Change_Label:
id: gb
<Change_Label>:
_python_access: ChangeLabel
Label:
id: ChangeLabel
text: "I'm Gonna Change."
Output
Based on ikolim's answer above I wanted to post the solution as one complete python program that relates to the format from which the question was posted. Really appreciate the solution. The complete working (one file) code would be as follows;
import kivy
kivy.require('1.9.1')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
from kivy.properties import ObjectProperty
Builder.load_string("""
<SingleScreen>:
id: single_screen
orientation: 'vertical'
Change_Label:
id: gb
<Change_Label>:
_python_access: ChangeLabel
Label:
id: ChangeLabel
text: "I'm Gonna Change."
""")
class SingleScreen(BoxLayout):
pass
class Change_Label(BoxLayout):
_python_access = ObjectProperty(None)
class OneScreen(App):
def build(self):
Clock.schedule_interval(self.Callback_Clock, 3)
return SingleScreen()
def Callback_Clock(self, dt):
self.root.ids.gb._python_access.text = "I Changed It By Clock! dt=" + str(dt)
if __name__ == '__main__':
OneScreen().run()

Resources