I want to access my images/photo gallery on an iOS device from a kivy application.
Kivy has no native way implemented to do this, so I'm trying to solve it with kivy/pyobjus
where I can use the UIImagePickerController (from Apples UIKit).
from kivy.app import App
from kivy.lang import Builder
from pyobjus import autoclass, protocol
class TestApp(App):
ui = Builder.load_file("main.kv")
def build(self):
return self.ui
def imagePicker(self):
UIImagePickerController = autoclass('UIImagePickerController')
self.picker = UIImagePickerController.alloc().init()
self.picker.delegate = self
self.picker.sourceType = 0
#protocol('UIImagePickerControllerDelegate')
def imagePickerControllerDidFinish(self, image):
print("ABC")
The ui is just a button, which calls the imagePicker function.
I have three questions on this code:
How can I display the imagePicker?
When I'm using imagePicker.delegate = self, the App crashes because
[...] delegate, but there is no #protocol methods declared.
But I declared a protocol with "#protocol('UIImagePickerControllerDelegate')"
So why it won't use my declared protocol? (I tried also to add the "UIImagePickerControllerDelegate" in the protocols.py from pyobjus. This didn't solved the problem)
If the protocol will work, it is the correct way to use the "imagePickerControllerDidFinish(self, image)" method to access the image?
Related
I am writing a music database manager using python and tkinter. It is nearly all complete but I am stuck on playing songs from a list. The native macOS player NSSound has a built-in callback to a delegate which signals the end of the track so I would like to use that to trigger a virtual event back to the main app to send the next song to play. But I cannot figure out how make the callback work and would appreciate some help (this being just a hobby project which has got somewhat out of hand).
This skeleton code shows the relevant structure of the app and plays the selected file as expected, but none of my numerous attempts at formulating the delegate have worked. As I understand it the player appoints the Delegate class as its delegate, and then this class should have a callback method 'sound' to receive a message when the song ends. I have tried to figure it out from the Apple Developer protocol, and also searched extensively and found only one example.
How do I do get to the 'Success!' message please?
from AppKit import NSSound
import tkinter as tk
from tkinter import filedialog
class Delegate (NSSound):
def init(self):
self = super(Delegate, self).init()
return self
#def sound (...) ??? #this should fire when the song finishes?
# print('Success!')
class App(tk.Tk): #representing the rest of the music database app
def __init__(self):
super().__init__()
file = filedialog.askopenfilename()
song = NSSound.alloc()
song.initWithContentsOfFile_byReference_(file, True)
delegate = Delegate.alloc().init()
song.setDelegate_(delegate)
song.play()
if __name__ == "__main__":
app = App()
app.mainloop()
The NSSound instance will call a method with this (swift) signature on its delegate:
sound(_:didFinishPlaying:)
Thus I think your Python function should have the same signature: it’s name should be sound and it should accept two parameters, the first one without a label (_) of type NSSound, the second one of type Bool with a label didFinishPlaying.
Your sound function in your delegate doesn’t appear to have such signature, hence most probably it’s not called.
That is cause such method on the delegate is optional, meaning if an instance conforming to NSSoundDelegate doesn’t implement such method, it won’t trap when attempted to be used by a delegating NSSound instance.
Thanks for your help #valeCocoa, your perserverance helped a lot. This works:
from AppKit import NSSound
import tkinter as tk
from tkinter import filedialog
import objc
class Song (NSSound) :
def initWithFile_(self, file):
self = objc.super(Song, self).initWithContentsOfFile_byReference_(file, True)
if self is None: return None
self.setDelegate_(self)
return self
def sound_didFinishPlaying_(self, _, didFinish):
print('Success')
class App(tk.Tk): #representing the rest of the music database app
def __init__(self):
super().__init__()
file = filedialog.askopenfilename()
song = Song.alloc().initWithFile_(file)
song.play()
if __name__ == "__main__":
app = App()
app.mainloop()
I am writing a code which starts the frontend, runs the backend and then loads the frontend. The frontend consists of TabbedPanel, and the currently displayed tab may be change by backend.
Here's the MRE:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
def button(instance):
instance.parent.parent.switch_to(instance.parent.parent.tab_2) # accessing TabbedPanel without messing with sending
# a variable
def backend(frontend):
# this class represents main backend function. In the result of its execution there might be a need to switch to
# another tab
frontend.switch_to(frontend.tab_2)
class MyTabbedPanel(TabbedPanel):
def __init__(self, **kwargs):
super().__init__()
self.tab_1 = TabbedPanelHeader()
self.tab_2 = TabbedPanelHeader()
self.tab_1.content = Button(text='Tab 1')
self.tab_1.content.bind(on_release=button)
self.tab_2.content = Label(text='Tab 2')
self.add_widget(self.tab_1)
self.add_widget(self.tab_2)
class Application(App):
def build(self):
frontend = MyTabbedPanel()
backend(frontend)
return frontend
Application().run()
The button, which I have added to compare, to switch from tab 1 to tab 2 works just fine, however, the auto swith when starting the app does not work.
What is the problem? Thank you in advance.
At the time that you're calling backend, there is no root widget returned by the build method, let alone a tab to switch to.
One way to solve this, is to schedule the call to the backend for after the build ends, using the Clock module.
def build(self):
frontend = MyTabbedPanel()
# backend(frontend)
from functools import partial
from kivy.clock import Clock
Clock.schedule_once(partial(backend, frontend))
return frontend
You also have to add an args argument to the backend method, because Clock sends a dt value:
def backend(frontend, *args):
So i downloaded the "kivy" module (using the 'command prompt') as shown during this video "https://www.youtube.com/watch?v=B79miUFD_ss&list=PLGLfVvz_LVvTAZ-OcNIXe05srJRXaJRd9"
But whenever i try to run this code:
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.button import Label
# Inherit Kivy's App class which represents the window
# for our widgets
# HelloKivy inherits all the fields and methods
# from Kivy
class HelloKivy(App):
# This returns the content we want in the window
def build(self):
# Return a label widget with Hello Kivy
return Label(text="Hello Kivy")
helloKivy = HelloKivy()
helloKivy.run()
It says the module doesn't exist?
How do i find the path of this module (and other modules)?
I have simple code for kivy, on W10 runs without problem. It falls down during loading in kivy launcher. Problem is without message.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
class View(BoxLayout):
def __init__(self):
super().__init__()
self.text = "No text"
but = Button(text = "Press",on_press = self.show)
self.add_widget(but)
self.lbl = Label()
self.add_widget(self.lbl)
def show(self,obj):
self.lbl.text = self.text
pass
class MyPaintApp(App):
def build(self):
return View()
if __name__ == '__main__':
MyPaintApp().run()
It does not run because you call super wrong.
As kivy launcher uses python 2, you need to pass your class (View) and the instance (self) to super.
You need to edit your class like this:
class View(BoxLayout):
def __init__(self,**kwargs):
super(View,self).__init__(**kwargs)
in every failure in kivy launcher, there is a '.kivy/log' directory inside the project directory that has a full log. you could find all the problem there.
I am developing a kivy app in which ,there are two screens
1.LoginScreen
and 2.HomeScreen.
What required is -
A value 'xyz' which is computed in class LoginScreen, to be passed to the method 'insertdata' of class HomeScreen and want to display that value on a label.
For this I tried following code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen, ScreenManager
class loginScreen(Screen):
def __init__(self,**kwargs):
super(HomeScreen, self).__init__(**kwargs)
def auth(self):
xyz=1
self.manager.current="home"
obj=HomeScreen()
# 1. To Pass 'xyz' to method scrn2
HomeScreen.insertdata(obj)
class HomeScreen(Screen):
def __init__(self,**kwargs):
super(LoginScreen, self).__init__(**kwargs)
if (a==1):
# 2. To display label
self.scrn2()
def insertdata(self):
print "screen 2"
label=Label(text="good moring")
self.add_widget(label)
class ScreenApp(App):
pass
if __name__ == '__main__':
ScreenApp().run()
Here:
insertdata is called from method auth
1)the 1st way is proper , as it is passing 'xyz' and calling the method insertdata but it dosen't display label
2) in 1st way I have to create to create an object of HomeScreen ,to call insertdata, which in turn calls the ___init__ of Homescreen and init calls insertdata
insertdata called from __init__
1) It loads data before user authentication at loginscreen
insertdata gets total 3 calls, which is affecting app launch time.
Suggest me any simple and effective way for this.
Thanks in advance.
You can use Screen.manager() method to get an manager object from one screen, use it to retrieve another one with its ScreenManager.get_screen() method and then pass the value directly. For an working example check an answer of this question: Kivy - Slider Class value change on another screen