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':
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')
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:
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')
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():
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')
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
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
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'))
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):
# 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()