kivyMD HotReloadViewer error: NoneType' object has no attribute 'fbind' - kivymd

I am trying to run the kivyMD HotReloadViewer script and when I run this code I get an error message inside the HotReloadViewer widget that says: 'NoneType' object has no attribute 'fbind'. I have researched the error and it is explained that somewhere in the code a variable is not defined or a function is returning None. I am wondering if there is something I am missing here, or advice on debugging where undefined variable or function is located. I am running kivymd-0.104.2.dev0 and have watchdog installed.
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
#:import KivyLexer kivy.extras.highlight.KivyLexer
#:import HotReloadViewer kivymd.utils.hot_reload_viewer.HotReloadViewer
BoxLayout:
CodeInput:
lexer: KivyLexer()
style_name: "native"
on_text: app.update_kv_file(self.text)
size_hint_x: .7
HotReloadViewer:
size_hint_x: .3
path: app.path_to_kv_file
errors: True
errors_text_color: 1, 1, 0, 1
errors_background_color: app.theme_cls.bg_dark
'''
class Example(MDApp):
path_to_kv_file = "kv_file.kv"
def build(self):
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
def update_kv_file(self, text):
with open(self.path_to_kv_file, "w") as kv_file:
kv_file.write(text)
Example().run()

class Example(MDApp):
path_to_kv_file = "kv_file.kv" # path to your KV file

Related

Get the status of a checkbox from a Custom List in Kivy/KivyMD

I'm trying a custom List item based on the KivyMD's documentation examples, but I'm having a problem identifying which of my chechkboxes has been activated.
With * args I can access its state and which object it is but it prints like this:
{<__ main __. RightCheckbox object at 0x000001B1A62E6970>, False}.
The problem is that "0x000001B1A62E6970" is not a constant value (this value may change with the execution of the code) that represents the checkbox as its id does.
My minimal code KV:
KV = '''
MDCard:
orientation : 'vertical'
size_hint : (0.8,0.3)
pos_hint : {"center_x":.5,"center_y":.5}
elevation : 15
padding : 20
spacing : 30
id: box
MDList:
id: scroll
<ListItemWithCheckbox>:
IconLeftWidget:
icon: root.icon
RightCheckbox:
'''
And the MainApp and Custom Class definitions:
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivymd.app import MDApp
from kivymd.uix.list import IRightBodyTouch, OneLineAvatarIconListItem
from kivymd.uix.selectioncontrol import MDCheckbox
from kivymd.icon_definitions import md_icons
class ListItemWithCheckbox(OneLineAvatarIconListItem):
'''Custom list item.'''
icon = StringProperty("android")
def on_press(self):
print(self.text)
class RightCheckbox(IRightBodyTouch, MDCheckbox):
'''Custom right container.'''
def on_active(self, *args):
print(args)
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
icons = list(md_icons.keys())
for i in range(5):
self.root.ids.scroll.add_widget(
ListItemWithCheckbox(text=f"Item {i}", icon=icons[i])
)
MainApp().run()
What I have tried:
I have tried to give a default id for the RightCheckbox to later change it to a unique one when putting the widgets in the list and thus access their states in something like "root.ids.checkboxid" but I don't know how to put it when doing self.root.ids.scroll.add_widget (ListItemWithCheckbox (text = f "Item {i}", icon = icons [i]))
Also in the on_active method (when any checkbox is selected) of the RightCheckbox class I have tried to print various attributes such as MDCheckBox.active .icon .ids. .text but none of them prints anything to help me identify which specific checkbox has been selected
I would really appreciate if anyone can help Thanks
One way to do this is to create a reference to the ListItemWithCheckbox within the RightCheckbox like this:
<ListItemWithCheckbox>:
IconLeftWidget:
icon: root.icon
RightCheckbox:
listItem: root
Then your on_active() method can use that reference:
class RightCheckbox(IRightBodyTouch, MDCheckbox):
'''Custom right container.'''
def on_active(self, rcb, value):
print(rcb.listItem.text, 'is', value)

How to dynamically update label texts in kivy that is imported from excel file?

I am creating a questionnaire form in kivy. I have added few label widgets in my GUI. I don't want to define label texts statically in my code, instead my objective is to dynamically update label texts that is fetched from an excel file.
For example: my excel file has 2 questions:
Name of the company?
Department?
I have 2 label widgets in my GUI, and the text of widgets should be:
Name of the company?
Department?
respectively and has to be dynamically fetched from the excel file.
I encountered an error when i tried to run my code.
Questionnaire.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
import pandas as pd
class FetchData():
file = pd.read_excel("Questionnaire.xlsx")
Quest = file['QUESTIONS']
class Questions(Widget):
Data = FetchData().Quest
qvars =[]
company = ObjectProperty(None)
department = ObjectProperty(None)
qvars.append(company)
qvars.append(department)
def validate(self):
for i in range(len(self.qvars)):
self.qvars[i].text = self.Data[i]
class QuestionnaireApp(App):
def build(self):
return Questions()
if __name__=="__main__":
QuestionnaireApp().run()
Questionnaire.kv
<Questions>:
company:company
department:department
GridLayout:
cols:1
size:root.width, root.height
GridLayout:
cols:1
Label:
id:company
TextInput:
Label:
id:department
TextInput:
Button:
text:"process"
on_release: root.validate()
I am getting the following error:
File "C:/Users/pavan m sunder/virtual environments/android/Questionnaire.py", line 23, in validate
self.qvars[i].text = self.Data[i]
AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'text'
I referred to similar questions that had the same error but none matches specifically to my problem.
Using your qvars list messes things up because it's a list of the property objects, which doesn't have the right behaviour - Kivy Properties are descriptors, they only work at class level.
Instead, just access self.company or self.department in your methods.

Is it possible to schedule Kivy StringProperty set() method using Clock?

I would like to delay Kivy screen manager transition, which I can do for example like this:
#!/usr/bin/env python
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
from kivy.uix.button import Button
from kivy.clock import Clock
Builder.load_string('''
#: kivy 1.9.2
#: import sm kivy.uix.screenmanager
#: set base_font_size 25
<MainWidget>:
manager: screen_manager
ScreenManager:
id: screen_manager
transition: sm.NoTransition()
Screen:
name: 'screen_one'
Button:
text: 'Screen 1, press to switch to Screen 2'
font_size: base_font_size
on_press:
root.manager.current = 'screen_two'
root.statusmsg = 'Screen 2, press to launch Armageddon'
Screen:
name: 'screen_two'
Button:
text: root.statusmsg
font_size: base_font_size
disabled: True if root.statusmsg == 'Busy launching Armageddon' else False # prevent multiple activation
on_press:
root.deliver_payload()
''')
class MainWidget(FloatLayout):
statusmsg = StringProperty()
def __init__(self, **kwargs):
super(MainWidget, self).__init__(**kwargs)
def deliver_payload(self, dt=0):
if not dt: # called via on_press
self.statusmsg = 'Busy launching Armageddon'
# launch Armageddon here
Clock.schedule_once(self.deliver_payload, 2)
else: # scheduled via Clock
self.manager.current = 'screen_one'
class MyApp(App):
def build(self):
mw=MainWidget()
return mw
if __name__ == '__main__':
MyApp().run()
However, manager.current is a Kivy StringProperty and I should be able to assign a new value to it with the set() method and perhaps schedule this with Clock e.g. Clock.schedule_once(lambda dt: self.manager.property('current').set(??, 'screen_one'), 2).
I wasn't able to find documentation for Kivy StringProperty set() method. It seems the method takes two args and the first argument needs to be of type kivy._event.EventDispatcher - according to traceback info that I get when I try some random guesses. Can anyone point to some documentation, or examples of use for the set() method?
EDIT: I realise I did not make it clear what I want to do ultimately - I am asking if it is possible to schedule the Kivy property set() method using Kivy Clock. For example, I am able to toggle a Kivy BooleanProperty like this:
if self.property('myboolean').get(self):
self.property('myboolean').set(self, False)
else:
self.property('myboolean').set(self, True)
But I was not able to schedule the method using Clock. The following line generated no errors but did not have any effect either:
Clock.schedule_once(lambda dt: self.property('myboolean').set(self, False),0)
In the case of Kivy StringProperty set() method, I was not even able to figure out what the 1st argument needed to be, so did not get as far as trying to schedule it with Clock.
FURTHER EDIT:
Although screen manager 'current' is a StringProperty according to documentation, it appears to behave somewhat differently. With a StringProperty I am able to do the following:
self.property('statusmsg').set(self, 'Armageddon now')
However, attempting something like this with manager.current does not succeed:
self.manager.property('current').set(self.manager, 'aux_screen')
The error message is:
self.manager.property('current').set(self.manager, 'screen_one')
TypeError: Argument 'obj' has incorrect type (expected kivy._event.EventDispatcher, got kivy.weakproxy.WeakProxy)
Confusing.
I stumbled across this by chance Kivy: Changing screens in screen manager with an on_press event (thank you, Tshirtman) and I now have one answer. The following change gives me what I want - the ability to schedule screen change directly (i.e. without an intermediate method to call):
def deliver_payload(self):
self.statusmsg = 'Busy launching Armageddon'
Clock.schedule_once(lambda dt: self.manager.setter('current')(self.manager,'screen_one'), 2)
So it appears that for assigning a new value to screen manager's 'current' property, the correct method to use is the 'setter' method (not the 'set' method that I was attempting to use).
You can set a new value for a StringProperty by simply doing a self.manager.current = 'some string', as you do in your code.

pyinstaller and loading pickle file

Has anyone worked with pyinstaller to create windows executables from python scripts? I'm trying to create an executable that loads a pickle file but not successful.
import pickle
filename='test.sav'
try:
model = pickle.load(open(filename, 'rb'))
print('model loaded')
except:
print('An error occurred.')
When run with python 3, it works and loads the model correctly but when run with the executable created by pyinstaller, it will through an exception. Help appreciated.
Im using kivy with pickle and it works correctly.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
import pickle
FRAMES_PER_SECOND = 60.0
Config.set('graphics','multisamples',2)
a = []
class Display(BoxLayout):
def save(self,text):
with open('db.prz','wb') as file:
pickle.dump(text,file)
def loads(self):
with open('db.prz','rb') as file:
a = pickle.load(file)
print(a)
class TestApp(App):
def build(self):
a = Display()
return a
if __name__ == '__main__':
TestApp().run()
kv file:
<Display>:
BoxLayout:
orientation: 'vertical'
TextInput:
id: kvtext
size_hint_y : 0.2
BoxLayout:
orientation : 'horizontal'
Button:
text: 'Save'
on_press: root.save(kvtext.text)
Button:
text: 'Load'
on_press: root.loads()
Spec File Changes:
# -*- mode: python ; coding: utf-8 -*-
from kivy_deps import sdl2, glew
a = Analysis(
datas=[('C:\\Users\\mnt\\Documents\\build_test\\test.kv','.')],
coll = COLLECT(
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
Note that im not adding my file 'db.prze' to data in Analysis()
I also installed pyi from github not from pip.
If you are loading class object, import its class from file.

How to read a Kivy.properties.NumericProperty value in my code at a specific point

So basically I have a kivy project in which,I have a layout that I use in many classes,as such..I have made in custom and put it in a separate file so I can just reference it from different parts of my code.
Snippet:
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string('''
<CustLayout>:
#code here
''')
class CustLayout(BoxLayout):
t_length = NumericProperty(0)
my_len = 0
print(my_len)
def __init__(self, **kwargs):
super(Silvertable,self).__init__(**kwargs)
self.bind(t_length=self.on_t_length)
#This statement is executed after all other prints
print(self.t_length)
def on_t_length(self,instance,length):
#I'd like to get kv file value before the next line
self.my_len = length
print(my_len)
My kiv file:
#:import Silvertable silvertables.Silvertable
#chunk of code
BoxLayout:
Silvertable:
t_length: 5
Here,I DO get the value but unfortunately too late.That is,I get the value after the program has finished.my_len Doesn't change it's still 0
Bind Kivy Properties
The value of my_len is 0 (zero) because the print() functions were executed first before the run() method.
The value of my_len did change from 0 to 5 as per binding on property of t_length.
Please refer to the example and trace for details.
Example
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty
from kivy.lang import Builder
Builder.load_string('''
<CustLayout>:
t_length: 5
''')
class CustLayout(BoxLayout):
t_length = NumericProperty(0)
my_len = 0
print("\tCustLayout.class level-start: my_len=", my_len)
def __init__(self, **kwargs):
super(CustLayout,self).__init__(**kwargs)
print("\nCustLayout.__init__:")
self.bind(t_length=self.on_t_length)
#This statement is executed after all other prints
print("\tself.t_length=", self.t_length)
print("\tself.my_len=", self.my_len)
def on_t_length(self, instance, length):
print("\nCustLayout.on_t_length:")
#I'd like to get kv file value before the next line
self.my_len = length
print("\tself.my_len=", self.my_len)
print("\tCustLayout.class level-end: my_len=", my_len)
class TestBindProperty(App):
def build(self):
print("\nTestBindProperty.build:")
return CustLayout()
def on_stop(self):
print("\tTestBindProperty.on_stop: my_len=", self.root.my_len)
if __name__ == "__main__":
TestBindProperty().run()
Output

Resources