Virtualbox Ubuntu pygame.display.set_mode在交互式python中的行为与解释文件时不同

时间:2014-06-04 21:26:22

标签: python ubuntu tkinter pygame virtualbox

我在虚拟机内运行Ubuntu(主机操作系统是Windows 7)。我正在使用python 2.7。以下代码在各种情况下表现异常:

def set_screen():
    global screen
    screen = pygame.display.set_mode((600,600))

def set_tk():
    global root
    global embed
    global tkwin
    root = tk.Tk()
    root.wm_title("OpenBox")
    embed = tk.Frame(root, width = 600, height = 600)
    embed.pack(side=LEFT)
    windowid = embed.winfo_id()
    tkwin = tk.Frame(root, width = 200, height = 600)
    tkwin.pack(side=RIGHT)
    os.environ['SDL_WINDOWID'] = str(windowid)
    if sys.platform == "win32":
        os.environ['SDL_VIDEODRIVER'] = 'windib'
    if len(sys.argv) > 1:
        if sys.argv[1] == "-f":
            root.attributes("-fullscreen", True)

set_tk()
pygame.init()
pygame.display.init()
set_screen()

这是为了创建一个嵌入了pygame显示的tkinter窗口。这是我遇到的各种行为中的一些:

在Windows上,代码运行正常。正如预期一样,打开一个带有嵌入式pygame显示的tkinter框架。

VirtualBox Ubuntu解释文件

在Ubuntu上,当我运行程序文件(输入“python”)时,程序不起作用,在调用pygame.display.set_mode时会触发此错误(如果我没有设置os,则不会引发错误将pygame窗口嵌入到tkinter中的环境):

X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  3 (X_GetWindowAttributes)
  Resource id in failed request:  0x1600004
  Serial number of failed request:  53
  Current serial number in output stream:  54

VirtualBox Ubuntu交互式python

我可以输入在键入“python script.py”时无效的代码,并将其输入到交互式python中,代码将起作用。交互式python和运行python在文件上的第一个主要区别是计时,所以我首先尝试在调用display.set_mode之前添加time.sleep(),但这没有任何区别。另一个主要的区别是它处理异常而不停止程序,所以我也试过尝试,除了测试这个,它没有解决问题。我也不能只在交互式python中运行整个程序(可能通过stdin和stdout上的pexpect或子进程句柄提供它),因为还有tkinter线程维护我的pygame显示的gui侧边栏,并且它们不能在交互式中工作蟒。

VirtualBox Ubuntu exec

我也尝试使用exec来调用display.set_mode,希望这个执行环境可能不同。但是,调用exec set_mode会产生与调用set_mode相同的结果,这意味着它在交互式python中工作,但在读取文件时则不行。

VirtualBox Ubuntu交互式python函数

代码在函数中的行为也不同。在交互式python中,在函数中运行所有这些代码将使其无法工作。当我试验代码工作的代码并且在函数内部不起作用时,我发现必须在函数外部输入的代码是pygame.display.set_mode。奇怪的是,当我将display.set_mode单独放在一个没有其他代码的函数中时,它就可以工作了。当python从文件中读取代码时,所有上述情况都会抛出错误。


我还尝试以交互方式定义所有显示信息,然后为我的主程序选择加载和访问。但是,由于pygame.surface对象无法进行pickle,因此无效。


为什么此代码在某些环境中有效但在其他环境中无效?有没有办法让这个代码在Virtualbox Ubuntu中成功?

1 个答案:

答案 0 :(得分:2)

Tkinter需要mainloop()才能工作 没有mainloop() Tkinter立即结束工作。

Windows和Interactive Python可能不会打扰这个,或者他们使用自己的主循环来保持Tkinter运行。

还有另一个问题:mainloop()让Tkinter工作,但它不允许在mainloop()下面运行任何行(mainloop()(和Tkinter)结束工作之前)。所以我使用after()在100毫秒后运行set_screen() - 当mainloop()正在运行时。

使用Python 2.7.5在(非虚拟)Linux Mint 16(基于Ubuntu)上进行测试

from Tkinter import *
import Tkinter as tk
import pygame
from pygame.locals import *
import os

def set_screen():
    global screen

    pygame.init()
    pygame.display.init()
    screen = pygame.display.set_mode((600,600))
    screen_rect = screen.get_rect()
    pygame.draw.circle(screen, (255,0,0), screen_rect.center, 50 )
    pygame.display.flip()


def set_tk():
    global root
    global embed
    global tkwin
    root = tk.Tk()
    root.wm_title("OpenBox")
    embed = tk.Frame(root, width = 600, height = 600)
    embed.pack(side=LEFT)
    windowid = embed.winfo_id()
    tkwin = tk.Frame(root, width = 200, height = 600)
    tkwin.pack(side=RIGHT)
    os.environ['SDL_WINDOWID'] = str(windowid)
    #~ if sys.platform == "win32":
        #~ os.environ['SDL_VIDEODRIVER'] = 'windib'
    #~ if len(sys.argv) > 1:
        #~ if sys.argv[1] == "-f":
            #~ root.attributes("-fullscreen", True)         
    root.after(100,set_screen)
    root.mainloop()

set_tk()