Please I would like to change the position of a button inside the list at any index to move in the x and y coordinate, but I don't seems to get it
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color
class LandingScreen(BoxLayout):
def __init__(self, **kwargs):
super(LandingScreen, self).__init__(**kwargs)
self.buttons = [] #we will add references to all buttons here
for x in range(4):
self.buttons.append(Button(text='button ' + str(x+1), size_hint=(0.5, 0.5)))
#make a reference to the button before adding it in
self.add_widget(self.buttons[x])
self.button[2] #change postion
class SplashApp(App):
def build(self):
return LandingScreen()
if __name__ == '__main__':
SplashApp().run()
Related
My app (using kivy) needs to substitute text with widgets inside an unspecified number of buttons using iteration. I don't use kv language. Only the last button displays any content.
My app should display an unspecified number of buttons. Simplified example:
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
class Layout(Widget):
def __init__(self, app):
super().__init__()
self.layout = BoxLayout(orientation='vertical', size=Window.size)
contents = ['text1', 'text2', 'text3']
for text in contents:
button = Button(height=300, size_hint=(1, None))
button.text = text
self.layout.add_widget(button)
self.add_widget(self.layout)
class MyApp(App):
def build(self):
self.form = Layout(self)
return self.form
def on_pause(self):
return True
if __name__ in ('__main__', '__android__'):
MyApp().run()
Only instead of text buttons display images with descriptions. I change the code:
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
class Layout(Widget):
def __init__(self, app):
super().__init__()
self.layout = BoxLayout(orientation='vertical', size=Window.size)
contents = [('img1', 'text1'), ('img2', 'text2'), ('img3', 'text3')]
for img, text in contents:
button = Button(height=300, size_hint=(1, None))
button_layout = BoxLayout(orientation='vertical', size_hint=(1, 1))
label = Label(text=text)
image = Image(source=f'{img}.jpg', size_hint=(1, 1), allow_stretch=True)
button_layout.add_widget(image)
button_layout.add_widget(label)
button.add_widget(button_layout)
self.layout.add_widget(button)
self.add_widget(self.layout)
class MyApp(App):
def build(self):
self.form = Layout(self)
return self.form
def on_pause(self):
return True
if __name__ in ('__main__', '__android__'):
MyApp().run()
And only the last button displays content.
As far as I can understand, at some point Python automatically gets read of the content of the previous button. How can I prevent it? Also what is the best way to center it?
I'm not a native speaker, so sorry for bad grammar. Thank you in advance.
I have a question about kivy. Is it possible to create screens as variables? Lets say I want to create a new screen with a button inside the kivy application. Is it possible to do that? If so how could you do it??
You just have to create a Screen object that you want to create and add it to the ScreenManager:
screen = Your_Screen(name="some_name")
your_screen_manager.add_widget(screen)
Example:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class TestScreen(Screen):
def __init__(self, **kwargs):
Screen.__init__(self, **kwargs)
layout = BoxLayout(orientation="vertical")
self.add_widget(layout)
layout.add_widget(Label(text=self.name))
button = Button(text="{}: Add Screen".format(self.name))
layout.add_widget(button)
button.bind(on_press=self.add_screen)
def add_screen(self, *args):
n = len(self.manager.screen_names)
screen = TestScreen(name="screen {}".format(n))
self.manager.add_widget(screen)
self.manager.current = screen.name
# Create the screen manager
sm = ScreenManager()
sm.add_widget(TestScreen(name='screen 0'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
how do i change the text of a label to the value of the slider immediately.
this is my current code
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label``
class app(App):
def build(self):
layout = BoxLayout(orientation='vertical')
slide = Slider(min=-100, max=100,value=0)
label = Label(text=str(slide.value))
layout.add_widget(slide)
layout.add_widget(label)
return layout
app().run()
i want the answer in python
You need to create a Kivy Property and bind the slider value to an on_ event where you can then update the label's text. Here's one way to do that:
from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.properties import NumericProperty
import kivy
kivy.require('1.10.0')
class Container(BoxLayout):
slider_val = NumericProperty(0)
def __init__(self, *args, **kwargs):
super(Container, self).__init__(*args, **kwargs)
self.orientation = 'vertical'
slide = Slider(min=-100, max=100, value=0)
slide.fbind('value', self.on_slider_val)
self.label = Label(text=str(self.slider_val))
self.add_widget(slide)
self.add_widget(self.label)
def on_slider_val(self, instance, val):
self.label.text = str(val)
class app(App):
def build(self):
return Container()
app().run()
I've tried multiple different solutions for this and I'm out of idea's. I'm brand new to Kivy and still learning. I'm building a very basic memorization game. I need the buttons inside the grid to blink in a certain order. I'm confident that I can make that work, however I can't figure out how to get one of the buttons to blink. Can anyone point me in the right direction? I know I just need need it to change colors for a second and then change back.
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from random import random
import time
class MemorizeGame(GridLayout):
def __init__(self, **kwargs):
super(MemorizeLayout, self).__init__(**kwargs)
self.cols = 2
#create buttons
self.button1 = Button(text='', background_color=(0,0,1,1))
self.button2 = Button(text='', background_color=(0,1,1,1))
self.button3 = Button(text='', background_color=(1,0,1,1))
self.button4 = Button(text='', background_color=(0,1,0,1))
self.buttonList = [self.button1, self.button2, self.button3, self.button4]
#add buttons to the screen
for button in self.buttonList:
self.add_widget(button)
def blinkSquare(self):
#logic to make a square blink
class MemorizeApp(App):
def build(self):
game= MemorizeGame()
return game
if __name__ == "__main__":
MemorizeApp().run()
Here's an example of how to do it, using kivy's clock.
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.gridlayout import GridLayout
from random import random
import time
from kivy.clock import Clock
from functools import partial
def set_color(button, color, *args):
button.color = color
class MemorizeGame(GridLayout):
def __init__(self, **kwargs):
super(MemorizeGame, self).__init__(**kwargs)
self.cols = 2
#create buttons
self.button1 = Button(text='', background_color=(0,0,1,1))
self.button2 = Button(text='', background_color=(0,1,1,1))
self.button3 = Button(text='', background_color=(1,0,1,1))
self.button4 = Button(text='', background_color=(0,1,0,1))
self.buttonList = [self.button1, self.button2, self.button3, self.button4]
#add buttons to the screen
for button in self.buttonList:
self.add_widget(button)
def blinkSquare(self):
self.button1.background_color = (1, 1, 1, 1)
def reset_color(*args):
self.button1.background_color = (0, 0, 1, 1)
Clock.schedule_once(reset_color, 1)
# alternative:
# Clock.schedule_once(partial(set_color, self.button1, (0, 0, 1, 1)))
def on_touch_down(self, touch):
self.blinkSquare()
class MemorizeApp(App):
def build(self):
game= MemorizeGame()
return game
if __name__ == "__main__":
MemorizeApp().run()
This just blinks the first button, but I'm sure you can extend it to do exactly what you want.
You might find it neatest to make your own button subclass with the color reset function, rather than making a new function each time.
I want to make a game and I have chosen Kivy for my GUI, as I have written my backend in Python. I am currently using runTouchApp(appwindow) to run the application, where appwindow is a FloatLayout() object. The way I update my screen is that I run appwindow.clear_widgets() and then appwindow.add_widget(new_screen) where new_screen is the layout object which contains all other widgets.
It worked fine till now, but for some reason I can't understand the widget I add gets loaded properly (according to the cmd running in the background) but won't display till I change the screen size.
Here is a sample code:
import kivy
kivy.require('1.1.1')
from kivy.base import runTouchApp
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
appwindow = FloatLayout()
class MenuScreen():
def build(self):
bg = Image(source = 'Images/bg/bg.jpg',allow_stretch= True,keep_ratio= False)
box = BoxLayout(orientation = 'vertical')
menu_items = []
for i in range (0,4):
button = Button(text = 'Menu item no:'+str(i))
button.bind(state = checkMenuPress)
menu_items.append(button)
for button in menu_items:
box.add_widget(button)
floater = FloatLayout(size = bg.size)
floater.add_widget(bg)
floater.add_widget(box)
floater.size_hint = 1,1
return floater
class SecondScreen():
def build(self):
bg = Image(source = 'Images/bg/bg.jpg',allow_stretch= True,keep_ratio= False)
box = BoxLayout(orientation = 'vertical')
box.add_widget(bg)
return box
def checkMenuPress(button,*args):
if button.state == 'normal':
sc = SecondScreen().build()
appwindow.clear_widgets()
appwindow.add_widget(sc)
if __name__ == '__main__':
menuscreen = MenuScreen().build()
appwindow.add_widget(menuscreen)
runTouchApp(appwindow)
Okay, there are a few things wrong here. To create an app, you should subclass kivy.app.App and have it's build method return the "root" widget. Only this class needs build method: any others are redundant.
Once you have a root widget, it's just a matter of inserting and removing widgets. This is how I would approach it.
import kivy
kivy.require('1.1.1')
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.app import App
class MenuScreen(App):
floater = None
def build(self):
bg = Image(source='Images/bg/bg.jpg',
allow_stretch= True,
keep_ratio= False)
box = BoxLayout(orientation='vertical')
menu_items = []
for i in range(0, 4):
button = Button(text='Menu item no:'+str(i))
button.bind(state=self.checkMenuPress)
menu_items.append(button)
for button in menu_items:
box.add_widget(button)
self.floater = FloatLayout(size=bg.size)
self.floater.add_widget(bg)
self.floater.add_widget(box)
self.floater.size_hint = 1, 1
return self.floater
def checkMenuPress(self, button,*args):
if button.state == 'normal':
self.floater.clear_widgets()
self.floater.add_widget(SecondScreen())
class SecondScreen(FloatLayout):
def __init__(self, **kwargs):
super(SecondScreen, self).__init__(**kwargs)
self.add_widget(Image(source='Images/bg/bg.jpg',
allow_stretch=True,
keep_ratio=False))
if __name__ == '__main__':
MenuScreen().run()
Okay, so here's a quick rework of the example using Screens. It's difficult without knowing what you are trying to do, so if this does not help, try writing summary of the behavior you are looking for.
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuScreen(Screen):
"""
The Screen containing the menu
"""
def __init__(self, sm, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
self.sm = sm # Store a reference to the screen manager
bg = Image(source='Images/bg/bg.jpg',
allow_stretch= True,
keep_ratio= False)
box = BoxLayout(orientation='vertical')
menu_items = []
for i in range(0, 4):
button = Button(text='Menu item no:'+str(i))
button.bind(state=self.check_menu_press)
menu_items.append(button)
for button in menu_items:
box.add_widget(button)
floater = FloatLayout(size=bg.size)
floater.add_widget(bg)
floater.add_widget(box)
floater.size_hint = 1, 1
self.add_widget(floater)
def check_menu_press(self, button, *args):
if button.state == 'normal':
self.sm.current = "second"
class SecondScreen(Screen):
def __init__(self, sm, **kwargs):
super(SecondScreen, self).__init__(**kwargs)
self.add_widget(Image(source='Images/bg/bg.jpg',
allow_stretch=True,
keep_ratio=False))
self.sm = sm # Store a reference to the screen manager
def on_touch_down(self, touch):
self.sm.current = "menu"
class MainApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(sm, name="menu"))
sm.add_widget(SecondScreen(sm, name="second"))
return sm
if __name__ == '__main__':
MainApp().run()
looks like i have found a source of the crashing problem. I had used multi-threading for a server client interaction. i had been using two extra threads, one for the server and another for the client. If i try to integrate the client thread with the GUI it raises another problem. even if the socket.recv() is after the ScreenManager.current = "newscreen" line, the app's screen does not change. it freezes in the way i left it. it resumes only after it gets a message from the server.