首页 > 解决方案 > 扩展布局添加的输入框的 PySimpleGui Rick Click Menu 剪贴板

问题描述

TL; DR:我基本上是想弄清楚如何从 PySimpleGui Github 合并这两个示例代码:https ://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Layout_Extend.py和 https:// github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_Multiline_Right_Click_Menu_Clipboard.py其中已动态创建传递给剪贴板函数的元素键...

使用 PySimpleGui 的文档以及关于 stackoverflow 和 Github 演示的大量信息,我制作了一个“简单”的 gui,可以添加和删除输入字段,并且我已经为这方面的所有内容进行了排序(即使用添加元素到 GUI layout_extend,使用 .hide_row() 删除元素并保留已删除值的列表等...

就像 layout_extend 演示一样,我正在使用 Frame,并使用迭代器向其中添加 GUI 元素以确保创建唯一的“键”。

##CODE SNIPPET AS MOST OF IT IS PRETTY MUCH THE SAME AS THE EXAMPLE DEMO CODE WITH MINOR CHANGES

right_click_menu = ['', ['Copy', 'Paste', 'Select All', 'Cut']]

def do_clipboard_operation(event, window, element):
    #Same as Demo Code Here No Point Copying!

...
...

if event in right_click_menu[1]:
    do_clipboard_operation(event, program_window, element)
if event == '-ADDPATH-':
    program_window.extend_layout(program_window['-FRAME1-'], [[sg.Text('PATH:'),sg.Input(key=f'-PATH{i}-', rick_click_menu=right_click_menu), sg.FolderBrowse(initial_folder="/base/path", key=f'-BROWSEPATH{i}-'), sg.Button('Remove Path', key=f'-REMOVEPATH{i}-')]])
    i += 1
...
...

当用户看到一个输入字段时,他们希望在其中放入一长串文本(在我的情况下为文件夹路径),因此需要“右键单击上下文菜单”,因此我想考虑添加它。

我的问题是 Multi-line Rick Click Menu Clipboard 演示需要将触发元素键传递给函数(然后用于向其中添加/删除文本),但是因为我为我需要的元素“动态生成”了键名在能够通过之前找出哪个元素键激活了右键菜单,我只是不知道该怎么做.....

我写的代码和 Layout_extend 演示基本相同.....

我很欣赏 PySimpleGui,尽管它很棒,但它可能并不是处理动态 GUI 的最佳工具,但由于我一直在为 OO 编程而苦苦挣扎,这几乎是我能够构建功能性 Python GUI 的唯一方法日期....

如果在现阶段无法做到这一点,那没关系,但至少我问过(当我不可避免地有人在使用它时说“我不能右键单击它真的很烦人”时,这让我感觉更好)!

一如既往地提前感谢!

欧文。

编辑:: 添加代码(必须删除对特定细节的一些引用 - 根路径和其他此类信息,将 '<' '>' 放置在数据存在位置的占位符周围 - 但代码是相同的:


#!/bin/python3

import PySimpleGUI as sg
import os.path
from getpass import getuser
from string import ascii_letters, digits
from random import choice as rchoice

SPLASH_IMAGE_PATH=r'<AN IMAGE FILE LOCATION>'
OUT_PATH='./'
DISPLAY_SPLASH_MS = 1500
REMOVE_LIST=[]
VERSION_NUM='0.3.0'

splash_theme = {'BACKGROUND': '#ffcc00',
                'TEXT': '#000000',
                'INPUT': '#ffffff',
                'TEXT_INPUT': '#ffffff',
                'SCROLL': '#ffffff',
                'BUTTON': ('white', '#000000'),
                'PROGRESS': ('#ffffff', '#ffffff'),
                'BORDER': 0,
                'SLIDER_DEPTH': 0,
                'PROGRESS_DEPTH': 0
}

right_click_menu = ['', ['Copy','Paste','Select All','Cut']]

def do_clipboard_operation(event, window, element):
    print(event)
    print(window)
    print(element)

##Random string generator: https://www.stackoverflow.com/questions/2257441/random-sting-generation-with-upper-case-letters-and-digits (Ignacio Vazquez-Abrams answer)
def random_string_gen(size=8, chars=ascii_letters + digits):
    return ''.join(rchoice(chars) for _ in range(size))

def main():
    sg.theme_add_new('SplashScreen', splash_theme)
    sg.theme('SplashScreen')
    splash_window= sg.Window('Uploader', [[sg.Image(SPLASH_IMAGE_PATH)], [sg.Text('Uploader', font=("any",20))], [sg.Text(f'Version: {VERSION_NUM}', font=('any',12))]], element_justification='c', no_titlebar=True, keep_on_top=True).read(timeout=DISPLAY_SPLASH_MS, close=True)

    sg.theme('DarkAmber')
    layout = [ [sg.Text('Please Enter FULL Paths. Use The Browse Button To Navigate, Or Copy Path Into Field.')],
             [sg.Text('Use The "Add Path" Button To Add More Rows, And The "Remove Path" Button To Remove A Row.')],
             [sg.Text('When Finished, Press The "Upload" Button - This Will Take Time To Process.')],
             [sg.Frame('Paths:', [[sg.Text('PATH:'), sg.Input(key='-PATH0-', right_click_menu=right_click_menu), sg.FolderBrowse(initial_folder="<ROOT PATH>",  key='-BROWSEPATH0-' ), sg.Button('Remove Path', key='-REMOVEPATH0-')]], key='-FRAME1-')],
             [sg.OK('Upload',key='-RUN-'), sg.Button('Add Additional Path', key='-ADDPATH-'), sg.Cancel('Exit', key='-EXIT-')]
    ]

    program_window = sg.Window('Uploader', layout)
    i = 1
    num_rows=1
    user=str(getuser())
    while True:
        event, values = program_window.read()
        if event == sg.WIN_CLOSED or event == '-EXIT-':
            break
        if event in right_click_menu[1]:
            print(values)
           # do_clipboard_operation(event, program_window, element)
        if event == '-ADDPATH-':
            ##Add new row to output window. uses f' ' string formatting to use the i iterator to create unique keys
            program_window.extend_layout(program_window['-FRAME1-'], [[sg.Text('PATH:'), sg.Input(key=f'-PATH{i}-', right_click_menu=right_click_menu), sg.FolderBrowse(initial_folder="<ROOT PATH>", key=f'-BROWSEPATH{i}-' ), sg.Button('Remove Path', key=f'-REMOVEPATH{i}-')]])
            i += 1
            num_rows += 1
        if event == '-RUN-':
            ##Iterate over values and remove duplicates (both the text field and the browse button can be populated with the same data so duplicates cannot be avoided
            ##Remove blank values (can occur when path is pasted into text field and browse button not used, and remove any paths that occur in the remove_list. generated when lines are removed
            ##Remove items that appear in REMOVE_LIST (created when removing lines)
            ##Output to a new out_list as items in value cannot be changed
            ##Validate User input to: ensure no <AVOID PATH> paths, no invalid paths, at least one path is submitted, and path submitted actually contains an <SPECIFIC FILES>... Show popup errors if any found and allow user to remove / alter offending paths.
            ##If all is OK generate a random string with the username appended and write all valid paths into a temp file with that random name. This is for back-end program to run.
            out_list = []
            error_list = []
            avoid_path_error=False
            invalid_path=False
            for key, value in values.items():
                if value not in out_list and not value == '' and not value in REMOVE_LIST:
                    if '<AVOID PATH>' in value:
                        avoid_path_error=True
                        sg.popup('One Or More Of Your Paths Is Located In The <AVOID PATH> And Cannot Be Used As An Input!\n\nPlease Remove The Offending Path.', title='<AVOID PATH> FOUND', keep_on_top=True, custom_text=('Sorry'), button_color=('white', 'red'))
                        break
                    elif not os.path.isdir(value):
                        invalid_path=True
                        sg.popup(f'The Following Invalid Path Has Been Entered And Does Not Seem To Exist / Is Unreadable:\n\n{value}', title='INVALID PATH ENTERED', keep_on_top=True, custom_text=('Oops!'), button_color=('white', 'red'))
                        break
                else:
                    out_list.append(value)
                    if not avoid_path_error ==  True and not invalid_path == True:
                        if not out_list:
                            sg.popup('You Have Not Added Any Paths!!! Please Try Again', title='NO PATH ENTERED', keep_on_top=True, custom_text=('Oops!'), button_color=('white', 'red'))
                    else:
                        for path in out_list:
                            for files in os.listdir(path):
                                if '<SPECIFIC FILE>' in files.lower():
                                    break
                                else:
                                    error_list.append(path)
                        if error_list:
                            error_list_string = '\n'.join(error_list)
                            sg.popup(f'The Following Path(s) Do NOT Contain <SPECIFIC FILE>...\nPlease ONLY Add Full Paths:\n\n{error_list_string}', title='NO <SPECIFIC PATH> FOUND', keep_on_top=True, custom_text=('Sorry!'), button_color=('white', 'red'))
                        else:
                            print(random_string_gen() + '.' + user)
                            break
            if '-REMOVEPATH' in event:
                ##Remove Line from window. values Dict cannot be altered, so need to generate a new list with the values of the data held in the value dict: -PATHx- and -BROWSEPATHx-
                ##Where x is the unique iterator number used to ensure unique keys. The Event also uses the same unique iterator key: -REMOVEPATHx- so replacing -REMOVEPATH with -PATH and -BROWSEPATH
                ##generates the keys we need. call the hide_row() function to remove row from window, and append both -PATHx- and -BROWSEPATHx-.
                folder_path=str(event).replace("-REMOVEPATH", "-PATH")
                browse_path=str(event).replace("-REMOVEPATH", "-BROWSEPATH")
                num_rows -= 1
                if num_rows == 0:
                    program_window[event].hide_row()
                    program_window.extend_layout(program_window['-FRAME1-'], [[sg.Text('PATH:'), sg.Input(key=f'-PATH{i}-', right_click_menu=right_click_menu), sg.FolderBrowse(initial_folder="<ROOT PATH>", key=f'-BROWSEPATH{i}-' ), sg.Button('Remove Path', key=f'-REMOVEPATH{i}-')]])
                    i += 1
                    num_rows = 1
                else:
                    program_window[event].hide_row()
                    REMOVE_LIST.append(values[folder_path])
                    REMOVE_LIST.append(values[browse_path])
    program_window.close()


if __name__ == "__main__":
    main()

标签: pythonpysimplegui

解决方案


推荐阅读