I have several screens run by ScreenManager, and on one I have an image that is loaded with an image taken from a URL (for weather). My issue is, I can't seem to quite get the URL & image updated periodically:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import pyowm
class Weather(Screen):
addr = StringProperty()
def wx_forecast(self):
owm = pyowm.OWM('******************')
observation = owm.weather_at_place('London,uk')
w = observation.get_weather()
i = w.get_weather_icon_name()
addr = str("http://openweathermap.org/img/w/" + i + ".png")
print(addr)
return addr
def update(self):
Clock.schedule_interval(self.ids.wxlabel.source, 45)
#def update(self):
#self.wx_forecast()
#Clock.schedule_interval(lambda dt: self.ids.wxlabel, 30)
class ScreenManagement(ScreenManager):
pass
smsettings = Builder.load_string( """
ScreenManagement:
Weather:
<Weather>:
name: 'weather'
FloatLayout:
BoxLayout:
AsyncImage:
id: wxlabel
source: root.wx_forecast()
BoxLayout:
size_hint_y: None
height: 30
Button:
text: 'Change Location'
on_press:
Button:
text: 'More Details'
on_release:
""" )
class HomeUtilities(App):
def build(self):
return smsettings
if __name__=='__main__':
HomeUtilities().run()
Where the def update is where I am having issues; I have tried calling the function wx_forecast again, even trying another function outside the Weather class, but all it says is str: has no attribute 'wx_forecast'
So I believe I am on the right lines? Or I could be completely mistaken, but nothing I try seems to work. Even putting self.ids.wxlabel.source.sunny.png brings up str: has no attribute image but the file is there.
Related
I am trying to put an icon to the right hand side of a text list item, but this code below is giving me an error AttributeError: 'super' object has no attribute '__getattr__'
at this line: items.add_widget(icon).
Here's what I want it to look like:
List item with icon
Here's my code. It can be copied, and run as-is.
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
from kivymd.uix.button import MDFlatButton
from kivymd.uix.list import OneLineIconListItem, IconRightWidget, MDList
from kivymd.uix.dialog import MDDialog
KV = '''
<Content>
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "400dp"
ScrollView:
MDList:
id: Mcontainer
MDFloatLayout:
'''
class Content(BoxLayout):
pass
class Example(MDApp):
def on_start(self):
Mcontent=Content()
for x in range(0,7):
icon = IconRightWidget(icon="lock")
items = OneLineIconListItem(text="This is a test")
items.add_widget(icon)
Mcontent.ids.Mcontainer.add_widget(items)
self.MSetFileOptionsdialog = MDDialog(type="custom",content_cls=Mcontent,)
self.MSetFileOptionsdialog.open()
def build(self):
return Builder.load_string(KV)
Example().run()
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
from kivymd.uix.list import OneLineAvatarIconListItem
from kivymd.uix.dialog import MDDialog
KV = '''
<Item>
_txt_left_pad: "12dp"
IconRightWidget:
icon: root.icon
<Content>
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "400dp"
ScrollView:
MDList:
id: Mcontainer
MDFloatLayout:
'''
class Item(OneLineAvatarIconListItem):
icon = StringProperty()
class Content(BoxLayout):
pass
class Example(MDApp):
def on_start(self):
Mcontent = Content()
for x in range(0, 7):
items = Item(text="This is a test", icon="lock")
Mcontent.ids.Mcontainer.add_widget(items)
self.MSetFileOptionsdialog = MDDialog(type="custom", content_cls=Mcontent)
self.MSetFileOptionsdialog.open()
def build(self):
return Builder.load_string(KV)
Example().run()
When you want to add widget to an Id from your load_string or .kv file, you can just use the following; this is to be done in the .py file. There are limitations if screens are involved.
self.root.ids.name_of_the_id_referenced_container_widget_or_layout.add_widget(the one you already have in your.kv file)
I am using kivy to scan cards.How do I manage multiple screens . I wanted to capture the card first and the captured card should be passed to tesseract?
from kivy.app import App
from kivy.lang import Builder
import time
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from PIL import Image, ImageEnhance, ImageFilter
import pytesseract
from kivy.uix.button import Button
Builder.load_string("""
<CameraClick>:
orientation: 'vertical'
Camera:
id: camera
resolution: (640, 480)
play: False
ToggleButton:
text: 'Play'
on_press: camera.play = not camera.play
size_hint_y: None
height: '48dp'
Button:
text: 'Capture'
size_hint_y: None
height: '48dp'
on_press: root.capture()
<SettingsScreen>:
BoxLayout:
Button:
text: 'My settings button'
Button:
text: 'Back to menu'
on_press: root.manager.current = 'menu'
""")
class CameraClick(BoxLayout):
def capture(self):
'''
Function to capture the images and give them the names
according to their captured time and date.
'''
camera = self.ids['camera']
timestr = time.strftime("%Y%m%d_%H%M%S")
camera.export_to_png("reading.png".format(timestr))
print("Captured")
class SettingsScreen(Screen):
def card(self):
im = Image.open(r"readimg.png")
p = pytesseract.image_to_string(im, lang='eng', config='-psm 6')
print p
return Button(text=p)
# Create the screen manager
sm = ScreenManager()
sm.add_widget(CameraClick(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
I am new to kivy I wanted to know how to manage multiple screens.How to display the content of the card from tesseract in another screen?
Using kivy 1.9.1/2
What I would like to achieve :
Saving the image when clicking 'OK' then clearing the screen. So the next time I enter the Signature screen, the screen doesn't contain anything but the 'OK' button.
My Issue:
canvas.clear doesn't work. I probably integrated it the wrong way.
Can someone help ?
I'm a beginner and have been stuck on this for days.
Thanks in advance.
#*** PYTHON FILE
from kivy.app import App
from kivy.lang import Builder
from kivy.config import Config
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Line
import datetime
Config.set('graphics', 'width', '1024')
Config.set('graphics', 'height', '768')
class Other(Screen):
pass
class Painter(Widget):
def __init__(self,**kwargs):
super(Painter, self).__init__(**kwargs)
self.canvas.clear()
def on_touch_down(self, touch):
with self.canvas:
touch.ud['line'] = Line(points=(touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class Signature(Screen):
def Save_image(self):
from PIL import Image, ImageFont, ImageDraw
self.export_to_png("test.png")
img=Image.open("test.png")
draw=ImageDraw.Draw(img)
font=ImageFont.truetype("/usr/share/fonts/truetype/noto/NotoSans-Bold.ttf",24, encoding="unic")
draw.text((0,0),str("{:%d %b %y-%Hh%Mm%Ss}".format(datetime.datetime.now())), (255,255,255), font=font)
img.save("test.png")
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("appdessin.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == '__main__':
MainApp().run()
#***KV FILE
#:import datetime datetime
#:kivy 1.9.1
ScreenManagement:
Other:
Signature:
<Other>:
name: "other"
id: otherScreen
BoxLayout:
Button:
text: "OK"
on_release:
root.manager.transition.direction = 'right'
app.root.current = "signature"
<Signature>:
name: "signature"
id: signatureScreen
BoxLayout:
Painter
Button:
background_color: 0,0,1,1
font_size: 32
size_hint: (0.1, 0.1)
text: "OK"
pos_hint: {"right":1, "bottom":1}
on_release:
root.Save_image()
root.manager.transition.direction = 'right'
app.root.current = "other"
As suggested by niavlys on kivy's google group, the answer is to clear the canvas everytime it is loaded. Obvious, but to achieve this, one has to declare in the kv file, in the screen:
on_pre_enter:
sign.canvas.clear()
BoxLayout:
Painter
id: sign
I have below example kivy app i want to redirect to new page/display after the popup box based on some validation. How to redirect to new UI/page after popup ends?
example.kv
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Button:
height: 40
width: 100
size_hint: (None, None)
text: 'Click Me'
on_press: app.process_button_click()
<PopupBox>:
pop_up_text: _pop_up_text
size_hint: .5, .5
auto_dismiss: True
title: 'Status'
BoxLayout:
orientation: "vertical"
Label:
id: _pop_up_text
text: ''
And main.py as
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
import time, threading
class PopupBox(Popup):
pop_up_text = ObjectProperty()
def update_pop_up_text(self, p_message):
self.pop_up_text.text = p_message
class ExampleApp(App):
def show_popup(self):
self.pop_up = Factory.PopupBox()
self.pop_up.update_pop_up_text('Running some task...')
self.pop_up.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 + 5 > 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()
In my application I want to call some function when one of the dynamically created labels is touched. And there is a button at the bottom which calls another function.But when I press the button, on_touch_up event called for every label:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.logger import Logger
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
Builder.load_string("""
<Root>:
BoxLayout:
orientation: 'vertical'
size_hint: 1, 1
ScrollView:
id: scroll_view
size_hint: 1,.9
do_scroll_x: False
BoxLayout:
orientation: 'horizontal'
size_hint: 1,.1
Button:
id: bt1
text: 'Click'
size_hint: 1,1
on_release: root.btn1_click()
""")
class Root(BoxLayout):
def btn1_click(self):
Logger.info('BUTTON: button was released')
class TestApp(App):
def callback(self, instance, touch):
#if not instance.collide_point(*touch.pos):
# return
Logger.info('LABEL: ' + instance.text + 'was released')
def build(self):
root = Root()
sv = root.ids.scroll_view
grid = GridLayout(cols=1, spacing=(0,10), size_hint_y=None,
padding = [10,10,10,10],row_force_default=True, row_default_height=50)
grid.bind(minimum_height=grid.setter('height'))
sv.add_widget(grid)
for tr in [i for i in range(50)]:
lb_text = str(tr) + ' ' + 'Label'
lb = Label(text=lb_text)
lb.bind(on_touch_up=self.callback)
grid.add_widget(lb)
return root
if __name__ == '__main__':
TestApp().run()
And if I use:
#if not instance.collide_point(*touch.pos):
# return
button and label behind this button will be pressed.
How should I properly handle this touch?
This is because you are binding to on_touch_up. The on_touch_down event has already been fired, and the Button has grabbed that touch. So when you release, the Button will process the event no matter what (even if the touch is no longer over the Button).
This is why we have ButtonBehavior. If you use the behavior, then everything plays nice:
from kivy.uix.behaviors import ButtonBehavior
class TouchLabel(ButtonBehavior, Label):
pass
Then when you add the labels:
lb = TouchLabel(text=lb_text)
lb.bind(on_release=self.callback)
And finally, the signature of the event handler for on_release is different from on_touch_down:
def callback(self, instance):
Logger.info('LABEL: ' + instance.text + 'was released')
on_touch_down/on_touch_move/on_touch_up are for more advanced usage.