I am currently trying to develop a test app by kivy. I am using python 2.7 . My code below returns
AttributeError: 'MainScreen' object has no attribute 'iptHpIdx'.
Could anyone please help me on this error? I just suspected that usage of self is wrong but I spent too long time to figure it out and still I have no clue on the reason why this occurs.
Thank you so much for your help in advance!
import kivy
kivy.require('1.8.0')
import numpy as np
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
import matplotlib
matplotlib.use('module://kivy.garden.matplotlib.backend_kivyagg')
from matplotlib import pyplot as plt
from kivy.garden.matplotlib import FigureCanvasKivyAgg
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MainScreen(Screen):
screenmanager = ObjectProperty()
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
iptHpIdx = TextInput(text = '', multiline=False, font_size=50)
btnToPoint = Button(text='input')
btnToPoint.bind(on_press=self.IptAct)
layout = BoxLayout(orientation='vertical') # syntax(padding=10, orientation='vertical')
layout.add_widget(iptHpIdx)
layout.add_widget(btnToPoint)
layout.add_widget(canvas)
self.add_widget(layout)
def IptAct(self, btn):
global HpHist
self.btnToPoint.text = 'Your input ' + self.iptHpIdx.text
try:
val = int(self.iptHpIdx.text)
HpHist.append(self.iptHpIdx.text)
print 'HpHistAf', HpHist
except ValueError:
print "That's not an int!"
pass
print HpHist
plt.clf()
plt.plot(HpHist)
canvas.draw_idle()
class Test(App):
def build(self):
sm = ScreenManager()
sc1 = MainScreen(name='MainPage')
sm.add_widget(sc1)
return sm
if __name__ == '__main__':
HpHist = []
(fig, axe) = plt.subplots()
canvas = fig.canvas
Test().run()}
You are referencing self.iptHpIdx in IptAct() function but you never created that on your __init__(), you need to create it as self.iptHpIdx. So change your __init__() to:
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
self.iptHpIdx = TextInput(text = '', multiline=False, font_size=50)
self.btnToPoint = Button(text='input')
self.btnToPoint.bind(on_press=self.IptAct)
layout = BoxLayout(orientation='vertical') # syntax(padding=10, orientation='vertical')
layout.add_widget(self.iptHpIdx)
layout.add_widget(self.btnToPoint)
layout.add_widget(canvas)
self.add_widget(layout)
You have to declare ObjectProperty and hook it up the child widgets. Please refer to the example below for details.
Snippets
class MainScreen(Screen):
ms_iptHpIdx = ObjectProperty(None)
ms_btnToPoint = ObjectProperty(None)
def __init__(self, **kwargs):
...
self.ms_iptHpIdx = iptHpIdx
self.ms_btnToPoint = btnToPoint
...
def IptAct(self, btn):
global HpHist
self.ms_btnToPoint.text = 'Your input ' + self.ms_iptHpIdx.text
try:
val = int(self.ms_iptHpIdx.text)
HpHist.append(self.ms_iptHpIdx.text)
Example
main.py
import kivy
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
import numpy as np
import matplotlib
matplotlib.use('module://kivy.garden.matplotlib.backend_kivyagg')
from matplotlib import pyplot as plt
from kivy.garden.matplotlib import FigureCanvasKivyAgg
class MainScreen(Screen):
ms_iptHpIdx = ObjectProperty(None)
ms_btnToPoint = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
iptHpIdx = TextInput(text='', multiline=False, font_size=50)
btnToPoint = Button(text='input')
self.ms_iptHpIdx = iptHpIdx
self.ms_btnToPoint = btnToPoint
btnToPoint.bind(on_press=self.IptAct)
layout = BoxLayout(orientation='vertical') # syntax(padding=10, orientation='vertical')
layout.add_widget(iptHpIdx)
layout.add_widget(btnToPoint)
layout.add_widget(canvas)
self.add_widget(layout)
def IptAct(self, btn):
global HpHist
self.ms_btnToPoint.text = 'Your input ' + self.ms_iptHpIdx.text
try:
val = int(self.ms_iptHpIdx.text)
HpHist.append(self.ms_iptHpIdx.text)
print('HpHistAf', HpHist)
except ValueError:
print("That's not an int!")
print(HpHist)
plt.clf()
plt.plot(HpHist)
canvas.draw_idle()
class TestKivyMatplotlib(App):
def build(self):
sm = ScreenManager()
sm.add_widget(MainScreen(name='MainPage'))
return sm
if __name__ == '__main__':
HpHist = []
(fig, axe) = plt.subplots()
canvas = fig.canvas
TestKivyMatplotlib().run()
Output
Related
There is no such error shown in the Python output shell.
What I want is that , the first page should be the Login page or as here, the "ConnectingPage" then Welcome Should Be shown, and then at last a Set of buttons named from 0 to 99 be shown.
Here is the code :
import kivy
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen, FallOutTransition
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.core.window import Window
class ConnectingPage(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text = "Usename:"))
self.username = TextInput(multiline=False)
self.add_widget(self.username)
self.add_widget(Label(text = "Password:"))
self.password = TextInput(multiline=False,password = True)
self.add_widget(self.password)
self.joinbutton = Button(text="Join")
self.joinbutton.bind(on_release = self.click_join_button)
self.add_widget(Label())
self.add_widget(self.joinbutton)
def click_join_button(self, instance):
username = self.username.text
password = self.password.text
#if username == "venu gopal" and password == "venjar":
MyApp.screen_manager.current = "Info"
MyApp.screen_manager.current = "Chat"
class InfoPage(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 1
self.message = Label(text = "welcome",halign="center", valign="middle", font_size=30)
self.add_widget(self.message)
class SomeApp(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
# Make sure the height is such that there is something to scroll.
layout.bind(minimum_height=layout.setter('height'))
for i in range(100):
btn = Button(text=str(i), size_hint_y=None, height=40)
layout.add_widget(btn)
root = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
root.add_widget(layout)
if __name__ == "__main__":
runTouchApp(root)
class MyApp(App):
screen_manager = ScreenManager(transition=FallOutTransition(duration=2)) # this make screen_manager a class vaiable
def build(self):
# self.screen_manager = ScreenManager()
self.connecting_page = ConnectingPage()
screen = Screen(name='Connect')
screen.add_widget(self.connecting_page)
self.screen_manager.add_widget(screen) # add screen to ScreenManager
# Info page
self.info_page = InfoPage()
screen = Screen(name='Info')
screen.add_widget(self.info_page)
self.screen_manager.add_widget(screen) # add screen to ScreenManager
# Chat App
self.chat_app = SomeApp()
screen = Screen(name='Chat')
screen.add_widget(self.chat_app)
self.screen_manager.add_widget(screen) # add screen to ScreenManager
# return ConnectingPage()
return self.screen_manager
if __name__ == "__main__":
MyApp().run()
The Problem is that: the set of Buttons are getting shown in the start. When the Cross is pressed to close the kivy window, then the Login page is shown and then "welcome" and then the buttons again.
I want It to show from the second Step.
What I believe is that the "line 61" in the code is making a problem. When the code is run it first shows the buttons and so on.
Please Help me find the solution for the above Problem.
Your __init__() method of the SomeApp class starts an App running with the lines:
if __name__ == "__main__":
runTouchApp(root)
and that runTouchApp() does not return until that App completes. So when you run your code, it stops a the line:
self.chat_app = SomeApp()
To fix that, just replace:
if __name__ == "__main__":
runTouchApp(root)
with:
self.add_widget(root)
so i'm trying to learn simple Kivy GUI to send SMS with a class i already made earlier, it works except the window freezes for a couple seconds, any tips on how to make the button press smooth and not freeze at all? Keep in mind the code below is just the beginning of the application, just to make sure it actually works. Thanks in advance.
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.uix.progressbar import ProgressBar
from kivy.config import Config
from sms_funksjon import SendSMS
Config.set('graphics', 'resizable', '0') # 0 being off 1 being on as in true/false
Config.set('graphics', 'width', '500')
Config.set('graphics', 'height', '200')
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.cols = 1
self.inside = GridLayout()
self.inside.cols = 2
self.inside.add_widget(Label(text="Mobil nummer: "), pow(50, 50))
self.mobile_number = TextInput(multiline=False)
self.inside.add_widget(self.mobile_number)
self.inside.add_widget(Label(text="Tekst: "))
self.tekst = TextInput(multiline=False)
self.inside.add_widget(self.tekst)
self.add_widget(self.inside)
self.pb = ProgressBar(max=100)
self.pb.value = 0
self.add_widget(self.pb)
self.submit = Button(text="Send", font_size=40)
self.submit.bind(on_press=self.pressed)
self.add_widget(self.submit)
def pressed(self, instance):
nummer = str(self.mobile_number.text)
tekst = str(self.tekst.text)
SendSMS(nummer, tekst)
self.clear_everything()
def clear_everything(self):
self.mobile_number.text = ""
self.tekst.text = ""
class Main(App):
def build(self):
return MyGrid()
Main().run()
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.effects.scroll import ScrollEffect
from kivy.uix.widget import Widget
from kivy.uix.button import Button
class BSGameMain:
def sas(self):
# blmain.remove_widget(scrlFBtns)
self.scrlFBtns.remove_widget(blbtns)
blmain = BoxLayout(orientation = 'vertical') # MainBoxLayout init
scrlFBtns = ScrollView(effect_cls = 'ScrollEffect')
blbtns = BoxLayout(
orientation = 'vertical',
size_hint_y = None
) # BoxLayout for buttons
blbtns.bind(minimum_height = blbtns.setter('height'))
scrlFBtns.add_widget(blbtns)
for i in range (2):
blbtns.add_widget(Button(
text='asd',
size_hint_y = None,
height = 40,
on_press = sas
))
lblmain = Label(text = 'asd')
blmain.add_widget(lblmain)
blmain.add_widget(scrlFBtns)
class BSApp(App):
def build(self):
game = BSGameMain()
return game.blmain
if __name__ == "__main__":
BSApp().run()
AttributeError 'Button' object has no attribute scrlFBtn. What is the problem? I'm trying to make it so that when you clicked, the screen was cleared (Widget was deleted). Рelp me please =)
Your code has several errors and bad programming practices:
if you declare variables that are inside a class and outside any method of the class will be class variables and not attributes of the class, so it is not a good practice to do so if you want to use later self, all that code must be within a method of a class.
on_someproperty wait as parameter a function that receives parameters, in your case sas() does not receive them so the solution is to use a lambda method.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.effects.scroll import ScrollEffect
from kivy.uix.button import Button
class BSGameMain:
def __init__(self):
self.blmain = BoxLayout(orientation = 'vertical') # MainBoxLayout init
self.scrlFBtns = ScrollView(effect_cls = 'ScrollEffect')
self.blbtns = BoxLayout(
orientation = 'vertical',
size_hint_y = None )
self.blbtns.bind(minimum_height = self.blbtns.setter('height'))
self.scrlFBtns.add_widget(self.blbtns)
for i in range(2):
self.blbtns.add_widget(Button(
text='asd',
size_hint_y = None,
height = 40,
on_press = lambda *args: self.sas()))
lblmain = Label(text = 'asd')
self.blmain.add_widget(lblmain)
self.blmain.add_widget(self.scrlFBtns)
def sas(self):
self.scrlFBtns.remove_widget(self.blbtns)
class BSApp(App):
def build(self):
game = BSGameMain()
return game.blmain
if __name__ == "__main__":
BSApp().run()
I am writing code for a heating control system.
I just want to be able to change the label texts FROM WITHIN PYTHON.
By that I mean, NOT in the GUI code, but somewhere else in the main.
Here is my MWE:
import time
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
import multiprocessing
from kivy.properties import StringProperty
class Data (Widget):
top = StringProperty('hiii')
def __init__(self, **kwargs):
super(Widget, self).__init__(**kwargs)
global mydata
mydata=Data()
class myw (BoxLayout):
def __init__(self, **kwargs):
super(myw, self).__init__(**kwargs)
VERT = BoxLayout(orientation='vertical')
o = Label(text='Oben: ',
font_size=120)
m = Label(text='Mitte: ',
font_size=120)
u = Label(text='Unten: ',
font_size=120)
a = Label(text='Aussen: ',
font_size=120)
mydata.bind(top=o.setter('text'))
VERT.add_widget(o)
VERT.add_widget(m)
VERT.add_widget(u)
VERT.add_widget(a)
onoff = Button(text='Ein',
font_size=120,
size_hint=(0.3, 1))
self.add_widget(VERT)
self.add_widget(onoff)
class TutorialApp(App):
def build(self):
return myw()
if __name__ == "__main__":
try:
global myapp
myapp=TutorialApp()
app_runner=multiprocessing.Process(target=myapp.run)
app_runner.start()
time.sleep(3)
mydata.top='new value assigned'
print (mydata.top)
time.sleep(5)
app_runner.terminate()
except Exception as e:
print ('error occured', e)
I deliberately declared the variable 'mydata' outside the kivy code, such that i can access it from elsewhere in the code (not shown here).
Using threading instead of multiprocessing solved the problem.
So instead of
app_runner=multiprocessing.Process(target=myapp.run)
it now reads:
app_runner=threading.Thread(target=myapp.run)
I am new to kivy.In the below code, Once the login successfull, I am unable to move from login screen to MenuScreen (self.parent.current = MenuScreen()).
How to fix this?.
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.popup import Popup
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.labelUsername = Label(text='User Name : ',pos = (200,300))
self.add_widget(self.labelUsername)
self.inputUser = TextInput(pos = (300,340), multiline=False,height=40,width = 150)
self.add_widget(self.inputUser)
self.labelPassword = Label(text='Password :',pos = (200,250))
self.add_widget(self.labelPassword)
self.inputPasswd = TextInput(pos = (300,280), height=40,width = 150,password=True, multiline=False)
self.add_widget(self.inputPasswd)
self.btnLogin = Button(text = 'Login',pos = (320,230),width = 100,height = 30 )
self.add_widget(self.btnLogin)
self.btnLogin.bind(on_press=self.get_user_passwd)
def get_user_passwd(self,*args):
username, passwd = self.inputUser.text,self.inputPasswd.text
if username == passwd:
self.parent.current = MenuScreen()
else:
pop_up = Popup(title="username and password should be the same.", size_hint=(.3, .3))
pop_up.open()
class MenuScreen(BoxLayout):
def __init__(self,*args):
l = BoxLayout(cols="2")
btn = Button(text="ad")
l.add_widget(btn)
print "flag"
class MyApp(App):
def build(self):
screen_manager = ScreenManager()
#screen_manager.add_widget(LoginScreen(name='LoginScreen'))
#screen_manager.add_widget(MenuScreen(name='menu'))
return LoginScreen()
if __name__ == '__main__':
MyApp().run()