Im getting empty box character instead of Ä character. How to make them show on my kivy application. I read some posts suggesting changing font type to some which support these characters. i tried few but it didnt seem solving it.
Tried pretty basic Calibri font and also just randomly picked font which was said to be suitable with my languange( AlegreyaSansSC)
Python file:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import StringProperty, BooleanProperty
class Row(BoxLayout):
x1 = StringProperty('')
x2 = StringProperty('')
x3 = BooleanProperty(False)
def __init__(self, x1, x2, x3, **kwargs):
super(Row, self).__init__(**kwargs)
self.x1 = x1
self.x2 = x2
self.x3 = x3
class MyPopup(Popup):
pass
class MainScreen(Screen):
pass
class SecondScreen(Screen):
def fire_popup(self):
pops = MyPopup()
pops.open()
class ScreenManagement(ScreenManager):
def changescreen(self, value):
try:
if value !='main':
self.current = value
except:
print('No Screen named'+ value)
class testiApp(App):
def build(self):
self.title = 'Hello'
def add_more(self, x1, x2, x3):
addbutton = self.root.get_screen('Page2').ids.empty
addbutton.add_widget(Row(x1, x2, x3))
def remove(self):
container = self.root.get_screen('Page2').ids.empty
if len(container.children) > 0:
container.remove_widget(container.children[0])
testiApp().run()
KV. file:
<MyPopup>:
id:pop
size_hint: .4, .4
auto_dismiss: False
title: 'XXX!!'
BoxLayout:
orientation:'vertical'
BoxLayout:
orientation:'horizontal'
Label:
text:'X1'
TextInput:
id: X1
Label:
text:'X2'
TextInput:
id:X2
CheckBox:
id:X3
BoxLayout:
orientation:'horizontal'
Button:
text:'Lisää'
on_release: app.add_more(X1.text, X2.text, X3.active)
Button:
text: 'Close'
on_press: pop.dismiss()
<Row>:
x1:''
x2:''
x3:False
Label:
text: root.x1
Label:
text: root.x2
CheckBox:
active: root.x3
ScreenManagement:
MainScreen:
name:'Main'
SecondScreen:
name:'Page2'
<MainScreen>:
name:'Main'
BoxLayout:
Button:
text:'Next Page'
on_release: app.root.current ='Page2'
<SecondScreen>:
name:'Page2'
BoxLayout:
orientation:'vertical'
BoxLayout:
orientation:'vertical'
Label:
text:'Popup Test'
ScrollView:
bar_width: 5
bar_color: 1,0,0,1 #red
bar_inactive_color: 0,0,1,1 #blue
effect_cls: 'ScrollEffect'
scroll_type:['bars','content']
GridLayout:
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
row_default_height: 60
cols:1
id:empty
BoxLayout:
Button:
text:'Open Popup'
on_press: root.fire_popup()
Button:
text:'Add'
on_release: app.add_more()
Button:
text:'remove'
on_release: app.remove()
Question
Seems that problem happens only if i use separate py. and kv file.
Answer
I don't think the problem is caused by separate py and kv file. The following example displayed the character correctly.
main.py
from kivy.base import runTouchApp
from kivy.lang import Builder
runTouchApp(Builder.load_file("main.kv"))
main.kv
GridLayout:
cols: 2
Label:
text: 'Alegreya Sans SC font'
Label:
text: 'Roboto font (Default)'
Label:
text: 'Ä'
font_size: 56
font_name: '/home/iam/share/fonts/Alegreya_Sans_SC/AlegreyaSansSC-Medium.ttf'
Label:
text: 'Ä'
font_size: 56
Problem
I'm getting empty box character instead of Ä character. How to make
them show on my kivy application.
Solution
Download and extract Alegreya Sans SC font from Google Fonts. This font is under Open Font License
Add attribute, font_name: and provide the path to the extracted folder plus the type of font (e.g. AlegreyaSansSC-Medium.ttf).
Example
The following example illustrates displaying character, Ä using attribute, font_name to use different font. The default font use by Kivy is Roboto.
main-kv.py
from kivy.base import runTouchApp
from kivy.lang import Builder
runTouchApp(Builder.load_string("""
GridLayout:
cols: 2
Label:
text: 'Alegreya Sans SC font'
Label:
text: 'Roboto font (Default)'
Label:
text: 'Ä'
font_size: 56
font_name: '/home/iam/share/fonts/Alegreya_Sans_SC/AlegreyaSansSC-Medium.ttf'
Label:
text: 'Ä'
font_size: 56
"""))
Output
Related
When going from the first screen to the second screen, I want to pass a variable as an argument so that kivyMD can update the second screen from text stored in an excel file. The following is a skeleton of my app's functionality:
The user reaches Screen 1 thru the navigation drawer in KivyMD, screen 1 presents the user with two options on two small clickable MDCards:
"Change text to 1"
"Change text to 2"
After clicking on one of these, the app switches to screen 2 with a single big MDCard, the text on this MDCard should change to reflect the option the user chose.
However, kivy is pulling the text that is to be displayed on the big MDCard from an excel file.
The variable that I want to pass from screen 1 to screen 2 is simply a number (1 or 2) that will tell kivy which row in the excel file it should pull the text from
If the user clicks "Change text to 1" then the first screen should pass "1" as the argument row_x to the function def change_text() (see screen 2 .py) so that the text in row 1 of excel can be displayed on the second screen. How can I achieve this?
I have 4 files in total; 3 are .py files (one for the main app, one for screen 1, and one for screen 2), and the excel file
NOTE: in the code below, Screen 1 & 2 are called Element 1 & 2 respectfully
Main.py:
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivymd.app import MDApp
from element_1 import element_1_screen
from element_2 import element_2_screen
MainNavigation = '''
<ContentNavigationDrawer>:
ScrollView:
MDList:
OneLineListItem:
text: 'Go to Element 1'
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "go_to_element_1_screen"
Screen:
MDToolbar:
id: toolbar
pos_hint: {"top": 1}
elevation: 10
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
MDNavigationLayout:
x: toolbar.height
ScreenManager:
id: screen_manager
Screen:
name: "words_nav_item"
element_1_screen:
name: "go_to_element_1_screen"
element_2_screen:
name: "go_to_element_2_screen"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
'''
class ContentNavigationDrawer(BoxLayout):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
class mainApp(MDApp):
def build(self):
self.theme_cls.primary_palette = "Red"
return Builder.load_string(MainNavigation)
mainApp().run()
Screen 1 / Element 1
from kivy.lang import Builder
from kivymd.uix.screen import MDScreen
element_1_contents = '''
<element_1_screen>:
MDGridLayout:
rows: 2
size: root.width, root.height
pos_hint: {"center_x": .8, "center_y": .2}
spacing: 40
MDCard:
orientation: 'vertical'
size_hint: None, None
size: "360dp", "120dp"
ripple_behavior: True
on_release:
root.manager.current = "go_to_element_2_screen"
MDLabel:
id: LabelTextID
text: "Change Text to 1"
halign: 'center'
MDCard:
orientation: 'vertical'
size_hint: None, None
size: "360dp", "120dp"
ripple_behavior: True
on_release:
root.manager.current = "go_to_element_2_screen"
MDLabel:
id: LabelTextID
text: "Change Text to 2"
halign: 'center'
'''
class element_1_screen(MDScreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Builder.load_string(element_1_contents)
Screen 2 / Element 2
from kivy.lang import Builder
from kivymd.uix.screen import MDScreen
import openpyxl
element_2_contents = '''
<element_2_screen>:
MDCard:
orientation: 'vertical'
size_hint: None, None
size: "360dp", "360dp"
pos_hint: {"center_x": .5, "center_y": .5}
ripple_behavior: True
focus_behavior: True
on_release: root.manager.current = "go_to_element_1_screen"
MDLabel:
id: TextID
text: "NOTHING HAS CHANGED"
halign: 'center'
MDLabel:
text: "(Click here to return)"
halign: 'center'
'''
class element_2_screen(MDScreen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
path = "data.xlsx"
self.wb_obj = openpyxl.load_workbook(path)
self.sheet_obj = self.wb_obj.active
Builder.load_string(element_2_contents)
def change_text(self, row_x=0):
row_number = self.sheet_obj.cell(row_x, column=1)
self.ids.TextID.text = str(row_number.value)
And the excel file only has two entries in Column A:
Row 1: You have chosen 1
Row 2: You have chosen 2
I found the answer and now it works flawlessly. Someone over on Reddit (u/Username_RANDINT) helped me, this is what they said:
The ScreenManager has a get_screen() method. You could use it to get
the instance of the second screen and call the change_text() method on
that. In the same place where you switch screens, add another line:
on_release:
root.manager.current = "go_to_element_2_screen"
root.manager.get_screen("go_to_element_2_screen").change_text(1)
Then the same for the other card, just pass in 2 instead of 1.
I'm new to kivy and I'm trying to create a drag and drop app where if the image is dropped onto the gridlayout the image is shown on the app as shown below. I'm trying to get the file_path of the image and then using the file_path to display it on the gridlayout but unfortunately, that is not working. Any help would be greatly appreciated!
This is the current image
This is what I want after dragging the image
Kv file
# Custom button
<CustButton#Button>:
font_size: 32
background_normal: 'Colour_yellow.png'
background_down: 'Colour_blue.png'
<Cust2#Button>:
font_size: 32
background_normal: 'Colour_red.png'
background_down: 'Colour_blue.png'
<Cust3#Button>:
font_size: 32
background_normal: 'Colour_white.png'
background_down: 'Colour_blue.png'
<Cust4#Button>:
font_size: 32
background_normal: 'Colour_blue.png'
background_down: 'Colour_white.png'
<CalcGridLayout>:
id: calculator
display: entry
rows: 5
padding: 10
spacing: 10
BoxLayout:
spacing: 100
size_hint: .5, None
Cust2:
text: "Whats the intensity you want?"
BoxLayout:
size_hint: .5, None
TextInput:
id: entry
font_size: 70
multiline: False
hint_text: "Type here"
BoxLayout:
spacing: 100
size_hint: .5, None
Cust4:
text: "Drag and Drop picture below:"
on_release: root.build1()
#THIS IS WHERE I'M STUCK ON
BoxLayout:
Image:
source: root._on_file_drop(file_path)
BoxLayout:
size_hint: 1, .3
spacing: 10
CustButton:
text: "Click here for \n reduced size"
CustButton:
text: "Click here for pos \n and intensity of \n each pixel"
on_release: root.reduced_image()
CustButton:
text: "Click here \n for graph"
CustButton:
text: "Click here \n for all"
CustButton:
text: "Extra"
Python file
import kivy
kivy.require("1.9.0")
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.clearcolor = (0.5, 0.5, 0.5, 1)
class CalcGridLayout(GridLayout):
def reduced_image(self):
#ignore
def build1(self):
Window.bind(on_dropfile=self._on_file_drop)
return
def _on_file_drop(self, window, file_path):
print(file_path)
return file_path
class dropdownApp(App):
def build(self):
return CalcGridLayout()
dropApp = dropdownApp()
dropApp.run()
Solution
Please refer to the snippets, and complete example for details.
kv file
Remove on_release: root.build1()
Replace source: root._on_file_drop(file_path) with id: img
Snippet
BoxLayout:
spacing: 100
size_hint: .5, None
Cust4:
text: "Drag and Drop picture below:"
BoxLayout:
Image:
id: img
Python Code
Add import statement, from kivy.properties import StringProperty
Declare property, filePath = StringProperty('') in class CalcGridLayout().
Add constructor to class CalcGridLayout() and move Window.bind(on_dropfile=self._on_file_drop) from build1() method
Remove build1() method
In _on_file_drop() method, replace return file_path with self.filePath = file_path.decode("utf-8") self.ids.img.source = self.filePath and self.ids.img.reload()
Snippet
from kivy.properties import StringProperty
...
class CalcGridLayout(GridLayout):
filePath = StringProperty('')
def __init__(self, **kwargs):
super(CalcGridLayout, self).__init__(**kwargs)
Window.bind(on_dropfile=self._on_file_drop)
def reduced_image(self):
print(self.filePath)
def _on_file_drop(self, window, file_path):
print(file_path)
self.filePath = file_path.decode("utf-8") # convert byte to string
self.ids.img.source = self.filePath
self.ids.img.reload() # reload image
Window » on_dropfile Event
on_dropfile(filename)
Event called when a file is dropped on the application.
Warning
This event currently works with sdl2 window provider, on pygame window
provider and OS X with a patched version of pygame. This event is left
in place for further evolution (ios, android etc.)
Example
main.py
import kivy
kivy.require("1.11.0")
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.properties import StringProperty
Window.clearcolor = (0.5, 0.5, 0.5, 1)
class CalcGridLayout(GridLayout):
filePath = StringProperty('')
def __init__(self, **kwargs):
super(CalcGridLayout, self).__init__(**kwargs)
Window.bind(on_dropfile=self._on_file_drop)
def reduced_image(self):
print(self.filePath)
def _on_file_drop(self, window, file_path):
print(file_path)
self.filePath = file_path.decode("utf-8") # convert byte to string
self.ids.img.source = self.filePath
self.ids.img.reload() # reload image
class DragDropApp(App):
def build(self):
return CalcGridLayout()
if __name__ == "__main__":
DragDropApp().run()
dragdrop.kv
#:kivy 1.11.0
# Custom button
<CustButton#Button>:
background_normal: "/home/iam/Pictures/AppImages/Colors/yellow.png" # 'Colour_yellow.png'
background_down: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
text_size: self.size
halign: 'center'
valign: 'middle'
<Cust2#Button>:
font_size: 32
background_normal: "/home/iam/Pictures/AppImages/Colors/red.png" # 'Colour_red.png'
background_down: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
<Cust3#Button>:
font_size: 32
background_normal: "/home/iam/Pictures/AppImages/Colors/white.png" # 'Colour_white.png'
background_down: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
<Cust4#Button>:
font_size: 32
background_normal: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
background_down: "/home/iam/Pictures/AppImages/Colors/white.png" # 'Colour_white.png'
<CalcGridLayout>:
id: calculator
display: entry
rows: 5
padding: 10
spacing: 10
BoxLayout:
spacing: 100
size_hint: .5, None
Cust2:
text: "Whats the intensity you want?"
BoxLayout:
size_hint: .5, None
TextInput:
id: entry
font_size: 70
multiline: False
hint_text: "Type here"
BoxLayout:
spacing: 100
size_hint: .5, None
Cust4:
text: "Drag and Drop picture below:"
BoxLayout:
Image:
id: img
BoxLayout:
size_hint: 1, .3
spacing: 10
CustButton:
text: "Click here for \n reduced size"
CustButton:
text: "Click here for pos \n and intensity of \n each pixel"
on_release: root.reduced_image()
CustButton:
text: "Click here \n for graph"
CustButton:
text: "Click here \n for all"
CustButton:
text: "Extra"
Output
I tried extracting the code for a closeable TabbedPanel from github here.
It works all fine but the content of the tab is not cleared as well, just the header. How can I remove the content of the Tab when closing it as well?
from kivy.app import App
from kivy.animation import Animation
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
from kivy.factory import Factory
from kivy.lang import Builder
class CloseableHeader(TabbedPanelHeader):
pass
class TestTabApp(App):
def build(self):
return Builder.load_string('''
TabbedPanel:
do_default_tab: False
FloatLayout:
BoxLayout:
id: tab_1_content
Label:
text: 'Palim 1'
BoxLayout:
id: tab_2_content
Label:
text: 'Palim 2'
BoxLayout:
id: tab_3_content
Label:
text: 'Palim 3'
CloseableHeader:
text: 'tab1'
panel: root
content: tab_1_content.__self__
CloseableHeader:
text: 'tab2'
panel: root
content: tab_2_content.__self__
CloseableHeader:
text: 'tab3'
panel: root
content: tab_3_content.__self__
<CloseableHeader>
color: 0,0,0,0
disabled_color: self.color
# variable tab_width
text: 'tabx'
size_hint_x: None
width: self.texture_size[0] + 40
BoxLayout:
pos: root.pos
size_hint: None, None
size: root.size
padding: 3
Label:
id: lbl
text: root.text
BoxLayout:
size_hint: None, 1
orientation: 'vertical'
width: 22
Button:
on_press:
root.panel.remove_widget(root)
''')
if __name__ == '__main__':
TestTabApp().run()
If I close tab 2, while being on tab 2.
I would like to see tab 1, right now I will still see the content of tab2.
As you said, in your code you just remove header. To also clear all the widgets in the content area, you have to add the following command:
Button:
on_press:
root.panel.switch_to(root.panel.tab_list[root.panel.tab_list.index(root.panel.current_tab) - 1])
root.panel.remove_widget(root)
root.content.clear_widgets()
Now the content area is cleared and another content is shown.
I have a piece of code. (1) The TextInput value should be shown , but first it should not be editable, after clicking the corresponding CheckBox, the TextInput will be editable.
(2) Using the iteration, the Label and the TextInput should get the value. The value at Label and TextInput should not be hard coded(although it's there in my code, #FJSevilla helped me for this one).
(3) However, the values of Label and TextInput are stored in a variable in json format. something like this(you can consider like key,value pair in map) [ variable = '{"a" : " Goc" , "b" : "Coc", "c" : "Dow" } ']
(you can see diagram for more clearance).
I appreciate the help.
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder
Builder.load_string("""
<Test>:
do_default_tab: False
TabbedPanelItem:
text: 'page1'
BoxLayout:
padding: 50, 50, 50, 50
orientation: 'horizontal'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 1
Label:
text: 'a'
Label:
text: 'b'
Label:
text: 'c'
BoxLayout:
spacing: 50
orientation: 'vertical'
TextInput:
text: 'Goc'
TextInput:
text: 'Coc'
TextInput:
text: 'Dow'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 0.40
CheckBox:
text: 'CheckBox'
CheckBox:
text: 'CheckBox'
CheckBox:
text: 'CheckBox'
BoxLayout:
spacing: 50
orientation: 'vertical'
size_hint_x: 0.60
Button:
text: 'save'
Button:
text: 'save'
Button:
text: 'save'
""")
class Test(TabbedPanel):
pass
class MyApp(App):
def build(self):
test = Test()
return test
if __name__ == '__main__':
MyApp().run()
First of all, thank you for providing an app which was easy to work with.
I tried to implement what you were looking for except the JSON. I am using a simple list, it should be straightforward to extend my code for a JSON.
Instead of using colums, I am using rows which makes it easier to link together the properties of the label textinput and checkbox.
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.uix.textinput import TextInput
from kivy.uix.checkbox import CheckBox
from kivy.lang import Builder
ROWS = ['Goc', 'COC', 'EEE']
Builder.load_string("""
<Test>:
do_default_tab: False
TabbedPanelItem:
text: 'page1'
Table:
padding: 50, 50, 50, 50
orientation: 'vertical'
<Row>:
spacing: 50
#orientation: 'vertical'
size_hint_x: 1
txt: txtinpt.text
Label:
text: root.txt
TextInput:
id: txtinpt
text: root.txt
disabled: not CheckBox.active
CheckBox:
id:CheckBox
text: 'CheckBox'
active: False
Button:
text: 'save'
""")
class Table(BoxLayout):
def __init__(self, **kwargs):
super(Table, self).__init__(**kwargs)
for row in ROWS:
self.add_widget(Row(row))
class Row(BoxLayout):
txt = StringProperty()
def __init__(self, row, **kwargs):
super(Row, self).__init__(**kwargs)
self.txt = row
class Test(TabbedPanel):
pass
class MyApp(App):
def build(self):
test = Test()
return test
if __name__ == '__main__':
MyApp().run()
I am trying to use input on one screen to make a list on a second screen using kivy. The basic idea is that a paragraph is broken up into words, which are then displayed on another page. Below is a minimum example.
What is happening is that the words are getting squished together, and there's no scrolling.
In main.py:
from kivy.app import App
from kivy.app import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
class InputScreen(Screen):
wordList = ObjectProperty()
def getwords(self):
self.wordList=[]
s = self.ids.textInput.text.split()
for w in s:
for punctuation in [',','.','!','?']:
w.strip(punctuation)
self.wordList.append(w)
return None
class WordLabel(Label):
pass
class WordScreen(Screen):
wordList = ObjectProperty()
def updateWords(self):
self.ids.scrollContainer.clear_widgets()
wordGrid = GridLayout(cols=2,size_hint_y=None)
wordGrid.bind(minimum_height=wordGrid.setter('height'))
for w in self.wordList:
wordGrid.add_widget(Label(text=w))
wordGrid.add_widget(Label(text='property of word'))
self.ids.scrollContainer.add_widget(wordGrid)
class testScreenManager(ScreenManager):
pass
class testApp(App):
def build(self):
sm = testScreenManager()
return sm
if __name__=='__main__':
testApp().run()
In test.kv:
<testScreenManager>
InputScreen:
id: inputScreen
name: 'input'
WordScreen:
id: wordScreen
name: 'word'
wordList: inputScreen.wordList
<InputScreen>:
GridLayout:
cols: 1
TextInput:
id: textInput
hint_text: 'Input paragraph'
BoxLayout:
orientation: 'horizontal'
size_hint_y: .2
Button:
text: 'Analyze paragraph'
on_press: root.getwords()
Button:
text: 'See word list'
on_press:
root.getwords()
root.manager.transition.direction = 'left'
root.manager.current = 'word'
BoxLayout:
orientation: 'horizontal'
size_hint_y: .2
Label:
id: wordCountResult
text: ''
<WordScreen>:
on_enter: root.updateWords()
BoxLayout:
orientation: 'vertical'
BoxLayout:
id: rowLabels
orientation: 'horizontal'
size_hint_y: .2
Label:
text: 'Words not at grade level:'
size_hint_x: .5
Label:
text: 'Grade Level'
size_hint_x: .5
ScrollView:
id: scrollContainer
size_hint: (None,None)
size: (self.parent.width,self.parent.height - rowLabels.height - buttonRow.height)
Button:
id: buttonRow
size_hint_y: .2
text: 'Back'
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'input'
<WordLabel>:
size_hint_y: None
height: '29sp'
I've tried using size_hint_y=.6 for the ScrollView, and swapping height and minimum_height in the wordGrid.bind(minimum_height=wordGrid.setter('height')).
What I thought was going to happen, is that the ScrollView container will be the height of the window minus the height used by two other widgets. Inside the ScrollView, WordGrid is longer (the height is bound to the minimum height necessary for all children) and so the scrolling is used to see all the items. I must not be understanding some fact about heights/sizes of ScrollView, WordGrid, and WordGrid's children. Anyone have some insight?
In this part of the code:
for w in self.wordList:
wordGrid.add_widget(Label(text=w))
wordGrid.add_widget(Label(text='property of word'))
the Label by default will have size_hint_y=1. Instead, size_hint_y=None is necessary. A height can be set, as is done in the WordLabel class - which was what the OP (by me) meant to do.
Thanks to related question Kivy ScrollView - Not Scrolling for helping me to realize the error.