Browse an image file and display it in a kivy window - python

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

Related

Python/Kivy Multiple screens not working, Code does not recognise the screen manager?

I am trying to make an app that starts in the main menu, you press the play button and it sends you to the game on a different screen.
Problem is i keep getting an error on the:
"kv= Builder.load_file("my.kv")" saying that "WindowManager" is an unknown class.
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.vector import Vector
from kivy.uix.floatlayout import FloatLayout
kv= Builder.load_file("my.kv")
class WindowManager(ScreenManager):
pass
class MenuWindow(Screen):
pass
class Game(Screen):
pass
class MyApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyApp().run()
AND HERE IS THE KV FILE:
WindowManager:
MenuWindow:
Game:
<MenuWindow>:
name: "Menu"
FloatLayout:
Button:
text:"Play"
on_release:
app.root.current= "Game"
<Game>:
name: "Game"

Why can't I acces my image's source using Screenmanager and ObjectProperty?

I'd like to access my image's source by pointing to its ID.
When I try it this way without using ScreenManager it works fine but using ScreenManager and gives the following error message:
AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'source'
So do you have any idea how to access my image using ScreenManager?
Python code:
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
class MainWindow(Screen):
img1 = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
self.print_image()
def print_image(self):
print(self.img1)
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
Gui = Builder.load_file("my.kv")
class MyApp(App):
def build(self):
return Gui
if __name__ == "__main__":
MyApp().run()
kv code:
WindowManager:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
img1: img1
Button:
id: b1
text: "Submit"
Image:
id: img1
source: "IMG_8681.jpg"
<SecondWindow>:
name: "second"
Button:
text: "Go Back"
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
Thanks a lot in advance!
You can access the Image as you described, but a print statement in a class, outside any method, is executed when the class is loaded and even before the kv file is loaded.
You can access the Image like this:
print(Gui.get_screen('main').img1)
or within a method in the MainWindow class, you can use:
print(self.img1)
But you must wait till the App is started

how to access an id from one class in another class

i want to access an id from class main to class fahim2_pop. want to access to word from textinput(in main class) to the popup widget which will appear when someone press the search button. when someone search "hello" and press search button the the popup widget will appear and in that popup widget the text of the label will be "hello" same as from the textinput. but the label and the id remains in different class. how to do it?
python code
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.properties import *
class fahim2_pop(Popup):
pass
class main(BoxLayout):
def word(self):
pop=fahim2_pop()
pop.open()
class go(BoxLayout):
def main(self):
self.clear_widgets()
self.add_widget(main())
class CallApp(App):
def build(self):
return go()
CallApp().run()
kv code
Builder.load_string('''
<main>:
BoxLayout:
orientation:"vertical"
TextInput:
id:word
Button:
text:"search"
on_press:root.word()
<go>:
Button:
text:"go"
on_press:root.go()
<fahim2_pop>:
id:pop
title:"result"
BoxLayout:
Label:
text:app.root.ids.word.text
''')
i know app.root.ids.word.text if that id remain in root of my app. but here go is the root of app. how to access id from class main in class fahim2_pop?
There are a couple of ways of solving this problem. One of the solution is as follow:
py file
Rename method main() in class go() to go() because in your kv file, you have binded on_press: root.go()
Instantiate main() and store it in a class attribute, main
Snippets - py file
from kivy.properties import ObjectProperty
...
class go(BoxLayout):
main = ObjectProperty(None) # declare class attribute
def go(self):
self.clear_widgets()
self.main = main()
self.add_widget(self.main)
kv file
Replace text:app.root.ids.word.text with text:app.root.main.ids.word.text
Snippets - kv file
<fahim2_pop>:
...
Label:
text:app.root.main.ids.word.text
Example - main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
Builder.load_string('''
<main>:
BoxLayout:
orientation:"vertical"
TextInput:
id:word
Button:
text:"search"
on_press:root.word()
<go>:
Button:
text:"go"
on_press:root.go()
<fahim2_pop>:
id:pop
title:"result"
BoxLayout:
Label:
text:app.root.main.ids.word.text
''')
class fahim2_pop(Popup):
pass
class main(BoxLayout):
def word(self):
pop = fahim2_pop()
pop.open()
class go(BoxLayout):
main = ObjectProperty(None)
def go(self):
self.clear_widgets()
self.main = main()
self.add_widget(self.main)
class CallApp(App):
def build(self):
return go()
CallApp().run()
Output

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

Kivy FileChooser: List directories only

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.

Categories