Reloading a Kivy Screen with a Button Push - python

I am currently trying to create an application that compares two user's playlist to each other using Spotipy and Kivy. My issue is when I try to switch pages in kivy, the page that I switch to doesn't have any of the elements that it is supposed to be loaded with from a previous function.
My main.py file builds the user login page (just asks for two usernames currently), then calls a validate function with a submit button. The validate function calls spotify's api to get each an OAuth token and then calls the PlaylistScreen class's function "show_playlists" which searches the passed in users' playlists and is supposed to add them to the PlaylistPage's floatlayout. Then the submit button from the login page should update the page to be the PlaylistPage that has the two grids full of togglebuttons with a submit button.
For some reason, when you press the button the API is called and all of the playlists are gotten and it looks like the widgets are all populated exactly how I want them to be, but nothing is output to the screen.
Here is my main.py code (Leaving out my ClientID and ClientSecret for the OAuth):
import sys
from statistics import mean
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.config import Config
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from functools import partial
import spotipy
from spotipy.oauth2 import SpotifyOAuth
import spotipy.util as util
scope = 'user-library-read'
# Setting resizeable window
Config.set('graphics', 'resizable', True)
# Class for storing song data for each track.
class SongData:
def __init__(self, name, dance, energy, key, loudness, speechiness, acousticness, instrumentalness, liveness,
valence, tempo):
self.name = name
self.dance = dance
self.energy = energy
self.key = key
self.loudness = loudness
self.speechiness = speechiness
self.acousticness = acousticness
self.instrumentalness = instrumentalness
self.liveness = liveness
self.valence = valence
self.tempo = tempo
# Class for storing playlists.
class Playlist:
def __init__(self, name, songlist):
self.name = name
self.songList = songlist
# Class to show login Page
class LoginPage(Screen):
user = ObjectProperty(None)
#staticmethod
def validate(user1, user2):
auth_manager = SpotifyOAuth(scope=scope, client_id='#your spotify client ID#',
client_secret='#your spotify client secret#',
redirect_uri='http://localhost:8080/')
sp = spotipy.Spotify(auth_manager=auth_manager)
PlaylistPage().show_playlists(sp, user1, user2)
# 37i9dQZF1EVHGWrwldPRtj
# 48s1ymkG8LOVAxoXV20Uyx
pass
class PlaylistPage(Screen):
sp = ObjectProperty(None)
screenmanager = ObjectProperty(None)
selected_playlist_1 = ObjectProperty(None)
selected_playlist_2 = ObjectProperty(None)
def __init__(self, **kw):
super().__init__(**kw)
def show_playlists(self, sp, user1, user2):
outer_grid = GridLayout(cols=2)
user1_all_playlists = sp.user_playlists(user1)
user2_all_playlists = sp.user_playlists(user2)
user1_grid = GridLayout(cols=1)
user2_grid = GridLayout(cols=1)
user_list = []
b1_list = []
b2_list = []
for cur_list in enumerate(user1_all_playlists['items']):
b = ToggleButton(text=cur_list[1]['name'], group='user1')
b.id = cur_list[0]
b1_list.append(b)
user_list.append(cur_list)
user1_grid.add_widget(b)
print(cur_list[1]['name'])
print()
outer_grid.add_widget(user1_grid)
if user2_all_playlists:
for cur_list in enumerate(user2_all_playlists['items']):
b = ToggleButton(text=cur_list[1]['name'], group='user2')
b.id = cur_list[0]
b2_list.append(b)
user_list.append(cur_list)
user2_grid.add_widget(b)
print(cur_list[1]['name'])
print()
outer_grid.add_widget(user2_grid)
self.ids.playlist_layout.add_widget(outer_grid)
submit = Button(text="Compare Playlists")
submit.bind(on_press=self.compute_avg)
self.ids.playlist_layout.add_widget(submit)
self.ids.playlist_layout.do_layout()
def compute_avg(self):
result = self.sp.playlist_items(self.selected_playlist_1[1]['id'])
track_list1 = []
for track in result['items']:
track_uri = track["track"]["uri"]
track_name = track["track"]["name"]
track_data = self.sp.audio_features(track_uri)[0]
track_dance = track_data["danceability"]
track_energy = track_data["energy"]
track_key = track_data["key"]
track_loudness = track_data["loudness"]
track_speechiness = track_data["speechiness"]
track_acousticness = track_data["acousticness"]
track_instrumentalness = track_data["instrumentalness"]
track_liveness = track_data["liveness"]
track_valence = track_data["valence"]
track_tempo = track_data["tempo"]
this_track = SongData(track_name, track_dance, track_energy, track_key, track_loudness,
track_speechiness, track_acousticness, track_instrumentalness,
track_liveness, track_valence, track_tempo)
track_list1.append(this_track)
result = self.sp.playlist_items(self.selected_playlist_1[1]['id'])
track_list2 = []
for track in result['items']:
track_uri = track["track"]["uri"]
track_name = track["track"]["name"]
track_data = self.sp.audio_features(track_uri)[0]
track_dance = track_data["danceability"]
track_energy = track_data["energy"]
track_key = track_data["key"]
track_loudness = track_data["loudness"]
track_speechiness = track_data["speechiness"]
track_acousticness = track_data["acousticness"]
track_instrumentalness = track_data["instrumentalness"]
track_liveness = track_data["liveness"]
track_valence = track_data["valence"]
track_tempo = track_data["tempo"]
this_track = SongData(track_name, track_dance, track_energy, track_key, track_loudness,
track_speechiness, track_acousticness, track_instrumentalness,
track_liveness, track_valence, track_tempo)
track_list2.append(this_track)
p1_name = self.sp.playlist(self.ids.playlist_1.text)['name']
p2_name = self.sp.playlist(self.ids.playlist_2.text)['name']
p1 = Playlist(p1_name, track_list1)
p2 = Playlist(p2_name, track_list2)
avg_list1 = SongData(p1.name, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
for i, song in enumerate(p1.songList, start=1):
avg_list1.dance += song.dance
avg_list1.energy += song.energy
avg_list1.key += song.key
avg_list1.loudness += song.loudness
avg_list1.speechiness += song.speechiness
avg_list1.acousticness += song.acousticness
avg_list1.instrumentalness += song.instrumentalness
avg_list1.liveness += song.liveness
avg_list1.valence += song.valence
avg_list1.tempo += song.tempo
avg_list2 = SongData(p2.name, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
for i, song in enumerate(p2.songList, start=1):
avg_list2.dance += song.dance
avg_list2.energy += song.energy
avg_list2.key += song.key
avg_list2.loudness += song.loudness
avg_list2.speechiness += song.speechiness
avg_list2.acousticness += song.acousticness
avg_list2.instrumentalness += song.instrumentalness
avg_list2.liveness += song.liveness
avg_list2.valence += song.valence
avg_list2.tempo += song.tempo
self.clear_widgets()
self.canvas.clear()
outer_grid = GridLayout(cols=3)
grid1 = GridLayout(cols=1)
grid2 = GridLayout(cols=1)
n_text = f"Name: {avg_list1.name}"
n = Button(disabled=True, text=n_text)
grid1.add_widget(n)
d_text = f"Danceability Avg: {avg_list1.dance / len(p1.songList):,.4f}"
d = Button(disabled=True, text=d_text)
grid1.add_widget(d)
e_text = f'Energy Avg: {avg_list1.energy / len(p1.songList):,.4f}'
e = Button(disabled=True, text=e_text)
grid1.add_widget(e)
k_text = f"Key Avg: {avg_list1.key / len(p1.songList):,.4f}"
k = Button(disabled=True, text=k_text)
grid1.add_widget(k)
loud_text = f"Loudness Avg: {avg_list1.loudness / len(p1.songList):,.4f}"
loud = Button(disabled=True, text=loud_text)
grid1.add_widget(loud)
s_text = f"Speechiness Avg: {avg_list1.speechiness / len(p1.songList):,.4f}"
s = Button(disabled=True, text=s_text)
grid1.add_widget(s)
a_text = f"Acousticness Avg: {avg_list1.acousticness / len(p1.songList):,.4f}"
a = Button(disabled=True, text=a_text)
grid1.add_widget(a)
i_text = f"Instrumentalness Avg: {avg_list1.instrumentalness / len(p1.songList):,.4f}"
i = Button(disabled=True, text=i_text)
grid1.add_widget(i)
live_text = f"Liveness Avg: {avg_list1.liveness / len(p1.songList):,.4f}"
live = Button(disabled=True, text=live_text)
grid1.add_widget(live)
t_text = f"Tempo Avg: {avg_list1.tempo / len(p1.songList):,.4f}"
t = Button(disabled=True, text=t_text)
grid1.add_widget(t)
#########################################################################################
n_text = f"Name: {avg_list2.name}"
n = Button(disabled=True, text=n_text)
grid2.add_widget(n)
d_text = f"Danceability Avg: {avg_list2.dance / len(p2.songList):,.4f}"
d = Button(disabled=True, text=d_text)
grid2.add_widget(d)
e_text = f'Energy Avg: {avg_list2.energy / len(p2.songList):,.4f}'
e = Button(disabled=True, text=e_text)
grid2.add_widget(e)
k_text = f"Key Avg: {avg_list2.key / len(p2.songList):,.4f}"
k = Button(disabled=True, text=k_text)
grid2.add_widget(k)
loud_text = f"Loudness Avg: {avg_list2.loudness / len(p2.songList):,.4f}"
loud = Button(disabled=True, text=loud_text)
grid2.add_widget(loud)
s_text = f"Speechiness Avg: {avg_list2.speechiness / len(p2.songList):,.4f}"
s = Button(disabled=True, text=s_text)
grid2.add_widget(s)
a_text = f"Acousticness Avg: {avg_list2.acousticness / len(p2.songList):,.4f}"
a = Button(disabled=True, text=a_text)
grid2.add_widget(a)
i_text = f"Instrumentalness Avg: {avg_list2.instrumentalness / len(p2.songList):,.4f}"
i = Button(disabled=True, text=i_text)
grid2.add_widget(i)
live_text = f"Liveness Avg: {avg_list2.liveness / len(p2.songList):,.4f}"
live = Button(disabled=True, text=live_text)
grid2.add_widget(live)
t_text = f"Tempo Avg: {avg_list2.tempo / len(p2.songList):,.4f}"
t = Button(disabled=True, text=t_text)
grid2.add_widget(t)
outer_grid.add_widget(grid1)
outer_grid.add_widget(grid2)
def div(v1, v2):
if v1 < v2:
return v1/v2
return v2/v1
dance_comp = div(avg_list1.dance, avg_list2.dance)
energy_comp = div(avg_list1.energy, avg_list2.energy)
key_comp = div(avg_list1.key, avg_list2.key)
loudness_comp = div(avg_list1.loudness, avg_list2.loudness)
speechiness_comp = div(avg_list1.speechiness, avg_list2.speechiness)
acousticness_comp = div(avg_list1.acousticness, avg_list2.acousticness)
instrumentalness_comp = div(avg_list1.instrumentalness, avg_list2.instrumentalness)
liveness_comp = div(avg_list1.liveness, avg_list2.liveness)
valence_comp = div(avg_list1.valence, avg_list2.valence)
tempo_comp = div(avg_list1.tempo, avg_list2.tempo)
comp_list = [dance_comp, energy_comp, key_comp, loudness_comp, speechiness_comp, acousticness_comp,
instrumentalness_comp, liveness_comp, valence_comp, tempo_comp]
comp_string = f"Compatibility: {(mean(comp_list))*100:2f}%"
comp_b = Button(disabled=True, text=comp_string, size=(20, 50))
outer_grid.add_widget(comp_b)
self.add_widget(outer_grid)
# Class for managing all windows in the application
class WindowManager(ScreenManager):
pass
# KV File
kv = Builder.load_file('PTStyles.kv')
Window.clearcolor = (0, 0.5, 0.05, 10)
Window.size = (600, 600)
sm = WindowManager()
sm.add_widget(LoginPage(name='login'))
sm.add_widget(PlaylistPage(name='playlists'))
# Class to run application.
class PTApp(App):
# Code to build the application's view.
def build(self):
return sm
# Run the App
if __name__ == "__main__":
PTApp().run()
And here is my .kv file:
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
#:import SwapTransition kivy.uix.screenmanager.SwapTransition
#:import WipeTransition kivy.uix.screenmanager.WipeTransition
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import RiseInTransition kivy.uix.screenmanager.RiseInTransition
#:import FallOutTransition kivy.uix.screenmanager.FallOutTransition
#:import NoTransition kivy.uix.screenmanager.NoTransition
WindowManager:
LoginPage:
PlaylistPage:
<LoginPage>:
username1 : user_1
username2 : user_2
FloatLayout:
id: login_layout
size: root.width, root.height
cols: 1
Label:
id: u1_l
name: 'u1'
text: "User 1:"
size_hint: 0.2, 0.1
pos_hint: {"x":0.25, "top":0.8}
TextInput:
id: user_1
name: 'user1'
text: 'joewilkinson00'
hint_text: 'User 1...'
size_hint: 0.5, 0.075
pos_hint: {"x":0.25, "top": 0.7}
Label:
id: u2_l
name: 'u2'
text: "User 2: "
size_hint: 0.2, 0.1
pos_hint: {"x":0.25, "top":0.6}
TextInput:
id: user_2
name: 'user2'
text: 'kenzieloupete'
hint_text: 'User 2...'
size_hint: 0.5, 0.075
pos_hint: {"x":0.25, "top": 0.5}
Button:
id: submit_button
name: 'submit'
text: 'Select Users'
size_hint: 0.5, 0.1
pos_hint: {"x":0.25, "top" : 0.4}
on_release:
root.validate(user_1.text, user_2.text)
root.manager.transition.direction = 'left'
root.manager.current = 'playlists'
<PlaylistPage>:
name: 'playlists'
FloatLayout:
id: playlist_layout
name: 'playlist_layout'
size: root.width, root.height
cols: 1
Thank you in advance if anyone is able to help me with this problem. I have been trying to figure out a way though this for days, to the ponit where I have considered switching to a technology where it is easier to switch between screens.
P.S.: If anyone has a good algorithm for looping through two lists and taking the averages between individual nodes in each list, that would be very helpful as I know my method right now is unlrealiable and a lot of lines of code.

Replace:
#staticmethod
def validate(user1, user2):
with:
def validate(self, user1, user2):
and:
PlaylistPage().show_playlists(sp, user1, user2)
with:
self.manager.get_screen('playlists').show_playlists(sp, user1, user2)
Then within PTStyles.kv file replace:
<PlaylistPage>:
name: 'playlists'
FloatLayout:
with:
<PlaylistPage>:
name: 'playlists'
GridLayout:
When kivy loads kv file it makes objects from classes defined within kv, so there are objects created for WindowManager, LoginPage and PlaylistPage.
Your mistake was that you created brand new PlaylistPage object instance and called it's method within line:
PlaylistPage().show_playlists(sp, user1, user2)
It works but this way you created another PlaylistPage object, which was not known to WindowManager. Your widgets were added, but NOT to already existing PlaylistPage object instance, created by Kivy itself. You have to retrieve object from WindowManager, then call your show_playlists method on it. It will add your widgets from the code to proper screen object. I also replaced FloatLayout with GridLayout, because last added widget (submit button) covered all screen area , making your GridLayouts not visible at all. Enjoy!

The line of code:
PlaylistPage().show_playlists(sp, user1, user2)
is creating a new instance of PlaylistPage and calling its show_playlists() method. However, that new instance of PlaylistPage is not part of your GUI. You need to access the instance of PlaylistPage that is in your GUI. You can do that by using the get_screen() method of ScreenManager, like this:
self.manager.get_screen('playlists').show_playlists(sp, user1, user2)
in place of the previous code.

Related

Why is ScrollView text displayed only with a certain font_size value?

I have a program that parses text from a site and outputs it. But the problem is that when I put this text in ScrollView then at 4 pages of the book it is displayed, but at 57 pages it simply is not. Only if I change the value of font_size to 1, only then the entire text of the book is displayed, but obviously this is not what I need. How to solve this problem?
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from bs4 import BeautifulSoup
from kivy.uix.scrollview import ScrollView
import requests
Builder.load_string('''
# Define the scroll view
<ScrollableLabel>:
Label:
id: label
color: (1,1,1,1)
font_size: 15
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
''')
class MyButton(Button):
color = (0, 0, 0, 1)
valign = 'bottom'
padding_y = 10
background_color = (.93, .91, .67, 1)
background_normal = ''
class ScrollableLabel(ScrollView):
pass
class Box(BoxLayout):
color = (.98, .98, .82, 1)
orientation = "vertical"
padding = [5, 5, 5, 5]
spacing = 10
def on_kv_post(self, widget):
self.add_widget(MyButton(text='И. С. Тургенев. «Отцы и дети»', on_press=self.btn_press))
def btn_press(self, instance):
self.clear_widgets()
sc = ScrollableLabel()
x = 1
data = ''
while True:
if x == 1:
url = "http://loveread.ec/read_book.php?id=12021&p=1"
elif x < 4:
url = "http://loveread.ec/read_book.php?id=12021&p=" + f'{x}'
else:
break
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
x = x + 1
sc.ids.label.text = data
self.add_widget(sc)
class MyApp(App):
def build(self):
return Box()
if __name__ == "__main__":
MyApp().run()

Kivy: how to access IDs created in python code

I have this code below. I've set id by python code, but I couldn't access.
def abrirReceita(self,instance):
instance.text = str(instance.ids)
I'd like to change the text with the number of the ID when I press.
Exemple: if I input the first button, change the text for '1', which is the ID I've passed.
from kivymd.app import MDApp
from kivymd.uix.boxlayout import BoxLayout
from kivymd.uix.floatlayout import FloatLayout
from kivymd.uix.list import TwoLineListItem
from kivymd.uix.textfield import MDTextField
from kivy.lang import Builder
import os
from kivy.core.window import Window
import sqlite3
KV = '''
ScreenManager:
Screen:
name: 'telaSelecionada'
BoxLayout:
orientation: 'vertical'
MDToolbar:
id: tb
title: 'Drinks'
md_bg_color: 0, 0, 0, 1
TelaSelecionada:
id: telaselecionada
<TelaSelecionada>:
ScrollView:
MDList:
id: mostraReceita
padding: '20dp'
'''
Window.softinput_mode = "below_target"
class TelaSelecionada(FloatLayout):
pass
class Aplicativo(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
i = 1
for x in range(5):
self.textLine = TwoLineListItem(text = 'change text', secondary_text = 'change text')
self.root.ids.telaselecionada.ids.mostraReceita.add_widget(self.textLine)
self.root.ids.telaselecionada.ids.mostraReceita.ids[i] = self.textLine
self.textLine.bind(on_release = self.abrirReceita)
i += 1
def abrirReceita(self,instance):
instance.text = str(instance.ids)
Aplicativo().run()
How do I access the IDs from python code?
I'd like to change the text with the number of the ID when I press.
Just pass the required args through method abrirReceita using functools.partial as,
def on_start(self):
...
self.textLine.bind(on_release = partial(self.abrirReceita, i))
i += 1
# Then in `abrirReceita` :
def abrirReceita(self, id_index, instance):
instance.text = str(id_index)
Note:
The ids are not used here at all (actually you don't need that here for this purpose) !
Update:
As, the Widget.id has been deprecated since version 2.0.0 you should use it only in kvlang not in python.
But that doesn't keep you from creating it as a dynamically added attribute. Thus you can do something like this (I modified the on_start method a little):
def on_start(self):
mostraReceita = self.root.ids.telaselecionada.ids.mostraReceita
for i, _ in enumerate(range(5), start=1):
# Or just,
# for i in range(1, 5+1):
self.textLine = TwoLineListItem(
text = 'change text',
secondary_text = 'change text',
)
self.textLine.index = i
# Or even,
# self.textLine.id = i
self.textLine.bind(on_release = self.abrirReceita)
mostraReceita.add_widget(self.textLine)
def abrirReceita(self,instance):
instance.text = str(instance.index) # or, str(instance.id)

Kivy callbacks for instanced buttons/widgets?

I am trying to make some instanced buttons that will trigger the 'on_toggle_button_state' function like the KV snippet below. I'm sure it's something simple I've overlooked, but this has stumped me for longer than I'd like to admit.
AttributeError: 'ToggleButtons' object has no attribute 'state'
class ToggleButtons(StackLayout):
def __init__(self, *args, **kwargs):
super().__init__(**kwargs)
conn = sqlite3.connect('players_db.db')
c = conn.cursor()
c.execute("DELETE FROM players WHERE (name IS NULL OR name = '')") ##Remove empty entries
c.execute("SELECT * FROM players")
records = c.fetchall()
records = list(filter(None, records))
for i in range(0, len(records)):
name = str(records[i])[2:-3]
b = ToggleButton(size_hint = (0.2, 0.2), text = name, on_state = self.on_toggle_button_state())
self.add_widget(b)
def on_toggle_button_state(self, widget):
print("toggle state: " + widget.state)
if widget.state == "normal":
widget.text = "OFF"
self.count_enabled = False
else:
widget.text = "ON"
self.count_enabled = True
KV that works for not-instanced buttons:
StackLayout:
ToggleButton:
text: "Charlie"
on_state: root.on_toggle_button_state(self)
size_hint: 0.2, 0.2
In you kv file use <ToggleButton>: to assign the on_state method with self.parent.on_toggle_button_state(self).
self is the dynamically instantiated button and parent is the ToggleButtons StackLayout where you have defined the on_toggle_button_state method.
I've modified your code a bit so I could run it without the SQL stuff. So ignore these changes.
The difference between ToggleButton and <ToggleButton> is that the first places an instance into the StackLayout - not what you want here.
And the bracket notation, defines methods & styles for each of your instances.
Please find the snippet below with the mentioned change:
from kivy.app import App
from kivy.uix.stacklayout import StackLayout
from kivy.uix.button import Button
from kivy.lang import Builder
kv = '''
StackLayout:
<ToggleButton>:
text: "Charlie"
on_state:
self.parent.on_toggle_button_state(self)
size_hint: 0.2, 0.2
'''
Builder.load_string(kv)
class ToggleButton(Button):
pass
class ToggleButtons(StackLayout):
def __init__(self, *args, **kwargs):
super().__init__(**kwargs)
# conn = sqlite3.connect('players_db.db')
# c = conn.cursor()
# c.execute("DELETE FROM players WHERE (name IS NULL OR name = '')") ##Remove empty entries
# c.execute("SELECT * FROM players")
# records = c.fetchall()
# records = list(filter(None, records))
records = ["test1", "test2"]
for i in range(0, len(records)):
# name = str(records[i])[2:-3]
name = records[i] # just for testing
print(name)
b = ToggleButton(size_hint = (0.2, 0.2), text = name, on_state = self.on_toggle_button_state)
self.add_widget(b)
def on_toggle_button_state(self, widget):
print("toggle state: " + widget.state)
if widget.state == "normal":
widget.text = "OFF"
widget.count_enabled = False
else:
widget.text = "ON"
widget.count_enabled = True
class MyApp(App):
def build(self):
return ToggleButtons()
if __name__ == '__main__':
MyApp().run()

Python Kivy: how to make execute a method after widgets Kivy file has loaded

I'm trying to build an interactive school timetable using Kivy. My logic is written inside Python and all layouts and the general estetic is written in Kivy files. I want to run a specific method right after the Kivy file has loaded so it changes the text of the buttons to display.
Here is how it looks after I start it:
Here is how I want my app to look like after I start it:
The names of days and lessons are in Polish .
Here is the code of planchart.py
class Okienko(Button):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.lessons = []
f = open("/interaktywny_plan/classes.dat", "rb")
pon = pickle.load(f)
wto = pickle.load(f)
sro = pickle.load(f)
czw = pickle.load(f)
pt = pickle.load(f)
f.close()
self.lessons.append(pon)
self.lessons.append(wto)
self.lessons.append(sro)
self.lessons.append(czw)
self.lessons.append(pt)
self.lesson = ""
self.sub_press = ""
def on_release(self):
self.text = self.lesson
def on_press(self):
self.text = self.sub_press
def update_button(self):
if self.name_ == "one_pon":
self.lesson = self.lessons[0][0][0]
self.sub_press = self.lessons[0][0][1] + "\n" + self.lessons[0][0][2]
elif self.name_ == "two_pon":
self.lesson = self.lessons[0][1][0]
self.sub_press = self.lessons[0][1][1] + "\n" + self.lessons[0][1][2]
elif self.name_ == "three_pon":
self.lesson = self.lessons[0][2][0]
self.sub_press = self.lessons[0][2][1] + "\n" + self.lessons[0][2][2]
elif self.name_ == "four_pon":
self.lesson = self.lessons[0][3][0]
self.sub_press = self.lessons[0][3][1] + "\n" + self.lessons[0][3][2]
.............
Here is the Kivy code:
<Okienko>:
background_color: [.5, .9, 1, 1]
halign: "center"
size_hint: None, None
font_size: 24
size: 96, 96
on_press: self.on_press()
on_release: self.on_release()
<PlanChart>:
cols: 11
padding: 2
Dzien:
id: pon
text: "Pon"
Okienko:
id: one_pon
name_: "one_pon"
Okienko:
id: two_pon
name_: "two_pon"
Okienko:
id: three_pon
name_: "three_pon"
Okienko:
id: four_pon
name_: "four_pon"
Okienko:
id: five_pon
name_: "five_pon"
..............
I tried using #mainthread and putting self.update_button() in __init__ but it would still start empty. I tried just putting self.update_button() in __init__ but I would get AtributeError becouse the Kivy file was not loaded. After that I read about Clock module but I couldn't figure how to use it properly.
You can use the Clock module to schedule a method call for after the Kivy file is loaded:
from kivy.clock import Clock
Clock.schedule_once(self.update_button, .1)

Kivy Custom Widget Sizing within a Layout

I'm trying to use a custom widget within a layout in another application, but instead of scaling correctly within the layout, it's taking up the entire screen. Here's the .kv files, broken down to the relevant parts (I took out all the callbacks, which function as expected):
<NodeWidget>
BoxLayout:
orientation: 'horizontal'
size:root.size
ToggleButton:
size_hint: 0.10345, 1
group: 'Ends'
background_normal: 'Left_Up.png'
background_down: 'Left_Down.png'
Button:
size_hint: 0.801724, 1
background_normal: 'Center_Button_Up.png'
background_down: 'Center_Button_Down.png'
ToggleButton:
size_hint: 0.094827, 1
group: 'Ends'
background_normal: 'Right_Up.png'
background_down: 'Right_Down.png'
Below is the .kv file for the separate app that's importing the class from above and using it:
<NodeEditorWidget>:
GridLayout:
size: root.size
cols: 3
Label:
text: 'Test 1'
NodeWidget:
...
Label:
text: 'Test 3'
Here's what I see when I run the test app now:
Thanks in advance for your help!
So I solved this by moving it back to straight python, no .kv files. Here's the code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ListProperty, StringProperty, BooleanProperty, ObjectProperty, NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
#This widget contains two buttons
#The buttons each expose two events
#Names still aren't functioning
class NodeWidget(BoxLayout):
#We expose events:
#on_press when the central button is pressed
#on_release when the central button is released
#on_press_right when the right button is pressed
#on_press_left when the left button is pressed
press = BooleanProperty(False)
release = BooleanProperty(False)
press_right = BooleanProperty(False)
press_left = BooleanProperty(False)
release_right = BooleanProperty(False)
release_left = BooleanProperty(False)
#Properties exposed to set internal properties
title = StringProperty('')
left_background_normal = StringProperty('Left_Up.png')
left_background_down = StringProperty('Left_Down.png')
center_background_normal = StringProperty('Center_Button_Up.png')
center_background_down = StringProperty('Center_Button_Down.png')
right_background_normal = StringProperty('Right_Up.png')
right_background_down = StringProperty('Right_Down.png')
font_name = StringProperty('Roboto')
markup = BooleanProperty(True)
padding_x = NumericProperty(0)
padding_y = NumericProperty(0)
#Which node is active
active_left = BooleanProperty(False)
active_right = BooleanProperty(False)
#Object Properties for internal elements
left_button = ObjectProperty(None)
center_button = ObjectProperty(None)
right_button = ObjectProperty(None)
def __init__(self, **kwargs):
super(NodeWidget, self).__init__(**kwargs)
center = Button()
left = ToggleButton()
right = ToggleButton()
left.size_hint = (0.10345, 1)
center.size_hint = (0.801724, 1)
right.size_hint = (0.094827, 1)
left.background_normal = 'Left_Up.png'
left.background_down = 'Left_Down.png'
center.background_normal = 'Center_Button_Up.png'
center.background_down = 'Center_Button_Down.png'
right.background_normal = 'Right_Up.png'
right.background_down = 'Right_Down.png'
left.group = 'ends'
right.group = 'ends'
left.bind(on_press=self.ActivateNode_Left)
left.bind(on_release=self.ReleaseNode_Left)
right.bind(on_press=self.ActivateNode_Right)
right.bind(on_release=self.ReleaseNode_Right)
center.bind(on_press=self.PressNode)
center.bind(on_release=self.ReleaseNode)
self.left_button = left
self.center_button = center
self.right_button = right
self.bind(title=self.SetTitle)
self.bind(left_background_normal=self.SetLeftBackgroundNormal)
self.bind(left_background_down=self.SetLeftBackgroundDown)
self.bind(center_background_normal=self.SetCenterBackgroundNormal)
self.bind(center_background_down=self.SetCenterBackgroundDown)
self.bind(right_background_normal=self.SetRightBackgroundNormal)
self.bind(right_background_down=self.SetRightBackgroundDown)
self.bind(font_name=self.SetFontName)
self.bind(markup=self.SetMarkup)
self.bind(padding_x=self.SetPaddingX)
self.bind(padding_y=self.SetPaddingY)
self.add_widget(left)
self.add_widget(center)
self.add_widget(right)
def ActivateNode_Left(self, *args):
if self.active_left == False:
self.active_left = True
self.active_right = False
else:
self.active_left = False
self.active_right = True
if self.press_left == True:
self.press_left = False
else:
self.press_left = True
def ActivateNode_Right(self, *args):
if self.active_right == False:
self.active_right = True
self.active_left = False
else:
self.active_right = False
self.active_left = True
if self.press_right == True:
self.press_right = False
else:
self.press_right = True
def ReleaseNode_Left(self, *args):
if self.release_left == True:
self.release_left == False
else:
self.release_left == True
def ReleaseNode_Right(self, *args):
if self.release_right == True:
self.release_right == False
else:
self.release_right == True
def PressNode(self, *args):
if self.press == True:
self.press = False
else:
self.press = True
def ReleaseNode(self, *args):
if self.release == True:
self.release = False
else:
self.release = True
def SetTitle(self, *args):
self.center_button.text = self.title
def SetLeftBackgroundDown(self, *args):
self.left_button.background_down = self.left_background_down
def SetLeftBackgroundNormal(self, *args):
self.left_button.background_normal = self.left_background_normal
def SetCenterBackgroundDown(self, *args):
self.center_button.background_down = self.center_background_down
def SetCenterBackgroundNormal(self, *args):
self.center_button.background_normal = self.center_background_normal
def SetRightBackgroundDown(self, *args):
self.right_button.background_down = self.right_background_down
def SetRightBackgroundNormal(self, *args):
self.right_button.background_normal = self.right_background_normal
def SetFontName(self, *args):
self.center_button.font_name = self.font_name
def SetMarkup(self, *args):
self.center_button.markup = self.markup
def SetPaddingX(self, *args):
self.center_button.padding_x = self.padding_x
def SetPaddingY(self, *args):
self.center_button.padding_y = self.padding_y

Categories

Resources