[ Question]right click menu in tree element
Type of Issue (Enhancement, Error, Bug, Question)
Question
Operating System
windows 10
PySimpleGUI Port (tkinter, Qt, Wx, Web)
tkinter
Versions
Version information can be obtained by calling sg.main_get_debug_data()
Or you can print each version shown in ()
Python version (sg.sys.version)
3.9.12
PySimpleGUI Version (sg.__version__)
4.60.1
GUI Version (tkinter (sg.tclversion_detailed), PySide2, WxPython, Remi)
8.6.12
Your Experience In Months or Years (optional)
Years Python programming experience
Years Programming experience overall
Have used another Python GUI Framework? (tkinter, Qt, etc) (yes/no is fine)
Anything else you think would be helpful?
Troubleshooting
These items may solve your problem. Please check those you've done by changing - [ ] to - [X]
- [X ] Searched main docs for your problem www.PySimpleGUI.org
- [ X] Looked for Demo Programs that are similar to your goal. It is recommend you use the Demo Browser! Demos.PySimpleGUI.org
- [X ] If not tkinter - looked for Demo Programs for specific port
- [X ] For non tkinter - Looked at readme for your specific port if not PySimpleGUI (Qt, WX, Remi)
- [ X] Run your program outside of your debugger (from a command line)
- [X ] Searched through Issues (open and closed) to see if already reported Issues.PySimpleGUI.org
- [ X] Have upgraded to the latest release of PySimpleGUI on PyPI (lastest official version)
- [X ] Tried using the PySimpleGUI.py file on GitHub. Your problem may have already been fixed but not released
Detailed Description
Hi I am now using the tree element in my gui.And now I need a function that when I right click one of the row ,it can show a rightclick menu and then return the value of the row so that I can reveise for that row.I look for it in the pysimplegui website but do not find it.Could you help me with it?
Code To Duplicate
A short program that isolates and demonstrates the problem (Do not paste your massive program, but instead 10-20 lines that clearly show the problem)
This pre-formatted code block is all set for you to paste in your bit of code:
# Paste your code here
Screenshot, Sketch, or Drawing
Watcha Makin?
If you care to share something about your project, it would be awesome to hear what you're building.
With option right_click_selects=True, right_click_menu=right_click_menu, you can get the value for which row and which column you clicked. Save the row and column when the event for right click happened firstly, then you can use them in the click event for menu.
[ Demo Code ]
import PySimpleGUI as sg
headings = ["Name", "Cases/All", "Case/Day", "Deaths/All", "Death/Day"]
data = [
["Global", "80773033", "563983", "1783619", "11784"],
["USA", "19147627", "174814", "332423", "1779"],
["India", "10244852", "20549", "148439", "286"],
["Brazil", "7504833", "20548", "191570", "431"],
["Russian", "3131550", "26513", "56426", "599"],
["France", "2530400", "11295", "63701", "969"],
["UK", "2382869", "53135", "71567", "458"],
["Italy", "2067487", "11210", "73029", "659"],
["Spain", "1893502", "7717", "50442", "36"],
["Germany", "1687185", "22459", "32107", "1129"],
["Colombia", "1603807", "9310", "42374", "203"],
["Argentina", "1590513", "6586", "42868", "218"],
["Mexico", "1389430", "5996", "122855", "429"],
["Turkey", "1364242", "15805", "20388", "253"],
["Poland", "1281414", "12780", "28019", "565"],
["Iran", "1212481", "6108", "54946", "132"],
["Ukraine", "1045348", "7986", "18324", "243"],
["South Africa", "1021451", "9580", "27568", "497"],
["Peru", "1008908", "1251", "37525", "51"],
["Netherlands", "778293", "7561", "11218", "171"],
]
sg.theme('DarkBlue')
sg.set_options(font='Courier 11')
right_click_menu = ['&Right', ['Edit', 'Cancel']]
layout = [
[sg.Table(data, headings=headings, pad=(0, 0), enable_click_events=True,
right_click_selects=True, right_click_menu=right_click_menu, key='-TABLE-')],
[sg.Text('', pad=(0, 0), relief=sg.RELIEF_SUNKEN, expand_x=True, key='-CELL-')],
]
window = sg.Window('Table', layout, margins=(0, 0), finalize=True)
table, cell = window['-TABLE-'], window['-CELL-']
while True:
event, values = window.read()
if event == sg.WINDOW_CLOSED:
break
# Left/right-click to select a row
elif isinstance(event, tuple) and event[:2]==('-TABLE-', sg.TABLE_CLICKED_INDICATOR):
row, col = event[2]
row_data = data[row]
cell_data = row_data[col]
cell.update(f'{row_data} - {cell_data}')
# Edit in right-click menu
elif event == 'Edit':
row_data = data[row]
cell_data = row_data[col]
cell.update(f'{row_data} - {cell_data}')
window.close()
It seems that tree element do not have the paramter 'right_click_selects=True'
Here is my code
layout=[sg.Button('cancel')], [sg.Tree(data=todoTree, headings=['Size', ], auto_size_columns=True, select_mode=sg.TABLE_SELECT_MODE_BROWSE, num_rows=20, col0_width=40, key='TREE', show_expanded=True, enable_events=True, expand_x=True, expand_y=True,right_click_selects=True,right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_EXIT)],
However pycharm told me that

what is more ,for the tree element,can I just double click a row (or other methods)and then I can edit that row. And can I select a certain row in tree element in program?(Other element has this method 'Select' but except tree element)
It looks much complex and something related your programming code, not like in the Table element.
For Tree element, there's still no some options for Table element at this moment. Double clicks will default expand /clapse the node, so there will be something problem, but still demo the way. Anyway, here the code to demo how I go it, you can find how to select item(s) of the Tree element in the button event.
[ Demo Code ]
from random import choice
import PySimpleGUI as sg
def get_location(element, event):
widget = element.widget
region = widget.identify('region', event.x, event.y)
if region in ('nothing', 'separator'):
row, col = None, None
elif region == 'heading':
row = -1
col = int(widget.identify_column(event.x)[1:])
elif region == 'tree':
row, col = widget.identify_row(event.y), 0
elif region == 'cell':
row = widget.identify_row(event.y)
col = int(widget.identify_column(event.x)[1:])
if row in element.IdToKey:
widget.selection_set(row)
row = element.IdToKey[row]
return (row, col)
sg.theme("DarkBlue")
sg.set_options(font=('Courier New', 12))
# Add tree data
treedata = sg.TreeData()
data = [[f'Node {i:0>2d}', f'Data 1 - {i:0>2d}', f'Data 2 - {i:0>2d}'] for i in range(5)]
for i, item in enumerate(data):
parent = choice(list(treedata.tree_dict.keys()))
treedata.insert(parent, i, item[0], values=item[1:])
right_click_menu = ['&Right', ['Edit', 'Cancel']]
layout = [
[sg.Button('Select 1~3')],
[sg.Tree(data=treedata, headings=['Data 1', 'Data 2'], auto_size_columns=False,
num_rows=10, col0_width=30, col_widths=[15, 15], justification='center',
show_expanded=True, col0_heading='Node',
right_click_menu=right_click_menu,
pad=(0, 0), key='TREE')],
[sg.Text('', pad=(0, 0), relief=sg.RELIEF_SUNKEN, expand_x=True, key='STATUS')],
]
window = sg.Window('Tree Element Test', layout, use_default_focus=False, margins=(0, 0), finalize=True)
window['Select 1~3'].block_focus()
tree, status = window['TREE'], window['STATUS']
tree.bind('<Button-1>', ' Select')
event = '<Button-2>' if sg.running_mac() else '<Button-3>'
tree.bind(event, ' Select')
tree.bind('<Double-Button-1>', ' Double')
# Remove the dash box in Table/Tree element
style_name = window['TREE'].widget['style']+'.Item'
style = sg.ttk.Style()
style.layout(style_name,
[('Treeitem.padding', {'sticky': 'nswe', 'children':
[('Treeitem.indicator', {'side': 'left', 'sticky': ''}),
('Treeitem.image', {'side': 'left', 'sticky': ''}),
# ('Treeitem.focus', {'side': 'left', 'sticky': '', 'children': [
('Treeitem.text', {'side': 'left', 'sticky': ''}),
# ]})
],
})]
)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == 'TREE Select':
# values not yet updated for the selection here
row, col = get_location(tree, tree.user_bind_event)
if None in (row, col):
status.update('Click on nothing or separator !')
row_data = col_data = None
elif row < 0:
status.update(f'Click on heading #{col}')
row_data = col_data = None
else:
row_data = data[row]
col_data = row_data[col]
status.update(f'{row_data} - {col_data}')
elif event in ('TREE Double', 'Edit'):
status.update(f'EDIT - {row_data} - {col_data}')
elif event in 'Select 1~3':
ids = tuple(map(lambda x:tree.KeyToID[x], [1, 2, 3]))
tree.widget.selection_set(ids)
status.update('Items with key 1 ~ 3 selected !')
window.close()
Perhaps this should be turned into an enhancement? Something like "provide same right_click_selects feature in Tree element that Table element has"?
I don't see any open issues for the tree element to have this feature added.
Thank you for your help.And there is a another problem.Can I edit the the tree element directly (instead of open a new window)?
No method provided to edit the tree element directly. Maybe you can refer issue #4972
Thank you.And there is another addition question.Could I click on the head and then order the tree element?What is more,can the program detect the element that user is clicking in a window that contains lots of elements
In my above demo code, you can find how to find which heading clicked, then sort your data to TreeData to update Tree element by yourselves.
Can the program detect the element that user is clicking in a window that contains lots of elements
What it mean for ?
like this.The above element is the tree element,and below is the input box.So can the program know whether I was input in the box ,or I was operating the tree element by the keyboard
It maybe presented by which element focused, you can call method find_element_with_focus of Window, like
element = window.find_element_with_focus()
print(element)