Ale*_*xiK 2 python embed subprocess tkinter
我正在尝试从 Tkinter 界面执行编译的 Pygame 图形应用程序。但是,我希望 pygame 界面启动到 800x600 图形框架中。在 pygame 应用程序的 800x600 框架下方的同一个根窗口中,我正在寻找一种嵌入的方法:
一个启动 python 可执行文件的 xterm 自动位于名为“lib/”的子目录中或
直接调用位于命名的“lib/”文件夹中的可执行文件。
我在这个主题上找到的唯一有用的文档在这里:http : //poultryandprogramming.wordpress.com/2012/10/28/embedded-terminal-in-pythontk-window/
该os.system航线是我看到的任何形式的文件的唯一方法。
可以做我想做的事subprocess.Popen吗?
这似乎是两个不同的问题。
首先,要直接在 Python 中运行可执行文件,您只需要subprocess模块。我不知道当您说您已经看过 的文档时,您是如何错过看到这一点的os.system,因为这清楚地说:
该
subprocess模块提供了更强大的工具来生成新进程并检索它们的结果;使用该模块比使用此功能更可取。有关一些有用的秘诀,请参阅文档中的用子流程模块替换旧函数部分subprocess。
特别是,要在“lib/”文件夹中运行一些可执行文件,只需执行以下操作:
p = subprocess.Popen(['lib/the_executable'])
Run Code Online (Sandbox Code Playgroud)
但是,我猜您真的不想lib从当前工作目录中获取,而是lib从主脚本所在的目录中获取,对吗?为此,您需要在脚本启动时执行以下操作:
scriptdir = os.path.abspath(os.path.dirname(__file__))
Run Code Online (Sandbox Code Playgroud)
......然后当你启动孩子时是这样的:
path = os.path.join(scriptdir, 'lib/the_executable')
p = subprocess.Popen([path])
Run Code Online (Sandbox Code Playgroud)
无论如何,一旦你有了一个Popen对象,你就可以检查它是否p仍在运行,等等,通过poll每隔一段时间调用一次,或者通过产生一个线程来阻塞wait;你可以通过调用kill它来杀死它;等等。关于Popen对象的文档显示了你可以做的所有事情。
如果您更喜欢运行启动 Python 可执行文件的 xterm 可执行文件,您可以这样做——只需xterm作为第一个参数传递,并将相关的 xterm 参数作为其余参数传递。
但我看不出这对你有什么好处。您不是要在窗口中嵌入终端会话,而是要嵌入游戏本身。当您从 xterm 会话启动 GUI 应用程序时,它不会在 xterm 窗口内运行;它在新窗口中运行。如果嵌入了 xterm 窗口,也会发生同样的事情。
至于在你自己的窗口中嵌入 Pygame 窗口,有两种方法可以做到这一点。
如果您自己编写 Pygame 游戏,如display.init文档所述:
在某些平台上,可以将 pygame 显示嵌入到已经存在的窗口中。为此,必须将环境变量 SDL_WINDOWID 设置为包含窗口 ID 或句柄的字符串。pygame 显示初始化时检查环境变量。请注意,在嵌入式显示器中运行时可能会出现许多奇怪的副作用。
请注意,Popen构造函数接受一个env参数:
如果env不是
None,则它必须是定义新进程的环境变量的映射;使用这些而不是继承当前进程的环境,这是默认行为。
所以,你可以这样做:
child_env = dict(os.environ)
child_env['SDL_WINDOWID'] = the_window_id
p = subprocess.Popen([path], env=child_env)
Run Code Online (Sandbox Code Playgroud)
问题是,你给它什么窗口ID?好吧,您发布的博客已经有了答案。与您为 xterm 提供的 ID 相同的 ID -into。
该博客没有解释如何将其限制为窗口的一部分,但它所引用的代码必须。答案是要么 (a) 在主窗口中嵌入一个子窗口,并将子窗口的 ID 提供给子进程,要么 (b) 将整个窗口提供给子进程,然后让子进程立即创建一个子进程表面,只绘制到那个而不是整个显示。
但是,对于 Pygame(或其他 SDL)应用程序的特殊情况,与 xterm 不同,环境SDL_VIDEO_WINDOW_POS中的设置也应该有效。(据我所知,这不是 Pygame 的记录功能,但它是 SDL 的记录功能,所以它应该是可靠的。)
最终,您可能需要在两个应用程序之间进行一些合作。像这样的东西:
Tkinter 父级:
child_env = dict(os.environ)
child_env['SDL_WINDOWID'] = the_window_id
child_env['SDL_VIDEO_WINDOW_POS'] = '{},{}'.format(left, top)
p = subprocess.Popen([path, width, height], env=child_env)
Run Code Online (Sandbox Code Playgroud)
Pygame孩子:
width, height = sys.argv[1:3]
pygame.display.init()
pygame.display.set_mode((width, height), pygame.NOFRAME)
Run Code Online (Sandbox Code Playgroud)
如果您无法修改 Pygame 应用程序,事情会变得更加棘手。您必须创建嵌入到父窗口中的两个单独的窗口,或者以某种方式将两个顶级窗口停靠在一起。(后者并不像在 X11 中听起来那么可怕。每当一个窗口移动时,以编程方式移动另一个窗口。)无论哪种方式,您都可以启动嵌入在一个子窗口中的 Pygame 应用程序,并将 Tkinter 内容塞进另一个窗口。你可以通过 Tkinter 做到这一切;您可能必须直接进行 Xlib 调用(通过ctypes-ing 到 Xlib,或使用类似的东西python-xlib)。
| 归档时间: |
|
| 查看次数: |
5730 次 |
| 最近记录: |