I was writing a piece of code with kivy with all the packages installed.
When I run the code it still shows "No module named kivy".
The modules were installed from both the command prompt and the VS code terminal though this code had worked fine just a few days ago. Today i opened it and it showed me this error
This is my code
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from database import DataBase
class CreateAccountWindow(Screen):
namee = ObjectProperty(None)
email = ObjectProperty(None)
password = ObjectProperty(None)
def submit(self):
if self.namee.text != "" and self.email.text != "" and self.email.text.count("#") == 1 and self.email.text.count(".") > 0:
if self.password != "":
db.add_user(self.email.text, self.password.text, self.namee.text)
self.reset()
sm.current = "login"
else:
invalidForm()
else:
invalidForm()
def login(self):
self.reset()
sm.current = "login"
def reset(self):
self.email.text = ""
self.password.text = ""
self.namee.text = ""
class LoginWindow(Screen):
email = ObjectProperty(None)
password = ObjectProperty(None)
def loginBtn(self):
if db.validate(self.email.text, self.password.text):
MainWindow.current = self.email.text
self.reset()
sm.current = "main"
else:
invalidLogin()
def createBtn(self):
self.reset()
sm.current = "create"
def reset(self):
self.email.text = ""
self.password.text = ""
class MainWindow(Screen):
n = ObjectProperty(None)
created = ObjectProperty(None)
email = ObjectProperty(None)
current = ""
def logOut(self):
sm.current = "login"
def on_enter(self, *args):
password, name, created = db.get_user(self.current)
self.n.text = "Account Name: " + name
self.email.text = "Email: " + self.current
self.created.text = "Created On: " + created
class WindowManager(ScreenManager):
pass
def invalidLogin():
pop = Popup(title='Invalid Login',
content=Label(text='Invalid username or password.'),
size_hint=(None, None), size=(400, 400))
pop.open()
def invalidForm():
pop = Popup(title='Invalid Form',
content=Label(text='Please fill in all inputs with valid information.'),
size_hint=(None, None), size=(400, 400))
pop.open()
kv = Builder.load_file("my.kv")
sm = WindowManager()
db = DataBase("users.txt")
screens = [LoginWindow(name="login"), CreateAccountWindow(name="create"),MainWindow(name="main")]
for screen in screens:
sm.add_widget(screen)
sm.current = "login"
class MyMainApp(App):
def build(self):
return sm
if __name__ == "__main__":
MyMainApp().run()
As people said in the comments, the reason is that the Python environment used by the terminal does not contain modules.
Solution: Please select the Python environment where the module "kivy" is installed in the lower left corner of VS Code, and use the shortcut key Ctrl+Shift+` to open a new VS Code terminal, it will automatically enter the selected environment.
check: We can use the command "pip --version" or "python --version" to check which Python the terminal is using and the module is installed in this location:
Reference: Python environment in VS Code.
You just need to select the right version of python with which you installed kivy.
Click at the bottom part as indicated in the image below to select the right one.
Change python interpreter
Related
I state that this is the first time I use Kivy.
The code I attached works, the only problem is that the lbl label does not update automatically but only if I press the update button.
In practice, if I call the update_lbl function via the "update" button it works, when it is called automatically by unpacking_msg it does nothing.
from email import message
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.lang import Builder
from numpy import empty
import paho.mqtt.client as mqttClient
from queue import Queue
import threading
q=Queue()
incoming_message =''
incoming_topic =''
class Manager(ScreenManager):
pass
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
class HomeScreen(Screen):
pass
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
class MsgDecoder ():
def __init__(self,msg):
self.msg = msg
def unpacking_msg(self):
global incoming_message
global incoming_topic
incoming_topic = str(self.msg.topic)
incoming_message = str(self.msg.payload.decode("utf-8"))
MainApp().update_lbl()
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
class MqttApp():
def __init__(self,broker_address,port,user,password):
self.password = password
self.user = user
self.port = port
self.broker_address = broker_address
broker_address = "broker.hivemq.com"
port = 1883
user = ""
password = ""
try:
client = mqttClient.Client(clean_session=True, userdata=True)
client.username_pw_set(user , password)
client.connect(broker_address,port)
client.loop_start()
except:
pass
def on_connect(client, userdata, flags, rc):
client.subscribe("kivy")
def on_message(client, userdata, msg):
q.put(msg)
client.on_connect = on_connect
client.on_message = on_message
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
class MainApp(App):
lbl_txt = StringProperty()
def __init__(self):
super(MainApp, self).__init__()
self.lbl_txt = ("No message")
def switch_callback(self, switchObject, switchValue):
if(switchValue):
MqttApp.client.publish("kivy", "ON")
else:
MqttApp.client.publish("kivy", "OFF")
def update_lbl(self, *args):
self.lbl_txt=incoming_message
#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
def get_msg ():
threading.Timer(1.0, get_msg).start()
while not q.empty():
msg = q.get()
if msg is None:
continue
md= MsgDecoder(msg)
md.unpacking_msg()
get_msg()
if __name__ == '__main__':
MainApp().run()
Here is the Kivy file:
ScreenManager:
HomeScreen:
id: 'homescreen'
<HomeScreen>:
swc: swc
BoxLayout:
orientation: 'vertical'
spacing: 50
padding: 100
Label:
text: 'Remote Lamp'
Switch:
id:swc
on_active: app.switch_callback(*args)
Button:
text: "update"
on_press: app.update_lbl()
Label:
id: lbl
text: app.lbl_txt
I really appreciate any other helpful advice! I am not an expert as you can see.
The problem is that your code:
MainApp().update_lbl()
is creating a new instance of MainApp and calling its update)lbl() method. However, that new instance of MainApp is not the instance that you see on the screen. You must call the update_lbl() method of the running App. You can do that by using the get_running_app() method. See the documentation. Try this replacement for the above line:
App.get_running_app().update_lbl()
I'm trying to build a Kivy application that has 2 screens which are re-used over and over again with different text.
So I go from a FirstScreen with a Label that says "First1" to a SecondScreen with a Label that says "Second1", and then back to the FirstScreen but this time with the Label "First2", then SecondScreen and "Second2", and so on and so forth.
The code for this is pretty straightforward, but there seems to be a problem in updating the Label text without a designated update button. For some reason, my Python code manages to update the text, but it isn't updated in my .kv file. So for instance, my print statements will tell me that the Label text is "First2", but Kivy displays "First1" for me. I've illustrated this in the Screenshot below:
By adding a Button that updates the text on press, everything is updated, synced up and works, but I'd really like it to work without the extra user input. Does anybody know how I can go about this? I've scoured the docs and stackoverflow questions left and right but can't seem to find the answer to my seemingly simple problem.
Here's the code:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty, ObjectProperty
from kivy.lang import Builder
S_ID = 1 # global screen ID. I'm using this to detect what text to use.
class FirstScreen(Screen):
text = StringProperty("")
lbl = ObjectProperty(None)
def __init__(self, **kwargs):
super(FirstScreen, self).__init__(**kwargs)
global S_ID
print("\nS_ID is ", S_ID)
self.update()
def update(self):
print("FIRST - UPDATE")
if S_ID == 1:
print("FIRST1")
self.text = "FIRST1"
elif S_ID == 2:
print("FIRST2")
self.text = "FIRST2"
print("self.lbl.text", self.lbl.text)
else:
print("FIRST ELSE")
self.text = "FIRST ELSE"
def pressed(self):
sm.current = "second"
class SecondScreen(Screen):
text = StringProperty("")
def __init__(self, **kwargs):
super(SecondScreen, self).__init__(**kwargs)
self.update()
def update(self):
print("SECOND - UPDATE")
if S_ID == 1:
print("SECOND1")
self.text = "SECOND1"
elif S_ID == 2:
print("SECOND2")
self.text = "SECOND2"
else:
print("SECOND ELSE")
self.text = "SECOND ELSE"
def pressed(self):
global S_ID
S_ID += 1
FirstScreen.update(FirstScreen())
sm.current = "first"
sm = ScreenManager()
kv = Builder.load_file("test.kv")
sm.add_widget(FirstScreen(name='first'))
sm.add_widget(SecondScreen(name='second'))
sm.current = "first"
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
and here's the .kv file:
<FirstScreen>:
name: "first"
lbl: lbl:
GridLayout:
cols:2
Label:
id: lbl
text: root.text
Button:
text: "next"
on_press: root.pressed()
<SecondScreen>:
name: "second"
GridLayout:
cols:2
Label:
text: root.text
Button:
text: "next"
on_press:
root.pressed()
The problem is your statement:
FirstScreen.update(FirstScreen())
This statement is creating a new instance of FirstScreen and updating that instance. Unfortunately, that instance is not the one shown in your GUI. You can correct that by replacing the above statement with:
first_screen = self.manager.get_screen('first')
first_screen.update()
This code gets the instance of FirstScreen from the ScreenManager and calls update() on that instance.
I am attempting to have a functioning back button to take user back to the main screen, seen below as 'Social', but cannot seem to make it function. I have tried multiple solutions that I've found on this site and some others, but haven't seemed to fix the issue yet.
I have tried multiple solutions that I've found on this site and some others, but haven't seemed to fix the issue yet. I am trying to avoid a Kivy file currently, but have accepted that at some point I'm going to have to make one.
#Main Screen
class Social(GridLayout):
title = "Welcome To PedaShield"
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.cols = 3
#FB 'Icon'
self.facebook = Button(text="Facebook")
self.facebook.bind(on_press=self.fb_signin)
self.add_widget(self.facebook)
#Button for Facebook Screen
def fb_signin(self, instance):
datastop.screen_manager.current = "FBSignin"
#Create FB sign-in screen w/ options
class FBSignin(GridLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.cols = 4
if os.path.isfile("fbprev_details.txt"):
with open("fbprev_details.txt", "r") as f:
d = f.read().split(",")
prev_username = d[0]
prev_password = d[1]
else:
prev_username = ""
prev_password = ""
#row 1
self.add_widget(Label())
self.add_widget(Label(text="Username: "))
self.username = TextInput(text=prev_username, multiline=False)
self.add_widget(self.username)
self.add_widget(Label())
#row 2
self.add_widget(Label())
self.add_widget(Label(text="Password: "))
self.password = TextInput(text=prev_password, multiline=False)
self.add_widget(self.password)
self.add_widget(Label())
#row 3 include checkbox for saving signin
self.add_widget(Label())
self.signin = Button(text="Sign In")
self.signin.bind(on_press=self.signin_button)
self.add_widget(self.signin)
self.goback = Button(text="Back")
self.signin.bind(on_press=self.go_back)
self.add_widget(self.goback)
self.add_widget(Label())
#sign-in button
def signin_button(self, instance):
username = self.username.text
password = self.password.text
print("Signing in as {username}")
with open("fbprev_details.txt","w") as f:
f.write(f"{username},{password}")
#Back button
def go_back(self, instance):
print('Here')
datastop.screen_manager.current = "Social"
class PedaShield(App):
title = "PedaShield"
def build(self):
self.screen_manager = ScreenManager()
#Main screen with Social Media Options
self.Social = Social()
screen = Screen(name='Social')
screen.add_widget(self.Social)
self.screen_manager.add_widget(screen)
#Facebook sign in/option page
self.fb_signin = FBSignin()
screen = Screen(name="FBSignin")
screen.add_widget(self.fb_signin)
self.screen_manager.add_widget(screen)
return self.screen_manager
if __name__ == "__main__":
datastop = PedaShield()
datastop.run()
I don't have anything to trace, just nothing happens when the 'back' button it pressed.
You assigned function go_back to button self.signin
self.signin.bind(on_press=self.go_back)
but it has to be self.goback
self.goback.bind(on_press=self.go_back)
In old code when you click button "Sign In" then you can see two strings
Here
Signing in as {username}
First text is from function go_back. And this should give you clue where is the problem
Using Kivy 1.10.0 with Python 2.7.9 I am trying to get the TextInput value entered by user when Button (my_button2) is clicked .And although I have been able to get this working with GridLayout it seems like the method I am using is not working with ScreenManager with BoxLayout . Error received is : AttributeError: 'ScreenTwo' object has no attribute 'inpt' when my_button2
After clicking 'Next Screen ' button , it takes me to page where user enters text value , and 'print' button should print it
Please see below :
import kivy
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
class ScreenOne(Screen):
def __init__ (self,**kwargs):
super (ScreenOne, self).__init__(**kwargs)
my_box1 = BoxLayout(orientation='vertical')
my_button1 = Button(text="Next Screen ",size_hint_y=None,size_y=100)
my_button1.bind(on_press=self.changer)
my_box1.add_widget(my_button1)
self.add_widget(my_box1)
def changer(self,*args):
self.manager.current = 'screen2'
class ScreenTwo(Screen):
def __init__(self,**kwargs):
super (ScreenTwo,self).__init__(**kwargs)
layout = BoxLayout(orientation='vertical')
self.add_widget(layout)
inpt = TextInput(text="Some text ",size_y=50)
layout.add_widget(inpt)
my_button2 = Button(text="Print ")
my_button2.bind(on_press=self.click)
layout.add_widget(my_button2)
Home_btn = Button(text="Back")
Home_btn.bind(on_press=self.home)
layout.add_widget(Home_btn)
def click(self,my_button2):
entered_value = self.inpt.text
print entered_value
def home(self,*args):
self.manager.current = 'screen1'
class TestApp(App):
def build(self):
my_screenmanager = ScreenManager()
screen1 = ScreenOne(name='screen1')
screen2 = ScreenTwo(name='screen2')
my_screenmanager.add_widget(screen1)
my_screenmanager.add_widget(screen2)
return my_screenmanager
if __name__ == '__main__':
TestApp().run()
second screen
When you use self you are trying to access members of the class, but in your case inpt it is not since it is a variable any, if you want to be a member of the class you must put forward self, in your case change:
inpt = TextInput(text="Some text ",size_y=50)
layout.add_widget(inpt)
to:
self.inpt = TextInput(text="Some text ",size_y=50)
layout.add_widget(self.inpt)
Note: I recommend you read OOP basics, if you are not going to have many of these problems.
I have some trouble to transfert a list of element, that i get from a file (in the first screen), to the second and third screen.
I have 3 Screen managed by ScreenManager, every screen is in a different file.py and have a file.kv.
This is what my ScreenManager looks like (filename : login.py):
from interface1 import Interface1App
from interface2 import Interface2App
class LoginApp(App):
def build(self):
manager = ScreenManager()
#add view login
manager.add_widget(Login(name='login'))
# add view 'interface1'
app = Interface1App()
app.load_kv()
interfacen1 = app.build()
manager.add_widget(interfacen1)
# add view 'interface2'
app2 = Interface2App()
app2.load_kv()
interfacen2 = app2.build()
manager.add_widget(interfacen2)
# add view 'interface3'
app3 = Interface3App()
app3.load_kv()
interfacen3 = app3.build()
manager.add_widget(interfacen3)
manager.transition = SlideTransition(direction="left")
return manager
In the screen manager login i import all the screens (ex: from interface1 import Interface1App)
In the second file, i put in self.list some data, and use it for that interface (filename : interface1.py):
from interface2 import Interface2App
class AllImage(Screen):
CONTAINER_PNG = os.path.join(AllImage_ROOT, 'images')
IMAGES_NAMES = [c[:-4] for c in os.listdir(CONTAINER_PNG)]
def __init__(self, **kwargs):
Screen.__init__(self, **kwargs)
for im in IMAGES_NAMES:
if IMAGES_NAMES != None :
toggleimage = ToggleWithImage(src=im+'.png')
toggleimage.bind(on_press= lambda a, im=im:self.onpress_addpage(self.listim, im))
self.layout.add_widget(toggleimage)
def change_screen(self, x, list):
self.manager.transition = SlideTransition(direction="left")
self.manager.current = 'interface2'
self.manager.get_screen('interface2')
self.manager.list1 = [1,2,3]
def backtologin(self):
self.manager.transition = SlideTransition(direction="right")
self.manager.current = 'login'
self.manager.get_screen('login')
class Interface1App(App):
'''The kivy App that runs the main root. All we do is build a AllImage
widget into the root.'''
def build(self):
screen = AllImage()
screen.name = 'interface1'
return screen
After that i want to use again the data collected in the 2nd interface (self.list) and use it in the 3rd Interface (filename: interace2.py):
from interface1 import AllImage #this isn't working
class Combinaison(Screen):
screen = ObjectProperty(None)
def __init__(self, **kwargs):
# self._previously_parsed_text = ''
super(Combinaison, self).__init__(**kwargs)
# self.list = list(self.manager.get_screen('interface1').list)
print(self.manager.list1) # The problem is here <===========
def backtointerface1(self):
self.manager.transition = SlideTransition(direction="right")
self.manager.current = 'interface1'
self.manager.get_screen('interface1')
class Interface2App(App):
'''The kivy App that runs the main root. All we do is build a Combinaison
widget into the root.'''
def build(self):
screen = Combinaison()
screen.name = 'interface2'
return screen
With this code i have this error : print(self.manager.list1)
AttributeError: 'NoneType' object has no attribute 'list1'
I think i didn't understand how i should use the self.manager.list1=[1, 2, 3]
I hope that i was clear, sorry for the long post.
Thank you for your time :)
You can use Screen.manager.get_screen(name).list = list(self.list)
A complete example:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
class Screen1(Screen):
list = [1,2,3]
def __init__(self,**kwargs):
super(Screen1,self).__init__(**kwargs)
self.switch_button = Button(text="goto 2")
self.switch_button.bind(on_release=self.switch)
self.add_widget(self.switch_button)
def switch(self,*args):
self.list = [4,5,6]
self.manager.get_screen("screen2").list = list(self.list)
self.manager.current = "screen2"
class Screen2(Screen):
def __init__(self,**kwargs):
super(Screen2,self).__init__(**kwargs)
self.switch_button = Button(text="goto 1")
self.switch_button.bind(on_release=self.switch)
self.add_widget(self.switch_button)
def switch(self,*args):
self.manager.current = "screen1"
def on_enter(self):
print self.list
class MainApp(App):
def build(self):
sc1 = Screen1(name="screen1")
sc2 = Screen2(name="screen2")
self.sm = ScreenManager()
self.sm.add_widget(sc1)
self.sm.add_widget(sc2)
return self.sm
MainApp().run()
You can also use the ScreenManager to store the list or lists.
self.manager.list1 = [1,2,3] # dont call this in __init__
self.manager.list2 = [4,5,6] # call it in on_enter instead
Those lists will be available from all screens after they are added to the manager. The on_enter method on the screen would be suitable for your example.