I am trying to display the speedometer in my MainWindow screen. Right now when i run the code, the speedometer works but it is not displayed on the MainWindow screen which i want rather it is just appearing on a normal screen. It is possible to combine class Gauge(Widget): and class MainWindow(Screen): together so that the speedometer will actually be displayed on the MainWindow?
.py file
import kivy
kivy.require('1.6.0')
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.properties import StringProperty
from kivy.properties import BoundedNumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.progressbar import ProgressBar
from os.path import join, dirname, abspath
from kivy.uix.screenmanager import Screen, ScreenManager
class WindowManager(ScreenManager):
pass
class MainWindow(Screen):
pass
class Gauge(Widget):
unit = NumericProperty(1.8)
value = BoundedNumericProperty(0, min=0, max=100, errorvalue=0)
path = dirname(abspath(__file__))
file_gauge = StringProperty(join(path, "cadran.png"))
file_needle = StringProperty(join(path, "needle.png"))
size_gauge = BoundedNumericProperty(128, min=128, max=256, errorvalue=128)
size_text = NumericProperty(10)
def __init__(self, **kwargs):
super(Gauge, self).__init__(**kwargs)
self._gauge = Scatter(
size=(1350,600),
do_rotation=False,
do_scale=False,
do_translation=False
)
_img_gauge = Image(
source=self.file_gauge,
size=(1350,600)
)
self._needle = Scatter(
size=(self.size_gauge, self.size_gauge),
do_rotation=False,
do_scale=False,
do_translation=False
)
_img_needle = Image(
source=self.file_needle,
size=(self.size_gauge, self.size_gauge)
)
self._glab = Label(font_size=self.size_text, markup=True)
self._progress = ProgressBar(max=100, height=20, value=self.value , size=(500,400))
self._gauge.add_widget(_img_gauge)
self._needle.add_widget(_img_needle)
self.add_widget(self._gauge)
self.add_widget(self._needle)
self.add_widget(self._glab)
self.add_widget(self._progress)
self.bind(pos=self._update)
self.bind(size=self._update)
self.bind(value=self._turn)
def _update(self, *args):
'''
Update gauge and needle positions after sizing or positioning.
'''
self._gauge.pos = self.pos
self._needle.pos = (self.x, self.y)
self._needle.center = self._gauge.center
self._glab.center_x = self._gauge.center_x
self._glab.center_y = self._gauge.center_y + (self.size_gauge / 4)
self._progress.x = self._gauge.x + (self.size_gauge/0.468 )
self._progress.y = self._gauge.y + (self.size_gauge/4 )
self._progress.width = self.size_gauge
def _turn(self, *args):
'''
Turn needle, 1 degree = 1 unit, 0 degree point start on 50 value.
'''
self._needle.center_x = self._gauge.center_x
self._needle.center_y = self._gauge.center_y
self._needle.rotation = (50 * self.unit) - (self.value * self.unit)
self._glab.text = "[b]{0:.0f}[/b]".format(self.value)
self._progress.value = self.value
class GaugeApp(App):
increasing = NumericProperty(1)
begin = NumericProperty(50)
step = NumericProperty(1)
def build(self):
box = BoxLayout(orientation='horizontal', padding=5)
self.gauge = Gauge(value=50, size_gauge=256, size_text=25)
box.add_widget(self.gauge)
Clock.schedule_interval(lambda *t: self.gauge_increment(), 0.05)
return box
def gauge_increment(self):
begin = self.begin
begin += self.step * self.increasing
if begin > 0 and begin < 100:
self.gauge.value = begin
else:
self.increasing *= -1
self.begin = begin
if __name__ == '__main__':
GaugeApp().run()
You need to create an instance of ScreenManager and an instance of Screen. Next you add_widget the Screen to ScreenManager and to the Screen you add box
sm = ScreenManager()
s1 = Screen()
s1.add_widget(box)
sm.add_widget(s1)
This is the complete code which uses your new classes
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import NumericProperty
from kivy.properties import StringProperty
from kivy.properties import BoundedNumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.progressbar import ProgressBar
from os.path import join, dirname, abspath
from kivy.uix.screenmanager import Screen, ScreenManager
class WindowManager(ScreenManager):
pass
class MainWindow(Screen):
pass
class Gauge(Widget):
unit = NumericProperty(1.8)
value = BoundedNumericProperty(0, min=0, max=100, errorvalue=0)
path = dirname(abspath(__file__))
file_gauge = StringProperty(join(path, "cadran.png"))
file_needle = StringProperty(join(path, "needle.png"))
size_gauge = BoundedNumericProperty(128, min=128, max=256, errorvalue=128)
size_text = NumericProperty(10)
def __init__(self, **kwargs):
super(Gauge, self).__init__(**kwargs)
self._gauge = Scatter(
size=(1350,600),
do_rotation=False,
do_scale=False,
do_translation=False
)
_img_gauge = Image(
source=self.file_gauge,
size=(1350,600)
)
self._needle = Scatter(
size=(self.size_gauge, self.size_gauge),
do_rotation=False,
do_scale=False,
do_translation=False
)
_img_needle = Image(
source=self.file_needle,
size=(self.size_gauge, self.size_gauge)
)
self._glab = Label(font_size=self.size_text, markup=True)
self._progress = ProgressBar(max=100, height=20, value=self.value , size=(500,400))
self._gauge.add_widget(_img_gauge)
self._needle.add_widget(_img_needle)
self.add_widget(self._gauge)
self.add_widget(self._needle)
self.add_widget(self._glab)
self.add_widget(self._progress)
self.bind(pos=self._update)
self.bind(size=self._update)
self.bind(value=self._turn)
def _update(self, *args):
'''
Update gauge and needle positions after sizing or positioning.
'''
self._gauge.pos = self.pos
self._needle.pos = (self.x, self.y)
self._needle.center = self._gauge.center
self._glab.center_x = self._gauge.center_x
self._glab.center_y = self._gauge.center_y + (self.size_gauge / 4)
self._progress.x = self._gauge.x + (self.size_gauge/0.468 )
self._progress.y = self._gauge.y + (self.size_gauge/4 )
self._progress.width = self.size_gauge
def _turn(self, *args):
'''
Turn needle, 1 degree = 1 unit, 0 degree point start on 50 value.
'''
self._needle.center_x = self._gauge.center_x
self._needle.center_y = self._gauge.center_y
self._needle.rotation = (50 * self.unit) - (self.value * self.unit)
self._glab.text = "[b]{0:.0f}[/b]".format(self.value)
self._progress.value = self.value
class GaugeApp(App):
increasing = NumericProperty(1)
begin = NumericProperty(50)
step = NumericProperty(1)
def build(self):
box = BoxLayout(orientation='horizontal', padding=5)
self.gauge = Gauge(value=50, size_gauge=256, size_text=25)
box.add_widget(self.gauge)
Clock.schedule_interval(lambda *t: self.gauge_increment(), 0.05)
sm = WindowManager()
s1 = MainWindow()
s1.add_widget(box)
sm.add_widget(s1)
return sm
def gauge_increment(self):
begin = self.begin
begin += self.step * self.increasing
if begin > 0 and begin < 100:
self.gauge.value = begin
else:
self.increasing *= -1
self.begin = begin
if __name__ == '__main__':
GaugeApp().run()
Related
Please I have created a kivymd app and it's running well on my android device. The app reads the names from a txt file, randomise them and group them into preferred number of groups. It works fine but I want to add functionality that users can add their own txt file into a folder created by the app after installation so that the app will read the txt file from the root folder.
Now I need a way that the app can create the folder by itself after installation. And also how the app can read txt files from that folder for the grouping.
Thanks in advance
import random
import kivymd
from kivy.animation import Animation
from kivy.app import App
from kivy.factory import Factory
from kivy.graphics.context import Clock
from kivy.uix.popup import Popup
from kivy.uix.scrollview import ScrollView
from kivy.utils import get_color_from_hex
from kivymd.app import MDApp
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.lang.builder import Builder
from kivy.properties import NumericProperty
from kivy.uix.screenmanager import Screen
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel
from kivymd.uix.list import OneLineListItem
Window.fullscreen = True
Window.maximize()
class CardOn(MDCard):
pass
class ListItems(OneLineListItem):
text = StringProperty()
class ContentNavigationDrawer(BoxLayout):
pass
class NavigationDrawerIconButton(BoxLayout):
pass
class NavigationLayout(Screen):
state = ''
my_text = "No names loaded yet"
convert_to_string = "No names loaded yet"
raw_file = open("Name.txt", "r")
read_content = raw_file.read()
class_split = read_content.split("\n")
num_of_generated_groups = StringProperty()
Shuffled_list = []
grouping_critera = StringProperty()
student_total = 0
Groups = NumericProperty(1)
hint = StringProperty()
Randomized_list = []
Created_groups = []
refined_group = StringProperty(""" """)
students_to_string = StringProperty("No names loaded yet")
my_index = NumericProperty
new_titles = StringProperty()
def group_criteria(self, value):
self.grouping_critera = value
if self.grouping_critera == "Number of groups":
self.hint = "Select desired number of groups"
elif self.grouping_critera == "Number of groups":
self.grouping_critera = "Number of groups"
else:
self.hint = "Select desired students per groups"
print(self.grouping_critera)
def group_nums(self, value):
self.Groups = int(value)
print(self.Groups)
def read_names(self):
raw_file = open("Name.txt", "r")
read_content = raw_file.read()
self.class_split = read_content.split("\n")
def create_groups(self):
self.student_total = len(self.class_split)
self.Shuffled_list = self.class_split
random.shuffle(self.Shuffled_list)
self.Groups = int(self.Groups)
if self.grouping_critera == "Number of groups":
groups_to_students = round(self.student_total / self.Groups)
self.Created_groups = [self.Shuffled_list[i * groups_to_students:(i + 1) * groups_to_students] for i in
range((len(self.Shuffled_list) + groups_to_students - 1) // groups_to_students)]
else:
self.Created_groups = [self.Shuffled_list[i * self.Groups:(i + 1) * self.Groups] for i in
range((len(self.Shuffled_list) + self.Groups - 1) // self.Groups)]
print(f"Created groups are {self.Created_groups}")
for self.i in self.Created_groups:
card = MDCard(orientation="vertical", padding="8dp", size_hint=(None, None),
size=(self.width, "10dp"),
pos_hint={"center_x": .5, "center_y": .5})
self.ids.md_list.add_widget(card)
self.num_of_generated_groups = f"{len(self.Created_groups)} Groups Generated"
self.my_index = self.Created_groups.index(self.i) + 1 # the 1 will replace the index at 0
label = MDLabel(text=f"Group {self.my_index} members = {len(self.i)} ", theme_text_color="Custom",
text_color=(1, 1, 1, 1), halign="center", font_size=30)
self.ids.md_list.add_widget(label)
for e in self.i:
self.ids.md_list.add_widget(ListItems(text=e))
def clear_screen(self):
self.ids.md_list.clear_widgets()
def generate_groups(self):
self.clear_screen()
self.create_groups()
class GroupingApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = Builder.load_string(screen_helper)
def build(self):
return self.screen
if __name__ == '__main__':
GroupingApp().run()
I want to draw image (*.png file) at FlayoutBox, on pc is result OK, after using KivyLauncher is on phone screen only white square. I tested two variants for drawing (draw_img_cnv and draw_img_wdg), but both results are bad.
Cann you explain me:
why is result white square on phone screen,
why draw_img_wdg isn't centered on pc,
how is diferent between both solutions?
Thank You!
from kivy.app import App
from kivy.graphics import Color, Rectangle, Ellipse
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.image import Image
import math
class Screen(FloatLayout):
def __init__(self, **kwargs):
super(Screen, self).__init__(**kwargs)
self.li_item = []
return
def draw_img_cnv(self):
size_img = (498, 498)
pos_img = (self.center[0] -size_img[0]/2.0, self.center[1] -size_img[1]/2.0)
with self.canvas:
Color(0, 1, 0, 1)
self.rect1 = Rectangle(size=self.size, pos=self.pos)
self. rose = Image(source="rose.png",pos=pos_img,size=size_img )
def draw_img_wdg(self):
size_img = (498, 498)
pos_img = (self.center[0] -size_img[0]/2.0, self.center[1] -size_img[1]/2.0)
with self.canvas:
Color(0, 1, 0, 1)
self.rect1 = Rectangle(size=self.size, pos=self.pos)
self. rose = Image(source="rose.png",pos=pos_img,size=size_img )
self.add_widget(self.rose)
return
class MainApp(App):
def build(self):
self.pos_sun = None
root = BoxLayout(orientation = 'vertical')
self.screen = Screen()
button = Button(text = 'Press',size_hint=(1, None), height=50)
root.add_widget(self.screen)
root.add_widget(button)
self.screen.draw_img_wdg()
self.screen.bind(size=self._update_rect, pos=self._update_rect)
return root
def _update_rect(self, instance, value):
self.screen.rect1.pos = instance.pos
self.screen.rect1.size = instance.size
self.screen.rose. pos = (instance.center[0] -498/2.0, \
instance.center[1] -498/2.0)
return
if __name__ == '__main__':
MainApp().run()
What I tried to do:
I wanted my program to print a message when it collides with the sprite in the middle.
Problem:
It doesn't stop printing that it collided. I looked into it with pdb and it says that the Player Sprite is the size of the whole screen, which is weird because I set the image size to 32px by 32px.
What it looks like
Code and Sprites mentioned
Link to mentioned block
Link to mentioned sprite
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
import random
import time
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
#############################################################################
class Collider(Image):
pass
#############################################################################
root = FloatLayout()
class GameScreen(Screen):
def __init__(self, **kwargs):
super(GameScreen, self).__init__(**kwargs)
self.wimg = Basic(size = (32,32), source='sprite.png', pos=(270,-120))
self.block = Collider(size = (32,32), source = 'block.png')
def playy(self):
root.add_widget(self.wimg)
Clock.schedule_interval(self.wimg.update, 1.0 / 60.0)
def worldgen1(self):
self.add_widget(root)
root.add_widget(self.block)
def on_enter(self):
self.worldgen1()
self.playy()
#############################################################################
class Basic(Image):
pFrame = 0
def __init__(self, **kwargs):
super(Basic, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.x -= 10
elif keycode[1] == 'right':
self.x += 10
elif keycode[1] == 'up':
self.y += 10
elif keycode[1] == 'down':
self.y -= 10
else:
return False
return True
def update(self, dt):
self.pFrame += 1
if self.parent.parent.block.collide_widget(self.parent.parent.wimg):
print ("collide with", self.parent.parent.block)
#############################################################################
class MeinApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(GameScreen(name='gameplay'))
return sm
if __name__ == '__main__':
MeinApp().run()
In this case the problem is that FloatLayout uses the size_hint to set the size of the widget when it is added, since it does not set it, they take the value of (1, 1), that is, the size of the window.
The solution is to set size_hint to (None, None), in addition to using allow_stretch in True and keep_ratio in False. In the code I have set the block pos_hint to (0.5, 0.5) and it will anchor it to that position so it will not move, if you want it to be able to move you must set the pos, not the pos_hint.
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
import random
import time
from kivy.uix.image import Image
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
#############################################################################
class Collider(Image):
pass
#############################################################################
root = FloatLayout()
class GameScreen(Screen):
def __init__(self, **kwargs):
super(GameScreen, self).__init__(**kwargs)
self.wimg = Basic(size = (32,32), pos=(200, 100), source='sprite.png', size_hint=(None, None), allow_stretch=True, keep_ratio=False)
self.block = Collider(size = (32,32), pos_hint={'x': 0.5, 'y':0.5}, source = 'block.png', size_hint=(None, None), allow_stretch=True, keep_ratio=False)
def playy(self):
root.add_widget(self.wimg)
Clock.schedule_interval(self.wimg.update, 1.0 / 60.0)
def worldgen1(self):
self.add_widget(root)
root.add_widget(self.block)
def on_enter(self):
self.worldgen1()
self.playy()
#############################################################################
class Basic(Image):
pFrame = 0
def __init__(self, **kwargs):
super(Basic, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.x -= 10
elif keycode[1] == 'right':
self.x += 10
elif keycode[1] == 'up':
self.y += 10
elif keycode[1] == 'down':
self.y -= 10
else:
return False
return True
def update(self, dt):
self.pFrame += 1
if self.parent.parent.block.collide_widget(self.parent.parent.wimg):
print ("collide with", self.parent.parent.block)
#############################################################################
class MeinApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(GameScreen(name='gameplay'))
return sm
if __name__ == '__main__':
MeinApp().run()
In the following code i don't explain two problems:
If I use method __init__ --> Scene.canvas = None
I don't underestand to relative position objects on image.
I wanted to obtain knowledges about coordinates system from Kivy Manual, but without success.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.image import Image
from kivy.graphics import Ellipse
class Scene(Widget):
"""
def __init__(self):
self.x = 0
self.y = 100
self.dir = 1
"""
def set_par(self):
self.x = 0
self.y = 100
self.dir = 1
def create_ball(self):
with self.canvas:
Ellipse(pos = (0,0), size = (40, 40))
img = Image(pos = (0,0), source = 'image1.png') # square 40x40pixels
self.add_widget(img)
class SceneApp(App):
def build(self):
scene = Scene()
scene.create_ball()
return scene
if __name__ == '__main__':
SceneApp().run()
Printscreen form my code:
You did not call super() in your __init__ method. So Widget's __init__ method just get completely overrited.
Then use FloatLayout instead of Widget
You can to do something like this:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Ellipse
Window.size = (300, 300)
class Scene(FloatLayout):
def __init__(self, **kwargs):
super(Scene,self).__init__(**kwargs)
self.size = 300,300
def create_ball(self):
img = Image(pos = (-130, -130), source = 'image1.png') # square 40x40pixels
self.add_widget(img)
with self.canvas:
Ellipse(pos = (0,0), size = (40, 40))
class SceneApp(App):
def build(self):
scene = Scene()
scene.create_ball()
return scene
if __name__ == '__main__':
SceneApp().run()
I am new to kivy.In the below code, Once the login successfull, I am unable to move from login screen to MenuScreen (self.parent.current = MenuScreen()).
How to fix this?.
from kivy.app import App
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.popup import Popup
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.labelUsername = Label(text='User Name : ',pos = (200,300))
self.add_widget(self.labelUsername)
self.inputUser = TextInput(pos = (300,340), multiline=False,height=40,width = 150)
self.add_widget(self.inputUser)
self.labelPassword = Label(text='Password :',pos = (200,250))
self.add_widget(self.labelPassword)
self.inputPasswd = TextInput(pos = (300,280), height=40,width = 150,password=True, multiline=False)
self.add_widget(self.inputPasswd)
self.btnLogin = Button(text = 'Login',pos = (320,230),width = 100,height = 30 )
self.add_widget(self.btnLogin)
self.btnLogin.bind(on_press=self.get_user_passwd)
def get_user_passwd(self,*args):
username, passwd = self.inputUser.text,self.inputPasswd.text
if username == passwd:
self.parent.current = MenuScreen()
else:
pop_up = Popup(title="username and password should be the same.", size_hint=(.3, .3))
pop_up.open()
class MenuScreen(BoxLayout):
def __init__(self,*args):
l = BoxLayout(cols="2")
btn = Button(text="ad")
l.add_widget(btn)
print "flag"
class MyApp(App):
def build(self):
screen_manager = ScreenManager()
#screen_manager.add_widget(LoginScreen(name='LoginScreen'))
#screen_manager.add_widget(MenuScreen(name='menu'))
return LoginScreen()
if __name__ == '__main__':
MyApp().run()