0

先前信息:我在 Mac 上。

问:如果我用 py2app 编译它以重新分发,如何从程序执行中获得类似终端的文本输出?

我的案例是一个复制大量大文件并需要一段时间来处理的程序,所以我希望每次复制每个文件时至少有一个输出通知。

如果我在命令行上运行它,这很容易,我可以打印一个新行。

但是当我做一个自给自足的包时,它只是在底部的底座上打开,没有窗口,完成后关闭。

一个简单的文本窗口就可以了。

提前致谢。

4

1 回答 1

0

如果你想创建一个简单的文本窗口,你需要选择一个 GUI 框架来做这件事。对于这么简单的事情,没有理由不使用Tkinter(任何 Python 附带的)或PyObjC(Apple 的 Python 2.7 预装的),除非您碰巧更熟悉wx, gobject,Qt等。

无论如何,无论你怎么做,你都需要编写一个函数来接收消息并将其附加到文本窗口(如果需要,可能会懒惰地创建它),然后在你通常会调用的任何地方调用该函数print。你可能还想编写和安装一个logging处理程序来做同样的事情,这样你就可以了log.info。(您可以改为创建一个类似文件的对象来执行此操作并重定向stdout和/或stderr,但除非您无法控制printing 代码,否则这将是更多的工作。)

这里唯一真正的问题是 GUI 需要一个事件循环,而您可能只是将代码编写为顺序脚本。

解决此问题的一种方法是将整个当前脚本变成后台线程。如果您使用的是允许您从后台线程访问小部件的 GUI 库,那么一切都很容易;你printfunc就是这样做的textwidget.append(msg)。如果没有,它可能至少有一个call_on_main_thread类型函数,所以你printfunccall_on_main_thread(textwidget.append, msg). 如果最坏的情况变得最糟(我相信 Tkinter 确实如此),您必须创建一个显式队列来推送消息,并在事件循环中编写一个队列处理程序。这个食谱应该给你一个想法。用您的代码替换正文workerThread,并以 . 结尾self.endApplication()。(那里可能有更好的例子;这正是我在快速搜索中首先找到的。)

另一种方法是让您的代码与事件循环协同操作。一些库,比如wxSafeYield如果你在每个处理块之后调用它,就可以让事情正常工作。其他人没有,但有办法从您的代码中显式驱动事件循环。其他人都没有——但每个事件循环框架都必须有一种方法来安排新事件,因此您可以将代码分解为一系列函数,每个函数都快速完成,然后执行类似root.after_idle(nextfunc).


但是……您确定需要这样做吗?

首先,任何应用程序,包括由 . 创建的应用程序,py2app如果您使用Foo.app/Contents/MacOS/Foo. 如果您愿意,您甚至可以进行设置,使其以open Foo.app这种方式工作。显然,这对于只在 Finder 中双击应用程序的人没有帮助(因为那时没有终端),但有时只需在人们需要时输出可用并知道如何遵循说明就足够了。

您还可以更进一步:创建一个Foo.command类似 的文件,$(dirname $0)/Foo.app/Contents/MacOS/Foo当您双击该文件时,它会启动 Terminal.app 并运行您的脚本。

或者您可以变得更简单:只需使用loggingsyslog 输出,如果您想查看每个文件何时完成,只需查看日志消息在Console.app.

最后,你甚至py2app首先需要吗?如果您没有任何外部依赖项,只需将您的脚本重命名为Foo.command,然后双击它将在 Terminal.app 中运行它。如果您确实有外部依赖项,您可能仍然可以将它们捆绑在一起作为一个文件夹,其中包含一个.command而不是一个.app.

显然,这些想法都不是构建界面的专业或新手友好方式,因此如果这很重要,您将不得不创建一个 GUI。

于 2013-02-06T19:22:50.470 回答