Kivy Screen not appearing - python

It was working fine. It would open window with 3 columns, with text I could enter. After adding some code, it suddenly stopped showing a screen, and it just says Username: in the terminal. I used a completely newly typed code, but still same result:
(I left out the importing from the top)
class ConnectPage(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 2 # used for our grid
with open("prev_details.txt","r") as f:
d = f.read().split(",")
prev_ip = d[0]
prev_port = d[1]
prev_username = d[2]
self.add_widget(Label(text='IP:')) # widget #1, top left
self.ip = TextInput(text=prev_ip, multiline=False) # defining self.ip...
self.add_widget(self.ip) # widget #2, top right
self.add_widget(Label(text='Port:'))
self.port = TextInput(text=prev_port, multiline=False)
self.add_widget(self.port)
self.add_widget(Label(text='Username:'))
self.username = TextInput(text=prev_username, multiline=False)
self.add_widget(self.username)
# add our button.
self.join = Button(text="Join")
self.join.bind(on_press=self.join_button)
self.add_widget(Label()) # just take up the spot.
self.add_widget(self.join)
def join_button(self, instance):
port = self.port.text
ip = self.ip.text
username = self.username.text
with open("prev_details.txt","w") as f:
f.write(f"{ip},{port},{username}")
info = f"Joining {ip}:{port} as {username}"
chat_app.info_page.update_info(info)
chat_app.screen_manager.current = 'Info'
Clock.schedule_once(self.connect, 1)
def connect(self, _):
port = int(self.port.text)
ip = self.ip.text
username = self.username.text
if not socket_client.connect(ip, port, username, show_error):
return
chat_app.create_chat_page()
chat_app.screen_manager.current = 'Chat'
class ChatPage(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 1
self.add_widget(Label(text='Fancy stuff here to come!!!', font_size=30))
class InfoPage(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 1
self.message = Label(halign="center", valign="middle", font_size=30)
self.message.bind(width=self.update_text_width)
self.add_widget(self.message)
def update_info(self, message):
self.message.text = message
def update_text_width(self, *_):
self.message.text_size = (self.message.width * 0.9, None)
class Epicapp(App):
def build(self):
self.screen_manager = ScreenManager()
self.connect_page = ConnectPage()
screen = Screen(name='Connect')
screen.add_widget(self.connect_page)
self.screen_manager.add_widget(screen)
# Info page
self.info_page = InfoPage()
screen = Screen(name='Info')
screen.add_widget(self.info_page)
self.screen_manager.add_widget(screen)
return self.screen_manager
def create_chat_page(self):
self.chat_page = ChatPage()
screen = Screen(name='Chat')
screen.add_widget(self.chat_page)
self.screen_manager.add_widget(screen)
def show_error(message):
chat_app.info_page.update_info(message)
chat_app.screen_manager.current = 'Info'
Clock.schedule_once(sys.exit, 10)
This is the result (no screen)
Username:
Process finished with exit code -1

Problem has been solved, i removed the import socket_client.py which is not shown in the code above. Now the prev_details.txt is making an error. FileNotFoundError: [Errno 2] No such file or directory: 'prev_details.txt'

Related

Strange visual bug happening on QFocusEvents in my child QLineEdit

I'm making this class to make my QEditLines to have a default value, that will work as a label for the line, it seems to be working, but when changing the focus with 'Tab' the line will add a '|' at the end of the line and keep it until restarting and it's just visual, it doesn't change the Entry's value.
My child class of QLineEdit:
class Entry(QtWidgets.QLineEdit):
def __init__(self, frame: QtWidgets.QFrame):
super(Entry, self).__init__(frame)
self.default_text = ''
#QtCore.pyqtSlot(QtGui.QFocusEvent)
def focusInEvent(self, a0: QtGui.QFocusEvent) -> None:
if self.text() == self.default_text:
self.clear()
if 'PASSWORD' in self.default_text:
self.setEchoMode(self.Password)
#QtCore.pyqtSlot(QtGui.QFocusEvent)
def focusOutEvent(self, a0: QtGui.QFocusEvent) -> None:
if self.text() == "":
self.setText(self.default_text)
if 'PASSWORD' in self.default_text:
self.setEchoMode(self.Normal)
can be reproducible with a simple GUI with the code below:
def print_value(entry: Entry, entry2: Entry):
print(entry.text())
print(entry2.text())
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
root = QtWidgets.QMainWindow()
root.resize(500,500)
frame = QtWidgets.QWidget(root)
frame.resize(500,500)
entry = Entry(frame)
entry.setGeometry(QtCore.QRect(0, 0, 100, 50))
entry.setText('PASSWORD')
entry.default_text = 'PASSWORD'
entry2 = Entry(frame)
entry2.setGeometry(QtCore.QRect(0, 100, 100, 50))
entry2.setText('USERNAME')
entry2.default_text = 'USERNAME'
button = QtWidgets.QPushButton(frame)
button.setGeometry(QtCore.QRect(0, 200, 50, 50))
button.pressed.connect(lambda: print_value(entry, entry2))
root.show()
sys.exit(app.exec_())
In the terminal is the output of the values in the Entry objects, Password, and USERNAME QLineEdits. [Screenshot]
The default implementation of focusInEvent and focusOutEvent has the task of enabling and disabling the cursor, but by override those methods you are eliminating that behavior. One possible solution is to also invoke the default implementation:
class Entry(QtWidgets.QLineEdit):
def __init__(self, frame: QtWidgets.QFrame):
super(Entry, self).__init__(frame)
self.default_text = ""
def focusInEvent(self, a0: QtGui.QFocusEvent) -> None:
if self.text() == self.default_text:
self.clear()
if "PASSWORD" in self.default_text:
self.setEchoMode(self.Password)
super().focusInEvent(a0)
def focusOutEvent(self, a0: QtGui.QFocusEvent) -> None:
if self.text() == "":
self.setText(self.default_text)
if "PASSWORD" in self.default_text:
self.setEchoMode(self.Normal)
super().focusOutEvent(a0)

'Back' Button not functioning in Python with Kivy

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

Resetting kivy text inputs once the inputs have been saved + any other comments

I'm currently making a program that logs strung racquets with a few different things that go along with the job. I'm having trouble resetting kivy text inputs after the information has been saved. The code is probably hard to read being it's slightly patchwork of my messing with things over the past few days. If you could help me to understand how to reset text inputs and any other improvements would be much appreciated - Chris - Novice
import kivy
import gspread
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager , Screen
from oauth2client.service_account import ServiceAccountCredentials
list = []
Client = ''
Racquet = ''
String = ''
Tension = ''
scope = ['https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scope)
client = gspread.authorize(creds)
sheet = client.open("Stringing Log MAIN").sheet1
def clients(instance, value):
print(value)
global Client
Client = str(value[8:])
global list
return
def racquets(instance, value):
print(value)
global Racquet
Racquet = str(value[9:])
global list
return
def strings(instance, value):
print(value)
global String
String = str(value[8:])
global list
return
def tensions(instance, value):
print(value)
global Tension
Tension = str(value[9:])
global list
return
clienttxt = open("Client", "w")
racquettxt = open("Racquet", "w")
stringtxt = open("String", "w")
tensiontxt = open("Tension", "w")
def Test(x):
global sheet
list.insert(0, Client)
list.insert(1, Racquet)
list.insert(2, String)
list.insert(3, Tension)
sheet.insert_row(list, 1)
list.clear()
return
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.cols = 1
client = TextInput(text = "Client: ", write_tab = False, multiline=False)
client.bind(text=clients)
self.add_widget(client)
racquet = TextInput(text= "Racquet: ", write_tab = False, multiline=False)
racquet.bind(text=racquets)
self.add_widget(racquet)
string = TextInput(text= "String: ", write_tab = False, multiline=False)
string.bind(text=strings)
self.add_widget(string)
tension = TextInput(text= "Tension: ", write_tab = False, multiline=False)
tension.bind(text=tensions)
self.add_widget(tension)
button1 = Button(text="Submit")
self.add_widget(button1)
button1.bind(on_press=Test)
class StringingApp(App):
def build(self):
return MyGrid()
if __name__ == "__main__":
StringingApp().run()
You can save a reference to each TextInput in your __init__() method, for example:
self.client = TextInput(text = "Client: ", write_tab = False, multiline=False)
Then, move your Test method inside your MyGrid class:
def Test(self, x):
global sheet
list.insert(0, Client)
list.insert(1, Racquet)
list.insert(2, String)
list.insert(3, Tension)
sheet.insert_row(list, 1)
list.clear()
# clear the TextInput widgets here
self.client.text = ''
return
And your Button bind becomes:
button1.bind(on_press=self.Test)
So here is the entire MyGrid class after my suggested changes:
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super(MyGrid, self).__init__(**kwargs)
self.cols = 1
# save a reference to the client TextInput
self.client = TextInput(text="Client: ", write_tab=False, multiline=False)
self.client.bind(text=clients)
self.add_widget(self.client)
racquet = TextInput(text="Racquet: ", write_tab=False, multiline=False)
racquet.bind(text=racquets)
self.add_widget(racquet)
string = TextInput(text="String: ", write_tab=False, multiline=False)
string.bind(text=strings)
self.add_widget(string)
tension = TextInput(text="Tension: ", write_tab=False, multiline=False)
tension.bind(text=tensions)
self.add_widget(tension)
button1 = Button(text="Submit")
self.add_widget(button1)
button1.bind(on_press=self.Test) # bind to Test() method below
def Test(self, x):
global sheet
list.insert(0, Client)
list.insert(1, Racquet)
list.insert(2, String)
list.insert(3, Tension)
sheet.insert_row(list, 1)
list.clear()
# clear the TextInput widgets here
self.client.text = '' # or set it to anything you want, handle the other TextInputs similarly
return

How to transfer a list of element from a screen to another using Kivy

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.

Tkinter app using sockets hangs on start

I am having problems with a socket/tkinter login app. The server is on a Raspberry Pi but even with the server not on I see no reason that this should hang on startup. I have imported a module I have made which I will include.
Why does it hang?
Here is my client code - the one that hangs:
import socket, pickle
import Tkinter as tk
import loginutility
class Server(object):
def __init__(self):
self.s = socket.socket()
self.p = 10000
self.ip = "192.168.1.120"
def addUser(self, userinfo):
puserinfo = pickle.dumps(userinfo)
self.s.connect((self.ip, self.p))
self.s.sendall("check")
self.sendall(puserinfo)
if self.s.recv(1024) == False:
self.s.sendall("add")
self.send(puserinfo)
return True
else:
return False
def userDump(self):
self.s.sendall("userdump")
return pickle.loads(self.s.recv(1024))
class Main(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
class LoginFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.pack()
self.l = loginutility.LoginBox(self)
login = tk.Button(self, text="Login", command=self.login)
login.pack()
def login(self):
u, p = self.l.values()
users = Server.userDump()
if u in users and users[u] == p:
tk.Label(self, text="Success").pack()
main = Main()
mf = LoginFrame(main)
main.mainloop()
The server code - wasn't on when tested:
import loginutility as lu
import socket
import pickle
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
address = ''
port = 10000
s.bind((address, port))
s.listen(5)
users = lu.UserList("accounts")
while True:
c, clientaddress = s.accept()
c.send("You're Connected")
d = c.recv(1024)
if d == "add":
userdata = c.recv(1024)
username, password = pickle.loads(userdata)
users.adduser(username, password)
print "User {} added with password of {}.".format(username, password)
c.send("Success")
elif d == "check":
username, password = pickle.loads(c.recv(1024))
if users.checkuser(username) == False:
c.sendall(False)
else:
c.sendall(True)
elif d == "userdump":
c.send(pickle.dumps(users.dumpuser())
c.close()
Necessary loginutility code:
class LoginBox:
def __init__(self, parent):
self.l1=Label(parent, text="Username:").grid()
self.ubox=Entry(parent)
self.ubox.grid()
self.l2=Label(parent, text="Password:").grid()
self.pbox=Entry(parent, show="*")
self.pbox.grid()
def values(self):
return (self.ubox.get(), self.pbox.get())
class UserList:
def __init__(self, file=None):
self.users = {}
self.file = file
if file != None:
with open(file, "rb") as f:
self.users = pickle.load(f)
def adduser(self, user, pswrd):
self.users[user] = pswrd
if file != None:
with open(self.file, "wb") as f:
pickle.dump(self.users, f)
def dumpuser(self):
return self.users
Any help is much appreciated!
The reason it hangs is because you are mixing both pack and grid in the same parent widget. Consider the following code:
class LoginFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.pack()
self.l = loginutility.LoginBox(self)
login = tk.Button(self, text="Login", command=self.login)
login.pack()
In the above code, you create a frame (self), create a LoginBox that is a child of self, and a button that is also the child of self. The button uses pack, and LoginBox.__init__ uses grid.
You cannot use both pack and grid on widgets that share a common parent. In this case the common parent is the instance of LoginFrame.

Categories

Resources