Reputation: 329
I'm trying to create a pysimplegui application to run on my raspberry pi. I managed to set a background image, but for it to work I need to open 2 windows, one for the background and one for the layout for my app (which is length x width inputs). How can I make a pysimplegui app where I add a background to the window while also being able to add a layout on top of it? The code I'm working with at the moment is:
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')
This code works fine, but if I click anywhere besides the window I put in front of my window containing a background image on my raspberry pi, the window disappears in the back. My question: Is there a way to create just one window with a background image on which I can add a layout ?
EDIT: considering I have 0 experience with pysimplegui, and made some projects in the past using Kivy, I've decided to stick to Kivy. Closing this question.
Kivy example code:
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:
Upvotes: 1
Views: 1100
Reputation: 13061
Here's the example, but with tkinter code.
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()
Upvotes: 1