Follow up to Colorbox example

26 views
Skip to first unread message

Dan Moormann

unread,
Sep 12, 2023, 11:37:33 PM9/12/23
to Kivy users support
Thought I'd start a new conversation as the other one was getting quite long.

I was able to successfully run the ColorBox example Eliot sent me earlier and am trying to incorporate it into my app. 

The problem that I'm running into is that the draw_recs routine (click on draw line rect)  displays the requested data, but it pushes everything up and off the screen.  I stopped it after the first 2 widgets (line 267) trying to get a handle on it.  I guessed I needed to use screenmanager but got it all messed up and broke everything.  I commented out all the screenmanager stuff and got it working again, but the roll up still happens.

I thought FloatLayout allows me put stuff anywhere.

I'll try to figure out screenmanager later, unless you can provide some guidance.

Enclosed is my code:

#:kivy 1.0.9

#WindowManager:
# ColorBox:
# ScatterTextWidget:

<ColorBox>:
name:'cbox'

canvas:
Color:
rgb: root.color
Line:
rectangle: (*self.pos, *self.size)
#
# FloatLayout:
# color: ColorProperty()

<ScatterTextWidget>:

orientation: 'vertical'
id: 'Main'
name: 'Main'
effect_cls: 'ScrollEffect'

Label:
id: titl
name: 'titl'
text: 'Enter Text - Version: '+kivy.platform
size_hint_y: None
height: dp(50)
font_size: sp(20)
pos: 0,550
background_color: 0,255,255,1 #'aqua'

TextInput:
id: txti
name: 'txti'
size_hint_y: None
height: dp(50)
font_size: '25sp'
pos: 0,500
focus: True
on_text: helo.text = self.text #change helo to match txti entered
background_color: 128,128,128,1 #gray

AnchorLayout: # use to center the row of buttons
id: anch
name: 'anch'
BoxLayout: # hold the row of buttons in a horizontal layout
id: boxl
name: 'boxl'
size_hint_y: None
height: dp(70) # set the height of the buttons
spacing: dp(5) # set spacing between the buttons
padding: dp(5) # padding around the outside of the buttons

Button:
id:lsiz
name: 'lsiz'
text: " Press\n to\ndisplay"
on_press: root.Listsizes(0)
on_release: root.set_focus()
background_color: 0,255,0,1 #green
color: 'black' #text color

Button: #list sizes to file
id: lfil
name: 'lfil'
text: "Press\n to\n file"
on_press: root.Listsizes(1)
on_release: root.set_focus()
background_color: 0,0,255,1 #blue
color: 'black'

Button: #clear
id: clea
name: 'clea'
text: 'Clear'
on_press: root.clear_it()
background_color: 255,0,0,1 #red
color: 'black'

Button: #drat
id: drat
name: 'drat'
text: "Draw\nTurtle"
on_press: root.drawit()
on_release: root.set_focus()
background_color: 128,0,128,1 #'purple'
color: 'black'

Button: #dral
id: dral
name: 'dral'
text: "Draw\nLine\nRect"
on_press: root.draw_recs()
on_release: root.set_focus()
background_color: 128,0,128,1 #'purple'
color: 'black'

Button: #mode
id: mode
name: 'mode'
text: 'Mode\n'+root.xltxt
on_press: root.set_mode()
on_release: root.set_focus()
background_color: 255,255,0,1 #yellow
color: 'black'

Button: #xtest
id: test
name: 'test'
on_press: root.xtest()
text: 'xtest'
background_color: 128,128,128,1 #grey
color: 'black'


Label: #widget display text
id: disp
name: 'disp'
font_name: root.xfontname
font_size: 14
size_hint_y: None
size: 800,375
pos: 0,0
background_color: 255,255,0,1 #yellow
color: 'yellow'

RelativeLayout:
id: rela
name: 'rela'
gid: rela
size_hint: None, None # use a relative layout so the position of the scatter widget is honored
size: 0, 0 # make the size zero so the Layout does not take any space

TextInput:
id: txt2
name: 'txt2'
size_hint: None,None
size: 100,30
pos: 5,100
text: 'txt2'
background_color: 255,255,255,1 #white

Label:
id:lab2
name: "lab2"
size_hint: None,None
size: 75,30
pos: 5,122
text: 'lab2'
background_color: 255,255,255,1 #white

Scatter:
id: scat
name: 'scat'
gid: scat
size_hint: None, None
size: helo.texture_size # make the Scatter the same size as the text "Hello!"
pos: disp.center_x - helo.width/2, disp.top-helo.height
#pos: 0,60
background_color: 0,255,0,1 #'lime'

Label: #hello
id: helo
name: 'helo'
text: "Hello!"
size_hint: None, None
size: scat.size
#pos: disp.center_x - helo.width/2, disp.top-helo.height
pos: 0,0
font_size: 50
color: 'teal'
background_color: 0,128,128,1 #'teal'
#on_touch_down: print('dn',int(scat.pos[0]),int(scat.pos[1]),end=' ')
#on_touch_up: print('up',int(scat.pos[0]),int(scat.pos[1]))

ScrollView:
id: scrv
name: 'scrv'
size_hint: None,None
#size: 257,340 #hard coded to emulated width of Samsung S23 (1080/4.2)
scroll_type: ['content']
do_scroll_y: True
font_size: 14
scroll_y: 1 #top of scrollview

Label:
id: scro
name: 'scro'
font_size: 12
size_hint: None,None
size: scrv.size
font_name: root.xfontname
height: self.texture_size[1]
#pos: 257,340
background_color: 255,255,0,1 #yellow
color: 'yellow'


from kivy.config import Config
import os
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty
#from kivy.properties import ColorProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.utils import platform
from kivy.core.window import Window
from webcolors import rgb_to_name
#from PIL import Image
from kivy.graphics import Line
from kivy.uix.floatlayout import FloatLayout
#from kivy.graphics import Rectangle
#from kivy.graphics import *
from PIL import ImageGrab
from kivy.core.text import Label as CoreLabel
from kivy.clock import Clock
import kivy.core.text
from inspect import currentframe, getframeinfo
from kivy.graphics import *
from kivy.uix.popup import Popup
from kivy.properties import ColorProperty
from kivy.uix.screenmanager import ScreenManager, Screen

import win32gui
hwnd = win32gui.GetForegroundWindow()
win32gui.MoveWindow(hwnd, 1380,50,816,639,True) #move console output to monitor 1

xmode= 'W' # Win/Emulate/Android
xx600=Window.height
xx300=xx600/2
xx800=Window.width
xx400=xx800/2

class ScatterTextWidget(BoxLayout):
print('STW')
#background_color = ColorProperty() # The ListProperty will also work.
xltxt = "Windows"
if platform == 'android':
xmode="A"
from android.storage import primary_external_storage_path
dir = primary_external_storage_path()
xfontname=os.path.join(dir,'/system/fonts/DroidSansMono.ttf')
xxfile = os.path.join(dir, 'Download') + '/Crash.txt'
else:
xfontname='C:/Windows/Fonts/Courbd'
xxfile = os.path.join(os.path.expanduser("~"), "Downloads") + '\\Crash.txt'
xtfile = os.path.join(os.path.expanduser("~"), "Downloads") + '\\turtle.png'
xmode='W'
#class end scattertextwidget

def __init__(self, **kwargs):
print('init')
super(ScatterTextWidget, self).__init__(**kwargs)
#self.save_initial_pos_size('init')
return

def on_kv_post(self, base_widget):
#self.save_initial_pos_size('kvpost')
Clock.schedule_once(self.after_post) # provide another clock tick...

def after_post(self, dt):
self.save_initial_pos_size('afterpost')

def save_initial_pos_size(self,xcaller):
#self.print_it(xcaller)
self.xihp = self.ids.helo.pos
self.xihs = self.ids.helo.size
self.xisp = self.ids.scat.pos
self.xiss = self.ids.scat.size
return

# def spot_it(self):
# label=Label(text='+',pos=(100,100))
# label.add_widget(Label)
# return

# def print_it(self, xcaller):
# # print(self.ln(),xwho,'scat',self.ids.scat.pos,self.ids.scat.size)
# # print(self.ln(),xwho,'helo',self.ids.helo.pos,self.ids.helo.size)
# print(self.ln(), 'scrv', self.ids.scrv.pos, self.ids.scrv.size,
## 'scro', self.ids.scro.pos, self.ids.scro.size,
# 'scat', self.ids.scat.pos, self.ids.scat.size,
# 'helo', self.ids.helo.pos, self.ids.helo.size, xcaller)
# return

def clear_it(self):
for i in range(2):
self.ids.scat.pos = self.xisp # reset to initial scat.pos/size/scale/rotation
#self.ids.scro.size_hint_y=None
if self.xmode!='W':
self.ids.scat.pos=64,341
#self.ids.spot.pos=self.ids.scat.pos
else:
self.ids.scat.pos=self.xisp
self.ids.scat.size = self.xiss
self.ids.scat.scale = 1
self.ids.scat.rotation = 0
#self.ids.scro.size= 257,0

self.ids.helo.pos = self.xihp # reset helo
self.ids.helo.size = self.xihs
self.ids.helo.text = 'Hello!'

#self.ids.disp.text = ''
self.ids.scro.text = ''
self.ids.txti.text = ''

Config.set('input', 'mouse', 'mouse,disable_multitouch')
#print('config',i)
return # clear_it
def set_focus(self):
if platform == "win": #so the keyboard on mobile doesn't pop
self.ids.txti.focus = True
return #set_focus

def set_mode(self):
if self.xmode=="A": #leave everything alone
return
if self.xmode=="E": #switch to Windows mode
Window.size= (xx800,xx600)
self.ids.disp.font_size = 14
self.xmode = "W"
self.xltxt='Windows'
else: #switch to Emulate mode
self.xresize = 4.2
x=self.xresize
Window.size = (1080 / x, 2340 / x) # 1080x2340 samsung s23 result 257x557
#self.ids.disp.font_size = 8
self.xmode='E'
self.xltxt='Emu\nlate'
self.ids.mode.text='Mode\n '+self.xltxt
self.ids.disp.background_color = 255, 255, 0, 1 # yellow
#self.ids.disp.text=str(self.ids.disp.background_color)+' '+str(self.ids.disp.font_size)
self.clear_it()
return #set_mode

def ask_it(self,xtxt,xlen,xx,yy):
self.ids.lab2.text=xtxt
self.ids.txt2.size=(xlen,30)
self.ids.txt2.pos=(xx,yy)
self.ids.lab2.pos=(xx,yy+22)

#gotta catch whatever is input before proceeding

print(self.ids.txt2.text)


def xtest(self):
print('xtext pop')
#lab2 size(75,30) pos(5,122)
#txt2 size(100,30) pos(5,100)
print(self.ids.txt2.focus)
self.ids.lab2.text='test'
self.ids.txt2.text=''
self.ids.txt2.focus = True
print(self.ids.txt2.focus)

self.ask_it('test2',200,200,200)


#RootBoxLayout()
#MessagePop.open()
return

#put text anywhere
self.ids.txt2.background_color=(255,0,0,1) #red
#self.ids.txt2.pos=200,200

#self.draw_recs()

#x=self.get_widget_colors('name')
#print(x)

#self.set_mode() #calls clear_it

#self.ids.disp.text='Test!'
return #xtest
#
def get_widget_colors(self,name_num):
#xcfile = 'c:/Users/danm9/Crash/colorcodes.txt'
#xcfile = os.path.join(os.path.expanduser("~"), "Downloads") + '\\colorcodes.txt'
#read file and set up array
#with open(xcfile) as f:
# xa=[]; xb=[] ; xc=[] ; xcc=[] ; xnn=[] #setup empty array
# for line in f:
# x= line.strip('\n').split("*")
# xa.append(x[0].rstrip()) ; xb.append(x[1].rstrip()) ; xc.append(x[2].rstrip())
xa = [0, 0, 0, 1], [0, 0, 255, 1], [0, 0, 128, 1], \
[0, 128, 128, 1], [0, 128, 0, 1], [0, 255, 0, 1], \
[0, 255, 255, 1], [128, 0, 0, 1], [128, 0, 128, 1], \
[128, 128, 0, 1], [128, 128, 128, 1], [192, 192, 192, 1], \
[255, 0, 0, 1], [255, 0, 255, 1], [255, 255, 0, 1], \
[255, 255, 255, 1]

xb = [0, 0, 0], [0, 0, 1], [0, 0, .5], \
[0, .5, .5], [0, 1, 0], [0, 1, 0], \
[0, 1, 1], [.5, 0, 0], [.5, 0, .5], \
[.5, .5, 0], [.5, .5, .5], [.75, .75, .75], \
[1, 0, 0], [1, 0, 1], [1, 1, 0], \
[1, 1, 1]

xc = "black", "blue", "navy", \
"teal", "green", "lime", \
"aqua", "maroon", "purple", \
"olive", "gray", "silver", \
"red", "fuchsia", "yellow", \
"white"
xcc=[] ; xcn=[] #setup empty array
#print('xa',len(xa),type(xa))
#print('xb',len(xb),type(xb))
#lookup funtion
for widget in self.walk():
#print(self.ln(),widget.name)
xlook = [255, 255, 255, 1] # default to white (no background_color)
if hasattr(widget, 'background_color'): # build the color list
xlook = widget.background_color # s/b x,x,x,1
#print(self.ln(),xlook,widget.name)
for i in range(len(xa)):
if str(xa[i]) == str(xlook):
#print(self.ln(),'hit',xc[i])
xcc.append(xb[i]) #3 dig color numbers from table
xcn.append(xc[i]) #color names from table

#print(self.ln(),xb)
#print(self.ln(),len(xcc),xcc)
#print(self.ln(),len(xcn),xcn)
return xcn if name_num=='name' else xcc # 3 digit color codes or color name

def draw_recs(self):
xxx=self.get_widget_names()
xxx.remove('Main')
xxn=self.get_widget_colors('num')
xxc=self.get_widget_colors('name')

#xxc.remove('white')
xpos = [self.ids[idx].pos for idx in xxx] #
xsiz = [self.ids[idx].size for idx in xxx] #
#print(xxx)
#print(xxc)
i=0 #index number from pos, size
for x in xxx: #run through widget names
x1 = xpos[i] #break out x and y values for pos
xx1=x1[0]
xy1=x1[1]
x2 = xsiz[i] #break out x and y values for size
xx2=x2[0]
xy2=x2[1]
#sm.switch_to(dscreen)
with self.canvas:
print(self.ln(),i,xxx[i],xxn[i],int(xx1),int(xy1)
,int(xx2),int(xy2))
box = ColorBox(color=xxn[i],
pos=(xx1, xy1),
size_hint=(None, None),
size=(xx2,xy2))
self.add_widget(box)
self.add_widget(Label(text=xxx[i],
pos=(xx1 , xy1),
size_hint=(None, None),
size=(xx2, xy2)))

#self.canvas.add(rect)
i+=1 #increment for next widget
if i==2:
return

def ln(self): #current line number
frameinfo = getframeinfo(currentframe().f_back)
return str(frameinfo.lineno)+':'

def get_widget_names(self):
xxx=[]
for widget in self.walk():
xxx.append(widget.name) #build the name list
return xxx #get_widget_name

# def old_get_widget_colors(self,xname_num):
# #ooo
# xxc=[]
# for widget in self.walk():
# if hasattr(widget,'background_color'): #build the color list
# x4=widget.background_color #s/b x,x,x,1
# if xname_num=='name':
#
# for i in range(3): #fix 1,1,0,1 yellow
# if x4[i]==1:
# x4[i]=255
# x5=rgb_to_name(x4)
# else:
# x5='white'
# xxc.append(x5)
# return xxc #get_widget_colors

def build_lxx(self,xline_in):
#print(self.ln(),' 1 2 3 4 5 6 7')
#print(self.ln(),'1234567890123456789012345678901234567890123456789012345678901234567890')
xfirst_half=' '+xline_in[:32]
xwname=xline_in[:5]
if xwname=='Outpu' and self.xmode!='W': #clean off Outp as if it's a widget name
xwname=''
xsecond_half=xline_in[33:]
self.lxx= self.lxx+ xline_in+'\n' #entire line
self.lxx1=self.lxx1+xfirst_half+'\n' #first half of line
self.lxx2=self.lxx2+xwname+' '+xsecond_half+'\n' #second half
return

def Listsizes(self,xf): #0=list, 1=file
self.lxx=''
self.lxx1=''
self.lxx2=''
self.ids.disp.font_size = 14
# xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
self.build_lxx(' ----pos- --size-- -------- hints -------')
self.build_lxx(' acr up wid hig parent color posx posy sizx sizy')
# 1 2 3 4 5 6
# 12345678901234567890123456789012345678901234567890123456789012
#self.ids.disp.font_size=12
xxx = self.get_widget_names()
xxx.remove('Main')
xxc = self.get_widget_colors('name')
#xxc.remove('white')
xparent = [self.ids[idx].parent.name for idx in xxx]
xppos = [self.ids[idx].parent.pos for idx in xxx]
xpsiz = [self.ids[idx].parent.size for idx in xxx]
xpos = [self.ids[idx].pos for idx in xxx]
xsiz = [self.ids[idx].size for idx in xxx]
#print(self.ln(),len(xxx),xxx)
#print(self.ln(),len(xxc),xxc)
#print(self.ln(),len(xparent),xparent)
#print(self.ln(),len(xppos),xppos)
#print(self.ln(),len(xpsiz),xpsiz)
#print(self.ln(),len(xpos),xpos)
#main requires seperate approach
self.build_lxx(self.pull_out('main', self.pos, self.size,' ',(0,0),(0,0),''))
i=0
for x in xxx:
# pass in tuples and parent
#print(self.ln(),i,xxx[i],xxc[i])
self.build_lxx(self.pull_out(x,xpos[i],xsiz[i],xparent[i],xppos[i],xpsiz[i],xxc[i]))
i+=1
if xf==1:
file1 = open(self.xxfile,'w+')
self.build_lxx("Output in <downloads> Crash.txt") #+self.xxfile)
file1.write(self.lxx)

self.ids.disp.color='yellow'
if self.xmode!='W': #send output to scroll
self.ids.scro.font_size=12
self.lxx=self.lxx1+'\n'+self.lxx2+'\n'
self.ids.scro.text=self.lxx
self.ids.scrv.size=257,328
else:
self.ids.scrv.size=800,320
self.ids.scro.text = self.lxx

return #listsizes

def pull_out(self,xname,x_pos, x_siz,x_parent,x_ppos,x_psiz,x_color):
#dont need to use unpack as cannot unpack scatter
x1, xx1 = x_pos[0],x_ppos[0]
y1, xy1 = x_pos[1],x_ppos[1]
x2, xx2 = x_siz[0],x_psiz[0]
y2, xy2 = x_siz[1],x_psiz[1]
xr="{0:5.0f}{1:5.0f} {2:5.0f}{3:5.0f}"
xy=xr.format(x1,y1,x2,y2)
xy=xname+xy #add name of widget to beginneing of line
xy=xy+' ' +x_parent
if xname=="main":
#preserve values for calculating hints - nothing to output for main
global xarc,xup,xwid,xhig,m_wid,m_hig
xarc, xup, xwid, xhig = x1,y1,x2,y2
m_wid, m_hig = xwid, xhig
else:
#calculate hints
xy=xy+' '+self.calc_pos_size(x1,y1,x2,y2,xx1,xy1,xx2,xy2,x_color)
#xy=xy+' '+x_color
return xy #pull_out

def calc_pos_size(self,acr,up,wid,hig,p_acr,p_up,p_wid,p_hig,xcolor):
pos_x= 0 if p_wid==0 else acr/p_wid
pos_y= 0 if p_hig==0 else up/p_hig
if pos_y > 1:
pos_y=(up-p_up)/p_hig
siz_x= 0 if p_wid==0 else wid/p_wid
siz_y= 0 if p_hig==0 else hig/p_hig
xr="{0:6}{1:5.2f} {2:5.2f} {2:5.2f} {2:5.2f}"
#print(self.ln(),xcolor,int(pos_x),int(pos_y),int(siz_x),int(siz_y))

xy=xr.format(xcolor,pos_x,pos_y,siz_x,siz_y)
return xy #calc_pos_size

def drawit(self):
if self.xmode != 'W':
self.ids.scrv.size=257,340
self.ids.scro.text='\n\nDraw only available\n in Windows mode\n '\
#+str(self.ids.disp.font_size)
self.ids.drat.disabled = True
self.ids.scro.font_size=12
return
self.ids.drat.color='black'
self.ids.drat.text = "Only 1 Draw \nPer Session" #draw
self.ids.drat.disabled = True

self.Listsizes(0)

self.turtle_it() #call turtle routine

return #drawit

def turtle_it(self):
import turtle
from turtle import Screen

t = turtle.Turtle()
s = Screen()
#s.setup(xx800+150, xx600+150, 1360, 0) # pushes turtle screen to monitor 1
s.setup(xx800+150,xx600+150,0,0) #make turtle screen 150 pixels larger monitor 0
turtle.bgcolor('black')
t.speed(10)
t.turtlesize(.5,.5,.5)
t.penup()
t.pencolor('white') #axis lines are white
t.goto(-xx400,0)
t.pendown()
xz=-xx400 #draw x axis (horizontal)
for i in range(8):
t.fd(100)
t.stamp()
zz=-0 #write horizontal py/turtle tickmarks
for i in range(9):
t.penup()
t.goto(xz,-15)
t.pendown()
t.write(' '+str(zz)+' : '+str(xz))
t.penup()
t.goto(xz,-15)
t.pendown()
xz=xz+100
zz=zz+100

#setup for y axis (vertical)
t.penup()
t.goto(0,-xx300)
t.pendown()
t.lt(90)
xz=-xx300
zz=0
for i in range(6): #draw y axis (vertical)
t.write(' '+str(zz)+' : '+str(xz))
xz=xz+100
zz=zz+100
t.fd(100)
t.stamp()
t.write(' '+str(zz)+' : '+str(xz)) #last tickmark
self.xboxes=2
xxx=self.get_widget_names()
xxx.remove('Main')
xcolor=self.get_widget_colors('name')
#xcolor.remove('white')
xpos = [self.ids[idx].pos for idx in xxx] #
xsiz = [self.ids[idx].size for idx in xxx] #
xnam = [self.ids[idx].name for idx in xxx] #

i=0 #index number from pos, size
for x in xxx: #run through widget names
x1 = xpos[i] #break out x and y values for pos
xx1=x1[0]
xy1=x1[1]
x2 = xsiz[i] #break out x and y values for size
xx2=x2[0]
xy2=x2[1]
self.drawbox(xx1,xy1,xx2,xy2,xcolor[i],xnam[i]) #draw the box
i+=1 #increment for next widget
#if i==13:
# turtle.done()
# return

t.penup() #put warning on top of drawing
t.goto(-xx300,xx300+25)
t.write('Close this screen to continue - Output saved in <downloads> turtle.png',font=('Arial', 14, 'normal'))

# Get the turtle canvas
canvas = turtle.getcanvas()

# Get the bounding box of the turtle canvas
x0 = canvas.winfo_rootx()
y0 = canvas.winfo_rooty()
x1 = x0 + canvas.winfo_width()
y1 = y0 + canvas.winfo_height()-50
#quit()
# Grab the image of the turtle canvas
image = ImageGrab.grab(bbox=(x0, y0, x1, y1))

# Save the image as a PNG file
image.save(self.xtfile,"PNG") #<downloads> turtle.png

turtle.done()
self.set_focus()

return #turtle_it

def drawbox(self, x0,y0,wid,hig,color,widg):
if self.xboxes==2:
#convert python to turtle
if x0==0:
xx0=-xx400
else:
if x0>xx400:
xx0=x0-xx400
else:
xx0=x0-xx400

if y0==0:
yy0=-xx300+hig
else:
if y0 > xx300:
yy0=y0-xx300+hig
else:
yy0=y0-xx300+hig

import turtle #draw a box
t=turtle.Turtle()
t.turtlesize(.5,.5,.5)
t.speed(30)
t.penup()
t.goto(xx0,yy0) #put text above box
t.pencolor(color)
xwrite=' '+widg+': py='+str(int(x0))+' '+str(int(y0))+' '+str(int(wid))+' '+str(int(hig))+\
' tu='+str(int(xx0))+' '+str(int(yy0))
#xfont=ImageFont.truetype("arial.ttf",10)
#widx, higx =xfont.getsize(xwrite)
widx=kivy.core.text.Label().get_extents(xwrite)[0] #number of pixels in xwrite
if widx>wid: #text > widget width
if xx0==-xx400 and yy0==-xx300:
if wid==0 and hig==0: #no size
t.goto(xx0+125,yy0)
else:
t.goto(xx0,yy0) #put text above box
else:
t.goto(xx0,yy0-52) #put text inside box
xwrite=' '+widg+': py='+str(int(x0))+' '+str(int(y0))+\
'\n '+str(int(wid))+' '+str(int(hig))+\
'\n tu='+str(int(xx0))+' '+str(int(yy0))
t.write(xwrite,font=('Arial', 10, 'normal'))
t.goto(xx0,yy0)
t.pencolor(color)
t.pendown()
t.fd(wid)
t.rt(90)
t.fd(hig)
t.rt(90)
t.fd(wid)
t.rt(90)
t.fd(hig)

class TutorialApp(App):
print('TA')
def build(self):
return ScatterTextWidget()
#
# def _reposition(self):
# #self.root.ids.scat.center = self.root.ids.floa.center
# pass

#stuff for popup
class MessagePop(Popup):
print('messagepop')
pass

class RootBoxLayout(BoxLayout):
print('rootboxlayout')
text = StringProperty('Your message goes here - rbox')

class PopApp(App):
print('popapp')
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.pop = None # used to hold the popup
print('pop popapp')

def build(self):
print('build')
#sm=ScreenManager()
#sm.add.widget(ScatterTextWidget(name='Main'))
#sm.add.widget(ColorBox(name='cbox'))
#return sm

def on_start(self):
print('pop onstart')
self.pop = MessagePop() # instance the popup after the kv has been processed

# stuff for color draw recs

class ColorBox(FloatLayout):
color = ColorProperty()

#stuff for screenmanager
#class ScatterTextWidget(Screen):
# print('screenstw')
# pass

#class ColorBox(Screen):
# print('screencb')
# pass

#class WindowManager(ScreenManager):
# print('smwm')
# pass


#class ColorBoxes(App):
# def build(self):
# return Builder.load_string(kv)#
# def on_start(self):
# for color in xb:
# box = ColorBox(color=color)
# self.root.add_widget(box)


if __name__ == "__main__":
TutorialApp().run()

elli...@cox.net

unread,
Sep 13, 2023, 12:19:56 AM9/13/23
to kivy-...@googlegroups.com

Just taking a quick look…

ScatterWidgetText is a BoxLayout.  BoxLayouts want to size a position their children.  You are adding widgets to the BoxLayout – and the BoxLayout is doing its thing.

 

Given you are positioning and sizing the widgets, I assume you want to put them in FloatLayout.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/3ef991c8-edb6-4fd1-98f1-c81321be831en%40googlegroups.com.

elli...@cox.net

unread,
Sep 13, 2023, 10:41:14 AM9/13/23
to kivy-...@googlegroups.com

What do you want to achieve?  Did you want the output of render_rec to render on a different screen?

Here is a video tutorial on the ScreenManager:   https://youtu.be/xx-NLOg6x8o?si=pYqvll_S65MkJ0qG

 

The ScreenManager manages Screens. A Screen does not need to be the full window, it could be a subset of the window.

Dan Moormann

unread,
Sep 16, 2023, 11:40:56 PM9/16/23
to Kivy users support
So I changed it to a FloatLayout and manually placed my buttons.  I got it to work by using size: and pos: explicitly. I calclulated the size_hint and got that working when I try to do pos_hint, I get an error      
for key, value in c.pos_hint.items():
                            ^^^^^^^^^^^^^^^^
 AttributeError: 'tuple' object has no attribute 'items'

The only reference to my code is the run()
You can see the entire traceback if you run the code as is
If you comment out line 51(kv) and un-comment line 50 you' see what I'm trying to get.
I tried various combinations of pos_hit: None and size_hint : None and got the same error.

#:kivy 1.0.9

<ColorBox>:
#name:'cbox'


canvas:
Color:
rgb: root.color
Line:
rectangle: (*self.pos, *self.size)

<ScatterTextWidget>:

orientation: 'vertical'
id: 'Main'
name: 'Main'
effect_cls: 'ScrollEffect'

Label:
id: titl
name: 'titl'
text: 'Enter Text - Version: '+kivy.platform
size_hint_y: None
height: dp(50)
font_size: sp(20)
pos: 0,550
background_color: 0,255,255,1 #'aqua'

TextInput:
id: txti
name: 'txti'
size_hint_y: None
height: dp(50)
font_size: '25sp'
pos: 0,500
focus: True
on_text: helo.text = self.text #change helo to match txti entered
background_color: 128,128,128,1 #gray

#Buttons#############################

Button:
id:lsiz
name: 'lsiz'
text: " Press\n to\ndisplay"
on_press: root.Listsizes(0)
on_release: root.set_focus()
background_color: 0,255,0,1 #green
color: 'black' #text color
size_hint: .14,.14
#pos: 0,415
pos_hint: (0,.69)


Button: #list sizes to file
id: lfil
name: 'lfil'
text: "Press\n to\n file"
on_press: root.Listsizes(1)
on_release: root.set_focus()
background_color: 0,0,255,1 #blue
color: 'black'
size_hint: .14,.14
pos: 114,415
#pos_hint: .14,.69


Button: #clear
id: clea
name: 'clea'
text: 'Clear'
on_press: root.clear_it()
background_color: 255,0,0,1 #red
color: 'black'
size_hint: .14,.14
#pos_hint: .28,.69
pos: 228,415


Button: #drat
id: drat
name: 'drat'
text: "Draw\nTurtle"
on_press: root.drawit()
on_release: root.set_focus()
background_color: 128,0,128,1 #'purple'
color: 'black'
size_hint: .14,.14
#pos_hint: .43,.69
pos: 342,415


Button: #dral
id: dral
name: 'dral'
text: "Draw\nLine\nRect"
on_press: root.draw_recs()
on_release: root.set_focus()
background_color: 128,0,128,1 #'purple'
color: 'black'
size_hint: .14,.14
#pos_hint: .57,.69
pos: 456,415


Button: #mode
id: mode
name: 'mode'
text: 'Mode\n'+root.xltxt
on_press: root.set_mode()
on_release: root.set_focus()
background_color: 255,255,0,1 #yellow
color: 'black'
size_hint: .14,.14
#pos_hint: .71,.69
pos: 570,415


Button: #xtest
id: test
name: 'test'
on_press: root.xtest()
text: 'xtest'
background_color: 128,128,128,1 #grey
color: 'black'
size_hint: .14,.14
#pos_hint: .85,.69
pos: 684,415

########################################
from kivy.uix.boxlayout import BoxLayout
from kivy.utils import platform
from kivy.core.window import Window
from webcolors import rgb_to_name
from PIL import Image
from kivy.graphics import Line
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Rectangle

from PIL import ImageGrab
from kivy.core.text import Label as CoreLabel
from kivy.clock import Clock
import kivy.core.text
from inspect import currentframe, getframeinfo
from kivy.graphics import *
from kivy.uix.popup import Popup
from kivy.properties import ColorProperty
from kivy.uix.screenmanager import ScreenManager, Screen

import win32gui

hwnd = win32gui.GetForegroundWindow()
win32gui.MoveWindow(hwnd, 1380, 50, 816, 639, True) # move console output to monitor 1

xmode = 'W' # Win/Emulate/Android
xx600 = Window.height
xx300 = xx600 / 2
xx800 = Window.width
xx400 = xx800 / 2

class ScatterTextWidget(FloatLayout):
print('STW')
# background_color = ColorProperty() # The ListProperty will also work.
xltxt = "Windows"
if platform == 'android':
xmode = "A"
from android.storage import primary_external_storage_path
dir = primary_external_storage_path()
xfontname = os.path.join(dir, '/system/fonts/DroidSansMono.ttf')

xxfile = os.path.join(dir, 'Download') + '/Crash.txt'
else:
xfontname = 'C:/Windows/Fonts/Courbd'
xxfile = os.path.join(os.path.expanduser("~"), "Downloads") + '\\Crash.txt'
xtfile = os.path.join(os.path.expanduser("~"), "Downloads") + '\\turtle.png'
xmode = 'W'

# class end scattertextwidget

def __init__(self, **kwargs):
print('init')
super(ScatterTextWidget, self).__init__(**kwargs)
# self.save_initial_pos_size('init')
return

def on_kv_post(self, base_widget):
# self.save_initial_pos_size('kvpost')
# self.ids.scro.size= 257,0

self.ids.helo.pos = self.xihp # reset helo
self.ids.helo.size = self.xihs
self.ids.helo.text = 'Hello!'

# self.ids.disp.text = ''
self.ids.scro.text = ''
self.ids.txti.text = ''

Config.set('input', 'mouse', 'mouse,disable_multitouch')
# print('config',i)
return # clear_it

def set_focus(self):
if platform == "win": # so the keyboard on mobile doesn't pop
self.ids.txti.focus = True
return # set_focus

def set_mode(self):
if self.xmode == "A": # leave everything alone
return
if self.xmode == "E": # switch to Windows mode
Window.size = (xx800, xx600)
self.ids.disp.font_size = 14
self.xmode = "W"
self.xltxt = 'Windows'
else: # switch to Emulate mode
self.xresize = 4.2
x = self.xresize
Window.size = (1080 / x, 2340 / x) # 1080x2340 samsung s23 result 257x557
# self.ids.disp.font_size = 8
self.xmode = 'E'
self.xltxt = 'Emu\nlate'
self.ids.mode.text = 'Mode\n ' + self.xltxt
self.ids.disp.background_color = 255, 255, 0, 1 # yellow
# self.ids.disp.text=str(self.ids.disp.background_color)+' '+str(self.ids.disp.font_size)
self.clear_it()
return # set_mode

def ask_it(self, xtxt, xlen, xx, yy):
self.ids.lab2.text = xtxt
self.ids.txt2.size = (xlen, 30)
self.ids.txt2.pos = (xx, yy)
self.ids.lab2.pos = (xx, yy + 22)

# gotta catch whatever is input before proceeding

print(self.ids.txt2.text)

def xtest(self):
print('xtext')
Line(rectangle=(100, 100, 100, 100))
return

# lab2 size(75,30) pos(5,122)
# txt2 size(100,30) pos(5,100)
print(self.ids.txt2.focus)
self.ids.lab2.text = 'test'
self.ids.txt2.text = ''
self.ids.txt2.focus = True
print(self.ids.txt2.focus)

self.ask_it('test2', 200, 200, 200)

# RootBoxLayout()
# MessagePop.open()
return

# put text anywhere
self.ids.txt2.background_color = (255, 0, 0, 1) # red
# self.ids.txt2.pos=200,200

# self.draw_recs()

# x=self.get_widget_colors('name')
# print(x)

# self.set_mode() #calls clear_it

# self.ids.disp.text='Test!'
return # xtest

#
def get_widget_colors(self, name_num):
# xcfile = 'c:/Users/danm9/Crash/colorcodes.txt'
# xcfile = os.path.join(os.path.expanduser("~"), "Downloads") + '\\colorcodes.txt'
# read file and set up array
# with open(xcfile) as f:
# lookup funtion
for widget in self.walk():
# print(self.ln(),widget.name)
xlook = [255, 255, 255, 1] # default to white (no background_color)
if hasattr(widget, 'background_color'): # build the color list
xlook = widget.background_color # s/b x,x,x,1
# print(self.ln(),xlook,widget.name)
for i in range(len(xa)):
if str(xa[i]) == str(xlook):
# print(self.ln(),'hit',xc[i])
xcc.append(xb[i]) # 3 dig color numbers from table
xcn.append(xc[i]) # color names from table

# print(self.ln(),xb)
# print(self.ln(),len(xcc),xcc)
# print(self.ln(),len(xcn),xcn)
return xcn if name_num == 'name' else xcc # 3 digit color codes or color name

def draw_recs(self):

xxx = self.get_widget_names()
xxx.remove('Main')
xxn = self.get_widget_colors('num')

xxc = self.get_widget_colors('name')

# xxc.remove('white')
xpos = [self.ids[idx].pos for idx in xxx] #
xsiz = [self.ids[idx].size for idx in xxx] #
# print(xxx)
# print(xxc)
i = 0 # index number from pos, size
for x in xxx: # run through widget names
x1 = xpos[i] # break out x and y values for pos
xx1 = x1[0]
xy1 = x1[1]
x2 = xsiz[i] # break out x and y values for size
xx2 = x2[0]
xy2 = x2[1]
# sm.switch_to(dscreen)
with self.canvas:
print(self.ln(), i, xxx[i], xxn[i], int(xx1), int(xy1)
, int(xx2), int(xy2))
box = ColorBox(color=xxn[i],
size_hint=(None, None),
size=(xx2,xy2))
self.add_widget(box)
self.add_widget(Label(text=xxx[i],
pos=(xx1 , xy1),
size_hint=(None, None),
size=(xx2, xy2)))
#Line(rectangle=(xx1, xy1, xx2, xy2))

# self.canvas.add(rect)
i += 1 # increment for next widget
if i==2:
return

def ln(self): # current line number
frameinfo = getframeinfo(currentframe().f_back)
return str(frameinfo.lineno) + ':'

def get_widget_names(self):
xxx = []
for widget in self.walk():
xxx.append(widget.name) # build the name list
return xxx # get_widget_name

# def old_get_widget_colors(self,xname_num):
# #ooo
# xxc=[]
# for widget in self.walk():
# if hasattr(widget,'background_color'): #build the color list
# x4=widget.background_color #s/b x,x,x,1
# if xname_num=='name':
#
# for i in range(3): #fix 1,1,0,1 yellow
# if x4[i]==1:
# x4[i]=255
# x5=rgb_to_name(x4)
# else:
# x5='white'
# xxc.append(x5)
# return xxc #get_widget_colors

def build_lxx(self, xline_in):
# print(self.ln(),' 1 2 3 4 5 6 7')
# print(self.ln(),'1234567890123456789012345678901234567890123456789012345678901234567890')
xfirst_half = ' ' + xline_in[:32]
xwname = xline_in[:5]
if xwname == 'Outpu' and self.xmode != 'W': # clean off Outp as if it's a widget name
xwname = ''
xsecond_half = xline_in[33:]
self.lxx = self.lxx + xline_in + '\n' # entire line
self.lxx1 = self.lxx1 + xfirst_half + '\n' # first half of line
self.lxx2 = self.lxx2 + xwname + ' ' + xsecond_half + '\n' # second half
return

def Listsizes(self, xf): # 0=list, 1=file
self.lxx = ''
self.lxx1 = ''
self.lxx2 = ''
self.ids.disp.font_size = 14
# xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx
self.build_lxx(' ----pos- --size-- -------- hints -------')
self.build_lxx(' acr up wid hig parent color posx posy sizx sizy')
# 1 2 3 4 5 6
# 12345678901234567890123456789012345678901234567890123456789012
# self.ids.disp.font_size=12
xxx = self.get_widget_names()
xxx.remove('Main')
xxc = self.get_widget_colors('name')
# xxc.remove('white')
xparent = [self.ids[idx].parent.name for idx in xxx]
xppos = [self.ids[idx].parent.pos for idx in xxx]
xpsiz = [self.ids[idx].parent.size for idx in xxx]
xpos = [self.ids[idx].pos for idx in xxx]
xsiz = [self.ids[idx].size for idx in xxx]
# print(self.ln(),len(xxx),xxx)
# print(self.ln(),len(xxc),xxc)
# print(self.ln(),len(xparent),xparent)
# print(self.ln(),len(xppos),xppos)
# print(self.ln(),len(xpsiz),xpsiz)
# print(self.ln(),len(xpos),xpos)
# main requires seperate approach
self.build_lxx(self.pull_out('main', self.pos, self.size, ' ', (0, 0), (0, 0), ''))
i = 0
for x in xxx:
# pass in tuples and parent
# print(self.ln(),i,xxx[i],xxc[i])
self.build_lxx(self.pull_out(x, xpos[i], xsiz[i], xparent[i], xppos[i], xpsiz[i], xxc[i]))
i += 1
if xf == 1:
file1 = open(self.xxfile, 'w+')
self.build_lxx("Output in <downloads> Crash.txt") # +self.xxfile)
file1.write(self.lxx)

self.ids.disp.color = 'yellow'
if self.xmode != 'W': # send output to scroll
self.ids.scro.font_size = 12
self.lxx = self.lxx1 + '\n' + self.lxx2 + '\n'
self.ids.scro.text = self.lxx
self.ids.scrv.size = 257, 328
else:
self.ids.scrv.size = 800, 320
self.ids.scro.text = self.lxx

return # listsizes

def pull_out(self, xname, x_pos, x_siz, x_parent, x_ppos, x_psiz, x_color):
# dont need to use unpack as cannot unpack scatter
x1, xx1 = x_pos[0], x_ppos[0]
y1, xy1 = x_pos[1], x_ppos[1]
x2, xx2 = x_siz[0], x_psiz[0]

y2, xy2 = x_siz[1], x_psiz[1]
xr = "{0:5.0f}{1:5.0f} {2:5.0f}{3:5.0f}"
xy = xr.format(x1, y1, x2, y2)
xy = xname + xy # add name of widget to beginneing of line
xy = xy + ' ' + x_parent
if xname == "main":
# preserve values for calculating hints - nothing to output for main
global xarc, xup, xwid, xhig, m_wid, m_hig
xarc, xup, xwid, xhig = x1, y1, x2, y2
m_wid, m_hig = xwid, xhig
else:
# calculate hints
xy = xy + ' ' + self.calc_pos_size(x1, y1, x2, y2, xx1, xy1, xx2, xy2, x_color)
# xy=xy+' '+x_color
return xy # pull_out

def calc_pos_size(self, acr, up, wid, hig, p_acr, p_up, p_wid, p_hig, xcolor):
pos_x = 0 if p_wid == 0 else acr / p_wid
pos_y = 0 if p_hig == 0 else up / p_hig
if pos_y > 1:
pos_y = (up - p_up) / p_hig
siz_x = 0 if p_wid == 0 else wid / p_wid
siz_y = 0 if p_hig == 0 else hig / p_hig
xr = "{0:6}{1:5.2f} {2:5.2f} {2:5.2f} {2:5.2f}"
# print(self.ln(),xcolor,int(pos_x),int(pos_y),int(siz_x),int(siz_y))

xy = xr.format(xcolor, pos_x, pos_y, siz_x, siz_y)
return xy # calc_pos_size

def drawit(self):
if self.xmode != 'W':
self.ids.scrv.size = 257, 340
self.ids.scro.text = '\n\nDraw only available\n in Windows mode\n ' \

# +str(self.ids.disp.font_size)
self.ids.drat.disabled = True
self.ids.scro.font_size = 12
return
self.ids.drat.color = 'black'
self.ids.drat.text = "Only 1 Draw \nPer Session" # draw
self.ids.drat.disabled = True

self.Listsizes(0)

self.turtle_it() # call turtle routine

return # drawit

def turtle_it(self):
import turtle
from turtle import Screen

t = turtle.Turtle()
s = Screen()
# s.setup(xx800+150, xx600+150, 1360, 0) # pushes turtle screen to monitor 1
s.setup(xx800 + 150, xx600 + 150, 0, 0) # make turtle screen 150 pixels larger monitor 0
turtle.bgcolor('black')
t.speed(10)
t.turtlesize(.5, .5, .5)
t.penup()
t.pencolor('white') # axis lines are white
t.goto(-xx400, 0)
t.pendown()
xz = -xx400 # draw x axis (horizontal)
for i in range(8):
t.fd(100)
t.stamp()
zz = -0 # write horizontal py/turtle tickmarks
for i in range(9):
t.penup()
t.goto(xz, -15)
t.pendown()
t.write(' ' + str(zz) + ' : ' + str(xz))
t.penup()
t.goto(xz, -15)
t.pendown()
xz = xz + 100
zz = zz + 100

# setup for y axis (vertical)
t.penup()
t.goto(0, -xx300)
t.pendown()
t.lt(90)
xz = -xx300
zz = 0
for i in range(6): # draw y axis (vertical)
t.write(' ' + str(zz) + ' : ' + str(xz))
xz = xz + 100
zz = zz + 100
t.fd(100)
t.stamp()
t.write(' ' + str(zz) + ' : ' + str(xz)) # last tickmark
self.xboxes = 2
xxx = self.get_widget_names()
xxx.remove('Main')
xcolor = self.get_widget_colors('name')
# xcolor.remove('white')
xpos = [self.ids[idx].pos for idx in xxx] #
xsiz = [self.ids[idx].size for idx in xxx] #
xnam = [self.ids[idx].name for idx in xxx] #

i = 0 # index number from pos, size
for x in xxx: # run through widget names
x1 = xpos[i] # break out x and y values for pos
xx1 = x1[0]
xy1 = x1[1]
x2 = xsiz[i] # break out x and y values for size
xx2 = x2[0]
xy2 = x2[1]
self.drawbox(xx1, xy1, xx2, xy2, xcolor[i], xnam[i]) # draw the box
i += 1 # increment for next widget
# if i==13:
# turtle.done()
# return

t.penup() # put warning on top of drawing
t.goto(-xx300, xx300 + 25)
t.write('Close this screen to continue - Output saved in <downloads> turtle.png', font=('Arial', 14, 'normal'))
widx = kivy.core.text.Label().get_extents(xwrite)[0] # number of pixels in xwrite
if widx > wid: # text > widget width
if xx0 == -xx400 and yy0 == -xx300:
if wid == 0 and hig == 0: # no size
t.goto(xx0 + 125, yy0)
else:
t.goto(xx0, yy0) # put text above box
else:
t.goto(xx0, yy0 - 52) # put text inside box
xwrite = ' ' + widg + ': py=' + str(int(x0)) + ' ' + str(int(y0)) + \
'\n ' + str(int(wid)) + ' ' + str(int(hig)) + \
'\n tu=' + str(int(xx0)) + ' ' + str(int(yy0))
t.write(xwrite, font=('Arial', 10, 'normal'))

t.goto(xx0, yy0)
t.pencolor(color)
t.pendown()
t.fd(wid)
t.rt(90)
t.fd(hig)
t.rt(90)
t.fd(wid)
t.rt(90)
t.fd(hig)


class TutorialApp(App):
print('TA')

def build(self):
return ScatterTextWidget()


#
# def _reposition(self):
# #self.root.ids.scat.center = self.root.ids.floa.center
# pass

# stuff for popup
class MessagePop(Popup):
print('messagepop')
pass


class RootBoxLayout(BoxLayout):
print('rootboxlayout')
text = StringProperty('Your message goes here - rbox')


class PopApp(App):
print('popapp')

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.pop = None # used to hold the popup
print('pop popapp')

def build(self):
print('build')
# sm=ScreenManager()
# sm.add.widget(ScatterTextWidget(name='Main'))
# sm.add.widget(ColorBox(name='cbox'))
# return sm

def on_start(self):
print('pop onstart')
self.pop = MessagePop() # instance the popup after the kv has been processed


# stuff for color draw recs

class ColorBox(FloatLayout):
color = ColorProperty()


# stuff for screenmanager
# class ScatterTextWidget(Screen):
# print('screenstw')
# pass

# class ColorBox(Screen):
# print('screencb')
# pass

# class WindowManager(ScreenManager):
# print('smwm')
# pass


# class ColorBoxes(App):
# def build(self):
# return Builder.load_string(kv)#
# def on_start(self):
# for color in xb:
# box = ColorBox(color=color)
# self.root.add_widget(box)


if __name__ == "__main__":
TutorialApp().run()

elli...@cox.net

unread,
Sep 17, 2023, 11:12:57 AM9/17/23
to kivy-...@googlegroups.com

A pos_hint takes a dictionary as an argument, not a tuple.

See: https://kivy.org/doc/stable/api-kivy.uix.widget.html#kivy.uix.widget.Widget.pos_hint

The keys ‘x’, ‘right’ and ‘center_x’ will use the parent width. The keys ‘y’, ‘top’ and ‘center_y’ will use the parent height.

 

You can also use nested layouts, so for example you could put a BoxLayout in the FloatLayout, let the BoxLayout (or other nested layouts) position the static widgets, as you had before, and they add the dynamic widgets to the FloatLayout.  Here is a small example.

 

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button

kv =
"""
FloatLayout:
    id: float
    BoxLayout:
        pos_hint: {'top': 1}  # using the dict for a pos_hint
        size_hint_y: None
        height: dp(48)
        Button:
            text: 'In BoxLayout'
        Button:
            text: '...also in BoxLayout'
"""


class NestedFloatApp(App):
   
def build(self):
       
return Builder.load_string(kv)

   
def on_start(self):
       
# add dynamic buttons to FloatLayout
       
positions = ((0, 0), ('100dp', '48dp'))
       
for i, pos in enumerate(positions):
           
self.root.add_widget(Button(text=f'{i}', size_hint=(None, None),
                                       
size=('100dp', '48dp'), pos=pos))
        center_button = Button(
text='Center', size_hint=(None, None),
                              
size=('100dp', '48dp'), pos_hint={'center_x': 0.5, 'center_y': 0.5})
       
self.root.add_widget(center_button)


NestedFloatApp().run()

Reply all
Reply to author
Forward
0 new messages