【问题标题】:Python tk(): No window appears when using in scripts (console works)Python tk():在脚本中使用时不出现窗口(控制台工作)
【发布时间】:2015-07-06 23:12:45
【问题描述】:

我对这个简单的脚本有以下问题:

from Tkinter import *
root = Tk()
while 1:
   pass

我认为,在第 2 行之后,每个人都希望出现一个 Tkinter 窗口。但事实并非如此! 如果我将此行放入 Python 控制台(没有无限循环),它就可以工作。

[我想在这里添加一张图片,但由于我是新人,我可以:-(]

但是运行脚本(在 Windows 资源管理器中双击 *.py 文件)只会导致一个空的 Python 控制台!

背景: 其实我想用Snack for Python。这是基于 Tkinter。这意味着我必须首先创建一个 Tk() 实例。在 Python 控制台中一切正常。但是我想用至少一个 Python 脚本编写一个更大的程序,因此我不能每次都将整个程序输入控制台:-)

我已经安装了 Python 2.7 和 Tcl/Tk 8.5(记住:它可以在控制台中运行)


编辑:所以这是我的解决方案:

首先,我创建一个 CSoundPlayer 类:

from Tkinter import*
import tkSnack

class CSoundPlayer:
    def __init__(self, callbackFunction):
        self.__activated = False
        self.__callbackFunction = callbackFunction
        self.__sounds = []
        self.__numberOfSounds = 0
        self.__root = Tk()
        self.__root.title("SoundPlayer")
        tkSnack.initializeSnack(self.__root)

    def __mainFunction(self):
        self.__callbackFunction()
        self.__root.after(1, self.__mainFunction)
        pass

    def activate(self):
        self.__activated = True
        self.__root.after(1, self.__mainFunction)
        self.__root.mainloop()

    def loadFile(self, fileName):
        if self.__activated:
            self.__sounds.append(tkSnack.Sound(load=fileName))
            self.__numberOfSounds += 1
            # return the index of the new sound
            return self.__numberOfSounds - 1
        else:
            return -1

    def play(self, soundIndex):
        if self.__activated:
            self.__sounds[soundIndex].play()
        else:
            return -1

然后,应用程序本身必须在一个类中实现,因此 main() 是在移交给 CSoundPlayer() 构造函数时定义的:

class CApplication:
    def __init__(self):
        self.__programCounter = -1
        self.__SoundPlayer = CSoundPlayer(self.main)
        self.__SoundPlayer.activate()

    def main(self):
        self.__programCounter += 1
        if self.__programCounter == 0:
            self.__sound1 = self.__SoundPlayer.loadFile("../mysong.mp3")
            self.__SoundPlayer.play(self.__sound1)
        # here the cyclic code starts:
        print self.__programCounter

CApplication()

如您所见,mainloop() 不是在构造函数中调用,而是在 activate() 方法中调用。这是因为 CApplication 永远不会获得对 CSoundPlayer 对象的引用,因为它停留在主循环中。 CApplication 类本身的代码会产生很多开销。实际的“应用程序代码”放在 CApplication.main() 中 - 只执行一次的代码由程序计数器控制。

现在我把它放到下一个层次,在 CApplication.main() 中放置一个 MIDI 设备的轮询过程。因此,我将使用 MIDI 命令作为播放声音文件的触发器。我希望性能足以应对适当的延迟。

您有什么优化建议吗?

【问题讨论】:

  • 使用 tkinter 提供的 mainloop 代替你自己的循环。删除您的 while 循环,并插入此代码:root.mainloop()。你应该看看一个很好的教程......
  • 显示窗口。但这不是我想要的。我需要 while 循环来轮询我的触发器输入以通过 Snack 播放声音文件。小吃文档并没有说需要 mainloop() 。我认为 Snack 只需要 Tk() 的一个实例,显示它并不重要。但是由于没有播放声音,我认为 Tk() 根本不起作用。所以我尝试了上面提到的简单脚本,没有任何零食,窗口也没有出现。此外,我想知道为什么我不需要控制台中的 mainloop()。
  • 那你想要什么?
  • 见上文。我编辑了评论。我在完成之前不小心按了 Enter :-)
  • 您将需要调用主循环,有关主循环的更多信息以及为什么不需要将其称为控制台请参阅thisthis。要在您通常使用 after() 的 Tkinter 主循环旁边运行无限循环,请参阅 thisthis 了解更多信息。

标签: python-2.7 tkinter window root tk


【解决方案1】:

您必须启动事件循环。如果没有事件循环,tkinter 就无法实际绘制窗口。删除while循环并用mainloop替换它:

from Tkinter import *
root = Tk()
root.mainloop()

如果您需要进行轮询(如问题的 cmets 中所述),请编写一个轮询函数,并使用 after 定期运行该函数:

def poll():
    <do the polling here>

    # in 100ms, call the poll function again
    root.after(100, poll)

您在控制台中不需要 mainloop 的原因取决于您所说的“控制台”。在 IDLE 中,也许还有其他一些交互式解释器,tkinter 在交互式运行时有一个特殊的模式,不需要你调用 mainloop。本质上,主循环就是控制台输入循环。

【讨论】:

  • 是的,我已经这样做了。但我不想让 poll() 方法知道根。所以我找到了一个将整个东西封装在一个类中并将 poll() 作为回调的解决方案。我会将解决方案作为代码添加到上面的问题中!
猜你喜欢
  • 2022-10-12
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 1970-01-01
  • 2023-02-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多