How to position Kivy Popup with absolute coordinate? - python

How do you disable relative position for a Kivy Popup object? For example, how would you define absolute pos for this example?:
from kivy.uix.popup import Popup
from kivy.uix.label import Label
popup = Popup(title='Test popup', content=Label(text='Hello world'),
size_hint=(None, None),
#pos_hint=None, pos_hint=(None, None), pos_hint={},
size=(200,200), pos=(10, 10))
popup.open()
Notice if the pos_hint attempts are uncommented, it fails either because pos_hint mustn't be null, cannot be a tuple, or simply has no effect (the popup is always centered vertically and horizontally). Notice also that the custom size does work.

Since pos_hint works well you can always do: ("10.0" is the absolute coordinate )
popup = Popup(title='Test popup', content=Label(text='Hello world'),
size_hint=(None, None),
pos_hint={'x': 10.0 / Window.width,
'y':10.0 / Window.height},
size=(200,200), #pos=(10, 10),
)
The only problem here is that you'll have to update the pos_hint on a re-size event

pos_hint should be a dict, not a tuple, so probably pos_hint={} or pos_hint=None will work (but I'm not sure which).

Related

No effects on size_hint , python, kivy

I try to change the size_hint of a button in Python, Kivy, but every value i put there the size of the button remain the same.. for the pos is changing but for the size_hint no, and if i change from pos to pos_hint the button is stuck in the corner of the window and from there i cant change nothing... also i tried to stick the pos of the button on a position where is a text in the photo but every time when i resize the kivy window the button and image are changing theyr position.. how i can solve this probelm ?? THANKSSS !!
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.button import Button
from random import choice
class MyImage(Image):
images = ["Q1.png", "Q2.png", "Q3.png"] # ........
def __init__(self, **kwargs):
super().__init__(**kwargs)
correct = Button(pos=(200, 200), size_hint=(.1, .1), on_release=self.random_image, background_color=(1, 1, 1, 0.2))
self.add_widget(correct)
self.random_image()
def random_image(self, *_):
self.source = choice(self.images)
class RandomQuestionApp(App):
def build(self):
return MyImage()
randomApp = RandomQuestionApp()
RandomQuestionApp().run()
Try size instead of size_hint.
correct = Button(
pos=(200, 200),
size=(100, 100),
on_release=self.random_image,
background_color=(1, 1, 1, 0.2)
)
size : This is for static sizing of widgets and takes two arguments
i.e. (width, height). Default size of the button = (100, 100).
size_hint : This is for dynamic sizing of the button and provide hint
of size. It contains two arguments i.e. width and height it can be
floating values.By default, all widgets have their size_hint=(1, 1).
If there is nothing that influences the button size, your dynamics won't do anything. Size on the other hand would define a fixed size of the button where 100x100 is the default.

Kivy ScrollView with over lapping layouts

I am trying to draw 10 images on the screen, then draw 10 more images (of the same size and shape) over them, in the same locations. This is fine but I also want it all the be scrollable but I get the error Exception: ScrollView accept only one widget
This is my code:
root = ScrollView(size_hint=(1,1), scroll_wheel_distance=40)
layout1 = GridLayout(cols=2, spacing=0, size_hint=(1, None), row_force_default=True, row_default_height=270)
layout1.bind(minimum_height=layout1.setter('height'))
for i in range(10):
img = Image(source=UI_bottom_path, size_hint_y=1, allow_stretch=True)
layout1.add_widget(img)
layout2 = GridLayout(cols=2, spacing=0, size_hint=(1, None), row_force_default=True, row_default_height=270)
for i in range(10):
img = Image(source=UI_top_path, size_hint_y=1, allow_stretch=True)
layout2.add_widget(img)
root.add_widget(layout1)
root.add_widget(layout2)
self.add_widget(root)
If I comment out "root.add_widget(layout2)" it works fine but doesn't draw the images.
This is how it currently looks:
This is how each should look:
Is there a way to get ScrollView and have the layers on top of each other?
Like your error says, ScrollView accepts only one widget. When you commented out "root.add_widget(layout2)" Scrollview has only one widget and that is why it works.
So you can add only one layout to Scrollview like BoxLayout or GridLayout and add the images to the same layout.
And please add your complete code and then we can show an example.

kivy listitem button with checkbox position

I would like to have a list item button with at the right a checkbox.
At the moment I have the checkbox in the center and the list item button text also in the center, so both widgets are mixed
How can I shift the checkbox at the right side ?
My class code :
class AttendanceListButton(FloatLayout, ListItemButton, CheckBox):
root = FloatLayout()
b1 = ListItemButton(pos_hint={'left': 1, 'center_y': .5}, size_hint=(None, None))
b2 = CheckBox(pos_hint={'right': 1 , 'center_y': .5}, size_hint=(None, None))
root.add_widget(b1)
root.add_widget(b2)
Thank you in advance!
I don't quite get what you're asking but I know that ListView is now depreciated and replaced with RecycleView

Ignore area in ScrollView for scrolling interactions

Assume I have this UI adapted from the ScrollView example:
from kivy.app import App
from kivy.uix.slider import Slider
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
class ScrollViewApp(App):
def build(self):
layout = GridLayout(cols=1, padding=10, spacing=10,
size_hint=(None, None), width=500)
layout.bind(minimum_height=layout.setter('height'))
for i in range(15):
blt = BoxLayout(size_hint=(None, None), size=(480, 40))
blt.add_widget(Label(text="Slider %d" % i))
btn = Slider(value=i, min=0, max=42, size=(400, 40),
size_hint=(None, None))
blt.add_widget(btn)
layout.add_widget(blt)
scroll = ScrollView(size_hint=(None, None), size=(500, 320),
pos_hint={'center_x': .5, 'center_y': .5}, do_scroll_x=False)
scroll.add_widget(layout)
return scroll
if __name__ == '__main__':
ScrollViewApp().run()
Due to scroll_timeout, interactions with the Sliders are delayed. Is it possible to define areas in the ScrollView in which touch events are just passed through to children without the delay (and without initiating a scroll)?
Have a look at Widget touch event bubbling.
I've never had to do the same thing as you but maybe you could create a custom class that inherits ScrollView and override on_touch_down event where you could:
Disable scroll
Call super.on_touch_down
Enable scroll.
Another way might be creating a custom widget that inherits Slider class that the user clicks. Then overload it's on_touch_down method with return True. Documentation says:
In order to stop this event bubbling, one of these methods must return True
ScrollView also fires on_scroll_start event so maybe you could do something similar there.
I came up with a simple override of ScrollView's on_touch_down, which so far seems to satisfy my needs. The idea is to test whether a touch event falls into an 'exclusion zone' (in the example below only the x dimension is checked, but it'd be trivial to extend this to arbitrary rectangular areas). If it does fall into that exclusion zone, the on_touch_down event will be dispatched to the ScrollView's children. If a child captures it, the event is swallowed. In all other cases, super.on_touch_down will be called, i.e. normal scroll behaviour is initiated. That has the benefit of still being able to scroll if the touch does not land on a Slider (in the question's example).
class MSV(ScrollView):
x_exclusion_lower = NumericProperty(None, allownone=True)
x_exclusion_upper = NumericProperty(None, allownone=True)
x_exclusion = ReferenceListProperty(x_exclusion_lower, x_exclusion_upper)
def on_touch_down(self, touch):
pos_in_sv = self.to_local(*touch.pos)
if (self.x_exclusion_lower is not None or self.x_exclusion_upper is not None) and (self.x_exclusion_lower is None or self.x_exclusion_lower <= pos_in_sv[0]) and \
(self.x_exclusion_upper is None or self.x_exclusion_upper >= pos_in_sv[0]):
touch.push()
touch.apply_transform_2d(self.to_local)
if self.dispatch_children('on_touch_down', touch):
return True
touch.pop()
super(MSV, self).on_touch_down(touch)

Anchor a label to the corner?

In Kivy:
from kivy.app import App
from kivy.uix.label import Label
class TestApp(App):
def build(self):
label = Label(text="TEST")
return label
TestApp().run()
My label is centred in the window:
How can I instead anchor my label to the bottom right corner of the window?
You'd think
label.halign = 'right'
label.valign = 'bottom'
would do the trick, but as the Label documentation points out,
The valign property will have no effect and halign will only have an effect if your text has newlines; a single line of text will appear to be centered even though halign is set to left (by default).
It looks like adding the label to an AnchorLayout, then shrinking the size of the label relative to its parent widget, together achieves what I want.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.anchorlayout import AnchorLayout
class TestApp(App):
def build(self):
anchor_layout = AnchorLayout(anchor_x='right', anchor_y='bottom')
label = Label(text="TEST")
label.size_hint = (0.1, 0.1)
anchor_layout.add_widget(label)
return anchor_layout
TestApp().run()
Produces:
Set the Label's text_size to its size, e.g. in kv text_size: self.size. The text_size controls the bounding box within which text is wrapped.

Categories