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'
Related
I am building an OCR application for visually impaired users. I'm wanting the app to open straight away onto the camera screen, when the user takes a pic on button press I want ocr process to occur and display the output on the text screen in a lbl or txtbox and have a TTS read out what the text says. My issue is that i am having trouble obtaining the output of ocr and displaying it, I'm not familiar with screenmanager or python. ideally the opencv and tesseract process would occur in same function as the capture however i cant get the output recognised on the following screen. heres some code, any suggestions and help appreciated!
# Importing the libraries
import cv2
import pytesseract
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
pytesseract.pytesseract.tesseract_cmd = r'D:/pytesseract/tesseract.exe'
# voice_text = ""
# for i in ocrtext.split():
# voice_text += i + ' '
# voice_text = voice_text[:-1]
# voice_text
# engine = pyttsx3.init()
# engine.setProperty("rate", 145)
# voices = engine.getProperty('voices')
# engine.setProperty('voice', voices[0].id)
# engine.say(voice_text)
# engine.runAndWait()
class CameraScreen(Screen):
def capture(self):
camera = self.ids['camera']
camera.export_to_png("./picforocr.png")
image = cv2.imread("./picforocr.png")
ocrtext = pytesseract.image_to_string(image)
class TextScreen(Screen):
pass
GUI = Builder.load_string("""
GridLayout:
cols: 1
ScreenManager:
id: screen_manager
CameraScreen:
name: "camera_screen"
id: camera_screen
TextScreen:
name: "text_screen"
id: text_screen
<CameraScreen>:
orientation: 'vertical'
GridLayout:
cols: 1
Camera:
id: camera
resolution: (800, 800)
Button:
text: 'OCR!'
size_hint_y: None
height: '48dp'
on_press:
root.capture()
# root refers to <CameraScreen>
# app refers to TestCamera, app.root refers to the GridLayout: at the top
app.root.ids['screen_manager'].transition.direction = 'left'
app.root.ids['screen_manager'].current = 'text_screen'
<TextScreen>:
Label:
id: ocr_output
text:
Camerascreen.ocrtext
font_size: 20
Button:
text: "Do OCR Again"
size_hint_y: None
height: '48dp'
font_size: 50
on_press:
app.root.ids['screen_manager'].transition.direction = 'right'
app.root.ids['screen_manager'].current = 'camera_screen'
""")
class MyOCRApp(App):
def build(self):
return GUI
if __name__ == "__main__":
MyOCRApp().run()
This is basic code for passing texts from one class to another and also TextInput data. This is python code:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class FirstPage(FloatLayout):
def switch_screen(self):
secondpage = self.login_name = self.ids.login_name.text
myapp.secondpage.update_name1(secondpage)
secondpage = self.password_name = self.ids.password_name.text
myapp.secondpage.update_name2(secondpage)
myapp.screen_manager.transition = SlideTransition(direction='left', duration=.25)
myapp.screen_manager.current = 'SecondPage'
class SecondPage(FloatLayout):
def switch_back(self):
myapp.screen_manager.transition = SlideTransition(direction='right', duration=.25)
myapp.screen_manager.current = 'FirstPage'
def update_name1(self, name_login):
self.ids.name_login.text = (f'{name_login}:')
def update_name2(self, name_password):
self.ids.name_password.text = (f'{name_password}:')
class MyApp(App):
def build(self):
self.screen_manager = ScreenManager()
self.firstpage = FirstPage()
screen = Screen(name='FirstPage')
screen.add_widget(self.firstpage)
self.screen_manager.add_widget(screen)
self.secondpage = SecondPage()
screen = Screen(name='SecondPage')
screen.add_widget(self.secondpage)
self.screen_manager.add_widget(screen)
return self.screen_manager
myapp = MyApp()
myapp.run()
And this is kivy code:
FirstPage:
<FirstPage>:
TextInput:
id: login_name
size_hint: .65, .08
multiline: False
font_size: 20
pos_hint: {'x': .2, 'y': .57}
TextInput:
id: password_name
size_hint: .65, .08
multiline: False
font_size: 20
pos_hint: {'x': .2, 'y': .47}
Button:
text: "First"
size_hint: .1, .1
on_release: root.switch_screen()
<SecondPage>:
Button:
text: "Second"
size_hint: .1, .1
on_release: root.switch_back()
Label:
id: name_login
text: "Login"
size_hint: .2, .2
pos_hint: {'x': .2, 'y': .57}
Label:
id: name_password
text: "Password"
size_hint: .2, .2
pos_hint: {'x': .2, 'y': .47}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am converting my code from kivy to kivymd. But it is not showing anything on screen. I am not able to find the issue... How can I run it..I am using pycharm.
it was working fine in the kivy code...I looked at some examples of kivymd and then converted it.
and If my question is in apropriate please someone edit it
.py code
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.popup import Popup
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.gridlayout import MDGridLayout
from kivymd.uix.button import MDFlatButton
import sys, time, threading
import pyrebase
from kivymd.uix.screen import MDScreen
from kivy.uix.screenmanager import ScreenManager, Screen
from datetime import datetime, timedelta
import pandas_datareader.data as web
from kivymd.theming import ThemeManager
import pandas as pd
from kivymd.icon_definitions import md_icons
from kivy.utils import get_color_from_hex
import webbrowser
from kivymd.uix.screen import Screen
from kivymd.uix.list import MDList, ThreeLineListItem, ThreeLineAvatarIconListItem, OneLineListItem
from kivymd.uix.list import IconLeftWidget, ImageLeftWidget
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button
from kivymd.uix.card import MDCardSwipe
from kivy.properties import ObjectProperty
import csv
from os import path
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import NumericProperty, ListProperty, BooleanProperty, ObjectProperty, StringProperty
from kivy.uix.recycleview import RecycleView
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
import re
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
import pandas as pd
from kivy.clock import Clock
from functools import partial
from kivymd.uix.dialog import MDDialog
from kivymd.uix.textfield import MDTextField, MDTextFieldRound
from kivymd.uix.label import MDLabel
from kivymd.toast import toast
from kivy.core.window import Window
Window.size = (300, 500)
username = ''
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableLabel(RecycleDataViewBehavior, MDLabel):
''' Add selection support to the Label '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
txt_input = ObjectProperty(None)
stock_name = ObjectProperty(None)
stock_symbol = ObjectProperty(None)
purchase_price = ObjectProperty(None)
stop_loss = ObjectProperty(None)
highlight = ListProperty([1, 1, 1, 1])
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableLabel, self).on_touch_down(touch):
return True
if self.collide_point(*touch.pos) and self.selectable:
return self.parent.select_with_touch(self.index, touch)
def apply_selection(self, rv, index, is_selected):
''' Respond to the selection of items in the view. '''
self.selected = is_selected
if is_selected:
# App.get_running_app().root.widget_1.ids.txt_input1.text = str(rv.data[index].get("text"))
xx = str(rv.data[index].get("text"))
if (xx.find('(NSI)') != -1):
x, y = xx.split(" (NSI)")
add_sym = '.NS'
else:
x, y = xx.split(" (BSE)")
add_sym = '.BO'
print(xx)
print(x)
App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_name.text = x
f = pd.read_csv("Stock Tickers.csv", encoding="ISO-8859-1", engine='python')
fl = len(f.index)
file = pd.DataFrame(f, columns=['Symbols', 'Name', 'Exchange'])
for i in range(fl):
for index in range(1):
columnSeriesObj_sym = file.iloc[:, 0]
columnSeriesObj1 = file.iloc[:, 1]
columnSeriesObj_ex = file.iloc[:, 2]
before_sym, b = columnSeriesObj_sym.values[i].split('.')
if columnSeriesObj1.values[i] == App.get_running_app().root.get_screen(
'body_screen').widget_1.ids.stock_name.text:
App.get_running_app().root.get_screen(
'body_screen').widget_1.ids.stock_symbol.text = before_sym + add_sym
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
class DropDownWidget(MDBoxLayout):
txt_input = ObjectProperty(None)
rv = ObjectProperty(None)
stock_name = ObjectProperty(None)
stock_symbol = ObjectProperty(None)
purchase_price = ObjectProperty(None)
stop_loss = ObjectProperty(None)
def back(self):
self.clear_texts()
MDApp.get_running_app().root.transition.direction = 'right'
MDApp.get_running_app().root.current = 'option_screen'
def clear_texts(self):
App.get_running_app().root.get_screen('body_screen').widget_1.ids.txt_input.text = ""
App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_name.text = ""
App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_symbol.text = ""
App.get_running_app().root.get_screen('body_screen').widget_1.ids.purchase_price.text = ""
App.get_running_app().root.get_screen('body_screen').widget_1.ids.stop_loss.text = ""
def btn_input(self):
if App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_name.text == '':
toast('Please Select Stock')
elif App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_symbol.text == '':
toast('Please Select Stock')
elif App.get_running_app().root.get_screen('body_screen').widget_1.ids.purchase_price.text == '':
toast('Please Enter Purchase Price')
elif App.get_running_app().root.get_screen('body_screen').widget_1.ids.stop_loss.text == '':
toast('Please Enter Stoploss')
elif float(App.get_running_app().root.get_screen('body_screen').widget_1.ids.stop_loss.text) <= 100:
print("Stock Name:", App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_name.text,
"Stock Symbol:", App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_symbol.text)
print("Purchase Price:",
App.get_running_app().root.get_screen('body_screen').widget_1.ids.purchase_price.text,
"Stop Loss(%):", App.get_running_app().root.get_screen('body_screen').widget_1.ids.stop_loss.text)
# write data to csv file
file_name ="stoploss.csv"
if path.exists(file_name):
with open(file_name, "a+", newline='')as newFile:
fieldnames = ["Stock Name", "Stock Symbol", "Purchase Price", "Stop Loss(%)"]
newFileWriter = csv.DictWriter(newFile, fieldnames=fieldnames)
newFileWriter.writerow({"Stock Name": App.get_running_app().root.get_screen(
'body_screen').widget_1.ids.stock_name.text,
"Stock Symbol": App.get_running_app().root.get_screen(
'body_screen').widget_1.ids.stock_symbol.text,
"Purchase Price": App.get_running_app().root.get_screen(
'body_screen').widget_1.ids.purchase_price.text,
"Stop Loss(%)": App.get_running_app().root.get_screen(
'body_screen').widget_1.ids.stop_loss.text})
else:
myFile = open(file_name, 'w+', newline='')
myData = [["Stock Name", "Stock Symbol", "Purchase Price", "Stop Loss(%)"],
[App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_name.text,
App.get_running_app().root.get_screen('body_screen').widget_1.ids.stock_symbol.text,
App.get_running_app().root.get_screen('body_screen').widget_1.ids.purchase_price.text,
App.get_running_app().root.get_screen('body_screen').widget_1.ids.stop_loss.text]]
with myFile:
writer = csv.writer(myFile)
writer.writerows(myData)
self.clear_texts()
else:
App.get_running_app().root.get_screen('body_screen').widget_1.ids.stop_loss.text = ''
toast(text='The Stoloss should be less then 100%')
class MyTextInput(MDTextFieldRound):
txt_input = ObjectProperty(None)
flt_list = ObjectProperty()
word_list = ListProperty()
stock_name = ObjectProperty(None)
stock_symbol = ObjectProperty(None)
purchase_price = ObjectProperty(None)
stop_loss = ObjectProperty(None)
# this is the variable storing the number to which the look-up will start
starting_no = NumericProperty()
suggestion_text = ''
def __init__(self, **kwargs):
super(MyTextInput, self).__init__(**kwargs)
def on_text(self, instance, value):
# find all the occurrence of the word
self.parent.parent.parent.ids.rv.data = []
if len(value) != 0:
matches = [word for word in self.word_list if word.lower().find(value.lower()) != -1]
# display the data in the recycleview
display_data = []
for i in matches:
display_data.append({'text': i})
self.parent.parent.parent.ids.rv.data = display_data
# ensure the size is okay
if len(matches) <= 10:
self.parent.height = (50 + (len(matches) * 20))
else:
self.parent.height = 250
def keyboard_on_key_down(self, window, keycode, text, modifiers):
if self.suggestion_text and keycode[1] == 'tab':
self.ids.rv.refresh_from_data()
self.insert_text(self.suggestion_text + ' ')
return True
return super(MyTextInput, self).keyboard_on_key_down(window, keycode, text, modifiers)
class Body1(MDScreen):
def build(self):
f = pd.read_csv("Stock Tickers.csv", encoding="ISO-8859-1", engine='python')
fl = len(f.index)
file = pd.DataFrame(f, columns=['Symbols', 'Name', 'Exchange'])
wl = []
for i in range(fl):
for index in range(1):
columnSeriesObj = file.iloc[:, 1]
self.columnSeriesObj_ex = file.iloc[:, 2]
wl.append(columnSeriesObj.values[i] + " (" + self.columnSeriesObj_ex.values[i] + ")")
tp = tuple(wl)
self.widget_1 = DropDownWidget()
self.widget_1.ids.txt_input.word_list = wl
self.widget_1.ids.txt_input.starting_no = 3
self.add_widget(self.widget_1)
sm = ScreenManager()
sm.add_widget(Body1(name='body_screen1'))
class stockinput1App(MDApp):
def build(self):
kv = Builder.load_file("ss.kv")
return kv
if __name__ == "__main__":
stockinput1App().run()
.kv code
ScreenManager:
Body1:
<Body1>:
on_enter:root.build()
name: 'body_screen1'
canvas.before:
Color:
rgba: 155/255, 159/255, 250/255, 1
Rectangle:
pos: self.pos
size: self.size
<DropDownWidget>:
canvas.before:
Color:
rgba: 155/255, 159/255, 250/255, 1
Rectangle:
pos: self.pos
size: self.size
cols:1
id: DropDownWidget
stock_name: stock_name
stock_symbol: stock_symbol
purchase_price: purchase_price
stop_loss: stop_loss
txt_input: txt_input
rv: rv
orientation:'vertical'
spacing: '20dp'
MDToolbar:
title:'Add Stock'
type: "top"
size_hint_y:0.1
pos_hint: {'top':1.0}
left_action_items: [["arrow-left", lambda x: root.back()]]
md_bg_color:152/255,87/255,189/255,1
elevation:10
MDBoxLayout:
spacing:'5dp'
orientation:'vertical'
MDCard:
md_bg_color:155/255, 159/255, 250/255, 1
pos_hint: {'center_x': .5, 'center_y': .5}
elevation:0
orientation:'vertical'
spacing:'10dp'
MyTextInput:
id: txt_input
hint_text: "Search"
icon_right: "magnify"
icon_right_color:1,1,1,1
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint:.9,.2
line_color_normal:184/255,187/255,252/255,1
normal_color:1,1,1,0
RV:
id: rv
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint:1,0.6
MDCard:
md_bg_color:155/255, 159/255, 250/255, 1
orientation:'horizontal'
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint:.9,.4
elevation:0
MDTextField:
id: stock_name
hint_text: "Stock Name"
readonly: True
multiline:True
mode:'rectangle'
required: True
outline_color:184/255,187/255,252/255,1
size:.5,.3
MDCard:
orientation:'horizontal'
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint:.9,.4
elevation:0
md_bg_color:155/255, 159/255, 250/255, 1
MDTextField:
id: stock_symbol
hint_text: "Stock Symbol"
readonly: True
multiline:False
mode:'rectangle'
required: True
pos_hint: {'center_x': .5, 'center_y': .5}
line_color_normal:184/255,187/255,252/255,1
MDCard:
orientation:'horizontal'
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint:.9,.4
elevation:0
md_bg_color:155/255, 159/255, 250/255, 1
MDTextField:
id: purchase_price
hint_text: "Purchase Price"
input_filter: 'float'
multiline:False
mode:'rectangle'
required: True
line_color_normal:184/255,187/255,252/255,1
size:.5,.3
MDCard:
orientation:'horizontal'
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint:.9,.4
elevation:0
md_bg_color:155/255, 159/255, 250/255, 1
MDTextField:
id: stop_loss
hint_text: "Stop Loss(%)"
input_filter: 'float'
max_text_length: 3
multiline:False
mode:'rectangle'
required: True
size:.5,.3
color_mode: 'custom'
line_color_normal:1,1,1,1
MDCard:
pos_hint: {'center_x': .5, 'center_y': .5}
size_hint:.5,.5
elevation:0
md_bg_color:155/255, 159/255, 250/255, 1
MDRaisedButton:
text:"Submit"
pos_hint: {'center_x': .5, 'center_y': .6}
size_hint:.5,.7
md_bg_color:40/255, 44/255, 177/255, 1
elevation:15
on_press: root.btn_input()
<MyTextInput>:
id: MyTextInput
mode:'rectangle'
readonly: False
multiline: False
<SelectableLabel>:
id: SelectableLabel
multiline: True
# Draw a background to indicate selection
canvas:
Color:
rgba: (218/255,112/255,214/255,.6) if self.selected else (1, 1, 1, 0.5)
Rectangle:
pos: self.pos if self.selected else (0,0)
size: self.size if self.selected else (0,0)
halign:'center'
<RV>:
canvas:
Color:
rgba: 1,1,1,1
Line:
width: 1.1
rectangle: self.x , self.y, self.width, self.height
height: 10
bar_width: 20
scroll_type:['bars']
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
cols:1
row_default_height: 30
row_force_default:True
default_size: self.size, dp(20)
default_size_hint: 1, None
size_hint_y: None
height: 300
multiselect: False
I am sharing the link to csv ,py,kv files ... here
A bug in Kivy results in the on_enter event not being dispatched for the initial Screen in a ScreenManager, so your build() method is never called. A work around is to call it yourself:
class stockinput1App(MDApp):
def build(self):
kv = Builder.load_file("ss.kv")
kv.get_screen('body_screen1').build()
return kv
Another note: Not technically an error, but the lines:
sm = ScreenManager()
sm.add_widget(Body1(name='body_screen1'))
are creating a a second instance of ScreenManager and two instances of Body1. All of which are then ignored. These lines can be removed. The entire GUI is actually built by the call to Builder.load_file().
Textfile should look like this :
e.g
Walking 61.0/2018-09-04 79.0/2018-10-04
Running 24.0/2018-09-04 33.0/2018-10-04
The point of this function is to append the textfile with the new value of the slider or to change one.
There are some names for the slider and each of them can have many values which consist of a slider.value and the current date. If today is not the date of the last value - then we append the file.
If today is the same date as the date of the last value - then it is supposed to change it(I did not do it yet, but this is not a problem, i will do it myself after I solve this problem).
Here is the full Python file and Kivy files, nothing but def save_values matters. Everything else is just to make the program working for you.
Python
from kivy.app import App
import time
import datetime
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.uix.slider import Slider
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.config import Config
screen_width = 450
screen_height = 800
Config.set("graphics", "resizable","1")
Config.set("graphics", "width", screen_width)
Config.set("graphics", "height", screen_height)
languages = ["Reading","Writing","Running","Climbing"]
spawned_List = ["False"]
class MenuScreen(Screen):
pass
class JobChoiceScreen(Screen):
def changing_screen(self, instance, *args):
self.manager.current= "sliderScreen"
screenSlider = self.manager.get_screen('sliderScreen')
text = str(instance.text)
screenSlider.changing_label(text)
def on_pre_enter(self, *args):
if spawned_List[0] == "False":
for x in range(0,len(languages)):
word = languages[x]
word = str(word)
btn = Button(text = word, size_hint=(None, None), size = (140,70),
font_size = 18, bold = True, color = [0,1,1,1], background_color = (.156, .172, .24, 0.7),
on_release = self.changing_screen)
self.ids.container.add_widget(btn)
spawned_List[0] = "True"
self.ids.boxLayBottom.add_widget(Widget(size_hint=(1, .4)))
self.ids.datesContainer.add_widget(Button(text = "Day back", size_hint=(.28, 1), font_size = 18, bold = True, color = [0,1,1,1], background_color = (.176, .192, .44, 0.7)))
self.ids.datesContainer.add_widget(Widget(size_hint=(.44, 1)))
self.ids.datesContainer.add_widget(Button(text = "Day forward", size_hint=(.28, 1), font_size = 18, bold = True, color = [0,1,1,1], background_color = (.176, .192, .44, 0.7)))
class SliderScreen(Screen):
def save_values(self, *args, **kwargs):
date = (datetime.datetime.now().strftime("%y-%m-%d"))
written = (str(self.ids.my_slider.value)+ "/" + date + " ")
print("started save_values")
with open('values.txt', 'r') as fileValues:
lines = fileValues.readlines()
print("opened the file")
with open('values.txt', 'a') as fileValues:
for i, line in enumerate(lines):
if line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = line + ((self.ids.my_label.text) + " " + written)
print(line)
if not line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = (" " + written)
print(line)
print("hello bill")
def changing_label(self, text):
self.ids.my_label.text = text
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("manager.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
Kivy
ScreenManagement:
#transition: FadeTransition()
MenuScreen:
JobChoiceScreen:
SliderScreen:
<MenuScreen>:
canvas:
Rectangle:
source:"background.jpg"
pos: self.pos
size: self.size
name: "menu"
BoxLayout:
padding: [10,10,10,10]
orientation: "vertical"
Widget:
size_hint: [1,0.2]
BoxLayout:
Button:
bold: True
color: [0,1,1,1]
on_release: app.root.current = "list_of_jobs"
text: "Change"
size_hint: [0.28,1]
font_size: 20
background_color: (.156, .172, .24, 0.7)
Widget:
size_hint: [0.44,1]
Button:
bold: True
color: [.5,0, .8, .7]
text: "View \n Progress"
size_hint: [0.28,1]
font_size: 20
halign: "center"
valign: "center"
background_color: (.156, .172, .24, 0.7)
on_release: app.root.current = "sliderScreen"
Widget:
size_hint: [1,0.2]
<JobChoiceScreen>:
canvas:
Rectangle:
source:"background.jpg"
pos: self.pos
size: self.size
name: "list_of_jobs"
BoxLayout:
orientation: "vertical"
padding: [10,10,10,10]
BoxLayout:
orientation: "vertical"
id: boxLayBottom
size_hint: (1,.1)
BoxLayout:
id: datesContainer
orientation: "horizontal"
size_hint: (1,.6)
AnchorLayout:
anchor_x: "center"
acnhor_y: "top"
size_hint: (1,.8)
GridLayout:
id: container
cols: 3
spacing: 5
BoxLayout:
orientation: "vertical"
id: boxContainer
size_hint: (1,.1)
Button:
text: "Back to Menu"
on_release: app.root.current = "menu"
bold: True
color: [0,1,1,1]
background_color: (.176, .192, .44, 0.7)
<SliderScreen>:
canvas:
Rectangle:
source:"background.jpg"
pos: self.pos
size: self.size
name: "sliderScreen"
BoxLayout:
padding: [10,10,10,10]
orientation: "vertical"
id: my_label_container
Slider:
id: my_slider
min: 0
max: 100
value: 0
orientation: "vertical"
size_hint: [1, 0.7]
step: 1
Label:
id: my_label
size_hint: [1, 0.2]
bold: True
font_size: 40
text: ""
Button:
size_hint: [1, 0.1]
bold: True
on_release: app.root.current = "menu"
text : "Back Home"
font_size: 20
halign: "center"
valign: "center"
background_color: (.156, .172, .24, 0.7)
on_press: root.save_values()
def save_values
def save_values(self, *args, **kwargs):
date = (datetime.datetime.now().strftime("%y-%m-%d"))
written = (str(self.ids.my_slider.value)+ "/" + date + " ")
print("started save_values")
with open('values.txt', 'r') as fileValues:
lines = fileValues.readlines()
print("opened the file")
with open('values.txt', 'a') as fileValues:
for i, line in enumerate(lines):
if line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = line + ((self.ids.my_label.text) + " " + written)
print(line)
if not line.startswith(self.ids.my_label.text) and line.find(date) == -1:
line = (" " + written)
print(line)
print("hello bill")
I see two problems with your code:
In your save_values() method, You are opening the values.txt file twice at the same time with the same name, but with different modes. I think you need to unindent the second with open block, remove the second with open statement, and modify the mode in the first with open statement to r+. So your code should look something like:
with open('values.txt', 'r+') as fileValues:
lines = fileValues.readlines()
print("opened the file")
for i, line in enumerate(lines):
You never call any write routine, so nothing gets written. When you want to append line/lines to values.txt, you need to call fileValues.write() or fileValues.writelines().
I have not looked at your code logic, so I will not comment on that.
I am using kivy and python to build an application.
I am trying to build an application in which I can select several images, add them to an array, and then pass this array of images through another method which stitches the images (using the stitcher class). The output image will display on one of the three screens (also I want to remove the middle screen).
So essentially what I would like help with is how to be able to select multiple files with filechooser in kivy and then add these files to array that I can later pass through a different method.
With the help of #ikolim in this post, I have been able to create the application.
main.py
from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.properties import ObjectProperty
from PIL import Image
class RootWidget(TabbedPanel):
manager = ObjectProperty(None)
img = ObjectProperty(None)
img3 = ObjectProperty(None)
img4 = ObjectProperty(None)
lab = ObjectProperty(None)
def on_touch_up(self, touch):
if not self.img3.collide_point(*touch.pos):
return True
else:
self.lab.text = 'Pos: (%d,%d)' % (touch.x, touch.y)
return True
def switch_to(self, header):
# set the Screen manager to load the appropriate screen
# linked to the tab head instead of loading content
self.manager.current = header.screen
# we have to replace the functionality of the original switch_to
self.current_tab.state = "normal"
header.state = 'down'
self._current_tab = header
def select_to(self, *args):
try:
print(args[1][0])
iw = Image.open(args[1][0])
iw.save('./phase.jpg')
gray = iw.convert('1')
gray.save('./gray_im.jpg')
self.img3.source = './gray_im.jpg'
self.img4.source = './gray_im.jpg'
self.img.source = './phase.jpg'
self.img.reload()
self.img3.reload()
self.img4.reload()
except:
pass
def update_touch_label(self, label, touch):
label.text = 'Pos:(%d, %d)' % (touch.x, touch.y)
label.texture_update()
label.pos = touch.pos
label.size = label.texture_size[0] + 20, label.texture_size[1] + 20
class TestApp(App):
title = 'Screen Widget'
def build(self):
return RootWidget()
def on_pause(self):
return True
if __name__ == '__main__':
TestApp().run()
Test.kv
#:kivy 1.10.1
<RootWidget>:
manager: manager
img: img
img3: img3
img4: img4
lab: lab
do_default_tab: False
ScreenManager:
id: manager
Screen:
id: sc1
name:'Load img'
FileChooserIconView:
canvas.before:
Color:
rgb: 0.5, 0.4, 0.5
Rectangle:
pos: self.pos
size: self.size
on_selection:
root.select_to(*args)
Screen:
id: sc2
name: 'Image'
FloatLayout:
Button:
id: lab
pos_hint: {"right": 0.55, 'top': 1}
size_hint: .15,0.1
RelativeLayout:
Image:
id: img
on_touch_down:
str('Relative:{}'.format(args[1].pos))
pos_hint: {"left": 1, 'bottom': 1}
size_hint: 0.5, 1
allow_stretch: True
RelativeLayout:
Image:
id: img3
pos_hint: {"right": 1, 'bottom': 1}
size_hint: 0.5, 1
allow_stretch: True
Screen:
id: sc3
name: 'Image_'
FloatLayout:
Image:
id: img4
keep_data: True
post: self.pos
size: self.size
TabbedPanelHeader:
text: sc1.name
background_color: 1, 0, 0, 1
screen: sc1.name
TabbedPanelHeader:
text: sc2.name
background_color: 1, 1, 0, 1
screen: sc2.name
TabbedPanelHeader:
text: sc3.name
background_color: 1, 0, 1, 1
screen: sc3.name
In your Test.kv file, after FileChooserIconView: add multiselect: True
FileChooserIconView:
multiselect: True
This will allow the selection of multiple files.
If you use FileChooserListView instead of FileChooserIconView, the file chooser window will not discriminate selected/not selected files visually. You can still select multiple files, but you need to remember the selected files. The first click selects and the second click deselects. I hope the developers of this widget will correct this issue soon.
Here is an example that does what I think you want:
import os
import kivy
from kivy import platform
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
import kivy.garden.filebrowser
class FileBrowserApp(App):
def build(self):
self.root = FloatLayout()
button = Button(text='Select Files', pos_hint={'x':0, 'y': 0}, size_hint=(0.2, 0.1))
button.bind(on_press=self.do_select)
self.root.add_widget(button)
return self.root
def do_select(self, *args):
homeDir = None
if platform == 'win':
homeDir = os.environ["HOMEPATH"]
elif platform == 'android':
homeDir = os.path.dirname(os.path.abspath(__file__))
elif platform == 'linux':
homeDir = os.environ["HOME"]
self.fbrowser = kivy.garden.filebrowser.FileBrowser(select_string='Select',
multiselect=True, filters=['*.png'], path=homeDir)
self.root.add_widget(self.fbrowser)
self.fbrowser.bind(
on_success=self._fbrowser_success,
on_canceled=self._fbrowser_canceled,
on_submit=self._fbrowser_success)
def _fbrowser_success(self, fbInstance):
if len(fbInstance.selection) == 0:
return
selected = []
for file in fbInstance.selection:
selected.append(os.path.join(fbInstance.path, file))
print('selected: ' + str(selected))
self.root.remove_widget(self.fbrowser)
self.fbrowser = None
def _fbrowser_canceled(self, instance):
self.root.remove_widget(self.fbrowser)
self.fbrowser = None
if __name__=="__main__":
app = FileBrowserApp()
app.run()
I'm trying to get a handle on Animations. The problem that I'm having is that my Animation plays once but does not repeat.
What I want to do: I want the image to slide up, and then off the screen. Then appear at the bottom of the screen and again slide up and off.
What actually happens: The Image slides "up" the screen, disappears off of the screen and that's it. It doesn't reset back to its original location, and it doesn't repeat.
My question is: How can I reset the position of the image so that it continues in a never-ending cycle (until the "Stop Animation" button is clicked)?
The animated object is the Image that's setup in .kv language it's directly under MyScreen
If you want to see how the animation plays just change the name of the image "binary_rain.png" in kv lang to w/e you have :)
import kivy
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen, FallOutTransition
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.uix.actionbar import ActionBar
from kivy.factory import Factory
from kivy.animation import Animation
class MyScreen(Screen):
def __init__(self, **kwargs):
super(MyScreen, self).__init__(**kwargs)
Clock.schedule_interval(self.example_func, 20.0)
self._test_bool = False
self.water = Animation(pos=(0, 800)) # It's setup in __init__ ; here
self.water &= Animation(size=(800, 800), duration=2, t='in_back') # and then here
def example_func(self, dt):
if self._test_bool == True:
self.ids.text_input_test_id.foreground_color = 255,0,0,1
self.ids.text_input_test_id.text = "The color has been changed"
self._test_bool = False
elif self._test_bool != True:
self.ids.text_input_test_id.foreground_color = 0, 255, 0, 1
self.ids.text_input_test_id.text = "The color has changed"
self._test_bool = True
def test_func(self):
if self._test_bool == True:
self.ids.text_input_2.foreground_color = 255,0,0,1
self.ids.text_input_2.text = "The color has been changed"
self._test_bool = False
elif self._test_bool != True:
self.ids.text_input_2.foreground_color = 0, 255, 0, 1
self.ids.text_input_2.text = "The color has changed"
self._test_bool = True
def test_func_two(self):
if self._test_bool == True:
self.ids.text_input_3.foreground_color = 255,0,0,1
self.ids.text_input_3.text = "The color has been changed"
self._test_bool = False
elif self._test_bool != True:
self.ids.text_input_3.foreground_color = 0, 255, 0, 1
self.ids.text_input_3.text = "The color has changed"
self._test_bool = True
def start_my_animation(self): # this is what starts the animation
self.water.repeat = True
self.water.start(self.ids.animated_bacground)
def stop_my_animation(self): # this is what should end the animation
self.water.stop(self.ids.animated_bacground)
class MyScreenManager(ScreenManager):
pass
root_widget = Builder.load_string('''
#:import FallOutTransition kivy.uix.screenmanager.FallOutTransition
#:import Config kivy.config
#:import Window kivy.core.window
#:import Clock kivy.clock
#:import ActionBar kivy.uix.actionbar
#:import Animation kivy.animation.Animation
MyScreenManager:
transition: FallOutTransition()
MyScreen:
<MyScreen>:
name: 'example_screen'
Image:
id: animated_bacground
size: self.size
pos: self.pos
source: 'binary_rain.png'
TextInput:
id: text_input_test_id
size_hint: .3, .05
pos_hint: {'x': .35, 'y': .85}
text: 'Hello'
font: '12sp'
TextInput:
id: text_input_2
size_hint: .3, .05
pos_hint: {'x': .35, 'y': .70}
text: 'Hello'
font: '12sp'
TextInput:
id: text_input_3
size_hint: .3, .05
pos_hint: {'x': .35, 'y': .65}
text: 'Button 3'
Button:
id: test_button_id
size_hint: .3, .05
pos_hint: {'x': .5, 'y': .5}
text: 'Click me'
on_press: root.test_func()
ActionBar:
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
title: 'Menu'
with_previous: False
ActionOverflow:
ActionButton:
text: 'click me'
on_press: root.test_func_two()
ActionButton:
text: 'Start Animation'
on_press: root.start_my_animation()
ActionButton:
text: 'Stop Animation'
on_press: root.stop_my_animation()
ActionButton:
text: 'Button 2'
ActionButton:
text: 'Button 3'
ActionGroup:
text: 'Group1'
ActionButton:
text: 'Button 5'
ActionButton:
text: 'Btn6'
ActionButton:
text: 'Btn7'
''')
Factory.unregister('ActionPrevious')
class TestApp(App):
def build(self):
self.title = 'Example App'
return root_widget
TestApp().run()
Your animation is setting the size, not the pos...
also you are doing both animations in the same time using &=, you need +=
self.water = Animation(pos=(0, 800))
# notice the changes * pos * and * += *
self.water += Animation(pos=(800, 800), duration=2, t='in_back') # and then here