【发布时间】:2019-04-20 17:52:05
【问题描述】:
我正在尝试动态填充 ScrollView 内的 Gridlayout。但是,当我尝试添加 Builder.load_string 生成的按钮时,出现以下错误: kivy.uix.widget.WidgetException:无法添加,它已经有一个父级 我不确定我做错了什么。 我可以通过构造函数在python中生成每个按钮,但我宁愿不重写按钮生成。
main.py
# IMSA Computational Science and Data Science Club: Brummet Client
# Written for ssh into IMSA SLURM cluster
# Written by: Arthur Lu, Jacob Levine
# Use at one's own risk
__author__ = ("Arthur Lu <alu1@imsa.edu>", "Jacob Levine <jlevine@imsa.edu>")
from kivy.config import Config
#Config.set('graphics', 'resizable', False)
from kivy.app import App
from kivy.properties import StringProperty, ObjectProperty
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition, NoTransition
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.lang.builder import Builder
from kivy.clock import Clock
import csv
import paramiko
import time
#import os
def load_csv(filepath):
with open(filepath, newline='') as csvfile:
file_array = list(csv.reader(csvfile))
csvfile.close()
return file_array
class Client(Screen):
def on_pre_enter(self, *args):
Window.size = (1280, 720)
Window.top = 100
Window.left = 100
def client(self, ssh, sftp):
self.ssh = ssh
self.sftp = sftp
self.sftp.chdir('brummet_projects')
Clock.schedule_interval(self.auto, 1)
def auto(self, dt):
projects = self.sftp.listdir('.')
for file in projects:
if file[0] == ".":
projects.remove(file)
list_view = self.ids.list_files
"""
Button:
background_color: 0,0,0,0
Image:
source:'data\customui\client_file_bar.png'
x: self.parent.x
y: self.parent.y
width: self.parent.width
height: self.parent.height
allow_stretch: True
keep_ratio: False
Image:
source:'data\customui\python.png'
y: self.parent.y + 10
x: - self.parent.width/2 + 25
width: self.parent.width - 20
height: self.parent.height - 20
Label:
size_hint:(0.9, 1)
text: "hello there"
y: self.parent.y
x: self.parent.x + self.parent.width*0.05
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "no u"
y: self.parent.y
x: self.parent.x + self.parent.width*0.7
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "dong big dumb"
y: self.parent.y
x: self.parent.x + self.parent.width*0.8
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
"""
template = Builder.load_string("""
Button:
background_color: 0,0,0,0
Image:
source:'data\customui\client_file_bar.png'
x: self.parent.x
y: self.parent.y
width: self.parent.width
height: self.parent.height
allow_stretch: True
keep_ratio: False
Image:
source:'data\customui\python.png'
y: self.parent.y + 10
x: - self.parent.width/2 + 25
width: self.parent.width - 20
height: self.parent.height - 20
Label:
size_hint:(0.9, 1)
text: "hello there"
y: self.parent.y
x: self.parent.x + self.parent.width*0.05
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "no u"
y: self.parent.y
x: self.parent.x + self.parent.width*0.7
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "dong big dumb"
y: self.parent.y
x: self.parent.x + self.parent.width*0.8
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
""")
print(projects)
for file in projects:
list_view.add_widget(template)
class Connect(Screen):
def on_pre_enter(self, *args):
Window.size = (600, 300)
def routine(self, host, port, username, password):
ssh = None
sftp = None
#print(username, password)
self.ids.status.text = "connecting"
try:
self.ids.status.text = "attempting to connect to " + host + ":" + str(port)
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, port, username, password)
transport = paramiko.Transport((host, port))
transport.connect(username = username, password = password)
sftp = paramiko.SFTPClient.from_transport(transport)
self.ids.status.text = "connected to " + host + ":" + str(port)
Clock.schedule_once(self.continue_to_client, 0.1)
self.manager.get_screen('client').client(ssh, sftp)
except Exception as e:
if sftp is not None:
sftp.close()
if ssh is not None:
ssh.close()
self.ids.status.text = "connection failed: " + str(e)
Clock.schedule_once(self.return_to_login, 4)
#self.manager.current = 'login'
def return_to_login(self, *args):
self.manager.transition = SlideTransition(direction = "right")
self.manager.current = 'login'
#time.sleep(5)
def continue_to_client(self, *args):
self.manager.transition = NoTransition()
self.manager.current = 'client'
class Login(Screen):
def on_pre_enter(self, *args):
Window.size = (600, 300)
def do_login(self, loginText, passwordText, hostText, portText):
app = App.get_running_app()
if hostText == "":
hostText = "titanrobotics.ddns.net"
if portText == "":
portText = "60022"
host = hostText
port = int(portText)
username = loginText
password = passwordText
self.manager.transition = SlideTransition(direction = "left")
self.manager.current = "connect"
self.manager.get_screen('connect').routine(host, port, username, password)
def resetForm(self):
self.ids['login'].text = ""
self.ids['password'].text = ""
manager = ScreenManager()
class BrummetApp(App):
username = StringProperty(None)
password = StringProperty(None)
title = 'Brummet Client v ' + load_csv("data/meta")[0][1]
def check_resize(self, instance, x, y):
# resize X
#screenName = manager.current
#print(screenName)
if manager.current != "client":
target_x = 600
target_y = 300
if x > target_x:
Window.size = (target_x, Window.size[1])
if y > target_y:
Window.size = (Window.size[0], target_y)
if x < target_x:
Window.size = (target_x, Window.size[1])
if y < target_y:
Window.size = (Window.size[0], target_y)
if manager.current == "client":
target_x = 1280
target_y = 720
if x < target_x:
Window.size = (target_x, Window.size[1])
if y < target_y:
Window.size = (Window.size[0], target_y)
def build(self):
manager.add_widget(Login(name = 'login'))
manager.add_widget(Connect(name = 'connect'))
manager.add_widget(Client(name = 'client'))
Window.bind(on_resize=self.check_resize)
return manager
if __name__ == '__main__':
BrummetApp().run()
brummet.kv
<Login>:
BoxLayout:
id: login_layout
orientation: 'vertical'
padding: [10,10,10,10]
spacing: 10
BoxLayout:
spacing: 10
orientation:'vertical'
Label:
id: title
text: 'Brummet Client'
halign: 'center'
valign: 'middle'
font_size: 24
Label:
text: 'Please log in with IMSA SLURM credentials'
halign: 'center'
valign: 'middle'
font_size: 20
BoxLayout:
orientation: 'horizontal'
Label:
size_hint: (0.15, 1)
text: 'Username'
font_size: 18
halign: 'left'
TextInput:
size_hint: (0.7, 1)
id: username
multiline: False
font_size: 18
write_tab: False
BoxLayout:
orientation: 'horizontal'
Label:
size_hint: (0.15, 1)
text: 'Password'
halign: 'left'
font_size: 18
TextInput:
size_hint: (0.7, 1)
id: password
multiline: False
password: True
font_size: 18
write_tab: False
BoxLayout:
orientation: 'horizontal'
Label:
size_hint: (0.15, 1)
text: 'Host'
halign: 'left'
font_size: 18
TextInput:
size_hint: (0.7, 1)
hint_text: 'slurm.imsa.edu'
id: host
multiline: False
font_size: 18
write_tab: False
BoxLayout:
orientation: 'horizontal'
Label:
size_hint: (0.15, 1)
text: 'Port'
halign: 'left'
font_size: 18
TextInput:
size_hint: (0.7, 1)
input_type: 'number'
input_filter: 'int'
hint_text: '22'
id: port
multiline: False
font_size: 18
write_tab: False
Button:
text: 'Log In'
font_size: 24
id: submit
on_press:
root.do_login(username.text, password.text, host.text, port.text)
<Connect>:
BoxLayout:
orientation: 'vertical'
padding: [0,100,0,100]
spacing: 0
Label:
text:'Logging In'
font_size: 24
halign: 'center'
valign: 'middle'
Label:
id: status
test:''
font_size: 12
halign: 'center'
valign: 'middle'
text_size: self.size
size_hint: 1,1
shorten: True
<Client>:
BoxLayout:
orientation: 'horizontal'
padding: [5, 5, 5, 5]
spacing: 5
GridLayout:
size_hint: (0.2, 1)
row_default_height: self.height / 10
row_force_default: True
cols: 1
Button:
Button:
BoxLayout:
orientation: 'vertical'
Button:
x: 0
y: 0
size: (self.parent.width, 50)
size_hint:(None, None)
background_color: 0,0,0,0
Label:
size_hint:(0.9, 1)
text: "My Projects"
y: self.parent.y
x: self.parent.x + self.parent.width*0
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 10
halign: 'left'
valign: 'middle'
Button:
x: 0
y: 0
size: (self.parent.width, 50)
size_hint:(None, None)
background_color: 0,0,0,0
Label:
size_hint:(0.9, 1)
text: "Project Name"
y: self.parent.y
x: self.parent.x + self.parent.width*0
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "Type"
y: self.parent.y
x: self.parent.x + self.parent.width*0.7
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "Date Modified"
y: self.parent.y
x: self.parent.x + self.parent.width*0.8
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
ScrollView:
GridLayout:
id:list_files
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
row_default_height:50
cols:1
Button:
background_color: 0,0,0,0
Image:
source:'data\customui\client_file_bar.png'
x: self.parent.x
y: self.parent.y
width: self.parent.width
height: self.parent.height
allow_stretch: True
keep_ratio: False
Image:
source:'data\customui\python.png'
y: self.parent.y + 10
x: - self.parent.width/2 + 25
width: self.parent.width - 20
height: self.parent.height - 20
Label:
size_hint:(0.9, 1)
text: "hello there"
y: self.parent.y
x: self.parent.x + self.parent.width*0.05
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "no u"
y: self.parent.y
x: self.parent.x + self.parent.width*0.7
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "dong big dumb"
y: self.parent.y
x: self.parent.x + self.parent.width*0.8
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
错误发生在以下代码中:
template = Builder.load_string("""
Button:
background_color: 0,0,0,0
Image:
source:'data\customui\client_file_bar.png'
x: self.parent.x
y: self.parent.y
width: self.parent.width
height: self.parent.height
allow_stretch: True
keep_ratio: False
Image:
source:'data\customui\python.png'
y: self.parent.y + 10
x: - self.parent.width/2 + 25
width: self.parent.width - 20
height: self.parent.height - 20
Label:
size_hint:(0.9, 1)
text: "hello there"
y: self.parent.y
x: self.parent.x + self.parent.width*0.05
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "no u"
y: self.parent.y
x: self.parent.x + self.parent.width*0.7
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
Label:
size_hint:(0.9, 1)
text: "dong big dumb"
y: self.parent.y
x: self.parent.x + self.parent.width*0.8
width: self.parent.width
height: self.parent.height
text_size: self.size
font_size: self.height - 30
halign: 'left'
valign: 'middle'
""")
print(projects)
for file in projects:
list_view.add_widget(template)
上面的代码应该在 ScrollView 中生成一些按钮,但是会产生以下错误: kivy.uix.widget.WidgetException: 无法添加,它已经有一个父级
【问题讨论】:
-
请发布一个 minimal 可运行示例,使用尽可能少的代码来演示问题。
-
依赖的东西太多了,但是相关的代码就是Builder.load_string所在的地方。在 Client 类下。
标签: python python-3.x kivy