Kivy: issue with event defined variables - python

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()

Related

Python Kivy: adding a FigureCanvas widget through a custom event

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)

How to grab the text from a kivy button?

I'm trying to build this simple GUI for a "voting app" where, by clicking the button with the candidate's ID, +1 will be added in the value of the ID key inside a dictionary. (counting votes on click basically)
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
CANDIDATES = {"T1031" : 0,"T2112" : 0, "T4561" : 0}
class MyLayout(BoxLayout):
orientation = "Vertical"
def __init__(self, **kwargs):
super(MyLayout, self).__init__(**kwargs)
for i in CANDIDATES:
canditate = Button(text=i, on_press=self.button_clicked)
self.add_widget(canditate)
def button_clicked(self, obj):
print("button pressed", obj)
class MyApp(App):
def build(self):
return MyLayout()
if __name__ == "__main__":
MyApp().run()
So how can I grab the text displayed on the button ?
(Also, if any of you guys know...how do I put an ID on the buttons? I tried with writing "id = i" but the GUI doesn't even start when I do that)
Many thanks in advance!
You can access the text value from a button using the Button.text property:
def button_clicked(self, obj):
# Note that obj here is a button object
# You can access it's text value, for example, using obj.text
CANDIDATES[obj.text] += 1
print(f"{obj.text}'s current vote count is now {CANDIDATES[obj.text]}")

How to bind Kivy TreeView node expand event to function

I looked online and I am still stuck on how to bind 'on_node_expand' of TreeView to a function.
Is it possible to get the proper syntax?
def createSubNode(elemObj,designTree,parent=None):
if type(elemObj) is (designClass.PathGroup):
pass
else:
for (name, obj) in elemObj.items():
subroot = designTree.add_node(TreeViewLabel(text=name,font_size=12),parent)
subroot.fbind('on_node_expand', bind_object)
createSubNode(obj,designTree,subroot)
def bind_object(node):
print("testing")
if __name__ == '__main__':
from kivy.app import App
class TestApp(App):
def build(self):
designTree = TreeView(root_options=dict(text='Designs',font_size=12))
designTree.size_hint = (1,None)
designTree.bind(minimum_height=designTree.setter('height'))
createSubNode(dsgnManObj, designTree)
svRoot = ScrollView(size=(Window.width, Window.height))
svRoot.add_widget(designTree)
root = BoxLayout(orientation ='horizontal')
root.add_widget(svRoot)
return root
TestApp().run()
on_node_expand is an event on the TreeView, not on the node, so you shouldn't need to bind it on subroot objects, but only on the designTree object.

Display and play audio files

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:

how to use blocking MessgeBox in kivy

I have a Kivy application.
From the main GUI, I want to open a new message box and force the main GUI to await the result of an action box interaction.
I saw that Qt4 message box has support for this blocking call type, but I haven't found the equivalent functionality in Kivy. Does such a feature exist?
The Popup widget is used to create modal popups. By default, the popup will cover the whole “parent” window. When you are creating a popup, you must at a minimum set a Popup.title and a Popup.content widget.
modal means blocking :)
http://kivy.org/docs/api-kivy.uix.popup.html
Here is a code snippet which does the job though it is actually not really blocking.
You need to define one or two alternatives to jump to in order to continue working with
the program. Thats the pseudo-blocking trick.
import kivy
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.app import App
class MessageBoxApp(App):
def build(self):
return Button(text='Press for MessageBox!', on_press=self.callpopup)
def callpopup(self, event):
dlg = MessageBox(self, titleheader="Title Header", message="Any Message",
options={"YES": "printyes()", "NO": "printno()", "CANCEL": ""})
print "Messagebox shows as kivy popup and we wait for the user action"
def printyes(self):
# routine for going yes
print "You chose the Yes routine"
def printno(self):
# routine for going no
print "You chose the No routine"
class MessageBox(MessageBoxApp):
def __init__(self, parent, titleheader="Title", message="Message", options={"OK": ""}, size=(400, 400)):
def popup_callback(instance):
"callback for button press"
self.retvalue = instance.text
self.popup.dismiss()
self.parent = parent
self.retvalue = None
self.titleheader = titleheader
self.message = message
self.options = options
self.size = size
box = GridLayout(orientation='vertical', cols=1)
box.add_widget(Label(text=self.message, font_size=16))
b_list = []
buttonbox = BoxLayout(orientation='horizontal')
for b in self.options:
b_list.append(Button(text=b, size_hint=(1,.35), font_size=20))
b_list[-1].bind(on_press=popup_callback)
buttonbox.add_widget(b_list[-1])
box.add_widget(buttonbox)
self.popup = Popup(title=titleheader, content=box, size_hint=(None, None), size=self.size)
self.popup.open()
self.popup.bind(on_dismiss=self.OnClose)
def OnClose(self, event):
self.popup.unbind(on_dismiss=self.OnClose)
self.popup.dismiss()
if self.retvalue != None and self.options[self.retvalue] != "":
command = "self.parent."+self.options[self.retvalue]
exec command
if __name__ == '__main__':
MessageBoxApp().run()

Categories