Я клонировал свой текущий проект на другой p c, установил python и все зависимости и выполнил мой GUI просто отлично. После нескольких попыток отладки с pyCharm мой GUI больше не будет запускаться ни из pyCharm, ни из командной строки. Я попытался установить другую версию python с нуля, чтобы проверить, не испортил ли я что-то, однако ошибка на одном p c осталась прежней, а на моем ноутбуке работает точно такой же код.
My python Файл уже достаточно большой, поэтому я удалил много своих функций, надеюсь, мой код все еще несколько понятен (я оставил в нем несколько более сложных функций).
Я получаю следующую ошибку: AttributeError : Объект 'NoneType' не имеет атрибута 'bind' . Однако я не использую * .bind ни в своем .py, ни в своем файле .kv, поэтому я предполагаю, что это может повлиять на то, как я создаю всплывающие окна и добавляю в него виджеты? Или как я загружаю компоновщик / инициализирую мой GUI?
Ошибка:
Traceback (most recent call last):
File "GUI.py", line 800, in <module>
GUI().run()
File "C:\Python38\lib\site-packages\kivy\app.py", line 949, in run
self._run_prepare()
File "C:\Python38\lib\site-packages\kivy\app.py", line 919, in _run_prepare
root = self.build()
File "GUI.py", line 797, in build
return BoxL()
File "GUI.py", line 76, in __init__
super(BoxL, self).__init__()
File "C:\Python38\lib\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
super(BoxLayout, self).__init__(**kwargs)
File "C:\Python38\lib\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "C:\Python38\lib\site-packages\kivy\uix\widget.py", line 359, in __init__
self.apply_class_lang_rules(
File "C:\Python38\lib\site-packages\kivy\uix\widget.py", line 463, in apply_class_lang_rules
Builder.apply(
File "C:\Python38\lib\site-packages\kivy\lang\builder.py", line 539, in apply
self._apply_rule(
File "C:\Python38\lib\site-packages\kivy\lang\builder.py", line 661, in _apply_rule
self._apply_rule(
File "C:\Python38\lib\site-packages\kivy\lang\builder.py", line 661, in _apply_rule
self._apply_rule(
File "C:\Python38\lib\site-packages\kivy\lang\builder.py", line 661, in _apply_rule
self._apply_rule(
[Previous line repeated 4 more times]
File "C:\Python38\lib\site-packages\kivy\lang\builder.py", line 657, in _apply_rule
child = cls(__no_builder=True)
File "C:\Python38\lib\site-packages\kivy\uix\spinner.py", line 155, in __init__
build_dropdown()
File "C:\Python38\lib\site-packages\kivy\uix\spinner.py", line 166, in _build_dropdown
self._dropdown = cls()
File "C:\Python38\lib\site-packages\kivy\uix\dropdown.py", line 218, in __init__
Window.bind(
AttributeError: 'NoneType' object has no attribute 'bind'
Python файл (сокращенный):
#kivy imports
from kivy.app import App
from kivy.config import Config
from kivy.properties import StringProperty
from kivy.properties import ObjectProperty
from kivy.properties import NumericProperty
from kivy.properties import BooleanProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.uix.video import Video
from kivy.uix.spinner import Spinner
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.label import Label
from kivy.uix.switch import Switch
from kivy.uix.filechooser import FileChooserListView
from kivy.uix.slider import Slider
from kivy.uix.progressbar import ProgressBar
from kivy.uix.textinput import TextInput
from kivy.clock import Clock
#various imports
from datetime import datetime #for time in logging
import logging
import webbrowser #for mailto
import os #for opening files or folders, currently only under windows
import glob #for opening most recent file
#from threading import Thread
import concurrent.futures #higher level threading API for loading big scripts
#imports functions
from restart_gui import restart_program #restarts GUI
from XY import open_com_port
from XY import open_sys_port
from XY import check_connectivity
from XY import check_connectivity_silent
from get_board_id import get_board_id
from get_resolution import get_resolution
class BoxL(BoxLayout):
""" Define class PageLayout here; This Class is used to create functions
and variables, which are then called in the GUI.kv file """
def __init__(self):
# The super function in Python can be
# used to gain access to inherited methods
# which is either from a parent or sibling class.
super(BoxL, self).__init__()
""" ##################### ROOT VARIABLES ##################### """
s = 0
c = 0
comEnabled = BooleanProperty(False)
sysEnabled = BooleanProperty(False)
sWork = BooleanProperty(False)
cWork = BooleanProperty(False)
laserColor = StringProperty()
redEnabled = BooleanProperty(True)
greenEnabled = BooleanProperty(True)
blueEnabled = BooleanProperty(True)
#Calibration (True = enabled)
calibrationEnabled = BooleanProperty(True)
someOtherVariable = NumericProperty(0)
scanUp = StringProperty('normal')
scanDown = StringProperty('down')
scanLeft = StringProperty('normal')
scanRight = StringProperty('down')
""" Defines column width; Kivy use: size_hint_x: root.devCol1 """
devCol1 = NumericProperty(0.2) #First colum width: 20%
devCol2 = NumericProperty(0.8) #Second column width: 80%
""" Messages between python/kivy and output to kivy/shell """
labelText = StringProperty() #Status+Debug Message on bottom of GUI
#Output to kivy (text: root.labelText);
#access in python: self.change_label('TEXT'),
#in kivy file: root.change_label('text')
boardID = StringProperty('No ID') #Variable for board ID
boardRes = StringProperty('No Res') #Variable for board resolution
""" Logging Variables; used by function change_label;
additional logging with: logging.[debug/info/error]('TEXT') """
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
logDateTime = datetime.now().strftime('%d-%b-%Y_%H-%M-%S')
fh = logging.FileHandler('GUI\\logs\\logfile_' + logDateTime + '.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
logging.debug('############## START OF LOG #### ' + \
logDateTime + ' ##############')
""" ############################ FUNCTIONS ########################## """
def change_label(self, labelValue):
""" change_label function to write to labelText (stringProperty)
Arguments: labelValue (string)
example: call from widget in kivy file: root.changelabel('TEXT')
call from python: self.change_label('TEXT') """
dateTimeObj = datetime.now()
self.labelText = dateTimeObj.strftime("%H:%M:%S") + \
' ' + labelValue
logging.debug(dateTimeObj.strftime('%d-%b-%Y %H-%M-%S: ') + \
labelValue) #writes to log
def mailto_me(self):
""" Opens standard email client to send email; Package: webbrowser """
recipient = 'xy@xy.com'
subject = 'Support'
body = 'Name: \n Text: '
body = body.replace(' ', '%20')
body = body.replace('\n','%0D%0A')
webbrowser.open('mailto:?to=' + recipient + '&subject=' + subject + '&body=' + body, new=1)
self.change_label('XY')
def open_file(self, filename):
""" Function to open file; Package: os """
os.startfile(filename)
self.change_label('Opened file: ' + str(filename))
def open_logfolder(self):
""" Function to open folder GUI\logs; Package: os """
logfolder = 'GUI\\logs'
os.startfile(logfolder)
self.change_label('Opened folder: ' + str(logfolder))
def get_latest_log(self):
""" Function to get latest log file from folder GUI\logs; Packages: os, glob """
currentPath = os.getcwd()
logPath = currentPath + '\\GUI\\logs\\*'
fileList = glob.glob(logPath)
lastFile = max(fileList, key=os.path.getctime)
os.startfile(lastFile)
self.change_label('Opened latest logfile: ' + str(lastFile))
def getID(self, kivyObject):
""" Gets ID (defined in kivy file) from kivy object and returns string
Arguments: kivyObject
Example kivy: on_release: root.function(*args) (*args includes object and objectValue)
Example python: def function(self, kivyObject, kivyObjectValue)
objectID = self.getID(kivyObject) """
for i_d in self.ids:
if kivyObject == self.ids[i_d]:
thisID = i_d
break
return thisID
def disable_everything(self, bool): #TODO: implement, disable all gui elements besides open com/sys
if True: #condition when disable_everything(True) is called
print('yet to be implemented')
else: #Condition when disable_everything(False) is called
pass
def reset_laser(self):
""" Restores configuration from flash-values """
if self.check():
restore_calibration(self.c) #Function call
self.read_lasers()
self.change_ledstatus()
self.ids.switchEnableRed.active = True
self.ids.switchEnableGreen.active = True
self.ids.switchEnableBlue.active = True
def save_config_to_file_(self):
""" Saves the Flash configuration to a BIN-file """
self.change_label('Initializing save configuration from flash to file ... (~3min)')
if self.check():
executor = concurrent.futures.ThreadPoolExecutor(max_workers=2) #This outside of function? create second thread from another location/popup/?
threadB = executor.submit(save_config_to_file, self.s, self.c) #starts save_config_to_file in thread
return_value = threadB.result()
self.change_label('Configuration saved to: ' + str(return_value) )
self.confPop.dismiss()
""" KIVY Popups """
def devPopup(self): #call from kivy-file with root.devPopup()
#create popup
self.devPop = Popup()
self.devPop.title = 'GUI Developer Warning'
self.devPop.title_size = 20
self.devPop.title_align = 'center'
self.devPop.auto_dismiss = True
self.devPop.size_hint = (None, None)
self.devPop.size = (400, 300)
#create popup-content
box = BoxLayout()
box.add_widget(Label(text = '[u][b]Warning!![/b][/u]\n\nUsing the developer mode might damage\nyour device, use with caution!',
color = (1, 1, 1, 1), #White text
pos_hint = {'center_x': .5, 'center_y': .5},
halign = 'center',
valign = 'middle'))
#add content, open popup
self.devPop.content = box
self.devPop.open()
def confirmPopup(self): #call from kivy-file with root.confirmPopup()
""" Popup to confirm action save_config_to_file_ """
#create popup
self.confPop = Popup()
self.confPop.title = 'Confirm ction'
self.confPop.title_size = 20
self.confPop.title_align = 'center'
self.confPop.auto_dismiss = False
self.confPop.size_hint = (None, None)
self.confPop.size = (250, 300)
#create popup-content
confBox = BoxLayout()
confBox.orientation = 'vertical'
confBox.spacing = 5
confBox.padding = (10, 30, 10, 30)
confBox.add_widget(Label(text = 'Please confirm your action!',
color = (1, 1, 1, 1), #white text
pos_hint = {'center_x': .5, 'center_y': .5},
halign = 'center'))
confBox.add_widget(Button(text = 'Accept',
#size_hint=(1,0.5),
on_release = lambda *args: confAcc()))
confBox.add_widget(Button(text='Cancel',
on_release = lambda *args: self.confPop.dismiss()))
#inner function
def confAcc():
print('IMPLEMENT CLOCK CALLBACK')
self.save_config_to_file_()
self.confPop.dismiss()
#add content, open popup
self.confPop.content = confBox
self.confPop.open()
def chooseFilePopup(self):
""" Popup to chose file for picture-screen """
#create popup
self.chosePop = Popup()
self.chosePop.title = '[b]Choose picture file to display on XYZ\u00AE[/b]'
self.chosePop.title_color = (0, 0, 0, 1)
self.chosePop.title_size = 20
self.chosePop.title_align = 'center'
self.chosePop.auto_dismiss = False
self.chosePop.size_hint = (None, None)
self.chosePop.size = (600, 600)
self.chosePop.background = '' #white background basis
self.chosePop.background_color = (71/255, 118/255, 176/255, 0.75) #Blue, 80% transparency
#create popup-content
choseBox = BoxLayout()
choseBox.orientation = 'vertical'
choseBox.spacing = 6
fichoo = FileChooserListView(dirselect = True, path = './')
choseBox.add_widget(Label(text = 'Warning!\n\nMake sure to chose *.png file with resolution 640x480!!', size_hint_y=0.3,
font_size = '22',
halign = 'center'))
choseBox.add_widget(fichoo)
choseBox.add_widget(Button(text='Load File',
size_hint_y = 0.2,
size_hint_x = 0.5,
pos_hint = {'center_x': 0.5},
on_release = lambda *args: load_from_filechooser(fichoo.selection)))
choseBox.add_widget(Button(text='Cancel',
size_hint_y = 0.2,
size_hint_x = 0.5,
pos_hint = {'center_x': 0.5},
on_release = lambda *args: self.chosePop.dismiss()))
#inner function
def load_from_filechooser(selection):
print(str(selection[0]))
print('demo(decision, self.s, show)')
if self.check():
demo(str(selection[0]), self.s, 0)
self.change_label('Image from file ' + str(selection[0] + ' displayed'))
self.ids.pictureBox.source = selection[0]
self.chosePop.dismiss()
self.chosePop.content = choseBox
self.chosePop.open()
#Creates the App Class
class GUI(App):
#Build Function:
def restart(self):
BoxL.change_label(BoxL, '### RESTARTING GUI .. ###')
restart_program()
def build(self):
""" GUI Window Configuration """
self.title = 'MyApp\u00AE' #\u00AE for registered trademark
#self.icon = 'trl_icon.ico'
Config.set('kivy','window_icon','GUI\icon2.png')
Config.set('graphics','width','1376') #1280
Config.set('graphics','height','774') #720
Config.set('kivy','exit_on_escape','0') #Disables ESC to exit GUI
fonts = ['GUI/fonts/calibril.ttf',
'GUI/fonts/calibrili.ttf',
'GUI/fonts/calibrilb.ttf',
'GUI/fonts/calibrilz.ttf']
Config.set('kivy','default_font',fonts)
Config.write()
return BoxL()
if __name__ == "__main__":
GUI().run()