好的,所以我正在编写一个使用 pytray 创建系统托盘图标的脚本。该脚本基本上连接到用户谷歌日历,并且(好吧,最终无论如何)允许您选择要使用的日历并向您显示不同的即将发生的事件。
问题 #1 选择我想使用的日历时,我总是在选择日历时获得最后一个日历 ID。我的通讯录日历恰好是我日历列表中列出的最后一个。当我选择任何日历时,我总是会获得地址簿日历的 ID。
我认为与此问题有关的代码:
def set_cal_id(self, cal_id):
self.cal_id = cal_id
print(self.cal_id)
# return self.cal_id
def get_cal_id(self):
return self.cal_id
def build_calendar_list(self):
cal_list = []
calendarlist = self.service.calendarList().list().execute()
for k in calendarlist.get('items', tuple()):
# print(k['id'])
calendar_id = k['id']
cal_list.append(
(item(k["summary"], lambda *args: self.set_cal_id(calendar_id)))
)
# pprint.pprint(k)
# pprint.pprint(cal_list)
# print(self.cal_id)
return cal_list
问题 #2(已修复)当使用 pystray 在系统托盘中创建我的日历列表时,是否有某种方法可以遍历我正在构建的元组并列出它?我必须手动输入元组中每个项目的索引才能列出菜单。有什么方法可以“动态/以编程方式”做到这一点吗?
更新问题 #2 我只需要 menu() 中的 lambda 函数来正确创建所有项目
与此问题相关的代码:
def create_tray(self):
# count = self.cal_list.count()
menu_items = tuple(self.cal_list)
icon(
'TrayCalendar',
icon=self.tray_icon(),
# visible=True,
menu=menu(
item(
'Quit',
self.good_bye
),
item(
'Calendar List',
menu(
lambda: (item for item in menu_items)
),
),
)
).run()
我认为最好知道一些事情:
我现在正在严格地为 Windows 编写这个。我稍后会扩展,也许嗯,现在不确定这只是一个“嘿,我可以做这个”的项目。
build_calendar_list() 为 pystray 的 MenuItem() 创建元组
create_tray() 创建托盘图标。
我正在 MyCalendar 类的 init 函数中构建日历列表。
我也可能这样做完全错误。
我认为问题在于,当它使用 lambda 函数生成列表时,无论出于何种原因,它都会导致回调的所有参数成为堆栈中的最后一项。如果是这种情况,那么生成此列表的更好方法是什么?
下面是完整的代码。
from __future__ import print_function
import datetime
import os.path
import pprint
import sys
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from PIL import Image
from pystray import Icon as icon, Menu as menu, MenuItem as item
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/calendar']
class MyCalendar:
def __init__(self):
"""Shows basic usage of the Google Calendar API.
Prints the start and name of the next 10 events on the user's calendar.
"""
self.creds = None
# The file token.json stores the user's access and refresh tokens, and is
# created automatically when the authorization flow completes for the first
# time.
if os.path.exists('token.json'):
self.creds = Credentials.from_authorized_user_file('token.json', SCOPES)
# If there are no (valid) credentials available, let the user log in.
if not self.creds or not self.creds.valid:
if self.creds and self.creds.expired and self.creds.refresh_token:
self.creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
self.creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.json', 'w') as token:
token.write(self.creds.to_json())
try:
# Call the Calendar API
self.service = build('calendar', 'v3', credentials=self.creds)
self.cal_id = None
self.cal_list = self.build_calendar_list()
# print(self.cal_list)
except HttpError as error:
print('An error occurred: %s' % error)
# def get_events(self):
# now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
# events_result = self.service.events().list(calendarId=self.get_cal_id(), timeMin=now,
# maxResults=10, singleEvents=True,
# orderBy='startTime').execute()
# events = events_result.get('items', [])
# if not events:
# print('No upcoming events found.')
# return
# # Prints the start and name of the next 10 events
# for event in events:
# start = event['start'].get('dateTime', event['start'].get('date'))
# print(start, event['summary'])
def set_cal_id(self, cal_id):
self.cal_id = cal_id
print(self.cal_id)
# return self.cal_id
def get_cal_id(self):
return self.cal_id
def tray_icon(self):
image = Image.open("icon.ico")
return image
def good_bye(self, icon):
print("Later Tater!")
icon.visible = False
icon.stop()
def create_tray(self):
# count = self.cal_list.count()
menu_items = tuple(self.cal_list)
icon(
'TrayCalendar',
icon=self.tray_icon(),
# visible=True,
menu=menu(
item(
'Quit',
self.good_bye
),
item(
'Calendar List',
menu(
lambda: (item for item in menu_items)
),
),
)
).run()
def build_calendar_list(self):
cal_list = []
calendarlist = self.service.calendarList().list().execute()
for k in calendarlist.get('items', tuple()):
# print(k['id'])
calendar_id = k['id']
cal_list.append(
(item(k["summary"], lambda *args: self.set_cal_id(calendar_id)))
)
# pprint.pprint(k)
# pprint.pprint(cal_list)
# print(self.cal_id)
return cal_list
if __name__ == '__main__':
my_cal = MyCalendar()
my_cal.create_tray()