I want to be able to build a midi sheet as shown here:
I've used a relative layout to place the buttons at certain positions (not finalised, still in testing). However, I can't get the scrollview to scroll horizontally or vertically for that matter. Could someone help me out? Or if you have any suggestions for a better implementation, that would be helpful. Where I create this relative layout is in the screen called MidiSheet:
class MidiSheet(Screen):
def __init__(self, **kwargs):
super(MidiSheet, self).__init__(**kwargs)
screen = ScrollView(size=(Window.width, Window.height), do_scroll_x=True, do_scroll_y=False)
notes = get_notes_in_song("../data/" + self.name)
layout = RelativeLayout(size=(Window.width, Window.height))
layout.add_widget(BackButton(self))
initial_y_pos = Window.height/2
initial_x_pos = Window.width*0.1
for note in notes:
note_name = note.split(":")[1]
layout.add_widget(MidiButton(note_name, initial_x_pos, initial_y_pos))
initial_x_pos += 100
screen.add_widget(layout)
self.add_widget(screen)
Here's my full .py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
import os
def get_notes_in_song(song):
with open(song) as f:
lines = f.readlines()
return lines
class SongButton(Button):
def __init__(self, file_name, **kwargs):
super(SongButton, self).__init__(**kwargs)
self.background_color = [0, 0, 0, 0]
self.size_hint = (0.5, None)
self.height = 40
self.file_name = file_name
def on_press(self):
App.get_running_app().root.add_widget(MidiSheet(name=self.file_name))
App.get_running_app().root.transition.direction = "left"
App.get_running_app().root.current = self.file_name
class BackButton(Button):
def __init__(self, screen_instance, **kwargs):
super(BackButton, self).__init__(**kwargs)
self.background_color = [1, 1, 1, 1]
self.size_hint = (0.1, 0.1)
self.text = "Back"
self.screen_instance = screen_instance
def on_press(self):
App.get_running_app().root.remove_widget(self.screen_instance)
App.get_running_app().root.transition.direction = "right"
App.get_running_app().root.current = "home"
class MidiButton(Button):
def __init__(self, name, pos_x, pos_y, **kwargs):
super(MidiButton, self).__init__(**kwargs)
self.background_color = [1, 1, 1, 1]
self.size_hint = (0.1, 0.1)
self.pos = (pos_x, pos_y)
self.text = name
self.padding = (10, 10)
def on_press(self):
self.background_color = [0, 1, 0, 1] if self.background_color == [1, 1, 1, 1] else [1, 1, 1, 1]
class Home(Screen):
def __init__(self, **kwargs):
super(Home, self).__init__(**kwargs)
screen = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
songs = [x for x in os.listdir("../data/") if ".txt" in x]
for song in songs:
name = song.replace("_", " ").replace(".txt", "")
layout.add_widget(SongButton(song, text=name))
screen.add_widget(layout)
self.add_widget(screen)
class MidiSheet(Screen):
def __init__(self, **kwargs):
super(MidiSheet, self).__init__(**kwargs)
screen = ScrollView(size=(Window.width, Window.height), do_scroll_x=True, do_scroll_y=False)
notes = get_notes_in_song("../data/" + self.name)
layout = RelativeLayout(size=(Window.width, Window.height))
layout.add_widget(BackButton(self))
initial_y_pos = Window.height/2
initial_x_pos = Window.width*0.1
for note in notes:
note_name = note.split(":")[1]
layout.add_widget(MidiButton(note_name, initial_x_pos, initial_y_pos))
initial_x_pos += 100
screen.add_widget(layout)
self.add_widget(screen)
class Localiser(App):
def build(self):
sm = ScreenManager(transition=SlideTransition())
sm.add_widget(Home(name="home"))
return sm
So actually my problem was that the size of my RelativeLayout wasn't bigger than my ScrollView's size. Only if the RelativeLayout is bigger, will there be something to scroll. So I had to disable the size_hint of my layout, and using the pixel size, I was able to make my layout size, bigger than my ScrollView size
screen = ScrollView(size_hint=(None, None), size=(Window.width, Window.height), do_scroll_x=True, do_scroll_y=False)
class MidiLayout(RelativeLayout):
def __init__(self, midi_buttons, **kwargs):
super(MidiLayout, self).__init__(**kwargs)
self.size_hint = (None, None)
self.window_width = Window.width
for note in midi_buttons:
self.window_width += note.size[0]
self.add_widget(note)
self.size = (self.window_width + 100, Window.height)