I am new to Kivy and GUIs in general and I am having a hard time understanding some simple concepts of Kivy callbacks logic. I want to make a simple app to read a CSV and plot a graph from it, so I want the widget that opens the file to trigger a function that adds a FigureCanvaKivyAgg widget that shows the figure.
On my source code I disabled the plotting from the CSV readed as it does not add to the issue at hand. You will see that I tried different ways to trigger the callback, but I only accomplish to trigger the custom event, it does not communicate with the callback nor add the FigureCanva Widget to the Layout.
import pandas as pd
import matplotlib.pyplot as plt
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.filechooser import FileChooserIconView
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
from shark_plot import shark_plot
import os
csv = {'x':[1,2,3,4,5,6],'y':[2,4,6,8,6,12]}
class MyWidget(BoxLayout):
def __init__(self, **kwargs):
super(MyWidget, self).__init__(**kwargs)
self.register_event_type('on_event')
container = BoxLayout(orientation='vertical')
filechooser = FileChooserIconView()
filechooser.bind(on_selection=lambda x: self.selected(filechooser.selection))
print(filechooser.selection,filechooser.path)
open_btn = Button(text='open', size_hint=(1, .2))
open_btn.bind(on_release=lambda x: self.open(filechooser.path, filechooser.selection))
box = BoxLayout(size_hint=(1, .5))
box.bind(on_event= self.action)
# if len(filechooser.path[0])>0:
# # box.add_widget(FigureCanvasKivyAgg(plt.gcf()))
container.add_widget(filechooser)
container.add_widget(open_btn)
container.add_widget(box)
self.add_widget(container)
def on_event(self):
print("Event triggered?")
plt.show()
canva = (FigureCanvasKivyAgg(plt.gcf()))
return canva
def action(self):
print('Action executed??')
canva = (FigureCanvasKivyAgg(plt.gcf()))
self.cb.ask_update()
return canva
def open(self, path, filename):
print(filename)
if len(filename) > 0:
selected_path = os.path.join(path, filename[0])
print(selected_path)
df=pd.read_csv(selected_path)
# fig = shark_plot(df)
fig = plt.plot(csv['x'],csv['y'])
g=self.dispatch('on_event')
print(type(df))
# print(f.read())
return fig
def selected(self, filename):
print("selected: %s" % filename[0])
def on_event_callback():
print("Action Triggered??")
canva = (FigureCanvasKivyAgg(plt.gcf()))
subbox = BoxLayout()
subbox.add_widget(canva)
return subbox
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
Hope that the question is clear, it is my first time making such here :)
Please reach out for any clarifications.
on_event() will run via the dispatch() statement, but there is no connection from on_event() to the add_widget() statement in on_event_callback(), so that never happens. You can either put add_widget() directly in on_event(), or, if you want a separate function, then call it directly from open() without using the kivy register and dispatch().
def on_event(self):
canva = FigureCanvasKivyAgg(plt.gcf())
self.add_widget(canva)
def on_event_callback(self,canva):
self.add_widget(canva)
def open(self, path, filename):
# open data files here etc to load self.csv
plt.plot(self.csv['x'],self.csv['y'])
self.dispatch('on_event')
canva2 = FigureCanvasKivyAgg(plt.gcf())
self.on_event_callback(canva2)
Related
I created a very simple GUI using Kivy which reads a CSV file and populates spinners with the data.
I would like once the spinner has been clicked, it will update the images that are beneath the spinner (using bind).
However, when I call the method updateImages it seems like nothing happens.
I looked at the following question and it seems like I did exactly the same however nothing happens.
How to get value outside function using python and kivy
Any help, please?
from kivy.uix.label import Label
from kivy.uix.spinner import Spinner
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
import pandas as pd
class GUI():
def loadData(self):
self.data = pd.read_csv('data.csv')
self.SValues = range(
min(self.data['sValue']), max(self.data['sValue']))
def updateImage(self, spinner, text):
for statue in self.SValues:
print(self.spinnerObject[statue])
try:
currLink = list(
self.data['Link'][self.data['Name'] == self.spinnerObject[statue].text])[0]
self.imageObject[statue] = Image(source=currLink)
self.imageObject[statue].size_hint = (
1/len(self.SValues), 0.1)
self.imageObject[statue].pos_hint = {
'x': (statue-1)/len(self.SValues), 'y': 0.6}
self.s_layout.add_widget(self.imageObject[statue])
except:
print('cant load image')
def initializeScreen(self):
self.spinnerObject = {}
self.imageObject = {}
self.s_layout = FloatLayout()
self.complete_layout = FloatLayout()
for statue in self.SValues:
self.spinnerObject[statue] = Spinner(text='sValue %d' % statue, values=list(
self.data['Name'][self.data['sValue'] == statue].values))
self.spinnerObject[statue].size_hint = (1/len(self.SValues), 0.1)
self.spinnerObject[statue].pos_hint = {
'x': (statue-1)/len(self.SValues), 'y': 0.7}
self.spinnerObject[statue].bind(text=self.updateImage)
self.s_layout.add_widget(self.spinnerObject[statue])
self.complete_layout.add_widget(self.s_layout)
return self.complete_layout
class MainApp(App):
def build(self):
gui = GUI()
gui.loadData()
layout = gui.initializeScreen()
return layout
if __name__ == '__main__':
MainApp().run()
I am a complete noob on kivy (and object oriented approach in python programming) and I struggle trying to implement a simple file checker (I think I am missing a key element of kivy's logic). I want my app to indicate whether my file is a csv.
class CsvLoader(BoxLayout):
def __init__(self, **kwargs):
super(CsvLoader, self).__init__(**kwargs)
self.btn = Button(text='Please, Drag and Drop your CSV')
self.add_widget(self.btn)
csv = Window.bind(on_dropfile=self._on_file_drop) # this is the s*** part: how to get the file_path?
if str(csv).split('.')[-1] != "csv'" and csv != None:
self.clear_widgets()
btn_error = Button(text='Wrong file type')
self.add_widget(btn_error)
def _on_file_drop(self, window, file_path):
return file_path
class VisualizeMyCsv(App):
def build(self):
return CsvLoader()
if __name__ == '__main__':
VisualizeMyCsv().run()
What am I missing? Thanks
with the function bind you link an action, which in your case on_dropfile that triggers when you place a file, with a function that is called when the event is triggered, so the logic must be done within that method:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.core.window import Window
class CsvLoader(BoxLayout):
def __init__(self, **kwargs):
super(CsvLoader, self).__init__(**kwargs)
self.btn = Button(text='Please, Drag and Drop your CSV')
self.add_widget(self.btn)
Window.bind(on_dropfile=self._on_file_drop)
def _on_file_drop(self, window, file_path):
if str(file_path).split('.')[-1] == "csv'":
print(file_path)
# here you must indicate that it is a .csv file
else:
# it is not a .csv file
print("it is not a .csv file")
class VisualizeMyCsv(App):
def build(self):
return CsvLoader()
if __name__ == '__main__':
VisualizeMyCsv().run()
I am trying to build an app that downloads a file, whose progress can be tracked on a kivy app.
I have looked at the example here and here for the download progress.
This is my code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.popup import Popup
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.clock import Clock
import urllib
URL = "http://s9.videozoo.me/S/saenai_heroine_no_sodatekata_flat_-_11.mp4?st=Ow7pwXbRt6vPWE-kr5Sn1A&e=1498847899&start=0"
class PopupBox(Popup):
pop_up_text = ObjectProperty()
def update_pop_up_text(self, p_message):
self.pop_up_text.text = p_message
class MyApp(App):
# layout
def show_popup(self):
self.pop_up = Factory.PopupBox()
self.pop_up.update_pop_up_text('Running some task...')
self.pop_up.open()
def build(self):
layout = BoxLayout(padding=10, orientation='vertical')
btn1 = Button(text="OK")
btn1.bind(on_press=self.buttonClicked)
layout.add_widget(btn1)
self.lbl1 = Label(text="test")
layout.add_widget(self.lbl1)
self.txt1 = TextInput(text='', multiline=False)
layout.add_widget(self.txt1)
return layout
# button click function
def buttonClicked(self, btn):
self.lbl1.text = "You wrote " + self.txt1.text
self.show_popup()
self.download_file(URL)
self.pop_up.dismiss()
def download_file(self, url):
u = urllib.request.urlopen(url)
meta = u.info()
metaInfo = str(meta).split()
fileTotalbytes = int(metaInfo[46])
data_blocks = []
total = 0
while True:
block = u.read(1024)
data_blocks.append(block)
total += len(block)
hash = ((60 * total) // fileTotalbytes)
print("[{}{}] {}%".format('#' * hash, ' ' * (60 - hash), int(total / fileTotalbytes * 100)), end="\r")
if not len(block):
break
data = b''.join(data_blocks) # had to add b because I was joining bytes not strings
u.close()
# run app
if __name__ == "__main__":
MyApp().run()
However, I am confused as to how do I bind the download_file function with the kivy widget functionality so as to make it work. How do I appropriately modify the print function so as to make it work with the widget
If you block in the mainthread kivy can no longer update the GUI. Instead create a new thread and use the #mainthread annotation to do gui updates.
Instead of the print you have to manipulate kivy widgets. You could create a rectangle and increase the width to 100%. You could create a textinput and output your text there.
I am new to python, and I'm trying to build a simple recording program. With the some help from my previous question, I was able to add a timestamp for each recorded file
EDIT:
I did some research and decided on displaying the files with filechooser... this still does not work
def openfiles(self, *args):
satter2 = BoxLayout(pos= (629, 950), size_hint= (.1,.1))
self.fclv = FileChooserListView(path= '/sdcard/', filters= [‘*.3gp’])
self.fclv.bind(on_selection= self.pressed(fclv.selection)
scatter.add_widget(self.fclv)
self.add_widget(satter2)
def pressed(self, filename):
#with open(os.path.join(path, filename[0]))
if self.soundf is None:
self.soundf = SoundLoader.load(self.path)
if self.soundf.status != 'stop':
self.soundf.stop()
self.soundf.loop = False
self.soundf.play()
Here is a simple example of how to show all 3gp files in your current directory.
from kivy.app import App
from kivy.uix.filechooser import FileChooserListView
from kivy.uix.boxlayout import BoxLayout
class MyLayout(BoxLayout):
def __init__(self,**kwargs):
super(MyLayout,self).__init__(**kwargs)
self.fclv = FileChooserListView(path= '.', filters= ['*.3gp'])
self.add_widget(self.fclv)
class MyApp(App):
def build(self):
return MyLayout()
MyApp().run()
Result is:
I am writing code for a heating control system.
I just want to be able to change the label texts FROM WITHIN PYTHON.
By that I mean, NOT in the GUI code, but somewhere else in the main.
Here is my MWE:
import time
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
import multiprocessing
from kivy.properties import StringProperty
class Data (Widget):
top = StringProperty('hiii')
def __init__(self, **kwargs):
super(Widget, self).__init__(**kwargs)
global mydata
mydata=Data()
class myw (BoxLayout):
def __init__(self, **kwargs):
super(myw, self).__init__(**kwargs)
VERT = BoxLayout(orientation='vertical')
o = Label(text='Oben: ',
font_size=120)
m = Label(text='Mitte: ',
font_size=120)
u = Label(text='Unten: ',
font_size=120)
a = Label(text='Aussen: ',
font_size=120)
mydata.bind(top=o.setter('text'))
VERT.add_widget(o)
VERT.add_widget(m)
VERT.add_widget(u)
VERT.add_widget(a)
onoff = Button(text='Ein',
font_size=120,
size_hint=(0.3, 1))
self.add_widget(VERT)
self.add_widget(onoff)
class TutorialApp(App):
def build(self):
return myw()
if __name__ == "__main__":
try:
global myapp
myapp=TutorialApp()
app_runner=multiprocessing.Process(target=myapp.run)
app_runner.start()
time.sleep(3)
mydata.top='new value assigned'
print (mydata.top)
time.sleep(5)
app_runner.terminate()
except Exception as e:
print ('error occured', e)
I deliberately declared the variable 'mydata' outside the kivy code, such that i can access it from elsewhere in the code (not shown here).
Using threading instead of multiprocessing solved the problem.
So instead of
app_runner=multiprocessing.Process(target=myapp.run)
it now reads:
app_runner=threading.Thread(target=myapp.run)