i have been trying to save the state of my application using python pickle module without success. my application works fine on mobile but whenever i close it, it loses all data. i want this application to be like a table notepad so that i can resume from where i left after closing the app. here is a part of my code to explain the problem.
example.py
import pickle
class MyGrid(BoxLayout):
pass
if os.path.isfile("notepad"):
load = pickle.load(open("notepad", "rb"))
print(load)
textinput = StringProperty(load)
else:
textinput = StringProperty()
class Goat(App):
def build(self):
return MyGrid()
def save(self):
rectangle1 = [self.root.ids.a2.text, self.root.ids.a2.text]
pickle.dump(rectangle1, open("notepad", "wb"))
if __name__ == "__main__":
Goat().run()
here is my .kv file
<MyGrid>:
orientation: 'vertical'
ScrollView:
bar_width: 10
GridLayout:
id:gridlayout
cols :3
row_default_height: 90
height: self.minimum_height
size: 600, 500
padding: 5
pos: 0, -200
size_hint_y: None
##############################################box1
Label:
text : "A"
background_color: (1, 5, 0, 1)
font_size: 30
TextInput:
id : a1
multiline : False
font_size: 30
TextInput:
id : a2
multiline : False
font_size: 30
Button:
text: 'SUBMIT'
id : submit1
background_color: (1, 0, 0, 1)
on_release: app.save()
font_size: 39
when i type on the input field and press submit, a notepad.dat file is formed on the directory and the contents typed on the input field are saved.( i know this by print(load) on my .py file)
my problem is bringing the contents of the dart file on the gui and making them stay there. i dont know how to do that. please help!
You need to load the pickled data after the App starts so that you can assign the pickled data to the widgets. Like this:
class Goat(App):
def on_start(self):
if os.path.isfile("notepad"):
load = pickle.load(open("notepad", "rb"))
self.root.ids.a1.text = load[0]
self.root.ids.a2.text = load[1]
Related
I want to keep the value returned from 2 time.time () methods in the on_event and on_leave functions in the ReflexScreen class. I want to use these values in the MainScreen class, but when I call these functions in the MainScreen class, these functions are called again and they do not keep the current value. So it returns me a new value and the value of both is the same because I called both at the same time.
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
from kivymd.app import MDApp
from time import sleep, time
from random import randint
from kivymd.uix.label import MDLabel
Window.size = (300, 500)
helper = """
ScreenManager:
MenuScreen:
ReflexScreen:
MainScreen:
<MainScreen>:
id: main
name: 'main'
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Test Your Reflex'
elevation:10
Widget:
MDRectangleFlatButton:
text: 'P L A Y'
on_press: root.manager.current = 'menu'
size_hint_x: None
size_hint_y: None
width: 20
height: 30
pos_hint: {'center_x':0.5, 'center_y':0.5}
md_bg_color: 0.2,0.3,0.6,0.1
text_color: 0.2, 0.5, 0.6, 1
MDLabel:
id: score_label
size_hint_x: 0.45
size_hint_y: None
pos_hint: {'center_x':0.5, 'center_y':0.4}
<ReflexScreen>:
id: reflex
name: 'reflex'
Button:
id: reflex_button
text: 'Wait Change The Color'
font_size: '20sp'
pos_hint: {'center_x':0.5, 'center_y':0.5}
on_press: root.manager.current = 'main'
size_hint_x: None
size_hint_y: None
width: 300
height: 500
background_color: 1,0,0,0.8
<MenuScreen>
id: menu
name: 'menu'
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Test Your Reflex'
elevation:10
Widget:
MDRectangleFlatButton:
text: 'P L A Y'
on_press: root.manager.current = 'reflex'
size_hint_x: None
size_hint_y: None
width: 20
height: 30
pos_hint: {'center_x':0.5, 'center_y':0.5}
md_bg_color: 0.2,0.3,0.6,0.1
text_color: 0.2, 0.5, 0.6, 1
"""
class ReflexScreen(Screen):
def on_enter(self, *args):
"""Event fired when the screen is displayed: the entering animation is
complete."""
sleep(randint(1,6))
self.ids.reflex_button.background_color = (0,1,0,0.8)
start = time()
print(start)
self.ids.reflex_button.text = 'CLICK !!!'
return start
def on_leave(self, *args):
end = time()
print(end)
self.ids.reflex_button.background_color = (1,0,0,0.8)
return end
"""rscreen = ReflexScreen()
start = rscreen.on_enter()
end = rscreen.on_leave()"""
class MainScreen(Screen):
def on_enter(self, *args):
rscreen = ReflexScreen()
start = rscreen.on_enter()
end = rscreen.on_leave()
#reflexclass = ReflexScreen()
#final_time = reflexclass.on_leave()-reflexclass.on_enter()
#print(final_time)
final_time = (end-start)
self.ids.score_label.text = f"TIME : {str(final_time)}"
If I add the code block below between two classes and use these variables in the MainScreen class,
rscreen = ReflexScreen()
start = rscreen.on_enter()
end = rscreen.on_leave()
I can get the result I want, but if I do this, kivy will tell me self.ids.reflex_button.background_color = (0,1,0,0.8) File "kivy \ properties.pyx", line 863, in kivy.properties.ObservableDict .__ getattr__ AttributeError: 'super' object has no attribute returns '__getattr__' error.
I think the reason for this is because of this. When the window is first loaded, the name value defined in the helper is not assigned, that name value is defined for the class when the window is opened for the second time. By doing a print (self), I see that the name value returns empty the first time and full the second time. How can I solve this problem or get the time difference between clicks?
The on_enter() and on_leave() methods are called for you. You do not need to explicitly call them yourself. You also do not need to do:
rscreen = ReflexScreen()
The ReflexScreen in your GUI is created when you load your helper string. and rscreen above is not the instance that appears in your GUI.
You can get the time difference by saving the start and end time in the ReflexScreen class, and adding a method to get the time difference:
class ReflexScreen(Screen):
start = NumericProperty()
end = NumericProperty()
def on_enter(self, *args):
"""Event fired when the screen is displayed: the entering animation is
complete."""
sleep(randint(1,6))
self.ids.reflex_button.background_color = (0,1,0,0.8)
self.start = time()
print(self.start)
self.ids.reflex_button.text = 'CLICK !!!'
# return start
def on_leave(self, *args):
self.end = time()
print(self.end)
self.ids.reflex_button.background_color = (1,0,0,0.8)
# set the text of a Label in MainScreen to show time difference
self.manager.get_screen('main').ids.score_label.text = str(self.end - self.start)
# return end
# a method to get the time difference
def get_time_diff(self):
return self.end - self.start
Haven't tested this code, so there may be some errors.
I'm not that new to Python so I have a basic understanding but I wouldn't say that I'm all that great either.
I've been having a tonne of problems with a brazilian jiujitsu app that I'm trying to make in Kivy. I am trying to get the text from a button that has been pressed in one window, and then use that text in a label for the next window that shows. The former window I have given the class name GuardWindow() and the latter window is called SweepSubTranPage().
I have managed to send the name of the button from my kivy file to the class GuardsWindow() easily enough, and the line self.guardlabel = instance.text works fine and retrieves the button name perfectly. My main problem however is sending that name over to the SweepSubTranPage() so that i can access it in my kivy file.
Here is the Python code:
class GuardsWindow(Screen):
guardButtonName = ObjectProperty(None)
def send_guard_type(self, instance, **kwargs):
self.guardButtonName = instance.text # retrieves the button name
def sender(self): # my attempt at sending it to the other class
return self.guardButtonName
class SweepSubTranPage(Screen):
pageTitle = ObjectProperty(None)
gw = GuardsWindow()
pageTitle.text = gw.sender()
kv = Builder.load_file("my.kv")
class MyMainApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyMainApp().run()
And here is the Kivy file code:
<GuardsWindow>
name: "GuardsHomepage"
ScrollView:
bar_width: 10
do_scroll_x: False
do_scroll_y: True
scroll_type: ["bars", "content"]
BoxLayout:
orientation: "vertical"
size_hint: 1, 2
padding: 10
spacing: 10
Button: # these are the buttons that i am getting the text from
text: "Full Guard"
on_press:
root.send_guard_type(self) # this sends the button
on_release:
app.root.current = "SweepSubTranPage"
root.manager.transition.direction = "left"
Button:
text: "Half Guard"
on_press:
root.send_guard_type(self) # this sends the button
on_release:
app.root.current = "SweepSubTranPage"
root.manager.transition.direction = "left"
<SweepSubTranPage>
name: "SweepSubTranPage"
pageTitle: title
BoxLayout:
orientation: "horizontal"
size_hint: 1, 0.1
Label: # this is the label that I need the text for
id: title
font_size: 40
size_hint: 1, 1
When I run the code above, I get the error:
File "C:/Users/bensw/PycharmProjects/BJJ Tracker/main.py", line 36, in <module>
class SweepSubTranPage(Screen):
File "C:/Users/bensw/PycharmProjects/BJJ Tracker/main.py", line 40, in SweepSubTranPage
pageTitle.text = gw.sender()
AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'text'
I hope I have been clear enough in explaining my issue. If you have any questions please ask!
Thank you so much!!
In your send_guard_type() method you can access another Screen using the manager property of any Screen, and the get_screen() method of the ScreenManager. Something like this:
def send_guard_type(self, instance, **kwargs):
self.guardButtonName = instance.text # retrieves the button name
self.manager.get_screen("SweepSubTranPage").ids.title.text = instance.text
I want to develop a chatting application for android. It will receive messages from the controller on the site. For this i have started designing a GUI. After practicing and studying a few codes I have been able to design a text box, a button and a label. When button is pressed, text in the text box gets displayed on the label named 'Display' and text box gets cleared. However now i want that with each time button is clicked text should move upwards and it's space should be replaced with the text in the text box. Similarly text from the sender should appear on the right side and text received should be displayed on left side of the screen. It might be a silly question but as i am totally new to python and kivy thing it is getting hard for me after trying it for over a week. Please guide me on this. Below is the code.
This is main.py
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
from kivy.uix.scrollview import ScrollView
class scrollableLabel(FloatLayout):
def display_txt(self):
self.ids.lbl.text = self.ids.txt.text
self.ids.txt.text = ''
class MyApp(App):
def build(self):
return scrollableLabel()
if __name__ == "__main__":
MyApp().run()
This is the kivy file
<scrollableLabel>:
FloatLayout:
cols : 1
rows : 3
Button:
text : 'Send'
size_hint : .2 , .1
pos : 640 , 0
on_press : root.display_txt()
TextInput:
hint_text : 'Write here'
id : txt
size_hint : .8 , .1
pos : 0 ,0
Label :
id : lbl
text : 'Display'
size_hint : .5 , .4
pos : 500 , 100
text_size : self.size
Chat App - Suggestion
Kivy Label » Text alignment and wrapping
Declare a custom widget with inheritance of Label widget so that you can control the text alignment i.e. left for text sent, and right for text received.
Snippets - kv file
<CustomLabel#Label>:
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
halign: 'left'
valign: 'middle'
Kivy RecycleView
Replace Label: with RecycleView:
Use CustomLabel as the viewclass
Append text sent or text received to RecycleView's data
Snippets - kv file
RecycleView:
id: rv
viewclass: 'CustomLabel'
RecycleBoxLayout:
default_size_hint: 1, None
orientation: 'vertical'
Kivy RecycleView » data
The view is generatad by processing the data, essentially a list of
dicts, and uses these dicts to generate instances of the viewclass as
required.
data
The data used by the current view adapter. This is a list of dicts
whose keys map to the corresponding property names of the
viewclass.
data is an AliasProperty that gets and sets the data used to
generate the views.
Snippets - Py file
def display_txt(self):
self.ids.rv.data.append({'text': self.ids.txt.text, 'halign': 'left'})
self.ids.txt.text = ''
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
class SMS(Screen):
def send_txt(self):
self.ids.rv.data.append({'text': self.ids.txt.text, 'halign': 'left'})
self.ids.txt.text = ''
def receive_txt(self):
self.ids.rv.data.append({'text': self.ids.txt.text, 'halign': 'right'})
self.ids.txt.text = ''
Builder.load_file("main.kv")
class MyApp(App):
def build(self):
return SMS()
if __name__ == "__main__":
MyApp().run()
main.kv
<ChatBox#Label>:
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
halign: 'left'
valign: 'middle'
<SMS>:
GridLayout:
cols : 1
BoxLayout:
size_hint: 1, 0.1
Button:
text : 'Send'
on_press : root.send_txt()
Button:
text : 'Receive'
on_press : root.receive_txt()
TextInput:
hint_text : 'Write here'
id : txt
size_hint : .8 , .1
pos : 0 ,0
RecycleView:
id: rv
viewclass: 'ChatBox'
RecycleBoxLayout:
default_size_hint: 1, None
orientation: 'vertical'
Output
I tried to change the appearance a little bit. I wanted send, receive button and textinput at the bottom and label on top of it. And found that text starts to display from some height above the text input box and buttons. I need it to be displayed right above the buttons and text input box immediately. And in my code, text for both send and receive buttons are getting displayed on left hand side. Please tell me why it is so.
Here is the .kv file
:
size_hint_x : None
size_hint_y : None
pos : 0,0
text_size: self.width, None
height: self.texture_size[1]
halign: 'left'
valign: 'middle'
<CustomButton#Button>:
font_size : 25
size_hint : 0.1,0.1
<MyWidget>:
GridLayout:
#size : root.width, root.height
#orientation : 'horizontal'
#pos:100,100
cols:1
row:3
RecycleView:
id: rv
viewclass: 'ChatBox'
RecycleBoxLayout:
default_size_hint: 1, None
orientation: 'vertical'
BoxLayout:
TextInput:
hint_text: 'type here'
id : txt
multiline : True
size_hint : .5,.1
#pos : 0,0
CustomButton:
text: 'Receive'
on_press : root.send_txt()
#pos : 10,0
CustomButton:
text: 'Send'
on_press : root.send_txt()
#pos : 20,0
Apart from that, when screen gets filled with the text and moved upwards completely, all the text disappears and if we again send or receives new text, it doesn't appear on the screen. Sir please tell me how to solve this issue.
Thanking you.
I want to add Buttons (Basicly custom Buttons with Image) as a custom Widgets to "Screen1" but I always end up with "_event.pyx not found" Error.
I've tried with "super().init(**kwargs)" and without.
Python code:
sm = ScreenManager()
class DrinkWidget(Widget):
pass
class HomeScreen(BoxLayout):
def switch(self, to):
#Swithing funktion
#This is the Part, that causes the Problem I think:
class Screen1(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add_widget(DrinkWidget(
lable_text_optn = 'test'
))
class Screen2(Screen):
pass
class ZapfanlageApp(App):
icon = 'GUI_Elemente/app_icon.png'
title = 'Zapfanlage'
def build(self):
pass
if __name__ == "__main__":
ZapfanlageApp().run()
Kivy code (separate .kv File. The part "HomeScreen" works so far):
HomeScreen:
sm: sm
name: 'ScreenManager'
BoxLayout:
orientation: 'vertical'
rows: 2
ActionBar:
pos_hint: {'top': 1}
size_hint_y: .065
ActionView:
ActionButton:
text: 'Cocktails'
on_press:
root.switch(1)
ActionButton:
text: 'Drinks'
on_press:
root.switch(2)
ActionButton:
text: 'Einstellungen'
on_press:
root.switch(3)
ScreenManager:
id: sm
size_hint_y: .935
Screen1:
name: "screen1"
id: screen1
Screen2:
name: "screen2"
id: screen2
<Screen1#Screen>:
name: "screen_1"
id: screen1
#Here should the Buttons in GridLayout appear
<Screen2#Screen>:
name: "screen_2"
id: screen2
#This is the Custom Button I want to be inserted above
<Drink_Widget#Button>:
image_path_optn: image_path
lable_text_optn: lable_text
Button:
size_hint_x: None
size_hint_y: None
height: (root.height) -10
width: 250
on_press:
BoxLayout:
orientation: "vertical"
width: root.width
height: root.height
pos_hint: root.pos
pos: root.pos
padding: 5
Image:
source: image_path
Label:
text: label_text
I want to show a various number of DrinkWidgets on screen1 vertically and add them in runtime. But I always end up with nothing showing up or with _event.pyx not found error. Passing the code under <Screen1#Screen>: directly works.
I hope someone can help me. Thanks a lot!
Okay, it looks like you want to add a number of your DrinkWidgets to your screen when your app loads. First things first, in your .py file you have defined a class named Drink_widget but in .kv you call it DrinkWidget
Next, since you have your DrinkWidget defined as inheriting the Button class from kivy, you can easily change the text in the DrinkWidget using the text: field. Similarly, you can change the image that the button displays to be whatever you like using the background_normal: field. To change the image displayed when you click the button, use the background_down: field. Example:
<DrinkWidget#Button>:
text: "some text"
background_normal: "image1.png"
background_down: "image2.png"
So you don't need your lable_text_optn or image_path_optn fields.
Also, you are trying to add a number of widgets to a Screen widget, when really you should be adding a number of widgets to a Layout widget (FloatLayout, BoxLayout, or GridLayout). Your Screen widget should only have the Layout widget as its direct child.
Another issue I see is you have two root widgets inside your .kv file -- HomeScreen and BoxLayout unless your indentation is correct in the question.
Here is a minimal example of what I believe you are trying to get working:
main.py
from kivy.app import App
from kivy.uix.button import Button
class DrinkWidget(Button):
pass
class MainApp(App):
def on_start(self):
# This command is automatically called when your app loads up
the_screen_grid = self.root.ids.some_descriptive_id
# self.root refers to the root widget, which is the GridLayout
# self.root.ids gets me a DictProperty of all children widgets that have an id associated with them
# self.root.ids.some_descriptive_id gets me the GridLayout widget I defined with the id: some_descriptive_id
for i in range(3):
the_screen_grid.add_widget(DrinkWidget(text="drink " + str(i)))
MainApp().run()
main.kv
GridLayout:
cols: 1
Screen:
# Widgets that aren't Layouts normally only have 1 child widget
# To "add multiple widgets" to a screen, give the screen a Layout, then add widgets to the layout
GridLayout:
id: some_descriptive_id
rows: 1
Your code is a bit too long to give you an exact solution for your case, but I hope this example gives you the knowledge to fix it up for yourself!
I am using pydev on eclipse luna. My kv file is as follows:
<LoginForm>:
userid: userid
password: password
size_hint_x: 0.5
size_hint_y: None
height: 200
orientation: 'vertical'
pos_hint: {'center_x': 0.5,'center_y':0.5}
minimum_height: 100
minimum_width: 100
#User ID
Label:
text: 'User ID'
font_size: 20
size_hint_x: None
TextInput:
id: userid
font_size: 20
#User PW
Label:
text: 'Password'
font_size: 20
TextInput:
id: password
password: True
font_size: 20
Button:
text: 'Login'
My python code is:
from kivy.app import App;
from forms.login import LoginForm;
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
class LoginForm(BoxLayout):
def __init__(self, **kwargs):
super(LoginForm, self).__init__(**kwargs)
class StartApp(App):
def build(self):
Window.size = (480, 800)
return LoginForm()
#return StartApp();
if __name__ == '__main__':
StartApp().run()
Output:
The code is working correctly, however, my issue is that there is still some gap at left which is not present for other controls. I want User ID to be completely left aligned (in the above pic it is left aligned, but some space is still left).
Could you please advice/correct me on where I went wrong?
The Label isn't left-aligned because you haven't actually set that, by disabling the size_hint_x it just takes the default width of 100 pixels and the text appears in its centre.
You have two options for declaring the label.
Label:
text: 'User ID'
font_size: 20
size_hint_x: None
width: self.texture_size[0]
This will set the width of the Label to the exact size of the texture containing the image of the text. However, I think it's probably preferable to do the following:
Label:
text: 'User ID'
font_size: 20
text_size: self.size
halign: 'left'
valign: 'middle'
This way, rather than messing with the widget size/position you set the text_size (this controls the bounding box of the text texture) and the built in text alignment options take care of the rest.
In this case, the results of these should be similar if not identical.