I'm starting in Kivy and this small example when running it opens the screen but everything is black nothing else is seen
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
import random
class RanWindow(BoxLayout):
def __init__(self, **kwargs):
super(RanWindow, self).__init__(**kwargs)
def generate_number(self):
self.rlabel.text = str(random.randint(0, 2000))
class RandomNumber(App):
def build(self):
return RanWindow()
if __name__=="__main__":
RandomNumber().run()
random.kv
<RanWindow>:
rlabel: rlabel
BoxLayout:
orientation: "vertical"
Label:
text: "Random Number"
font_size: 30
color: 0, 0.62, 0.96
Label:
id: rlabel
text: "_"
font_size: 30
Button:
text: "Generate"
font_size: 15
on_press: root.generate_number()
does not show any error
Your random.kv file is not loaded. You need to either add:
Builder.load_file('random.kv')
to your code. Or change the name of random.kv to randomnumber.kv.
Related
I am trying to make a children's learning app using KIVY and gTTS where a child will be shown a random image and will have to identify it by saying what it is ("square" for square, "three" for 3 etc).
So far I have the menus working fine.
I am using random.choice() in a dictionary where the value is the image path and the key is "the name"
If I open the relevant screen the image is correctly selected at random and displayed using def on_pre_enter(self, *args): and gTTS kicks in fine as well using def on_enter(self, *args): but only ONCE
I want it to load a new random image once the user replies to the previous one for an X amount of loops but no matter what I try I cannot get it to work (I thought of putting everything on a for x in range() loop as well as using a counter on a while X < Y: but without any success).
here's my .py file
import random
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
class MenuWindow(Screen):
pass
class ShapeGame(Screen):
rand_shape = StringProperty()
def on_pre_enter(self, *args):
random_shape = {"square":'shapes/square.png', "triangle":'shapes/triangle.jpg', "circle":'shapes/circle.jpg'}
random_shape_key, random_shape_value = random.choice(list(random_shape.items()))
print(random_shape_key)
self.rand_shape_key = random_shape_key
self.rand_shape = random_shape_value
def on_enter(self, *args):
print(self.random_shape_key)
class WindowManager(ScreenManager):
pass
class MainApp(App):
def build(self):
return Builder.load_file('Main.kv')
if __name__ == '__main__':
MainApp().run()
and my .kv file
#:kivy 2.0
WindowManager:
MenuWindow:
ShapeGame:
<MenuWindow>:
name: "menu"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
id:"menu"
text: "Menu Screen"
font_size: 34
BoxLayout:
size_hint: 1.0, 0.2
Button:
text: "Shape Game"
font_size: 22
on_release:
app.root.current = "shapes"
root.manager.transition.direction = "left"
Button:
text: "Exit"
font_size: 22
size_hint: 1.0, 0.2
on_release: app.root.current = exit()
<ShapeGame>:
name: "shapes"
id: ShapeGame
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Image:
id:"shapes"
screen: ShapeGame
source: self.screen.rand_shape
before_source: self.source
BoxLayout:
size_hint: 1.0, 0.2
size: root.width, root.height
Button:
text: "Menu"
on_release:
app.root.current = "menu"
root.manager.transition.direction = "right"
Button:
text: "Exit"
on_release:
app.root.current = exit()
and the entire repo
Not sure I can follow your problem, assuming that you want to shuffle images on entering screen after some time until some value reaches its limit.
For that you can use Clock.schedule_interval with some waiting time, say 2.0 sec.
Thus your ShapeGame will now look like,
class ShapeGame(Screen):
rand_shape = StringProperty()
count = 0
def on_pre_enter(self, *args):
self.count = 0
self.change_event = Clock.schedule_interval(self.chage_photo, 2.0)
def chage_photo(self, *args):
if self.count < 3:
self.count += 1
else:
self.change_event.cancel()
random_shape = {"square":'shapes/square.png', "triangle":'shapes/triangle.jpg', "circle":'shapes/circle.jpg'}
random_shape_key, random_shape_value = random.choice(list(random_shape.items()))
print(random_shape_key)
self.rand_shape_key = random_shape_key
self.rand_shape = random_shape_value
You should change source: self.screen.rand_shape to source: root.rand_shape.
You may also trigger the same action by a button instead of using Clock.schedule.
i have the following example using kivy -
When i write something in the input field1 and press Reset - everything works fine (input field get deleted, focus on field1).
But when i am changing something in field2 and press the Reset Button it seems that the App gets broken...
Why is that and why is the statement self.ids.stockTicker.focus = True not working every time?
py-file:
import threading
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.core.window import Window
Builder.load_file("TryApp.kv")
class MyLayout(Widget):
Window.size = (550, 700)
def Reset(self):
self.ids.stockTicker.text = ""
self.ids.stockTicker.focus = True
self.ids.index.text = "SP500"
def pressReset(self):
threading.Thread(target=self.Reset).start()
class MyTry(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
MyTry().run()
kv-file:
<MyLayout>
BoxLayout:
orientation: "vertical"
size: root.width, root.height
GridLayout:
size_hint: (1, .5)
cols: 2
Label:
text: "Field1"
font_size: 18
TextInput:
id: stockTicker
focus: True
Label:
text: "Field2"
font_size: 18
TextInput:
id: index
text: "xyz"
Button:
id: buttonReset
text: "Reset"
#font_size: 20
on_press: root.pressReset()
size_hint: (None,None)
width: 110
height: 70
I think you just need to change:
on_press: root.pressReset()
to:
on_release: root.pressReset()
The reasoning is that when the pressReset() method is triggered by the on_press event, the focus is changed as you desire, but then the Button release event changes focus back to the Button. Changing it to the on_release event eliminates that problem.
I have the following classes in my kivy app, and i would like to call the blink method in my mainApp class. The start pulsing and blink methods enable the MainWindow background to pulse. However it's not working inside the MainWindow class and i need to call it in my mainApp class. Commented out (build method in mainApp) is what i tried, which results to the error Exception: Invalid instance in App.root. My python file:
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.core.window import Window
from kivymd.app import MDApp
from kivy.uix.image import Image
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.properties import ColorProperty
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from plyer import filechooser
data = ""
class MainWindow(Screen):
def analyze_data(self):
global data
data = self.ids.user_input.text
data = analyze(data)
animated_color = ColorProperty()
pulse_interval = 4
def blink(self):
x = Clock.schedule_once(self.start_pulsing, 5)
return x
def start_pulsing(self, *args):
d = self.pulse_interval / 2
anim = Animation(animated_color=(69/255, 114/255, 147/255, 1), duration=d) + Animation(animated_color=(1, 1, 1, 1), duration=d)
anim.repeat = True
anim.start(self)
class OutputScreen(Screen):
def on_enter(self, *args):
self.ids.output_label.text = data
class mainApp(MDApp):
def __init__(self):
super().__init__()
def choose_file(self):
try:
filechooser.open_file(on_selection = self.handle_selection)
except:
pass
def handle_selection(self,selection):
global path
selection_ls = selection[0]
path = selection_ls
#print(path)
def change_screen(self,screen):
screemanager = self.root.ids['screenmanager']
screemanager.current = screen
def change(self):
self.change_screen('output')
def back(self):
self.change_screen('main')
'''
def build(self):
x = MainWindow().blink()
return x'''
and my kv file:
#:import utils kivy.utils
GridLayout:
cols:1
ScreenManager:
id: screenmanager
MainWindow:
id: main
name: 'main'
OutputScreen:
id: output
name: 'output'
<MainWindow>:
BoxLayout:
orientation:'vertical'
MDBottomNavigation:
panel_color: utils.get_color_from_hex("#ffffff")
MDBottomNavigationItem:
name:'analytics'
text:'analytics'
icon:'account-circle'
FloatLayout:
size: root.width, root.height
canvas.before:
Color:
rgba: root.animated_color
Rectangle:
pos:self.pos
size:self.size
TextInput:
multiline:True
id: user_input1
pos_hint:{"x" : 0.05, "top" : 0.9}
size_hint: 0.9, 0.37
Label:
markup: True
id:input_label
pos_hint:{"x" : 0, "top":1}
size_hint: 1 ,0.08
font_size : 32
bold: True
canvas.before:
Color:
rgb: utils.get_color_from_hex("01121c")
Rectangle:
size: self.size
pos: self.pos
Button:
pos_hint:{"top" : 0.51, "x" : 0.05}
size_hint: (None,None)
width : 150
height : 40
font_size : 23
text:'Submit'
on_press: root.analyze_data()
on_release: app.change()
Button:
pos_hint:{"top":0.42, "x":0.05}
size_hint: (None,None)
width : 150
height : 40
font_size : 23
text:'Upload'
on_release:app.choose_file()
Button:
id:'info_button'
pos_hint:{"top":0.47, "x":0.8}
size_hint: (None,None)
width : 50
height : 22
font_size : 23
text:'i'
on_release:root.analytics_info()
<OutputScreen>:
ScrollView:
GridLayout:
cols:1
MDIconButton:
icon:'arrow-left'
pos_hint:{'top':1,'left':1}
size_hint: 0.1,0.1
user_font_size : '64sp'
on_release: app.back()
Label:
id: output_label
multiline:True
text_size: self.width, None
size_hint: 1, None
height: self.texture_size[1]
color: 0,0,0,1
padding_x: 15
Any help will be much appreciated.
The build() method of an App should return a Widget that will become the root of the App. But your build() method returns a ClockEvent (the return from Clock.schedule_once()). Try changing your build() method to:
def build(self):
x = MainWindow()
x.blink()
return x
Since you do not call Builder.load_file(), I assume that your kv file is named main.kv, and therefore will get loaded automatically. If that is true, then you do not need a build() method at all. Instead add an on_start() method to your mainApp class, like this:
def on_start(self):
self.root.ids.main.blink()
I was using my main class as widget and was passing IDs from kv file to python without problems.
Now changed it to a screen as I need to switch between 2 screens but now I cant access the IDs declared in kv file. I get error - 'MainScreen'object has no attribute 'labINFO' - (this is the first label id I am trying to modify.)
Here are parts of py and kv files
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
class GSMNosScreen(Screen):
def gsmclose(self, obj):
Clock.schedule(self.startgetTemps,dataInterval)
BoilerApp.sm.current = 'main'
class MainScreen(Screen):
....
....
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.labINFO.text = "Waiting for Pic..."
self.labM1.text = str(b1Min)
self.labM2.text = str(b2Min)
sm = ScreenManager() #transition=NoTransition()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(GSMNosScreen(name='gsmnos'))
class BoilerApp(App):
def build(self):
self.title = 'Boiler Monitor'
return sm
if __name__ == "__main__":
from kivy.core.window import Window
Window.fullscreen = True
app = BoilerApp()
app.run()
KV file
<GSMNosScreen>:
labN1: labN1
size_hint: .5, .5
auto_dismiss: False
title: "GSM Numbers" # <<<<<<<<
separator_height: 0 # <<<<<<<<
GridLayout:
cols: 1
size: root.width, root.height
MyTLab:
id:labN1
font_size: 20
text: "Number 1 : ..."
MyBut:
text: "Close"
font_size: 20
size_hint: .2, .2
on_press: gsmclose()
<MainScreen>
labM1: labM1
labM2: labM2
labM3: labM3
labM4: labM4
labM5: labM5
labINFO: labINFO
labDT: labDT
GridLayout:
cols: 1
size: root.width, root.height
MyTLab:
text: "Monitor"
underline: True
size_hint: .5, .2
BoxLayout:
orientation: "horizontal"
size_hint_y: .2
MySTLab:
color: 0.8,.2,.2,0.7
text: "Min °C"
size_hint_x: 1.5
font_size: 25
MyMLab:
id: labM1
text: "50"
MyMLab:
id: labM2
text: "50"
MyMLab:
id: labM3
text: "50"
MyMLab:
id: labM4
text: "50"
BoxLayout:
orientation: "horizontal"
#cols:2
size_hint_y: .1
Label:
id: labDT
color: 0,1,0.5,0.8
text: "Starting ...."
font_size: sp(20)
size_hint_x: .3
Label:
id: labINFO
color: 0,1,0.5,0.8
text: "...."
font_size: sp(20)
size_hint_x: .7
I believe the problem is that the kv file has not been loaded yet when the lines:
sm = ScreenManager() #transition=NoTransition()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(GSMNosScreen(name='gsmnos'))
are executed.
Try moving the above lines into the build() method of the App:
class BoilerApp(App):
def build(self):
self.title = 'Boiler Monitor'
sm = ScreenManager() # transition=NoTransition()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(GSMNosScreen(name='gsmnos'))
return sm
The kv file (if it is named boiler.kv) is loaded before the build() mehod is called.
I am trying create a GUI by implementing the template of the ComicCreator GUI sample as a template for my own project. The code is easy to follow, but I would like to be able to reconfigure the drawingspace.kv, each time a button is pushed, say for example something like this:
Q: How could I configure the drawingspace.kv to have a different layout with different widgets for each button that is pressed?
A neat way to do this is to use screen.
Since I allready have an example of this app from you earlier question, it was easy to implement the screens, and rewrite the classes a bit.
When a button is pressed, you set the screenmanager's current to whatever the name you named the screen you want.
Then you just edit the layouts as you want inside of each screen, in the kv file, or python file.
I choose to make most of the layout stuff in kv language here. Because I find it easier to develop a layout the way I want it this way.
Later I could rewrite it to python if I want that.
So my python file looks like this now:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.clock import Clock
from kivy.uix.screenmanager import Screen,ScreenManager,NoTransition
from kivy.lang import Builder
import time
Builder.load_file("kv.kv")
class MyLayout(BoxLayout):
def __init__(self,**kwargs):
super(MyLayout,self).__init__(**kwargs)
self.orientation = "vertical"
self.padding = 10
class MainScreen(Screen):
pass
class RemoveScreen(Screen):
pass
class GroupScreen(Screen):
pass
class MyLogo(BoxLayout):
your_time = StringProperty()
def __init__(self,**kwargs):
super(MyLogo,self).__init__(**kwargs)
Clock.schedule_interval(self.set_time, 0.1)
def set_time(self,dt):
self.your_time = time.strftime("%m/%d/%Y %H:%M")
class MyApp(App):
def __init__(self,**kwargs):
super(MyApp,self).__init__(**kwargs)
self.sm = ScreenManager(transition=NoTransition())
self.sm.add_widget(MainScreen(name = "main"))
self.sm.add_widget(RemoveScreen(name = "remove"))
self.sm.add_widget(GroupScreen(name = "group"))
self.sm.current = "main"
def build(self):
return self.sm
if __name__ == "__main__":
MyApp().run()
And kv.kv file looks like this:
#:kivy 1.9.1
<MyButtons#BoxLayout>:
padding: 10,10,10,0
spacing: 10
size_hint: 1,0.3
orientation: "horizontal"
Button:
text: "Clear"
on_press: app.sm.current = "main"
Button:
text: "Remove"
on_press: app.sm.current = "remove"
Button:
text: "Group"
on_press: app.sm.current = "group"
Button:
text: "Color"
Button:
text: "Gestures"
<MyLogo>:
spacing: 10
padding: 10,10,10,0
orientation: "horizontal"
BoxLayout:
orientation: "vertical"
size_hint: 0.3,1
canvas:
Rectangle:
pos: self.pos
size: self.size
AsyncImage
source: 'http://lmsotfy.com/so.png'
Label:
size_hint: 1,0.3
text: root.your_time
color: [0,0,0,1]
Label:
size_hint: 1,0.3
text: "NYC, New York, USA"
color: [0,0,0,1]
<MainScreen>:
MyLayout:
MyLogo:
#Button:
# text: "main"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
<RemoveScreen>:
MyLayout:
MyLogo:
BoxLayout:
orientation: "horizontal"
Label:
font_size: "40sp"
text: "Remove"
Button:
font_size: "20sp"
text: "Remove this or something"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
<GroupScreen>:
MyLayout:
MyLogo:
BoxLayout:
orientation: "vertical"
Label:
font_size: "40sp"
text: "Group"
Button:
font_size: "20sp"
text: "Something groups stuff"
MyButtons:
#buttons
BoxLayout:
padding: 10,10,10,10
size_hint: 1,0.3
Button:
text: "Total figures: 1 Kivy Started"
The layout frame should be a screen manager, and each layout a screen. Screen transitions would be then triggered by pressing the buttons. You can also watch a tutorial here if you don't know how to do this, but the documentation should be enough.