简体   繁体   English

在启动树莓派时加载 GUI Python 脚本

[英]Loading GUI Python script on boot for raspberry pi

I'm on Raspberry Pi 3B+ (Raspbian) and I'm trying to load a Python script on boot which display 720p images into full screen mode, the user should then be able to press a push button to go to the next image.我在 Raspberry Pi 3B+(Raspbian)上,我正在尝试在启动时加载 Python 脚本,该脚本将 720p 图像显示为全屏模式,然后用户应该能够按下按钮 go 到下一个图像。

Currently, I have created the code which allows for the images to display and the images to change due to the push button.目前,我已经创建了允许图像显示和图像由于按钮而改变的代码。

Right now I'm having trouble with having the images load into full screen mode and boot on start-up.现在我无法将图像加载到全屏模式并在启动时启动。 I have followed many guides and tutorials on how I can load a GUI Python script on boot but none of them have seemed to work for my specific script (but they loaded on boot successfully from their example scripts) which is making me think that there's an issue in the code for why it won't boot (probably because I haven't implemented so that they open in full screen).我遵循了许多关于如何在启动时加载 GUI Python 脚本的指南和教程,但它们似乎都不适用于我的特定脚本(但它们在启动时从他们的示例脚本成功加载)这让我觉得有一个代码中关于为什么它无法启动的问题(可能是因为我没有实现它们以全屏打开)。 These are all the guides which I tried out ( https://www.raspberrypi-spy.co.uk/2015/02/how-to-autorun-a-python-script-on-raspberry-pi-boot/ , raspberry pi: Auto run GUI on boot , https://raspberrypi.stackexchange.com/questions/4123/running-a-python-script-at-startup , https://www.digikey.ca/en/maker/blogs/2018/how-to-run-python-programs-on-a-raspberry-pi , https://www.instructables.com/Raspberry-Pi-Launch-Python-script-on-startup/ , https://bc-robotics.com/tutorials/running-python-program-boot-raspberry-pi/ ) and I'd like to focus on the GUI method from this tutorial for my question ( https://learn.sparkfun.com/tutorials/how-to-run-a-raspberry-pi-program-on-startup/all )这些是我尝试过的所有指南( https://www.raspberrypi-spy.co.uk/2015/02/how-to-autorun-a-python-script-on-raspberry-pi-boot/raspberry pi:启动时自动运行 GUIhttps: //raspberrypi.stackexchange.com/questions/4123/running-a-python-script-at-startup,https://www.digikey.ca/en/maker/blogs/ 2018/how-to-run-python-programs-on-a-raspberry-pihttps://www.instructables.com/Raspberry-Pi-Launch-Python-script-on-startup/,https ://bc -robotics.com/tutorials/running-python-program-boot-raspberry-pi/ ),我想专注于本教程中针对我的问题的 GUI 方法( https://learn.sparkfun.com/tutorials/如何运行树莓派程序启动/全部

I'm very much a beginner right now when it comes to GUI programming (I took the original script from online and modified it to include the push button) and I'm not too sure on how I can implement the full screen option into the code which displays the images.在 GUI 编程方面,我现在是一个初学者(我从网上获取了原始脚本并对其进行了修改以包含按钮),我不太确定如何将全屏选项实现到显示图像的代码。

Here is what I have currently (will load images into a window, you can then change to the next image using a push button).这是我目前拥有的(将图像加载到 window 中,然后您可以使用按钮更改为下一个图像)。 At the beginning of my code, I tried adding in some functions from the example listed later which allowed toggling of full screen and also their associated root functions at the bottom to complement this在我的代码的开头,我尝试从后面列出的示例中添加一些函数,这些函数允许切换全屏以及它们在底部的相关根函数以补充这一点

import tkinter as tk
from PIL import Image, ImageTk
import time
import sys
import os
import keyboard
import RPi.GPIO as GPIO
import time

    
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(10, GPIO.FALLING) 

def toggle_fullscreen(event=None):    # I added this in to try full screen

    global root
    global fullscreen

    # Toggle between fullscreen and windowed modes
    fullscreen = not fullscreen
    root.attributes('-fullscreen', fullscreen)
    resize()

# Return to windowed mode
def end_fullscreen(event=None):  # I added this in to try full screen

    global root
    global fullscreen

    # Turn off fullscreen mode
    fullscreen = False
    root.attributes('-fullscreen', False)

root= tk.Tk()  # I added this in to try full screen
class HiddenRoot(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        #hackish way, essentially makes root window
        #as small as possible but still "focused"
        #enabling us to use the binding on <esc>
        self.wm_geometry("0x0+0+0")

        self.window = MySlideShow(self)
        #self.window.changeImage()
        self.window.startSlideShow()


class MySlideShow(tk.Toplevel):
    def __init__(self, *args, **kwargs):
        tk.Toplevel.__init__(self, *args, **kwargs)
        #remove window decorations 
        self.overrideredirect(True)

        #save reference to photo so that garbage collection
        #does not clear image variable in show_image()
        self.persistent_image = None
        self.imageList = []
        self.pixNum = 0

        #used to display as background image
        self.label = tk.Label(self)
        self.label.pack(side="top", fill="both", expand=True)

        self.getImages()
        
        #### Added the GPIO event here
        GPIO.add_event_callback(10, self.changeImage)
        
    def getImages(self):
        '''
        Get image directory from command line or use current directory
        '''
        if len(sys.argv) == 2:
            curr_dir = sys.argv[1]
        else:
            curr_dir = '.'

        for root, dirs, files in os.walk(curr_dir):
            for f in files:
                if f.endswith(".png") or f.endswith(".jpg"):
                    img_path = os.path.join(root, f)
                    print(img_path)
                    self.imageList.append(img_path)

   
    def startSlideShow(self, delay=4):
        myimage = self.imageList[self.pixNum]
        self.pixNum = (self.pixNum + 1) % len(self.imageList)
        self.showImage(myimage)
        #self.after(delay*1000, self.startSlideShow)
     #   while True:
      #      buttonState = GPIO.input(buttonPin)
       #     if buttonState == False:
        #        self.startSlideShow(self, delay=4)
    #@staticmethod
    def changeImage(self, pull_up_down=GPIO.PUD_DOWN):
        prev_input = 0
        while True:
          #take a reading
          input = GPIO.input(10)
          #if the last reading was low and this one high, print
          if ((not prev_input) and input):
            myimage = self.imageList[self.pixNum]
            self.pixNum = (self.pixNum + 1) % len(self.imageList)
            self.showImage(myimage)
          #update previous input
          prev_input = input
          #slight pause to debounce
          time.sleep(0.05)
   #     myimage = self.imageList[self.pixNum]
    #    self.pixNum = (self.pixNum + 1) % len(self.imageList)
     #   self.showImage(myimage)
        

    def showImage(self, filename):
        image = Image.open(filename)  

        img_w, img_h = image.size
        scr_w, scr_h = self.winfo_screenwidth(), self.winfo_screenheight()
        width, height = min(scr_w, img_w), min(scr_h, img_h)
        image.thumbnail((width, height), Image.ANTIALIAS)

        #set window size after scaling the original image up/down to fit screen
        #removes the border on the image
        scaled_w, scaled_h = image.size
        self.wm_geometry("{}x{}+{}+{}".format(scaled_w,scaled_h,0,0))
        
        # create new image 
        self.persistent_image = ImageTk.PhotoImage(image)
        self.label.configure(image=self.persistent_image)


slideShow = HiddenRoot()
slideShow.bind("<Escape>", lambda e: slideShow.destroy())  # exit on esc
slideShow.mainloop()
root.bind('<F11>', toggle_fullscreen)              # I added this in to try full screen
root.bind('<Escape>', end_fullscreen)              # I added this in to try full screen
toggle_fullscreen()                                # I added this in to try full screen
root.mainloop()                                    # I added this in to try full screen
GPIO.cleanup()                 

And from that guide I said to note earlier, here is the code they which loads a clock into fullscreen mode (and I followed their method of loading the script on boot which worked)从我之前说过要注意的那个指南中,这是他们将时钟加载到全屏模式的代码(我遵循了他们在启动时加载脚本的方法)

import tkinter as tk
import tkinter.font as tkFont
import time

###############################################################################
# Parameters and global variables

# Default font size
font_size = -24

# Declare global variables
root = None
dfont = None
frame = None
dtime = None

# Global variable to remember if we are fullscreen or windowed
fullscreen = False

###############################################################################
# Functions

# Toggle fullscreen
def toggle_fullscreen(event=None):

    global root
    global fullscreen

    # Toggle between fullscreen and windowed modes
    fullscreen = not fullscreen
    root.attributes('-fullscreen', fullscreen)
    resize()

# Return to windowed mode
def end_fullscreen(event=None):

    global root
    global fullscreen

    # Turn off fullscreen mode
    fullscreen = False
    root.attributes('-fullscreen', False)
    resize()

# Automatically resize font size based on window size
def resize(event=None):

    global time_dfont
    global button_dfont
    global frame

    # Resize font based on frame height (minimum size of 12)
    # Use negative number for "pixels" instead of "points"
    new_size = -max(12, int((frame.winfo_height() / 2)))
    time_dfont.configure(size=new_size)
    new_size = -max(12, int((frame.winfo_height() / 30)))
    button_dfont.configure(size=new_size)


# Read values from the sensors at regular intervals
def update():

    global root
    global dtime

    # Get local time
    local_time = time.localtime()

    # Convert time to 12 hour clock
    hours = local_time.tm_hour
    if hours > 12:
        hours -= 12

    # Add leading 0s
    shours = str(hours)
    smin = str(local_time.tm_min)
    if hours < 10:
        shours = '0' + shours
    if local_time.tm_min < 10:
        smin = '0' + smin

    # Construct string out of time
    dtime.set(shours + ':' + smin)

    # Schedule the poll() function for another 500 ms from now
    root.after(500, update)

###############################################################################
# Main script

# Create the main window
root = tk.Tk()
root.title("My Clock")

# Create the main container
frame = tk.Frame(root, bg='black')

# Lay out the main container (expand to fit window)
frame.pack(fill=tk.BOTH, expand=1)

# Variables for holding temperature and light data
dtime = tk.StringVar()

# Create dynamic font for text
time_dfont = tkFont.Font(family='Courier New', size=font_size)
button_dfont = tkFont.Font(size=font_size)

# Create widgets
label_time = tk.Label(  frame, 
                        textvariable=dtime, 
                        font=time_dfont, 
                        fg='red', 
                        bg='black')
button_quit = tk.Button(frame, 
                        text="Quit", 
                        font=button_dfont, 
                        command=root.destroy,
                        borderwidth=0,
                        highlightthickness=0, 
                        fg='gray10',
                        bg='black')

# Lay out widgets in a grid in the frame
label_time.grid(row=0, column=0, padx=20, pady=20)
button_quit.grid(row=1, column=0, padx=5, pady=5, sticky=tk.E)

# Make it so that the grid cells expand out to fill window
frame.rowconfigure(0, weight=10)
frame.rowconfigure(1, weight=1)
frame.columnconfigure(0, weight=1)

# Bind F11 to toggle fullscreen and ESC to end fullscreen
root.bind('<F11>', toggle_fullscreen)
root.bind('<Escape>', end_fullscreen)

# Have the resize() function be called every time the window is resized
root.bind('<Configure>', resize)

# Schedule the poll() function to be called periodically
root.after(20, update)

# Start in fullscreen mode and run
toggle_fullscreen()
root.mainloop()

Now what I'm trying to figure out is how I can implement their method of going into a full screen display into my program现在我想弄清楚的是如何在我的程序中实现他们进入全屏显示的方法

Thank you:)!谢谢:)!

I am not sure if I really understood your question.我不确定我是否真的理解你的问题。

I understood you want to change on certain events to full screen.我了解您想将某些事件更改为全屏。 If yes, you just need to change the geometry property of your root.如果是,您只需要更改根的几何属性。 Like for example比如像

master.geometry("{0}x{1}+0+0".format( master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad)) master.geometry("{0}x{1}+0+0".format(master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad))

above code checks for screen size and reduces some distance on w and h to fit in screen.上面的代码检查屏幕大小并减少 w 和 h 上的一些距离以适应屏幕。 Have a look to below link.看看下面的链接。

https://stackoverflow.com/questions/7966119/display-fullscreen-mode-on-tkinter#:~:text=This%20creates%20a%20fullscreen%20window,geometry%20and%20the%20previous%20geometry.&text=You%20can%20use%20wm_attributes%20instead%20of%20attributes%20%2C%20too . https://stackoverflow.com/questions/7966119/display-fullscreen-mode-on-tkinter#:~:text=This%20creates%20a%20fullscreen%20window,geometry%20and%20the%20previous%20geometry.&text=You %20can%20use%20wm_attributes%20instead%20of%20attributes%20%2C%20too

you can create a function with that call and trigger it on start up or button pressed.您可以使用该调用创建一个 function 并在启动或按下按钮时触发它。

Hope my guess is right and this answers helps.希望我的猜测是正确的,这个答案会有所帮助。

Cheers干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM