ActionPrevious getting an unexpected background - python

I've made a rule in my kv for the Button class to have a specific background (provided in an image). When I created an ActionBar that contains ActionPrevious and ActionButton widgets, they both seemed to get the same background.
And I would understand that ActionButton instance got that background, since it inherits from Button and ActionItem classes, but why did the ActionPrevious get the same background? It inherits from BoxLayout and ActionItem, neither of which have anything to do with the Button class. What's the reason behind it?
Also, a side question
The ActionPrevious has a property with_previous which, when set to True, adds a clickable arrow. However, the title of the widget remains unclickable. But the docs say that this property would make the whole widget clickable. While it's not a big deal, I'd rather want the entire ActionPrevious widget background to change on press. Is it possible to achieve this?
So what I mean is that when you press the Back arrow, only the space around it and the app icon turns blue, but the text doesn't, as if it's part of a different widget.
Here is the code to visualize the question:
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.actionbar import ActionBar
Builder.load_string('''
<Button>:
background_normal: 'some_file.png'
<MenuBar>:
ActionView:
ActionPrevious:
title: "Log out"
with_previous: True
ActionButton:
text: "Settings"
''')
class MenuBar(ActionBar):
pass
runTouchApp(MenuBar())

Okay, so the truth was in the style.kv file. Basically, ActionPrevious widget has the following structure:
<ActionPrevious>:
GridLayout:
ActionPreviousButton:
GridLayout:
ActionPreviousImage:
id: prev_icon_image # the "back" arrow
ActionPreviousImage:
id: app_icon_image # the app icon
Widget:
# perhaps something to split the title from the GridLayout
Label:
id: title # the title
And the ActionPreviousButton inherits from Button, so that's why the ActionPrevious arrow part was getting that background.
Here also lies the answer to the side question. Since the clickable part is the ActionPreviousButton, and the title is kept in a Label, that is not a child of it, the text is unclickable. So to fix that, one has to create a custom class and put the Label as a child of the ActionPreviousButton.

Related

Why does resizing in kivy brings back widgets in old positions?

I'm making a game in kivy and when I close the screen (android) or try to resize the window (linux) some widgets that I've moved away from the screen return to their starting position.
I created a minimal reproducible example for that:
example.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class GameCanvas(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def start(self):
# move the label widget far away
self.children[0].pos = 10000, 10000
class Example(App):
pass
if __name__ == '__main__':
Example().run()
example.kv
GameCanvas:
<GameCanvas>:
Button:
text: 'Start Game'
size: root.width, root.height / 2
on_release: root.start()
Label:
text: 'Game Title'
size: root.width, root.height / 2
Before pressing the button:
After pressing the button:
After resizing:
As the attached images show after I press the button the label 'disappears' (moves position) but when I try to resize the Window it comes back.
Why does this happen? Also why does it happen on android as well? Does it have to do with some sort of events in kivy?
Thanks in advance!
The behavior you see is the intended behavior of the BoxLayout. The BoxLayout positions its children. So, you can move the Label, but as soon as the BoxLayout gets a chance (as in a size change event), it positions its children as intended. If you want to control the position of the children widgets, then you should use a Layout that does not position its children, perhaps a FloatLayout or RelativeLayout

Python Kivy library adding widgets

For example we created with kivy language simple BoxLayout1 that contains button1 and another BoxLayout2. When you click button1 it adds a new button in BoxLayout2 but it's written in python.
Is it possible to acces existing layout in kv language, in python code? Or only solution is writting whole window in python?
I couldn't find any info in kivy docs, maybe I've just missed something.
EDIT:
I've something like this
Kv:
<CreateWindow>:
BoxLayout:
Button:
text: "test"
on_release: root.press()
BoxLayout:
Label:
text: "Label"
Python:
class CreateWindow(Screen):
def press(self):
I want to add a new button near Label by activating press function
in python will be like this
class CreateWindow(Screen):
def press(self):
# the first box is the first child in the children list of the CreateWindow widget so
box1=self.children[0]
box2=self.children[1]
# and now you can decide which box you want to use add_widget method with
# in your case it should be
box2.add_widget(Button())

Static background in kivy

I was wondering if there is a way to get a static background in a Kivy application with a screen manager. With static, I mean that the background remains as it is, even when switching screens. I am using a .kv file for the layout. I'd guess it has something to do with the placement order within a .kv file.
Thanks!
You can use a float layout as the root widget in every screen and add to that float layout the image and the other layout in your screen, here is a code example in kv:
Screen: # Screen 1
id: Home
FloatLayout:
Image:
source: "path to the image"
BoxLayout: # Here you put your other layout
# And here the code you had
Screen: # Screen 2
id: Another Screen
FloatLayout:
Image:
source: "path to the image"
BoxLayout: # Here you put your other layout
# And here the code you had
This is the solution that I know, it might not be perfect for you, but I will leave the other options to others...
FloatLayout:
Image:
ScreenManager:
would be enough I think but be careful, if the transition of ScreenManager is ShaderTransition(or a sub-class thereof), it doesn't respect the pixels in the background, so the animation during the transition may not work properly.

Kivy text markup printing its own syntax

I was testing out Kivy's markup feature. The basic outline of my test program is there are 4 labels and a button and if the button is pressed, it changes the color of the first letter of label's text. Now, the problem is when I press the button for the first time, it changes the color of first letter of all the label's text BUT from the second press onwards, it starts adding the markup syntax in the reverse manner at the beginning of the text. This is the program:
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.lang import Builder
import string
Builder.load_string(
'''
<CLabel#Label>:
markup: True
<box>:
orientation: 'vertical'
Button:
text: 'press'
on_press: app.change()
CLabel:
id: a
text: 'abcd'
CLabel:
id: b
text: 'efgh'
CLabel:
id: c
text: 'ijkl'
CLabel:
id: d
text: 'mnop'
'''
)
class box(BoxLayout):
pass
class main(App):
def change(self):
for lol in string.lowercase[:4]:
self.root.ids[lol].text = '[color=#E5D209]{}[/color]{}'.format(self.root.ids[lol].text[0], self.root.ids[lol].text[1:])
def build(self):
return box()
if __name__ == "__main__":
main().run()
This is the output after the first press:
This is the output after the second press:
This is the output after the third press:
I hope you get the problem now. The markup syntax at the beginning of the text keeps on increasing with the number of times the button is pressed.
I thought maybe it was the loop's fault. So I removed the loop and tested with only the first widget. Same problem.
Now here's the catch- when I change the color by changing the contents of the change function like this:
def change(self):
self.root.ids.a.text = '[color=#E5D209]a[/color]bcd'
self.root.ids.b.text = '[color=#E5D209]e[/color]fgh'
self.root.ids.c.text = '[color=#E5D209]i[/color]jkl'
self.root.ids.d.text = '[color=#E5D209]m[/color]nop'
It works perfectly fine. But by doing this method, I'll have to copy paste a lot of lines. This was just a snippet of what I'm working on. The real project I'm working on has more than 15 labels and copy pasting for each and every label is tiresome. It'd be much better if it is done by a loop. It makes work short and precise.
After this, out of frustration I tried with get_color_from_hex method by this code:
self.root.ids[lol].text[0] = self.root.ids[lol].text[0].get_color_from_hex('#E5D209')
But I ended up getting an error message saying:
AttributeError: 'str' object has no attribute 'color'
I'd be really glad if someone came with a way to change the color of first letter of the text of god knows how many labels. :'(
The markup is part of the string stored in text. So the second time you run the loop, indeed the first character ([) gets inserted in between the markup tags, messing up the parsing.
What you want to do could be achieved by storing the raw text in another StringProperty, let's call it _hidden_text. Then, in the loop, you can set
self.root.ids[lol].text = '[color=#E5D209]{}[/color]{}'.format(self.root.ids[lol]._hidden_text[0], self.root.ids[lol]._hidden_text[1:])
In this way you avoid reusing the added markup.
Of course you may want to set up bindings for making the assignment _hidden_text→text automatic.
Edit:
Add this class definition:
class CLabel(Label):
hidden_text = StringProperty('')
then change the kv style for CLabel to
<CLabel>:
markup: True
text: self.hidden_text
and each use of CLabel should look like
CLabel:
id: a
hidden_text: 'abcd'

Kivy CheckBox Looks Like Solid Black Box (Not a Checkbox)

I am making a BoxLayout widget (orientation = 'horizontal') that contains three widgets inside of it, a label, a text box, and a check box.
thisRow = BoxLayout(orientation='horizontal')
l = Label(text='Enter plate 1:\n(Plate #)')
t = TextInput(text = 'this is a text box')
c = CheckBox()
thisRow.add_widget(l)
thisRow.add_widget(t)
thisRow.add_widget(c)
This produces the following widget (thisRow):
After the box is checked...
The rightmost black box is actually the checkbox, and works functionally, however there is no way for the user to know that it is in fact a checkbox. I would expect a smaller empty square in the middle, as is depicted in pictures here.
How do i get the traditional checkbox image (smaller empty square box)? Or generally, how can I make it more obvious that the box is a check box and not just an empty label?
Thank you
This is really interesting question and Malonge tried it in a good way. Right now(1.9.2-dev) there is still fixed size on CheckBox's well, call it a background. It's an image that Widget takes from atlas and changes if the state changes. Therefore until now there was no clear way how to do it. Here is an example. Soon on master there'll be CheckBox(color=[r,g,b,a]) option. Thanks ;)
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
<CheckBoxBG>:
Label:
TextInput:
CheckBox:
canvas.before:
Color:
rgb: 1,0,0
Rectangle:
pos:self.center_x-8, self.center_y-8
size:[16,16]
Color:
rgb: 0,0,0
Rectangle:
pos:self.center_x-7, self.center_y-7
size:[14,14]
''')
class CheckBoxBG(BoxLayout):pass
runTouchApp(CheckBoxBG())
Looks like the smaller check box is hidden when the background color is black. Here is an example of a red background.
It's not ideal because I do like the black background, but I can run with it for now. If anyone knows how to do this with a black background that would be great. Thank you
Alternatively, to change your checkboxes background, you can use another image from the atlas or create images and then load them:
mycheckbox= CheckBox(
background_checkbox_normal ='tlas://data/images/defaulttheme/button_disabled'
background_checkbox_down = 'my_checkboxes_checked.png'
)
In Kivy 1.9.2.dev0 (and apparently since version 1.9.0) you can change the background image of checkboxes. By default, Kivy uses for these backgrounds from the atlas*.
background_checkbox_normal = StringProperty('atlas://data/images/defaulttheme/checkbox_off') #when the checkbox is not active.
background_checkbox_down = StringProperty('atlas://data/images/defaulttheme/checkbox_on') # when the checkbox is active.
background_checkbox_disabled_normal = StringProperty('atlas://data/images/defaulttheme/checkbox_disabled_off') #when the checkbox is disabled and not active.
background_checkbox_disabled_down = StringProperty('atlas://data/images/defaulttheme/checkbox_disabled_on') #when the checkbox is disabled and active.
You can have a look here at all the attributes :
*The atlas is a package of multiple textures that reduces the number of images loaded and speedup the application loading. You have see a preview of the atlas in Python Install Folder\Lib\site-packages\kivy\data\images\defaulttheme-0.png

Categories

Resources