Can't close Kivy app or avoid fullscreen - python

I am new to Kivy and trying to find my way around. Whenever I create and run an app, it displays as a full-screen that I am unable to close without disconnecting the power (which I know is not ideal, but that's exactly why I am desperate to fix it!).
Shortcuts that are suggested to work (Esc, Ctrl+C, Ctrl+Alt+break) don't. I have attempted changing the config settings at the beginning of the script as follows:
from kivy.config import Config
Config.set('graphics', 'fullscreen', 0)
Config.write()
I've also tried variations on the theme - 0 as a string, 1 as both an integer and string (and trying to provide a width and height for the window) but with no perceivable change. Even if this did work, it would not be the ideal fix given that I would probably want to be able to run things full-screen in the end!
Given that each time I've tried changing something I've had to restart the pi by disconnecting the power, playing around has been quite time-consuming!
Does anybody have any suggestions about how I should proceed?
I'm currently using:
Raspberry Pi 2 Model B connected to normal TV (many people having problems have been using a touchscreen, but that is not true for me)
Raspbian Jessie, Linux 8
Python 2.7
I'm afraid I don't know how to check details about the Kivy module I have downloaded.
I'm very new to this, so apologies if I don't manage to provide all of the relevant information.
Full code I am trying to run (excluding the above config changes):
import kivy
kivy.require('1.9.2') #may be part of the problem - not 100% sure this is correct
from kivy.app import App
from kivy.uix.label import Label
class MyApp(App):
def build(self):
return Label(text='Hello world')
if __name__ == '__main__':
MyApp().run()

As a temporary workaround you could just do :
def build(self):
button = Button(text = 'Exit', size_hint = (.1, .05),
pos_hint = {'x':0, 'y':0})
button.bind(on_press = self.on_quit)
self.layout = FloatLayout()
self.layout.add_widget(button)
return self.layout
def on_quit(self):
exit()
Which would provide you with an exit button. For your fullscreen problem it's weird, can you provide some more code ?
EDIT:
Can you try this ? :
from kivy.config import Config
Config.set('graphics', 'borderless', 0)
Config.write()

To work around this issue, you can change the full screen to fake so kivy can exit on Ctrl+C.
from kivy.config import Config
Config.set('graphics', 'fullscreen', 'fake')
Config.write()
Also, try to run the code in command line prompt. Avoid raspberry pi's desktop environment while running kivy apps. This will free up pi's memory for running kivy.

Related

Kivy, Python 3.8 - Unable to get SoundLoader working properly

I'm making an app/game and the user is able to play a sound when pressing the sound button, and the same sound is played after the user finishes a level. The next level contains a new sound.
For some reason, my code doesn't act how I want it and the results aren't consistent: sometimes it works only once, sometimes it works twice or more. Sometimes the next level contains the new sound but most of the time it doesn't play anything.
It probably has something to do with the way I load/try to unload audio files because the code returns 'play' when printing out the audio state.
Here is a simplified version of the code:
import time
import kivy
from kivy.app import App
from kivy.core.audio import SoundLoader
from kivy.lang import Builder
from kivy.uix.widget import Widget
root_widget = Builder.load_file('app.kv')
class ExampleWidget(Widget):
def play_sound(self):
file = 'correct.wav'
print('playing ', file)
click_sound = SoundLoader.load(file)
click_sound.play()
time.sleep(2)
print(click_sound.state)
click_sound.stop()
print(click_sound.state)
#click_sound.unload() # Crashes the app
click_sound = ''
class MyApp(App):
def build(self):
return ExampleWidget()
MyApp().run()
app.kv:
<ExampleWidget>:
id: ew
GridLayout:
col: 2
rows: 3
size: root.size
Button:
text: 'play sound'
size: self.size
on_release: ew.play_sound()
I also tried to empty the click_sound variable by assigning it a None value, using 'del click_sound', tried emptying the variable at the start of the function, end or both and I also tried using the unload() function but that returns the following error:
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
I'm also getting the following warning. I don't think it's a part of my problem but I'm adding it just in case:
[WARNING] [ffpyplayer ] [wav # 0x7fc738908e00] Discarding ID3 tags because more suitable tags were found.
Hopefully someone can help me out, I thank you in advance.
EDIT:
As ApuCoder said, the code works fine, just not on my macbook. Just tested it on a Windows pc and there were no problems. Does anybody know a way to fix this on Apple computers?

Kivy Audio Will Not Seek, Win 11

According to the documentation Kivy 2.0.0 audio will likely not seek unless played first. However, I cannot get it to seek at all with this simple code on Windows 11. It always plays from the beginning and the position is always 0,
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
sound = SoundLoader.load('test.mp3')
def play():
sound.play()
sound.seek(5)
print(sound.get_pos())
if sound:
print("Sound found at %s" % sound.source)
print("Sound is %.3f seconds" % sound.length)
#Clock.schedule_once(play, .3)
play()
Also, I tried to schedule a delay using Clock and the audio does not play at all. What am I missing?
Edit:
It was suggested that this code needs to be wrapped in an app to work. That did fix the clock delay issue, but the player still will not seek ahead,
from kivy.core.audio import SoundLoader
from kivy.clock import Clock
from kivy.app import App
from kivy.uix.button import Button
class MainApp(App):
sound = SoundLoader.load('test.mp3')
def build(self):
return Button(text='Play', on_press = self.clock)
def clock(self, evt):
Clock.schedule_once(self.play, 1)
def play(self, evt):
self.sound.play()
self.sound.seek(5)
#self.sound.play()
print(self.sound.get_pos())
MainApp().run()
After digging into the Kivy source code I found out why Kivy audio will not seek.
The default Kivy audio provider on Windows is SDL2 and when I looked at the source (kivy/core/audio/audio_sdl2.pyx) I found it does NOT have a seek method. Only "play" and "stop." In the init.py file the "seek" method returns "pass." However, the audio_ffpyplayer.py files DOES have a "seek" method. If one has ffpyplayer installed on his system Kivy will load it and seek will work, but with the default install it will not.
(It would be good if the Kivy Docs would reflect this. It would have saved me and others, I'm sure, a lot of "hair pulling.")
I tried ffpyplayer and it works good, but it has a lot of bloat. When packaged with pyinstaller there is around 40MB of added dlls. Since Windows already has the files needed to play audio, this bloat is redundant. While looking for a Python tool to play Windows audio using existing dlls, I found mp3play (https://github.com/michaelgundlach/mp3play). It is old but works flawlessly using only Window's native audio dlls and adds essentially no bloat. I think "playsound" will work as well.

Maximum recursion depth exceeded in kivy but only when packaging, not when developing the app in python

I am trying to pack an app that requires several imports, among those matplotlib.pyplot
The kivy app (simplified, but still working) is:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
import matplotlib.pyplot
Builder.load_string("""
<MyWidget>:
id: my_widget
FileChooserIconView:
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 app works perfectly in python using spyder.
However, when I try to pack it as an independent kivy app it gives me error maximum recursion depth exceeded.
I am surprised and I do not know what the problem is because:
1.There are no recursive functions in the app.
2.Works perfectly in python spyder while developing it and testing it, the only problem is during packaging.
3.I have tried multiple options, including commenting out several portions and, most surprising, when I comment out the import matplotlib.pyplot the app packages well. However I need matplotlib.pyplot for this app so taking it out is not an option.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
#import matplotlib.pyplot
Builder.load_string("""
<MyWidget>:
id: my_widget
FileChooserIconView:
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()
The above code works and packages well.
Is it that there is some limit of the size of the files one can import to a kivy app? I have already tried to increase the recursion limit with sys.setrecursionlimit(high numbers) but it is not a solution to this problem.
I am really lost. Any insight appreciated.
Thank you
Edit 2/4/2019:
It has been suggested that the question: pyinstaller creating EXE RuntimeError: maximum recursion depth exceeded while calling a Python object is a duplicate and answers this question. Although this is definitively a related question and is helpful, my error occurs in the first stage of the creation of the kivy package:
python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py
Thank you so MUCH to everybody who tried to help.
I found an answer and I hope it helps other people who tries to create a kivy package and there is a problem importing python module(s).
Once you have your main.py script ready to package:
1.Start with the instructions at
https://kivy.org/doc/stable/guide/packaging-windows.html
and do the first step:
python -m PyInstaller --name touchtracer examples-path\demo\touchtracer\main.py
This will give you the error of maximum recursion depth exceeded or whatever error this gives to you originally. No worries. The purpose of this step is to create an initial spec file.
2.Open the spec file and add all the extras that the kivy instructions give you at
https://kivy.org/doc/stable/guide/packaging-windows.html
that is:
from kivy.deps import sdl2, glew
Tree('examples-path\\demo\\touchtracer\\'),
*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
3.In addition to that, add at the beginning of the spec file the following:
import sys
sys.setrecursionlimit(5000) # (or some big number)
4.Also add any imports in the hidden imports that you might need.
hiddenimports=[] # change to (example importing pandas and matplotlib) hiddenimports=['pandas', 'matplotlib']
5.Just follow the last step at
https://kivy.org/doc/stable/guide/packaging-windows.html
that is:
python -m PyInstaller touchtracer.spec
and get your app built
When we go into a recursion, there is a risk of stack overflow and the Cpython working under the hood does not take it upon itself to optimize tail recursion, so if you go too deep, you will move closer towards a stack overflow. Generally different Cpython/python flavors have different recursion permit depth, The version of python you have running locally has a more liberal depth limit (Generally because it is assumed developers have good enough computers that this can take place). But when you use tools to package your application they generally override the sys.setrecursionlimit to a more conservative value as they try to make sure you don't cause an stack overflow on systems with lower hardware.
Sadly there is no silver bullet for this problem, you can try to look into your specific manager and change the limit (Not recommended) or you can try to convert your recursive blocks into iterative blocks.

kivy executes "on_release"-command multiple times

To trigger the acquisition of an image, I use the on_release-function of a kivy-button.
So, whenever this button is clicked (or pressed -- since using a touchscreen) a camera is triggered using gphoto2.
The issue:
From time to time, the function is executed multiple times (taking multiple images), while it was clearly pressed only a single time.
According to the logs, I'm confident, that it's a kivy-related issue (not related to the camera, etc.): Logging entries within the on_release-function appear multiple times within the logs.
I'm running an app with kivy (version 1.9.0) and python (version 2.7.6) under Ubuntu 14.04 LTS (64bit) using a touchscreen.
Any hint on how to debug or fix the issue is welcome.
I was stuck at the same problem for days!
Do you have this line in your code?
Config.set('input', 'mouse', 'mouse, multitouch_on_demand')
If yes, then remove it.
On touch devices, touch gets triggered multiple times.
Hope it helps someone with the same problem.
You could disable the button when the first release event starts, and in the end of the thread where the picture is taken, enable the button again. Then you will not have multiple events from that button executing, but still the main app thread is allowed to continue.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
import time
import threading
Builder.load_string('''
<MyLayout>:
Button:
text: 'Print to terminal'
on_release:
root.button_released(self)
''')
class MyLayout(BoxLayout):
def button_released(self,button):
button.disabled = True
print("{} pressed!".format(button))
threading.Thread(target=self.take_picture, args=(button,)).start()
def take_picture(self,button):
time.sleep(1) # taking picture or whatever
button.disabled = False
class MyApp(App):
def build(self):
return MyLayout()
MyApp().run()

Issue setting Kivy to fullscreen

I'm trying to write an application that runs kivy at full screen. But these are my issues:
1) When I run the command:
#Config.set('graphics', 'fullscreen', 1)
Then kivy appears to go full time, but the window has a lot of black spaces around the background image. Even if I elongate the image, kivy just cuts the image when showing it.
2) When I run this command to set the window size to the size of my screen:
Config.set('graphics', 'width', '1366')
Config.set('graphics', 'height', '768')
This way actually gives me a better result than full screen, but kivy returns a height parameter of only 715 instead of the 768, which is the value I told kivy to use (as you can see in the Config.set() function above).
My screen resolution is 1366x768
How can I solve this issue and make my kivy app go real full screen?
Thank you very much
Had a similar problem. Using the 'auto' option got rid of the bands for me.
Window.fullscreen = 'auto'
Quote from Kivy Configuration Object documentation: "If set to auto, your current display’s resolution will be used instead. This is most likely what you want."
Try
from kivy.core.window import Window
Window.fullscreen = True
Do this before you App.run() method, and it should switch to fullscreen mode.
Cheers
I managed to do it as follows:
from kivy.core.window import Window
Window.maximize()
I just want to complement:
from kivy.core.window import Window
Window.size = (1366, 768)
Window.fullscreen = True
this works for me:
Config.set('graphics', 'fullscreen', 'auto')
Answering lately For those who are still struggling to figure out how to have the true fullscreen. I have managed to get the rid of those black strip by adding Config.set('graphics','window_state'_'maximized' just after the fullscreen call. the whole code looks like
from kivy.config import Config
# ...
if __name__ == "__main__":
Config.set('graphics', 'fullscreen', 'auto')
Config.set('graphics', 'window_state', 'maximized')
Config.write()
YourApp().run()
This will work no matter what is your resolution.
from kivy.core.window import Window
Window.fullscreen = True
Window.maximize()

Categories