I am currently developing a GUI with python and kivy. My aim is to have a Label/ Widget on a screen, which displays the current time and is updating by itself. Later I want to use that value (time) to then fill in other Input Widgets ('Use current time').
This is the .kv file for the screen, on which I would like to have the time displayed.
For now I added a button which will trigger the function change_time in my main.py and then update the text/ Label using the label id 'current_time'. In the end this should happen automatically, without using the button
<ClockScreen>:
FloatLayout:
#Background color
canvas:
Color:
rgb: utils.get_color_from_hex("#00a7d8")
Rectangle:
size: self.size
pos: self.pos
#Input-Fields and Labels
GridLayout:
cols: 1
pos_hint: {"top": 1, "right": 1}
size_hint: 1, .8
Label:
id: current_time
text: "Current Time"
Button:
on_press:
root.change_time()
[...]
This is the main.py file, where I have the function change_time in my class for the ClockScreen defined.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.uix.button import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.spinner import Spinner
from kivy.properties import ObjectProperty
import requests
import time
[...]
class ClockScreen(Screen):
def change_time(self):
time = time.asctime()
current_time = self.ids.current_time
current_time.text = time
print(current_time.text)
[...]
GUI = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return GUI
def change_screen(self, screen_name):
screen_manager = self.root.ids['screen_manager']
screen_manager.transition = NoTransition()
screen_manager.current = screen_name
MainApp().run() #Um die Mainapp zu starten
If I run this I get the error "UnboundLocalError: local variable 'time' referenced before assignment". When I define the variable time out of the class ClockScreen it works, but then the time is static and just updates once (when I run the App).
How is it possible to have the current time updated automatically and then displayed on my ClockScreen without using a button to call a function? Thanks!
Related
I'm trying to create a simple login page for this app using Kivy.
I'm new to this, and I'm wondering how I can connect the Email TextInput to a variable (email_catch) in my python code, similar to a normal .get() function.
Python Code
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
class Login_Window(Screen):
def verify(self):
email_catch = self.root.ids.email.text
print(email_catch)
class MyApp(App):
def build(self):
return Login_Window()
if __name__ == "__main__":
MyApp().run()
.KV File
#:kivy 2.0.0
<Login_Window>:
GridLayout:
cols:1
size: root.width, root.height
GridLayout:
cols:2
Label:
text: 'Email'
TextInput:
multiline: False
id: email
Button:
text: 'Log In'
on_press: root.verify()
Since you are calling root in verify method of Login_Window class (where it (root) hasn't been defined yet) and not in the build method of the App class you are supposed to get an AttributeError .
In order to access an id within that class you should use self.ids. So the change you need:
def verify(self):
email_catch = self.ids.email.text
print(email_catch)
I'm relatively new to programming, little over 8 months or so, but I am learning kivy and python3 and I am attempting to create a password managing application and I would like for it to open a new screen when a button is pressed. but I am getting a Type Error.
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
from kivy.uix.screenmanager import ScreenManager, Screen
class LoginScreen(Widget):
pass
class PasswordScreen(Widget):
pass
class PasswordApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(LoginScreen(name='login'))
sm.add_widget(PasswordScreen(name='passwords'))
return sm
if __name__ == '__main__':
PasswordApp().run()
heres the .kv code
<LoginScreen>:
GridLayout:
Button:
text: 'Goto passwords'
on_press: root.manager.current = 'passwords'
Button:
text: 'Quit'
<PasswordScreen>:
GridLayout:
Button:
text: 'My settings button'
Button:
text: 'logout'
on_press: root.manager.current = 'login'
Your LoginScreen and PasswordScreen extend Widget, and the Widget __init__() does not support a name property. Both those classes should extend Screen instead of Widget.
As my app has many screens and is almost done building the frontend i dont want to change the screen manager(<root widget>:) and class MainApp(MDApp):. Please help me on how i can add a MDDropdownMenu on pressing package weight button on my home screen without changing the layout of my code. Not only the below mentioned code but i have tried different ways to implement it but faced lots of errors. Please help and Thanks in advance.
MY main.py file
from kivymd.app import MDApp
import json
from datetime import datetime
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
from kivymd.uix.button import MDFlatButton ,MDRectangleFlatIconButton
from kivymd.uix.label import MDLabel, MDIcon
from kivymd.uix.textfield import MDTextField
from kivymd.uix.dialog import MDDialog
from kivymd.uix.list import OneLineListItem
from kivy.core.window import Window
from kivymd.uix.menu import MDDropdownMenu, MDMenuItem
class HomeScreen(Screen):
def drop(self):
self.dropdown= MDDropdownMenu(items= {"viewclass": "MDMenuItem","text":"option1"}, width_mult=4)
self.dropdown.open()
class RootWidget(ScreenManager):
pass
class MainApp(MDApp):
def build(self):
self.theme_cls.primary_palette= "Green"
return RootWidget()
if __name__ == "__main__":
MainApp().run()
My design.kv file
<HomeScreen>:
GridLayout:
cols: 1
padding: 20, 20
spacing: 10,10
size_hint: 1,0.87
MDRectangleFlatIconButton:
icon: 'weight-kilogram'
text: "Package weight"
size_hint: (0.55,1)
on_press: root.drop()
<RootWidget>:
HomeScreen:
name: "home_screen"
This is the image of my app home screen
You need to include the caller in your MDDropdownMenu() call, and the items is expected to be a list of dictionaries.
Try changing your kv to include an id for the MDRectangleFlatIconButton:
<HomeScreen>:
GridLayout:
cols: 1
padding: 20, 20
spacing: 10,10
size_hint: 1,0.87
MDRectangleFlatIconButton:
id: caller # ADDED
icon: 'weight-kilogram'
text: "Package weight"
size_hint: (0.55,1)
on_press: root.drop()
The id is used to identify the caller.
Then create the DropDown in a on_kv_post() method, and the drop() method just opens the DropDown:
class HomeScreen(Screen):
def on_kv_post(self, base_widget):
caller = self.ids.caller
self.dropdown = MDDropdownMenu(caller=caller, items=[{"viewclass": "MDMenuItem", "text": "option1"}], width_mult=4)
def drop(self):
self.dropdown.open()
The on_kv_post() method is executed after the kv rules have been executed, so that the ids are available.
The MDDropdownMenu is not created in the drop() method, as recommended in the documentation.
I'm a beginner with kivy language. I'm writing an app but I have some difficulties. My app is going to consist of a few screens so I decided to use the ScreenManager but each time I'm trying to launch the .py I get an error and this makes the python not responding. I have saved both the .py file and the .kv file in the same folder.
Traceback (most recent call last):
File "C:\Users\Eng. Aladdin Hammodi\Desktop\kivy\main.py", line 15, in <module>
presentation = Builder.load_file(Aladdin.kv)
NameError: name 'Aladdin' is not defined
Python file:
import kivy
kivy.require("1.9.1")
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.lang import Builder
presentation = Builder.load_file(Aladdin.kv)
class ScreenOne(Screen):
pass
class ScreenTwo(Screen):
pass
class ScreenManager(ScreenManager):
pass
class AladdinApp(App):
def build(self):
return presentation
sample_app = AladdinApp()
sample_app.run()
aladdin.kv
<ScreenOne>:
name:screen1
FloatLayout:
canvas:
source:'image1'
Label:
text:'Hello\n Welcome to my app\n'
font_size: 40
Button:
text: 'Next'
pos: 0,1
font_size:20
hint_size:0.1,0.05
on_press:root.manager.current='screen2'
<ScreenTwo>:
name:screen2
FloatLayout:
canvas:
source:'image1'
Label:
text:'Please insert your name'
text:'Please insert your Password'
font_size: 40
Button:
text: 'Next'
pos: 0,1
font_size:20
hint_size:0.1,0.05
on_press:root.manager.current='screen1'
The problem is in the line:
presentation = Builder.load_file(Aladdin.kv)
Aladdin is interpreted as the variable. If you want to pass a string to the method, call it like:
presentation = Builder.load_file("Aladdin.kv")
The files had a couple of issues:
#Artur R. Czechowski already pointed out missing quotation marks Builder.load_file('Aladdin.kv')
you did not define a root widget in the kv file or in your python code. I changed this by returning it in the build method def build(self): return ScreenManager()
it is not hint_size, correct is size_hint
I think you tried having an image as background. This is one way of doing it, do not forget the file ending e.g. .jpg
canvas.before:
Rectangle:
pos:self.pos
size: self.size
source:'image1.jpg'
As a side note: It makes sense to build your app step by step. Write as little code as possible which works and then check. Write some more code, check again. Happy coding with kivy :).
python code:
import kivy
kivy.require("1.9.1")
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
from kivy.uix.button import Button
from kivy.lang import Builder
#### in comment requested to also make cursor visible and not full screen ####
from kivy.config import Config
Config.set('graphics', 'fullscreen', '0')
Config.set('graphics','show_cursor','1')
####
Builder.load_file('Aladdin.kv')
class ScreenOne(Screen):
pass
class ScreenTwo(Screen):
pass
class ScreenManager(ScreenManager):
pass
class AladdinApp(App):
def build(self):
return ScreenManager()
AladdinApp().run()
revised kv file:
<ScreenManager>:
ScreenOne:
ScreenTwo:
<ScreenOne>:
name:'screen1'
FloatLayout:
canvas.before:
Rectangle:
pos:self.pos
size: self.size
source:'image1.jpg'
Label:
text:'Hello\n Welcome to my app\n'
font_size: 40
Button:
text: 'Next'
pos: 0,1
font_size:20
size_hint:0.1,0.05
on_press:root.manager.current='screen2'
<ScreenTwo>:
name:'screen2'
FloatLayout:
canvas.before:
Rectangle:
pos:self.pos
size: self.size
source:'image1.jpg'
Label:
text:'Please insert your name'
#text:'Please insert your Password'
font_size: 40
Button:
text: 'Next'
pos: 0,1
font_size:20
size_hint:0.1,0.05
on_press:root.manager.current='screen1'
as stated in the title - I'm stuck. I've been playing with the code around and everything works as long as I keep ScreenManager and Popup separate. Once combined - they refuse to cooperate. Anyway, here is the simple app that shows the problem I'm having.
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import Screen, ScreenManager
class First(GridLayout,Screen):
def show_popup(self):
Popp().open()
pass
class Second(Screen):
pass
class Popp(Popup):
pass
class ScreenManagement(ScreenManager):
pass
app = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return app
if __name__ == "__main__":
MainApp().run()
And main.kv file
ScreenManagement:
First:
Second:
<First>:
name:"First"
rows: 2
Button:
text: "FirstButton"
on_release: app.root.current = "Second"
Button:
text: "Show popup"
on_release: root.show_popup()
<Second>:
name:"Second"
Button:
text: "BUTTON"
on_release: app.root.current = "First"
<Popp>:
title: "testing"
text: "Hello world"
size_hint: None,None
size: 400,400
auto_dismiss: False
Button:
text: "Okay"
on_press: root.dismiss()
App starts, first and second screen are working but when trying to get popup up I end up with:
kivy.uix.popup.PopupException: Popup can have only one widget as content
Somehow Screen is seen as a widget inside of Popp? Or am I terribly misinterpreting kivy docs?
It's a bug with loading kv file, it should throw an exception in this case.
What you are doing in the code is loading the kv file twice, what causes some weird behavior. Just delete the Builder.load_file(..) and it will work. The file is going to be loaded automatically.
Also, never do double subclassing of widgets like class First(GridLayout, Screen) as it might lead to some problems. Instead, create a grid layout inside the screen.
Put the elements in the Popup inside a layout, for example: Boxlayout.
Here's what I mean:
<Popp>:
title: "testing"
BoxLayout:
orientation: 'vertical'
size_hint: None,None
size: 400,400
Label:
text: "Hello world"
Button:
text: "Okay"
on_press: root.dismiss()
I have same problem with using kivy Builder.load_file and Popup, they dont work together.
the solution is simple, build popup in python code side. this is a loading popup example:
python:
from kivy.app import App
from kivy.uix.popup import Popup
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
import time, threading
buildKV = Builder.load_file("example.kv")
class ExampleApp(App):
def show_popup(self):
content = BoxLayout(orientation= "vertical")
image=Image(source= 'files/loading.gif', anim_delay= 0)
label=Label(text= 'Model is Running.\nBe Patient Please.')
content.add_widget(image)
content.add_widget(label)
self.popup = Popup(title='Model is Running.',
size_hint=(.250, .785),
content=content, auto_dismiss=False)
self.popup.open()
def process_button_click(self):
# Open the pop up
self.show_popup()
# Call some method that may take a while to run.
# I'm using a thread to simulate this
mythread = threading.Thread(target=self.something_that_takes_5_seconds_to_run)
mythread.start()
def something_that_takes_5_seconds_to_run(self):
thistime = time.time()
while thistime + 10 > time.time(): # 5 seconds
time.sleep(1)
# Once the long running task is done, close the pop up.
self.pop_up.dismiss()
if __name__ == "__main__":
ExampleApp().run()
kivy:
BoxLayout:
Button:
height: 40
width: 100
size_hint: (None, None)
text: 'Click Me'
on_press: app.process_button_click()