I have the following kivymd
code:
main.py
import itertools
from ctypes import windll, c_int64
windll.user32.SetProcessDpiAwarenessContext(c_int64(-4)) # Has to be here before kivy import. 4k fix
from kivy.core.window import Window
from kivy.metrics import sp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivymd.app import MDApp
from kivymd.uix.list import OneLineListItem
from skimage.io import imread
import os
import struct
# C:\WPy64-31040\python-3.10.4.amd64\python.exe main.py
import kivy; print(kivy.__version__)
def clickme(list_item):
print(list_item.text)
class MyLayout(BoxLayout):
pass
class MyTextInput(TextInput):
def __init__(self, **kwargs):
super(MyTextInput, self).__init__(**kwargs)
self.size_hint = (None, None)
self.foreground_color = (0, 0, 0, 1) # Text is black.
self.background_color = (0.6, 0.6, 0.6, 0.3) # Background is transparent and therefore not visible.
self.cursor_color = (0, 0, 0, 0) # Hide the cursor by making it transparent.
self.font_size = sp(24)
# Left, right center.
self.halign = 'center'
# self.padding_x = [self.center[0] - self._get_text_width(max(self._lines, key=len), self.tab_width, self._label_cached) / 2.0,
# 0] if self.text else [self.center[0], 0]
# Top, bottom center. Moved to kv file.
# self.padding_y = [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0] # Deprecated. Use padding instead.
# self.padding = [self.padding[0], self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), self.padding[2], 0]
def keyboard_on_textinput(self, window, text):
"""Upper case and always one letter only."""
self.text = text.upper()
class CrosswordApp(MDApp):
def build(self):
return MyLayout()
def on_start(self):
# List of possible crossword candidates.
for i in range(20):
self.root.ids.lst_matches.add_widget(
OneLineListItem(text=f"Single-line item {i} very very very very very long string that hopefully is long enough", on_release=clickme,
divider="Full", font_style="Caption"))
# Get black and white blocks.
# tex = self.root.ids.img_crossword.texture
# for y in range(0, tex.size[1], 5):
# for x in range(0, tex.size[0], 5):
# print(self.get_color_value(x, y, tex))
# Read crossword image using path relative to this file's path.
img = imread(os.path.dirname(os.path.realpath(__file__)) r"\images\Huisgenoot20220605P.png")
dcol = {}
ysize = int(img.shape[0] / 23) # Also len(img)
xsize = int(img.shape[1] / 18) # Also len(img[0])
for y, x in itertools.product(range(23), range(18)):
cnt = r = g = b = 0
for y2, x2 in itertools.product(range(y * ysize, y * ysize ysize - 1), range(x * xsize, x * xsize xsize - 1)):
cnt = cnt 1
r = r img[y2][x2][0]
g = g img[y2][x2][1]
b = b img[y2][x2][2]
dcol[(x, y)] = [int(r / cnt), int(g / cnt), int(b / cnt)]
for row in range(23):
for col in range(18):
v = dcol[col, row]
if v[0] > 230 and v[1] > 230 and v[2] > 230:
print(" ", end="")
elif 167 <= v[0] <= 187 and 203 <= v[1] <= 223 and 203 <= v[2] <= 223:
print("B", end="")
else:
print("#", end="")
print("")
print(dcol[0, 0])
print(dcol[1, 0])
print(dcol[2, 0])
print(dcol[3, 0])
print(dcol[6, 1])
print(dcol[17, 0])
def get_color_value(self, x, y, texture):
"""Get the rgba (0..255) value at x and y of an image texture."""
pixel = texture.get_region(x, y, 1, 1)
bp = pixel.pixels
return struct.unpack('4B', bp) # tuple [c for c in struct.unpack('4B', bp)] # / 255.0
if __name__ == '__main__':
Window.maximize()
CrosswordApp().run()
crossword.kv
#:kivy 2.1.0
<MyTextInput>
<MyLayout>
BoxLayout:
orientation: 'horizontal'
size: root.width, root.height
padding: 0
spacing: 0
Image:
id: img_crossword
source: 'images/Huisgenoot20220605P.png'
size_hint: None, None
size: img_crossword.image_ratio * root.height, root.height
allow_stretch: True
keep_ratio: True
BoxLayout:
orientation: 'vertical'
size_hint: None, None
size: root.width - (img_crossword.image_ratio * root.height), root.height
padding: 0
spacing: 0
ScrollView:
# size_hint: None, 1
width: root.width - (img_crossword.image_ratio * root.height)
do_scroll_x: False
do_scroll_y: True
bar_color: 0, 0, 255, 1
bar_width: 12
MDList:
id: lst_matches
size_hint: None, 0.8
width: root.width - (img_crossword.image_ratio * root.height)
height: self.height
spacing: dp(0)
padding: dp(0)
BoxLayout:
orientation: 'horizontal'
size_hint: None, 0.2
width: root.width - (img_crossword.image_ratio * root.height)
padding: 0
spacing: 0
TextInput:
id: txt_clue
size_hint: 0.4, 0.2
text: 'Clue'
Label:
id: lbl_clue
size_hint: 0.4, 0.2
color: 0, 0, 0, 1
text: 'Clue'
TextInput:
id: txt_word
size_hint: 0.2, 0.2
text: 'Word'
FloatLayout:
MyTextInput:
text: 'A'
pos: img_crossword.pos[0] img_crossword.width / 18 * 16, img_crossword.pos[1] img_crossword.height / 23 * 5
size: img_crossword.width / 18, img_crossword.height / 23
padding: [self.padding[0], self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), self.padding[2], 0]
The MDList
and ScrollView
worked fine when I did not have widgets below it, but since adding the BoxLayout
and the TextInput
and Label
below it; the list does not scroll all the way to the end and instead scrolls a little bit to the first invisible line and then bounces back to show only the first lines. How can I make it scroll to the end again?
CodePudding user response:
The problem is that you are setting a size_hint_y
for the MDList
, but it must be None
in order for the scrolling to work correctly. I suggest the following change:
BoxLayout:
orientation: 'vertical'
size_hint: None, None
size: root.width - (img_crossword.image_ratio * root.height), root.height
padding: 0
spacing: 0
ScrollView:
size_hint: None, 0.8 # set size_hint_y
width: root.width - (img_crossword.image_ratio * root.height)
do_scroll_x: False
do_scroll_y: True
bar_color: 0, 0, 255, 1
bar_width: 12
MDList:
id: lst_matches
size_hint: None, None # set size_hint_y to None
width: root.width - (img_crossword.image_ratio * root.height)
height: self.minimum_height
spacing: dp(0)
padding: dp(0)
BoxLayout:
orientation: 'horizontal'
size_hint: None, 0.2