Witam ponownie i ponownie Kivy.
Wymyśliłem sobie, że wykrywanie czy przenoszony buton ma wywołać scroll
będę robił za pomocą collide
, a nie zwykłych warunków if czy x,y jest w strefie. Pokombinowałem i stworzyłem takiego potworka. Strefy chcę, aby były uzależnione od pozycji obiektu który ma być skrolowany, więc muszę przekazać go do buildera
. Niby tak to miało wyglądać:
class clMyScrollZone(FloatLayout):
opLay = ObjectProperty()
Builder.load_string('''<clMyScrollZone>
pos: root.opLay.pos # <- tu nie działa i wyliczenia dla zmiany pozycji
size: root.opLay.size # <- tu też nie działa i wyliczenia dla zmiany rozmiaru np 25%
canvas.after:
Clear
Color:
rgba: .7,0,0,.8
Rectangle:
pos: self.pos # tu wyliczenia dla zmiany pozycji
size: self.size # i zmiany rozmiaru np 25%
''')
i ten opLay
to przekazany inny widdżet na którym ma być narysowana strefa.
A poniżej działający potworek:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import time
from kivy.app import runTouchApp
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Color,Rectangle
from kivy.properties import BooleanProperty,ObjectProperty
from kivy.lang import Builder
from kivy.clock import Clock
class clMyScrollZone(FloatLayout):
opLay = ObjectProperty()
obPos = BooleanProperty()
def __init__(self, **kwargs): # ten init gdzie generuję string dla buildera
if kwargs['obPos']: # obPos: strefa górna czy dolna dla łapania skrola
tCol = (.9,0,0,.4) # kolor dla zaznaczenia strefy tylko tymczasowo
oLayP = kwargs['opLay'].pos
oLaySx = kwargs['opLay'].size[0]
oLaySy = kwargs['opLay'].size[1] * .25 # 25% wielkości skrolla
else:
tCol = (0,.9,0,.4)
oLayP = (kwargs['opLay'].pos[0], kwargs['opLay'].pos[1] + \
kwargs['opLay'].size[1] - (kwargs['opLay'].size[1] * .25))
oLaySx = kwargs['opLay'].size[0]
oLaySy = kwargs['opLay'].size[1] * .25
Builder.load_string(f'''<clMyScrollZone>
pos: {oLayP}
size: {oLaySx},{oLaySy}
canvas.after:
Clear
Color:
rgba: {tCol}
Rectangle:
pos: self.pos
size: self.size
''')
return super(FloatLayout, self).__init__(**kwargs)
pass # end of class clMyScrollZone
def f_move(*d):
def m_ScrollStill(*d):
print(time.time(),d[1])
return None
if koZoneUp.collide_point(*d[1].pos):
if koScrlLay.myClock is None:
koScrlLay.myClock = Clock.schedule_interval(lambda *_: m_ScrollStill(d[1],'Up'),.1)
elif koZoneDw.collide_point(*d[1].pos):
if koScrlLay.myClock is None:
koScrlLay.myClock = Clock.schedule_interval(lambda *_: m_ScrollStill(d[1],'Dw'),.1)
else:
if koScrlLay.myClock:
print('Clear Clock Object')
koScrlLay.myClock.cancel()
koScrlLay.myClock = None
x,y = d[1].pos
dx,dy = d[0].my_tDeltas
setattr(d[0], 'pos', (x-dx,y-dy))
return None
def f_addZone(*d):
koLay.add_widget(koZoneUp)
koLay.add_widget(koZoneDw)
x,y = d[1].pos
d[0].my_tDeltas = (x - d[0].pos[0],y - d[0].pos[1])
return None
def f_remZone(*d):
koLay.remove_widget(koZoneUp)
koLay.remove_widget(koZoneDw)
return None
koLay=FloatLayout(size_hint = (1,1))
# poniżej Float, ale docelowo będzie ScrollView z buttonami, które będzie można przekładać
koScrlLay = FloatLayout(size_hint = (None,None), pos=(200,200), size=(200,300))
koScrlLay.myClock = None
with koScrlLay.canvas.before:
Color(0,.2,.7,.2)
Rectangle(pos=koScrlLay.pos,size=koScrlLay.size)
koZoneDw = clMyScrollZone(size_hint=(None,None), opLay = koScrlLay, obPos=True,)
koZoneUp = clMyScrollZone(size_hint=(None,None), opLay = koScrlLay, obPos=False)
koBtn = Button(size_hint = (.3,.1), pos = (100,100))
koBtn.my_tDeltas = (None,None)
koBtn.bind(on_touch_move=f_move)
koBtn.bind(on_touch_down=f_addZone)
koBtn.bind(on_touch_up=f_remZone)
koLay.add_widget(koBtn)
koLay.add_widget(koScrlLay)
runTouchApp(koLay)
quit()
W klasie musiałem użyć init, aby odczytać dane przekazanego widdżetu
i zbudować stringa
dla buildera
.
Generalnie: jak przekazać do klasy inny widdżet, aby tam czytać jego parametry: size
i pos
. I od nich uzależnić size
i pos
tworzonego klasą obiektu?
Trochę to pokręcone. Mam nadzieję, że ktoś to pojmie i pojmie również moją potrzebę.
Dzięki i pozdrawiam
Radek Głębicki