main.py
from kivy.uix.button import Button
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivymd.uix.gridlayout import MDGridLayout
kv="""
<RoundedButton#Button>:
background_color: 0,0,0,0 # the last zero is the critical on, make invisible
canvas.before:
Color:
rgba: (.4,.1,.4,1) if self.state=='normal' else (0,.7,.7,1) # visual feedback of press
RoundedRectangle:
pos: self.pos
size: self.size
radius: [(30,30),(30,30),(30,30),(30,30)]
"""
class RoundedButton(Button):
pass
class grid(MDGridLayout):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.rows=3
self.cols=3
self.padding=10
self.spacing=10
self.add_widget(RoundedButton(text="12"))
self.add_widget(RoundedButton(text="12"))
self.add_widget(RoundedButton(text="12"))
self.add_widget(RoundedButton(text="12"))
self.add_widget(RoundedButton(text="12"))
Builder.load_string(kv)
runTouchApp(grid())
Output
output of this program
Here I want the kv string portion to be in the in my RoundedButton
class in python file instead of writing it in kivy format in a string.
Can you tell me how to proceed?
Related
I am trying to change the text of a label using an id, I tried it with stringProperty, with objectProperty without any properties. There has to be something I am missing in my code because it simply does not work whatever I try and any help would be greatly appreciated.
This bit of code is a simple screen with 2 buttons, one for going to the other screen and one for changing the label
from kivy.app import *
from kivy.uix.button import *
from kivy.graphics import *
from kivy.uix.widget import *
from kivy.uix.label import *
from kivy.uix.floatlayout import *
from kivy.uix.boxlayout import *
from kivy.uix.relativelayout import *
from kivy.uix.scrollview import ScrollView
from kivy.properties import ListProperty, StringProperty,ObjectProperty
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
class WindowManager(ScreenManager):
pass
class Name(FloatLayout):
def __init__(self, **kwargs):
super(Name, self).__init__(**kwargs)
def changeName(self):
print(self.ids)
self.name = self.ids.nameOfSong.text
print(self.name)
self.ids.nameOfSong.text = 'name'
self.name = self.ids.nameOfSong.text
print(self.name)
class MainWindow(Screen):
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
self.pos = (0, 0)
self.size = (1,1)
self.z = Name()
self.add_widget(self.z)
def swap(self):
Name().changeName()
class SecondWindow(Screen,BoxLayout):
def __init__(self, **kwargs):
super(SecondWindow, self).__init__(**kwargs)
class langApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MainWindow(name='main'))
sm.add_widget(SecondWindow(name='second'))
return sm
Builder.load_file("kiv.kv")
if __name__ == '__main__':
langApp().run()
My kiv.kv file, most of it is not connected to the problem (I think)
#:kivy 1.11.1
WindowManager:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
FloatLayout:
pos: 0,0
size: root.width,root.height
Button:
on_release:
root.manager.transition.direction = 'left'
app.root.current = "second"
text: 'Stop'
pos_hint: {'x':.45,'y':.1}
size_hint: .1,.1
Button:
on_press: root.swap()
text: 'Next'
pos_hint: {'x':.65,'y':.1}
size_hint: .1,.1
<SecondWindow>:
name: "second"
FloatLayout:
pos: 0,0
size: root.width,root.height
Button:
on_release:
root.manager.transition.direction = 'right'
app.root.current = "main"
text: 'Stop'
pos_hint: {'x':.45,'y':.1}
size_hint: .1,.1
<Name>:
Label:
text: nameOfSong
font_size: 20
size_hint: None, None
pos_hint: {'x': 0.435, 'y': 0.25}
A few problems with your code:
First, your code as posted dos not run. The line in your kv:
text: nameOfSong
is illegal.
Second, the code:
def swap(self):
Name().changeName()
is creating a new instance of Name and calling changeName() on that new instance. However, that new instance is not the one that is displayed in your GUI.
To fix that, you just need to call changeName() on the instance of Name that is in your GUI. Conveniently, you have saved a reference to the correct instance with the line:
self.z = Name()
So, you can change the swap() method to use that instance of Name:
def swap(self):
self.z.changeName()
The other problem is that the changeName() method tries to use a non-existent id nameOfSong. To fix that (and to make your posted code runnable), just change the <Name> rule in your kv to define that id:
<Name>:
Label:
id: nameOfSong
text: 'Some Name'
font_size: 20
size_hint: None, None
pos_hint: {'x': 0.435, 'y': 0.25}
On an unrelated note, your code is building the App GUI twice. The line:
Builder.load_file("kiv.kv")
is building the GUI from the lines:
WindowManager:
MainWindow:
SecondWindow:
and your python code is building it again here:
def build(self):
sm = ScreenManager()
sm.add_widget(MainWindow(name='main'))
sm.add_widget(SecondWindow(name='second'))
return sm
You can delete those three lines from your kv file.
I am using Kivy to make an app, and I'm trying to display a label. Here's my main code
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.popup import Popup
class storageApp(App):
def build(self):
return kvfile
class LoginPage(Screen):
pass
class WindowManager(ScreenManager):
pass
kvfile = Builder.load_file('storage.kv')
storageApp().run()
Here's my .kv file
WindowManager:
current: 'login'
LoginPage:
<LoginPage>:
name: 'login'
FloatLayout:
Label:
text: 'Welcome to the secret app!'
size_hint: 0.5, 0.1
pos_hint: {'center_x': 0.5, 'top': 0.95}
background_color: 1, 0, 1, 1
And I get the following output on my screen
The color of the label is still black. However, when Ichange the Label to Button it seems to work.
This seems very odd. Any idea how to fix it?
The Label doesn't have a background colour property. If you want a background, draw one:
<KvBackgroundRule>:
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
pos: self.pos
size: self.size
I'm attempting to drag some images arranged inside a GridLayout (which is indeed inside a ScrollView) to outer Layout.
The image to be dragged has its on_touch_down event defined, when image is clicked parent is changed from WidgetMenu to MainLayout so it can be dragged between those widgets. The current problem is when I touch the image, DragBehavior is lost.
The full code:
import kivy
kivy.require("1.9.1")
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget
from kivy.uix.behaviors import DragBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.base import runTouchApp
from kivy.lang import Builder
Builder.load_string('''
<WidgetMenu>:
canvas.before:
Color:
rgb: 0.9,0.5,0.3
RoundedRectangle:
pos:self.pos
size: self.size
radius: [20,]
orientation: "vertical"
padding:30
ScrollView:
GridLayout:
cols:1
size_hint_y:None
row_default_height:root.height*.15
height:self.minimum_height
DragImage:
DragImage:
DragImage:
<DragImage>:
drag_rectangle: self.x, self.y, self.width, self.height
drag_timeout: 100000000
drag_distance: 0
size_hint:None,None
size:234,34
canvas:
Color:
rgb:1,0,1
Rectangle:
pos: self.pos
size: self.size
<MainLayout>:
canvas:
Color:
rgb:1,1,1
Rectangle:
size: self.size
pos: self.pos
WidgetMenu:
size_hint: 0.35,0.9
''')
class MainLayout(FloatLayout):
pass
class WidgetMenu(BoxLayout):
pass
class DragImage(DragBehavior,FloatLayout):
def on_touch_down(self,touch):
workspace = self.parent.parent.parent.parent
grid = self.parent
menu = self.parent.parent.parent
if "MainLayout" in str(workspace):
grid.remove_widget(self)
workspace.remove_widget(menu)
self.pos = Window.mouse_pos
workspace.add_widget(self)
return True
class ScrollApp(App):
def build(self):
return MainLayout()
ScrollApp().run()
Please help.
Two problems with your code are that you are not calling the super method in your on_touch_down, and placing the DragImage in the top level MainLayout changes the pos of the DragImage, thus changing its DragRectangle. That change in DragRectangle leaves the touch.pos outside of it, so DragBehavior thinks the touch is not on the DragImage.
I have fixed both those problems by calling the super method and changing the touch.pos before passing it to the super method. I also added some code to keep the DragImage in the same position relative to the mouse when it is clicked. Also added a call to self.collide_point() in order to ignore clicks not on the DragImage.
class DragImage(DragBehavior,FloatLayout):
def on_touch_down(self,touch):
if not self.collide_point(*touch.pos):
return False
workspace = self.parent.parent.parent.parent
grid = self.parent
menu = self.parent.parent.parent
if "MainLayout" in str(workspace):
grid.remove_widget(self)
workspace.remove_widget(menu)
# the following code assumes that workspace is the entire Window
self.x = Window.mouse_pos[0] - (touch.pos[0] - self.x)
self.y = Window.mouse_pos[1] - (touch.pos[1] - self.y)
workspace.add_widget(self)
touch.pos = Window.mouse_pos
return super(DragImage, self).on_touch_down(touch)
I'm trying to add a digital clock to my Kivy program, it seems to be having trouble.
Here is the .py:
import kivy
kivy.require('1.10.0')
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.stacklayout import StackLayout
from kivy.clock import Clock
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
import time
class IntroScreen(Screen):
pass
class ContScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
backbone = Builder.load_file("main.kv")
class Status(FloatLayout):
_change = StringProperty()
_tnd = ObjectProperty(None)
def update(self, *args):
self.time = time.asctime()
self._change = str(self.time)
self._tnd.text = str(self.time)
print (self._change)
class XGApp(App):
time = StringProperty()
def update(self, *args):
self.time = str(time.asctime()) # + 'time'?
def build (self):
Clock.schedule_interval(self.update, 1)
return backbone
xApp = XGApp()
if __name__ == "__main__":
xApp.run()
and the .kv
<ContScreen>:
FloatLayout
size_hint: .1,.1
canvas.before:
Color:
rgba: 0,0,0,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: app.time
ContScreen is the title of the screen I want to show the clock on, it's served by a separate Builder (main.kv).
Any help would be appreciated! Been struggling with this clock for a few hours now. The trouble seems to be on the .kv side from what I can tell.
BONUS: If you want to go the extra mile, I also want to add a timer that counts down x amount on press of a button on the .kv. The x amount would be different depending on which button you press.
I have made a fork of the original kivydigitalclock here. It should be easier to use than the original. You can add it to your .kv file just as any other widget. For example, something like:
<ContScreen>:
FloatLayout
size_hint: .1,.1
canvas.before:
Color:
rgba: 0,0,0,1
Rectangle:
pos: self.pos
size: self.size
Label:
text: app.time
DigitalClock:
pos_hint: {'right': 1.0, 'center_y': 0.5}
size_hint: (0.2, 0.2)
should work. Note that in your main .py file you will need to include:
from digitalclock.digitalclock import DigitalClock
(assuming that the digitalclock.py file is in a digitalclock folder)
How to add my widget in a ScrollView or ListView to scroll it?
I've written a code but it doesn't work good, this is my main.py:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from random import random
class chat_history(BoxLayout):
def profile(self):
return random(),random(),random()
Builder.load_file('widg.kv')
class myApp(App ):
def build(self):
x=BoxLayout(orientation='vertical')
s=ScrollView()
for i in range(1,21):
x.add_widget(chat_history(height=50))
s.add_widget(x)
return s
myApp().run()
And this is my kv file:
<chat_history>:
height:100
BoxLayout:
height:50
name:'haha very funny '
size_hint_y:None
id:cv
orientation:'horizontal'
canvas:
Color:
rgb:root.profile()
Ellipse:
pos:root.pos
Label:
text_hint:{'x':0,'y':0.1}
pos:root.pos
size_hint_x:0.7
height:cv.height
text:cv.name
id:lbl
First of all, you should prevent the layout from automatically adapting its height to the height of its parent widget (size_hint_y = None).
On the other hand, make sure the height is such that there is something to scroll. You must explicitly specify layout height.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from random import random
kv_text = '''
<chat_history>:
size_hint_y: None
height:100
BoxLayout:
height:50
name:'haha very funny '
size_hint_y:None
id:cv
orientation:'horizontal'
canvas:
Color:
rgb:root.profile()
Ellipse:
pos:root.pos
Label:
text_hint:{'x':0,'y':0.1}
pos:root.pos
size_hint_x:0.7
height:cv.height
text:cv.name
id:lbl
'''
class chat_history(BoxLayout):
def profile(self):
return random(),random(),random()
class myApp(App ):
def build(self):
Builder.load_string(kv_text)
x=BoxLayout(orientation='vertical', size_hint_y=None) #<<<<<<<<<<<
x.bind(minimum_height=x.setter('height')) #<<<<<<<<<<<
s=ScrollView()
for i in range(1,21):
x.add_widget(chat_history(height=50))
s.add_widget(x)
return s
myApp().run()