I know this is a duplicate, but no answers for this have worked for me.
I am trying to add a widget which serves as an input line with a prompt.
I am getting a name error stating that 'prompt_text' in line 2 of client.kv is not defined.
I believe this is an issue to do with the StringProperty() not being run.
Here is my python file:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.widget import Widget
import kivy.properties as kyProps
import ChatClient
CLIENT = None
VERSION = open("Version.txt").read()
class LoginWindow(Screen):
namee = kyProps.ObjectProperty(None)
password = kyProps.ObjectProperty(None)
def loginBtn(self):
global CLIENT
CLIENT = ChatClient(self.namee.ti.text, self.password.ti.text, VERSION)
if CLIENT.didConFail:
errorMsg = f"Failed to connect. Reason: {CLIENT.connectFailedReason}"
pop = Popup(title='Login Error', content=Label(text=errorMsg))
pop.open()
elif "REFUSED" in CLIENT.finalSetUpMsg:
pop = Popup(title='Login Error', content=Label(text=CLIENT.finalSetUpMsg))
pop.open()
else:
sm.current = "main"
class MainWindow(Screen):
pass
class StyleEditorWindow(Screen):
pass
class PMWindow(Screen):
pass
class ChatWidget(Widget):
pass
class InputLineWidget(Widget):
prompt_text = kyProps.StringProperty("")
ti = kyProps.ObjectProperty(None)
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("client.kv")
sm = WindowManager()
screens = [LoginWindow(name="login"), MainWindow(name="main"), StyleEditorWindow(name="styleEditor"), PMWindow(name="pm")]
for screen in screens:
sm.add_widget(screen)
sm.current = "login"
class CpClientApp(App):
def build(self):
return sm
if __name__ == "__main__":
CpClientApp().run()
And here is my client.kv file:
<InputLineWidget>:
prompt_text: prompt_text
ti: ti
GridLayout:
cols: 2
size: root.width, root.height
Label:
text: prompt_text
TextInput:
id: ti
multiline: false
<ChatWidget>:
<LoginWindow>:
namee: namee
password: password
size: root.width, root.height
GridLayout:
cols: 1
InputLineWidget:
id: namee
prompt_text: "Name: "
InputLineWidget:
id: password
prompt_text: "Password: "
Button:
text: "Log In"
on_release:
root.manager.transition.direction = "up"
root.loginBtn()
<MainWindow>:
<StyleEditorWindow>:
<PMWindow>:
I've tried many solutions based on others encountering similar issues but none have worked.
Im running python 3.7 on Windows 10 using Kivy 2.0.0
Any help would be greatly appreciated. Thank you.
The line:
prompt_text: prompt_text
creates an ObjectProperty named prompt_text that contains a reference to an object that has an id of prompt_text. But since that id is not defined in the <InputLineWidget> rule of your kv file, you get the noted error.
If you want the prompt_text to be used as the text for the label, change the kv to:
<InputLineWidget>:
ti: ti
GridLayout:
cols: 2
size: root.width, root.height
Label:
text: root.prompt_text
TextInput:
id: ti
multiline: false
Related
I have tried to resolve this issue many times but still getting the same error.
I dont Know it is en error from ny code or some other error in installation but i have run kivy without using kv language and got output without error. iam getting error only while using kv.
Python Code
import kivy
kivy.require("2.0.0")
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
class MyGrid(Widget):
name = ObjectProperty(None)
email = ObjectProperty(None)
def btn(self):
print("Name:", self.name.text, "email:", self.email.text)
self.name.text = ""
self.email.text = ""
class MyApp(App):
def build(self):
return MyGrid()
if __name__ == "__main__":
MyApp().run()
KV Code:
#:kivy 2.0.0
<MyGrid>
name: name
email: email
GridLayout:
cols:1
size: root.width - 200, root.height -200
pos: 100, 100
GridLayout:
cols:2
Label:
text: "Name: "
TextInput:
id: name
multiline:False
Label:
text: "Email: "
TextInput:
id: email
multiline:False
Button:
text:"Submit"
on_press: root.btn()
I tried your code and it worked for me, but if it's still printing out errors, I think it's because of the missing colon in line 2 of your kivy file, as Iain suggested, and it should be:
#:kivy 2.0.0
<MyGrid>:
insert the rest of the code here...
I have a question about kivy and it runs weird on anaconda
First weird thing: I have to add into the kivy file then run it and delete the <> from the MenuScreen in the kivy code and run the file again in order for my code to runs like I want. if I don't do this the code will give FactoryException: Unknown class <MenuScreen>
Second weird thing is that after I end kivy and run it again it doesn't let me change screen on the app, I have to restart the shell and do everything like the (first weird thing above) for it to switch screen and run properly.
Here is the code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
kv = Builder.load_file('mymain.kv')
class MainWindow(Screen):
pass
class SecondWindow(Screen):
point = ObjectProperty(None)
note = ObjectProperty(None)
def pressed(self):
''' this fuction is the function of the good action button'''
point1 = self.point.text
Note1 = self.note.text
try:
point1 = int(point1)
print("You just got: ",point1)
print('Note of this action: ')
print(Note1)
except:
if point1 == '':
print('please enter something')
else:
print("point should be a number")
#print(point1, Note1)
self.point.text = ""
self.note.text = ''
#return grid
def increased(self):
''' this function is to increase the mark'''
point2 = self.point.text
try:
point2 = int(float(point2))+1
print('increase point is', point2)
#self.point.text = str(point2)
except:
point2 = 1
print('your point is: ','1')
self.point.text = str(point2)
def decreased(self):
''' this function decrease the point'''
point3 = self.point.text
try:
point3 = int(float(point3))-1
print('decrease point is', point3)
#self.point.text = str(point3)
except:
point3 = -1
print('your point is: ', '-1')
self.point.text = str(point3)
class MenuScreen(ScreenManager):
pass
class MyMainApp(App):
def build(self):
return kv
if __name__ == '__main__':
MyMainApp().run()
Here is the mymain.kv
MenuScreen:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
GridLayout:
cols: 1
Button:
text: 'Good'
on_release: app.root.current = 'second'
Button:
text: 'Bad' #not doing anything yet
<SecondWindow>:
name: 'second'
point: point
note: note
GridLayout:
cols: 1
size: root.width, root.height
GridLayout:
cols: 3
Label:
text: 'Good Point: '
TextInput:
id: point
multiline: False
GridLayout:
cols: 1
Button:
text: 'up'
on_press: root.increased()
Button:
text: 'down'
on_press: root.decreased()
Label:
text: 'Note: '
TextInput:
id: note
multiline: True
Button:
text: ' submit'
on_press: root.pressed()
please help me. Idk why kivy runs like this. Thank you
The problem is that your mymain.kv is getting loaded twice. Kivy will automatically load a kv file if it is named correctly (as your is - See the documentation), and you are also loading it via a Builder.load_string() call. The fix is to remove the line:
kv = Builder.load_file('mymain.kv')
and simplify your App class to:
class MyMainApp(App):
pass
# def build(self):
# return kv
in mymain.kv change:
MenuScreen:
MainWindow:
SecondWindow:
to
<MenuScreen>:
MainWindow:
SecondWindow:
Is there a way to reference a custom widget from the py file?
I made a widget in kv, but I want to reference it from py, then add it again to another widget in kv.
I tried doing this using id but I got an error (KeyError: 'words_entry').
This is what I tried:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.textinput import TextInput
import os
class GetCount(Screen):
count_input = ObjectProperty(None)
def next(self):
# Setup next screen
text_inputs = [self.ids.words_entry for i in range(int(self.count_input.text))]
for text_input in text_inputs:
self.manager.ids.get_input.ids.grid.add_widget(text_input)
# Switch to next screen
self.manager.current = "get_input"
class GetInput(Screen):
pass
kv_file = Builder.load_string("""
ScreenManager:
GetCount:
name: "get_count"
id: get_count
GetInput:
name: "get_input"
id: get_input
<WordEntry#TextInput>:
id: words_entry
multiline: False
size_hint: (self.width, None)
<GetCount>:
count_input: count_input
FloatLayout:
Label:
text: "count"
size_hint: 1, 0.05
pos_hint: {"top":0.9}
TextInput:
id: count_input
size_hint: 0.8, 0.05
pos_hint: {"top":0.7, "x":0.1}
multiline: False
Button:
text: "Next"
on_release: root.next()
size_hint: 0.8, 0.05
pos_hint: {"top":0.5, "x":0.1}
<GetInput>:
ScrollView:
GridLayout:
size_hint_y: None
height: self.minimum_height
id: grid
cols: 1
""")
class MainApp(App):
def build(self):
return kv_file
if __name__ == "__main__":
app = MainApp()
app.run()
In this code, I want to add WordEntry to the GridLayout in GetInput from py (the reason is that I need to add multiple depending on the user's input).
You can use Factory to create an instance of a class that has been defined in kv. So your GetCount class can be:
from kivy.factory import Factory
class GetCount(Screen):
count_input = ObjectProperty(None)
def next(self):
# Setup next screen
for _ in range(int(self.count_input.text)):
new_word_entry = Factory.WordEntry()
self.manager.ids.get_input.ids.grid.add_widget(new_word_entry)
# Switch to next screen
self.manager.current = "get_input"
Trying to create a basic version of the website "leafly".
I want use user input to look up a row in a data set and display all the information on whatever the user has typed in.
I save the user's TextInput to a txt file and then open the text file in the next window.
The txt file saves fine but for some reason it will only load the right text after i've closed the app.
So if the user inputs text into the InputText box it will save to the txt file, but when i try to display that txt file in the next window it only loads what the text file was before loading the programme.
If i run the programme again the previous user input works but i want it to work live without having to close the app.
I am new to python so that might explain any weird code you see haha.
The data set i am using can be found here: https://www.kaggle.com/kingburrito666/cannabis-strains
Also i know how funny and ridiculous this is haha but if you can help i'd appreciate it!
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.properties import ObjectProperty
import pandas as pd
from kivy.properties import StringProperty
from pathlib import Path
pd.set_option('display.max_rows', 500)
pd.set_option('display.max_columns', 500)
df = pd.read_csv("cannabis.csv", sep=",")
class Menu(Screen):
pass
class MainWindow(Screen):
pass
class SecondWindow(Screen):
st = str("")
str(df[df['Strain'].str.match(st)])
type = ObjectProperty(None)
def btn(self):
self.st = self.st + str(self.type.text)
self.st = str(self.st)
print(self.st, file=open("text.txt", "w"))
then
class ThirdWindow(Screen):
with open('text.txt', 'r') as myfile:
data = myfile.read().strip()
strain = StringProperty(str(df[df['Strain'].str.match(str(data))]))
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("my.kv")
class MyMainApp(App):
def build(self):
return kv
if __name__== "__main__":
MyMainApp().run()
.kv file
WindowManager:
Menu
MainWindow:
SecondWindow:
ThirdWindow:
<Menu>:
name: "menu"
GridLayout:
cols:1
Button:
text: "Launch My Weed"
on_release:
app.root.current = "main"
then
<MainWindow>:
name: "main"
GridLayout:
cols:1
GridLayout:
cols:2
Label:
text: "Password: "
TextInput:
id: password
multiline: False
Button:
text: "Login"
on_release:
app.root.current = "second" if password.text == "password" else "main"
root.manager.transition.direction = "left"
then
<SecondWindow>:
name: "second"
type: type
GridLayout:
cols:1
GridLayout:
cols:2
Label:
text: "Strain?: "
TextInput:
id: type
multiline: False
Button:
text: "Tell Me About My Weed"
on_release:
app.root.current = "third"
root.manager.transition.direction = "down"
root.btn()
<ThirdWindow>:
name: "third"
GridLayout:
cols:1
GridLayout:
cols:2
Label:
text : root.strain
You read the text file in the class definition of ThirdWindow which happens at startup, if you want it to happen when you enter the screen, you can put this code in the on_pre_enter (or on_enter but this will happen after the transition has complete, so if it changes the content, it might "flash").
class ThirdWindow(Screen):
strain = StringProperty()
def on_pre_enter(self, *args):
with open('text.txt', 'r') as myfile:
data = myfile.read().strip()
self.strain = str(df[df['Strain'].str.match(str(data))])
I'm currently working to update a bunch of labels with a button press, which I was able to get an answer with through Kivy: How to refernce kv ID in Python?
However, now that I'm in my actual app, I need the functionality to be able to take a user input value and update existing labels. I've modified the example slightly where I'm just taking a user input for a starting number, adding one with each button click and displaying the running total to the right of all of this.
The code I have now is shown below, but the addition of 1 doesn't seem to be processing (it's just staying with the same total after a click). Any ideas why? Thanks very much!
This is the display before the button is clicked (running total is just the user input):
My Python file:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
import random
class TestingWidget(BoxLayout):
# This is the kv id of the Label I would like to update
starting_number = StringProperty('Put your Starting Number here')
running_total = StringProperty(str(0))
#default text set
# This is the action I would like to happen when the button is pressed
def button_pressed(self):
self.running_total = str(int(self.running_total) + 1)
class TestButtonApp(App):
def build(self):
return TestingWidget()
if __name__ == '__main__':
TestButtonApp().run()
My kv file:
<TestingWidget>:
BoxLayout:
orientation: 'horizontal'
TextInput:
id: starting_number
hint_text: root.starting_number
Button:
id: add_one_button
text: 'Add 1 to Starting Number'
on_press: root.button_pressed()
Label:
id: running_total
text: starting_number.text
the problem is that Label is bound with TextInput, and if you change Label as you are doing it the TextInput updates it again giving the feeling that it does not change. What you should do is change the text with the on_text event as shown below:
*.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
class TestingWidget(BoxLayout):
starting_number = StringProperty("")
running_total = StringProperty(str(0))
def button_pressed(self):
if self.running_total != "":
self.running_total = str(int(self.running_total) + 1)
def text_changed(self, instance, value):
self.running_total = value
class TestButtonApp(App):
def build(self):
return TestingWidget()
if __name__ == '__main__':
TestButtonApp().run()
*.kv
<TestingWidget>:
BoxLayout:
orientation: 'horizontal'
TextInput:
id: starting_number
hint_text: "Put your Starting Number here"
on_text: root.text_changed(*args)
text: root.starting_number
Button:
id: add_one_button
text: 'Add 1 to Starting Number'
on_press: root.button_pressed()
Label:
id: running_total
text: root.running_total
The solution is to only change your kv File and no changes required to your Python Script. The changes are as follow:
kv File
1. TextInput: Add on_text Event
The textinput’s text is stored in its TextInput.text property. To run a callback when the text changes, do the following.
on_text:
root.running_total = self.text
2. Label: Reference StringProperty, root.running_total
Replace:
text: starting_number.text
with:
text: root.running_total
testbutton.kv
#:kivy 1.10.0
<TestingWidget>:
BoxLayout:
orientation: 'horizontal'
TextInput:
id: starting_number
hint_text: root.starting_number
on_text:
root.running_total = self.text
Button:
id: add_one_button
text: 'Add 1 to Starting Number'
on_press: root.button_pressed()
Label:
id: running_total
text: root.running_total
Output