我在虚拟机内运行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框架。
在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
我可以输入在键入“python script.py”时无效的代码,并将其输入到交互式python中,代码将起作用。交互式python和运行python在文件上的第一个主要区别是计时,所以我首先尝试在调用display.set_mode之前添加time.sleep(),但这没有任何区别。另一个主要的区别是它处理异常而不停止程序,所以我也试过尝试,除了测试这个,它没有解决问题。我也不能只在交互式python中运行整个程序(可能通过stdin和stdout上的pexpect或子进程句柄提供它),因为还有tkinter线程维护我的pygame显示的gui侧边栏,并且它们不能在交互式中工作蟒。
我也尝试使用exec来调用display.set_mode,希望这个执行环境可能不同。但是,调用exec set_mode会产生与调用set_mode相同的结果,这意味着它在交互式python中工作,但在读取文件时则不行。
代码在函数中的行为也不同。在交互式python中,在函数中运行所有这些代码将使其无法工作。当我试验代码工作的代码并且在函数内部不起作用时,我发现必须在函数外部输入的代码是pygame.display.set_mode。奇怪的是,当我将display.set_mode单独放在一个没有其他代码的函数中时,它就可以工作了。当python从文件中读取代码时,所有上述情况都会抛出错误。
我还尝试以交互方式定义所有显示信息,然后为我的主程序选择加载和访问。但是,由于pygame.surface对象无法进行pickle,因此无效。
为什么此代码在某些环境中有效但在其他环境中无效?有没有办法让这个代码在Virtualbox Ubuntu中成功?
答案 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()