.kv is loaded multiples times, you might have unwanted behaviors - kivy

I can run my code but I'm having such unwanted behavior enter image description here, I combined my source code with the https://dev.to/ngonidzashe/how-to-create-a-simple-to-do-list-application-with-kivymd-d89 , and I guess I didn't combine it right here are my code:
import mysql.connector
from kivy.lang import Builder
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.picker import MDDatePicker
from datetime import datetime
from kivymd.uix.list import TwoLineAvatarIconListItem, ILeftBodyTouch
from kivymd.uix.selectioncontrol import MDCheckbox
from database import Database
from kivy.core.window import Window
Window.size = (350, 600)
db = Database()
class MainApp(MDApp):
def build(self):
global screen_manager
screen_manager = ScreenManager()
screen_manager.add_widget(Builder.load_file("login.kv"))
screen_manager.add_widget(Builder.load_file("register.kv"))
screen_manager.add_widget(Builder.load_file("main.kv"))
return screen_manager
database = mysql.connector.connect(host='localhost',
database='loginform',
user='root',
password='****')
cursor = database.cursor()
def send_data(self, user, password):
self.cursor.execute(f"insert into example2 values('{user.text}','{password.text}')")
self.database.commit()
def receive_data(self, user, password):
self.cursor.execute("select * from example2")
user_list = []
for i in self.cursor.fetchall():
user_list.append(i[0])
if user.text in user_list and user.text != "":
self.cursor.execute(f"select password from example2 where user='{user.text}'")
for j in self.cursor:
if password.text == j[0]:
open_button = MDFlatButton(text='Open the App', on_release=self.open_app)
close_button = MDFlatButton(text='Close', on_release=self.close_dialg)
self.dialog = MDDialog(text='Welcome to the *****',
buttons=[close_button, open_button])
self.dialog.open()
else:
try_button = MDFlatButton(text='Try Again', on_release=self.close_dialg)
self.dialog = MDDialog(title='Incorrect Password',
text='You entered wrong password please try again',
buttons=[try_button])
self.dialog.open()
else:
open_regist = MDFlatButton(text="Register", on_release=self.open_regist)
close_button = MDFlatButton(text='Close', on_release=self.close_dialg)
self.dialog = MDDialog(title='Incorrect User',
text='There are no such user',
buttons=[close_button, open_regist])
self.dialog.open()
def open_regist(self, *args):
screen_manager.current = "register"
self.dialog.dismiss()
def close_dialg(self, *args):
self.dialog.dismiss()
def open_app(self, *args):
screen_manager.current = "tasks"
self.dialog.dismiss()
task_list_dialog = None # Here
# Add the below functions
def show_task_dialog(self):
if not self.task_list_dialog:
self.task_list_dialog = MDDialog(
title="Create Task",
type="custom",
content_cls=DialogContent(),
)
self.task_list_dialog.open()
def on_start(self):
"""Load the saved tasks and add them to the MDList widget when the application starts"""
try:
completed_tasks, uncomplete_tasks = db.get_tasks()
if uncomplete_tasks != []:
for task in uncomplete_tasks:
add_task = ListItemWithCheckbox(pk=task[0], text=task[1], secondary_text=task[2])
self.root.ids.container.add_widget(add_task)
if completed_tasks != []:
for task in completed_tasks:
add_task = ListItemWithCheckbox(pk=task[0], text='[s]' + task[1] + '[/s]',
secondary_text=task[2])
add_task.ids.check.active = True
self.root.ids.container.add_widget(add_task)
except Exception as e:
print(e)
pass
def close_dialog(self, *args):
self.task_list_dialog.dismiss()
def add_task(self, task, task_date):
"""Add task to the list of tasks"""
# Add task to the db
created_task = db.create_task(task.text, task_date) # Here
# return the created task details and create a list item
self.root.ids['container'].add_widget(
ListItemWithCheckbox(pk=created_task[0], text='[b]' + created_task[1] + '[/b]',
secondary_text=created_task[2])) # Here
task.text = ''
class DialogContent(MDBoxLayout):
"""OPENS A DIALOG BOX THAT GETS THE TASK FROM THE USER"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
# set the date_text label to today's date when user first opens dialog box
self.ids.date_text.text = str(datetime.now().strftime('%A %d %B %Y'))
def show_date_picker(self):
"""Opens the date picker"""
date_dialog = MDDatePicker()
date_dialog.bind(on_save=self.on_save)
date_dialog.open()
def on_save(self, instance, value, date_range):
"""This functions gets the date from the date picker and converts its it a
more friendly form then changes the date label on the dialog to that"""
date = value.strftime('%A %d %B %Y')
self.ids.date_text.text = str(date)
# create the following two classes
class ListItemWithCheckbox(TwoLineAvatarIconListItem):
"""Custom list item"""
def __init__(self, pk=None, **kwargs):
super().__init__(**kwargs)
# state a pk which we shall use link the list items with the database primary keys
self.pk = pk
def mark(self, check, the_list_item):
"""mark the task as complete or incomplete"""
if check.active == True:
# add strikethrough to the text if the checkbox is active
the_list_item.text = '[s]' + the_list_item.text + '[/s]'
db.mark_task_as_complete(the_list_item.pk) # here
else:
the_list_item.text = str(db.mark_task_as_incomplete(the_list_item.pk)) # Here
def delete_item(self, the_list_item):
"""Delete the task"""
self.parent.remove_widget(the_list_item)
db.delete_task(the_list_item.pk) # Here
class LeftCheckbox(ILeftBodyTouch, MDCheckbox):
"""Custom left container"""
if __name__ == '__main__':
app = MainApp()
app.run()
and here is my kv file with this:
MDScreen:
name: "tasks"
MDFloatLayout:
MDLabel:
id: task_label
halign: 'center'
markup: True
text: "[u][size=48][b]TASKS[/b][/size][/u]"
pos_hint: {'y': .45}
ScrollView:
pos_hint: {'center_y': .5, 'center_x': .5}
size_hint: .9, .8
MDList:
id: container
MDFloatingActionButton:
icon: 'plus-thick'
on_release: app.show_task_dialog() #functionality to be added later
elevation_normal: 12
pos_hint: {'x': .8, 'y':.05}
<DialogContent>:
orientation: "vertical"
spacing: "10dp"
size_hint: 1, None
height: "130dp"
GridLayout:
rows: 1
MDTextField:
id: task_text
hint_text: "Add Task..."
pos_hint: {"center_y": .4}
max_text_length: 50
on_text_validate: (app.add_task(task_text, date_text.text), app.close_dialog())
MDIconButton:
icon: 'calendar'
on_release: root.show_date_picker()
padding: '10dp'
MDLabel:
spacing: '10dp'
id: date_text
BoxLayout:
orientation: 'horizontal'
MDRaisedButton:
text: "SAVE"
on_release: (app.add_task(task_text, date_text.text), app.close_dialog())
MDFlatButton:
text: 'CANCEL'
on_release: app.close_dialog()
<ListItemWithCheckbox>:
id: the_list_item
markup: True
LeftCheckbox:
id: check
on_release:
root.mark(check, the_list_item)
IconRightWidget:
icon: 'trash-can-outline'
theme_text_color: "Custom"
text_color: 1, 0, 0, 1
on_release:
root.delete_item(the_list_item)
I would be very thankful if someone can help or give some tips, how to improve. I'm open to have private conversation.

A kv file with the name main.kv will be loaded automatically by Kivy for your application (See documentation). So your code:
screen_manager.add_widget(Builder.load_file("main.kv"))
is loading main.kv a second time. The easiest fix is to just rename the main.kv file.

Related

Python3 KivyMD - MDDialog get ItemConfirm text value

I want to pass to my project_selected function the selected item in my MDDialog after pressing the OK button. But I can't figure out how can I get the value and do this.
I could print the value inside my set_icon funtion in ItemConfirm class, but I don't know whats the better way to pass that value to HomeWindow(Screen) class or if it is possible to call it directly from inside of it once that the ItemConfirm is already called from inside a function that is part of HomeWindow class.
main.py
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.app import MDApp
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.uix.list import OneLineAvatarIconListItem
class ItemConfirm(OneLineAvatarIconListItem):
divider = None
def set_icon(self, instance_check):
print(self.text)
instance_check.active = True
check_list = instance_check.get_widgets(instance_check.group)
for check in check_list:
if check != instance_check:
check.active = False
class HomeWindow(Screen):
dialog = None
def show_confirmation_dialog(self):
projects = [{id: 0, name: "example1"},{id: 1, name: "example2"}]
if not self.dialog:
self.dialog = MDDialog(
title="Projects",
type="confirmation",
auto_dismiss=False,
items=[ItemConfirm(text=f"{project['name']}") for project in projects],
buttons=[
MDFlatButton(text="CANCEL", theme_text_color="Custom"),
MDFlatButton(
text="OK",
theme_text_color="Custom",
on_release=self.project_selected,
),
],
)
self.dialog.open()
def project_selected(self, *args, **kwargs):
self.ids.project_selection.text = self.dialog.text
class WindowManager(ScreenManager):
pass
class RlogTimer(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "BlueGray"
self.root = Builder.load_file("templates/main.kv")
return self.root
if __name__ == "__main__":
RlogTimer().run()
templates/main.kv
#: import NoTransition kivy.uix.screenmanager.NoTransition
WindowManager:
HomeWindow:
<ScreenManager>:
transition: NoTransition()
<ItemConfirm>:
on_release: root.set_icon(check)
CheckboxLeftWidget:
id: check
group: "check"
<HomeWindow>:
name: "home"
MDBoxLayout:
orientation: "vertical"
MDToolbar:
id: title
title: "Redmine logTimer"
right_action_items: [["clock", lambda x: app.callback_2()]]
MDFlatButton:
id: project_selection
text: "Select Project"
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: root.show_confirmation_dialog()
You can achieve that as follows,
First create a prop. say, selected_project in HomeWindow as,
class HomeWindow(Screen):
dialog = None
selected_project = StringProperty()
Now set its value in method set_icon as,
def set_icon(self, instance_check):
...
app = MDApp.get_running_app() # Access the running app instance.
home_screen = app.root.get_screen("home") # Access required screen.
home_screen.selected_project = self.text # Now set value.
...
Now it's time to set this value in method project_selected,
def project_selected(self, *args, **kwargs):
self.ids.project_selection.text = self.selected_project

Retrieve Data from Kivy Recycleview

I am able to make a recycle view layout of TextInput boxes. Now, further, I would like to give text input in these boxes and gather these inputs in the form of list or dict.
I have tried, self.ids.idname.data to append in an empty list but it didn't work.
Following an example showing how to extract TextInput entries under a RecycleView and put that into a list:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty, NumericProperty, ObjectProperty
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.textinput import TextInput
APP_KV = """
#:import ScrollEffect kivy.effects.scroll.ScrollEffect
<DataView>:
orientation: 'vertical'
RecycleView:
id: rv
size_hint_y: 0.9
viewclass: 'RecycleItem'
key_size: 'size'
effect_cls: ScrollEffect
cols: 1
RecycleBoxLayout:
id: rvbox
cols: rv.cols
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
default_size_hint: 1, None
Button:
text: 'Submit'
size_hint_y: 0.1
on_release: root.extract_data()
<RecycleItem>:
on_text: self.parent.parent.data[self.index]['text'] = self.text
"""
class RecycleItem(RecycleDataViewBehavior, TextInput):
index = NumericProperty(0)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(RecycleItem, self).refresh_view_attrs(rv, index, data)
class DataView(BoxLayout):
DataList = ListProperty()
TextInputNum = NumericProperty(10)
def __init__(self, **kwargs):
super().__init__(**kwargs)
data = []
for x in range(self.TextInputNum):
data.append({'text': '', 'height': 50})
self.ids.rv.data = data
def extract_data(self):
self.DataList.clear()
for x in range(self.TextInputNum):
self.DataList.append(self.ids.rv.data[x]['text'])
print(self.DataList)
class MainApp(App):
def build(self):
self.root = Builder.load_string(APP_KV)
return DataView()
if __name__ == '__main__':
MainApp().run()

Close kivy popup from another class

I am writing a simple Vocabulary App and when the user submits an answer, a popup should display if he has answered correct or not. This works so far, but when the popup should be dismissed/closed the app crashes telling that AttributeError: 'MyScreenManager' object has no attribute 'close_pop'
which does makes sense, because the close_pop method is defined in the PopupWindow class (I'd like to separate the different concerns if possible)
I though of two possible solutions, but don't know how to realize them:
1: Call the close_pop method from within the MyScreenManager class, but I don't know how to reference the popup object that should be closed
2: Adjust the kv part:
<PopupWindow>:
pLabel: pLabel
Label:
id: pLabel
size_hint: .6, .2
pos_hint:{'x': .2, 'top': 1}
font_name: 'static/NotoSansSC-Regular.otf'
Button:
text: 'Close'
size_hint: .8, .2
pos_hint:{'x': .1, 'y': .1}
on_release: app.root.close_pop()
to not call the root class (MyScreenManager), but instead do something like app.PopupWindow.close_pop(), but this doesn't work either.
I was able to get it working without screenmanager (and putting all methods into one class 'Mainwindow' which also was the root class then) but for further enhancements I'd like to use screen manager :)
Any other fine solution will also work - thanks a lot!
Here is my Python Code:
import random
import pandas as pd
import unidecode
from kivy.app import App
#from kivy.uix.gridlayout import GridLayout
#from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
#from kivy.uix.actionbar import ActionBar
#from kivy.uix.label import Label
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MainWindow(Screen):
userInput = ObjectProperty(None)
vocab = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainWindow, self).__init__(**kwargs)
self.df = pd.read_excel(r"static/HSK1-Vocabulary-List.xlsx")
self.en = self.df['English']
self.zh = self.df['Chinese']
self.pinyin = self.df['Pinyin']
self.rd = None
def btn_submit(self):
if self.rd is None:
pLabel = "Please start before submitting!"
elif not self.userInput.text:
pLabel = "Please enter something!"
else:
pLabel = self.validate(self.userInput.text)
self.btn_next()
PopupWindow(pLabel).open_popup()
def btn_next(self):
self.userInput.text = ""
self.rd = random.randint(0, self.df.shape[0]-1)
self.vocab.text = "What is '{}' in Chinese?".format(self.en[self.rd])
def validate(self, answer):
def replace_tones(orig_voc):
unaccented_voc = unidecode.unidecode(orig_voc)
return(unaccented_voc)
if answer == self.zh[self.rd]:
#correct+=1
return("Well done, even in chinese characters!")
elif answer == self.pinyin[self.rd]:
#correct+=1
return("Well done, you also got the correct tones!")
elif answer == replace_tones(self.pinyin[self.rd]):
#correct+=1
return("Well done! Keep in mind the tones '{}'".format(self.pinyin[self.rd]))
else:
return("Sorry, that was not correct!\nThe correct vocab is {}".format(self.pinyin[self.rd]))
#cnt+=1
class PopupWindow(FloatLayout):
def __init__(self, userInput):
super().__init__()
self.pLabel.text = userInput
def open_popup(self):
content = PopupWindow(self.pLabel.text)
self.pop = Popup(title="Result", content=content, size_hint=(None, None), size=(400, 400))
self.pop.open()
def close_pop(self):
self.pop.dismiss()
class DashboardWindow(Screen):
pass
class MyScreenManager(ScreenManager):
pass
#def close_pop(self):
# print("This should close the popup...")
KV = Builder.load_file("main.kv")
class VocabularyTrainer(App):
def build(self):
return KV
if __name__ == "__main__":
app = VocabularyTrainer()
app.run()
and here my .kv file:
MyScreenManager:
MainWindow:
DashboardWindow:
<MainWindow>:
name: 'main'
vocab: vocab
userInput: userInput
GridLayout:
size: root.width, root.height
rows: 4
ActionBar:
id: actBar
background_image: ''
background_color: (0.53, 0.808, 0.98, 1)
ActionView:
ActionPrevious:
ActionButton:
text: 'Quiz'
ActionButton:
text: 'Training'
ActionButton:
text: 'Settings'
Label:
id: vocab
text: 'Welcome to the Chinese Learning App!'
TextInput:
id: userInput
hint_text: 'Enter answer'
width: 300
multiline: False
on_text_validate: root.btn_submit()
font_name: 'static/NotoSansSC-Regular.otf'
GridLayout:
cols: 3
Button:
text: 'Submit'
on_press: root.btn_submit()
Button:
text: 'Start/Skip'
on_press: root.btn_next()
Button:
text: 'Dashboard'
on_press: app.root.current = 'dashboard'
<PopupWindow>:
pLabel: pLabel
Label:
id: pLabel
size_hint: .6, .2
pos_hint:{'x': .2, 'top': 1}
font_name: 'static/NotoSansSC-Regular.otf'
Button:
text: 'Close'
size_hint: .8, .2
pos_hint:{'x': .1, 'y': .1}
on_release: app.root.close_pop()
<DashboardWindow>:
name: 'dashboard'
GridLayout:
rows: 2
Label:
text: '<e.g. PieChart Results>'
Button:
text: 'Go back'
on_press: app.root.current = 'main'
The problem is that your PopupWindow is creating two PopupWindows each time you use it. A better approach would be to just create one, like this:
class PopupWindow(FloatLayout):
def __init__(self, userInput):
super().__init__()
self.pLabel.text = userInput
self.pop = Popup(title="Result", content=self, size_hint=(None, None), size=(400, 400))
def open_popup(self):
self.pop.open()
def close_pop(self):
self.pop.dismiss()
Then in your kv you can use:
<PopupWindow>:
pLabel: pLabel
Label:
id: pLabel
size_hint: .6, .2
pos_hint:{'x': .2, 'top': 1}
font_name: 'static/NotoSansSC-Regular.otf'
Button:
text: 'Close'
size_hint: .8, .2
pos_hint:{'x': .1, 'y': .1}
on_release: root.close_pop()
You should break it down to a simple example of your problem. From what I have seen so far you should try to change your btn_submit method to something like this to make the popup accessible easily:
def btn_submit(self):
if self.rd is None:
pLabel = "Please start before submitting!"
elif not self.userInput.text:
pLabel = "Please enter something!"
else:
pLabel = self.validate(self.userInput.text)
self.btn_next()
self.mypopup = PopupWindow(pLabel)
self.mypopup.open_popup()
and then you should be able to access it with your screenmanager like this:
class MyScreenManager(ScreenManager):
def close_pop(self):
print("This should close the popup...")
self.get_screen('main').mypopup.close_pop()

Kivy Text Input. Setting text with Clock.schedule_once()

I though that it will be fairly simple to show set some text to TextInput and show it on the screen but it seems I was wrong. In the below code I need to set text Lorem ipsum... to the text input and switch the tabs. I can see the text only when I uncomment Clock.schedule_interval(self.set_text, 1). I would use Clock.schedule_once or any other way than just constantly calling set_text() method.
'''
Test of the widget TabbedPanel.
'''
from kivy.app import App
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.tabbedpanel import TabbedPanel, TabbedPanelHeader
from kivy.factory import Factory
theRoot = """
#:import Factory kivy.factory.Factory
<EditButton>
orientation: 'vertical'
Button:
text: 'Switch to Edit Screen'
on_press: root.change_tab()
<EditInput>
orientation: 'vertical'
TextInput:
id: text_input
<UnCloseableHeader>
color: 0,0,0,1
disabled_color: self.color
# variable tab_width
text: 'tabx'
size_hint_x: None
width: self.texture_size[0] + 40
BoxLayout:
pos: root.pos
size_hint: None, None
size_y: 20
padding: 3
Label:
id: lbl
text: root.text
<MainTabbedPanel>:
size_hint: (1, 1)
do_default_tab: False
#default_tab: edit_button_tab
tab_width: 130
FloatLayout:
EditButton:
id: edit_button
EditInput:
id: edit_input
UnCloseableHeader:
id: edit_button_tab
text: 'Edit'
content: edit_button.__self__
UnCloseableHeader:
id: edit_input_tab
text: 'Edit Tab'
content: edit_input.__self__
MainTabbedPanel:
"""
class EditInput(BoxLayout):
notes = ''
def __init__(self, **kwargs):
super(EditInput, self).__init__(**kwargs)
print('NOTES', self.notes)
#Clock.schedule_interval(self.set_text, 1)
Clock.schedule_once(self.set_text, -1)
def set_text(self, dt):
print('SET TEXT', self.notes)
self.ids.text_input.text = self.notes
class EditButton(BoxLayout):
def __init__(self, **kwargs):
super(EditButton, self).__init__(**kwargs)
def change_tab(self):
EditInput.notes = 'Lorem ipsum...'
EditInput()
mtp = App.get_running_app().root
mtp.switch_to(mtp.ids.edit_input_tab)
class MainTabbedPanel(TabbedPanel):
tab = ''
def __init__(self, **kwargs):
super(MainTabbedPanel, self).__init__(**kwargs)
self.tabs_showing = True
class UnCloseableHeader(TabbedPanelHeader):
pass
Factory.register('UnCloseableHeader', cls=UnCloseableHeader)
sm = Builder.load_string(theRoot)
class TabbedPanelApp(App):
def build(self):
return sm
if __name__ == '__main__':
TabbedPanelApp().run()
EDIT
I've tried with:
SNIPPET
def change_tab(self):
EditInput.notes = 'Lorem ipsum...'
EditInput()
and:
Clock.schedule_once(self.set_text, 1)
It works in about 50% of cases witch is pretty hard to understand
You can take advantage of Property binding that kv sets up for you. Change your EditInput class to simply:
class EditInput(BoxLayout):
notes = StringProperty('')
no need for any of the methods. Then, in your kv, change the EditInput rule to:
<EditInput>
orientation: 'vertical'
TextInput:
id: text_input
text: root.notes
and change the change_tab method of EditButton to:
def change_tab(self):
mtp = App.get_running_app().root
mtp.ids.edit_input.notes = 'Lorem ipsum...'
mtp.switch_to(mtp.ids.edit_input_tab)
Note that changing the notes property of the EditInput instance will automatically change the TextInput (due to the property binding set up by kv).
Also, the line in change_tab():
EditInput()
is creating a new instance of the EditInput class that is unused and will be garbage collected.

kivy select folder with FileChooser

i want to add kivy filechooser into gridlayout https://kivy.org/docs/api-kivy.uix.filechooser.html
i apply documentation and use root widget for have list file, but it's not work, my all folders not appear to my window
i have my main class :
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.factory import Factory
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
import os
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class SaveDialog(FloatLayout):
save = ObjectProperty(None)
text_input = ObjectProperty(None)
cancel = ObjectProperty(None)
class Root(FloatLayout):
loadfile = ObjectProperty(None)
savefile = ObjectProperty(None)
text_input = ObjectProperty(None)
def dismiss_popup(self):
self._popup.dismiss()
def show_load(self):
content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def show_save(self):
content = SaveDialog(save=self.save, cancel=self.dismiss_popup)
self._popup = Popup(title="Save file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def load(self, path, filename):
with open(os.path.join(path, filename[0])) as stream:
self.text_input.text = stream.read()
self.dismiss_popup()
def save(self, path, filename):
with open(os.path.join(path, filename), 'w') as stream:
stream.write(self.text_input.text)
self.dismiss_popup()
class Editor(App):
pass
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
class MyApp(App):
def build(self):
layout = BoxLayout(orientation='vertical')
root=Root()
root.show_load()
layout.add_widget(root)
return layout
if __name__ == '__main__':
MyApp().run()
i have only filechooser title, i have not folder or file in window why ?
the result :
You need to create a kv file, my.kv and some minor changes to the Python code. Please refer to the example for details.
Example
Python Script - main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.uix.popup import Popup
import os
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class SaveDialog(FloatLayout):
save = ObjectProperty(None)
text_input = ObjectProperty(None)
cancel = ObjectProperty(None)
class Root(FloatLayout):
loadfile = ObjectProperty(None)
savefile = ObjectProperty(None)
text_input = ObjectProperty(None)
def dismiss_popup(self):
self._popup.dismiss()
def show_load(self):
content = LoadDialog(load=self.load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def show_save(self):
content = SaveDialog(save=self.save, cancel=self.dismiss_popup)
self._popup = Popup(title="Save file", content=content,
size_hint=(0.9, 0.9))
self._popup.open()
def load(self, path, filename):
with open(os.path.join(path, filename[0])) as stream:
self.text_input.text = stream.read()
self.dismiss_popup()
def save(self, path, filename):
with open(os.path.join(path, filename), 'w') as stream:
stream.write(self.text_input.text)
self.dismiss_popup()
class MyApp(App):
def build(self):
return Root()
if __name__ == '__main__':
MyApp().run()
kv file - my.kv
#:kivy 1.11.0
<Root>:
text_input: text_input
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: None
height: 30
Button:
text: 'Load'
on_release: root.show_load()
Button:
text: 'Save'
on_release: root.show_save()
BoxLayout:
TextInput:
id: text_input
text: ''
RstDocument:
text: text_input.text
show_errors: True
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
<SaveDialog>:
text_input: text_input
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
on_selection: text_input.text = self.selection and self.selection[0] or ''
TextInput:
id: text_input
size_hint_y: None
height: 30
multiline: False
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Save"
on_release: root.save(filechooser.path, text_input.text)
Output

Resources