在树莓派 B+ 上使用 tkinter 从引导 shell 脚本没有显示名称和 $DISPLAY 环境变量 [英] No display name and no $DISPLAY environment variable using tkinter on raspberry Pi B+ from boot shell script

查看:63
本文介绍了在树莓派 B+ 上使用 tkinter 从引导 shell 脚本没有显示名称和 $DISPLAY 环境变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的第一篇文章,如果我做错了什么,我深表歉意.

my first post so apologies if I do anything wrong.

我在 python3 上使用 tkinter 编写了一个 python 脚本,该脚本在 IDLE3 中运行良好.我希望在启动 Pi 时运行此脚本,因此执行以下过程以使用 cron 作业运行 @reboot.http://www.instructables.com/id/Raspberry-Pi-Launch-Python-script-on-startup/step4/Add-to-your-crontab/

I have written a python script using tkinter on python3 that runs totally fine from within IDLE3. I wanted this script to run when i started up the Pi so did the following procedure to run @reboot using a cron job. http://www.instructables.com/id/Raspberry-Pi-Launch-Python-script-on-startup/step4/Add-to-your-crontab/

最初我遇到了初始化错误,所以我添加了'/bin/sleep 120;'到@reboot 行,因此它现在读取如下,并且似乎等待足够长的时间以在启动后初始化所有内容.@reboot/bin/sleep 120;sh/home/pi/launcher.sh >/home/pi/logs/cronlog 2>&1

Initially I got an initialisation error so I added in '/bin/sleep 120 ;' to the @reboot line so it now reads as follows and seems to wait long enough for everything to initialise after boot. @reboot /bin/sleep 120; sh /home/pi/launcher.sh >/home/pi/logs/cronlog 2>&1

但是在此之后,我的 cronlog 显示以下错误:

But following this my cronlog shows the following error:

回溯(最近一次调用最后一次):文件walk.py",第 29 行,在MyGUI = Tk() 文件 "/usr/lib/python3.2/tkinter/init.py",第 1701 行,在 init self.tk = _tkinter.create(screenName, baseName,className、interactive、wantobjects、useTk、sync、use)_tkinter.TclError: 没有显示名称和 $DISPLAY 环境变量

Traceback (most recent call last): File "walk.py", line 29, in MyGUI = Tk() File "/usr/lib/python3.2/tkinter/init.py", line 1701, in init self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use) _tkinter.TclError: no display name and no $DISPLAY environment variable

现在我在其他线程上看到了这个错误,许多似乎与我不使用的初始化库有关.我想补充一点,我的代码在空闲状态下运行良好,从终端运行良好,我已经制作了 launcher.sh 并使其可执行,如果我从终端运行 'sh launcher.sh' 它工作正常,所以 launcher.sh shell 脚本看起来不错.但是在启动时出现上述错误,我不知道为什么?请帮忙.

Now I have seen this error on other threads and many seem to relate to initialising libraries that I don't use. I want to add that my code runs fine from idle, fine from terminal, I have made launcher.sh and made it executable and if I run 'sh launcher.sh' from terminal it works fine so the launcher.sh shell script seems good. but on boot I get the above error and i have no idea why? Please help.

我在这台机器上没有代码的副本,但如果有人认为这会有所帮助,我会尝试将其复制并作为评论发布.

I do not have a copy of the code on this machine but I will try to copy it across and post it as a comment if anyone thinks that would help.

提前致谢保罗

完整代码如下

import sys
import tkinter #might not be needed
from tkinter import *
import pymysql
import os.path
import datetime
import json

#Define local database connection
try:
    localdb = pymysql.connect(host="localhost", user="root", passwd="p054169q", db="walk")
except Exception as e:
    sys.exit('Can not locate localdb')

lcur = localdb.cursor()

#Define web database connection (Maybe add later for easy sync)

#Initialise GUI using Tkinter 
MyGUI = Tk()

#Remove title bar from GUI window
#(BUG: Causes window not to have focus for scanning)
#MyGUI.overrideredirect(1)
#Doing it this way works but disable until working on small screen, this just sets window as fullscreen
#MyGUI.attributes('-fullscreen', True)

#Set window to resolution of screen 800x420 pixels
MyGUI.geometry('800x420')
#Set window title (Perhaps later remove title bar if possible)
MyGUI.title('Island Walk Tracker')

#Set window background colour to black
MyGUI.configure(background='black')



##GLOBAL VARIABLES ##

#Create variable for RFID code
global RFIDcode
RFIDcode = ''

#Create variable for checkpoint number
global checkpoint_number
checkpoint_number = 2

#Create variable for photo filepath
global photo_path
photo_path = ''




## DECLARE ALL TKINTER VARIABLES ##
#Declare like this for a tkinter variable to update dynamically on GUI (A global var will not do this)
rfid_codeTK = StringVar()
rfid_codeTK.set('')

walk_numberTK = IntVar()
walk_numberTK.set(0)

fullnameTK = StringVar()
fullnameTK.set('')

classTK = StringVar()
classTK.set('')




## DEFINE LABELS AND HOW/WHERE THEY APPEAR ON THE SCREEN ##
#USE 'textvariable' instead of text for labels below to link to a live variable (See info here http://www.tutorialspoint.com/python/tk_label.htm)

#Spacer label just adds blank label of fixed width to set width of column and space down one row from top of page
lblSpacer = Label (text = '                                                                                         ',fg='white',bg='black',font = 'Helvetica 8 bold')
lblSpacer.grid(row=0,column=0)

#TEST CODE: Display variable RFIDcode in a label for testing. Comment out to hide rfid code.
#lblRFID = Label (MyGUI,textvariable = rfid_codeTK ,fg='white',bg='black',font = 'Helvetica 20 bold')
#lblRFID.grid(row=3,column=1)

#Display Walk number in a label
lblWalkNumber = Label(MyGUI,textvariable = walk_numberTK ,fg='white',bg='black',font = 'Helvetica 115 bold')
#Unlike other TK variables this is not placed in grid until after scan as this stops a big '0' appearing on screen
#lblWalkNumber.grid(row=2,column=0)

#Display Walker name in a label
lblWalkerName = Label (MyGUI,textvariable = fullnameTK ,fg='white',bg='black',font = 'Helvetica 25 bold')
lblWalkerName.grid(row=3,column=0)

#Display class in a label
lblWalkerClass = Label(MyGUI,textvariable = classTK ,fg='white',bg='black',font = 'Helvetica 25 bold')
lblWalkerClass.grid(row=4,column=0)

#Display photo on the screen
#TEST CODE: later on change 'Blank' for the field in database that represents Student_ID
#photo_path = 'WALK_PHOTOS/'+ 'Blank' +'.gif'
#pic = PhotoImage(file= photo_path )
#ImgWalkerPhoto = Label(MyGUI,image = pic)
#ImgWalkerPhoto.grid(row=2,column=1)




## EVENT OCCURS WHEN RFID CODE IS ENTERED (following 'enter' keypress) ##
def Update_Walker_Screen(event):
    global RFIDcode
    global photo_path
    global checkpoint_number

    #Search database for matching RFIDcode from localdb and SELECT all data from that row
    lcur.execute("SELECT walk_number, forename, surname, class, student_id FROM walkers WHERE rfid_code = '"+ RFIDcode +"'")
    row = lcur.fetchall()


## SET POSITIONS OF THINGS ON THE TKINTER FORM ##

    #Display walker number in its label (done here after the scan event as if done above with other TK variables a big '0' appears on screen because it is an int so has a '0' not null value when initialised.
    lblWalkNumber.grid(row=2,column=0)

    pic = PhotoImage(file='WALK_PHOTOS/'+ 'Blank' +'.gif')
    ImgWalkerPhoto = Label(MyGUI,image = pic)
    #Hide image for testing
    #ImgWalkerPhoto.grid(row=2,column=1)


## SET VARIABLES TO DISPLAY ON SCREEN (WILL AUTO UPDATE SCREEN WHEN TK VARIABLES CHANGE) ## 

    #Set rfid_codeTK variable to be RFIDcode from the code entered from scan.
    rfid_codeTK.set(RFIDcode)

    #Set walk_numberTK variable to be walk_number from the fetched database record
    walk_numberTK.set(row[0][0])

    #Set fullnameTK variable to be forename + surname from the fetched database record
    fullnameTK.set(row[0][1] + ' ' + row[0][2])

    #Set classTK variable to be class from the fetched database record
    classTK.set(row[0][3])

    #Display photo on the screen after scan

    photo_path = 'WALK_PHOTOS/'+ row[0][4] +'.gif'

    if os.path.isfile(photo_path) == True:
        #show photo with filename as
        photo_path = 'WALK_PHOTOS/'+ row[0][4] +'.gif'
    else:
        #show blank photo
        photo_path = 'WALK_PHOTOS/Blank.gif'

    #Display image
    #ImgWalkerPhoto.grid(row=2,column=1)

    #This should update screen items (does flash picture up but not sure if its any use)
    #MyGUI.update_idletasks()

    #Look up current time
    walkers_time = datetime.datetime.now().strftime("%H:%M:%S")

    #Log time into database in correct checkpoint column
    if checkpoint_number == 1:
        #sqlquery = """INSERT INTO walkers('ckpt_1') VALUES({0})""".format(json.dumps(walkers_time))
        #lcur.execute("INSERT INTO walkers('ckpt_1') VALUES ()
        print('Checkpoint 1 selected')
    elif checkpoint_number == 2:
        sqlquery = "INSERT INTO walkers('ckpt_1') VALUES({0})".format(json.dumps(walkers_time))
        print(sqlquery)
        print('Checkpoint 2 selected')
    elif checkpoint_number == 3:
        print('Checkpoint 3 selected')
    elif checkpoint_number == 4:
        print('Checkpoint 4 selected')
    elif checkpoint_number == 5:
        print('Checkpoint 5 selected')
    elif checkpoint_number == 6:
        print('Checkpoint 6 selected')
    elif checkpoint_number == 7:
        print('Checkpoint 7 selected')
    elif checkpoint_number == 8:
        print('Checkpoint 8 selected')
    elif checkpoint_number == 9:
        print('Checkpoint 9 selected')
    elif checkpoint_number == 10:
        print('Checkpoint 10 selected')
    elif checkpoint_number == 11:
        print('Checkpoint 11 selected')
    elif checkpoint_number == 12:
        print('Checkpoint 12 selected')
    else:
        #Checkpoint not correctly selected so ask them to restart and select a new checkpoint number
        print('Please select a checkpoint number') 


    #Write the scanned walker details into text file ready to email. If file does not exist then create it, else append to existing file.
    #file = open('emaildata.txt', 'a')
    with open('emaildata.txt', 'a') as myfile:
        myfile.write(str(row[0][0]) + ',' + str(walkers_time) + ',' + 'Y' + '|')#walk_numberTK.get())

    #Clear global variable RFIDcode ready for next scan.
    RFIDcode = ''


#This function detects any keypresses and then adds them intothe RFIDcode global string variable
#(Ignores Enter key as thats handled earlier in code so never reaches it. Add extra ignores if needed above.)
def keypress(event):
    global RFIDcode
    RFIDcode = RFIDcode + str(event.char)


#Bind any key press to run the keypress function.
MyGUI.bind('<Key>',keypress)

#Bind an 'Enter' key press to run the Update_Walker_Screen function. 
MyGUI.bind('<Return>',Update_Walker_Screen)


MyGUI.mainloop()

推荐答案

我认为不是您的代码问题导致了您的错误.尤其是因为你说:

I don't think a problem with your code is causing your error. Especially since you said:

我想补充一点,我的代码在空闲时运行良好,从终端运行良好

I want to add that my code runs fine from idle, fine from terminal

让我建议,虽然 cron 是用于安排重复性作业的出色工具,我经常使用它(实际上是每分钟永远),但它可能不是满足您的需求的最佳工具.

Let me suggest that while cron is an excellent tool for scheduling recurring jobs, which I use constantly (every minute forever, actually), it may not be the best tool to meet your needs here.

既然您想在 PI 启动时运行您的程序,并且您的程序在 X 中运行,为什么不将它添加到 LXDE 自动启动文件中?使用 nano 或您选择的文本编辑器,编辑以下文件:
对于较旧的 Raspbian 构建:

Since you want to run your program when your PI boots, and your program runs in X, why don't you add it to the LXDE autostart file? Using nano, or the text editor of your choice, edit the following file:
For older Raspbian builds:

sudo nano /etc/xdg/lxsession/LXDE/autostart

或者对于当前的 Rasbian 构建:

Or for current Rasbian builds:

sudo nano /etc/xdg/lxsession/LXDE-pi/autostart

添加以下行,然后保存文件:

Add the following line, and then save the file:

@sh /home/pi/launcher.sh

或者如果你还想要一个终端窗口,用于调试:

Or if you want a terminal window also, for debugging:

@lxterminal --command='sh /home/pi/launcher.sh'


此外,您可以通过两个简单的步骤使 shell 脚本和 python 脚本可执行.


Also, you can make shell scripts and python scripts executable with two simple steps.

  1. 在脚本的第一行添加一个 hashbang.
    Python:   #!/usr/bin/python2   或  #!/usr/bin/python3

    外壳:   #!/bin/sh   或者也许   #!/bin/bash
  2. 将脚本标记为可执行.从命令行输入:

  1. Add a hashbang to the very first line of the script.
    Python:   #!/usr/bin/python2   or   #!/usr/bin/python3

    Shell:   #!/bin/sh   or maybe   #!/bin/bash
  2. Mark the script as executable. From the command line enter:

chmod +X ./myscript.sh  或 sudo chmod 755 ./myscript.sh

chmod +X ./myscript.sh  or  sudo chmod 755 ./myscript.sh

这篇关于在树莓派 B+ 上使用 tkinter 从引导 shell 脚本没有显示名称和 $DISPLAY 环境变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆