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)
Related
I am writing a program that requires a label, a text_input, and a checkbox to be aligned on screen in that order. They should span the width of the screen and be at the same y level.
I have written this code in my .kv file which uses identical pos_hint values, but only the text_input box moves
Below is my .kv code:
<Union>:
BoxLayout:
orientation: "vertical"
BoxLayout:
orientation: "horizontal"
pos_hint_y: {"top":.85}
Label:
text: 'Session Length'
pos_hint: {"x":.3, "top":.85}
TextInput:
id: input
text: "test"
pos_hint: {"x":.5, "top":.85}
size_hint: 0.3, 0.05
background_disabled_normal: ""
disabled: not checkbox.active
on_text: app.return_text()
CheckBox:
id: checkbox
pos_hint: {"x":.7, "top":.85}
and here is my main.py
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen, ScreenManager
Window.size = (309, 555)
class MenuScreen(Screen):
pass
class SetupScreen(Screen):
pass
class drop_content(DropDown):
pass
class UnionScreen(Screen):
class Checkbox_Setup(FloatLayout):
pass
class TheApp(App):
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SetupScreen(name='setup'))
sm.add_widget(UnionScreen(name='union'))
return sm
def return_text(self):
text = self.root.get_screen('union').ids.input.text
print(text)
def main():
Builder.load_file('menu.kv')
app = TheApp()
app.run()
if __name__ == '__main__':
main()
Finally, here is the output I am currently getting, with the label and checkbox in line but underneath the text_input which is in the right place.
I am relatively new to kivy so any help would be greatly appreciated. Thanks in advance!
I'm a beginner at kivy, I have an fclass(Widget) that I want it to be a fclass(Screen), but when I tried to make the change all the screen messed up, the code generate some buttons with a for loop, I wish I coud do the same with a float layout, but I want the fclass to stay a screen since I'm building a multiscreen app.
Here is the .py file:
import kivy
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.core.window import Window
from kivy.config import Config
from kivy.lang import Builder
from kivy.properties import StringProperty, ObjectProperty, NumericProperty,ReferenceListProperty
from kivy.graphics.texture import Texture
from kivy.core.camera import Camera
from kivy.graphics import *
import time
import os
from pathlib import Path
#import cv2
import struct
import threading
import pickle
Builder.load_file('the.kv')
class fscreen(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.list_of_btns = []
def create(self):
self.h = self.height*0.9
for i in range(4):
self.h = self.h - self.height*0.1
self.btn = Button(text='button '+str(i), size=(self.width*0.4,self.height*0.05), pos=(self.width*0.3, self.h), on_press=self.press)
self.list_of_btns.append(self.btn)
self.add_widget(self.btn)
def press(self, instance):
print(instance.text)
def delete(self):
for btns in self.list_of_btns:
self.remove_widget(btns)
class theapp(App):
def build(self):
self.screenm = ScreenManager()
self.fscreen = fscreen()
screen = Screen(name = "first screen")
screen.add_widget(self.fscreen)
self.screenm.add_widget(screen)
return self.screenm
if __name__ == "__main__":
theapp = theapp() #
theapp.run()
The .kv file:
<fscreen>
Button:
text: 'create'
size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.1
on_press: root.create()
Button:
text: 'delete'
size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.2
on_press: root.delete()
How can I make the fclass a screen class without messing up everything ?
Thank you in advance
Seems to me that code should work, but it doesn't. A fix is to use size_hint instead of size in both your kv and py. So the kv could look like:
<fscreen>:
Button:
text: 'create'
size_hint: 0.4, 0.05
# size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.1
on_press: root.create()
Button:
text: 'delete'
size_hint: 0.4, 0.05
# size: root.width*0.4, root.height*0.05
pos: root.width*0.3, root.height*0.2
on_press: root.delete()
and in the create() method:
def create(self):
self.h = self.height * 0.9
for i in range(4):
self.h = self.h - self.height * 0.1
self.btn = Button(text='button ' + str(i), size_hint=(0.4, 0.05),
pos=(self.width * 0.3, self.h), on_press=self.press)
self.list_of_btns.append(self.btn)
self.add_widget(self.btn)
Your size in the kv and py were both just trying to do the size_hint anyway.
And, of course, your build() method must be adjusted:
def build(self):
self.screenm = ScreenManager()
self.fscreen = fscreen(name="first screen")
self.screenm.add_widget(self.fscreen)
return self.screenm
Other things to note:
You should use upper case for class names. Failure to do so can lead to errors in kv
You should consider using pos_hint instead of pos to allow better resizing of your App
For some reason when I run the code my accordion titles are black and the title text is not visible, when comparing it to example code where the accordion are a dark grey with white text. The rest of the accordion works fine when I click on it, it expands and closes. The only problem is the accordion titles not properly working.
*.py
#imported from kivy framework
from kivy.app import App
from kivymd.app import MDApp
from kivy.app import App
from kivy.uix.label import Label
from datetime import datetime
from datetime import timedelta
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.image import Image
import dictionaryData
from kivy.lang import Builder
from kivy.base import runTouchApp
import os
from kivy.uix.button import Button
from kivy.uix.accordion import Accordion, AccordionItem
class Main_Screen(Screen):
pass
class Dictionary_Screen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
layout = BoxLayout(orientation='vertical') # instantiate BoxLayout
self.add_widget(layout) # add BoxLayout to screen
btn2 = Button(
text='change screen',
size_hint=(.5, .05),
)
btn2.bind(on_press=self.changer)
layout.add_widget(btn2) # add Button to BoxLayout
title = ["Title 1", "Title 2", "Title 3", "Title 4", "Title 5"]
accordion = Accordion(orientation='vertical') # instantiate Accordion
layout.add_widget(accordion) # add Accordion to BoxLayout
for x in range(2):
item = AccordionItem(title="Cheese",background_normal= "LogoFF.png")
item.add_widget(Label(text='Very big content\n' * 2))
accordion.add_widget(item) # add AccordionItem to Accordion
def changer(self,*args):
print("ww")
#class for all screens
class ScreenManagement(ScreenManager):
pass
class MainApp(MDApp):
def build(self):
# declaring time from python, and making it refresh every second
self.now = datetime.now()
Clock.schedule_interval(self.update_clock, 1)
def update_clock(self, *args):
self.now = self.now + timedelta(seconds=1)
self.root.get_screen("Main_Screen").ids["CurrentTime"].text = self.now.strftime("%H:%M:%S")
MainApp().run()
*.kv
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
#styles that will apply to all intences for each tag
<MDRaisedButton>:
font_size:18
<Label>:
color: 0,0,0,1
#declaring screen managers and printing them in this order
ScreenManagement:
Main_Screen:
name: "Main_Screen"
Dictionary_Screen:
name: "Dictionary_Screen"
<Main_Screen>:
FloatLayout:
spacing: 10
canvas.before:
Color:
rgba: hex('#eff3fa')
Rectangle:
size: self.size
pos: self.pos
#Navbar
MDToolbar:
id: fb
pos_hint: {'center_x': 0.5, 'top':1.0}
size_hint_y:None
height: 50
title: "Virtual Assistant"
md_bg_color: hex('#132843')
Label:
id: CurrentTime
font_size:18
size_hint_x: .1
color: (1,1,1,1)
BoxLayout:
orientation: 'vertical'
spacing: 10
padding: 50
canvas.before:
Color:
rgba: hex('#000')
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
size_hint: 0.5, 0.5
Button:
text: "Dictionary"
on_release:
app.root.current = "Dictionary_Screen"
<Dictionary_Screen>:
Label:
id: box
color: (1,0,1,1)
Is there a way I can fix this?
The AccordionItemTitle is a Label, and your <Label>: rule sets all text in all Labels to black. You can fix the problem by removing the lines:
<Label>:
color: 0,0,0,1
from your kv file. It is generally a bad idea to make a kv rule for a commonly used Widget. A better approach would be to create a custom class like:
<BlackLabel#Label>:
color: 0,0,0,1
and use BlackLabel where you want such a Label.
I am able to display text from the text file on to the UI but I don't know how to give each piece of text its own label so I am able to evenly spread the text out on screen.
*.py
#imported from kivy framework
from kivy.app import App
from kivymd.app import MDApp
from kivy.app import App
from kivy.uix.label import Label
from datetime import datetime
from datetime import timedelta
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.image import Image
import dictionaryData
from kivy.lang import Builder
from kivy.base import runTouchApp
import os
class Main_Screen(Screen):
pass
class Dictionary_Screen(Screen):
def on_enter(self):
self.Data()
def Data(self):
i = 0
print("trigger")
file1 = open('dict.txt','r')
for lines in file1:
i +=1
fields = lines.split(',')
print('I draw label')
Data = (fields[0], fields[1])
Title,Description = Data
# page is an object
page = dictionaryData.Dictionary(Title,Description)
page.formatData()
work = page.placeholder()
flipper = page.placeholder()
self.add_widget(Label(text = flipper, pos=(i*00, 100)))
self.ids["textFile"].text += flipper + '\n'
#class for all screens
class ScreenManagement(ScreenManager):
pass
class MainApp(MDApp):
pass
MainApp().run()
*.kv
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
#styles that will apply to all intences for each tag
<MDRaisedButton>:
font_size:18
<Label>:
color: 0,0,0,1
#declaring screen managers and printing them in this order
ScreenManagement:
Main_Screen:
name: "Main_Screen"
Dictionary_Screen:
name: "Dictionary_Screen"
<Main_Screen>:
Button:
text: "Dictionary"
on_release:
app.root.current = "Dictionary_Screen"
<Dictionary_Screen>:
BoxLayout:
orientation: 'vertical'
spacing: 10
padding: 50
canvas.before:
Color:
rgba: hex('#000')
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
size_hint: 0.5, 0.5
GridLayout:
rows: 3
cols: 3
padding: 10
spacing: 10
Label:
id:textFile
color: (1,0,1,1)
Data from the text file goes through a class where it get properly formatted and as you can see by the image it appears fine on screen but its all packed together and not evenly separated.
The purple text is just me hard coding the text using a label in the kv file but I plan to have more than 50 lines that I want to display and hard coding each one does not seem like the right way to go about it.
Is there a way I'm able to give each piece of text it's own label or some how even spread the text out so it appears as a list on screen?
Below is data just in case for reference.
Class module that gets imported and processes the text file
# class
class Dictionary:
# Dunder init asigns values to varibles each time code is exacuted.
def __init__(self,title,description):
self.title = title
self.description = description
def formatData(self):
print("Title: {} Description {}".format(self.title,self.description))
def placeholder(self):
return "Title: {} Description {}".format(self.title,self.description)
dict.txt
CPU,CPU_INFORMATION
RAM,RAM_INFORMATION
SOMETHING,SOMETHING_INFORMATION
I think your problem is a simple one. Try changing the line:
self.add_widget(Label(text = flipper, pos=(i*00, 100)))
to something like:
self.add_widget(Label(text = flipper, pos=(00, i*50)))
Or, if you add an id to your BoxLayout:
<Dictionary_Screen>:
BoxLayout:
id: box
Then you can use:
self.ids.box.add_widget(Label(text = flipper))
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()