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
Related
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 have a label which when you click on it prints its value. It should also change the label on the first screen. Changing that label works as it should, but when I use the same method from outside the main class it does not work. Because of that I think the problem haws something to do with making new instances of classes instead of updating the ones that are already there. My knowledge of OOP is not good and because of that I can't figure this out. Any help and/or tips would be appreciated.
I tried resolving the problem with solutions from : Instantiate a class but don't call its __init__ method , but could not make it work in my case
The problem starts at line 93/94, then goes to line 45 from then it's clear
from kivy.app import *
from kivy.uix.button import *
from kivy.graphics import *
from kivy.uix.widget import *
from kivy.uix.label import *
from kivy.uix.behaviors import *
from kivy.uix.floatlayout import *
from kivy.uix.boxlayout import *
from kivy.uix.scrollview import ScrollView
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
brojPjesmi = 50
def dobijJenegaArtista(kega):
f = "Hi"+ str(x[0])
return f
x = [0]
#---------------------------------------------------------------------------------
class Name(Widget):
def __init__(self, **kwargs):
super(Name, self).__init__(**kwargs)
def changeName(self):
self.nam = "yeah"
self.ids.nameOfSong.text = self.nam[0]
self.ids.artistOfSong.text = str(dobijJenegaArtista(x[0]))
#---------------------------------------------------------------------------------
class FirstWindow(Screen):
def __init__(self, **kwargs):
super(FirstWindow, self).__init__(**kwargs)
self.pos = (0, 0)
self.size = (1,1)
self.z = Name()
self.add_widget(self.z)
def next(self):
if x[0] == brojPjesmi:
x[0] = 0
else:
x[0] = x[0] + 1
self.z.changeName()
def selected(self,p):
x[0] = p - 1 # it puts the value clicked to my counter x, because
# I will send it to next which will add 1 i subtract 1
print(x[0]) # check to see if it is correct
self.next()
def last(self):
if x[0] == 0:
x[0] = brojPjesmi
else:
x[0] = x[0] - 1
self.z.changeName()
#---------------------------------------------------------------------------------
#---------------------------------------------------------------------------------
class SecondWindow(Screen,BoxLayout):
def __init__(self, **kwargs):
super(SecondWindow, self).__init__(**kwargs)
self.d = MyRow()
self.add_widget(self.d)
#---------------------------------------------------------------------------------
g = []
class MyRow(ScrollView):
def __init__(self, **kwargs):
super(MyRow, self).__init__(**kwargs)
self.size_hint=(1,None)
self.size=(Window.width,Window.height)
layout = GridLayout(cols = 1,spacing= 10,size_hint_y = None)
layout.bind(minimum_height = layout.setter('height'))
self.butt = Button(text="gmm",height=40,size_hint_y = None,on_press = lambda x:self.change_screen())
layout.add_widget(self.butt)
for i in range(brojPjesmi):
self.z = OneRow()
u = self.z.make()
layout.add_widget(u)
self.add_widget(layout)
def change_screen(self):
App.get_running_app().root.transition.direction = "right"
App.get_running_app().root.current = 'main'
i = [0]
#---------------------------------------------------------------------------------
class OneRow(ButtonBehavior,GridLayout):
def mm(self):
print(self.i)
self.z = MyRow
self.z.change_screen(self)
self.man = FirstWindow()
self.man.selected(self.i)
def make(self):
i[0] = i[0] + 1
self.i = i[0]
self.cols = 3
self.rows = 1
self.height = 25
self.size_hint_y = None
self.on_release = self.mm
self.Treci = Label(text = str(""),size_hint_y= None,size_hint_x =.1,height=25)
self.prviDio = Label(text = str(self.i),size_hint_y= None,height=25)
self.drugiDio = Label(text = str(self.i*2),size_hint_y= None,height=25)
self.add_widget(self.Treci)
self.add_widget(self.prviDio)
self.add_widget(self.drugiDio)
return self
#---------------------------------------------------------------------------------
class langApp(App):
def build(self):
return kv
#---------------------------------------------------------------------------------
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("nu.kv")
if __name__ == '__main__':
langApp().run()
.kv file
#:kivy 1.11.1
WindowManager:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "main"
FloatLayout:
pos: 0,0
size: root.width,root.height
Button:
on_press: root.last()
text: 'Last'
pos_hint: {'x':.25,'y':.1}
size_hint: .1,.1
Button:
on_release:
text: 'Stop'
pos_hint: {'x':.45,'y':.1}
size_hint: .1,.1
Button:
on_press: root.next()
text: 'Next'
pos_hint: {'x':.65,'y':.1}
size_hint: .1,.1
Button:
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
text: 'songs'
pos_hint: {'x':.8,'y':.8}
size_hint: .05,.05
<Name>:
FloatLayout:
pos: 0,0
size: root.width,root.height
pos_hint_x: None
pos_hint_y: None
Label:
id: nameOfSong
text: "Choose a song"
font_size: 20
size_hint: None, None
pos_hint: {'x': 0.435, 'y': 0.25}
Label:
id: artistOfSong
text: ""
font_size: 40
size_hint: None, None
pos_hint: {'x': 0.435, 'y': 0.20}
<SecondWindow>:
name: "second"
PS: The code should: when you press next or last it should update the counter and the screen with the hi+counter(it's just a placeholder), after you click the button in the upper right corner it should list the numbers(also a placeholder usually it's songs and artists) and when you click on a number it should take you to the first screen(works until this point) and then change to label to the number you clicked
The number is also printed for debugging purposes
I know this is probably an easy answer, and I've been digging around trying to figure this out but can't quite seem to understand it. Anytime I run this, when I click the button to call the method, I always get the same problem. im trying my best to understand this stuff but its getting the best of me right now.
AttributeError: 'NoneType' object has no attribute 'text'
import kivymd
from kivy.app import App
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.textfield import MDTextField
from kivy.properties import ObjectProperty
class MainApp(MDApp):
height_feet = ObjectProperty(None)
height_feet = height_feet
height_inches = ObjectProperty(None)
weight = ObjectProperty(None)
bmiout = ObjectProperty(None)
def calculate(self):
height_feet = float(self.height_feet.text)
height_feet = float(height_feet * 12)
height_inches = float(self.height_inches.text)
height = float(height_feet + height_inches)
weight = float(self.weight.text)
bmi = int(weight / (height * height) * 703)
percent = str("%")
self.bmiout.text = "{}{}".format(bmi, percent)
self.height_feet.text = ""
self.height_inches.text = ""
self.weight.text = ""
def __init__(self, **kwargs):
self.title = "BMI"
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Blue"
super().__init__(**kwargs)
MainApp().run()
'KV'
#:import MDTextField kivymd.uix.textfield.MDTextField
#:import MDFillRoundFlatIconButton kivymd.uix.button.MDFillRoundFlatIconButton
BoxLayout:
id:layout
size_hint: .8, .8
pos_hint: {"center_x": .5, "center_y": .5}
spacing: dp(50)
orientation: 'vertical'
height_feet: height_feet
height_inches: height_inches
weight: weight
bmiout: bmiout
Label:
text: "BMI"
font_size: 100
MDTextField:
id: height_feet
hint_text: "Enter your height in feet"
require: True
max_text_length: 1
halign: 'center'
MDTextField:
id: height_inches
hint_text: "Enter your height in inches"
require: True
max_text_length: 2
halign: "center"
MDTextField:
id: weight
hint_text: "Enter your weight"
require: True
max_text_length: 3
halign: "center"
Label:
text: "Your BMI is"
font_size: 60
Label:
id: bmiout
font_size: 60
MDFillRoundFlatIconButton:
text: "Calculate"
icon: "calculator"
pos_hint:{ "center_x": .5, "center_y": .5}
width: dp(25)
on_release:
app.calculate()
Well, you should connect your object properties to widgets. Until it's done it is None.
from kivy.clock import Clock
...
class MainApp(MDApp):
# isn't it more readable when init is at the start?
def __init__(self, **kwargs):
self.title = "BMI"
# run function with delay
Clock.schedule_once(self.connectwidgets)
super().__init__(**kwargs)
# KivyMD can break when theme manager is in the init method
# so I put it here, just in case
theme_cls.theme_style = "Dark"
theme_cls.primary_palette = "Blue"
height_feet = ObjectProperty(None)
height_inches = ObjectProperty(None)
weight = ObjectProperty(None)
bmiout = ObjectProperty(None)
# As I said you should connect properties with widgets with using it's IDs
# but we have to delay running this function because instead Kivy run it before getting the widgets from kv file and won't work. Again.
def connectwidgets(self, *args):
self.height_feet = self.ids.height_feet
self.height_inches = self.ids.height_inches
self.weight = self.ids.weight
self.bmiout = self.ids.bmiout
def calculate(self):
height_feet = float(self.height_feet.text)
height_feet = float(height_feet * 12)
height_inches = float(self.height_inches.text)
height = float(height_feet + height_inches)
weight = float(self.weight.text)
bmi = int(weight / (height * height) * 703)
percent = str("%")
self.bmiout.text = "{}{}".format(bmi, percent)
self.height_feet.text = ""
self.height_inches.text = ""
self.weight.text = ""
MainApp().run()
PS. I don't know if that works, because I never put widgets to App class, but try it.
I have written some code in Python (test.py) and kivy (test.kv).When i run test.py.then show Test Menu and user submenu.When i click on user then +Add button show.When click on +add then show Number TextBox Type.
I am using treeView in number textbox.when i click on select number then it gives error
File "kivy/_event.pyx", line 273, in kivy._event.EventDispatcher.init (kivy/_event.c:5375)
File "kivy/properties.pyx", line 478, in kivy.properties.Property.set (kivy/properties.c:5171)
File "kivy/properties.pyx", line 513, in kivy.properties.Property.set (kivy/properties.c:5882)
ValueError: TreeViewLabelAccountGroup.text accept only str
if i use rows = [(1, 'Male'), (2, 'Female'), (3, 'Dog')] instead of rows = [(1, 111), (2, 112), (3, 113)]
then its working fine.
I do not know where I'm making a mistake.
If i change text to int then its working but data not showing.
if parent is None:
tree_node = tree_view_account_group.add_node(TreeViewLabelAccountGroup(text=node['node_id'],
is_open=True))
else:
tree_node = tree_view_account_group.add_node(TreeViewLabelAccountGroup(text=node['node_id'],
is_open=True), parent)
test.py
import kivy
kivy.require('1.9.0') # replace with your current kivy version !
import sqlite3 as lite
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.lang import Builder
from kivy.uix.dropdown import DropDown
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window
from kivy.uix.label import Label
Window.maximize()
from kivy.clock import Clock
from kivy.uix.treeview import TreeView, TreeViewLabel, TreeViewNode
from kivy.uix.image import AsyncImage
import os
import sys
#root.attributes("-toolwindow", 1)
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
def populate_tree_view_account_group(tree_view_account_group, parent, node):
if parent is None:
tree_node = tree_view_account_group.add_node(TreeViewLabelAccountGroup(text=node['node_id'],
is_open=True))
else:
tree_node = tree_view_account_group.add_node(TreeViewLabelAccountGroup(text=node['node_id'],
is_open=True), parent)
for child_node in node['children']:
populate_tree_view_account_group(tree_view_account_group, tree_node, child_node)
#this is retrieve from database
rows = [(1, 111), (2, 112), (3, 113)]
treeAccountGroup = []
for r in rows:
treeAccountGroup.append({'node_id': r[1], 'children': []})
class TreeviewAccountGroup(Popup):
treeviewAccount = ObjectProperty(None)
tv = ObjectProperty(None)
h = NumericProperty(0)
#ti = ObjectProperty()
popup = ObjectProperty()
def __init__(self, **kwargs):
super(TreeviewAccountGroup, self).__init__(**kwargs)
self.tv = TreeView(root_options=dict(text=""),
hide_root=False,
indent_level=4)
for branch in treeAccountGroup:
populate_tree_view_account_group(self.tv, None, branch)
#self.remove_widgets()
self.treeviewAccount.add_widget(self.tv)
Clock.schedule_once(self.update, 1)
def remove_widgets(self):
for child in [child for child in self.treeviewAccount.children]:
self.treeviewAccount.remove_widget(child)
def update(self, *args):
self.h = len([child for child in self.tv.children]) * 24
def filter(self, f):
self.treeviewAccount.clear_widgets()
self.tv = TreeView(root_options=dict(text=""),
hide_root=False,
indent_level=4)
new_tree = []
for n in treeAccountGroup:
if f.lower() in n['node_id'].lower():
new_tree.append(n)
for branch in new_tree:
populate_tree_view_account_group(self.tv, None, branch)
self.treeviewAccount.add_widget(self.tv)
class TreeViewLabelAccountGroup(Label, TreeViewNode):
pass
class AccountGroupPopup(Popup):
category_label = ObjectProperty(None)
category_text = ObjectProperty(None)
name_label = ObjectProperty(None)
name_txt = ObjectProperty(None)
popupGroupAccount = ObjectProperty(None)
popupEffect = ObjectProperty(None)
groupType = ObjectProperty(None)
mode = StringProperty("")
col_data = ListProperty(["?", "?", "?", "?","?"])
index = NumericProperty(0)
popup4 = ObjectProperty(None)
popup5 = ObjectProperty(None)
primary_check_button = BooleanProperty(False)
secondary_check_button = BooleanProperty(False)
def __init__(self, obj, **kwargs):
super(AccountGroupPopup, self).__init__(**kwargs)
self.mode = obj.mode
if obj.mode == "Add":
self.col_data[0] = ''
self.col_data[1] = ''
self.col_data[2] = ''
self.col_data[3] = 'Select Number'
def display_primary_treeview(self, instance):
if len(instance.text) > 0:
if self.popupGroupAccount is None:
self.popupGroupAccount = TreeviewAccountGroup()
self.popupGroupAccount.popup4 = self
self.popupGroupAccount.filter(instance.text)
self.popupGroupAccount.open()
def display_effect_type(self, instance):
if len(instance.text) > 0:
if self.popupEffect is None:
self.popupEffect = TreeviewEffectType()
self.popupEffect.popup5 = self
self.popupEffect.filter(instance.text)
self.popupEffect.open()
class SelectableButtonGroupAccount(RecycleDataViewBehavior, Button):
''' Add selection support to the Button '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
rv_data_account_group = ObjectProperty(None)
start_point = NumericProperty(0)
mode = StringProperty("Update")
def __init__(self, **kwargs):
super(SelectableButtonGroupAccount, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data_account_group[self.index][self.key]
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButtonGroupAccount, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButtonGroupAccount, 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
self.rv_data_account_group = rv.data
#print("selection changed to {0}".format(rv.data[1]))
def on_press(self):
popup = AccountGroupPopup(self)
popup.open()
class RVACCOUNTGROUP(BoxLayout):
def add_account_group(self):
self.mode = "Add"
popup = AccountGroupPopup(self)
popup.open()
class CustDrop(DropDown):
def __init__(self, **kwargs):
super(CustDrop, self).__init__(**kwargs)
self.select('')
class MainMenu(BoxLayout):
content_area = ObjectProperty()
rv = ObjectProperty(None)
dropdown = ObjectProperty(None)
def display_account_group(self):
self.dropdown.dismiss()
self.remove_widgets()
self.rvarea = RVACCOUNTGROUP()
self.content_area.add_widget(self.rvarea)
def remove_widgets(self):
self.content_area.clear_widgets()
def insert_update(self, obj):
print('Test')
class TacApp(App):
title = "FactEx"
def build(self):
self.root = Builder.load_file('test.kv')
return MainMenu()
if __name__ == '__main__':
TacApp().run()
test.kv
#:kivy 1.10.0
#:import CoreImage kivy.core.image.Image
#:import os os
<TreeviewAccountGroup>:
id: treeviewAccount
treeviewAccount: treeviewAccount
title: ""
pos_hint: {'x': .65, 'y': .3}
size_hint: .2,.4
#size: 800, 800
auto_dismiss: False
BoxLayout
orientation: "vertical"
ScrollView:
size_hint: 1, .9
BoxLayout:
size_hint_y: None
id: treeviewAccount
height: root.h
rooot: root
TextInput:
id: treeview
size_hint_y: .1
on_text: root.filter(self.text)
#BoxLayout:
#id: treeview
#on_press: root.select_node(self.text)
Button:
size_hint: 1, 0.1
text: "Close"
on_release: root.dismiss()
<TreeviewEffectType>:
#id: treeviewAccount
treeviewEffectType: treeviewEffectType
title: ""
pos_hint: {'x': .65, 'y': .3}
size_hint: .2,.4
#size: 800, 800
auto_dismiss: False
BoxLayout
orientation: "vertical"
ScrollView:
size_hint: 1, .9
BoxLayout:
size_hint_y: None
id: treeviewEffectType
height: root.h
rooot: root
TextInput:
id: treeview
size_hint_y: .1
on_text: root.filter(self.text)
#BoxLayout:
#id: treeview
#on_press: root.select_node(self.text)
Button:
size_hint: 1, 0.1
text: "Close"
on_release: root.dismiss()
<TreeViewLabelEffectType>:
height: 24
on_touch_down:
root.parent.parent.rooot.popup5.col_data[4] = self.text
#app.root.effect_type_txt.text = self.text
#root.parent.parent.rooot.popup5.popup.dismiss()
<TreeViewLabelAccountGroup>:
height: 24
on_touch_down:
root.parent.parent.rooot.popup4.col_data[3] = self.text
#app.root.effect_type_txt.text = self.text
#app.root.popupEffect.dismiss()
<AccountGroupPopup>:
title: ""
size_hint: None, None
size: 500, 350
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
padding : 30, 0
row_default_height: '30dp'
size_hint: 1, .1
pos_hint: {'x': .1, 'y': .06}
GridLayout:
cols: 2
padding: 10, 10
spacing: 20, 20
#row_default_height: '30dp'
size_hint: 1, .7
pos_hint: {'x': 0, 'y':.65}
Label:
id:category_label
text: 'Number'
text_size: self.size
valign: 'middle'
TextInput:
id: category_text
text: root.col_data[3]
on_focus: root.display_primary_treeview(self)
Button:
text: 'Ok'
on_release:
#root.package_changes(name_txt.text,primary_group_txt.text,effect_type_txt.text)
app.root.insert_update(root)
root.dismiss()
Button:
text: 'Cancel'
on_release: root.dismiss()
<AccountGroup#RecycleView>:
viewclass: 'SelectableButtonGroupAccount'
SelectableRecycleGridLayout:
cols: 1
default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
<RVACCOUNTGROUP>:
BoxLayout:
orientation: "vertical"
Button:
size_hint: .05, .03
text: "+Add"
on_press: root.add_account_group()
<DropdownButton#Button>:
border: (0, 16, 0, 16)
text_size: self.size
valign: "middle"
padding_x: 5
size_hint_y: None
height: '30dp'
#on_release: dropdown.select('')
#on_release: app.root.test
background_color: 90 , 90, 90, 90
color: 0, 0.517, 0.705, 1
<MenuButton#Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
content_area: content_area
dropdown: dropdown
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'Test'
size : (60,30)
on_release: dropdown.open(self)
CustDrop:
id: dropdown
auto_width: False
width: 150
DropdownButton:
text: 'User'
size_hint_y: None
height: '32dp'
# on_release: dropdown3.open(self)
on_release: root.display_account_group()
BoxLayout:
id: content_area
size_hint_y: 30
Label:
size_hint_y: 1
Can someone help me?
You need to convert the node_id to str:
for r in rows:
treeAccountGroup.append({'node_id': str(r[1]), 'children': []})
test.kv
:kivy 1.10.0
<CRUD>:
title: self.mode + " State"
size_hint: None, None
size: 350, 350
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
Label:
text: root.label_rec_id
Label:
id: userid
text: root.col_data[0] # root.userid
Label:
text: "First Name"
TextInput:
id: fname
text: root.col_data[1] # root.fname
Label:
text: "Last Name"
TextInput:
id: lname
text: root.col_data[2] # root.lname
Button:
size_hint: 1, 0.4
text: "Save Changes"
on_release:
root.package_changes(fname.text, lname.text)
app.root.update_changes(root)
root.dismiss()
Button:
size_hint: 1, 0.4
text: "Cancel Changes"
on_release: root.dismiss()
when click on any row then edit form open.Can i use same form for add user.
At this time i click on add user then user.py file run and open a new form.how to use same form for both add update.
Yes, you can use the same form to add city. In the example, I added a button, a method add_record, some variable e.g. mode of type StringProperty, and INSERT SQL command. Please refer to the example for details.
Example
main.py
import kivy
kivy.require('1.10.0') # replace with your current kivy version !
import sqlite3 as lite
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, StringProperty, ObjectProperty, NumericProperty
from kivy.lang import Builder
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window
Window.size = (500, 500)
MAX_TABLE_COLS = 3
con = lite.connect('company.db')
# con.text_factory = str
cur = con.cursor()
class CRUD(Popup):
"""CRUD - Create, Read, Update, Delete"""
label_id_text = ObjectProperty(None)
label_id_data = ObjectProperty(None)
mode = StringProperty("")
label_rec_id = StringProperty("UserID")
start_point = NumericProperty(0)
col_data = ListProperty(["", "", ""])
def __init__(self, obj, **kwargs):
super(CRUD, self).__init__(**kwargs)
self.mode = obj.mode
if obj.mode == "Add":
self.label_id_text.opacity = 0 # invisible
self.label_id_data.opacity = 0 # invisible
else:
self.label_id_text.opacity = 1 # visible
self.label_id_data.opacity = 1 # visible
self.start_point = obj.start_point
self.col_data[0] = obj.rv_data[obj.start_point]["text"]
self.col_data[1] = obj.rv_data[obj.start_point + 1]["text"]
self.col_data[2] = obj.rv_data[obj.start_point + 2]["text"]
def package_changes(self, fname, lname):
self.col_data[1] = fname
self.col_data[2] = lname
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Button '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
rv_data = ObjectProperty(None)
start_point = NumericProperty(0)
mode = StringProperty("")
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, 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
self.rv_data = rv.data
def on_press(self):
self.mode = "Update"
self.start_point = 0
end_point = MAX_TABLE_COLS
rows = len(self.rv_data) // MAX_TABLE_COLS
for row in range(rows):
if self.index in list(range(end_point)):
break
self.start_point += MAX_TABLE_COLS
end_point += MAX_TABLE_COLS
popup = CRUD(self)
popup.open()
class RV(BoxLayout):
rv_data = ListProperty([])
start_point = NumericProperty(0)
mode = StringProperty("")
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_users()
def get_users(self):
'''This result retrieve from database'''
self.rv_data = []
cur.execute("SELECT * FROM Users ORDER BY UserID ASC")
rows = cur.fetchall()
# create data_items
for row in rows:
for col in row:
self.rv_data.append(col)
def add_record(self):
self.mode = "Add"
popup = CRUD(self)
popup.open()
def update_changes(self, obj):
if obj.mode == "Add":
# insert record into Database Table
cur.execute("INSERT INTO Users VALUES(NULL, ?, ?)",
(obj.col_data[1], obj.col_data[2]))
else:
# update Database Table
cur.execute("UPDATE Users SET FirstName=?, LastName=? WHERE UserID=?",
(obj.col_data[1], obj.col_data[2], obj.col_data[0]))
con.commit()
self.get_users()
class ListUser(App):
title = "Users"
def build(self):
self.root = Builder.load_file('main.kv')
return RV()
if __name__ == '__main__':
ListUser().run()
main.kv
#:kivy 1.10.0
<CRUD>:
label_id_text: label_id_text
label_id_data: label_id_data
title: self.mode + " State"
size_hint: None, None
size: 350, 350
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
Label:
id: label_id_text
text: "ID"
Label:
id: label_id_data
text: root.col_data[0] # root.userid
Label:
text: "First Name"
TextInput:
id: fname
text: root.col_data[1] # root.fname
Label:
text: "Last Name"
TextInput:
id: lname
text: root.col_data[2] # root.lname
Button:
size_hint: 1, 0.4
text: "Confirm " + root.mode
on_release:
root.package_changes(fname.text, lname.text)
app.root.update_changes(root)
root.dismiss()
Button:
size_hint: 1, 0.4
text: "Cancel " + root.mode
on_release: root.dismiss()
<SelectableButton>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<RV>:
BoxLayout:
orientation: "vertical"
Button:
size_hint: 1, 0.1
text: "Add Record"
on_press: root.add_record()
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
text: "ID"
Label:
text: "First Name"
Label:
text: "Last Name"
BoxLayout:
RecycleView:
viewclass: 'SelectableButton'
data: [{'text': str(x)} for x in root.rv_data]
SelectableRecycleGridLayout:
cols: 3
default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
Output