Kivy FileChooser: List directories only - python

How to list only directories in Kivy FileChooser? I've read about callback filters, but didn't found any examples.
My Kv code:
<Saveto>:
select: select
chooser: chooser
orientation: 'vertical'
FileChooserIconView:
id: chooser
size_hint_y: 0.9
rootpath: home
dirselect: True
filters: ['How to list folders only?']
Button:
...select button...

Here's an example:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from os.path import join, isdir
Builder.load_string("""
<MyWidget>:
FileChooserListView:
filters: [root.is_dir]
""")
class MyWidget(BoxLayout):
def is_dir(self, directory, filename):
return isdir(join(directory, filename))
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
Note that the property is called filters, not filter, because it's a list, for example, a list of callbacks.

You can also do it in KV directly:
<Saveto>:
select: select
chooser: chooser
orientation: 'vertical'
FileChooserIconView:
id: chooser
size_hint_y: 0.9
rootpath: home
dirselect: True
filters: [lambda folder, filename: not filename.endswith('')]
Button:
...select button...

If you want to use the directory without any file on it you can use:
os.path.dirname(filename)
in the following way (example where the directory is just used to print the directory as a label in the right side of the screen):
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.lang import Builder
import os
Builder.load_string("""
<MyWidget>:
FileChooserIconView:
filters: [root.selected]
BoxLayout:
Label:
id: mypath
text: ''
""")
class MyWidget(BoxLayout):
def selected(self, directory, filename):
self.ids.mypath.text = os.path.dirname(filename)
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
Hope it helps

This is a bit of a hack, but seems to work and can be done in the kv file only:
dirselect: True
filters: ['']
Only folders are shown in FileChooser.

Related

How to make kivy app from different py files

I am trying to make an app out of different .py files. But I don't know how to add them together, I have one main file, and one login file with plans to add a lot more, but with these I'm experimenting right now. They are pretty basic for now until I figure out this "bonding" between them and then I will start adding some more complex stuff. I tried couple of things and they didn't work, but I left them in code for you to see (I tried to make the app to start with MainWindow, and on press of the first button it goes to login page*). Here's the code and please help me.
*Right now when I press the button it gives me this error: OSError: exception: access violation writing 0x0000000080006010
this is main.py:
from kivy.lang import Builder
from kivy.app import App
import login
from kivy.uix.screenmanager import Screen
kv = Builder.load_string('''
<MainWindow>:
GridLayout:
cols:1
GridLayout:
rows:5
Button:
text:"NOVA ROBA"
on_release:
root.call_login()
Button:
text:"KUPCI"
Button:
text:"PRODATO"
Button:
text: "AGRONOMI"
Button:
text: "STANJE U MAGACINU"
''')
class MainWindow(Screen):
def call_login(self):
login.app().run()
pass
class main_app(App):
def build(self):
return MainWindow()
if __name__ == '__main__':
main_app().run()
this is login.py:
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.app import App
class Login(Screen, App):
def build(self):
return
pass
kv = Builder.load_string('''
<Login>:
name:"login"
GridLayout:
rows:2
GridLayout:
cols:2
Label:
text:"Password: "
TextInput:
id:passwd
multiline: False
Button:
text: "Submit"
on_release:
passwd.text = ""
''')
class app(App):
def build(self):
return Login()
if __name__ == "__main__":
app().run()
You are creating 2 apps, which is not needed. Instead of inheriting from both Screen and App in the Loginscreen, inherit only from Screen. Then create a ScreenManager in your main.py's build method and then add the imported loginscreen as a widget, to switch to the new screen, use self.manager.current = "login" in the call_login method of MainWindow
class app(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MainWindow())
sm.add_widget(Login())
return sm

why i am getting black screen when running this .py and .kv script?

.py file
this is python code
When I start the program it gives me a blank, black screen. I used the python file for the functionality and the kv file for the properties of the objects. Py file:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file('design.kv')
class LoginScreen(Screen):
pass
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__=="__main__":
MainApp().run()
.kv file
this is kv script
<LoginScreen>:
GridLayout:
cols:1
GridLayout:
cols:1
Label:
text: "User Login"
TextInput:
hint_text: "Username"
TextInput:
hint_text: "Password"
Button:
text: "Login"
GridLayout:
cols:2
Button:
text: "Forgot password"
Button:
text: "Sign Up"
<RootWidget>:
name: "Login_screen"
You need to load the file at the end of the script, and then return it inside the build method:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class LoginScreen(Screen):
pass
class RootWidget(ScreenManager):
pass
kvfile = Builder.load_file('design.kv')
class MainApp(App):
def build(self):
return kvfile
if __name__=="__main__":
MainApp().run()

KivyMD - MDTabs - How to get current active tab name?

I need to get current Tab's name. I checked this topic. And tried this code:
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.floatlayout import FloatLayout
from kivymd.uix.tab import MDTabsBase
from kivymd.app import MDApp
kv = Builder.load_string("""
<SM>
P1:
<P1>
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'TEST'
MDTabs:
id: toolbar
on_tab_switch: root.give_current_tab_name()
Tab:
text: 'Tab 1'
Tab:
text: 'Tab 2'
Tab:
text: 'Tab 3'
""")
class P1(Screen):
def give_current_tab_name(self):
print(self.ids.toolbar.carousel.current_slide.tab_label.text) #It gives previous tab name...
class Tab(FloatLayout,MDTabsBase):
pass
class SM(ScreenManager):
pass
class MyApp(MDApp):
def build(self):
return SM()
if __name__ == '__main__':
MyApp().run()
But, it gives me previous Tab's name.Should i use schedule_once(testfunc,delay_time) for check current tab's name or is there a any other easy way to do that?
Also, i need to disallow to slide page for change tab.It must be only from top tab's names.Can anyone help me for these problems. Thanks already..
For getting tabs name,
on_tab_switch pass 4 arguments:
instance_tabs, instance_tab, instance_tab_label, tab_text
so you can write something like this:
MDTabs:
id: toolbar
on_tab_switch: root.give_current_tab_name(*args)
...
def give_current_tab_name(self, *args):
tab_name = args[3]
For disallowing sliding,
just add:
MDTabs:
id: toolbar
on_tab_switch: root.give_current_tab_name(*args)
lock_swiping: True

Browse an image file and display it in a kivy window

I am a beginner in Kivy and trying to browse an image file using kivy fileChooser and then displaying it on the window. Bellow you find my code but it wouldn't do the task. It just displays '?PNG' on the console. Please, check this out with me !
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.image import Image
import os
Builder.load_string("""
<MyWidget>:
id: my_widget
Button
text: "open"
on_release: my_widget.open(filechooser.path,
filechooser.selection)
FileChooserListView:
id: filechooser
on_selection: my_widget.selected(filechooser.selection)
""")
class MyWidget(BoxLayout):
def open(self, path, filename):
with open(os.path.join(path, filename[0])) as f:
print f.read()
def selected(self, filename):
return Image(source=filename[0])
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
Try this:
I exclude the open button, and just display it when selected.
So we add an Image widget, and set its source when selected.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string("""
<MyWidget>:
id: my_widget
FileChooserListView:
id: filechooser
on_selection: my_widget.selected(filechooser.selection)
Image:
id: image
source: ""
""")
class MyWidget(BoxLayout):
def selected(self,filename):
self.ids.image.source = filename[0]
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
This is just a minimal example. It will throw an error if you go a directory up. So you need to handle that.
Easy fix:
class MyWidget(BoxLayout):
def selected(self,filename):
try:
self.ids.image.source = filename[0]
except:
pass

Kivy - Removing widget by id

I have the following code:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
class GUI(FloatLayout):
def remove(self):
self.remove_widget(self.ids.test)
class GUIApp(App):
def build(self):
return GUI()
if __name__ == '__main__':
GUIApp().run()
And the corresponding kv file:
#:kivy 1.9.1
<GUI>:
BoxLayout:
Button:
id: test
text: 'Test'
on_press: root.remove()
The button should be removed when clicked. However, this does not happen. If I remove the BoxLayout in the kv file, the program works as expected, and the button is removed. Why does this happen, and how can I remove a widget declared in a kv file? (I know I can replace the Button's on_press with self.parent.remove_widget(self), but I have code in root.remove() besides removing the widget.)
You're calling remove_widget of GUI object when your button's parent is actually BoxLayout inside it. remove_widget only deletes a direct children, not any descendant.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
Builder.load_string('''
<GUI>:
BoxLayout:
id: layout
Button:
id: test
text: 'Test'
on_press: root.remove()
''')
class GUI(FloatLayout):
def remove(self):
self.ids.layout.remove_widget(self.ids.test)
class GUIApp(App):
def build(self):
return GUI()
if __name__ == '__main__':
GUIApp().run()

Categories