Image inputed from user is displayed black in kivy after using Intent - python

I want the user of an android app input an image using on_activity_result funtion which is bind to the activity and then display it in a kivy image widget. I used Intent.createChooser for user's input:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.app import App
from kivy.uix.image import Image, CoreImage
class MainApp(App):
def build(self):
return Builder.load_file('main.kv')
def set_texture(self, root):
i = root.children[0].children[0] # getting the image widget
##set the image as bytes
with open("./small image.png", "rb") as image:
f = image.read()
bytesArray = bytearray(f)
import io
img = CoreImage(io.BytesIO(bytesArray), ext="png").texture
i.texture = img
def set_texture_after_intent(self):
from jnius import autoclass, cast
from android import activity
activity.bind(on_activity_result=on_activity_result)
PythonActivity = autoclass("org.kivy.android.PythonActivity")
context = PythonActivity.mActivity
currentActivity = cast('android.app.Activity', PythonActivity.mActivity)
AndroidString = autoclass('java.lang.String')
Intent = autoclass('android.content.Intent')
intent = Intent()
intent.setType("image/*")
intent.setAction(Intent.ACTION_GET_CONTENT)
currentActivity.startActivityForResult(
Intent.createChooser(intent, cast('java.lang.CharSequence', AndroidString("Select Picture"))), 1)
def on_activity_result(request, response, data):
#get the image widget
root = App.get_running_app().root
#call same display function
App.get_running_app().set_texture(root)
MainApp().run()
kv file:
Screen:
id:myscreen
BoxLayout:
Button:
text:'change image normally'
on_release: app.set_texture(root)
Button:
text:'change image after intent'
on_release: app.set_texture_after_intent()
Image:
id: image_id
source:'./big image.png'
if I change the texture of an image without getting back from an intent, it is displayed normally on android devices. I think this could be helpful in understanding the cause. After returning from an intent, the same image read in the same way is displayed black.

It might be a thread/gl context issue, can you try adding the mainthread decorator to your on_activity_result function?
from kivy.clock import mainthread
...
#mainthread
def on_activity_result(request, response, data):
...

Related

kivymd, creating a splash loading page as animation I couldn't code it instead I use Gif not working why?

Hello Guys i create a page using kivymd using an gif because i couldn't code it so i make a video for it than i convert it to gif.
the point is the code doesn't work and the error wasn't clear any help please
this the code of the splashloading.kv
MDFloatLayout:
md_bg_color:1,1,1,1
md_bg_color: (255/255, 250/255, 245/255, 1)
Image:
source:"assets/start.gif"
size_hint:.50,.50
pos_hint:{"center_x":.5,"center_y":.8}
and the code for the main.py I comment the first page just to see the splashloading page.
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.clock import Clock
from kivy.core.text import LabelBase
Window.size =(350, 580)
class StartPage(MDApp):
def build(self):
LabelBase.register(name='Lemonada',fn_regular='fonts/Lemonada-VariableFont_wght.ttf')
global screen_manager
screen_manager = ScreenManager()
#screen_manager.add_widget(Builder.load_file("firstUse.kv"))
#screen_manager.add_widget(Builder.load_file("main.kv"))
screen_manager.add_widget(Builder.load_file("splashloading.kv"))
return screen_manager
def Login(self, *args):
screen_manager.current = "Login"
if __name__ == "__main__":
StartPage().run()
the error:
I am not sure about the gif, but I can give you code for a video player that has worked fairly smoothly in some of my projects.
Need to create a Video player class which can then be used in the .kv file
In .kv file
# This is only the code for the widget, the structure around it is not included
PlayerOpen:
id: player_open
opacity: 1
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
state: 'play'
Python code defining the widget
from kivy.uix.video import Video
video_list = ['your_video.mp4'] # Can uses a list of videos
class PlayerOpen(Video):
video_list = ['vid.mp4']
def __init__(self, **kwargs):
self.v = 0
super().__init__(source=video_list[0], state='stop', **kwargs)
def on_eos(self, *args):
print(f'on_eos: {self.eos} loaded: {self.loaded}, state: {self.state}')
if self.eos:
self.v += 1
if self.v == len(video_list):
print('End of playlist')
self.v = 0
return
self.source = video_list[self.v]
self.state = 'play' # must set state to play for video to be loaded
def on_loaded(self, *args):
print(f'loaded: {self.loaded}')
I know this isn't exactly what you asked for, but this might be able to solve your problem as you could still get the animation playing in your loading screen. Hope it helps

Create a kivy application to take input from user in one screen and display those many images in other screen

I am trying to create an application that would display images from a certain path in my PC.
I would like to display those images based on the user input. Let's suppose user gave a number 5, then it would display 5 images randomly in that path.
Here is a basic example app that should do what you asked using pure python (no KV language). Just saying, when displaying the images you may want to consider adding a scrollview to be able to view full image. Currently, I have "shrunk" them by specifing size_hint(.3,.3) . Also, you want to find a better way to filter out files that are not images, I created a basic filter by checking if the file path ends with ".jpg" or ".png", you could probably do this regex or use the glob library.
import os, random
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.textinput import TextInput
from kivy.uix.image import Image
from kivy.properties import ListProperty, NumericProperty
class Screen2(Screen):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.layout = StackLayout()
self.random_image_number = App.get_running_app().images_num
self.images_paths = App.get_running_app().images_paths
self.random_paths = random.choices(self.images_paths, k=self.random_image_number)
for path in self.random_paths:
# You may wanna change the size_hint or add a scrollview if you want full size images
img = Image(source=path,size_hint=(.3,.3))
self.layout.add_widget(img)
self.add_widget(self.layout)
class Screen1(Screen):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Add your path here
self.image_path = os.path.join("C:\\Users\\dimit\\Pictures")
self.layout = RelativeLayout()
self.input_bar = TextInput(multiline=False, size_hint=(0.4, 0.1), pos_hint={"center_x":.5, "center_y":.5}, hint_text="How many images to show", input_type="number")
self.input_bar.bind(on_text_validate=self.get_images)
self.layout.add_widget(self.input_bar)
self.add_widget(self.layout)
# inst refers to the input bar object
def get_images(self, inst):
App.get_running_app().images_num = int(inst.text)
for fname in os.scandir(self.image_path):
# Skip any directories
if fname.is_dir():
continue
# Filter for images
if fname.path.endswith(".jpg") or fname.path.endswith(".png"):
App.get_running_app().images_paths.append(fname.path)
# This line needs to be here, because if you add the screen in the build method, it wont add the images
App.get_running_app().screen_manager.add_widget(Screen2(name="Image Display Page"))
# Changes screen to image display screen
App.get_running_app().screen_manager.current = "Image Display Page"
class ImageApp(App):
images_paths = ListProperty([])
images_num = NumericProperty(0)
def build(self):
self.title = "Image Display App"
self.screen_manager = ScreenManager()
self.screen_manager.add_widget(Screen1(name="Home Page"))
return self.screen_manager
if __name__ == "__main__":
ImageApp().run()

How to change screen by swiping in kivy python

I am trying to change to another screen by swiping the screen. I've tried carousel but it seems that it only works with images, so I've tried detecting a swipe motion and changing the screen after it has been detected.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.uix.button import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.carousel import Carousel
from kivy.uix.widget import Widget
from kivy.uix.popup import Popup
class HomeScreen(Screen):
def on_touch_move(self, touch):
if touch.x < touch.ox: # this line checks if a left swipe has been detected
MainApp().change_screen(screen_name="swipedhikr_screen") # calls the method in the main app that changes the screen
class ImageButton(ButtonBehavior, Image):
pass
class LabelButton(ButtonBehavior, Label):
pass
class SettingsScreen(Screen):
pass
class SwipeDhikrScreen(Screen):
pass
#def quit_verification():
# pop = Popup(title="verification", content=Label(text= "Are you sure?"))
GUI = Builder.load_file("main.kv")
class MainApp(App):
def build(self):
return GUI
def change_screen(self, screen_name):
# get the screen manager from the kv file
screen_manager = self.root.ids["screen_manager"]
screen_manager.transition.direction = "up"
screen_manager.current = screen_name
def quit_app(self):
MainApp().stop()
MainApp().run()
I got an attribute error: "None type object has no attribute 'ids'"
MainApp().change_screen(screen_name="swipedhikr_screen")
This line creates a new instance of MainApp, which doesn't have any widgets and therefore naturally fails when you try to access them.
Use the existing instance of MainApp, i.e. the one that you're actually running, via MainApp.get_running_app().
Also you are not correct that Carousel works only with images.

FactoryException when trying to create a "IconButton" in Kivy

I've tried to create an Icon that can be clicked, which means an Image with a ButtonBehavior.I followed the documentation (http://kivy.org/docs/api-kivy.uix.behaviors.html), and I've got a FactoryException with the following code:
# coding: utf-8
from kivy.uix.behaviors import ButtonBehavior
from kivy.core.image import Image
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
kv_string = """
BoxLayout:
IconButton
"""
class IconButton(ButtonBehavior, Image):
def on_press(self):
print("on_press")
class DashboardApp(App):
pass
Builder.load_string(kv_string)
if __name__ == "__main__":
DashboardApp().run()
When I change the parent class of IconButton from (ButtonBehavior, Image) to (ButtonBehavior, Widget), the problem disappears.
You want kivy.uix.image, not kivy.core.image.

Kivy Event on carousel when slide change

I don't have any idea to find a solution of my problem.
I have make an application with Carousel Widget. In this Carousel I have 4 slides.
welcomeSlide -> DVDSlide -> DVDPretSlide --> CategorySlide
I have make a class for each slides.
I use a ListAdpter to display the data extracted from an Sqlite3 Database.
My pblem is about the refresh of the list, when I modify a DVD (add name to pret) in the DVDSlide, when I slide to the DVDPret, the DVD do not appears because the List is not refresh.
Like the doccumentation for the carousel I don't find the event when slide change. It will be the best if an event exist to get the current slide index.
Have you got any Idea ?
Thanks,
You can observe index property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
Label:
text: str(id(root))
<Carousel>
on_index: print("slide #{}".format(args[1]))
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
Or you can observe current_slide property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
label_id: label_id
Label:
id: label_id
text: str(id(root))
<Carousel>
on_current_slide: print(args[1].label_id.text)
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
If you want a pure python solution rather than a Kivy Language solution you can create your own carousel that inherits from the Kivy carousel as follows.
import kivy
from kivy.uix.carousel import Carousel
class MyCarousel(Carousel):
# This class is a carousel that runs script
# when a slide gets focus (except first load).
def on_index(self, *args):
print('the slide is', self.index)
# YOUR CODE GOES HERE
Carousel.on_index(self, *args)

Categories

Resources