enter def start(update: Update, context: CallbackContext) -> None:
"""Sends a message with three inline buttons attached."""
keyboard = [
[
InlineKeyboardButton("Option 1", callback_data='1'),
InlineKeyboardButton("Option 2", callback_data='2'),
],
[InlineKeyboardButton("Option 3", callback_data='3')],
]
reply_markup = InlineKeyboardMarkup(keyboard)
update.message.reply_text('Please choose:', reply_markup=reply_markup) here
I know that 'Option 1' is the name that the button displays and callback_data is the data that is called back in, but · I don't know where this InlineKeyboardButton will respond to the pressed event,Or in which function will this callback_data be passed to be executed?
You need to use handler to get callback data
updater = Updater(token, use_context=True)
dp = updater.dispatcher
dp.add_handler(CallbackQueryHandler(c_back_respons))
then you can use function like this
def c_back_respons(update: Update, context: CallbackContext):
call_back_data = update.callback_query.data
if call_back_data in ("1"):
function(update)
Related
I am trying to set the description of a Google Calendar event to have a different selected presenter that is chosen in a rotatory manner (it is a slide deck that needs to be presented by a different person each week). The Python script specifying the rationale would work as the following
import datetime
people = ['Person 1', 'Person 2', 'Person 3']
year, week, day = datetime.date.today().isocalendar()
print(people[week_of_year % len(people)])
the resulting person from this calculation would show up in the calendar event description. Is there any tool to do that?
I was not able to find a way to create a recurrent event with different descriptions for each event.
However, I found a workaround for you using Events: patch. You first create an event using Events: insert, get the ID of the event you created with Events: list, and after that, then get the ID of the recurrences using Events: instances. Lastly, you use Events: patch to add the new description.
It might sound long, but I'm adding a sample with explanations on how to use it.
# impor the libraries that you will use for the calendar API
from __future__ import print_function
import os.path
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
# The scopes that we need to use based on the Google documentation
# I added the information in the reference at the end of the answer
SCOPES = ['https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/calendar.events']
# creation of the credential, I use as a base the Google Documentation "Python quickstart"
def main():
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
service = build('calendar', 'v3', credentials=creds)
# The list of people that will be use in each event
peoples = ['Person 1', 'Person 2', 'Person 3', 'Person 4']
number_week = 0
event = {
# Event title
'summary': 'Testing create description',
# A test description will be replaced later, so you can add anything you want to it.
'description': 'test',
# The start and end dates need to be in ISO-8601 date format
# and the time zone needs to be formatted as an IANA Time Zone Database name, e.g. "Europe/Zurich
'start': {
'dateTime': '2022-10-28T09:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'end': {
'dateTime': '2022-10-28T17:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'recurrence': [
# You can change the recurrence of the event
# for this example is a weekly event, and it has 4 recurrences
'RRULE:FREQ=WEEKLY;COUNT=4'
],
# The list of attendees
'attendees': [
{'email': 'test#email.xyz'},
{'email': 'test2#email.xyz'},
],
'reminders': {
'useDefault': False,
'overrides': [
{'method': 'email', 'minutes': 24 * 60},
{'method': 'popup', 'minutes': 10},
],
},
}
# We use insert to create the event
event = service.events().insert(calendarId='primary', body=event).execute()
# You can use the print in the next line to see the information about the event while you are testing
# print('Event created: %s' % (event.get('htmlLink')))
page_token = None
# Search for the event, using the method list and the event title q='Testing create description'
# you can use any other search key to get the event ID
events = service.events().list(calendarId='primary', pageToken=page_token, q='Testing create description').execute()
# get the ID of the event
for event in events['items']:
# print(event['id'])
id_event = event['id']
# Will search the ID of the recurrences of the event using the method instances
# e.g. xxxxxxxxxxxxxxxxx_20221028T160000Z
while True:
recurrences_for_events = service.events().instances(calendarId='primary', eventId=id_event,
pageToken=page_token).execute()
# run the dictionary of each iteration
for recurrence_instance in recurrences_for_events['items']:
id_to_update = recurrence_instance['id']
# I used the next print just to review the IDs of each event
# print(id_to_update)
# Create the new body of the event with the name of the people in the list of peoples
# instead of using year, week, day = datetime.date.today().isocalendar(). I use a simple counter to iterate on the list
body = {
'description': peoples[number_week],
}
# update the event description with patch
updated_event = service.events().patch(calendarId='primary', eventId=id_to_update, body=body).execute()
# print(updated_event['description'])
# next patch in case you have a large recurrence of the event
page_token = events.get('nextPageToken')
number_week += 1
# This will reset the counter, in case the number of people is less than the recurrences of the event
if number_week >= len(peoples):
number_week = 0
if not page_token:
break
except HttpError as error:
print('An error occurred: %s' % error)
if __name__ == '__main__':
main()
If the recurrent event has already been created, you only need to use the imports until the number_week = 0, and the part from:
events = service.events().list(calendarId='primary', pageToken=page_token, q='Testing create description').execute()
To the end, you might need to modify the for loop to only run once per recurrence.
Reference:
Python quickstart
Events: insert
Events: list
Events: instances
Events: patch
ISO 8601
This question already has answers here:
how to change the frames in tkinter using time and without button command
(1 answer)
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 5 years ago.
From the answer given by Bryan Oakley to the question “Switch between two frames in tkinter”, I trie to change how the button works in page two.
On page one, with command=lambda: controller.show_frame(“StartPage”), it works as it should.
On page two, I want to add something and then go back but it does not work.
Why does my callback not get called?
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=self.go_to())
button.pack()
def go_to(self):
# Add something to do
self.controller.show_frame("StartPage")
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
The problem is that the command keyword argument of Button takes a function.
You create your button with tk.Button(self, ..., command=self.go_to()), so the command is self.go_to(), which evaluates to None.
Why is that so?
go_to is defined as follows:
def go_to(self):
# Add something to do
self.controller.show_frame("StartPage")
So when Python comes across command=self.go_to(), it calls go_to, and passes the returned value to the command option.
This value is None (implied by the absence of a return statement), so your command is None, and your button has no effect.
You need to remove the parentheses, so has to have tk.Button(self, ..., command=self.go_to).
I am working on a fantasy football type app for a school project.
We have created a scrollview with a list of characters in a team within it, each assigned to a button. on press of the button a new scrollview displaying a second list of 'inactive character buttons' is displayed, allowing the user to press one to swap the first and second character from team to team.
our issue comes from a difficulty in managing to 'locate' which button is pressed in order to tell our swap function which two characters to swap on the list. Is it possible to retain the id of a button and call it into a new function on press of said button?
Our code is a bit messy, but is displayed bellow:
class SMApp(App):
teamlist = []
idvar = ""
btnlist = []
def popupfunc(self, event):
"""
creates a popup asking if the user wishes to swap a character from team to subs
then proceeds to allow user to choose who swaps
"""
def subscroll(self):
"""
opens scroll list of substitute characters in a popup
"""
sublist = []
curs.execute('SELECT * FROM Subs')
for row in curs:
sublist.append([row[0], row[2]])
layout = GridLayout(cols=2, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
for i in range(len(sublist)):
btn = Button(text=str(sublist[i][0]), size_hint_y=None, height=40)
layout.add_widget(btn)
lbl = Label(text=str(sublist[i][1]), size_hinty=None, height=40)
layout.add_widget(lbl)
root = ScrollView(size_hint=(None, None), size=(400, 400))
root.add_widget(layout)
popup2 = Popup(content=root, size=(7, 10), size_hint=(0.55, 0.8), title="list of subs")
popup2.open()
box = BoxLayout()
btn1 = Button(text='yeah ok')
btn2 = Button(text='nope')
popup1 = Popup(content=box, size=(10, 10), size_hint=(0.3, 0.3), title="add to team?")
btn2.bind(on_press=popup1.dismiss)
btn1.bind(on_press=subscroll)
box.add_widget(btn1)
box.add_widget(btn2)
popup1.open()
def build(self):
curs.execute('SELECT * FROM Team')
for row in curs:
self.teamlist.append([row[0], row[2]])
layout = GridLayout(cols=2, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
for i in range(len(self.teamlist)):
btn = Button(text=str(self.teamlist[i][0]), size_hint_y=None, height=40, id=str(i))
btn.bind(on_press=self.popupfunc)
self.btnlist.append(btn)
layout.add_widget(btn)
lbl = Label(text=str(self.teamlist[i][1]), size_hinty=None, height=40)
layout.add_widget(lbl)
for item in self.btnlist:
print item.id
root = ScrollView(size_hint=(None, None), size=(400, 400),
pos_hint={'center_x':.5, 'center_y':.5})
root.add_widget(layout)
return root
if __name__ == '__main__':
SMApp().run()
Each of the btn = Button(...) you create is a different object, therefore you can tell which is pressed. The thing is what way you'll choose.
You can use:
str(your button) and get a specific object address(?) like 0xAABBCCEE
bad, don't do that
Button(id='something', ...)
ids from kv language
or create own widget with a property for specific identificator. Then you'd use a loop for the parent's children which would check for identificator and do something:
for child in layout.children:
if child.id == 'something':
# do something
And it seems you'd need this loop inside your subscroll, or access that layout some other way.
I am trying to understand how data binding works in Go walk.
I have reviewed the somewhat complex data binding example, but I am having difficulties implementing a simple, one field data binding.
The code below demonstrates more or less what I am trying to achieve - I want the text label to be bound to the message variable (i.e., to be synchronized with its content) - of course, without the need for me to push changes to the label itself.
package main
import (
"github.com/lxn/walk"
. "github.com/lxn/walk/declarative"
"strconv"
"time"
)
func main() {
var messageLabel *walk.Label
var message string = "Hello"
// Change `message` over 5 seconds
go func() {
for i := 1; i < 6; i++ {
time.Sleep(time.Second)
message = "Counting: " + strconv.Itoa(i)
// I want to make it work
// without this line below
messageLabel.SetText(message)
}
}()
// Build a simple window with a text label
// that is supposed to be bound to the
// contents of the `message` variable
MainWindow{
Title: "Binding Test",
MinSize: Size{300, 50},
Layout: VBox{},
Children: []Widget{
Label{
AssignTo: &messageLabel,
Text: message,
// Text: BindTo{message} // Objective
},
},
}.Run()
}
I didn't see any Databinder code in your snapshot.
In that exanple you mentioned,these code below makes databinding work
DataBinder: DataBinder{
AssignTo: &db,
Name: "animal",
DataSource: animal,
ErrorPresenter: ToolTipErrorPresenter{},
},
It binds the data who calls Bind("Name") to the field with the same name in Datasource which is animal in that example.
I have placed a search button on a datawindow, and i have already an event for searching such list...how is it possible to call an event once the button is clicked on runtime.
below is the code on my event named "ue_key"
string xcode, iseries, ycode, sql_statement, xname, i_cname, name, iseries_no, irequested_by, irequest_problem, irequesting_dept, idate_request, idate_needed
string iasset_no, idate_received, istatus
long i_row
//integer
i_cname = dw_work_order.getcolumnname()
i_row = this.getrow()
if i_row > 0 then
if key = keyF2! and i_cname = 'series_no' then
//open(w_csearch)
// Then, define select statement
sql_statement = "SELECT series_no as 'Series NO', requested_by as 'Requested By' FROM work_order_form where status = 'A' or status = 'ACTIVE';"
str_sellist args
args.trans = sqlca
args.sel_cmd = sql_statement
// Specify which column will be the return value
args.retcol = 1
// Define drop-down items. NOTE: This should correspond
// with the alias you use for the columns you retrieve
args.dropdown_items[1] = "Series NO"
args.dropdown_items[2] = "Requested By"
// Define Search Window Title
args.title = "Work Order"
// Define transaction object for the window
// This is REQUIRE for now... :)
// Open with parameter
OpenWithParm(w_sellist, args)
ycode=message.stringparm
xcode = ycode
// MessageBox('test', xcode)
if trim(xcode) <> '' then
select series_no, requested_by, request_problem, requesting_dept, date_request,date_needed, asset_no, status
into :iseries, :irequested_by, :irequest_problem, :irequesting_dept, :idate_request, :idate_needed, :iasset_no, :istatus
From work_order_form where series_no = :xcode using sqlca;
// Messagebox('test', iseries)
this.setitem(THIS.GETROW(),'series_no', iseries)
this.setitem(THIS.GETROW(),'requested_by', irequested_by)
this.setitem(THIS.GETROW(),'request_problem', irequest_problem)
this.setitem(THIS.GETROW(),'requesting_dept', irequesting_dept)
this.setitem(THIS.GETROW(),'date_request', idate_request)
this.setitem(THIS.GETROW(),'date_needed', idate_needed)
this.setitem(THIS.GETROW(),'asset_no', iasset_no)
this.setitem(THIS.GETROW(),'status', istatus)
//dw_work_order.retrieve(iseries)
end if
end if
end if
Thanks a lot!
The datawindow control has "ButtonClicking" and "ButtonClicked" events. You can use these event to identify which button was clicked (check the event arguments, specifically dwo.Name) and call the appropriate code.
You'll want to make sure that your datawindow button's action is set for "User Defined (0)".