I want to update the source of an image when root.stop_recording() is called in the kv file, but the command self.ids.Mic_Image.source = self.Mic_Loading doesn't update the image. Instead the previous image (a gif opened in a zip file) just freezes. How can I fix this?
Here's the relevant section of my Python code:
class IdentifyItem(Screen):
Mic_Loading = StringProperty()
Mic_Listening = StringProperty()
Mic_Pressed = StringProperty()
Mic_Static = StringProperty()
def __init__(self, **kwargs):
super(IdentifyItem, self).__init__()
self.Mic_Loading = 'Mic_Loading.zip'
self.Mic_Listening = "Mic_Listening.zip"
self.audio_to_text = AudioToText()
def on_press(self):
self.ids.Mic_Image.anim_loop = 0
self.ids.Mic_Image.source = self.Mic_Listening
self.record = self.audio_to_text.start()
self.audio_thread = threading.Thread(target=self.record, args=(),
daemon=True) # initialises an instance of Thread.
self.audio_thread.start() # starts the Thread instance
def stop_recording(self):
self.ids.Mic_Image.source = self.Mic_Loading
self.audio_to_text.stop()
And the .kv file:
Image:
id: Mic_Image
source: "Mic_Static.png"
opacity: 1
anim_delay: 0
size_hint: (0.9,0.9)
pos_hint: {"center_x":0.5, "center_y": 0.2}
Button:
id: mic
background_color: (1, 1, 1, 0)
pos_hint: {"center_x":0.5, "y":0.08}
size_hint: (0.26,0.19)
on_press:
root.on_press()
on_release:
root.stop_recording()
Related
Kivy does not update the refreshed data on the screen.
If i restart the app, i can see the new data after calculation.
I want to see refreshed data on the screen after the calculation is done, without restarting the program again.
When i run the app, datas() function pulls the json file at the first time and also when i on the second calculation screen, before calculation, the Clock.schedule_once(self.datas) pulls the data again as well but sill i can't see the refreshed names on the screen.
PY File:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.metrics import dp
from kivy.uix.behaviors import ButtonBehavior
from kivy.clock import Clock, mainthread
import json
import threading
class Test(BoxLayout):
def __init__(self, **kwargs):
super(Test, self).__init__(**kwargs)
self.data = self.datas()
# Homepage Screen
def homepage(self, screenmanager):
screenmanager.current = 'homepage_screen'
Clock.schedule_once(self.clear_widgets)
# Clear Widgets
def clear_widgets(self, *args):
for child in [child for child in self.ids.gridsonuc.children]:
self.ids.gridsonuc.remove_widget(child)
# Under Over Screen
def second(self,screenmanager):
screenmanager.current = 'second_screen'
Clock.schedule_once(self.clear_widgets)
Clock.schedule_once(self.datas) # Before calculation, each time app pulls data again, but Kivy Does Not Update The Refreshed Data in The Screen!
Clock.schedule_once(self.calculate)
# or, if i can use threading system as well but this time i must add #mainthread above def calculate(self, *args): to make code work.
# in both scenario, Kivy Does Not Update The Refreshed Data in The Screen While APP is Running.
# mythread1 = threading.Thread(target=self.clear_widgets)
# mythread1.start()
# mythread2 = threading.Thread(target=self.datas)
# mythread2.start()
# mythread3 = threading.Thread(target=self.calculate)
# mythread3.start()
# Calculation
##mainthread
def calculate(self, *args):
for i in self.data['home']:
box = BoxLayout(size_hint_y = None, height = dp(50))
hometeams = Label(text = f'{[i]}', font_name = 'Roboto', font_size = dp(15), size_hint = (0.225, 1), halign='center', bold = True )
box.add_widget(hometeams)
self.ids.gridsonuc.add_widget(box)
def datas(self, *args):
# PLEASE CHANGE THE LOCATION!!!!!!!!!!!!!!!!!
with open ("C:\\Users\\Messi\\Desktop\\Python\\Projects\\Football Tips\\Kivy\\Testing Bugs\\Test1\\data.json", "r") as dosya:
dataApi = json.load(dosya)
print('datas updated')
return dataApi
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()
KV File:
#:import NoTransition kivy.uix.screenmanager.NoTransition
<Test>:
ScreenManager:
transition: NoTransition()
id: sm
size: root.width, root.height
Screen:
name: 'homepage_screen'
BoxLayout:
size_hint: 1, 0.10
Button:
text: 'Calculate'
id: underOver_button_homepage
on_press: root.second(sm)
background_color: 0, 0, 0, 0
Screen:
name: 'second_screen'
BoxLayout:
spacing: '20dp'
orientation: 'vertical'
BoxLayout:
size_hint: 1, 0.80
ScrollView:
scroll_type: ['bars', 'content']
bar_margin: '5dp'
bar_color: 1, 0.4, 0.769, 1
bar_width: '5dp'
bar_inactive_color: 1, 0.4, 0.769, 1
GridLayout:
id: gridsonuc
cols: 1
spacing: '50dp'
size_hint_y: None
height: self.minimum_height
BoxLayout:
size_hint: 1, 0.10
Button:
text: 'Home'
id: home_button_underOver
on_press: root.homepage(sm)
background_color: 0, 0, 0, 0
data.json File
Please create a data.json file and PLEASE CHANGE THE LOCATION!!!!!!!!!!!!!!!!! in def datas(self, *args):
with open ("C:\Users\Messi\Desktop\Python\Projects\Football Tips\Kivy\Testing Bugs\Test1\data.json", "r") as dosya:
{"home": ["Manchester City", "Arsenal"]}
Video Of The Problem
https://www.youtube.com/watch?v=mMwryGLQ5SQ
Thanks for your help
The problem is that your display is created using self.data, but when you call the datas() method and read the updated json file, you don't do anything with the newly read data. Try changing:
def datas(self, *args):
# PLEASE CHANGE THE LOCATION!!!!!!!!!!!!!!!!!
with open ("C:\\Users\\Messi\\Desktop\\Python\\Projects\\Football Tips\\Kivy\\Testing Bugs\\Test1\\data.json", "r") as dosya:
dataApi = json.load(dosya)
print('datas updated')
return dataApi
to:
def datas(self, *args):
# PLEASE CHANGE THE LOCATION!!!!!!!!!!!!!!!!!
with open ("C:\\Users\\Messi\\Desktop\\Python\\Projects\\Football Tips\\Kivy\\Testing Bugs\\Test1\\data.json", "r") as dosya:
dataApi = json.load(dosya)
print('datas updated')
self.data = dataApi # update the self.data
return dataApi
My app extracts frames from a video, when the function get_frames gets called it should set some MDApp variables and change to screen named extracting, then when it finishes extracting the frames it should go to completed screen.
But for some reason it never shows the extracting screen, the code never shows any error and just goes directly to completed screen when it finishes extracting.
What is causing this?
How can I change my code to fix this error?
Code:
from kivymd.app import MDApp
from kivy.properties import StringProperty, NumericProperty
from kivy.config import Config
from kivy.uix.screenmanager import ScreenManager
from kivymd.uix.screen import MDScreen
#from marquee import Marquee
from kivy.uix.floatlayout import FloatLayout
import cv2
import time
import datetime
import os
from tkinter.filedialog import askopenfilename
from tkinter import Tk
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'width', '500')
Config.set('graphics', 'height', '200')
Config.write()
def direxist(dir):
if os.path.isdir(dir) != True:
os.mkdir(dir)
return dir
else:
a = f'{dir}(1)'
return direxist(a)
""""class Marquee():
pass"""
class Completed(MDScreen):
pass
class Extracting(MDScreen):
pass
class SelectFileScreen(MDScreen):
def get_image_one(self):
Tk().withdraw() # avoids window accompanying tkinter FileChooser
filename = askopenfilename(
initialdir = f"{os.getcwd()}",
title = "Select a File",
)
if filename != '':
MDApp.get_running_app().app_filepath = filename
self.manager.transition.direction = 'left'
self.manager.current = 'settings'
class GetFramesScreen(MDScreen):
base_dir_for_frames = StringProperty(f"{os.path.join(os.path.expanduser('~'),'Desktop')}")
def get_frames(self):
start_time = time.time()
MDApp.get_running_app().file_name = str(os.path.basename(MDApp.get_running_app().app_filepath))
saved_frame_dir = os.path.join(self.base_dir_for_frames,os.path.basename(MDApp.get_running_app().app_filepath)).replace('.', '_').replace('\01', '01')
b = direxist(saved_frame_dir)
print(f'pathe to save ->{b}')
vidcap = cv2.VideoCapture(MDApp.get_running_app().app_filepath)
fps= vidcap.get(cv2.CAP_PROP_FPS)
MDApp.get_running_app().fps = str(int(fps))
frame_count = vidcap.get(cv2.CAP_PROP_FRAME_COUNT)
capduration = int(frame_count/fps)
video_time = str(datetime.timedelta(seconds=capduration))
MDApp.get_running_app().video_duration = str(video_time)
self.manager.transition.direction = 'right'
self.manager.current = 'extracting'
success,frame = vidcap.read()
cont = 1
n_extracted_frames = 0
while success:
if cont == 1 or cont%int(fps) == 0:
seconds1 = (vidcap.get(cv2.CAP_PROP_POS_MSEC))/(1000)
video_time2 = str(datetime.timedelta(seconds=seconds1))
x = video_time2.replace(':','.')
formatted = f"frame{cont}_{x}.jpg"
dd = os.path.join(str(b),formatted)
cv2.imwrite(dd,frame)
#MDApp.get_running_app().pb = cont
#print(MDApp.get_running_app().pb)
n_extracted_frames+=1
success,frame = vidcap.read()
cont+=1
end_time =time.time() - start_time
MDApp.get_running_app().extracted_total = str(n_extracted_frames)
MDApp.get_running_app().time_taken = str(datetime.timedelta(seconds=end_time))
MDApp.get_running_app().saved_path = str(b)
self.manager.transition.direction = 'right'
self.manager.current = 'completed'
class GetframesApp(MDApp):
app_filepath = StringProperty('Not Set')
#totalf = StringProperty('-')
iiii = StringProperty('-')
extracted_total = StringProperty('-')
time_taken = StringProperty('-')
saved_path = StringProperty('-')
file_name = StringProperty('-')
fps = StringProperty('-')
video_duration = StringProperty('-')
pb = NumericProperty(0)
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Purple"
sm = ScreenManager()
sm.add_widget(SelectFileScreen(name='menu'))
sm.add_widget(GetFramesScreen(name='settings'))
sm.add_widget(Extracting(name = 'extracting'))
sm.add_widget(Completed(name = 'completed'))
return sm
GetframesApp().run()
kv file:
<SelectFileScreen>:
MDFillRoundFlatButton:
text: 'Select file'
md_bg_color: 1, 0, 1, 1
on_press: root.get_image_one()
pos_hint: {'center_x':0.5, 'center_y':0.5}
<GetFramesScreen>:
MDFloatLayout:
size: (500,200)
MDIconButton:
icon: "arrow-left-bold"
pos_hint: {'x':0, 'y':.79}
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'menu'
BoxLayout:
orientation: 'vertical'
padding: [25, 40, 0, 0]
MDStackLayout:
adaptive_height: True
orientation: 'rl-tb'
MDRaisedButton:
text: 'Get frames'
md_bg_color: 1, 0, 1, 1
on_press: root.get_frames()
<Extracting>:
MDFloatLayout:
size: (500,200)
MDLabel:
text: 'Extracting: '+app.file_name
halign: 'center'
pos: (0,60)
BoxLayout:
orientation: 'horizontal'
pos: (0, 10)
MDLabel:
text: 'FPS: '+app.fps
halign: 'center'
MDLabel:
text: 'Video duration: '+app.video_duration
halign: 'center'
MDProgressBar:
value: app.pb
max: 100
pos: (0, -40)
<Completed>:
MDFloatLayout:
size: (500,200)
MDLabel:
text: 'Completed frame extraction!'
halign: 'center'
pos: (0,70)
MDLabel:
text: app.extracted_total+' frames extracted.'
halign: 'center'
pos: (0,40)
MDLabel:
text: 'in '+app.time_taken+' hrs'
halign: 'center'
pos: (0,20)
MDLabel:
text: 'saved at '+app.saved_path
halign: 'center'
pos: (0,0)
MDFillRoundFlatButton:
text: 'Select new file'
halign: 'center'
pos_hint: {'center_x': 0.5, 'center_y': 0.3}
md_bg_color: 1, 0, 1, 1
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'menu'
You are running your frame extraction code on the main thread, and kivy updates the GUI on the main thread. But as long as you are holding the main thread with a long running method, kivy never gets an opportunity to update the GUI until that method completes and surrenders the main thread.
The fix is to run the frame extraction on a new thread. Here is a modified version of your GetFramesScreen that does that:
class GetFramesScreen(MDScreen):
base_dir_for_frames = StringProperty(f"{os.path.join(os.path.expanduser('~'), 'Desktop')}")
def get_frames(self): # this is run on the main thread
self.manager.transition.direction = 'right'
self.manager.current = 'extracting'
threading.Thread(target=self.get_frames_thread, daemon=True).start()
def get_frames_thread(self): # this is run on a new thread
start_time = time.time()
MDApp.get_running_app().file_name = str(os.path.basename(MDApp.get_running_app().app_filepath))
saved_frame_dir = os.path.join(self.base_dir_for_frames,
os.path.basename(MDApp.get_running_app().app_filepath)).replace('.',
'_').replace(
'\01', '01')
b = direxist(saved_frame_dir)
print(f'pathe to save ->{b}')
vidcap = cv2.VideoCapture(MDApp.get_running_app().app_filepath)
fps = vidcap.get(cv2.CAP_PROP_FPS)
MDApp.get_running_app().fps = str(int(fps))
frame_count = vidcap.get(cv2.CAP_PROP_FRAME_COUNT)
capduration = int(frame_count / fps)
video_time = str(datetime.timedelta(seconds=capduration))
MDApp.get_running_app().video_duration = str(video_time)
success, frame = vidcap.read()
cont = 1
n_extracted_frames = 0
while success:
if cont == 1 or cont % int(fps) == 0:
seconds1 = (vidcap.get(cv2.CAP_PROP_POS_MSEC)) / (1000)
video_time2 = str(datetime.timedelta(seconds=seconds1))
x = video_time2.replace(':', '.')
formatted = f"frame{cont}_{x}.jpg"
dd = os.path.join(str(b), formatted)
cv2.imwrite(dd, frame)
# MDApp.get_running_app().pb = cont
# print(MDApp.get_running_app().pb)
n_extracted_frames += 1
success, frame = vidcap.read()
cont += 1
end_time = time.time() - start_time
MDApp.get_running_app().extracted_total = str(n_extracted_frames)
MDApp.get_running_app().time_taken = str(datetime.timedelta(seconds=end_time))
MDApp.get_running_app().saved_path = str(b)
Clock.schedule_once(self.go_to_completed) # run the switch to the completed Screen back on the main thread
def go_to_completed(self, dt): # this is run on the main thread
self.manager.transition.direction = 'right'
self.manager.current = 'completed'
for example, with this code i print with a while true loop the text that is in the inputs, after that is running i want to do it the same but with different text but when i trigger the task it starts printing the new text and the first one no. i tried already with threading and multithreading library but the result is the same
.kv file
screen_helper = '''
ScreenManager:
Loginscreen:
<Loginscreen>:
name: 'login'
MDTextField:
id: emaillogin
hint_text: "E-mail"
pos_hint: {"center_x": 0.5, "center_y": 0.70}
size_hint_x: None
width: 300
MDTextField:
id: passwordlogin
hint_text: "Password"
pos_hint: {"center_x": 0.5, "center_y": 0.60}
size_hint_x: None
width: 300
MDLabel:
text: "Welcome to Profit Alert"
pos_hint: {"center_x": 0.7, "center_y": 0.80}
size_hint_x: None
width: 500
MDRaisedButton:
text: "Sign up"
pos_hint: {"center_x": 0.5, "center_y": 0.45}
on_press: root.calling()
MDTextButton:
text: "Don't have an account?, create a new one"
pos_hint: {"center_x": .5, "center_y": .25}
on_press: root.manager.current = 'request'
MDTextButton:
text: "Forgot password?"
pos_hint: {"center_x": .5, "center_y": 0.35}
on_press: root.call()
.py file
class Loginscreen(Screen):
def __init__(self, **kw):
super().__init__(**kw)
def calling(self, *args):
executor = ThreadPoolExecutor(max_workers=5)
executor.submit(self.func)
def imprimir(self, *args):
self.palabra1 = self.ids.emaillogin.text
self.palabra2 = self.ids.passwordlogin.text
def func(self, *args):
Clock.schedule_once(self.imprimir, 0)
while True:
time.sleep(1)
print(self.palabra1, self.palabra2)
def call(self, *args):
Clock.schedule_interval(self.imprimir, 1 / 1)
pass
class work(MDApp):
def build(self):
self.theme_cls.primary_palette = "Yellow"
screen = Builder.load_string(screen_helper)
return screen
work().run()
i tried with threading and multiprocessing pool
Let me put it this way a kivy gui it self is a loop u cant put an infinite loop inside the gui cause you will push it to a bug. the only way is use a thread. follow this example and u ll find ur problem.
Lets say we have a main.py file like this:
import threading
import # what u need
Builder.load_file('the.kv')
some_cond = False # Note that this function is gonna be
string = '' # running on thread and threads can't
some_function(): # be started twice or stopped
global string, some_cond # and restarted
while True: # the while True is meant to keep
if some_cond == True: # the thread alive
print(string) #
some_thread = threading.Thread(target = some_function)
class fscreen(Widget):
def __init__(self, **kwargs):
global string, some_cond ## dont forget this
super().__init__(**kwargs)
Clock.schedule_interval(update_string, 1) # 1 time per sec
# this Clock is meant to update the string the outer thread
def update_string(self, *args):
global string
string = self.ids.my_text_input.text
#### assuming that some_cond = True the thread is gonna
### print(string) endlessly for that u may consider managing
## some_cond True or False with a Button or something
# depends on when and what u want to print
class secscreen(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
pass
class thscreen(Widget):
def __init__(self,**kwargs):
super().__init__(**kwargs)
pass
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()
some_thread.start() # this way both the gui and
threading.Thread(target = theapp.run()) # and the function are threading
Now in ur the.kv file i have something like this:
<fscreen>
TextInput:
id: my_text_input
size: ## whatever u want
pos: ## whatever u want
I wrote a simple code to create a timer, and for this I added two buttons: Start and Stop. The idea is that when one of the buttons is enabled the other isn't, and viceversa.
The code below works, but I want to get the same behaviour using the kv file.
def update_time(self, instance):
timer = Clock.schedule_interval(self.timer, 1.0 / 1.0)
instance.disabled = True
self.stop_button.disabled = False
def stop_updating(self, instance):
Clock.unschedule(self.timer)
instance.disabled = True
self.timer_button.disabled = False
If I try to use the code snippet below, the script throws an error because it is lacking one argument (instance).
Button:
text: 'Start'
on_press: root.update_time()
I know the "disabled" property in kv file exists, but I don't know how (or whether) to use it to modify the two buttons I want to be modified, onclick.
Any idea how to go about it?
All script code
class LandingScreen(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def go_to_timer(self):
clock_app.screen_manager.current = 'Timer'
class TimerScreen(GridLayout):
current_time = StringProperty()
timer_start = ObjectProperty(Button)
timer_stop = ObjectProperty(Button)
tot_sec = 0
def __init__(self, **kwargs): # Widgets without .kv file
super().__init__(**kwargs)
self.rows = 4
self.current_time = '00:00'
def update_time(self, instance):
timer = Clock.schedule_interval(self.timer, 1.0 / 1.0)
instance.disabled = True
# self.stop_button.disabled = False
self.timer_stop.disabled = False
def stop_updating(self, instance):
Clock.unschedule(self.timer)
instance.disabled = True
# self.timer_button.disabled = False
self.timer_start.disabled = False
def timer(self, instance):
# Code
class ClockApp(App):
def build(self):
self.screen_manager = ScreenManager()
# Landing screen
self.landing_screen = LandingScreen()
screen = Screen(name='Landing')
screen.add_widget(self.landing_screen)
self.screen_manager.add_widget(screen)
# Timer screen
self.timer_screen = TimerScreen()
screen = Screen(name='Timer')
screen.add_widget(self.timer_screen)
self.screen_manager.add_widget(screen)
return self.screen_manager
def go_to_landing(self):
clock_app.screen_manager.current = 'Landing'
if __name__ == '__main__':
clock_app = ClockApp()
clock_app.run()
kv file
<TimerScreen>:
rows: 5
Label:
font_size: 60
text: root.current_time
GridLayout:
cols: 3
Label:
text: ''
Button:
id: 'timer_start'
text: 'Start'
on_press: root.update_time(self)
Label:
text: ''
Label:
text: ''
Button:
id: 'timer_stop'
text: 'Stop'
on_press: root.stop_updating(self)
disabled: True
Label:
text: ''
Label:
text: ''
Label:
text: ''
Label:
text: ''
AnchorLayout:
anchor_x: 'left'
Button:
text: 'Back'
width: root.width / 7
size_hint_x: None
on_press: app.go_to_landing()
<LandingScreen>:
rows: 7
Label:
font_size: 50
text: 'Clock types'
canvas.before:
Color:
rgba: 1, 0, 0, 1
GridLayout:
cols:3
Label:
text: ''
Button:
text: 'Timer'
on_press: root.go_to_timer()
Label:
text: ''
Label:
text: ''
Button:
text: 'Countdown'
on_press: root.go_to_countdown()
Label:
text: ''
Label:
text: ''
Label:
text: ''
I think your code is mostly working. Just a few notes on the use of the ids:
You should not use a string literal as an id. Instead of id: 'timer_start', use id: timer_start. If you use a string literal, you will encounter problems if you try to reference it elsewhere in the kv (it will be interpreted as a string, not an id).
When declaring an ObjectProperty in a class that will be defined by an id in the kv, use ObjectProperty(None) in the declaration in the class.
Use declarations in the kv to match up with the declarations in the class.
Applying the above to your python code:
class TimerScreen(GridLayout):
current_time = StringProperty()
timer_start = ObjectProperty(None)
timer_stop = ObjectProperty(None)
tot_sec = 0
and in the corresponding kv:
<TimerScreen>:
timer_start: timer_start
timer_stop: timer_stop
rows: 5
and the ids should be changed to:
Button:
id: timer_start
text: 'Start'
on_press: root.update_time(self)
and:
Button:
id: timer_stop
text: 'Stop'
on_press: root.stop_updating(self)
disabled: True
The typical declaration of an ObjectProperty in kv like:
timer_start: timer_start
can be confusing, but that is how it is usually done. I prefer to use a different name for the ObjectProperty, to make it clearer. The first name in the above is the name of the ObjectProperty, and the second is the id. They just happen to have the same name.
ScrollView:
id: historyscroll
size_hint: 1, 0.925
pos_hint: {"x": 0, "top": 1}
Label:
id: historybox
text: "start"
size_hint: 1, None
size_hint_y: None
height: self.texture_size[1]
Issue:
Text is not displayed. Adding new text to the label causes the word pause to get displayed with different font sizes.
Issue2:
TextInput:
text: "localhost:"
size_hint: 1, 0.06
pos_hint: {"x": 0, "y": 0}
id: cmdbox
multiline: False
text_validate_unfocus:False
font_size: "20sp"
Upon typing something in the text box, sometimes some wierd image gets displayed. Also text_validate_unfocus: False does not prevent text box from unfocusing when enter key is pressed
Edit:
Whole code:
main.py:
#-*-coding:utf8;-*-
#qpy:3
#qpy:kivy
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
from kivy.clock import Clock
from kivy.core.window import Window
from game import Game
class Sm(ScreenManager):
pass
class GameScreen(Screen):
def __init__(self, **kwargs):
super(GameScreen, self).__init__(**kwargs)
self.game = Game()
self.add_widget(self.game)
self.ids.cmdbox.bind(on_text_validate=self.cmdreturn)
self.ids.cmdbox.bind(focus=self.cmdfocus)
self.ids.historybox.text=" "*(Window.width*75/1048)
#Clock.schedule_interval(self.render, 0.5)
def cmdreturn(self, args):
self.cmd = self.ids.cmdbox.text
#self.ids.historybox.insert_text("\n"+self.cmd)
self.ids.historybox.text += "\n" + self.cmd
self.cmdexecute(self.cmd.split(str(self.game.current_)+":")[1])
self.ids.cmdbox.text = str(self.game.current_) + ":"
def cmdexecute(self, cmd):
print(cmd)
if cmd == "fill":
self.ids.historybox.text+="\nfill"*30
if cmd == "clear":
self.ids.historybox.text= " "*(Window.width*75/1048)
if cmd == "ls":
self.ids.historybox.text= "\n"+str(self.game.current.folders.keys())
def cmdfocus(self, instance, value):
if value:
self.ids.cmdbox.pos_hint={"x":0, "y":0.45}
self.ids.historyscroll.size_hint=(1, 0.475)
else:
self.ids.cmdbox.pos_hint={"x":0, "y":0}
self.ids.historyscroll.size_hint=(1, 0.925)
class MenuScreen(Screen):
pass
class PauseScreen(Screen):
pass
class OptionsScreen(Screen):
pass
class GameApp(App):
def build(self):
sm = Sm()
sm.add_widget(MenuScreen(name="menu"))
sm.add_widget(GameScreen(name="game"))
sm.add_widget(PauseScreen(name="pause"))
sm.add_widget(OptionsScreen(name="options"))
sm.transition = NoTransition()
return sm
GameApp().run()
game.kv:
#kivy 1.10.0
<GameScreen>:
id:gscreen
FloatLayout:
Button:
text:"pause"
size_hint:(0.15, 0.05)
pos_hint:{"right":0.98, "top":0.98}
on_press:root.manager.current="pause"
ScrollView:
id: historyscroll
size_hint: 1, 0.925
pos_hint: {"x": 0, "top": 1}
Label:
id: historybox
#readonly: True
text: "start"
size_hint: 1, None
size_hint_y: None
height: self.texture_size[1]
#height: max(self.minimum_height, historyscroll.height)
#multiline: True
#foreground_color: (1,1,1,1)
#background_color: (255,255,255,0)
#font_size: "17sp"
#halign: "left"
#text_size:(self.width, "None")
TextInput:
text: "localhost:"
size_hint: 1, 0.06
pos_hint: {"x": 0, "y": 0}
id: cmdbox
multiline: False
text_validate_unfocus:False
font_size: "20sp"
<MenuScreen>:
FloatLayout:
Button:
text:"start"
size_hint:(0.3, 0.1)
pos_hint:{"center_x":0.5, "center_y":0.61}
on_press:root.manager.current="game"
Button:
text:"options"
size_hint:(0.3, 0.1)
pos_hint:{"center_x":0.5, "center_y":0.5}
on_press:root.manager.current="options"
Button:
text:"exit"
size_hint:(0.3, 0.1)
pos_hint:{"center_x":0.5, "center_y":0.39}
on_press:quit
<OptionsScreen>:
FloatLayout:
Button:
text:"back"
size_hint:(0.3, 0.1)
pos_hint:{"center_x":0.5, "center_y":0.5}
on_press:root.manager.current="menu"
<PauseScreen>:
FloatLayout:
Button:
text:"back"
size_hint:(0.3, 0.1)
pos_hint:{"center_x":0.5, "center_y":0.495}
on_press:root.manager.current="game"
Button:
text:"exit"
size_hint:(0.3, 0.1)
pos_hint:{"center_x":0.5, "center_y":0.605}
on_press:root.manager.current="menu"
game.py:
from kivy.uix.widget import Widget
from random import randint
class Game(Widget):
def __init__(self, **kwargs):
super(Game, self).__init__(**kwargs)
self.localhost = "5255.7611"
self.internet = Internet(self.localhost)
self.current_ = "localhost"
self.current = self.internet.links[self.localhost.split(".")[0]].links[self.localhost.split(".")[1]]
class Internet:
def __init__(self, localhost):
self.links = {}
self.links[str(localhost)[:4]] = Router(str(localhost)[:4], self)
self.links[str(localhost)[:4]].islocal(localhost)
def Crouter(self):
tmp = str(randint(1000, 9999))
if not str(tmp) in self.links:
self.links[str(tmp)] = Router(tmp, self)
else: self.Crouter
class Computer:
def __init__(self, ip, router):
self.ip = ip
self.router = router
self.islocal = False
self.folders = {"programs":Folder("programs",[], {}),
"downloads":Folder("downloads",[], {})}
class Folder:
def __init__(self, name, content, data):
self.content = content
self.data = data
class File:
def __init__(self, content, data):
self.content = content
self.data = data
class Router:
def __init__(self, ip, internet):
self.ip = ip
self.internet = internet
self.links = {}
def Ccomputer(self):
tmp = str(randint(1000, 9999))
if not str(tmp) in self.links:
self.links[str(tmp)] = Computer(str(tmp)+self.ip, self)
else: self.Ccomputer
def islocal(self, localhost):
self.links[str(localhost)[5:]] = Computer(str(localhost), self)
self.links[str(localhost)[5:]].islocal = True
(Btw, I am using qpython-kivy)
Issue in brief:
The text input(id:cmdbox) on editing sometimes displays wierd images in place of text.
Also, the label(id:historybox) does not display the correct text(it only displays "pause" in different font size each time)
Edit2:
Finally got some images.
https://www.dropbox.com/sh/i6t192ujys2hivz/AACPR5Sgb72Mv8M7gB3DiGmNa?dl=0
For the first issue, in the __init__ of your screen you are replacing the text of your label
For the second, I don't know if that property exists in kivy If you want to keep the focus in your TextInput Try this:
...
class GameScreen(Screen):
def __init__(self, **kwargs):
super(GameScreen, self).__init__(**kwargs)
self.game = Game()
self.add_widget(self.game)
self.ids.cmdbox.bind(on_text_validate=self.cmdreturn)
self.ids.cmdbox.bind(focus=self.cmdfocus)
#self.ids.historybox.text=" "*(Window.width*75/1048)
#Clock.schedule_interval(self.render, 0.5)
def cmdreturn(self, args):
self.cmd = self.ids.cmdbox.text
#self.ids.historybox.insert_text("\n"+self.cmd)
self.ids.historybox.text += "\n" + self.cmd
self.cmdexecute(self.cmd.split(str(self.game.current_)+":")[1])
self.ids.cmdbox.text = str(self.game.current_) + ":"
Clock.schedule_once(self.refocus)
def refocus(self, *args):
self.ids.cmdbox.focus = True
...
And I can't say anything about the weird images because I don't get them