I'm trying to create a digital notebook app using kivy. I have my basic screen and a ScrollView of the lined sheet I want to use. It seems to be fine, but I now want this sheet to be infinite - meaning you'd be able to keep scrolling down and have more lines of it (like having the image duplicate itself vertically). How can I do that?
I'd really appreciate any help :)
Python code:
import kivy
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from PIL import Image as Image1
from kivy.uix.image import Image
GUI = Builder.load_file('style.kv')
img_size = Image1.open("images/notebook.png").size
class NotebookScreen(GridLayout):
def __init__(self, **kwargs):
self.rows = 1
super(NotebookScreen, self).__init__(**kwargs)
def get_size_for_notebook(self, **kwargs):
global img_size
width, height = Window.size
return width, (img_size[0] * height / width)
class MainApp(App):
def build(self):
return NotebookScreen()
if __name__ == "__main__":
MainApp().run()
kv file:
<NotebookScreen>
FloatLayout:
rows: 2
GridLayout:
size_hint: 1, .05
pos_hint: {"top": 1, "left": 1}
id: tool_bar
cols: 1
canvas:
Color:
rgba: 0, 0, 1, 1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
id: notebook_grid
size_hint: 1, .95
pos_hint: {"top": .95, "left": .97}
cols: 1
ScrollView:
do_scroll: (False, True) # up and down
Image:
id: notebook_image
source: 'images/notebook.png'
allow_stretch: True
keep_ratio: False
pos: self.pos
size: root.get_size_for_notebook()
size_hint: 1, None
You can do that by using a BoxLayout
to hold the lined sheet Image
. Then you can just add more instances of the same Image
to the BoxLayout
as needed. Here is a version of your code that does that:
from kivy.lang import Builder
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.core.window import Window
from PIL import Image as Image1
from kivy.uix.image import Image
#GUI = Builder.load_file('style.kv')
Builder.load_string('''
<NotebookScreen>
FloatLayout:
GridLayout:
size_hint: 1, .05
pos_hint: {"top": 1, "left": 1}
id: tool_bar
cols: 1
canvas:
Color:
rgba: 0, 0, 1, 1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
id: notebook_grid
size_hint: 1, .95
pos_hint: {"top": .95, "left": 0}
cols: 1
MyScrollView:
do_scroll: (False, True) # up and down
BoxLayout:
id: notebook_images
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
MyImage:
<MyImage>:
source: 'images/notebook.png'
allow_stretch: True
keep_ratio: True
size_hint: None, None
size: self.get_size_for_notebook()
''')
Window.size = (1000, 200)
img_size =Image1.open("images/notebook.png").size
class MyImage(Image):
def get_size_for_notebook(self, **kwargs):
global img_size
width, height = Window.size
return width, (img_size[0] * height / width)
class MyScrollView(ScrollView):
def on_scroll_y(self, instance, scroll_val):
if scroll_val < 0.05: # no logic for this number
box = App.get_running_app().root.ids.notebook_images
new_image = MyImage()
box.add_widget(new_image)
self.scroll_y = new_image.height / box.height # a more careful calculation may provide smoother operation
class NotebookScreen(GridLayout):
def __init__(self, **kwargs):
self.rows = 1
super(NotebookScreen, self).__init__(**kwargs)
class MainApp(App):
def build(self):
return NotebookScreen()
if __name__ == "__main__":
MainApp().run()
The use of Builder.load_string()
instead of load_file()
is just for my own convenience.