I want to change the source path of an image from outside of the class/screen where the image is shown.
I have a callback function called my_callback, which will be called at some point during runtime of the app:
def my_callback():
# do stuff
MDApp.get_running_app().manager.get_screen('my_class').ids.imageID.source = "my_image.png"
MDApp.get_running_app().manager.current = "my_class"
I would expect the above two lines of code to do the following:
Switch the kivy screen to the my_class screen
Update the source of the image with the id "imageID" (as defined in my .kv file).
Outcome (1) is successful, but outcome (2) is not: rather than showing the image "my_image.png", a black shape is shown of equivalent dimensions to the image "my_image.png".
How can I fix this?
Note that MDApp is used here in place of App, as I am using the KivyMD library for my project.
I still don't know why the method I posted in the question doesn't work, but I have found an alternative solution.
The function my_callback now looks like this:
def my_callback():
# do stuff
MDApp.get_running_app().manager.current = "my_class"
image = AsyncImage(source='my_image.png')
MDApp.get_running_app().manager.get_screen('my_class').ids.floatLayoutID.add_widget(image)
And in the .kv file, there is a nested floatLayout:
<MyClass>:
name: "my_class"
FloatLayout:
FloatLayout:
id: floatLayoutID
Related
I cant seem to find any examples of interfacing kivy mapview with python for things like moving the map or adding markers from the python side of things.
What I mean is I would like to eventually pull data from a CSV file and have it control the information on screen. This is straightforward with labels and buttons. But I'm not able to make the same methides work with mapview.
All references I find on line controlled all logic inside the .KV files. None of the examples I find use python to reach in and change things inside the .KV file.
This is the best example I have tested so far. but as you can see all logic is inside the .KV file. https://github.com/kivy-garden/mapview/blob/develop/examples/map_browser.py
I want to be able to send data from the python side to the .kv side and have it update the screen as its being sent. Like Lat and lon positions, markers and so on.
What I am use to doing something like this.
Python side
from kivy_garden.mapview import MapView
from kivy.lang import Builder
from kivymd.app import MDApp
class MainApp(MDApp):
def build(self):
return Builder.load_file('MapViewApp.kv')
MainApp().run()
MapViewApp.kv
MapView:
id: map
lat: 36
lon: -115
zoom: 10
So I have been coding this file explorer program. I have coded the copy function so far and the problem I am running into is that after I copy a file to its new directory(i.e. the directory that I am on currently in the filechooser) the file isn't showing up in the the actual filechooser. I am using the icon view and I saw only one mention of this online here:Refresh / Reload FileChooser and I tried this method and like the actual _update_files() function is getting executed.(checked it with a couple of print statements) But I am noticing that there is not any change in the actual filechooser.What am i doing wrong here? THANK YOU!!!
This is the python code that is executed when ever the file is copied. I assigned the actual screen that contains the file chooser to a variable named MainScreenVar
for i in range(0, self.execute_data_length):
if self.execute_data[i][2] == "File" :
shutil.copy2(self.execute_data[i][1], current_path)
MainScreenvar = MainScreen()
return MainScreenvar.ids.filechooser._update_files()
mycursor.execute("DELETE FROM selection")
mydb.commit()
This is part of the kivy file:
<MainScreen>:
FileChooserIconView:
id:filechooser
size_hint:1,.9
pos_hint:{"top": .9}
color: 0,0,0,0
and the source code for the kivy file chooser is here:
https://kivy.org/doc/stable/_modules/kivy/uix/filechooser.html
The error in your code is the line:
MainScreenvar = MainScreen()
which is creating a new instance of MainScreen. This will not be the instance that is displayed in your GUI, so the line:
return MainScreenvar.ids.filechooser._update_files()
is calling _update_files() for a FileChooserIconView that is not displayed in your GUI. The solution is to use a reference to the actual FileChooserIconView that is in your GUI. Probably something like:
MainScreenvar = self.manager.get_screen('main')
However, this is only a guess since you haven't provided much of your code. This assumes that your posted code is from a Screen, and that the name that you provided for MainScreen is main.
Was wondering why the Kivy code kept on showing me the same black window despite doing some updates on the kv file. Then noticed I had a typo on the buidl() method.
From the docs "...implementing its build() method so it returns a Widget instance (the root of your widget tree)
...", you have to implement the method.
Why does this code run and give the default black window?
# game.py
from kivy.app import App
from kivy.uix.widget import Widget
class Game(Widget):
pass
class GameApp(App):
def buidl(self):
return Game()
GameApp().run()
The kv file
#game.kv
<Game>:
canvas:
Color:
rgb: .5,.5, 1.0
Rectangle:
pos: 0,0
size: self.size
Running kivy 1.11.1 python 3.7
Kivy apps have a default build() method, which you can see here; it just returns an empty widget. Generally kivy has two methods to create the root widget tree, either through overriding build() or by defining a root widget in a kv file. For more information see the documentation on creating an application.
Your quote can be found in kivy basics, before your quoted sentence:
Creating a kivy application is as simple as:
I guess the authors decided to keep the basic tutorial easy and did not mention the default implementation of build, as it doesn't really do anything useful. They also omitted the kv way of defining the root widget; again I would guess to not overwhelm the reader in this first introduction.
I'm using gestures in all of my screens, and I cannot use a screen manager class to manage my screens, or so I believe. I can navigate the .kv file by using manger.current = 'some_screeen' but cannot in the .py file.
I've been trying Runner().ids.manager.current = 'some_screen' in the .py file but it doesn't work. There isn't even an error thrown. The screen doesn't change at all.
Essential Code (for the sake of brevity):
class Runner(gesture.GestureBox):
pass
MyApp(App):
def build(self):
return Runner()
Then in the KV file, I'm creating the screen manager.
<Runner>:
ScreenManager:
id: manager
Screen:
name: 'main_screen'
Button:
on_press:
manager.current = 'screen1'
Screen:
name: 'screen1'
Button:
on_press:
manager.current = 'home_screen'
I've been trying Runner().ids.manager.current = 'some_screen' in the .py file but it doesn't work. There isn't even an error thrown. The screen doesn't change at all.
It works fine, it just doesn't do what you believe. When you write Runner() you get a new instance of the Runner class, with its own children including its own ScreenManager. This one has nothing to do with the one you're displaying in your gui. When you set its current property the ScreenManager will dutifully change the screen, it's just you have no way to see that.
What you actually want is to change the current property of the widget that you are displaying in your gui. The best way to do this depends on the context, which you have omitted (always try to provide a full runnable example, it isn't clear what your failing code looked like). However, in this case the Runner instance is your root widget which is accessible with App.get_running_app().root, so you can write App.get_running_app().root.ids.manager.current = 'some_screen'. Again, there might be neater ways to do it depending on how you structure your code, but this is always an option.
I'm absolutely new to GUI desing and trying to create a very simple App using python and kivy with a little bit of animations after pressing buttons. But as I'm completely new to kivy I'm stuck. I think the answer is very easy but after roundabout 8h of trial and error and googling through the internet I'm desperate :-)
I have created a little App with a button and an Image. What I'm trying to do is changing the Image after "button_pressed". The code in kivy file:
<FirstTest>:
my_image: my_image
source_image: self.source_image
Button:
on_press: root.gamer.changeImage()
My_Image:
id: my_image
source: self.parent.source_image
<My_Image>:
allow_stretch:True
keep_ratio: False
And the python Code (only the necessary part):
class Player(object):
def changeImage(self):
FirstTest.source_image = 'new_image.png'
class My_Image(Image):
pass
class FirstTest(FloatLayout):
my_image = ObjectProperty(None)
source_image = StringProperty(None)
source_image = 'First_Image.png'
gamer = Player()
def update(self, dt):
print(self.source_image) #To see in realtime if the image source changed
class MyApp(App):
def build(self):
game = FirstTest()
Clock.schedule_interval(partial(FirstTest.update, FirstTest), 1/60)
return game
When I start the App I see the Button and the "First_Image" loaded. But when I hit the button nothing changes. The only thing I see is that the source_image path changed in the console.
I do not understand why the Image isn't reloaded with the new source. I thought when I change the path I will get a new Image and if I do this repeated I would get some kind of animation. But not even a single image changes. If I try to change the Objectproperty of "my_image" I got an error message with "ObjectProperty has no attribute source"
What do I miss? Please help!
Thanks in advance!
The most obvious problem I see with your code is that you are confusing class objects with instance objects.
FirstTest is a class object, and when you do:
game = FirstTest()
You are creating an instance of FirstTest. The instance will have its own properties and methods. This means that you don't want to call FirstTest.update but game.update.
Also, FirstTest.source_image = ... is wrong, as you are not changing the image source on the instance object in the GUI, but modifying the class definition. You will need to modify game.source_image instead. The easiest way to do this is to save a reference of game in the App object (self.game = game in build), and then reference it with App.get_running_app().game.