Problem in hand is that i have a screen where i have created 4 widgets under gridlayout . Widget one is a custom widget which have a boxlayout and have 2 images and a button .
and other 3 widgets are simple buttons
Now i want to have a background image or coloured rectangle to the 1st widget but image is getting drawn at position 0,0 . I am trying to use canvas instructions to create a rectangle or Border Image but seems gridlayout shows the widget position as 0,0 and hence it created the rectangle at 0,0 . please see the code below :
Any ideas how to fix this and create rectangle as at the border of widget 1?
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen,FallOutTransition
from kivy.uix.image import Image
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.graphics import BorderImage
from kivy.graphics import Color, Rectangle ,Line
################# Images ######################
S = Image(source='images/Sti.png')
L = 'images/spinnin.gif'
################# Images ######################
class CButtonW(BoxLayout):
def __init__(self, **kwargs):
print "init --> CButton self.pos is ",self.pos
super(CButtonW, self).__init__(**kwargs)
self.orientation = 'vertical'
with self.canvas.before:
Color(1, 1, 0, 1, mode='rgba')
Rectangle(pos=self.pos,size=self.size)
BorderImage(
border=(10, 10, 10, 10),
source='images/tex.png')
self.add_widget(S)
self.add_widget(Button(text="Button 1"))
self.add_widget(Image(source=L))
class LevelScreen(Screen,GridLayout):
def __init__(self, **kwargs):
super(LevelScreen, self).__init__(**kwargs)
with self.canvas:
Line(points=(10, 10, 20, 30, 40, 50))
Color(1, 0, 1, 1, mode='rgba')
Rectangle(pos=self.pos, size=Window.size)
self.layout = GridLayout(cols=3,spacing=1,padding=10)
self.Button1 = CButtonW(id='1',text='Level 1')
self.Button2 = Button(id='2',text='Level 2')
self.Button3 = Button(id='3',text='Level 3')
self.Button4 = Button(id='4',text='Level 4')
self.layout.add_widget(self.Button1)
self.layout.add_widget(self.Button2)
self.layout.add_widget(self.Button3)
self.layout.add_widget(self.Button4)
LevelScreen.cols=3
LevelScreen.add_widget(self,self.layout)
print "position of 1st button is ",self.Button1.pos
print "position of 2 button is ",self.Button2.pos
# App Class
class MyJBApp(App):
def build(self):
sm = ScreenManager(transition= FallOutTransition())
sm.add_widget(LevelScreen(name='level'))
return sm
if __name__ == '__main__':
MyJBApp().run()
Your canvas instructions are drawn before the CButtonW is positioned by its layout, so at that point it's still in its default position of 0, 0.
You can fix it by adding code to reposition the instructions when the widget's position or size changes. The easiest way is to just use kv language in the first place, which will automatically create the relevant bindings, but you can also bind to pos or size in python, or use the on_propertyname events associated with their changes.
Related
I am trying to center text in kivy. I tried using halign="center" like so:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import CoreLabel
from kivy.graphics import Rectangle, Color
from kivy.core.window import Window
class MyWidget(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Window.clearcolor = (1, 1, 1, 1)
self.canvas.clear()
with self.canvas:
Color(0, 0, 0, 1)
label = CoreLabel(text="Text", font_size=50, halign="center")
label.refresh()
text = label.texture
Rectangle(size=text.size, pos=(865, 30), texture=text)
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == "__main__":
MyApp().run()
But that doesn't center the text around the given position (it is still left aligned). If I change the length of the text (and therefore its size), its position doesn't change, even though I want it to.
Try adding
label = CoreLabel(halign='center',valign='center')
It's me again, trying to understand Kivy concepts.
I have a widget with a base class of RelativeLayout containing a chessboard image displaying in a splitter. I want to display a label, and 2 buttons horizontally below the chessboard spaced a small distance away from the chessboard and still have everything resizable with splitter. I've tried numerous ways to no avail. What I currently have is this:
What I want is this: (How do I achieve it?)
Here is the code:
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.splitter import Splitter
from kivy.uix.image import Image
kivy.require('2.0.0')
class ChessBoardWidget(RelativeLayout): # FloatLayout
def __init__(self, **kwargs):
super(ChessBoardWidget, self).__init__(**kwargs)
repertoire_boxlayout = BoxLayout(orientation='horizontal')
repertoire_boxlayout.add_widget(Label(text='Repertoire for:'))
repertoire_boxlayout.add_widget(Button(text='White'))
repertoire_boxlayout.add_widget(Button(text='Black'))
chessboard_gui_boxlayout = BoxLayout(orientation='vertical')
chessboard_gui_boxlayout.add_widget(
Image(source="./data/images/chess-pieces/DarkerGreenGreyChessBoard.png", pos=self.pos,
size_hint=(1, 1), keep_ratio=True, allow_stretch=True))
chessboard_gui_boxlayout.add_widget(repertoire_boxlayout)
self.add_widget(chessboard_gui_boxlayout)
class SplitterGui(BoxLayout):
def __init__(self, **kwargs):
super(SplitterGui, self).__init__(**kwargs)
self.orientation = 'horizontal'
# Splitter 1
split1_boxlayout = BoxLayout(orientation='vertical')
split1 = Splitter(sizable_from='bottom', min_size=74, max_size=1100)
chessboard_widget = ChessBoardWidget()
split1.add_widget(chessboard_widget)
split1_boxlayout.add_widget(split1)
s3_button = Button(text='s3', size_hint=(1, 1))
split1_boxlayout.add_widget(s3_button)
self.add_widget(split1_boxlayout)
# Splitter 2
split2 = Splitter(sizable_from='left', min_size=74, max_size=1800)
s2_button = Button(text='s2', size_hint=(.1, 1))
split2.add_widget(s2_button)
self.add_widget(split2)
class ChessBoxApp(App):
def build(self):
return SplitterGui() # root
if __name__ == '__main__':
ChessBoxApp().run()
In a BoxLayout (see the documentation), you can use size_hint and size (or height, width) to adjust sizes. So, you can set the height of your Buttons, and let the Image use the remaining height of the BoxLayout:
class ChessBoardWidget(RelativeLayout):
def __init__(self, **kwargs):
super(ChessBoardWidget, self).__init__(**kwargs)
repertoire_boxlayout = BoxLayout(orientation='horizontal', size_hint=(1, None), height=30) # set height of Buttons
repertoire_boxlayout.add_widget(Label(text='Repertoire for:'))
repertoire_boxlayout.add_widget(Button(text='White'))
repertoire_boxlayout.add_widget(Button(text='Black'))
chessboard_gui_boxlayout = BoxLayout(orientation='vertical')
chessboard_gui_boxlayout.add_widget(
Image(source="./data/images/chess-pieces/DarkerGreenGreyChessBoard.png", pos=self.pos, keep_ratio=True, allow_stretch=True)) # default size_hint of (1,1) claims all of remaining height
chessboard_gui_boxlayout.add_widget(repertoire_boxlayout)
self.add_widget(chessboard_gui_boxlayout)
I am new to kivy. I have chosen a background image and i want to insert a label on it. But it shows like this.
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
class MyApp(App):
def build(self):
self.box = BoxLayout()
self.img = Image(source = 'image4.png')
self.lbl = Label(text = "Total_Wealth")
self.box.add_widget(self.img)
self.box.add_widget(self.lbl)
return self.box
[![enter image description here][1]][1]MyApp().run()
The BoxLayout automatically stacks the widgets.
If you want to put Label on top of the image, you can use FloatLayout for more control on the placement of the widgets
I have some simple code below that is just creating some rectangles with a color assigned to them, and then storing them into a FloatLayout. For some reason, the very first rectangle 'Brick' that I create, doesnt get a color, but all subsequent ones do. I have issues with my game also where when another widget collides with a brick, it updates the attributes of the brick to its left, and not itself. I think the two issues are related.
What is going on with the first instance of Brick (brick1) that is being added to the FloatLayout that it doesnt get the color created?
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.properties import NumericProperty, ReferenceListProperty
from kivy.clock import Clock
from kivy.graphics import Rectangle, Ellipse, Color
from kivy.uix.floatlayout import FloatLayout
from kivy.vector import Vector
from kivy.utils import get_color_from_hex
import random
from kivy.config import Config
Window.size = (300,600)
class Brick(Widget):
def __init__(self, xloc, yloc, **kwargs):
super().__init__(**kwargs)
with self.canvas:
self.size = (25,25)
self.x = xloc
self.y = yloc
self.pos = (self.x,self.y)
self.body = Rectangle(pos=self.pos,size = self.size)
self.c = Color(1,0,1)
class Game(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.brick_container = FloatLayout(size = (25,25))
brick1 = Brick(50,100)
brick2 = Brick(100,100)
self.brick_container.add_widget(brick1)
self.brick_container.add_widget(brick2)
self.add_widget(self.brick_container)
def update(self,dt):
self.name = 'nothing'
class MyApp(App):
def build(self):
game = Game()
Clock.schedule_interval(game.update, 1.0/60.0)
return game
if __name__ == '__main__':
MyApp().run()
You have to set the color first and then the rectangle
class Brick(Widget):
def __init__(self, xloc, yloc, **kwargs):
super().__init__(**kwargs)
self.size = (25,25)
self.pos = (xloc , yloc)
with self.canvas:
self.c = Color(1,0,1)
self.body = Rectangle(pos=self.pos,size = self.size)
According to the docs when using a Drawing Instruction, use the color set above.
Drawing instructions
Drawing instructions range from very simple
ones, like drawing a line or a polygon, to more complex ones, like
meshes or bezier curves:
with self.canvas:
# draw a line using the default color
Line(points=(x1, y1, x2, y2, x3, y3))
# lets draw a semi-transparent red square
Color(1, 0, 0, .5, mode='rgba')
Rectangle(pos=self.pos, size=self.size)
For that reason in your original code the first Brick used the color by default(white), and the others if they had the correct color.
I am getting to know with kivy's manual slowly. I need to centered image in FloatLayout ans I set up size for FloatLayout according to advice: Kivy: Image sometimes is not centered in BoxLayout . Image is now in center FloatLayout sometimes. Position image in center dependes on value of parameter orientation. Influence of parameter' value is described here:
orientation = 'horizontal' - ---> image is centered
orientation = 'vertical' -----> image isn't centered
Thank You for your help!
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.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
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(self):
img = Image(pos = (0, 0), source = 'grase40.png') # square 40x40pixels
self.add_widget(img)
with self.canvas:
Color=(1,0,0)
Ellipse(pos = (80,80), size = (40, 40))
class Title(BoxLayout):
def __init__(self,**kwargs):
super(Title, self).__init__(**kwargs)
self.orientation ='vertical'
self.scene = Scene()
self.add_widget(self.scene)
but = Button(text ='hallo', size_hint = (0.2, 1))
self.add_widget(but)
class SceneApp(App):
def build(self):
title = Title()
title.scene.create()
return title
if __name__ == '__main__':
SceneApp().run()