Strefy włączające scroll

0

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

0

Hmm nie wiem co tu zrobiłem inaczej, ale działa.
Tylko wycinek:

class clMyButton(Button):
	opLay = ObjectProperty()
	Builder.load_string("""<clMyButton>
	text: str(root.opLay.size)""") # możemy czytać rozmiar tego testowego layouta
	pass

koTst = FloatLayout(size_hint=(None,None), size=(20,20)) # jakiś testowy layout, aby tylko odczytać z niego rozmiar
koBtnCh = clMyButton(size_hint=(.3,.1),pos = (10,10), opLay = koTst)

koLay = FloatLayout(size_hint=(1,1))


koLay.add_widget(koBtnCh)

runTouchApp(koLay)
quit()

Sam sobie odpowiedziałem. Może się komuś przyda.

Pozdrawiam
Radek Głębicki

1 użytkowników online, w tym zalogowanych: 0, gości: 1