标签归档:wxpython

如何在Python中创建一个简单的消息框?

问题:如何在Python中创建一个简单的消息框?

我正在寻找与alert()JavaScript 相同的效果。

我今天下午使用Twisted.web编写了一个基于Web的简单解释器。您基本上是通过表单提交Python代码块的,客户端来抓取并执行它。我希望能够做出一个简单的弹出消息,而不必每次都重写一堆样板的wxPython或TkInter代码(因为该代码是通过表单提交的,然后消失了)。

我尝试过tkMessageBox:

import tkMessageBox
tkMessageBox.showinfo(title="Greetings", message="Hello World!")

但这会在后台用tk图标打开另一个窗口。我不要这个 我一直在寻找一些简单的wxPython代码,但是它总是需要设置一个类并进入应用程序循环等。在Python中没有简单易行的方法来制作消息框吗?

I’m looking for the same effect as alert() in JavaScript.

I wrote a simple web-based interpreter this afternoon using Twisted.web. You basically submit a block of Python code through a form, and the client comes and grabs it and executes it. I want to be able to make a simple popup message, without having to re-write a whole bunch of boilerplate wxPython or TkInter code every time (since the code gets submitted through a form and then disappears).

I’ve tried tkMessageBox:

import tkMessageBox
tkMessageBox.showinfo(title="Greetings", message="Hello World!")

but this opens another window in the background with a tk icon. I don’t want this. I was looking for some simple wxPython code but it always required setting up a class and entering an app loop etc. Is there no simple, catch-free way of making a message box in Python?


回答 0

您可以使用导入和单行代码,如下所示:

import ctypes  # An included library with Python install.   
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)

或定义一个函数(Mbox),如下所示:

import ctypes  # An included library with Python install.
def Mbox(title, text, style):
    return ctypes.windll.user32.MessageBoxW(0, text, title, style)
Mbox('Your title', 'Your text', 1)

注意样式如下:

##  Styles:
##  0 : OK
##  1 : OK | Cancel
##  2 : Abort | Retry | Ignore
##  3 : Yes | No | Cancel
##  4 : Yes | No
##  5 : Retry | No 
##  6 : Cancel | Try Again | Continue

玩得开心!

注意:已编辑以MessageBoxW代替MessageBoxA

You could use an import and single line code like this:

import ctypes  # An included library with Python install.   
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)

Or define a function (Mbox) like so:

import ctypes  # An included library with Python install.
def Mbox(title, text, style):
    return ctypes.windll.user32.MessageBoxW(0, text, title, style)
Mbox('Your title', 'Your text', 1)

Note the styles are as follows:

##  Styles:
##  0 : OK
##  1 : OK | Cancel
##  2 : Abort | Retry | Ignore
##  3 : Yes | No | Cancel
##  4 : Yes | No
##  5 : Retry | Cancel 
##  6 : Cancel | Try Again | Continue

Have fun!

Note: edited to use MessageBoxW instead of MessageBoxA


回答 1

你看过easygui吗?

import easygui

easygui.msgbox("This is a message!", title="simple gui")

Have you looked at easygui?

import easygui

easygui.msgbox("This is a message!", title="simple gui")

回答 2

另外,您可以在撤消另一个窗口之前先放置它,以便放置消息

#!/usr/bin/env python

from Tkinter import *
import tkMessageBox

window = Tk()
window.wm_withdraw()

#message at x:200,y:200
window.geometry("1x1+200+200")#remember its .geometry("WidthxHeight(+or-)X(+or-)Y")
tkMessageBox.showerror(title="error",message="Error Message",parent=window)

#centre screen message
window.geometry("1x1+"+str(window.winfo_screenwidth()/2)+"+"+str(window.winfo_screenheight()/2))
tkMessageBox.showinfo(title="Greetings", message="Hello World!")

Also you can position the other window before withdrawing it so that you position your message

#!/usr/bin/env python

from Tkinter import *
import tkMessageBox

window = Tk()
window.wm_withdraw()

#message at x:200,y:200
window.geometry("1x1+200+200")#remember its .geometry("WidthxHeight(+or-)X(+or-)Y")
tkMessageBox.showerror(title="error",message="Error Message",parent=window)

#centre screen message
window.geometry("1x1+"+str(window.winfo_screenwidth()/2)+"+"+str(window.winfo_screenheight()/2))
tkMessageBox.showinfo(title="Greetings", message="Hello World!")

回答 3

您提供的代码很好!您只需要使用以下代码显式创建“背景中的其他窗口”并将其隐藏:

import Tkinter
window = Tkinter.Tk()
window.wm_withdraw()

就在您的消息框之前。

The code you presented is fine! You just need to explicitly create the “other window in the background” and hide it, with this code:

import Tkinter
window = Tkinter.Tk()
window.wm_withdraw()

Right before your messagebox.


回答 4

PyMsgBox模块正是这样做的。它具有遵循JavaScript命名约定的消息框功能:alert(),confirm(),prompt()和password()(后者是hint(),但键入时使用*)。这些函数调用将阻塞,直到用户单击“确定” /“取消”按钮为止。这是一个无依赖的跨平台纯Python模块。

安装方式: pip install PyMsgBox

用法示例:

import pymsgbox
pymsgbox.alert('This is an alert!', 'Title')
response = pymsgbox.prompt('What is your name?')

完整文档位于http://pymsgbox.readthedocs.org/en/latest/

The PyMsgBox module does exactly this. It has message box functions that follow the naming conventions of JavaScript: alert(), confirm(), prompt() and password() (which is prompt() but uses * when you type). These function calls block until the user clicks an OK/Cancel button. It’s a cross-platform, pure Python module with no dependencies.

Install with: pip install PyMsgBox

Sample usage:

import pymsgbox
pymsgbox.alert('This is an alert!', 'Title')
response = pymsgbox.prompt('What is your name?')

Full documentation at http://pymsgbox.readthedocs.org/en/latest/


回答 5

在Windows中,可以将ctypes与user32库一起使用:

from ctypes import c_int, WINFUNCTYPE, windll
from ctypes.wintypes import HWND, LPCSTR, UINT
prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)

MessageBox()
MessageBox(text="Spam, spam, spam")
MessageBox(flags=2, text="foo bar")

In Windows, you can use ctypes with user32 library:

from ctypes import c_int, WINFUNCTYPE, windll
from ctypes.wintypes import HWND, LPCSTR, UINT
prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT)
paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0)
MessageBox = prototype(("MessageBoxA", windll.user32), paramflags)

MessageBox()
MessageBox(text="Spam, spam, spam")
MessageBox(flags=2, text="foo bar")

回答 6

在Mac上,python标准库有一个名为的模块EasyDialogs。在http://www.averdevelopment.com/python/EasyDialogs.html上还有一个(基于ctypes)Windows版本

如果对您来说很重要:它使用本机对话框并且不像已经提到的那样依赖Tkinter easygui,但是它可能没有那么多功能。

On Mac, the python standard library has a module called EasyDialogs. There is also a (ctypes based) windows version at http://www.averdevelopment.com/python/EasyDialogs.html

If it matters to you: it uses native dialogs and doesn’t depend on Tkinter like the already mentioned easygui, but it might not have as much features.


回答 7

import ctypes
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)

可以更改最后一个数字(此处为1)以更改窗口样式(不仅是按钮!):

## Button styles:
# 0 : OK
# 1 : OK | Cancel
# 2 : Abort | Retry | Ignore
# 3 : Yes | No | Cancel
# 4 : Yes | No
# 5 : Retry | No 
# 6 : Cancel | Try Again | Continue

## To also change icon, add these values to previous number
# 16 Stop-sign icon
# 32 Question-mark icon
# 48 Exclamation-point icon
# 64 Information-sign icon consisting of an 'i' in a circle

例如,

ctypes.windll.user32.MessageBoxW(0, "That's an error", "Warning!", 16)

会给这个

import ctypes
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)

The last number (here 1) can be change to change window style (not only buttons!):

## Button styles:
# 0 : OK
# 1 : OK | Cancel
# 2 : Abort | Retry | Ignore
# 3 : Yes | No | Cancel
# 4 : Yes | No
# 5 : Retry | No 
# 6 : Cancel | Try Again | Continue

## To also change icon, add these values to previous number
# 16 Stop-sign icon
# 32 Question-mark icon
# 48 Exclamation-point icon
# 64 Information-sign icon consisting of an 'i' in a circle

For example,

ctypes.windll.user32.MessageBoxW(0, "That's an error", "Warning!", 16)

will give this:


回答 8

from tkinter.messagebox import *
Message([master], title="[title]", message="[message]")

必须先创建主窗口。这是针对Python 3的。这不是wxPython,而是tkinter的。

Use

from tkinter.messagebox import *
Message([master], title="[title]", message="[message]")

The master window has to be created before. This is for Python 3. This is not fot wxPython, but for tkinter.


回答 9

import sys
from tkinter import *
def mhello():
    pass
    return

mGui = Tk()
ment = StringVar()

mGui.geometry('450x450+500+300')
mGui.title('My youtube Tkinter')

mlabel = Label(mGui,text ='my label').pack()

mbutton = Button(mGui,text ='ok',command = mhello,fg = 'red',bg='blue').pack()

mEntry = entry().pack 
import sys
from tkinter import *
def mhello():
    pass
    return

mGui = Tk()
ment = StringVar()

mGui.geometry('450x450+500+300')
mGui.title('My youtube Tkinter')

mlabel = Label(mGui,text ='my label').pack()

mbutton = Button(mGui,text ='ok',command = mhello,fg = 'red',bg='blue').pack()

mEntry = entry().pack 

回答 10

另外,您可以在撤消另一个窗口之前先放置它,以便放置消息

from tkinter import *
import tkinter.messagebox

window = Tk()
window.wm_withdraw()

# message at x:200,y:200
window.geometry("1x1+200+200")  # remember its.geometry("WidthxHeight(+or-)X(+or-)Y")
tkinter.messagebox.showerror(title="error", message="Error Message", parent=window)

# center screen message
window.geometry(f"1x1+{round(window.winfo_screenwidth() / 2)}+{round(window.winfo_screenheight() / 2)}")
tkinter.messagebox.showinfo(title="Greetings", message="Hello World!")

请注意:这是Lewis Cowles的答案,只是Python 3ified,因为tkinter自python 2起就发生了变化。

try:
    import tkinter
    import tkinter.messagebox
except ModuleNotFoundError:
    import Tkinter as tkinter
    import tkMessageBox as tkinter.messagebox

Also you can position the other window before withdrawing it so that you position your message

from tkinter import *
import tkinter.messagebox

window = Tk()
window.wm_withdraw()

# message at x:200,y:200
window.geometry("1x1+200+200")  # remember its.geometry("WidthxHeight(+or-)X(+or-)Y")
tkinter.messagebox.showerror(title="error", message="Error Message", parent=window)

# center screen message
window.geometry(f"1x1+{round(window.winfo_screenwidth() / 2)}+{round(window.winfo_screenheight() / 2)}")
tkinter.messagebox.showinfo(title="Greetings", message="Hello World!")

Please Note: This is Lewis Cowles’ answer just Python 3ified, since tkinter has changed since python 2. If you want your code to be backwords compadible do something like this:

try:
    import tkinter
    import tkinter.messagebox
except ModuleNotFoundError:
    import Tkinter as tkinter
    import tkMessageBox as tkinter.messagebox

回答 11

并不是最好的,这是我仅使用tkinter的基本消息框。

#Python 3.4
from    tkinter import  messagebox  as  msg;
import  tkinter as      tk;

def MsgBox(title, text, style):
    box = [
        msg.showinfo,       msg.showwarning,    msg.showerror,
        msg.askquestion,    msg.askyesno,       msg.askokcancel,        msg.askretrycancel,
];

tk.Tk().withdraw(); #Hide Main Window.

if style in range(7):
    return box[style](title, text);

if __name__ == '__main__':

Return = MsgBox(#Use Like This.
    'Basic Error Exemple',

    ''.join( [
        'The Basic Error Exemple a problem with test',                      '\n',
        'and is unable to continue. The application must close.',           '\n\n',
        'Error code Test',                                                  '\n',
        'Would you like visit http://wwww.basic-error-exemple.com/ for',    '\n',
        'help?',
    ] ),

    2,
);

print( Return );

"""
Style   |   Type        |   Button      |   Return
------------------------------------------------------
0           Info            Ok              'ok'
1           Warning         Ok              'ok'
2           Error           Ok              'ok'
3           Question        Yes/No          'yes'/'no'
4           YesNo           Yes/No          True/False
5           OkCancel        Ok/Cancel       True/False
6           RetryCancal     Retry/Cancel    True/False
"""

Not the best, here is my basic Message box using only tkinter.

#Python 3.4
from    tkinter import  messagebox  as  msg;
import  tkinter as      tk;

def MsgBox(title, text, style):
    box = [
        msg.showinfo,       msg.showwarning,    msg.showerror,
        msg.askquestion,    msg.askyesno,       msg.askokcancel,        msg.askretrycancel,
];

tk.Tk().withdraw(); #Hide Main Window.

if style in range(7):
    return box[style](title, text);

if __name__ == '__main__':

Return = MsgBox(#Use Like This.
    'Basic Error Exemple',

    ''.join( [
        'The Basic Error Exemple a problem with test',                      '\n',
        'and is unable to continue. The application must close.',           '\n\n',
        'Error code Test',                                                  '\n',
        'Would you like visit http://wwww.basic-error-exemple.com/ for',    '\n',
        'help?',
    ] ),

    2,
);

print( Return );

"""
Style   |   Type        |   Button      |   Return
------------------------------------------------------
0           Info            Ok              'ok'
1           Warning         Ok              'ok'
2           Error           Ok              'ok'
3           Question        Yes/No          'yes'/'no'
4           YesNo           Yes/No          True/False
5           OkCancel        Ok/Cancel       True/False
6           RetryCancal     Retry/Cancel    True/False
"""

回答 12

签出我的python模块:pip install quickgui(需要wxPython,但不需要wxPython知识) https://pypi.python.org/pypi/quickgui

可以创建任意数量的输入((比率,复选框,输入框),自动将它们排列在一个GUI上。

check out my python module: pip install quickgui (Requires wxPython, but requires no knowledge of wxPython) https://pypi.python.org/pypi/quickgui

Can create any numbers of inputs,(ratio, checkbox, inputbox), auto arrange them on a single gui.


回答 13

最新的消息框版本是hint_box模块。它有两个软件包:警报和消息。Message使您可以更好地控制该框,但键入时间会更长。

警报代码示例:

import prompt_box

prompt_box.alert('Hello') #This will output a dialog box with title Neutrino and the 
#text you inputted. The buttons will be Yes, No and Cancel

消息代码示例:

import prompt_box

prompt_box.message('Hello', 'Neutrino', 'You pressed yes', 'You pressed no', 'You 
pressed cancel') #The first two are text and title, and the other three are what is 
#printed when you press a certain button

A recent message box version is the prompt_box module. It has two packages: alert and message. Message gives you greater control over the box, but takes longer to type up.

Example Alert code:

import prompt_box

prompt_box.alert('Hello') #This will output a dialog box with title Neutrino and the 
#text you inputted. The buttons will be Yes, No and Cancel

Example Message code:

import prompt_box

prompt_box.message('Hello', 'Neutrino', 'You pressed yes', 'You pressed no', 'You 
pressed cancel') #The first two are text and title, and the other three are what is 
#printed when you press a certain button

回答 14

带螺纹的ctype模块

我正在使用tkinter消息框,但它会使我的代码崩溃。我不想找出原因,所以我改用ctypes模块。

例如:

import ctypes
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)

我从Arkelis那里得到了那个代码


我喜欢它不会使代码崩溃,因此我对其进行了工作并添加了线程,以便随后的代码可以运行。

我的代码示例

import ctypes
import threading


def MessageboxThread(buttonstyle, title, text, icon):
    threading.Thread(
        target=lambda: ctypes.windll.user32.MessageBoxW(buttonstyle, text, title, icon)
    ).start()

messagebox(0, "Your title", "Your text", 1)

对于按钮样式和图标编号:

## Button styles:
# 0 : OK
# 1 : OK | Cancel
# 2 : Abort | Retry | Ignore
# 3 : Yes | No | Cancel
# 4 : Yes | No
# 5 : Retry | No
# 6 : Cancel | Try Again | Continue

## To also change icon, add these values to previous number
# 16 Stop-sign icon
# 32 Question-mark icon
# 48 Exclamation-point icon
# 64 Information-sign icon consisting of an 'i' in a circle

ctype module with threading

i was using the tkinter messagebox but it would crash my code. i didn’t want to find out why so i used the ctypes module instead.

for example:

import ctypes
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)

i got that code from Arkelis


i liked that it didn’t crash the code so i worked on it and added a threading so the code after would run.

example for my code

import ctypes
import threading


def MessageboxThread(buttonstyle, title, text, icon):
    threading.Thread(
        target=lambda: ctypes.windll.user32.MessageBoxW(buttonstyle, text, title, icon)
    ).start()

messagebox(0, "Your title", "Your text", 1)

for button styles and icon numbers:

## Button styles:
# 0 : OK
# 1 : OK | Cancel
# 2 : Abort | Retry | Ignore
# 3 : Yes | No | Cancel
# 4 : Yes | No
# 5 : Retry | No
# 6 : Cancel | Try Again | Continue

## To also change icon, add these values to previous number
# 16 Stop-sign icon
# 32 Question-mark icon
# 48 Exclamation-point icon
# 64 Information-sign icon consisting of an 'i' in a circle

回答 15

您可以使用pyautoguipymsgbox

import pyautogui
pyautogui.alert("This is a message box",title="Hello World")

使用pymsgbox与使用相同pyautogui

import pymsgbox
pymsgbox.alert("This is a message box",title="Hello World")

You can use pyautogui or pymsgbox:

import pyautogui
pyautogui.alert("This is a message box",title="Hello World")

Using pymsgbox is the same as using pyautogui:

import pymsgbox
pymsgbox.alert("This is a message box",title="Hello World")

在Python中以编程方式生成视频或动画GIF?

问题:在Python中以编程方式生成视频或动画GIF?

我有一系列要用来创建视频的图像。理想情况下,我可以为每个帧指定帧持续时间,但是固定帧速率也可以。我在wxPython中进行此操作,因此可以渲染到wxDC或将图像保存到文件,例如PNG。是否有Python库可让我从这些帧创建视频(AVI,MPG等)或动画GIF?

编辑:我已经尝试过PIL,它似乎不起作用。有人可以用这个结论纠正我还是建议其他工具箱?这个链接似乎是在备份关于PIL的结论:http : //www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/

I have a series of images that I want to create a video from. Ideally I could specify a frame duration for each frame but a fixed frame rate would be fine too. I’m doing this in wxPython, so I can render to a wxDC or I can save the images to files, like PNG. Is there a Python library that will allow me to create either a video (AVI, MPG, etc) or an animated GIF from these frames?

Edit: I’ve already tried PIL and it doesn’t seem to work. Can someone correct me with this conclusion or suggest another toolkit? This link seems to backup my conclusion regarding PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/


回答 0

我建议不要使用visvis中的images2gif,因为它在PIL / Pillow方面存在问题,并且没有得到积极维护(我应该知道,因为我是作者)。

相反,请使用imageio,它是为解决此问题而开发的,并且打算保留下来

快速而肮脏的解决方案:

import imageio
images = []
for filename in filenames:
    images.append(imageio.imread(filename))
imageio.mimsave('/path/to/movie.gif', images)

对于较长的电影,请使用流媒体方法:

import imageio
with imageio.get_writer('/path/to/movie.gif', mode='I') as writer:
    for filename in filenames:
        image = imageio.imread(filename)
        writer.append_data(image)

I’d recommend not using images2gif from visvis because it has problems with PIL/Pillow and is not actively maintained (I should know, because I am the author).

Instead, please use imageio, which was developed to solve this problem and more, and is intended to stay.

Quick and dirty solution:

import imageio
images = []
for filename in filenames:
    images.append(imageio.imread(filename))
imageio.mimsave('/path/to/movie.gif', images)

For longer movies, use the streaming approach:

import imageio
with imageio.get_writer('/path/to/movie.gif', mode='I') as writer:
    for filename in filenames:
        image = imageio.imread(filename)
        writer.append_data(image)

回答 1

好吧,现在我正在使用ImageMagick。我将帧保存为PNG文件,然后从Python调用ImageMagick的convert.exe创建动画GIF。这种方法的好处是我可以为每个帧分别指定一个帧持续时间。不幸的是,这取决于在计算机上安装了ImageMagick。他们有一个Python包装器,但是看起来很烂而且不受支持。仍然欢迎其他建议。

Well, now I’m using ImageMagick. I save my frames as PNG files and then invoke ImageMagick’s convert.exe from Python to create an animated GIF. The nice thing about this approach is I can specify a frame duration for each frame individually. Unfortunately this depends on ImageMagick being installed on the machine. They have a Python wrapper but it looks pretty crappy and unsupported. Still open to other suggestions.


回答 2

截至2009年6月,最初引用的博客文章中提供了一种在评论中创建动画GIF的方法。下载脚本images2gif.py(以前称为images2gif.py,由@geographika提供更新)。

然后,例如,反转gif中的帧:

#!/usr/bin/env python

from PIL import Image, ImageSequence
import sys, os
filename = sys.argv[1]
im = Image.open(filename)
original_duration = im.info['duration']
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]    
frames.reverse()

from images2gif import writeGif
writeGif("reverse_" + os.path.basename(filename), frames, duration=original_duration/1000.0, dither=0)

As of June 2009 the originally cited blog post has a method to create animated GIFs in the comments. Download the script images2gif.py (formerly images2gif.py, update courtesy of @geographika).

Then, to reverse the frames in a gif, for instance:

#!/usr/bin/env python

from PIL import Image, ImageSequence
import sys, os
filename = sys.argv[1]
im = Image.open(filename)
original_duration = im.info['duration']
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]    
frames.reverse()

from images2gif import writeGif
writeGif("reverse_" + os.path.basename(filename), frames, duration=original_duration/1000.0, dither=0)

回答 3

使用PIL(使用:安装pip install Pillow)的方法如下:

import glob
from PIL import Image

# filepaths
fp_in = "/path/to/image_*.png"
fp_out = "/path/to/image.gif"

# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]
img.save(fp=fp_out, format='GIF', append_images=imgs,
         save_all=True, duration=200, loop=0)

Here’s how you do it using only PIL (install with: pip install Pillow):

import glob
from PIL import Image

# filepaths
fp_in = "/path/to/image_*.png"
fp_out = "/path/to/image.gif"

# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]
img.save(fp=fp_out, format='GIF', append_images=imgs,
         save_all=True, duration=200, loop=0)

See docs: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif


回答 4

我使用了易于使用的images2gif.py。它似乎确实使文件大小增加了一倍。

26 110kb PNG文件,我期望26 * 110kb = 2860kb,但是my_gif.GIF为5.7mb

同样因为GIF为8位,所以漂亮的png在GIF中变得有点模糊

这是我使用的代码:

__author__ = 'Robert'
from images2gif import writeGif
from PIL import Image
import os

file_names = sorted((fn for fn in os.listdir('.') if fn.endswith('.png')))
#['animationframa.png', 'animationframb.png', 'animationframc.png', ...] "

images = [Image.open(fn) for fn in file_names]

print writeGif.__doc__
# writeGif(filename, images, duration=0.1, loops=0, dither=1)
#    Write an animated gif from the specified images.
#    images should be a list of numpy arrays of PIL images.
#    Numpy images of type float should have pixels between 0 and 1.
#    Numpy images of other types are expected to have values between 0 and 255.


#images.extend(reversed(images)) #infinit loop will go backwards and forwards.

filename = "my_gif.GIF"
writeGif(filename, images, duration=0.2)
#54 frames written
#
#Process finished with exit code 0

以下是26帧中的3帧:

缩小图像会减小尺寸:

size = (150,150)
for im in images:
    im.thumbnail(size, Image.ANTIALIAS)

I used images2gif.py which was easy to use. It did seem to double the file size though..

26 110kb PNG files, I expected 26*110kb = 2860kb, but my_gif.GIF was 5.7mb

Also because the GIF was 8bit, the nice png’s became a little fuzzy in the GIF

Here is the code I used:

__author__ = 'Robert'
from images2gif import writeGif
from PIL import Image
import os

file_names = sorted((fn for fn in os.listdir('.') if fn.endswith('.png')))
#['animationframa.png', 'animationframb.png', 'animationframc.png', ...] "

images = [Image.open(fn) for fn in file_names]

print writeGif.__doc__
# writeGif(filename, images, duration=0.1, loops=0, dither=1)
#    Write an animated gif from the specified images.
#    images should be a list of numpy arrays of PIL images.
#    Numpy images of type float should have pixels between 0 and 1.
#    Numpy images of other types are expected to have values between 0 and 255.


#images.extend(reversed(images)) #infinit loop will go backwards and forwards.

filename = "my_gif.GIF"
writeGif(filename, images, duration=0.2)
#54 frames written
#
#Process finished with exit code 0

Here are 3 of the 26 frames:

shrinking the images reduced the size:

size = (150,150)
for im in images:
    im.thumbnail(size, Image.ANTIALIAS)


回答 5

要创建视频,您可以使用opencv

#load your frames
frames = ...
#create a video writer
writer = cvCreateVideoWriter(filename, -1, fps, frame_size, is_color=1)
#and write your frames in a loop if you want
cvWriteFrame(writer, frames[i])

To create a video, you could use opencv,

#load your frames
frames = ...
#create a video writer
writer = cvCreateVideoWriter(filename, -1, fps, frame_size, is_color=1)
#and write your frames in a loop if you want
cvWriteFrame(writer, frames[i])

回答 6

我碰到了这篇文章,但没有一个解决方案起作用,所以这是我有效的解决方案

到目前为止,其他解决方案存在问题:
1)没有明确修改持续时间的方式
2)没有解决乱序目录迭代的方法,这对于GIF至关重要
3)没有解释如何为python安装imageio 3

像这样安装imageio: python3 -m pip安装imageio

注意:您需要确保帧在文件名中具有某种索引,以便可以对其进行排序,否则您将无法知道GIF的开始或结束位置

import imageio
import os

path = '/Users/myusername/Desktop/Pics/' # on Mac: right click on a folder, hold down option, and click "copy as pathname"

image_folder = os.fsencode(path)

filenames = []

for file in os.listdir(image_folder):
    filename = os.fsdecode(file)
    if filename.endswith( ('.jpeg', '.png', '.gif') ):
        filenames.append(filename)

filenames.sort() # this iteration technique has no built in order, so sort the frames

images = list(map(lambda filename: imageio.imread(filename), filenames))

imageio.mimsave(os.path.join('movie.gif'), images, duration = 0.04) # modify duration as needed

I came across this post and none of the solutions worked, so here is my solution that does work

Problems with other solutions thus far:
1) No explicit solution as to how the duration is modified
2) No solution for the out of order directory iteration, which is essential for GIFs
3) No explanation of how to install imageio for python 3

install imageio like this: python3 -m pip install imageio

Note: you’ll want to make sure your frames have some sort of index in the filename so they can be sorted, otherwise you’ll have no way of knowing where the GIF starts or ends

import imageio
import os

path = '/Users/myusername/Desktop/Pics/' # on Mac: right click on a folder, hold down option, and click "copy as pathname"

image_folder = os.fsencode(path)

filenames = []

for file in os.listdir(image_folder):
    filename = os.fsdecode(file)
    if filename.endswith( ('.jpeg', '.png', '.gif') ):
        filenames.append(filename)

filenames.sort() # this iteration technique has no built in order, so sort the frames

images = list(map(lambda filename: imageio.imread(filename), filenames))

imageio.mimsave(os.path.join('movie.gif'), images, duration = 0.04) # modify duration as needed

回答 7

就像沃伦去年所说的那样,这是一个古老的问题。由于人们似乎仍在浏览页面,因此我想将他们重定向到更现代的解决方案。就像blakev 在这里说的那样,github上有一个Pillow示例。

 import ImageSequence
 import Image
 import gifmaker
 sequence = []

 im = Image.open(....)

 # im is your original image
 frames = [frame.copy() for frame in ImageSequence.Iterator(im)]

 # write GIF animation
 fp = open("out.gif", "wb")
 gifmaker.makedelta(fp, frames)
 fp.close()

注意:此示例已过时(gifmaker不是可导入模块,仅是脚本)。Pillow有一个GifImagePlugin(其源代码在GitHub上),但是ImageSequence上的文档似乎表明支持有限(只读)

Like Warren said last year, this is an old question. Since people still seem to be viewing the page, I’d like to redirect them to a more modern solution. Like blakev said here, there is a Pillow example on github.

 import ImageSequence
 import Image
 import gifmaker
 sequence = []

 im = Image.open(....)

 # im is your original image
 frames = [frame.copy() for frame in ImageSequence.Iterator(im)]

 # write GIF animation
 fp = open("out.gif", "wb")
 gifmaker.makedelta(fp, frames)
 fp.close()

Note: This example is outdated (gifmaker is not an importable module, only a script). Pillow has a GifImagePlugin (whose source is on GitHub), but the doc on ImageSequence seems to indicate limited support (reading only)


回答 8

它不是python库,但是mencoder可以做到这一点:从多个输入图像文件进行编码。您可以像这样从python执行mencoder:

import os

os.system("mencoder ...")

It’s not a python library, but mencoder can do that: Encoding from multiple input image files. You can execute mencoder from python like this:

import os

os.system("mencoder ...")

回答 9

旧问题,很多好的答案,但仍然可能对另一种选择感兴趣。

numpngw我最近在github(https://github.com/WarrenWeckesser/numpngw)上放置的模块可以从numpy数组编写动画PNG文件。(更新numpngw现在在pypi上:https : //pypi.python.org/pypi/numpngw

例如,此脚本:

import numpy as np
import numpngw


img0 = np.zeros((64, 64, 3), dtype=np.uint8)
img0[:32, :32, :] = 255
img1 = np.zeros((64, 64, 3), dtype=np.uint8)
img1[32:, :32, 0] = 255
img2 = np.zeros((64, 64, 3), dtype=np.uint8)
img2[32:, 32:, 1] = 255
img3 = np.zeros((64, 64, 3), dtype=np.uint8)
img3[:32, 32:, 2] = 255
seq = [img0, img1, img2, img3]
for img in seq:
    img[16:-16, 16:-16] = 127
    img[0, :] = 127
    img[-1, :] = 127
    img[:, 0] = 127
    img[:, -1] = 127

numpngw.write_apng('foo.png', seq, delay=250, use_palette=True)

创建:

您将需要一个支持动画PNG(直接或通过插件)的浏览器来观看动画。

Old question, lots of good answers, but there might still be interest in another alternative…

The numpngw module that I recently put up on github (https://github.com/WarrenWeckesser/numpngw) can write animated PNG files from numpy arrays. (Update: numpngw is now on pypi: https://pypi.python.org/pypi/numpngw.)

For example, this script:

import numpy as np
import numpngw


img0 = np.zeros((64, 64, 3), dtype=np.uint8)
img0[:32, :32, :] = 255
img1 = np.zeros((64, 64, 3), dtype=np.uint8)
img1[32:, :32, 0] = 255
img2 = np.zeros((64, 64, 3), dtype=np.uint8)
img2[32:, 32:, 1] = 255
img3 = np.zeros((64, 64, 3), dtype=np.uint8)
img3[:32, 32:, 2] = 255
seq = [img0, img1, img2, img3]
for img in seq:
    img[16:-16, 16:-16] = 127
    img[0, :] = 127
    img[-1, :] = 127
    img[:, 0] = 127
    img[:, -1] = 127

numpngw.write_apng('foo.png', seq, delay=250, use_palette=True)

creates:

You’ll need a browser that supports animated PNG (either directly or with a plugin) to see the animation.


回答 10

正如上面提到的一个成员,imageio是执行此操作的好方法。imageio还允许您设置帧速率,实际上我在Python中编写了一个函数,该函数允许您设置最终帧的保持时间。我将此功能用于科学动画,在这种动画中循环很有用,但没有立即重启。这是链接和功能:

如何使用Python制作GIF

import matplotlib.pyplot as plt
import os
import imageio

def gif_maker(gif_name,png_dir,gif_indx,num_gifs,dpi=90):
    # make png path if it doesn't exist already
    if not os.path.exists(png_dir):
        os.makedirs(png_dir)

    # save each .png for GIF
    # lower dpi gives a smaller, grainier GIF; higher dpi gives larger, clearer GIF
    plt.savefig(png_dir+'frame_'+str(gif_indx)+'_.png',dpi=dpi)
    plt.close('all') # comment this out if you're just updating the x,y data

    if gif_indx==num_gifs-1:
        # sort the .png files based on index used above
        images,image_file_names = [],[]
        for file_name in os.listdir(png_dir):
            if file_name.endswith('.png'):
                image_file_names.append(file_name)       
        sorted_files = sorted(image_file_names, key=lambda y: int(y.split('_')[1]))

        # define some GIF parameters

        frame_length = 0.5 # seconds between frames
        end_pause = 4 # seconds to stay on last frame
        # loop through files, join them to image array, and write to GIF called 'wind_turbine_dist.gif'
        for ii in range(0,len(sorted_files)):       
            file_path = os.path.join(png_dir, sorted_files[ii])
            if ii==len(sorted_files)-1:
                for jj in range(0,int(end_pause/frame_length)):
                    images.append(imageio.imread(file_path))
            else:
                images.append(imageio.imread(file_path))
        # the duration is the time spent on each image (1/duration is frame rate)
        imageio.mimsave(gif_name, images,'GIF',duration=frame_length)

As one member mentioned above, imageio is a great way to do this. imageio also allows you to set the frame rate, and I actually wrote a function in Python that allows you to set a hold on the final frame. I use this function for scientific animations where looping is useful but immediate restart isn’t. Here is the link and the function:

How to make a GIF using Python

import matplotlib.pyplot as plt
import os
import imageio

def gif_maker(gif_name,png_dir,gif_indx,num_gifs,dpi=90):
    # make png path if it doesn't exist already
    if not os.path.exists(png_dir):
        os.makedirs(png_dir)

    # save each .png for GIF
    # lower dpi gives a smaller, grainier GIF; higher dpi gives larger, clearer GIF
    plt.savefig(png_dir+'frame_'+str(gif_indx)+'_.png',dpi=dpi)
    plt.close('all') # comment this out if you're just updating the x,y data

    if gif_indx==num_gifs-1:
        # sort the .png files based on index used above
        images,image_file_names = [],[]
        for file_name in os.listdir(png_dir):
            if file_name.endswith('.png'):
                image_file_names.append(file_name)       
        sorted_files = sorted(image_file_names, key=lambda y: int(y.split('_')[1]))

        # define some GIF parameters

        frame_length = 0.5 # seconds between frames
        end_pause = 4 # seconds to stay on last frame
        # loop through files, join them to image array, and write to GIF called 'wind_turbine_dist.gif'
        for ii in range(0,len(sorted_files)):       
            file_path = os.path.join(png_dir, sorted_files[ii])
            if ii==len(sorted_files)-1:
                for jj in range(0,int(end_pause/frame_length)):
                    images.append(imageio.imread(file_path))
            else:
                images.append(imageio.imread(file_path))
        # the duration is the time spent on each image (1/duration is frame rate)
        imageio.mimsave(gif_name, images,'GIF',duration=frame_length)


回答 11

您尝试过PyMedia吗?我不确定100%,但是看起来本教程示例针对您的问题。

Have you tried PyMedia? I am not 100% sure but it looks like this tutorial example targets your problem.


回答 12

使用Windows7,python2.7,opencv 3.0,以下对我有用:

import cv2
import os

vvw           =   cv2.VideoWriter('mymovie.avi',cv2.VideoWriter_fourcc('X','V','I','D'),24,(640,480))
frameslist    =   os.listdir('.\\frames')
howmanyframes =   len(frameslist)
print('Frames count: '+str(howmanyframes)) #just for debugging

for i in range(0,howmanyframes):
    print(i)
    theframe = cv2.imread('.\\frames\\'+frameslist[i])
    vvw.write(theframe)

With windows7, python2.7, opencv 3.0, the following works for me:

import cv2
import os

vvw           =   cv2.VideoWriter('mymovie.avi',cv2.VideoWriter_fourcc('X','V','I','D'),24,(640,480))
frameslist    =   os.listdir('.\\frames')
howmanyframes =   len(frameslist)
print('Frames count: '+str(howmanyframes)) #just for debugging

for i in range(0,howmanyframes):
    print(i)
    theframe = cv2.imread('.\\frames\\'+frameslist[i])
    vvw.write(theframe)

回答 13

使它对我有用的最简单的方法是在Python中调用shell命令。

如果存储图像,例如dummy_image_1.png,dummy_image_2.png … dummy_image_N.png,则可以使用以下功能:

import subprocess
def grid2gif(image_str, output_gif):
    str1 = 'convert -delay 100 -loop 1 ' + image_str  + ' ' + output_gif
    subprocess.call(str1, shell=True)

只需执行:

grid2gif("dummy_image*.png", "my_output.gif")

这将构建您的gif文件my_output.gif。

The easiest thing that makes it work for me is calling a shell command in Python.

If your images are stored such as dummy_image_1.png, dummy_image_2.png … dummy_image_N.png, then you can use the function:

import subprocess
def grid2gif(image_str, output_gif):
    str1 = 'convert -delay 100 -loop 1 ' + image_str  + ' ' + output_gif
    subprocess.call(str1, shell=True)

Just execute:

grid2gif("dummy_image*.png", "my_output.gif")

This will construct your gif file my_output.gif.


回答 14

可以通过在与图片文件序列相同的文件夹中运行两行python脚本来完成此任务。对于png格式的文件,脚本为-

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')

The task can be completed by running the two line python script from the same folder as the sequence of picture files. For png formatted files the script is –

from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')

回答 15

我一直在寻找单个行代码,并发现以下内容适用于我的应用程序。这是我所做的:

第一步: 从下面的链接安装ImageMagick

https://www.imagemagick.org/script/download.php

第二步: 将cmd线指向放置图像(在我的情况下为.png格式)的文件夹

第三步: 键入以下命令

magick -quality 100 *.png outvideo.mpeg

感谢FogleBird的想法!

I was looking for a single line code and found the following to work for my application. Here is what I did:

First Step: Install ImageMagick from the link below

https://www.imagemagick.org/script/download.php

Second Step: Point the cmd line to the folder where the images (in my case .png format) are placed

Third Step: Type the following command

magick -quality 100 *.png outvideo.mpeg

Thanks FogleBird for the idea!


回答 16

我只是尝试了以下内容,所以非常有用:

首先下载库Figtodatimages2gif到您的本地目录。

其次,将图形收集到数组中并将其转换为动画gif:

import sys
sys.path.insert(0,"/path/to/your/local/directory")
import Figtodat
from images2gif import writeGif
import matplotlib.pyplot as plt
import numpy

figure = plt.figure()
plot   = figure.add_subplot (111)

plot.hold(False)
    # draw a cardinal sine plot
images=[]
y = numpy.random.randn(100,5)
for i in range(y.shape[1]):
    plot.plot (numpy.sin(y[:,i]))  
    plot.set_ylim(-3.0,3)
    plot.text(90,-2.5,str(i))
    im = Figtodat.fig2img(figure)
    images.append(im)

writeGif("images.gif",images,duration=0.3,dither=0)

I just tried the following and was very useful:

First Download the libraries Figtodat and images2gif to your local directory.

Secondly Collect the figures in an array and convert them to an animated gif:

import sys
sys.path.insert(0,"/path/to/your/local/directory")
import Figtodat
from images2gif import writeGif
import matplotlib.pyplot as plt
import numpy

figure = plt.figure()
plot   = figure.add_subplot (111)

plot.hold(False)
    # draw a cardinal sine plot
images=[]
y = numpy.random.randn(100,5)
for i in range(y.shape[1]):
    plot.plot (numpy.sin(y[:,i]))  
    plot.set_ylim(-3.0,3)
    plot.text(90,-2.5,str(i))
    im = Figtodat.fig2img(figure)
    images.append(im)

writeGif("images.gif",images,duration=0.3,dither=0)

回答 17

我遇到了PIL的ImageSequence模块,该模块提供了更好(和更标准)的GIF动画效果。这次我也使用Tk的after()方法,这比time.sleep()更好。

from Tkinter import * 
from PIL import Image, ImageTk, ImageSequence

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = im.info['duration'] # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True;
while play:
  for frame in ImageSequence.Iterator(im):
    if not play: break 
    root.after(delay);
    img = ImageTk.PhotoImage(frame)
    lbl.config(image=img); root.update() # Show the new frame/image

root.mainloop()

I came upon PIL’s ImageSequence module, which offers for a better (and more standard) GIF aninmation. I also use Tk’s after() method this time, which is better than time.sleep().

from Tkinter import * 
from PIL import Image, ImageTk, ImageSequence

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = im.info['duration'] # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True;
while play:
  for frame in ImageSequence.Iterator(im):
    if not play: break 
    root.after(delay);
    img = ImageTk.PhotoImage(frame)
    lbl.config(image=img); root.update() # Show the new frame/image

root.mainloop()

回答 18

制作GIF的简单函数:

import imageio
import pathlib
from datetime import datetime


def make_gif(image_directory: pathlib.Path, frames_per_second: float, **kwargs):
    """
    Makes a .gif which shows many images at a given frame rate.
    All images should be in order (don't know how this works) in the image directory

    Only tested with .png images but may work with others.

    :param image_directory:
    :type image_directory: pathlib.Path
    :param frames_per_second:
    :type frames_per_second: float
    :param kwargs: image_type='png' or other
    :return: nothing
    """
    assert isinstance(image_directory, pathlib.Path), "input must be a pathlib object"
    image_type = kwargs.get('type', 'png')

    timestampStr = datetime.now().strftime("%y%m%d_%H%M%S")
    gif_dir = image_directory.joinpath(timestampStr + "_GIF.gif")

    print('Started making GIF')
    print('Please wait... ')

    images = []
    for file_name in image_directory.glob('*.' + image_type):
        images.append(imageio.imread(image_directory.joinpath(file_name)))
    imageio.mimsave(gif_dir.as_posix(), images, fps=frames_per_second)

    print('Finished making GIF!')
    print('GIF can be found at: ' + gif_dir.as_posix())


def main():
    fps = 2
    png_dir = pathlib.Path('C:/temp/my_images')
    make_gif(png_dir, fps)

if __name__ == "__main__":
    main()

A simple function that makes GIFs:

import imageio
import pathlib
from datetime import datetime


def make_gif(image_directory: pathlib.Path, frames_per_second: float, **kwargs):
    """
    Makes a .gif which shows many images at a given frame rate.
    All images should be in order (don't know how this works) in the image directory

    Only tested with .png images but may work with others.

    :param image_directory:
    :type image_directory: pathlib.Path
    :param frames_per_second:
    :type frames_per_second: float
    :param kwargs: image_type='png' or other
    :return: nothing
    """
    assert isinstance(image_directory, pathlib.Path), "input must be a pathlib object"
    image_type = kwargs.get('type', 'png')

    timestampStr = datetime.now().strftime("%y%m%d_%H%M%S")
    gif_dir = image_directory.joinpath(timestampStr + "_GIF.gif")

    print('Started making GIF')
    print('Please wait... ')

    images = []
    for file_name in image_directory.glob('*.' + image_type):
        images.append(imageio.imread(image_directory.joinpath(file_name)))
    imageio.mimsave(gif_dir.as_posix(), images, fps=frames_per_second)

    print('Finished making GIF!')
    print('GIF can be found at: ' + gif_dir.as_posix())


def main():
    fps = 2
    png_dir = pathlib.Path('C:/temp/my_images')
    make_gif(png_dir, fps)

if __name__ == "__main__":
    main()

回答 19

我了解您问过有关将图像转换为gif的问题;但是,如果原始格式是MP4,则可以使用FFmpeg

ffmpeg -i input.mp4 output.gif

I understand you asked about converting images to a gif; however, if the original format is MP4, you could use FFmpeg:

ffmpeg -i input.mp4 output.gif

回答 20

真是太不可思议了……所有人都提出了一些特殊的程序包来播放GIF动画,目前可以用Tkinter和经典的PIL模块来完成!

这是我自己的GIF动画方法(我之前创建的)。很简单:

from Tkinter import * 
from PIL import Image, ImageTk
from time import sleep

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}    
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = float(im.info['duration'])/1000; # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True; frame = 0
while play:
  sleep(delay);
  frame += 1
  try:
    im.seek(frame); img = ImageTk.PhotoImage(im)
    lbl.config(image=img); root.update() # Show the new frame/image
  except EOFError:
    frame = 0 # Restart

root.mainloop()

您可以设置自己的方式停止动画。让我知道您是否想要使用播放/暂停/退出按钮获取完整版本。

注意:我不确定是从内存还是从文件(磁盘)读取连续的帧。在第二种情况下,如果将它们全部一次读取并保存到一个数组(列表)中,将会更加高效。(我不是很感兴趣找出!:)

It’s really incredible … All are proposing some special package for playing an animated GIF, at the moment that it can be done with Tkinter and the classic PIL module!

Here is my own GIF animation method (I created a while ago). Very simple:

from Tkinter import * 
from PIL import Image, ImageTk
from time import sleep

def stop(event):
  global play
  play = False
  exit() 

root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}    
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = float(im.info['duration'])/1000; # Delay used in the GIF file 
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True; frame = 0
while play:
  sleep(delay);
  frame += 1
  try:
    im.seek(frame); img = ImageTk.PhotoImage(im)
    lbl.config(image=img); root.update() # Show the new frame/image
  except EOFError:
    frame = 0 # Restart

root.mainloop()

You can set your own means to stop the animation. Let me know if you like to get the full version with play/pause/quit buttons.

Note: I am not sure if the consecutive frames are read from memory or from the file (disk). In the second case it would be more efficient if they all read at once and saved into an array (list). (I’m not so interested to find out! :)


PySimpleGUI Python图形用户界面

用于人类的Python图形用户界面

将tkinter、Qt、WxPython和REMI(基于浏览器)GUI框架转换为更简单的界面。通过使用初学者理解的Python核心数据类型(列表和字典)简化了窗口定义。通过将事件处理从基于回调的模型更改为消息传递模型,可以进一步简化

您的代码不是必填项具有面向对象的体系结构,使包可以被更多的受众使用。虽然体系结构很容易理解,但它并不容易理解。必然限制您只处理简单的问题

但是,有些程序并不能很好地适用于PySimpleGUI。根据定义,PySimpleGUI实现底层GUI框架功能的子集。很难准确定义哪些程序适合PySimpleGUI,哪些不适合。这取决于你的计划的细节。复制Excel的每一个细节就是不太适合PySimpleGUI的一个例子

Japanese version of this readme

我想喝杯咖啡!它支持顾问、编辑、域名注册和PySimpleGUI成为一个蓬勃发展的项目所需的许多其他东西。每一笔捐款都是有帮助的,我们需要并感激帮助。


统计数据📈

PyPI统计信息和版本

Tk TK 2.7 Qt WxPython 网络(REMI)

GitHub统计信息

问题 提交活动 星星 文档


什么是PySimpleGUI❓

PySimpleGUI是一个Python包,它允许所有级别的Python程序员创建GUI。您可以使用包含小部件(在PySimpleGUI中称为“元素”)的“布局”来指定GUI窗口。您的布局用于创建一个窗口,该窗口使用4个受支持的框架之一来显示您的窗口并与之交互。支持的框架包括tkinter、Qt、WxPython或REMI。术语“包装器”有时用于这些类型的包裹

您的PySimpleGUI代码比直接使用底层框架编写的代码更简单、更短,因为PySimpleGUI为您实现了大部分“样板代码”。此外,还简化了接口,以便需要尽可能少的代码即可获得所需的结果。根据使用的程序和框架的不同,PySimpleGUI程序可能需要1/2到1/10的代码量才能直接使用其中一个框架创建相同的窗口

虽然目标是封装/隐藏您在其上运行的GUI框架使用的特定对象和代码,但如果需要,您可以直接访问框架的依赖小部件和窗口。如果尚未使用PySimpleGUIAPI公开或访问设置或功能,则不会将您与框架隔开。您可以扩展功能,而无需直接修改PySimpleGUI包本身

弥合“GUI鸿沟”

Python为编程社区带来了大量的人。项目的数量和涉及的领域之广令人难以置信。但通常情况下,除了少数人之外,所有人都无法接触到这些技术。大多数Python程序都是基于“命令行”的。这对于程序员来说不是问题,因为我们都习惯于通过文本界面与计算机交互。虽然程序员对命令行界面没有问题,但大多数“普通人”都有问题。这造成了一个数字鸿沟,一个“GUI鸿沟”

向程序添加GUI可使该程序向更广泛的受众开放。它变得更加平易近人。GUI还可以使与某些程序的交互变得更容易,即使对于那些熟悉命令行界面的人也是如此。最后,有些问题需要GUI


关于我👋

嗨,你们好!我是迈克。你会发现我就在这里,在PySimpleGUI GitHub上,解决问题,不断推动PySimpleGUI向前发展。我把白天、晚上和周末都奉献给了项目和PySimpleGUI用户。我们的成功最终是共享的。当你成功的时候我就成功了

虽然我是Python的新手,但我从70年代就开始编写软件了。我职业生涯的大部分时间都是在硅谷创造产品。我为PySimpleGUI带来了与我开发的公司产品相同的专业精神和奉献精神。你们现在是我的客户了

项目目标🥅

PySimpleGUI项目最重要的两个目标是:

  • 玩得开心
  • 你的成功

有趣的作为一个严肃项目的目标听起来很奇怪,但这是一个严肃的目标。我发现编写这些GUI程序非常有趣。其中一个原因是编写一个完整的解决方案所需的时间非常短。如果我们不享受这个过程,那么就会有人放弃

这里有大量的文档、一本食谱、100个可让您立即运行的演示程序、详细的通话参考资料、YouTube视频、在线特立尼达演示等等。所有人都在努力创造。有趣的经历

你的成功是一个共同的目标。PySimpleGUI是为开发人员构建的。你们是我的偷窥者。看到用户和PySimpleGUI共同努力的结果是意想不到的回报。使用文档和其他材料帮助构建您的应用程序。如果您遇到麻烦,打开Issue on the PySimpleGUI GitHub请看下面关于支撑的部分


教育资源📚

www.PySimpleGUI.org易于记忆,也是文档所在的位置。您将在顶部找到代表几个不同文档的选项卡。文档位于“Read the Docs”(阅读文档)上,因此每个文档都有一个目录,便于搜索

这里有100页的书面文档和100页的示例程序,它们将帮助您非常迅速地发挥作用。使用PySimpleGUI时,您可以在一个下午完成项目,而不需要几天或几周的投资来学习单个GUI包

示例1-单次窗口

这种类型的程序被称为“一次性”窗口,因为该窗口只显示一次,收集的值,然后关闭。它不会像在文字处理器中那样长时间保持打开状态

一个简单的PySimpleGUI程序剖析

PySimpleGUI程序分为5个部分

import PySimpleGUI as sg                        # Part 1 - The import

# Define the window's contents
layout = [  [sg.Text("What's your name?")],     # Part 2 - The Layout
            [sg.Input()],
            [sg.Button('Ok')] ]

# Create the window
window = sg.Window('Window Title', layout)      # Part 3 - Window Defintion
                                                
# Display and interact with the Window
event, values = window.read()                   # Part 4 - Event loop or Window.read call

# Do something with the information gathered
print('Hello', values[0], "! Thanks for trying PySimpleGUI")

# Finish up by removing from the screen
window.close()                                  # Part 5 - Close the Window

代码将生成此窗口


示例2-交互窗口

在本例中,我们的窗口将一直显示在屏幕上,直到用户关闭窗口或单击Quit按钮。您在前面看到的单次窗口与交互式窗口之间的主要区别在于增加了“事件循环”。事件循环从您的窗口读取事件和输入。应用程序的核心位于事件循环中

import PySimpleGUI as sg

# Define the window's contents
layout = [[sg.Text("What's your name?")],
          [sg.Input(key='-INPUT-')],
          [sg.Text(size=(40,1), key='-OUTPUT-')],
          [sg.Button('Ok'), sg.Button('Quit')]]

# Create the window
window = sg.Window('Window Title', layout)

# Display and interact with the Window using an Event Loop
while True:
    event, values = window.read()
    # See if user wants to quit or window was closed
    if event == sg.WINDOW_CLOSED or event == 'Quit':
        break
    # Output a message to the window
    window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI")

# Finish up by removing from the screen
window.close()

这是示例2生成的窗口

下面是在输入字段中输入值并单击确定按钮后的结果

让我们快速了解一下此示例与单一窗口之间的一些不同之处

首先,您会注意到布局中的不同之处。有两个变化尤其重要。其一是添加了key参数添加到Input元素和一个Text元素。一个key类似于元素的名称。或者,在Python术语中,它就像一个字典键。这个Input元素的键将在稍后的代码中用作字典键

另一个不同之处是增加了这个Text元素:

          [sg.Text(size=(40,1), key='-OUTPUT-')],

有两个参数,即key我们已经调查过了。这个size参数定义元素的大小(以字符为单位)。在这种情况下,我们表示这是Text元素宽40个字符,高1个字符。请注意,没有指定文本字符串,这意味着它将为空。您可以很容易地在创建的窗口中看到此空白行

我们还添加了一个按钮“退出”

Event Loop有我们熟悉的window.read()打电话

以下是Read IF语句:

    if event == sg.WINDOW_CLOSED or event == 'Quit':
        break

这段代码检查用户是否通过单击“X”或单击“Quit”按钮关闭了窗口。如果发生这两种情况中的任何一种,则代码将中断事件循环

如果窗口没有关闭,也没有单击Quit按钮,则继续执行。唯一可能发生的事情是用户单击了“确定”按钮。Event Loop中的最后一条语句如下所示:

    window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI")

此语句更新Text具有密钥的元素-OUTPUT-用一根绳子。window['-OUTPUT-']查找具有键的元素-OUTPUT-那把钥匙属于我们的空白处Text元素。一旦该元素从查找中返回,那么它的update方法被调用。几乎所有元素都有一个update方法。此方法用于更改元素的值或更改元素的某些配置

如果我们希望文本是黄色的,那么可以通过添加一个text_color参数添加到update方法,以便它读取:

    window['-OUTPUT-'].update('Hello ' + values['-INPUT-'] + "! Thanks for trying PySimpleGUI",
                              text_color='yellow')

在添加了text_color参数,这是我们新的结果窗口:

每个元素可用的参数都记录在call reference documentation以及文档字符串。PySimpleGUI提供了大量文档来帮助您了解所有可用的选项。如果您查找update方法,用于Text元素,您将找到该调用的以下定义:

正如您可以看到的,有几件事可以更改为Text元素。调用参考文档是一个有价值的资源,它将使PySimpleGUI、uhm、uhm中的编程变得简单


布局很好笑,哈哈!😆

您的窗口布局是“列表列表”(LOL)。窗户被分解成“行”。窗口中的每一行都会成为布局中的列表。将所有列表连接在一起,您就得到了一个布局。列表列表

这是与以前相同的布局,但增加了一个Text元素添加到每行,以便您可以更轻松地查看行是如何定义的:

layout = [  [sg.Text('Row 1'), sg.Text("What's your name?")],
            [sg.Text('Row 2'), sg.Input()],
            [sg.Text('Row 3'), sg.Button('Ok')] ]

此布局的每一行都是将在窗口的该行上显示的元素列表

与使用其他框架进行GUI编程相比,使用列表定义GUI有一些巨大的优势。例如,您可以使用Python的列表理解功能在一行代码中创建按钮网格

这3行代码:

import PySimpleGUI as sg

layout = [[sg.Button(f'{row}, {col}') for col in range(4)] for row in range(4)]

event, values = sg.Window('List Comprehensions', layout).read(close=True)

生成此窗口,该窗口具有4 x 4网格的按钮:

回想一下,“有趣”是该项目的目标之一。直接将Python强大的基本功能应用于GUI问题非常有趣。创建GUI不需要几页代码,只需要几行(通常是1行)代码

折叠代码

可以将窗口的代码压缩为一行代码。布局定义、窗口创建、显示和数据收集都可以用以下代码行编写:

event, values = sg.Window('Window Title', [[sg.Text("What's your name?")],[sg.Input()],[sg.Button('Ok')]]).read(close=True)

将显示相同的窗口,并返回与显示PySimpleGUI程序部分的示例相同的值。能够用这么少的资源做这么多事情,使您能够快速、轻松地将GUI添加到Python代码中。如果您想要显示某些数据并让用户进行选择,可以在一行代码中完成,而不是在一页代码中完成

通过使用速记别名,您可以使用更少的字符来节省更多的代码空间。所有元素都有一个或多个可以使用的较短名称。例如,Text元素可以简单地写为T这个Input元素可以写成I以及Button作为B这样,您的单行窗口代码就变成了:

event, values = sg.Window('Window Title', [[sg.T("What's your name?")],[sg.I()],[sg.B('Ok')]]).read(close=True)

代码可移植性

PySimpleGUI目前能够在4个Python GUI框架上运行。使用IMPORT语句指定要使用的框架。更改导入,您将更改底层GUI框架。对于某些程序,只需更改import语句即可在不同的GUI框架上运行。在上面的示例中,将导入从PySimpleGUIPySimpleGUIQtPySimpleGUIWxPySimpleGUIWeb将会改变框架

导入语句 结果窗口
PySimpleGUI
PySimpleGUIQt
PySimpleGUIWx
PySimpleGUIWeb

将GUI代码从一个框架移植到另一个框架(例如,将代码从tkinter移植到Qt)通常需要重写代码。PySimpleGUI旨在使您能够轻松地在框架之间移动。有时需要进行一些更改,但目标是以最少的更改获得高度可移植的代码

有些功能(如系统托盘图标)并非在所有端口上都可用。系统托盘图标功能在Qt和WxPython端口上可用。在tkinter上有一个模拟版本。PySimpleGUIWeb端口中不支持系统托盘图标

运行时环境

环境 支持
python Python 3.4+
操作系统 Windows、Linux、Mac
硬件 台式PC、笔记本电脑、Raspberry PI、运行PyDroid3的Android设备
在线 repli.it、Trin ket.com(两者都在浏览器中运行tkinter)
GUI框架 tkinter、pyside 2、WxPython、Remi

集成

在200多个“演示程序”中,您可以找到如何将许多流行的Python包集成到您的GUI中的示例

想要将Matplotlib绘图嵌入到您的窗口中吗?没问题,复制演示代码,立即将您的梦想的Matplotlib绘图放到您的GUI中

这些软件包和更多软件包已准备好放入您的GUI中,因为每个软件包都有演示程序或演示回放:

套餐 描述
Matplotlib 多种类型的图表和曲线图
OpenCV 计算机视觉(通常用于人工智能)
VLC 视频播放
金丝雀 物理引擎
Psutil(伪装) 系统环境统计信息
对虾 Reddit API
JSON PySimpleGUI包装了一个特殊的API来存储“用户设置”
天气 集成多个天气API,制作天气应用程序
米多 MIDI播放
美味的汤 Web抓取(GitHub问题观察器示例)

正在安装💾

安装PySimpleGUI的两种常见方式:

  1. 要从PyPI安装的PIP
  2. 下载文件PySimpleGUI.py并将其放入应用程序的文件夹中

PIP安装和升级

当前建议的调用pip命令的方法是使用Python将其作为模块运行。以前的命令是pippip3是直接放到命令行/shell上的。建议的方式

Windows的初始安装:

python -m pip install PySimpleGUI

Linux和MacOS的初始安装:

python3 -m pip install PySimpleGUI

要使用升级,请执行以下操作pip,您只需向该行添加2个参数--upgrade --no-cache-dir

Windows上的升级安装:

python -m pip install --upgrade --no-cache-dir PySimpleGUI

Linux和MacOS升级:

python3 -m pip install --upgrade --no-cache-dir PySimpleGUI

单文件安装

PySimpleGUI被创建为一个单独的.py文件,因此您可以非常容易地安装它,即使是在不像Raspberry PI那样没有连接到互联网的系统上也是如此。只需将PySimpleGUI.py文件放在与导入它的应用程序相同的文件夹中即可。Python在执行导入时将使用您的本地副本

仅使用.py文件进行安装时,您可以从PyPI获取该文件,或者如果要运行最新的未发布版本,则可以从GitHub下载该文件

要从PyPI安装,请下载控制盘或.gz文件并解压缩该文件。如果将.whl文件重命名为.zip,则可以像打开任何普通zip文件一样打开它。您将在其中一个文件夹中找到PySimpleGUI.py文件。将此文件复制到应用程序的文件夹中,即可完成

PySimpleGUI的tkinter版本的PyPI链接为:https://pypi.org/project/PySimpleGUI/#files

GitHub回购的最新版本可在此处找到:https://raw.githubusercontent.com/PySimpleGUI/PySimpleGUI/master/PySimpleGUI.py

现在你们中的一些人在想,“是的,但是,等等,拥有一个巨大的源文件是一个糟糕的想法”。而且,是的,有时候这可能是个糟糕的主意。在这种情况下,好处远远大于坏处。计算机科学中的许多概念都是权衡或主观的。正如一些人所希望的那样,并不是一切都是黑白分明的。很多时候,问题的答案是“视情况而定”。

画廊🎨

用户提交的GUI以及在GitHub上找到的图形用户界面的更正式图库的工作正在进行中,但在撰写本文时还没有完成。目前有2个地方可以集中查看截图。希望维基或其他机制能够很快发布,以公正地对待人们正在进行的令人惊叹的创作

用户提交的库

第一个是一个user submitted screenshots issue位于GitHub上。这是人们炫耀他们所做的东西的一种非正式方式。这不是很理想,但这是一个开始

海量擦除的GitHub图像

第二个是一个massive gallery of over 3,000 images摘自GitHub上据称使用PySimpleGUI的1000个项目。它没有经过手动过滤,而且有很多早期文档中使用的旧屏幕截图。但是,你可能会在那里发现一些能激发你想象力的东西


PySimpleGUI的用法🔨

以下各节展示了PySimpleGUI的一小部分用法。仅在GitHub上就有1000多个项目使用PySimpleGUI。真正令人惊讶的是,为这么多人打开了这样多的可能性。许多用户谈到以前尝试用Python创建GUI都失败了,但是当他们尝试PySimpleGUI时最终实现了他们的梦想

您的第一个GUI

当然,PySimpleGUI最好的用法之一就是让您为Python项目制作GUI。您可以从请求文件名这样的小操作开始。为此,您只需要对一个名为的“高级函数”进行一次调用popup有各种各样的弹出窗口,有些会收集信息

popup在其自身上会生成一个窗口来显示信息。您可以像打印一样传递多个参数。如果您想要获取信息,那么您将调用以popup_get_比如popup_get_filename

添加一行来获取文件名,而不是在命令行上指定文件名,可以将您的程序转换为“普通人”会感到舒服的程序

import PySimpleGUI as sg

filename = sg.popup_get_file('Enter the file you wish to process')
sg.popup('You entered', filename)

此代码将显示2个弹出窗口。一个用于获取文件名,该文件名可以浏览到输入框或粘贴到输入框中

另一个窗口将输出收集到的内容

雨量计式窗户

GUI框架的默认设置往往不会产生最美观的窗口。但是,只要注意一些细节,就可以做几件事来使窗口看起来很吸引人。PySimpleGUI使操作颜色和功能(如删除标题栏)变得更容易。其结果是,窗口看起来与典型的tkinter窗口不同

下面是一个示例,说明如何创建与Windows中典型的tkinter不同的窗口。在本例中,窗口的标题栏被删除。其结果是,窗口看起来与使用Raineter(桌面小部件程序)时发现的窗口非常相似

您还可以轻松地设置窗口的透明度。下面是相同Raineter样式的更多桌面小部件示例。有些是暗淡的,因为它们是半透明的。

这两种效果(移除标题栏和使窗口半透明)都是通过在创建窗口时设置两个参数来实现的。这是一个PySimpleGUI如何支持轻松访问功能的示例。因为PySimpleGUI代码可以跨GUI框架移植,所以这些相同的参数也适用于其他端口,如Qt

将示例1中的窗口创建调用更改为此行代码会生成类似的半透明窗口:

window = sg.Window('My window', layout, no_titlebar=True, alpha_channel=0.5)

游戏

虽然没有专门编写为游戏开发SDK,但PySimpleGUI使某些游戏的开发变得相当容易

这个象棋程序不仅下棋,而且还集成了Stockfish下棋人工智能

用户已经发布了几个版本的扫雷器

纸牌游戏可以很好地与PySimpleGUI配合使用,因为使用PySimpleGUI操作图像非常简单Graph元素

虽然没有专门编写为游戏开发SDK,但PySimpleGUI使某些游戏的开发变得相当容易

媒体捕获和播放

在GUI中捕获和显示网络摄像头中的视频只需要4行PySimpleGUI代码。更令人印象深刻的是,这4行代码可以与tkinter、qt和Web端口配合使用。您可以使用与使用tkinter显示图像相同的代码在浏览器中实时显示您的网络摄像头。

媒体播放,音频和视频,也可以使用VLC播放器实现。我们为您提供了一个演示应用程序,这样您就可以从一个可操作的示例开始。您在本自述中看到的所有内容都可以作为您自己创作的起点

人工智能

当AI和Python组合在一起时,它们长期以来一直是公认的超级大国。然而,经常缺少的是一种让用户使用GUI熟悉地与这些人工智能算法交互的方式

这些YOLO演示是一个很好的例子,说明了GUI如何在与AI算法的交互中产生巨大的差异。请注意这些窗口底部的两个滑块。这两个滑块更改了YOLO算法使用的几个参数

如果您仅使用命令行调整YOLO演示,则需要在启动应用程序时设置参数一次,查看它们的执行情况、停止应用程序、更改参数,最后使用新参数重新启动应用程序

将这些步骤与使用GUI可以完成的操作进行对比。GUI使您能够实时修改这些参数。您可以立即获得有关它们如何影响算法的反馈

有这么多已经发布的人工智能程序是命令行驱动的。这本身并不是一个巨大的障碍,但是要在命令行上键入/粘贴您想要着色的文件名,运行程序,然后在文件查看器中打开结果输出文件,这已经够“屁股痛”了

图形用户界面有能力改变用户体验,以填补“图形用户界面空白”。在此着色器示例中,用户只需提供一个装满图像的文件夹,然后单击图像即可上色并显示结果

进行着色的程序/算法是免费提供的,随时可以使用。缺少的是GUI可能带来的易用性


作图

使用PySimpleGUI,在GUI中显示数据和与数据交互非常简单。您有几个选择

您可以使用内置的绘图/绘图功能来生成自定义图形。此CPU使用情况监视器使用Graph元素

Matplotlib是Python用户的热门选择。PySimpleGUI可以让您将Matplotlib图形直接嵌入到GUI窗口中。如果您想保留Matplotlib交互功能,甚至可以将交互控件嵌入到您的窗口中

使用PySimpleGUI的颜色主题,您可以生成比大多数人在Matplotlib中创建的默认图表高一个档次的图表


前端

前面提到的“GUI差距”可以使用PySimpleGUI轻松解决。您甚至不需要拥有要添加GUI的程序的源代码。“前端”GUI是一种收集信息,然后将这些信息传递给命令行应用程序的图形用户界面

对于程序员来说,前端GUI是分发用户以前不愿使用的应用程序的绝佳方式,因为他们在使用命令行界面时感到不舒服。对于您无权访问其源代码的命令行程序,这些GUI是您唯一的选择

此示例是名为“Jump Cutter”的程序的前端。通过GUI收集参数,使用这些参数构造命令行,然后使用命令行程序的输出将命令执行到GUI界面。在此示例中,您可以看到执行的命令为黄色


覆盆子猪

因为PySimpleGUI与Python3.4兼容,所以它能够为您的Raspberry PI项目创建GUI。当它与触摸屏搭配使用时,效果特别好。如果PI没有连接监视器,您还可以使用PySimpleGUIWeb来控制PI


轻松访问高级功能

因为很容易访问许多底层GUI框架的功能,所以可以将各种功能拼凑在一起来创建与直接使用GUI框架生成的应用程序完全不同的应用程序

例如,不能使用tkinter或其他GUI包更改标题栏的颜色/外观,但使用PySimpleGUI可以很容易地创建窗口,就好像它们有一个自定义标题栏一样

令人难以置信的是,这个窗口正在使用tkinter来实现类似于屏幕保护程序的功能。

在windows上,tkinter可以从你的应用程序中完全移除背景。再一次,PySimpleGUI使访问这些功能变得微不足道。创建透明窗口需要向创建Window只需更改一个参数,即可生成具有以下效果的简单应用程序:

您可以通过单击全屏窗口与桌面上的所有内容进行交互


主题

厌倦了默认的灰色图形用户界面吗?PySimpleGUI只需调用theme功能。有150多种不同的颜色主题可供您选择:

对于大多数GUI框架,您必须为您创建的每个小部件指定颜色。PySimpleGUI会自动为元素上色,使其与您选择的主题相匹配

若要使用主题,请调用theme在创建窗口之前使用主题名称函数。您可以添加空格以提高可读性。要将主题设置为“Dark Grey 9”,请执行以下操作:

import PySimpleGUI as sg

sg.theme('dark grey 9')

这一行代码完全更改了窗口的外观:

主题更改了背景、文本、输入背景、输入文本和按钮颜色的颜色。在其他GUI包中,要像这样更改配色方案,您需要单独指定每个小部件的颜色,这需要对代码进行大量更改


支持💪

你的第一站应该是documentationdemo programs如果您还有问题或需要帮助。没问题。您可以免费获得帮助。简单地说file an Issue在PySimpleGUI GitHub资源库上,您将获得帮助

几乎所有的软件公司都有一个随附错误报告的表格。这是一笔不错的交易。填写表格,即可获得免费软件支持。此信息可帮助您有效地获得答案

除了请求PySimpleGUI和底层GUI框架的版本号等信息外,还向您提供了一份可能帮助您解决问题的项目清单

请填写这张表格你可能会觉得这毫无意义。这可能会感到痛苦,尽管只需要片刻的时间。它可以帮助您更快地获得解决方案。如果它不是帮助你快速回复和修复的有用和必要的信息,你就不会被要求填写它。“帮我帮你”

支持

我们非常感谢对该项目的财政支持。老实说,经济上的帮助是需要的。光是开着灯就很贵。域名注册、一长串的订阅、咨询帮助等,很快就会累积成一笔可观的经常性成本

PySimpleGUI的创建成本并不低。虽然这是一项热爱的劳动,但在几年的时间里,它是非常辛苦的,而且相当多的投资被投入,并将继续投入,创造出你今天看到的东西。

PySimpleGUI拥有开放源码许可,如果它能保持这种状态,那就太好了。如果您或您的公司(特别是如果您在公司中使用PySimpleGUI)通过使用PySimpleGUI获得经济利益,则您有能力延长您和其他用户的项目生命周期

给我买咖啡

给我买杯咖啡是公开支持开发者的一种很好的方式。它快速、简单,并且您的贡献会被记录下来,这样其他人就可以看到您是PySimpleGUI的支持者。您也可以选择将您的捐赠设置为私人捐赠

GitHub赞助商

这个GitHub recurring sponsorship就是如何在持续的基础上以不同级别的支持来赞助该项目。它是指有多少开放源码开发者能够获得企业级赞助

我们将非常感谢您在财政上对该项目的帮助。作为一名开放源码开发人员在财务上具有挑战性。YouTube视频创建者能够通过制作视频谋生。对于开源开发人员来说,这并不容易

谢谢你的谢谢

对于所有帮助过的人,无论以什么方式,我都非常非常感激

即使花点时间说一句“谢谢”也有帮助,而且你们中的很多人都这么做了。事实上,这是一个令人惊叹的数字。我珍视这些感谢,仅从文字中就能找到灵感。每一条信息都是一种小小的推动。它增加了一点能量,保持了整个项目的势头。我非常感谢所有以任何形式帮助过我的人

贡献👷

虽然PySimpleGUI目前是在开放源码许可下获得许可的,但项目本身的结构类似于专有产品。不接受拉取请求

对您来说,贡献代码的最佳方式之一是编写和发布应用程序。用户从看到其他用户构建的内容中获得灵感。这里有一组您可以执行的简单步骤–创建一个GitHub repo,发布代码,并在repo的自述文件中包含一个屏幕截图。然后回到PySimpleGUI资源库,在第10期或项目的Wiki中发布一个屏幕截图

如果缺少您需要的功能,或者您有要建议的增强功能,那么open an Issue

特别感谢🙏

这个版本的PySimpleGUI自述文件如果没有@M4cs他是一位出色的开发人员,自项目启动以来一直是PySimpleGUI的支持者。@israel-dryer是另一个长期的支持者,他已经编写了几个PySimpleGUI程序,推动了包功能的极限。以色列制造了唯一一艘使用图像作为棋盘的扫雷舰。@jason990420当他发布了第一款使用PySimpleGUI的纸牌游戏(如上图所示),以及第一款使用PySimpleGUI制作的扫雷舰游戏时,许多人都大吃一惊。@Chr0nicT是我合作过的最年轻的项目开发人员。这孩子经常让我吃惊。请求一种功能,比如PySimpleGUI GitHub从错误检查机器人发出的问题,不管涉及到什么技术,它都会简单地发生。我很幸运,我们被介绍认识了。总有一天他会被带走,但在那之前我们都受益于他的才华。日文版的自述文件在以下方面的帮助下得到了极大的改进@okajun35@nngogol对该项目产生了非常大的影响,在最初发布的第一年就参与了PySimpleGUI。他编写了一个设计器,提出了熟悉的窗口[键]查找语法,编写了创建文档的工具,设计了第一组文档字符串,以及使用PySimpleGUI代码本身生成在线文档的工具。如果没有这些人的帮助,PySimpleGUI就不会有今天的成就

使用PySimpleGUI的2200多个GitHub回购也应该得到“谢谢”,因为它是这就是推动这个项目引擎的灵感

隔夜在推特上发帖的海外用户是开始一天PySimpleGUI工作的电光。它们一直是让开发引擎启动并准备好每天运行的正能量源泉。为了表示感谢,本自述文件已翻译为Japanese

你们都是开放源码开发人员所希望的最好的用户社区

©版权所有2021 PySimpleGUI

Youtube-dl-gui-用wxPython编写的流行的youtube-dl的跨平台前端GUI

一款流行的跨平台前端GUIyoutube-dl用wxPython编写的媒体下载器。Supported sites

屏幕截图

要求

下载次数

安装

从源安装

  1. 下载并解压缩源代码
  2. 将目录更改为youtube-dl-gui-0.4
  3. python setup.py install

安装PyPi

  1. pip install youtube-dlg

安装Windows Installer

  1. 下载并解压缩Windows Installer
  2. 运行setup.exe文件

贡献

作者

看见AUTHORS文件

许可证

这个Public Domain License

常见问题解答

看见FAQs文件

谢谢

感谢为这个项目做出贡献的每一个人,感谢@philipzae用于设计新的UI布局