我正在尝试从Tkinter接口执行已编译的Pygame Graphical应用程序。但是,我希望pygame界面启动到800x600图形框架。在用于pygame应用程序的800x600帧下面的同一根窗口中,我正在寻找一种嵌入方式:
启动python可执行文件的xterm,它自动位于名为“lib /”的子目录中
直接调用位于命名的“lib /”文件夹中的可执行文件。
我在这个主题上找到的唯一有用的文档是: http://poultryandprogramming.wordpress.com/2012/10/28/embedded-terminal-in-pythontk-window/
os.system
路线是我看到任何形式的文档的唯一方法。
是否可以使用subprocess.Popen
执行我想要的操作?
答案 0 :(得分:4)
这似乎是两个不同的问题。
首先,要在Python中直接运行可执行文件,您只需要subprocess
模块。当你说你看过os.system
的文档时,我不知道你是怎么错过的,因为这清楚地说明了:
subprocess
模块提供了更强大的工具来生成新流程并检索其结果;使用该模块比使用此功能更可取。有关一些有用的配方,请参阅Replacing Older Functions with the subprocess Module文档中的subprocess
部分。
特别是,要在“lib /”文件夹中运行某些可执行文件,只需执行以下操作:
p = subprocess.Popen(['lib/the_executable'])
但是,我猜你确实不希望当前工作目录中有lib
,而是来自主脚本所在目录的lib
,对吧?为此,你需要在脚本启动时做这样的事情:
scriptdir = os.path.abspath(os.path.dirname(__file__))
...当你启动孩子时会发生类似这样的事情:
path = os.path.join(scriptdir, 'lib/the_executable')
p = subprocess.Popen([path])
无论如何,一旦你有一个Popen
对象,你可以通过每隔一段时间调用p
或通过生成一个线程来检查poll
是否仍在运行等等阻止wait
;你可以通过调用kill
来杀死它;等Popen
objects上的文档显示了你可以做的所有事情。
如果您更喜欢运行启动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)
问题是,你给了什么窗口ID?那么,你发布的博客已经有了答案。与您提供xterm的-into
相同的ID。
博客没有解释如何将其限制在窗口的部分,但它所引用的代码必须。答案是(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)
Pygame孩子:
width, height = sys.argv[1:3]
pygame.display.init()
pygame.display.set_mode((width, height), pygame.NOFRAME)
如果你无法修改Pygame应用程序,事情就会变得棘手。您必须创建嵌入父窗口的两个单独窗口,或以某种方式停靠在顶层的两个窗口。 (后者并不像在X11中听起来那么可怕。每当一个窗口移动时,以编程方式移动另一个窗口。)无论哪种方式,然后启动嵌入在一个子窗口中的Pygame应用程序,并将Tkinter填充到另一个窗口中。你或许可以通过Tkinter做到这一点;您可能必须直接进行Xlib调用(通过ctypes
- 使用Xlib,或使用python-xlib
之类的内容。