从外螺纹更新带纹理的矩形

时间:2019-05-16 23:12:57

标签: kivy

我正在尝试编写一个程序,该程序将具有从matplotlib生成的动画。这个想法是将Rectangle写到画布上,并使用blit_buffer更新其纹理。因此,在调用app.run()之后,外部线程会调用Rectangle的update函数来更新该纹理。

有问题的主类,其中static_spin_globe_arr是一个numpy数组

class SpinGlobeRectangle(Rectangle):

    def __init__(self, **kwargs):
        super(SpinGlobeRectangle, self).__init__(**kwargs)

        self.lon_float = 0
        self.lon_idx = 0
        self.spin_speed = 5.5

        self.texture = Texture.create(size=(400, 400), colorfmt='rgba')
        self.spin_update(time_delta=0)

    def spin_update(self, time_delta):
        self.lon_float += 360 * time_delta / self.spin_speed
        if self.lon_float >= 360:
            self.lon_float -= 360

        self.lon_idx = round(self.lon_float * static_spin_globe_arr.shape[0] / 360) % static_spin_globe_arr.shape[0]
        self.texture.blit_buffer(static_spin_globe_arr[self.lon_idx, :, :, :].tostring(), colorfmt='rgba', bufferfmt='ubyte')
        # self.pos = (self.pos[0]+1,self.pos[1])

相关标题屏幕课程

class TitleScreen(Screen):

    def __init__(self, window_size, **kwargs):
        super(TitleScreen, self).__init__(**kwargs)

        self.layout = FloatLayout(size_hint=(1, 1))
        self.add_widget(self.layout)

        btn_spacing = 5
        btn_height = 40
        btn_width = 300

        title_bar_size = (btn_width, 3 * (btn_spacing + btn_height) - btn_spacing)
        title_bar_pos = (2 * btn_spacing, (window_size[1] - title_bar_size[1]) / 2)

        self.title_bar_layout = BoxLayout(size=title_bar_size, pos=title_bar_pos, size_hint=(None, None), orientation='vertical', spacing=btn_spacing)
        self.layout.add_widget(self.title_bar_layout)

        self.new_game_button = Button(text='x', font_size=14)
        self.load_game_button = Button(text='y', font_size=14)
        self.credits_game_button = Button(text='z', font_size=14)

        self.title_bar_layout.add_widget(self.new_game_button)
        self.title_bar_layout.add_widget(self.load_game_button)
        self.title_bar_layout.add_widget(self.credits_game_button)

        with self.canvas.before:
            Color(0,.5,.5, mode='rgb')
            self.background_rect = Rectangle(size=window_size)

            glb_size = (window_size[0] - title_bar_size[0] - 8 * btn_spacing,) * 2
            glb_pos = (window_size[0] - 2 * btn_spacing - glb_size[0], (window_size[1] - glb_size[1]) / 2)

            Color(1, 1, 1, mode='rgb')
            self.spin_globe_rect = SpinGlobeRectangle(size=glb_size, pos=glb_pos)

相关的应用定义

class AeroSimApp(App):

    def __init__(self, title, window_size, **kwargs):
        super(AeroSimApp, self).__init__(**kwargs)

        self.screenManager = ScreenManager()

        self.loadScreen = LoadScreen(name='LOAD_SCREEN', window_size=window_size)
        self.titleScreen = TitleScreen(name='TITLE_SCREEN', window_size=window_size)
        self.mainScreen = MainScreen(name='MAIN_SCREEN', window_size=window_size)

        self.screenManager.add_widget(self.loadScreen)
        self.screenManager.add_widget(self.titleScreen)
        self.screenManager.add_widget(self.mainScreen)

        self.screenManager.current = 'LOAD_SCREEN'
        # self.screenManager.current_screen = 'LOAD_SCREEN'

        Window.size = window_size

        # kivy.config.Config.set('graphics', 'width', window_size[0])
        # kivy.config.Config.set('graphics', 'height', window_size[1])
        # kivy.config.Config.write()

        self.title = title

    def build(self):
        return self.screenManager

如何从外部线程调用该类(该类封装在循环中)

    def doTitleScreenGraphics(self, first_loop, time_delta):
        self.kivyApp.titleScreen.spin_globe_rect.spin_update(time_delta=time_delta)
        self.kivyApp.titleScreen.canvas.ask_update()

这是其他上下文的图片 Here is an image for additional context

我一直在尝试各种GUI库,但尚未决定使用kivy。我不想将所有功能都移到应用程序代码中。

我运行了程序,外线程通过了spin_update函数,但是纹理没有改变。当我取消注释更改pos的行时,矩形pos在屏幕上更新。如何实现纹理变化?

一个次要的但不那么重要的问题是,如何在所需的时间间隔内最好地实现这一更改,在此时间间隔内所有对象都被更新?我不认为我目前正在这样做。

我看过Updating a textured rectangle in Kivy after the texture changes,这似乎是我的问题,但是坦率地说,我不理解ObjectProperty类,也不想使用Kivy的Clock类,因为我已经有了一个有效的设置没有显示在提供的代码中。

编辑:我也看过How to update a texture from array in Kivy?,但是每帧重新创建对象似乎很浪费。 (编辑:所以我尝试了这个,充其量只有一个黑色的矩形。否则,崩溃或没有更新图像)

编辑:我现在认为In Kivy, is there a way to dynamically change the shape of a texture?是我想要的。我正在研究它,但是文档令人困惑。

编辑:我看不到没有在应用程序的构建函数中涉及时钟的方法,并且将我的一些代码合并到kivy代码中(因为同一任务的两个时钟是多余的)。 :(积极地说,似乎需要在时钟内完成的唯一一行是重载函数调用,因此使用Clock.schedule_once(self.kivyApp.custom_update)可能必须这样做。:/

类似...

    def update(self, dt):
        self.titleScreen.spin_globe_rect.spin_update(dt)
        self.titleScreen.spin_globe_rect.reload(self.titleScreen.spin_globe_rect.texture)
        self.titleScreen.canvas.ask_update()
        pass

    def build(self):
        Clock.schedule_interval(self.update, 1/30)
        return self.screenManager

SpinGlobeRectangle已更新为

的位置
class SpinGlobeRectangle(Rectangle):

    def __init__(self, **kwargs):
        super(SpinGlobeRectangle, self).__init__(**kwargs)

        self.lon_float = 0
        self.lon_idx = 0
        self.spin_speed = 5.5

        self.texture = Texture.create(size=(400, 400), colorfmt='rgba')
        self.spin_update(time_delta=0)

    def spin_update(self, time_delta):
        self.lon_float += 360 * time_delta / self.spin_speed
        if self.lon_float >= 360:
            self.lon_float -= 360

        self.lon_idx = round(self.lon_float * static_spin_globe_arr.shape[0] / 360) % static_spin_globe_arr.shape[0]
        self.reload(self.texture)

    def reload(self, texture):
        texture.blit_buffer(static_spin_globe_arr[self.lon_idx, :, :, :].tostring(), colorfmt='rgba', bufferfmt='ubyte')

0 个答案:

没有答案