Trouble Multithreading a Kivy applciation - python

I'm trying to have the application UI continue to run even while the BLE scan function is running which is asynchronous. I tried creating another thread but, the UI still freezes when I use the activate button. The screen in question is Screen4, the rest is unimportant. I've tried a couple of different methods to get it to work but I'm having trouble implementing some of the example with it either producing an error or just still causing the UI to freeze for a couple of seconds. Here's the code:
import sys
import json
import googlemaps
import pygatt
import time
import asyncio
from bleak import discover
from urllib.request import urlopen
from twilio.rest import Client
from threading import Thread
#UI import libraries
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.event import EventDispatcher
from kivy.clock import Clock
accSID = '**********'
authtkn = '*********'
twilcli = Client(accSID, authtkn)
sendNum = '********'
key = '*********'
url = 'http://ipinfo.io/json'
i = 0
sm = ScreenManager()
class Screen1(Screen):
def pair_pressed(self):
def BLEdetect (self):
async def run():
devices = await discover()
for d in devices:
print(d)
k = 0
if (str(d).find('DSD TECH') != -1):
global address
address = str(d)[0:18]
print(address)
sm.current = 's2'
k = 1
break
if (k != 1):
k = 0
sm.current = 's3'
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
Clock.schedule_once(BLEdetect, 0.5)
class Screen2(Screen):
def submit_pressed(self):
contact1_inp = ObjectProperty(None)
contact1 = StringProperty('')
self.contact1 = self.contact1_inp.text
phone1_inp = ObjectProperty(None)
phone1 = StringProperty('')
self.phone1 = self.phone1_inp.text
#----------------------------------------------------------------
contact2_inp = ObjectProperty(None)
contact2 = StringProperty('')
self.contact2 = self.contact2_inp.text
phone2_inp = ObjectProperty(None)
phone2 = StringProperty('')
self.phone2 = self.phone2_inp.text
#---------------------------------------------------------------
contact3_inp = ObjectProperty(None)
contact3 = StringProperty('')
self.contact3 = self.contact3_inp.text
phone3_inp = ObjectProperty(None)
phone3 = StringProperty('')
self.phone3 = self.phone3_inp.text
#--------------------------------------------------------------
contact4_inp = ObjectProperty(None)
contact4 = StringProperty('')
self.contact4 = self.contact4_inp.text
phone4_inp = ObjectProperty(None)
phone4 = StringProperty('')
self.phone4 = self.phone4_inp.text
#-------------------------------------------------------------
global contactlst
contactlst = [[self.contact1, self.phone1], [self.contact2, self.phone2],
[self.contact3, self.phone3],[self.contact4, self.phone4]]
#if contaclst is None:
j = 0
while (j < 4):
print("Contact " + str(j + 1) + ": " + contactlst[j][0])
print("Phone " + str(j + 1) + ": " + contactlst[j][1])
j += 1
sm.current = 's4'
class Screen3(Screen):
def tryagain_pressed(self):
sm.current = 's1'
def cancel_pressed(self):
exit()
class Screen4(Screen):
stop = threading.Event()
global BLEscan, i
def BLEscan(self):
while (i == 0):
async def run():
devices = await discover()
for d in devices:
print(d)
k = 0
if (str(d).find(address) != -1):
response = urlopen(url)
data = json.load(response)
city = data['city']
loc = data['loc']
country = data['country']
region = data['region']
gmapurl = 'http://maps.googleapis.com/maps/api/staticmap?center='
gmapurl = gmapurl + loc + '&size=600x600&zoom=14&sensor=true&markers=color:red%7Clabel:A%7C' + loc + '&key=' + key
def waste_time(dt):
pass
while ((k < 4) and (contactlst[k][0] != '')):
mes = 'Please Send Help ' + contactlst[k][0]
info = '{4} \nRegion : {1} \nCountry : {2} \nCity : {3} \nLoc: {0}'.format(loc,region,country,city,mes)
message = twilcli.messages.create(body=info, from_=sendNum, to=contactlst[k][1], media_url= gmapurl)
Clock.schedule_once(waste_time, 3)
k += 1
i = 1
break
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
def second_thread(self):
Clock.schedule_interval(BLEscan, 5)
def activate_pressed (self):
i = 0
threading.Thread(target=self.second_thread).start()
def deactivate_pressed(self):
i = 1
class esosApp(App):
def on_stop(self):
self.root.stop.set()
def build(self):
screenone = Screen1(name='s1')
screentwo = Screen2(name='s2')
screenthree = Screen3(name='s3')
screenfour = Screen4(name='s4')
sm.add_widget(screenone)
sm.add_widget(screentwo)
sm.add_widget(screenthree)
sm.add_widget(screenfour)
return sm
if __name__ == '__main__':
esosApp().run()```

Related

how to trick Thread.start() to run more than once in python

intro
im building a p2pvideo call app.
from the side that gets the call
i have the kivy main loop running as a thread with a another thread slistner_bind_thread.start() (a socket.bind function) that listens to calls and returns a pickup quote or a decline quote, if its picked up quote it starts another thread sstream_bind_thread.start() which cv2capture and pack send the feed (socket.bind).
from the side that calls
i have the same kivy main loop running as a thread with another thread scall_CON_thread.start() (socket.connect) that starts with a call button and waits for either a pickup quote or a decline from the other side if its picked up quote it calls for another threads feed_CON_thread.start() that revieves an opencv2 data packets.
Problem
when i make the call everything works as expected but when hanging up and calling again i understood that threads cant be started more than once. if i attempt to use anything else the gui gets bugged obviously.
i have some ideas but i dont know if they will work or not, if anyone can suggest something PLEASE at least a comment.
here is the main.py
import socket
import gi
gi.require_version('Gst', '1.0')
import kivy
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
from kivy.uix.image import Image
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.core.window import Window
from kivy.config import Config
from kivy.lang import Builder
from kivy.properties import StringProperty, ObjectProperty, NumericProperty, ReferenceListProperty
from kivy.graphics.texture import Texture
from kivy.core.camera import Camera
from kivy.graphics import *
import time
import os
from pathlib import Path
import cv2
import struct
import threading
import pickle
Builder.load_file('the.kv')
##########go to line 233 and 240
################################ GLOBAL VARIABLAS BEGIN #######################
######## PORTS ############
sfeed_CON_port = 2430
slistner_bind_port = 1330
sstream_bind_port = 2430
scall_CON_port = 1330
###################### ################# #########
action = ''
endcall = False
endcall_string = ''
myip = ''
sfeed_cv_frame_recieve = None
incall_add = 'nocalls'
outcall_add = ''
################################ GLOBAL VARIABLS END #########################
def feedconnect():
global outcall_add, sfeed_CON_port, endcall ########### addr conn from listenr
global sfeed_cv_frame_recieve
try:
sfeed_CON_ad = outcall_add
sfeed_CON = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sfeed_CON.connect((sfeed_CON_ad, sfeed_CON_port))
data = b""
payload_size = struct.calcsize("Q")
while endcall == False:
while len(data) < payload_size:
packet = sfeed_CON.recv(4*1024)
if not packet: break
data+=packet
packed_msg_size = data[:payload_size]
data =data[payload_size:]
msg_size = struct.unpack("Q", packed_msg_size)[0]
while len(data) < msg_size:
data+=sfeed_CON.recv(4*2024)
frame_data = data[:msg_size]
data =data[msg_size:]
frame = pickle.loads(frame_data)
sfeed_cv_frame_recieve = frame
key = cv2.waitKey(1) & 0xFF
if endcall == True:
print(endcall_string + ' closing feedconnect() socket')
sfeed_CON.close()
break
sfeed_CON.close()
except Exception as e:
print("client: " + outcall_add + 'disconnected ')
sfeed_CON_thread = threading.Thread(target = feedconnect) ####### THREAD
def callconnect():
global outcall_add, scall_CON_port
scall_CON_ad = outcall_add
scall_CON = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scall_CON.connect((scall_CON_ad, scall_CON_port))
print('callconnect is waiting for an answer from :' + scall_CON_ad + ' on port: ' + str(scall_CON_port))
time.sleep(15)
answer = scall_CON.recv(4*1024)
decoded_answer = answer.decode("utf-8")
if decoded_answer == 'decilned':
print(decoded_answer)
elif decoded_answer == 'picked up' :
print(decoded_answer)
f = True ############ to check
#feedconnect()
sfeed_CON_thread.start()
print(f)
else:
print(decoded_answer)
scall_CON.close()
scall_CON_thread = threading.Thread(target = callconnect) #### THREAD
def streambind():
global myip, sstream_bind_port
sstream_bind_ad = myip
sstream_bind = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sstream_bind.bind((sstream_bind_ad, sstream_bind_port))
print('myip is : ' + myip + ' from streambind() ' )
sstream_bind.listen(5)
sstream_bind_sclient, sstream_bind_sclient_ad = sstream_bind.accept()
if sstream_bind_sclient:
opcv_vid = cv2.VideoCapture(0)
while (opcv_vid.isOpened()):
try:
img, frame = opcv_vid.read()
pickled_frame = pickle.dumps(frame)
struct_pickled_frame = struct.pack("Q", len(pickled_frame)) + pickled_frame
sstream_bind_sclient.sendall(struct_pickled_frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
slistner_bind_sclient.close()
except:
endcall = True
endcall_string ='endcall'
print(endcall_string, endcall)
sstream_bind.close()
break
#sstream_bind_sclient.close() ############ hint i am closing only the client
sstream_bind_thread = threading.Thread(target = streambind) #### THREAD
def listnerbind():
global myip, slistner_bind_port, incall_add
global action
host_name = socket.gethostname()
myip = socket.gethostbyname(host_name + ".local")
slistner_bind_ad = myip
slistner_bind = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
slistner_bind.bind((slistner_bind_ad, slistner_bind_port))
slistner_bind.listen(10)
print('listnerbind() on thread')
print('listning for calls in: ' + slistner_bind_ad + ' on port: ' + str(slistner_bind_port))
while True:
slistner_bind_sclient, slistner_bind_sclient_ad = slistner_bind.accept()
###### block note start ###
#### the incall_add should be a list for multiple incalls at once #####
incall_add = str(slistner_bind_sclient_ad[0])
###### block note end ####
print('incall from: ' + incall_add + ' at port: ' + str(slistner_bind_port))
time.sleep(15) ##### needs to be edited later #########
if action == '':
slistner_bind_sclient.send(bytes('no answer',"utf-8"))
elif action == 'picked up':
sstream_bind_thread.start()
slistner_bind_sclient.send(bytes(action,"utf-8"))
elif action == 'declined':
slistner_bind_sclient.send(bytes(action,"utf-8"))
slistner_bind_thread = threading.Thread(target = listnerbind)
class fscreen(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def on_touch_down(self, touch):
if touch.x !=0:
theapp.screenm.current = "secondscreen"
class secscreen(Widget):
waiter = StringProperty()
callerid = StringProperty()
def __init__(self,**kwargs):
super().__init__(**kwargs)
global outcall_add
Clock.schedule_interval(self.callcheck, 0.5)
def callcheck(self, *args):
global incall_add
self.waiter = incall_add
self.callerid = incall_add
def decline(self):
global action
action = "declined"
def pickup(self):
global action
action = "picked up"
theapp.screenm.current = "thirdscreen"
def call(self):
global callconnect
global outcall_add
self.ip = self.ids.ipcall.text
outcall_add = self.ip
theapp.screenm.current = "thirdscreen"
if outcall_add != '':
print('')
#### note start sstreamer_bind_thread should also start but i dont have another camera###
#callconnect()
scall_CON_thread.start()
########## note end ########
class thscreen(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
global sfeed_cv_frame_recieve, endcall
Config.set('graphics', 'resizable', True)
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '800')
#######################
Clock.schedule_interval(self.feedupdate, 0.01)
def feedupdate(self, dt): # MULTIPLE USERS NEDSS MORE WORK OF POS AND SIZE AFTER SOCKETS
global sfeed_cv_frame_recieve, endcall
############## note begin sfeed_cv_frame_recieve is converted to texture ############
if sfeed_cv_frame_recieve is not None and endcall == False:
self.frame = sfeed_cv_frame_recieve
buf1 = cv2.flip(self.frame, 0)
buf = buf1.tostring()
image_texture = Texture.create(
size=(self.frame.shape[1], self.frame.shape[0]), colorfmt='bgr')
image_texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')
self.texture = image_texture
with self.canvas:
Rectangle(texture=self.texture, pos=(self.pos[0], self.pos[1]+(self.size[1]*0.1)), size=(self.size[0],self.size[1]*0.9))
###################### note end ##############
elif endcall == True:
theapp.screenm.current = "secondscreen"
def hangup(self):
global endcall
endcall = True
endcall_string = 'endcall'
print(endcall_string)
theapp.screenm.current = "secondscreen"
class theapp(App):
def build(self):
self.screenm = ScreenManager() #(transition=FadeTransition())
self.fscreen = fscreen()
screen = Screen(name = "first screen")
screen.add_widget(self.fscreen)
self.screenm.add_widget(screen)
self.secscreen = secscreen()
screen = Screen(name = "secondscreen")
screen.add_widget(self.secscreen)
self.screenm.add_widget(screen)
self.thscreen = thscreen()
screen = Screen(name = "thirdscreen")
screen.add_widget(self.thscreen)
self.screenm.add_widget(screen)
return self.screenm
if __name__ == "__main__":
theapp = theapp()
slistner_bind_thread.start() ########### LISTING THREAD
threading.Thread(target = theapp.run()) ################ GUI APP THREAD
and here is the.kv file
<fscreen>
Label:
text: '0I Mechanics'
font_size: root.width*0.05
pos: root.width*0.4, root.height*0.8
<secscreen>
TextInput:
id: ipcall
hint_text: 'Ip'
width: root.width*0.3
height: root.height*0.05
pos: root.width*0.4, root.height*0.8
Button:
text: 'call'
width: root.width*0.3
height: root.height*0.05
pos: root.width*0.4, root.height*0.7
on_press: root.call()
Label:
text: root.callerid
font_size: root.width*0.02
pos: root.width*0.4, root.height*0.4
Button:
text: 'pickup'
width: root.width*0.2
height: root.height*0.05
disabled: True if root.waiter == 'nocalls' else False
pos: root.width*0.5, root.height*0.3
on_press: root.pickup()
Button:
text: 'decline'
width: root.width*0.2
height: root.height*0.05
disabled: True if root.waiter == 'nocalls' else False
pos: root.width*0.3, root.height*0.3
on_press: root.decline()
<thscreen>
Widget:
Button:
text: 'hangup'
width: root.width*0.2
height: root.height*0.05
pos: root.width*0.45, root.height*0.01
on_press: root.hangup()

Keyerror Display on pyatogui in kivy android app

i imported my kivy app to android, but on run it crashes and gives me the above error. I tried moving the location of display 0 but it did not change the error. it tells me the error happens when importing pyautogui.
Code:
import time
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
import pyautogui
import os
class layy(App):
os.environ['DISPLAY'] = ':0'
global t
t = TextInput(hint_text='insert text')
global c
global s
s = TextInput(hint_text='insert time till begin')
c = TextInput(hint_text='insert amount')
def bot(self, instance):
am = c.text
if (am == ""):
am = '0'
l = int(am)
apm = t.text
m = str(apm)
if (m == ""):
m = 'hi'
pm = c.text
if (pm == ""):
pm = '0'
o = int(pm)
base = 0
time.sleep(o)
while (base < l):
pyautogui.typewrite(m)
pyautogui.press('enter')
base = base + 1
def build(self):
b = Button(text='Start Spam')
b.bind(on_press=self.bot)
layout = BoxLayout(orientation='vertical')
sublay1 = BoxLayout(orientation='horizontal')
sublay2 = BoxLayout(orientation='horizontal')
sublay3 = BoxLayout(orientation='horizontal')
layout.add_widget(sublay1)
sublay1.add_widget(t)
layout.add_widget(sublay2)
sublay2.add_widget(s)
sublay2.add_widget(c)
layout.add_widget(sublay3)
sublay3.add_widget(b)
return layout
if __name__ == '__main__':
layy().run()
If anyone knows what to do, please tell me. Sorry if it is simple, i'm new to python.

Can buildozer made android apps use glob and os modules?

So at the moment in try to figure out why is my small player i wrote in kivy crashes on start. It says build successful and all modules seem to work separately in other tests (except for glob) but this one is pure python as far as i know.
here's my code
import glob
import kivy
from kivy.core.audio import SoundLoader
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.screenmanager import ScreenManager, Screen
from kivy.graphics import Rectangle
from kivy.graphics import Color
from kivy.uix.widget import Widget
import random
import os
from android.permissions import request_permissions, Permission
request_permissions([Permission.READ_EXTERNAL_STORAGE])
class PageI(GridLayout):
def __init__(self,**kwargs):
super().__init__( **kwargs)
self.cols = 3
self.state = False
self.music = glob.glob('/Phone/reMusic/*.mp3')#glob.glob('music\\*.mp3')
self.currname = self.music[0]
self.lasttime = 0
self.currsound = SoundLoader.load(self.currname)
fillclr = (round(random.random(),4), round(random.random(),4), round(random.random(),4), 1)
SR = Button(text='forward')
SR.bind(on_press=self.switchoR)
self.add_widget(SR)
placeholder = Label()
self.add_widget(placeholder)
SL = Button(text='backward')
SL.bind(on_press=self.switchoL)
self.add_widget(SL)
placeholder = Label()
self.add_widget(placeholder)
self.PP = Button(on_press = self.switchostate)
self.add_widget(self.PP)
placeholder = Label()
self.add_widget(placeholder)
placeholder = Label()
self.add_widget(placeholder)
self.showcase = Label(text=self.currname)
self.add_widget(self.showcase)
def PPcontrol(self):
if not self.currsound.state == 'play':
self.currsound.play()
self.currsound.seek(self.lasttime)
else:
self.lasttime = int(self.currsound.get_pos())
self.currsound.stop()
def switchostate(self,instance):
self.PPcontrol()
def showsitch(self):
self.showcase.text = self.currname
def switchoR(self,instance):
instance.background_color = (round(random.random(),4), round(random.random(),4), round(random.random(),4), 1)
ind = self.music.index(self.currname)
if ind+1 > len(self.music)-1:
self.currname = self.music[ind - len(self.music) + 1]
else:
self.currname = self.music[ind + 1]
self.lasttime = 0
self.currsound.stop()
self.currsound = SoundLoader.load(self.currname)
self.currsound.play()
self.showsitch()
def switchoL(self,instance):
instance.background_color = (round(random.random(),4), round(random.random(),4), round(random.random(),4), 1)
ind = self.music.index(self.currname)
if ind - 1 < 0:
self.currname = self.music[len(self.music) - 2]
else:
self.currname = self.music[ind - 1]
self.lasttime = 0
self.currsound.stop()
self.currsound = SoundLoader.load(self.currname)
self.currsound.play()
self.showsitch()
class Applet(App):
def build(self):
self.dircheck()
self.p = PageI()
return self.p
def dircheck(self):
try:
if not os.path.exists(os.path.join(os.getcwd(),'\\music')):
os.mkdir(os.path.join(os.getcwd(),'\\music'))
except: None
if __name__ == '__main__':
apper = Applet()
apper.run()
ik its quite messy but as you can see i tried both creating directories and accessing premade one.
and well, im not sure why it dies, i made sure it had all perms in spec file as well.

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

Kivy opens two popup windows, when I only expected one

So, I've been trying to get a popup to open on Kivy, and close it with when pressing Escape. However I found myself having to press it twice, and then I found out that it was opening two popups.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.popup import Popup
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.config import Config
Config.set('kivy', 'exit_on_escape', '0')
class KeyDown(App):
def build(self):
self.popup_exists = 0
Window.bind(on_key_down=self.key_action)
return Widget()
def key_action(self, *args):
key1 = args[1]
key2 = args[2]
special_keys = args[4]
letter = args[3]
if special_keys == ['ctrl'] and letter == 'f': # Ctrl-F
print('Find')
self.open_find_dialog()
if key1 == 13 and key2 == 40 and self.popup_exists == 1: # ENTER KEY
pass
if key1 == 27 and key2 == 41 and self.popup_exists == 1: # ESC
self.find_window.dismiss()
def open_find_dialog(self):
content = BoxLayout(orientation='horizontal')
col1_cont = BoxLayout(size_hint_x = 2,orientation = 'vertical')
col2_cont = BoxLayout(size_hint_x = 4,orientation = 'vertical')
find_labl = Label(text='Find',size_hint_y=None, height = 40)
repl_labl = Label(text='Replace',size_hint_y=None, height = 40)
find_text = TextInput(text='', size_hint_y = None, height = 40)
repl_text = TextInput(text='', size_hint_y = None, height = 40)
col1_cont.add_widget(find_labl)
col1_cont.add_widget(repl_labl)
col2_cont.add_widget(find_text)
col2_cont.add_widget(repl_text)
content.add_widget(col1_cont)
content.add_widget(col2_cont)
self.find_window = Popup(title='Find and Replace',content = content,size_hint=(None, None), size=(240, 140))
self.find_window.open()
self.popup_exists = 1
if __name__ == '__main__':
KeyDown().run()
Does anyone know why would it open two popups? How would I prevent it from doing so?

Categories

Resources