Tkinter嵌入图形子过程 [英] Tkinter embed Graphical subprocess

查看:79
本文介绍了Tkinter嵌入图形子过程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从Tkinter界面执行已编译的Pygame图形应用程序。但是,我希望pygame界面启动到800x600图形框架。在pygame应用程序的800x600框架下方的同一根窗口中,我正在寻找一种嵌入其中一种方法:


  1. xterm会自动启动位于 lib /子目录中的python可执行文件,或者


  2. 直接调用位于名为 lib /文件夹中的可执行文件。


关于该主题的唯一有用的文档是在这里:
http://poultryandprogramming.wordpress.com/2012/10/28/embedded -terminal-in-pythontk-window /



os.system 路由是唯一方法我看到任何形式的文档。



是否可以用 subprocess.Popen 来完成我想要的工作?

解决方案

这似乎是两个独立的问题。






首先,要直接在Python中运行可执行文件,您需要的是 子进程 模块。我不知道当您说已经看过 os.system ,因为它清楚地表明:


子过程 模块提供更强大的功能来产生新流程并检索其结果;使用该模块优于使用此功能。请参见将旧功能替换为子流程模块, a href = http://docs.python.org/2/library/subprocess.html rel = noreferrer> 子过程 文档以获取一些帮助


特别是要在 lib /文件夹中运行某些可执行文件,只需执行以下操作:

  p = subprocess.Popen(['lib / the_executable'])

但是,我想您真的不想从当前工作目录中 $ ,而是<主脚本所在目录中的code> lib ,对吗?为此,您需要在脚本启动时执行以下操作:

  scriptdir = os.path.abspath(os。 path.dirname(__ file__))

...然后在启动子项时出现类似的情况:

  path = os.path.join(scriptdir,'lib / the_executable')
p = subprocess.Popen([路径] )

无论如何,一旦您拥有 Popen 对象,您可以经常调用 poll 来检查 p 是否仍在运行,或者通过产生一个在 wait 等待时阻塞的线程;您可以通过调用 kill 杀死它;等等。 Popen 对象显示您可以做的所有事情。






如果您希望运行xterm可执行文件启动了Python可执行文件,您可以 做到这一点-只需传递 xterm 作为第一个参数,并将相关的xterm参数作为其余参数。



但是我看不出有什么好处。您不是要在窗口中嵌入终端会话,而是游戏本身。从xterm会话启动GUI应用程序时,它不会在xterm窗口中运行;它在新窗口中运行。如果嵌入了xterm窗口,也会发生同样的事情。






关于将Pygame窗口嵌入您自己的窗口中,有两种方法。






如果您是在自己编写Pygame游戏,请使用 display.init 文档说:


在某些平台上,可以将pygame显示器嵌入到现有的窗口中。为此,必须将环境变量SDL_WINDOWID设置为包含窗口ID或句柄的字符串。初始化pygame显示时,将检查环境变量。请注意,在嵌入式显示器中运行时可能会有许多奇怪的副作用。


请注意 Popen 构造函数使用 env 参数:


如果 env 不是 None ,它必须是一个为新进程定义环境变量的映射;


所以,您可以这样做:


p>

  child_env = dict(os.environ)
child_env ['SDL_WINDOWID'] = the_window_id
p = subprocess.Popen ([path],env = child_env)

问题是,您给它什么窗口ID?好吧,您发布到的博客已经有了答案。您将xterm的放入的I​​D。



博客未解释如何限制它到窗口的 part ,但是它所引用的代码必须。答案是:(a)在主窗口中嵌入一个子窗口,并将该子窗口的ID提供给该子进程,或者(b)将整个窗口提供给该子进程,然后让该子项立即创建一个子窗口,



但是,对于Pygame(或其他SDL)应用的特定情况,与xterm相反,设置<环境中的code> 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( [路径,宽度,高度],env = child_env)

Pygame孩子:

 宽度,高度= sys.argv [1:3] 
pygame.display.init()
pygame.display.set_mode ((宽度,高度),pygame.NOFRAME)






如果您无法修改Pygame应用,那么事情将变得更加棘手。您将必须创建两个单独的窗口嵌入到父窗口中,或者以某种方式将两个顶级窗口停靠在一起。 (后者并不像X11中那样令人恐惧。每当一个窗口移动时,以编程方式移动另一个窗口。)不管哪种方式,您都可以启动嵌入在一个子窗口中的Pygame应用,然后将Tkinter的内容塞入另一个窗口中。您可能可以通过Tkinter做到所有这些;您可能必须直接进行Xlib调用(通过 ctypes -ing到Xlib,或使用类似 python-xlib )。


I am trying to execute a compiled Pygame Graphical application from a Tkinter interface. However, I want the pygame interface to launch into a 800x600 Graphical frame. In the same root window below the 800x600 frame that is for the pygame application, I am looking for a way to embed either:

  1. a xterm that launches a python executable automatically located in a subdirectory called "lib/" OR

  2. directly call the executable located in the named "lib/" folder.

The only helpful documentation i have found on the subject is here: http://poultryandprogramming.wordpress.com/2012/10/28/embedded-terminal-in-pythontk-window/

The os.system route is the only method I see any form of documentation for.

Is it possible to do what I want with subprocess.Popen?

解决方案

This seems to be two separate questions.


First, to directly run an executable in Python, all you need is the subprocess module. I don't know how you missed seeing this when you say you've seen the documentation for os.system, because that clearly says:

The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.

In particular, to run some executable in the "lib/" folder, just do this:

p = subprocess.Popen(['lib/the_executable'])

However, I'm guessing you really want not lib from the current working directory, but lib from the directory the main script resides in, right? For that, you'll want to do something like this at script startup:

scriptdir = os.path.abspath(os.path.dirname(__file__))

… and then something like this when you launch the child:

path = os.path.join(scriptdir, 'lib/the_executable')
p = subprocess.Popen([path])

At any rate, once you have a Popen object, you can check whether p is still running, etc., by calling poll every so often, or by spawning a thread to block on wait; you can kill it by calling kill on it; etc. The docs on Popen objects show all the things you can do.


If you'd prefer to run an xterm executable that launches the Python executable, you can do that—just pass xterm as the first argument, and the relevant xterm arguments as the remaining arguments.

But I can't see what good that would do you. You're not trying to embed a terminal session in your window, but the game itself. When you launch a GUI app from an xterm session, it doesn't run inside the xterm window; it runs in a new window. The same thing will happen if the xterm window is embedded.


As for embedding the Pygame window in your own window, there are two ways to do that.


If you're writing the Pygame game yourself, as the display.init docs say:

On some platforms it is possible to embed the pygame display into an already existing window. To do this, the environment variable SDL_WINDOWID must be set to a string containing the window id or handle. The environment variable is checked when the pygame display is initialized. Be aware that there can be many strange side effects when running in an embedded display.

Notice that the Popen constructor takes an env argument:

If env is not None, it must be a mapping that defines the environment variables for the new process; these are used instead of inheriting the current process’ environment, which is the default behavior.

So, you can do this:

child_env = dict(os.environ)
child_env['SDL_WINDOWID'] = the_window_id
p = subprocess.Popen([path], env=child_env)

The problem is, what window ID do you give it? Well, the blog you posted to already has the answer. The same ID that you'd give xterm's -into.

The blog doesn't explain how to restrict it to part of your window, but the code it refers to must. The answer is to either (a) embed a child window in the main window, and give the child window's ID to the child process, or (b) give the entire window to the child process, then have the child immediately create a sub-surface and only draw to that instead of to the whole display.

However, for the particular case of Pygame (or other SDL) apps, as opposed to xterm, setting SDL_VIDEO_WINDOW_POS in the environment should also work. (As far as I can tell, this isn't a documented feature of Pygame, but it is a documented feature of SDL, so it ought to be reliable.)

Ultimately, you'll probably need a bit of cooperation between the two apps. Spmething like this:

Tkinter parent:

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 child:

width, height = sys.argv[1:3]
pygame.display.init()
pygame.display.set_mode((width, height), pygame.NOFRAME)


If you can't modify the Pygame app, things will be trickier. You will have to create two separate windows embedded into a parent window, or two windows top-level docked together in some way. (The latter isn't as scary as it sounds in X11. Whenever one window moves, programmatically move the other one.) Either way, you then launch the Pygame app embedded in one child window, and cram the Tkinter stuff into the other. You may be able to do that all through Tkinter; you may have to make Xlib calls directly (either by ctypes-ing to Xlib, or by using something like python-xlib).

这篇关于Tkinter嵌入图形子过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆