如何使用 pysimplegui 为我的 GUI 创建背景?

How can I create a background for my GUI with pysimplegui?

我正在尝试在我的 raspberry pi 上为 运行 创建一个 pysimplegui 应用程序。我设法设置了一张背景图片,但要使其正常工作,我需要打开 2 个 windows,一个用于背景,一个用于我的应用程序的布局(长度 x 宽度输入)。 如何制作一个 pysimplegui 应用程序,在其中向 window 添加背景,同时还能够在其上添加布局? 我目前使用的代码是:

import PySimpleGUI as sg
from io import BytesIO
from PIL import Image
import os

def image_to_data(im):
    """
    Image object to bytes object.
    : Parameters
      im - Image object
    : Return
      bytes object.
    """
    with BytesIO() as output:
        im.save(output, format="PNG")
        data = output.getvalue()
    return data

class GUI:
    def __init__(self):
        self.size = (1280, 800)
        self.background_image = os.path.join(os.getcwd(), 'background.png')
        self.im = Image.open(self.background_image)
        #background
        self.background_layout = [[sg.Image(data=image_to_data(self.im))]]
        self.window_background = sg.Window('Background', self.background_layout, no_titlebar=True, finalize=True, margins=(0, 0), element_padding=(0,0), right_click_menu=[[''], ['Exit',]])
        #background
        self.column1 = [
                [sg.Text('Fill in the length', justification='center', font='Helvetica 18')],
                [sg.Input(justification='center', key='length'), sg.Text('X', justification='center'), sg.Input(justification='center', key='width')],
                [sg.Button('OK', key='OK')],
                [sg.Button('Exit', key='Exit')]
            ]

        self.layout = [
            [sg.Column(self.column1, element_justification='center')]
        ]
        self.window = sg.Window('Title', keep_on_top=True, layout=self.layout, finalize=True, grab_anywhere=False, transparent_color=sg.theme_background_color(), no_titlebar=True)
        
        self.start()
    def start(self):
        while True:
            window, event, values = sg.read_all_windows()
            if event in (sg.WINDOW_CLOSED, 'Exit'):
                break
        self.window.close()
        self.window_background.close()

if __name__ == '__main__':
    if os.environ.get('DISPLAY','') == '':
        print('DISPLAY variable will be set to :0.0')
        os.environ.__setitem__('DISPLAY', ':0.0')
        GUI()
    else:
        print('DISPLAY variable is already set to :0.0')

此代码工作正常,但如果我单击 window 之外的任何位置,我会在我的 window 前面单击包含我 raspberry pi 上的背景图像,window 消失在后面。 我的问题: 有没有办法只创建一个 window 带有背景图像,我可以在其上添加布局?

编辑:考虑到我对 pysimplegui 的经验为 0,并且过去使用 Kivy 做过一些项目,我决定坚持使用 Kivy。结束这个问题。

Kivy 示例代码:

main.py:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
Config.set('graphics', 'width', '1280')
Config.set('graphics', 'height', '800')

class MainWidget(BoxLayout):
    pass

class TheLabApp(App):
    pass

if __name__ == '__main__':
    TheLabApp().run()

thelab.kv:

#:kivy 2.1.0
MainWidget:

<MainWidget>:
    canvas.before:
        Rectangle:
            pos: self.pos
            size: self.size
            source: 'assets/background.png' #note how simple it is to add a background image
    BoxLayout:
        orientation: 'vertical'
        Label:
        BoxLayout:
            orientation: 'vertical'
            Label:
                text: 'Fill in the length'
                font_size: 30
            BoxLayout:
                orientation: 'horizontal'
                TextInput:
                    id: width
                    multiline: False
                    font_size: 30
                    #size_hint: (0.5, 1)
                Label:
                    text: 'X'
                    font_size: 20
                TextInput:
                    id: length
                    multiline: False
                    font_size: 20
        Label:

这是示例,但使用了 tkinter 代码。

import os
from io import BytesIO
from PIL import Image
import PySimpleGUI as sg

def image_to_data(im):

    with BytesIO() as output:
        im.save(output, format="PNG")
        data = output.getvalue()
    return data

def make_background(window, file, main_frame):

    global images

    def find_frames(widget):
        widgets = list(widget.children.values())
        if isinstance(widget, (sg.tk.Frame, sg.tk.LabelFrame)):
            widget.update()
            x, y = widget.winfo_rootx() - x0, widget.winfo_rooty() - y0
            width, height = widget.winfo_width(), widget.winfo_height()
            new_im = im_.crop((x, y, x+width, y+height))
            image = sg.tk.PhotoImage(data=image_to_data(new_im))
            images.append(image)
            label = sg.tk.Label(widget, image=image, padx=0, pady=0, bd=0, bg=bg)
            label.place(x=0, y=0)
            label.lower()
        for widget in widgets:
            find_frames(widget)

    size = window.size
    im_ = Image.open(file).resize(size)
    root = window.TKroot
    widgets = list(root.children.values())
    x0, y0 = root.winfo_rootx(), root.winfo_rooty()

    frame = sg.tk.Frame(root, padx=0, pady=0, bd=0, bg=bg)
    frame.place(x=0, y=0)
    images = []
    image = sg.tk.PhotoImage(data=image_to_data(im_))
    images.append(image)
    label = sg.tk.Label(frame, image=image, padx=0, pady=0, bd=0, bg=bg)
    label.pack()
    main_frame.Widget.master.place(in_=frame, anchor='center', relx=.5, rely=.5)
    frame.lower()
    frame.update()
    for widget in widgets:
        find_frames(widget)

bg = sg.theme_background_color()
background_image_file = os.path.join(os.getcwd(), 'background.png')
size = (640, 480)

sg.set_options(dpi_awareness=True)

frame = [
    [sg.Text('Fill in the length', justification='center', background_color='black', font='Helvetica 18')],
    [sg.Input(justification='center', size=10, key='length'),
     sg.Text('X', justification='center', background_color='black'),
     sg.Input(justification='center', size=10, key='width')],
    [sg.Button('OK', key='OK')],
    [sg.Button('Exit', key='Exit')]
]
# Need only one frame here to move it to center of window
layout = [[sg.Frame('', frame, border_width=0, key='FRAME', background_color=bg)]]

location = sg.Window.get_screen_size()
window = sg.Window('Background Demo', layout, margins=(0, 0), grab_anywhere=True,
    size=size, keep_on_top=True, finalize=True,
    no_titlebar=True,
    transparent_color=bg,
)

images = []
make_background(window, background_image_file, window['FRAME'])

while True:
    event, values = window.read()
    if event in (sg.WINDOW_CLOSED, 'Cancel', 'Exit'):
        break
    print(event)

window.close()