I am building a kivy application and i am using ScreenManager to go from one window to another. The program is working if i have all the classes used in the screenmanager in the same python file, like this:
sm = ScreenManager()
sm.add_widget(Login(name='login'))
sm.add_widget(Account(name='create_account'))
sm.add_widget(AfterLogin(name='after_login'))
But I want to have for each class a separate python file. How can I import the classes and make the screenmanager worK? i have tried to create "login_after.py" having for now only template:
class AfterLogin(Screen):
pass
And importing the class like this:
import login_after
sm.add_widget(login_after.AfterLogin(name='after_login'))
but this triggers the following error:
AttributeError: module 'login_after' has no attribute 'AfterLogin'
How to solve this?
Maybe this will work?
from login_after import AfterLogin
sm.add_widget(AfterLogin(name='after_login'))
Related
I'm new to programming and trying to use Kivy to create a simple game.
I am following a tutorial, and I'm using VSCode, but I can't understand why the code I write in the .kvfile doesn't is used by the main.pyfile.
I have two files in the directory.
main.py
from kivy.app import App
from kivy.uix.widget import Widget
class MainWidget(Widget):
pass
class TheLabApp(App):
pass
TheLabApp().run()
thelab.kv
MainWidget:
<MainWidget>:
Button:
text: 'Hello'
size: 400, 200
I have installed a Kivy extension, and of course the Kivy module. But when I run the code the only thing that appears is a black screen, without the button.
What is happening?
I found the solution. It is required to save the .kv file before running the code, it is just such a sily thing, but if it isn't saved it is read like if it was empty, or never changed.
first time posting!
I'm fairly new to python (and programing!), and I have started to make a basic tkinter program. The code is getting pretty long now, and I want to split it between different .py files to make it more navigatable. So far, all my code exists in classes, seperating the main window, from calculation functions, secondary windows and so on.
First question, is it considered good practice to split code like this? I feel like it is, but want to make sure!
Secondly, how is the best way to handle modules between files?
For example, I have tkinter and matplotlib imported in the main_window.py file. I have the main_window class function which calls a different class which I want to move to another file, but this secondary class has a line which calls tkinter. I want to pass self through the secondary function so that it is using the same instance, as it were.
Here is an example code to illustrate. The first file, main_window.py:
# main_window.py
import tkinter as tk
import matplotlib
import matplotlib.pyplot as plt
import app_design # app_design.py contains the code I want to break out
class MainWindow:
def __intit__(self, root):
self.root = root
self.start_gui()
def start_gui(self):
# a bunch of code
...
# in reality this is read from a program file on startup
color_mode = "Dark"
# This is just an example, the matplotlib call in the other app is in the __init__
self.bg_col_mode = tk.StringVar()
self.bg_col_mode.set(app_design.AppColors(color_mode).background())
# a bucnh more code of various tk widgets and matplotlib charts
...
if __name__ == '__main__':
app = MainWindow(tk.Tk())
app.root.mainloop()
and then an example of some code which I'd like to split out. This is not the only instance of the class referencing a module outside the MainWindow class, but it works as an example:
# app_design.py
class AppColors:
def __init__(self, color_mode):
self.color_mode = color_mode
if self.col_mode == "Dark":
self.plt.style.use("Dark") # it is this .plt call that has moved from the main_window.py file to the new file
else:
self.plt.style.use("Light")
def background_mode(self):
if self.color_mode == "Dark":
return "#292929" # colour code
else:
return "#F8F1F1"
Hopefully this makes sense!
First question, is it considered good practice to split code like this? I feel like it is, but want to make sure!
I actually don't know myself, I only have coded stuff for backend.
Secondly, how is the best way to handle modules between files?
You simply import the file (or function directly).
Example:
file1.py
def hello(name):
print("Hello ", name)
file2.py
from file1 import hello
hello("arjix")
this way you can directly use the function hello
or
import .file1
file1.hello("arjix")
PS: Make sure these two files are in the same folder.
I'm new with kivy, but I have decent experience with Python and Tkinter. I'm trying to control a carousel in kivy programmatically. Essentially, I have an external python program which I want to use to automatically switch images in the carousel. To make an example, I have some code in another file:
import time
while True:
time.sleep(1)
#do something to control the carousel
and then I have my kivy app:
import kivy
from kivy.app import App
from kivy.uix.carousel import Carousel
from kivy.uix.image import AsyncImage
class CarouselApp(App):
self.srcs = ["/a/bunch.png", "/of/paths.jpg", "/to/images.png."]
def build(self):
self.carousel = Carousel(direction="right")
for i in range(0, len(self.srcs)):
src = self.srcs[i]
image = AsyncImage(source=src, allow_stretch=True)
self.carousel.add_widget(image)
return self.carousel
if __name__ == "__main__":
CarouselApp().run()
I would like to be able to control which slide is displayed in the carousel using the top code, but I'm not sure how I would go about doing that, since I can't execute anything after App.run()
I have investigated kivy's Clock module, but I'm not sure that would work for me since I want to switch slides when certain conditions are satisfied rather than on a time basis. The time example I gave is simply an example of my line of thinking.
Any help would be greatly appreciated!
I strongly suggest using a Kivy file to handle this situation. Second, AsyncImage is used when you want to use an image that will be downloaded from the Internet, and as I can see you have the images you are going to use are locally stored, so use Image instead.
I think you should implement the method on_start in the class which is extending App (CarouselApp in this case) and schedule a function using Clock as,
def on_start(self):
Clock.schedule_interval(self.my_callback, 1)
Then in the same class (CarouselApp) you should define my_callback:
def my_callback(self, nap):
if condition_is_satisfied: # this is supposed to be your condition
# control carousel
Follow up from Kivy class in .py and .kv interaction , but more complex.
Here is the full code of what I'm writing:
The data/screens/learnkanji_want.kv has how I want the code to be, but I don't fully understand how the class KanjiOriginScreen() plays it's role in screen management.
data/screens/learnkanji.kv works how I want it, but for this to work I have to put keyb_height in class KanjiOriginScreen() (main.py). However I want that code to be in the class LayoutFunction() (learnkanji.py).
Question
How can I put keyb_height in the function LayoutFunction() and access this in the .kv file in <LayoutFunction>?
Could you also explain why KanjiOriginScreen: can be put in learnkanji.kv without < > and the program still recognizes it should use this?
If anything is unclear, please ask :)
Edit
I found out that I didn't import the learnkanji.py in the learnkanji.kv file and that caused that it couldn't find the class 'LayoutFunction'.
#:import learnkanji data.screens.learnkanji
To answer your questions:
The way you are doing it should work. You should be able to access object attributes from kv. If your attribute is going to change, however, and you want the UI to update when it does, you should use Kivy Properties. If it is constant, a normal attribute works fine.
From the Kivy Docs, <Widget>: is a class rule that will be applied to every instance of that class. Widget: will create an actual instance of that class (in this case it is your root widget).
As for ScreenManager and Screens, you can think of them this way. Each Screen is it's own individual UI (it's own root widget). The screen manager is a container that holds your Screen and can swap between different Screens. This lets you create separate UIs that you can toggle between. Each UI is a separate widget tree with a Screen at its root. The docs are actually pretty good at describing ScreenManager.
How can I put keyb_height in the function LayoutFunction() and access this in the .kv file in ?
You can't do this with a function. You need to make LayoutFunction into a class to do this. Like so:
main.py
class LayoutClass(BoxLayout): # I made it a boxlayout, you could make it anything you want
keyb_height = NumericProperty(260) # from kivy.properties import NumericProperty
kv file:
<LayoutClass>: # can only access it this way if it's a class in main.py
something: root.keyb_height
Could you also explain why KanjiOriginScreen: can be put in learnkanji.kv without < > and the program still recognizes it should use this?
It sounds like you're asking how you can achieve this.. but I can't think why?
Unless you want it managed by a ScreenManager perhaps? However, the only way you can have KanjiOriginScreen within the kv file without the <> is if it is inside another root widget. For instance, see Testy and ScreenTwo as they are in the kv file under <Manager> in my answer to your other question(here). They are without <> because they are class instances, WITHIN another class(the Manager class). Only root widgets have the <> around them in the kv file. If none of this makes sense to you, you need to do a tutorial on kivy.
Check out this tutorial I made a while back, it explains a little about root widgets in kv(at around 4.30).
Sorry I was not clear with my question, but with the help on IRC on #Kivy I ended up with the following:
learnkanji.py
class LayoutFunctioning(BoxLayout):
keyb_height = NumericProperty(260)
learnkanji.kv
KanjiOriginScreen:
name: 'LearnKanji'
fullscreen: True
LayoutFunction:
id: lfunc
#...code...
height: lfunc.keyb_height #Instead of root.keyb_height
Now I understand how to use the id, I can use lfunc to call my code in LayoutFunction() :)
The following is a function I created, and put it in a file called last_function.py
from tkinter import*
def new_gui(app,sound_file,mixer):
track=mixer.Sound(sound_file)
def track_toggle():
if ballCheckbutton.get()==1:
track.play(loops=-1)
else:
track.stop()
ballCheckbutton=IntVar()
c1=Checkbutton(app,text="check me out",command=track_toggle,variable=ballCheckbutton)
c1.pack(side=LEFT)
ballScale=DoubleVar()
def ScaleVolume(v):
track.set_volume(ballScale.get())
ballScale.set(track.get_volume())
s1=Scale(app,variable=ballScale,resolution=0.1,command=ScaleVolume,orient=HORIZONTAL,from_=0.0,to=1.0,label="volume")
s1.pack()
and this is the file i use.. to call the code and run it..
from tkinter import *
import pygame.mixer
from last_function import*
app=Tk()
mixer=pygame.mixer
mixer.init()
new_gui(app,"49119_M_RED_HardBouncer.wav",mixer)
def close():
mixer.stop()
app.destroy()
app.protocol("WM_DELETE_WINDOW",close)
app.mainloop()
Everything works fine.. but my query is...
1> Why can't I remove from tkinter import* from the last_function file.. cause anyway it's got that on the top of the file that's calling it right. Why do I get an error saying IntVar() not defined.
2> Why do I have to pass mixer as a parameter in the function? can the function not inherit it directly from import pygame.mixerthat's on top of the file calling it?
What I mean to say is. THERE ARE TKINTER COMPONENTS ALSO BEING USED, BUT I DON'T PASS TKINTER AS A PARAMETER.. Do I ! then why is there this... selective parameter assignment??
I'm really confused!!!
1> Why can't i remove from tkinter
import* from the last_function file..
cause anyway it's got that on the top
of the file that's calling it
right.Why do i get an error saying
IntVar() not defined
The Python "import" follows the same scoping rules as the rest of the Python language. By "import" at the top of your second files does not make the Tkinter namespace available to the last_function.py module. Tkinter also needs to be imported there.
2>why do i have to pass mixer as a
parameter in the function? can the
function not inherit it directly from
import pygame.mixerthat's on top of
the file calling it? WHAT I MEAN TO
SAY IS. THERE ARE TKINTER COMPONENTS
ALSO BEING USED,BUT I DON'T PASS
TKINTER AS A PARAMETER.. DO I!! then
why is there this.. selective
parameter assignment??
With the way you have this coded, you need to pass mixer because you are modifying it in your second file with:
mixer.init()
If you reimported mixer in your last_function.py, you would be getting another instance of mixer and not the one previously imported. There is nothing selective about this since both of your files have the Tkinter namespace imported.
You should try and re-factor this code to avoid having to import Tkinter into two modules and having to init mixer in one module and pass it to another.