python - 在 Python 中打开窗口并在其上绘制填充矩形的最简单方法
问题描述
我尝试了 pygame 和 tkinter,但都用 while 循环阻塞了主线程。有一些解决方法,但我认为它们相对复杂。例如,在 Java 中,我可以创建一个 JFrame 添加一个 JPanel 并在 JPanel 上绘图。这不会阻塞创建 JFrame/JPanel 的线程。Python 和 Java 之间是否存在关键区别,因此 Python 不能做同样的事情,还是我只是使用了错误的包或使用了错误的包?
Edit1:主要问题:在 Python 中打开窗口并在其上绘制填充矩形而不阻塞主线程的最简单方法。
编辑2:
tkinter 示例:
import tkinter
root = tkinter.Tk()
canvas = tkinter.Canvas(root)
canvas.create_rectangle(10, 10, 60, 60, fill='blue')
canvas.pack()
tkinter.mainloop()
print("I won't get printed until window is closed")
pygame 示例:
import pygame
pygame.init()
width = 500
height = 500
window = pygame.display.set_mode((width, height))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
print("I won't get printed until window is closed")
我想要的是:
class Canvas:
def __init__(self):
... # create window that does not block main thread
def draw_rect(self, x, y, width, height, color):
... # draw rect on window
def clear(self):
... # clear window
canvas = Canvas()
canvas.draw_rect(10, 10, 60, 60, 'blue')
print('I get printed even while window is active')
编辑3:
我在 Java 中想要什么:
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class Canvas {
public static void main(String[] args) {
// test the Canvas class
Canvas canvas = new Canvas(500, 500); // creates canvas window
canvas.fillRect(50, 50, 200, 200, Color.BLUE); // draws a rect
canvas.clear(); // removes all drawings from canvas window
canvas.fillRect(50, 100, 300, 200, Color.RED);
canvas.fillRect(100,150,300,300, Color.CYAN);
// everything here will be executed
}
private JFrame frame = new JFrame();
private List<Consumer<Graphics>> drawTasks = new ArrayList<>();
public Canvas(int width, int height) {
JPanel panel = new JPanel() {
@Override
public void paint(Graphics g) {
super.paint(g);
for (Consumer<Graphics> drawTask : drawTasks) {
drawTask.accept(g);
}
}
};
panel.setPreferredSize(new Dimension(width, height));
frame.add(panel);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void fillRect(int x, int y, int width, int height, Color color){
drawTasks.add(graphics -> {
graphics.setColor(color);
graphics.fillRect(x, y, width, height);
});
frame.repaint();
}
public void clear() {
drawTasks.clear();
frame.repaint();
}
}
解决方案
当您运行 Java 代码时,会创建一个单独的线程(事件调度线程)来为您处理 GUI。pygame 中的等价物是这样的:
import pygame
import threading
class Canvas(threading.Thread):
def __init__(self):
super().__init__()
self.screen = pygame.display.set_mode((800, 600))
self.screen.fill((50, 50, 50))
self.clock = pygame.time.Clock()
self.start()
def draw_rect(self, x, y, width, height, color):
pygame.draw.rect(self.screen, pygame.Color(color), (x, y, width, height))
def clear(self):
self.screen.fill((50, 50, 50))
def run(self):
while True:
for e in pygame.event.get():
print(e)
if e.type == pygame.QUIT:
return
pygame.display.update()
self.clock.tick(60)
canvas = Canvas()
canvas.draw_rect(10, 10, 60, 60, 'blue')
print('I get printed even while window is active')
但是,如果您运行此代码,您会看到自己,它不会工作,因为 pygame 的事件系统只有在从主线程调用时才能正常工作(至少在 Windows 上。它在 Linux IIRC 中工作)。
因此,以这种方式使用 pygame,您所要求的内容是不可靠的。
使用 tkinter,你可以使用这样的东西:
import threading
class Canvas(threading.Thread):
def __init__(self):
super().__init__()
self.start()
def run(self):
import tkinter
root = tkinter.Tk()
s = tkinter.StringVar()
s.set('Foo')
f = tkinter.StringVar()
f.set('Bar')
tkinter.Label(root,textvariable=s).pack()
tkinter.Button(root,textvariable=f).pack()
root.mainloop()
app = Canvas()
print('I get printed even while window is active')
这将起作用,但有点hacky,因为tkinter
模块必须在您调用的同一线程中导入mainloop()
。
推荐阅读
- vba - VBA - 删除B列中的空白行 - 卡在无限循环中
- python - 电报机器人-getChat-invite_link
- phpdesktop - 执行多个 .bat 或 .exe 文件
- cassandra - 如何在聊天应用程序中按最后回复时间订购房间实体?
- jquery - 如果子图像源为空,则更改/添加父类
- json - 使用 Java 驱动程序将带有 JsonNode 字段的 POJO 插入 MongoDB
- node.js - Dialog.ElicitSlot 在循环中运行如何在 alexa 中结束并再次开始对话?
- java - java需要代码帮助以从数组列表中删除重复项
- javascript - react-native-map 图像源未在 android 上更新
- python - 在 Python 中迭代/枚举 N^5 的子集