0

I have programmed a menu and currently when a menu item is clicked it does a print(sometext from menu).

I need this menu click option to open a python file instead of printing the name of the file.

This seems like a very simple issue but I am new to python and am still learning.

I cannot find an exact fit to this circumstance. I have tried popen and execfile with no luck.; though I am not sure if I used them correctly.

import tkinter

def set_menu(window, choices):
    menubar = tkinter.Menu(root)
    window.config(menu=menubar)

    def _set_choices(menu, choices):
        for label, command in choices.items():
            if isinstance(command, dict):
                # Submenu
                submenu = tkinter.Menu(menu)
                menu.add_cascade(label=label, menu=submenu)
                _set_choices(submenu, command)
            elif label == '-' and command == '-':
                # Separator
                menu.add_separator()
            else:
                # Simple choice
                menu.add_command(label=label, command=command)

    _set_choices(menubar, choices)


if __name__ == '__main__':
    import sys

    root = tkinter.Tk()

    from collections import OrderedDict

    set_menu(root, {
        'Table of Contents': OrderedDict([
            ('Ecclesiastes', lambda: print('Ecclesiastes.py')),
            ('Ecclesiasticus', lambda: print('ecclesiaticus.exe')),
            ('-', '-'),
            ('Quit', lambda: sys.exit(0))
        ])
    })
    root.mainloop()

I expected it to open by doing a few different methods of executing the 'ecclesiastes.py' and the 'ecclesiasticus.exe' but unfortunately the error messages really only tell me I have no idea what i am stuck on rather than a clue as to how to get the proper code needed to execute these two files. I put popen before the .py file and execfile before the .exe file but I think that is not near the correct way to do this.

I placed print before each of the two file names so that the correct command can be pointed out by someone else here because I do not think execfile or popen are correct for this code.

martineau
  • 119,623
  • 25
  • 170
  • 301
Steed
  • 61
  • 9
  • 3
    Read [tkinterbook/menu](http://effbot.org/tkinterbook/menu.htm) and [calling-an-external-command-in-python](https://stackoverflow.com/questions/89228/calling-an-external-command-in-python) – stovfl Aug 22 '19 at 17:01

2 Answers2

2

Since it appears the you actually want to execute the file, you could do it something like this:

import os
import shlex
import subprocess
import sys
import tkinter


def set_menu(window, choices):
    menubar = tkinter.Menu(root)
    window.config(menu=menubar)

    def _set_choices(menu, choices):
        for label, command in choices.items():
            if isinstance(command, dict):
                # Submenu
                submenu = tkinter.Menu(menu)
                menu.add_cascade(label=label, menu=submenu)
                _set_choices(submenu, command)
            elif label == '-' and command == '-':
                # Separator
                menu.add_separator()
            else:
                # Simple choice
                menu.add_command(label=label, command=command)

    _set_choices(menubar, choices)

def exec_command(command):
    cmd = shlex.split(command)
    print('subprocess({})'.format(cmd))
    subprocess.run(cmd, shell=True)


if __name__ == '__main__':
    from collections import OrderedDict
    import sys

    root = tkinter.Tk()

    set_menu(root, {'Table of Contents':
                        OrderedDict([
                            ('Ecclesiastes',
                                lambda: exec_command('Ecclesiastes.py')),
                            ('Ecclesiasticus',
                                lambda: exec_command('ecclesiaticus.exe -arg 42')),
                            ('-', '-'),
                            ('Quit', 
                                lambda: sys.exit(0))
                        ])
                   })
    root.mainloop()
martineau
  • 119,623
  • 25
  • 170
  • 301
1

The comment of stovfl is a great solution.

I often use:

os.startfile('filename')

I can't tell you if this the best option out there but it works :)

Your code would look like this:

import tkinter 
import os

def set_menu(window, choices):
    menubar = tkinter.Menu(root)
    window.config(menu=menubar)

    def _set_choices(menu, choices):
        for label, command in choices.items():
            if isinstance(command, dict):
                # Submenu
                submenu = tkinter.Menu(menu)
                menu.add_cascade(label=label, menu=submenu)
                _set_choices(submenu, command)
            elif label == '-' and command == '-':
                # Separator
                menu.add_separator()
            else:
                # Simple choice
                menu.add_command(label=label, command=command)

    _set_choices(menubar, choices)


if __name__ == '__main__':
    import sys

    root = tkinter.Tk()

    from collections import OrderedDict

    set_menu(root, {
        'Table of Contents': OrderedDict([
            ('Ecclesiastes', lambda: os.startfile('Ecclesiastes.py')),
            ('Ecclesiasticus', lambda: os.startfile('ecclesiaticus.exe')),
            ('-', '-'),
            ('Quit', lambda: sys.exit(0))
        ])
    })
    root.mainloop()

I hope this solves your question!

Anton van der Wel
  • 451
  • 1
  • 6
  • 20