【问题标题】:kivy Popup fails under Windows 10kivy Popup 在 Windows 10 下失败
【发布时间】:2016-12-06 01:32:57
【问题描述】:

这类似于关于 Kivy 早期版本的问题:Kivy Popup rendering issue 但是没有找到有用的答案。

这是我在使用 Kivy 1.9.1 和 Python 2.7.12 的 Windows 10 下使用 Popup 时遇到的问题的简化版本。每次打开弹出窗口时都不会出现问题,但大约有 50% 的时间会出现此问题。症状是弹出窗口的布局有时不正确,有时甚至完全不正确(即按钮文本甚至不在按钮上,或者标题甚至不在弹出窗口内)。我正在使用线程和队列来等待弹出窗口完成。要查看问题,请运行 kivyplay.py 脚本,单击“开始游戏线程”,然后单击弹出窗口中的“确定”按钮。弹出窗口会出现 4 次,如果问题没有出现,您可以再次点击“开始游戏线程”。我看到的警告信息是:

[WARNING           ] <kivy.uix.gridlayout.GridLayout object at 0x000000000ADDF118> have no cols or rows set, layout is not triggered.

我没有直接使用任何 GridLayout 小部件。在 Ubuntu 16.04 和相同版本的 Kivy 和 Python 下,同样的代码可以完美运行且没有警告。

我尝试了许多不同的方法:

  • 使用线程锁代替队列
  • 在 MyPopup 中创建弹出窗口而不是子类化
  • 在 MyPopup 中创建 ModalView 而不是子类化
  • 完全消除pop_test.kv,只使用一个Button作为Popup内容

使用 ModalView 可以消除 GridLayout 警告,但不能解决问题。似乎弹出布局越复杂,错误出现的频率就越高,所以这个简单的例子并没有经常显示错误。难道我做错了什么?关于如何让弹出窗口正确呈现的任何想法?我应该将此报告为错误吗?

谢谢!!!

kivyplay.kv:

from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout

from game_thread import GameThread

class KivyPlay(RelativeLayout):

    def __init__(self, *args):
        RelativeLayout.__init__(self, *args)

    def start_thread(self):
        print "Got a click"
        gameThread = GameThread()
        gameThread.start()

    def quit(self):
        app.stop()

class PlayApp(App):
    def build(self):
        return KivyPlay()

if __name__ == '__main__':
    app = PlayApp()
    app.run()

game_thread.py:

from threading import *
from Queue import Queue

from my_popup import MyPopup

class GameThread(Thread):

    def __init__(self):
        Thread.__init__(self, name="GameThread")
        self.daemon = True
        self.queue = Queue()


    def run(self):

        for i in range(0,4):
            popup = MyPopup("Popup Test", self.queue, i)
            popup.open()
            popReturn = self.queue.get(True)
            print "Popup #" + str(i) + " returned " + str(popReturn)

my_popup.ky:

from kivy.uix.popup import Popup
from kivy.lang import Builder

class MyPopup(Popup):

    def __init__(self, theTitle, theQueue, playerNumber):
        self.queue = theQueue
        title = theTitle
        self.player = playerNumber
        myContent = Builder.load_file('pop_test.kv')
        self.button = myContent.ids["ok_button"]
        self.button.bind(on_press=self.okButton)
        Popup.__init__(self, title=title, title_align='center', content=myContent, size_hint=(None, None), size=(400,150), auto_dismiss=False)

    def okButton(self, *args):
        self.queue.put(self.player, False)
        self.dismiss()

play.kv:

#:kivy 1.9.1

<KivyPlay>:
    canvas:
        Color:
            rgba: 1, 0, 0, 1
        Rectangle:
            pos: self.pos
            size: self.size
    Button:
        size_hint: 0.25, 0.25
        pos_hint: {'center_x': 0.5, 'y': 0.5}
        text: 'Start Game Thread'
        on_press: root.start_thread()

    Button:
        size_hint: 0.25, 0.25
        pos_hint: {'center_x': 0.5, 'y': 0.25}
        text: 'Quit'
        on_press: root.quit()

pop_test.kv:

#:kivy 1.9.1

BoxLayout:
    orientation: 'vertical'

    AnchorLayout:
        anchor_x: 'center'
        anchor_y: 'center'
        Button:
            id: ok_button
            size_hint: 0.2, 0.2
            text: 'OK'

【问题讨论】:

  • 您的评论有何意义?创建此问题时,我遵循了您链接中的指南。它是完整的、最小的和可验证的。
  • 重点是,您不需要 4 个文件来制作弹出窗口的最小示例。代码中实现了很多不相关的东西,比如线程和队列。您只需要一个简单的 Popup 即可重现您的错误。
  • @JohnAnderson 我知道这是一篇旧帖子,但您找到解决方法了吗?
  • 我终于确定问题是我在主线程以外的线程上做GUI操作,以及下面回答中指出的错误。

标签: python multithreading popup kivy


【解决方案1】:

在运行__init__ 时,您需要在顶部调用super(),以确保在开始覆盖类中的内容之前启动小部件。

所以我更改了你的三个文件。而且我没有看到任何错误(在win 10上测试)。您可以忽略网格布局警告。

kivy_play.py:

from kivy.app import App
from kivy.uix.relativelayout import RelativeLayout

from game_thread import GameThread

class KivyPlay(RelativeLayout):

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

    def start_thread(self):
        print "Got a click"
        gameThread = GameThread()
        gameThread.start()

    def quit(self):
        app.stop()

class PlayApp(App):
    def build(self):
        return KivyPlay()

if __name__ == '__main__':
    app = PlayApp()
    app.run()

还有 my_popup.py:

from kivy.uix.popup import Popup
from kivy.lang import Builder

Builder.load_file('pop_test.kv')

class MyPopup(Popup):

    def __init__(self, theTitle, theQueue, playerNumber,**kwargs):
        super(MyPopup,self).__init__(**kwargs)
        self.title = theTitle
        self.title_align='center'
        self.queue = theQueue
        self.player = playerNumber
        self.size_hint=(None, None)
        self.size=(400,150)
        self.auto_dismiss=False


    def okButton(self, *args):
        self.queue.put(self.player, False)
        self.dismiss()

pop_test.kv:

#:kivy 1.9.1

<MyPopup>:
    BoxLayout:
        orientation: 'vertical'

        AnchorLayout:
            anchor_x: 'center'
            anchor_y: 'center'
            Button:
                id: ok_button
                size_hint: 0.2, 0.2
                text: 'OK'
                on_press:root.okButton()

【讨论】:

  • 感谢您的帮助,但它并没有解决问题。我仍然偶尔会看到糟糕的布局。也许我最初估计的 50% 发生率有点高,但我经常看到它不会将我的代码提供给打算在 Windows 10 上运行它的客户。我还尝试使用 kivy 的开发版本(v1.1)。 9.2-dev0),但没有区别。
  • @JohnAnderson 好的,我会尝试多次运行它。也许我发现了什么。
  • 我决定捕获错误渲染的弹出窗口的图像。尝试使用 Widget.export_to_png() 或 Window.screenshot() 也失败了。所以我最终使用了一个子进程来获取图像。代码与上面的代码有些不同,但这是预期的结果:!correct,这是一个典型的错误:!error 不确定我是否正确执行了这些图像链接。我怀疑问题可能与 NVIDIA 驱动程序有关。
猜你喜欢
  • 1970-01-01
  • 2018-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-26
  • 2019-05-20
  • 2017-08-28
相关资源
最近更新 更多