我正在为爱好编写一个卡拉OK软件,可下载YouTube视频,保存在数据库中并放入播放列表。代码是用Python编写的,我在Windows 10 64位机器上使用kivy作为用户界面。我搜索并搜索并搜索了互联网,找不到任何有类似问题的人:如果我只是将鼠标光标悬停在程序的kivy窗口上,界面会开始出现口吃,fps会下降很多。
我只会放置Widget类,因为代码太大了:
class InterfaceWidget(BoxLayout):
#Definitions for properties of the graphic interface.
FONT_NAME_1 = StringProperty('NotoSansCJKjp-Medium.otf')
FONT_NAME_2 = StringProperty('NotoSansMonoCJKjp-Regular.otf')
current_title_prop = ObjectProperty(None)
current_artist_prop = ObjectProperty(None)
playlist_list_prop = ObjectProperty(None)
results_list_prop = ObjectProperty(None)
search_bar_prop = ObjectProperty(None)
play_button_prop = ObjectProperty(None)
stop_button_prop = ObjectProperty(None)
restart_button_prop = ObjectProperty(None)
remove_button_prop = ObjectProperty(None)
search_title_button_prop = ObjectProperty(None)
search_artist_button_prop = ObjectProperty(None)
current_time_prop = ObjectProperty(None)
current_duration_prop = ObjectProperty(None)
youtube_status_prop = ObjectProperty(None)
counter_prop = ObjectProperty(None)
current_title = ''
current_artist = ''
current_time = ''
current_duration = ''
results_list = ''
search_bar = ''
playlist_list = ''
youtube_status = ''
current_path = ''
category_state = None
processes_started = False
already_focused = False
karaoke = KaraokeGuts()
i = 0
remaining_time = WAIT_TO_NEXT_SONG
changed = {
'title': False,
'artist': True,
'current_time': False,
'length': False,
'queue': True,
'playlist': False,
'download_status': False,
'search_bar': False,
'search_result': False,
'buttons': True,
}
def update(self, dt):
print(dt)###MAIN LOOP###
if self.processes_started == False:
self.configure_threads()
self.processes_started = True
self.next_music()
self.get_search_results()
self.get_add_title()
if self.changed['title'] == True:
self.current_title_prop.text = self.update_title()
self.changed['title'] = False
if self.changed['artist'] == True:
self.current_artist_prop.text = self.update_artist()
self.changed['artist'] = False
self.current_time_prop.text = self.update_time()
if self.changed['length'] == True:
self.current_duration_prop.text = self.update_duration()
self.changed['length'] = False
if self.changed['queue'] == True:
self.counter_prop.text = self.update_counter()
self.changed['queue'] = False
if self.changed['playlist'] == True:
self.playlist_list_prop.text = self.update_playlist()
self.changed['playlist'] = False
self.youtube_status_prop.text = self.update_download_status()
if self.changed['search_bar'] == True:
self.search_bar_prop.text = self.update_search_bar()
self.changed['search_bar'] = False
if self.changed['search_result'] == True:
self.results_list_prop.text == self.update_results_list()
self.changed['search_result'] = False
if self.changed['buttons'] == True:
self.update_buttons()
self.changed['buttons'] = False
###
###DEFINITION OF SYNCRONOUS UPDATES METHODS###
def update_title(self):
if self.karaoke.playing in ('playing', 'paused'):
return self.current_title
else:
return ''
def update_artist(self):
if self.karaoke.playing in ('playing', 'paused'):
return self.current_artist
else:
if self.karaoke.counter == 0:
return 'Fila vazia: adicione uma música para começar'
def update_duration(self):
if self.karaoke.playing in ('playing', 'paused'):
return self.current_duration
else:
return ''
def update_time(self):
if self.karaoke.playing in ('playing', 'paused'):
self.q_put.put(['','get_time'])
ctime = self.q_get.get()
self.current_time = self.karaoke.format_seconds(float(ctime))
else:
self.current_time = ''
return self.current_time
def update_counter(self):
return str(self.karaoke.counter)
def update_download_status(self):
download_status = self.karaoke.downloaded_percent
if download_status == None:
self.youtube_status = ''
elif download_status == 'ERROR':
self.youtube_status = 'Um erro ocorreu ao baixar o vídeo =('
elif download_status == 'UNKNOWN_FILESIZE':
self.youtube_status = 'Baixando, mas tamanho de arquivo desconhecido'
elif download_status == 'FINISHED':
self.youtube_status = 'Vídeo baixado!'
else:
self.youtube_status = 'Baixando: {:2.1f}%'.format(download_status)
#return self.youtube_status
self.i += 1
return str(self.i)
def update_playlist(self):
playlist_aux2 = ''
for i in self.karaoke.playlist:
playlist_aux = playlist_aux2 + '[size=20][color=#FFFFFF][font=NotoSansCJKjp-Medium.otf]' + escape_markup(i['title']) + '[/color][/size][/font]' + '\n'
playlist_aux = playlist_aux + '[size=15][color=#c5cacd][font=NotoSansCJKjp-Medium.otf]' + escape_markup(i['artist']) + ' ' + escape_markup('[') + self.karaoke.format_seconds(i['length']) + escape_markup(']') + '[/color][/size][/font]' + '\n'
playlist_aux2 = playlist_aux
self.playlist_list = playlist_aux2
return self.playlist_list
def update_search_bar(self):
return self.search_bar
def update_results_list(self):
return self.results_list
def update_buttons(self):
if self.karaoke.playing not in ('playing','paused'):
self.play_button_prop.disabled = True
self.stop_button_prop.disabled = True
self.restart_button_prop.disabled = True
else:
self.play_button_prop.disabled = False
self.stop_button_prop.disabled = False
self.restart_button_prop.disabled = False
if self.karaoke.counter == 0:
self.remove_button_prop.disabled = True
else:
self.remove_button_prop.disabled = False
###DEFINITIONS OF SYNCRONOUS NON-UPDATE METHODS###
def next_music(self):
if self.karaoke.counter != 0 and self.karaoke.playing not in ('playing','paused'):
self.q_put.put([self.karaoke.playlist[0]['path'], 'play'])
self.current_title = self.karaoke.playlist[0]['title']
self.current_artist = self.karaoke.playlist[0]['artist']
self.current_duration = self.karaoke.format_seconds(float(self.karaoke.playlist[0]['length']))
self.current_time = '00:00'
self.remove_title()
self.karaoke.playing = 'playing'
self.changed.update(title = True, artist = True, current_time = True, length = True, playlist = True, queue = True, buttons = True)
def get_search_results(self):
try:
result = self.q_search_get.get(block = False)
if result == 'SEARCH_NOT_FOUND':
self.results_list = 'Busca não encontrada, tente outro termo.'
else:
results_aux = self.results_list + '[size=15][color=#FFFFFF][font=NotoSansCJKjp-Medium.otf]' + escape_markup(result['title']) + '[/color][/size][/font]' + '\n'
results_aux = results_aux + '[size=12][color=#c5cacd][font=NotoSansCJKjp-Medium.otf]' + escape_markup(result['artist']) + '[/color][/size][/font]' + '\n'
self.results_list = results_aux
self.changed['search_result'] = True
except thq.Empty:
pass
def get_add_title(self):
try:
metadata = self.q_youtube_get.get(block = False)
if metadata != 'ERROR':
self.karaoke.playlist.append(metadata)
self.karaoke.counter += 1
self.changed.update(queue = True, playlist = True)
# else:
# self.youtube_status = 'Erro ocorreu ao baixar o vídeo.'
# changed
except:
pass
###DEFINITIONS OF ASYNCRONOUS METHODS##
def search(self):
if self.search_bar_prop.text.startswith('https://') == False and self.search_bar_prop.text != '':
self.results_list = ''
if self.search_artist_button_prop.state == 'normal' and self.search_title_button_prop.state == 'down':
input_text = {'fieldname': 'title', 'search_term': self.search_bar.text}
self.q_search_put.put(input_text)
elif self.search_artist_button_prop.state == 'down' and self.search_title_button_prop.state == 'normal':
input_text = {'fieldname': 'title', 'search_term': self.search_bar.text}
self.q_search_put.put(input_text)
elif self.search_bar_prop.text.startswith('https://') == True and (self.search_artist_button_prop.state == 'down' or self.search_title_button_prop.state == 'down'):
self.results_list = '[size=15][color=#FFFFFF][font=NotoSansCJKjp-Medium.otf]Desative as opções de busca antes de adicionar um link.[/color][/size][/font]'
elif self.search_bar_prop.text == '':
self.results_list = ''
self.changed['search_result'] = True
def search_state(self, category):
if category == 'title':
self.search_artist_button_prop.state = 'normal'
if category == 'artist':
self.search_title_button_prop.state = 'normal'
def add_title(self):
self.q_youtube_put.put(self.search_bar_prop.text, block = False)
self.search_bar_prop.focus = False
self.search_bar_prop.do_cursor_movement('cursor_home')
self.already_focused = False
self.search_bar = 'Digite um termo de busca ou cole um link'
self.changed.update(search_bar = True, download_status = True)
def remove_title(self):
self.karaoke.remove_title()
self.changed.update(queue = True, playlist = True)
#The following methods executes on VLC separate process.
def stop(self):
self.q_put.put(['','stop'])
self.q_put.put(['','get_state'])
state = self.q_get.get()
self.karaoke.playing = state
self.changed.update(title = True, artist = True, current_time = True, current_duration = True, playlist = True, buttons = True)
def play(self):
self.q_put.put(['','get_state'])
self.karaoke.playing = self.q_get.get()
if self.karaoke.playing == 'paused':
self.q_put.put(['','play'])
self.play_button_prop.background_normal = "buttons\\pause.png"
self.play_button_prop.background_down = "buttons\\paused_clicked.png"
print(1)
else:
self.q_put.put(['','pause'])
self.play_button_prop.background_normal = "buttons\\play.png"
self.play_button_prop.background_down = "buttons\\play_clicked.png"
print(2)
def restart(self):
self.q_put.put([self.current_path,'play'])
def search_bar_focused(self, focus):
if focus == True and self.already_focused == False:
self.search_bar_prop.text = ''
self.already_focused = True
###EXECUTED ONLY ONCE METHOD###
def configure_threads(self):
if self.processes_started == False:
self.media = Media()
self.q_get = mp.Queue()
self.q_put = mp.Queue()
self.vlc_process = mp.Process(target = self.media.vlc, args = (self.q_put, self.q_get,))
self.vlc_process.daemon = True
self.vlc_process.start()
self.q_youtube_get = thq.Queue()
self.q_youtube_put = thq.Queue()
self.th_youtube = th.Thread(target = self.karaoke.add_title, args = (self.q_youtube_put, self.q_youtube_get,))
self.th_youtube.daemon = False
self.th_youtube.start()
self.q_search_get = thq.Queue()
self.q_search_put = thq.Queue()
self.th_search = th.Thread(target = self.karaoke.yield_search_to_queue, args = (self.q_search_put, self.q_search_get,))
self.th_search.daemon = True
self.th_search.start()
self.processes_started = True
update
方法由Clock.schedule_interval(iw.update, 0)
安排。每个属性都是UI中的交互式小部件(属性太多?)。
编辑:这是我的kivy日志:
[INFO ] [Kivy ] v1.10.0
[INFO ] [Python ] v3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit (AMD64)]
[INFO ] [Factory ] 194 symbols loaded
[DEBUG ] [Cache ] register <kv.lang> with limit=None, timeout=None
[DEBUG ] [Cache ] register <kv.image> with limit=None, timeout=60
[DEBUG ] [Cache ] register <kv.atlas> with limit=None, timeout=None
[INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored)
[DEBUG ] [Cache ] register <kv.texture> with limit=1000, timeout=60
[DEBUG ] [Cache ] register <kv.shader> with limit=1000, timeout=3600
[DEBUG ] [App ] Loading kv <.\karaoke.kv>
[DEBUG ] [App ] kv <.\karaoke.kv> not found
[INFO ] [OSC ] using <thread> for socket
[INFO ] [Window ] Provider: sdl2
[INFO ] [GL ] Using the "OpenGL" graphics system
[INFO ] [GL ] GLEW initialization succeeded
[DEBUG ] [GL ] available extensions: b'GL_AMDX_debug_output GL_AMDX_vertex_shader_tessellator GL_AMD_conservative_depth GL_AMD_debug_output GL_AMD_depth_clamp_separate GL_AMD_draw_buffers_blend GL_AMD_multi_draw_indirect GL_AMD_name_gen_delete GL_AMD_performance_monitor GL_AMD_pinned_memory GL_AMD_query_buffer_object GL_AMD_sample_positions GL_AMD_seamless_cubemap_per_texture GL_AMD_shader_stencil_export GL_AMD_shader_trace GL_AMD_texture_cube_map_array GL_AMD_texture_texture4 GL_AMD_transform_feedback3_lines_triangles GL_AMD_vertex_shader_layer GL_AMD_vertex_shader_tessellator GL_AMD_vertex_shader_viewport_index GL_ARB_ES2_compatibility GL_ARB_ES3_1_compatibility GL_ARB_ES3_compatibility GL_ARB_arrays_of_arrays GL_ARB_base_instance GL_ARB_blend_func_extended GL_ARB_buffer_storage GL_ARB_clear_buffer_object GL_ARB_clear_texture GL_ARB_clip_control GL_ARB_color_buffer_float GL_ARB_compatibility GL_ARB_compressed_texture_pixel_storage GL_ARB_compute_shader GL_ARB_conditional_render_inverted GL_ARB_conservative_depth
GL_ARB_copy_buffer GL_ARB_copy_image GL_ARB_cull_distance GL_ARB_debug_output GL_ARB_depth_buffer_float GL_ARB_depth_clamp GL_ARB_depth_texture GL_ARB_derivative_control GL_ARB_direct_state_access GL_ARB_draw_buffers GL_ARB_draw_buffers_blend GL_ARB_draw_elements_base_vertex GL_ARB_draw_indirect GL_ARB_draw_instanced GL_ARB_enhanced_layouts GL_ARB_explicit_attrib_location GL_ARB_explicit_uniform_location GL_ARB_fragment_coord_conventions GL_ARB_fragment_layer_viewport GL_ARB_fragment_program GL_ARB_fragment_program_shadow GL_ARB_fragment_shader GL_ARB_framebuffer_no_attachments GL_ARB_framebuffer_object GL_ARB_framebuffer_sRGB GL_ARB_geometry_shader4 GL_ARB_get_program_binary GL_ARB_get_texture_sub_image GL_ARB_gpu_shader5 GL_ARB_gpu_shader_fp64 GL_ARB_half_float_pixel GL_ARB_half_float_vertex GL_ARB_imaging GL_ARB_instanced_arrays GL_ARB_internalformat_query GL_ARB_internalformat_query2 GL_ARB_invalidate_subdata GL_ARB_map_buffer_alignment GL_ARB_map_buffer_range GL_ARB_multi_bind GL_ARB_multi_draw_indirect GL_ARB_multisample GL_ARB_multitexture GL_ARB_occlusion_query GL_ARB_occlusion_query2 GL_ARB_pipeline_statistics_query GL_ARB_pixel_buffer_object GL_ARB_point_parameters GL_ARB_point_sprite GL_ARB_program_interface_query GL_ARB_provoking_vertex GL_ARB_query_buffer_object GL_ARB_robust_buffer_access_behavior GL_ARB_sample_shading GL_ARB_sampler_objects GL_ARB_seamless_cube_map GL_ARB_seamless_cubemap_per_texture GL_ARB_separate_shader_objects GL_ARB_shader_atomic_counters GL_ARB_shader_bit_encoding GL_ARB_shader_image_load_store GL_ARB_shader_image_size GL_ARB_shader_objects GL_ARB_shader_precision GL_ARB_shader_stencil_export GL_ARB_shader_storage_buffer_object GL_ARB_shader_subroutine GL_ARB_shader_texture_image_samples GL_ARB_shader_texture_lod GL_ARB_shading_language_100 GL_ARB_shading_language_420pack GL_ARB_shading_language_packing GL_ARB_shadow GL_ARB_shadow_ambient GL_ARB_stencil_texturing GL_ARB_sync GL_ARB_tessellation_shader GL_ARB_texture_barrier GL_ARB_texture_border_clamp GL_ARB_texture_buffer_object GL_ARB_texture_buffer_object_rgb32 GL_ARB_texture_buffer_range GL_ARB_texture_compression GL_ARB_texture_compression_bptc GL_ARB_texture_compression_rgtc GL_ARB_texture_cube_map GL_ARB_texture_cube_map_array GL_ARB_texture_env_add GL_ARB_texture_env_combine GL_ARB_texture_env_crossbar GL_ARB_texture_env_dot3 GL_ARB_texture_float GL_ARB_texture_gather GL_ARB_texture_mirror_clamp_to_edge GL_ARB_texture_mirrored_repeat GL_ARB_texture_multisample GL_ARB_texture_non_power_of_two GL_ARB_texture_query_levels GL_ARB_texture_query_lod GL_ARB_texture_rectangle GL_ARB_texture_rg GL_ARB_texture_rgb10_a2ui GL_ARB_texture_snorm GL_ARB_texture_stencil8 GL_ARB_texture_storage GL_ARB_texture_storage_multisample GL_ARB_texture_swizzle GL_ARB_texture_view GL_ARB_timer_query GL_ARB_transform_feedback2 GL_ARB_transform_feedback3 GL_ARB_transform_feedback_instanced GL_ARB_transform_feedback_overflow_query GL_ARB_transpose_matrix GL_ARB_uniform_buffer_object GL_ARB_vertex_array_bgra GL_ARB_vertex_array_object GL_ARB_vertex_attrib_64bit GL_ARB_vertex_attrib_binding GL_ARB_vertex_buffer_object GL_ARB_vertex_program GL_ARB_vertex_shader GL_ARB_vertex_type_10f_11f_11f_rev GL_ARB_vertex_type_2_10_10_10_rev GL_ARB_viewport_array GL_ARB_window_pos GL_ATI_draw_buffers GL_ATI_envmap_bumpmap GL_ATI_fragment_shader GL_ATI_separate_stencil GL_ATI_texture_compression_3dc GL_ATI_texture_env_combine3 GL_ATI_texture_float GL_ATI_texture_mirror_once GL_EXT_abgr GL_EXT_bgra GL_EXT_bindable_uniform GL_EXT_blend_color GL_EXT_blend_equation_separate GL_EXT_blend_func_separate GL_EXT_blend_minmax GL_EXT_blend_subtract GL_EXT_compiled_vertex_array GL_EXT_copy_buffer GL_EXT_copy_texture GL_EXT_direct_state_access GL_EXT_draw_buffers2 GL_EXT_draw_instanced GL_EXT_draw_range_elements GL_EXT_fog_coord GL_EXT_framebuffer_blit GL_EXT_framebuffer_multisample GL_EXT_framebuffer_object GL_EXT_framebuffer_sRGB GL_EXT_geometry_shader4 GL_EXT_gpu_program_parameters GL_EXT_gpu_shader4 GL_EXT_histogram GL_EXT_multi_draw_arrays GL_EXT_packed_depth_stencil GL_EXT_packed_float GL_EXT_packed_pixels GL_EXT_pixel_buffer_object GL_EXT_point_parameters GL_EXT_polygon_offset_clamp GL_EXT_provoking_vertex GL_EXT_rescale_normal GL_EXT_secondary_color GL_EXT_separate_specular_color GL_EXT_shader_image_load_store GL_EXT_shader_integer_mix GL_EXT_shadow_funcs GL_EXT_stencil_wrap GL_EXT_subtexture GL_EXT_texgen_reflection GL_EXT_texture3D GL_EXT_texture_array GL_EXT_texture_buffer_object GL_EXT_texture_compression_bptc GL_EXT_texture_compression_latc GL_EXT_texture_compression_rgtc GL_EXT_texture_compression_s3tc GL_EXT_texture_cube_map GL_EXT_texture_edge_clamp GL_EXT_texture_env_add GL_EXT_texture_env_combine GL_EXT_texture_env_dot3 GL_EXT_texture_filter_anisotropic GL_EXT_texture_integer GL_EXT_texture_lod GL_EXT_texture_lod_bias GL_EXT_texture_mirror_clamp GL_EXT_texture_object GL_EXT_texture_rectangle GL_EXT_texture_sRGB GL_EXT_texture_sRGB_decode GL_EXT_texture_shared_exponent GL_EXT_texture_snorm GL_EXT_texture_storage GL_EXT_texture_swizzle GL_EXT_timer_query GL_EXT_transform_feedback GL_EXT_vertex_array GL_EXT_vertex_array_bgra GL_EXT_vertex_attrib_64bit
GL_IBM_texture_mirrored_repeat GL_KHR_context_flush_control GL_KHR_debug GL_KHR_robust_buffer_access_behavior GL_KHR_robustness GL_KTX_buffer_region GL_NV_blend_square GL_NV_conditional_render GL_NV_copy_depth_to_color GL_NV_copy_image GL_NV_depth_buffer_float GL_NV_explicit_multisample GL_NV_float_buffer GL_NV_half_float GL_NV_primitive_restart GL_NV_texgen_reflection GL_NV_texture_barrier GL_OES_EGL_image GL_SGIS_generate_mipmap GL_SGIS_texture_edge_clamp GL_SGIS_texture_lod GL_SUN_multi_draw_arrays GL_WIN_swap_hint WGL_EXT_swap_control'
[DEBUG ] [GL ] glShaderBinary is not available
[INFO ] [GL ] Backend used <glew>
[INFO ] [GL ] OpenGL version <b'4.5.13399 Compatibility Profile Context 15.201.1151.1008'>
[INFO ] [GL ] OpenGL vendor <b'ATI Technologies Inc.'>
[INFO ] [GL ] OpenGL renderer <b'AMD Radeon HD 5800 Series'>
[INFO ] [GL ] OpenGL parsed version: 4, 5
[INFO ] [GL ] Shading version <b'4.40'>
[INFO ] [GL ] Texture max size <16384>
[INFO ] [GL ] Texture max units <18>
[DEBUG ] [Shader ] Fragment compiled successfully
[DEBUG ] [Shader ] Vertex compiled successfully
[DEBUG ] [ImageSDL2 ] Load <E:\Python364\lib\site-packages\kivy\data\glsl\default.png>
[INFO ] [Window ] auto add sdl2 input provider
[INFO ] [Text ] Provider: sdl2
[DEBUG ] [Modules ] Start <monitor> with config {}
[DEBUG ] [Resource ] add <C:\WINDOWS\Fonts> in path list
[DEBUG ] [Resource ] add <E:\Python364\lib\site-packages\kivy\data\fonts> in path list
[INFO ] [Window ] virtual keyboard not allowed, single mode, not docked
[DEBUG ] [Cache ] register <textinput.label> with limit=None, timeout=60.0
[DEBUG ] [Cache ] register <textinput.width> with limit=None, timeout=60.0
[DEBUG ] [Atlas ] Load <E:\Python364\lib\site-packages\kivy\data\images\defaulttheme.atlas>
[DEBUG ] [Atlas ] Need to load 1 images
[DEBUG ] [Atlas ] Load <E:\Python364\lib\site-packages\kivy\data\images\defaulttheme-0.png>
[DEBUG ] [ImageSDL2 ] Load <E:\Python364\lib\site-packages\kivy\data\images\defaulttheme-0.png>
[INFO ] [GL ] NPOT texture support is available
[DEBUG ] [Base ] Create provider from mouse
[DEBUG ] [Base ] Create provider from wm_touch
[DEBUG ] [Base ] Create provider from wm_pen
[INFO ] [Base ] Start application main loop
[DEBUG ] [ImageSDL2 ] Load <F:\karaoke\buttons\restart_disabled.png>
[DEBUG ] [ImageSDL2 ] Load <F:\karaoke\buttons\stop_disabled.png>
[DEBUG ] [ImageSDL2 ] Load <F:\karaoke\buttons\pause_disabled.png>
[DEBUG ] [ImageSDL2 ] Load <F:\karaoke\buttons\remove_disabled.png>
[DEBUG ] [ImageSDL2 ] Load <F:\karaoke\buttons\add.png>
[DEBUG ] [ImageSDL2 ] Load <F:\karaoke\buttons\search_artist.png>
[DEBUG ] [ImageSDL2 ] Load <F:\karaoke\buttons\search_music.png>
[INFO ] [Kivy ] v1.10.0
[INFO ] [Python ] v3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit (AMD64)]
[INFO ] [Factory ] 194 symbols loaded
[DEBUG ] [Cache ] register <kv.lang> with limit=None, timeout=None
[DEBUG ] [Cache ] register <kv.image> with limit=None, timeout=60
[DEBUG ] [Cache ] register <kv.atlas> with limit=None, timeout=None
[INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored)
[DEBUG ] [Cache ] register <kv.texture> with limit=1000, timeout=60
[DEBUG ] [Cache ] register <kv.shader> with limit=1000, timeout=3600
最初我认为update
应该受到指责,因为我使用的是线程和队列,但我使用perf_counter()
来测量循环开始和结束之间的时间,所有措施都是低于1毫秒。另外,我计算fps计算计数器在1秒循环中递增的次数,并输出到标签小部件(考虑到1个循环= 1帧,为了我的目的,也许它与我们知道的fps不同) )。当鼠标未在窗口上方时,fps> 100;在窗口内,如果我只是让光标停下来,fps保持&gt;但是,如果我在窗口内移动光标,fps会下降,如果我在窗口上有更新,它会断断续续。在最坏的情况下,如果我不断移动鼠标光标,则fps会低于5. kivy的监视器模块的变化几乎与“my fps”相同,在最坏的情况下降至1以下。另一个例子,如果我在我的UI中的TextInput小部件中键入文本,这些字母将看起来像一个“旧的和慢的计算机”,最近显示,虽然键击没有丢失(看起来像缓冲区在内部工作)。
我只能得出结论知道某些东西阻挡了我的循环,可能是一些Kivy隐藏的例程,但我不能确定。我该如何解决这个问题?
感谢。