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

查看:135
本文介绍了在启动shell脚本中在树莓派B +上使用tkinter时没有显示名称,也没有$ 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,交互式,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 版本:

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     or    #!/usr/bin/python3

    Shell:   #!/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

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

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