kxgames / glooey

An object-oriented GUI library for pyglet.
MIT License
91 stars 6 forks source link

how to implement a file-chooser dialog? #38

Open soaroc opened 4 years ago

soaroc commented 4 years ago

Is there any idea to implement a file-chooser dialog? In specific: 1) how do I know which pathes to list in current dialog? 2) how do I know which path/file is chosen in the dialog?

kalekundert commented 4 years ago

Currently there is no built-in file-chooser dialog. It'd definitely be a useful widget, though, so I'd be open to a PR if you're interested.

benmoran56 commented 4 years ago

Over on the Discord server we recently came up with a hack using tkinter. It runs in another process, so it won't cause any conflicts. Results are pyglet events. I don't mean to spam, but just in case it's useful I thought I would share:

from concurrent.futures import ProcessPoolExecutor as _ProcessPoolExecutor

from pyglet.event import EventDispatcher as _EventDispatcher

import os

class _Dialog(_EventDispatcher):
    executor = _ProcessPoolExecutor(max_workers=1)

    @staticmethod
    def _open_dialog():
        raise NotImplementedError

    def open(self):
        future = self.executor.submit(self._open_dialog, self._dialog)
        future.add_done_callback(self._dispatch_event)

    def _dispatch_event(self, future):
        raise NotImplementedError

class FileOpenDialog(_Dialog):
    def __init__(self, title="Open File", initial_dir=os.path.curdir, filetypes="", multiple=False):
        from tkinter import filedialog

        self._dialog = filedialog.Open(title=title,
            initialdir=initial_dir,
            filetypes=filetypes,
            multiple=multiple
        )

    @staticmethod
    def _open_dialog(dialog):
        import tkinter as tk
        root = tk.Tk()
        root.withdraw()
        return dialog.show()

    def _dispatch_event(self, future):
        self.dispatch_event('on_dialog_open', future.result())

    def on_dialog_open(self, filename):
        """Event for filename choice"""
        pass

class FileSaveDialog(_Dialog):
    def __init__(self, title="Save As", initial_dir=os.path.curdir, initial_file="", filetypes="", default_ext=""):
        from tkinter import filedialog
        self._dialog = filedialog.SaveAs(title=title,
            initialdir=initial_dir,
            initialfile=initial_file,
            filetypes=filetypes,
            defaultextension=default_ext,
        )

    @staticmethod
    def _open_dialog(dialog):
        import tkinter as tk
        from tkinter import filedialog
        root = tk.Tk()
        root.withdraw()
        return dialog.show()

    def _dispatch_event(self, future):
        self.dispatch_event('on_dialog_save', future.result())

    def on_dialog_save(self, filename):
        """Event for filename choice"""
        pass

FileOpenDialog.register_event_type('on_dialog_open')
FileSaveDialog.register_event_type('on_dialog_save')

if __name__ == '__main__':
    #save_as = FileSaveDialog(initial_file="test", filetypes=[("PNG", ".png"),("24-bit Bitmap", ".bmp")])
    #save_as.open()

    #@save_as.event
    #def on_dialog_save(filename):
    #    print("FILENAMES ON SAVE!", filename)

    open = FileOpenDialog(filetypes=[("PNG", ".png"),("24-bit Bitmap", ".bmp")], multiple=True)
    open.open()

    @open.event
    def on_dialog_open(filename):
        print("FILENAMES ON OPEN!", filename)