isl-org / Open3D

Open3D: A Modern Library for 3D Data Processing
http://www.open3d.org
Other
11.21k stars 2.28k forks source link

Open3D gui crashing after open tkinter filedialog #4427

Closed ezrogoodman closed 2 years ago

ezrogoodman commented 2 years ago

Describe the bug Open3D application based on example vis-gui.py crashes after usage of a tkinter askopenfilename file dialog.

To Reproduce Steps to reproduce the behavior:

  1. run attached script and select File - Open
  2. the app crashes without any error message no matter if a file was selected or the dialog was canceled

Environment (please complete the following information):

Additional context The reason for me to use a different file dialog than open3d.visualization.gui.FileDialog is the unability to select files from different that initial path's hard drive. I also tried easygui - it caused the same crashes. This might be the same issue as https://github.com/isl-org/Open3D/issues/1715 vis-gui-tk.zip

dd-ff commented 2 years ago

I had similar issues a while back and in order to fix it I had to run tkinter stuff in a separate thread, something like this:

import threading as thr
import tkinter as tk
from tkinter import filedialog
def AskFolder():
    a = tk.Tk()
    global save_path
    save_path = filedialog.askdirectory()
    a.destroy()

t = thr.Thread(target=AskFolder)
t.start()
t.join()
del t
global save_path #contains the requested path

Hope this helps.

ezrogoodman commented 2 years ago

Thanks for this tip. However, this solution works only once in an application run. On the second and every other call of the file dialog there is an error saying:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "C:\ProgramData\Anaconda3\lib\threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "D:\Zivid storage\open3d\examples\python\gui\vis-gui-tk.py", line 651, in _open_file
    filePath = askopenfilename(title = "Select 3D data file",filetypes = (("Zivid or Polygon files", ".zdf .ply"),("Zivid files", ".zdf"),("Polygon files", ".ply"))) # Full pile will be returned as string
  File "C:\ProgramData\Anaconda3\lib\tkinter\filedialog.py", line 376, in askopenfilename
    return Open(**options).show()
  File "C:\ProgramData\Anaconda3\lib\tkinter\commondialog.py", line 40, in show
    w = Frame(self.master)
  File "C:\ProgramData\Anaconda3\lib\tkinter\__init__.py", line 3124, in __init__
    Widget.__init__(self, master, 'frame', cnf, {}, extra)
  File "C:\ProgramData\Anaconda3\lib\tkinter\__init__.py", line 2572, in __init__
    self.tk.call(
RuntimeError: main thread is not in main loop

I suppose there is some collision in accessing threads from tkinter and open3d window..

dd-ff commented 2 years ago

I currently don't get this error if I use the example code on Win10. The code:

t = thr.Thread(target=AskFolder)
t.start()
t.join()
del t
global save_path #contains the requested path

Is run in a new action (and callback function) added to the O3DVisualizer, while AskFolderis just a global method...

ezrogoodman commented 2 years ago

There's a difference: I'm not working with O3DVisualizer, my testing script is based on the vis-gui.py example code in which I added two methods to the AppWindow class: _on_menu_open_new() is called after File - Open selection, it starts new thread as you suggested containing _open_file() method which is basically the same as your AskFolder. You can try my code here: vis-gui-tk.zip Thanks for your cooperation :)

dd-ff commented 2 years ago

Upon seeing your code, you need to destroy Tk window each time you are done with it. This fixes your problem:

def _open_file(self):
        w = Tk()
        w.withdraw() # Added so Tk window doesn't appear on opening the dialog
        global filePath
        filePath = askopenfilename(title = "Select 3D data file",filetypes = (("Zivid or Polygon files", ".zdf .ply"),("Zivid files", ".zdf"),("Polygon files", ".ply"))) # Full pile will be returned as string
        # filePath = easygui.fileopenbox(title = "Select 3D data file",filetypes = [["*.zdf", "*.ply"],"*.zdf","*.ply"])
        if filePath:
            print(filePath)
        else:
            print("File dialog canceled")
        w.destroy()
ezrogoodman commented 2 years ago

That's it. Thank you very much!

ssheorey commented 2 years ago

Thanks @dd-ff for the help! Closing since this has been resolved. @ezrogoodman please reopen if you'd like any change in Open3D.