I'm building an application with wxPython and I need to ask the user for a file. here are my functions:
def choose_path(self, event):
"""Choose the path"""
self.btnPath.Disable()
path, exists = open_file()
self.btnPath.Enable()
if path is not None:
if exists:
self.txtPath.SetLabel(path)
self.btnOpen.Enable(bool(self.txtPath.GetValue()))
def open_file(default_path="data\\pcap"):
"""Method for opening files,returns the file_path of the choosen file and exists"""
file_path = None
dialog = wx.FileDialog(None, "File Browser", default_path,
style=wx.FD_OPEN | wx.FD_MULTIPLE | wx.STAY_ON_TOP, wildcard=OPEN_WILDCARD)
if dialog.ShowModal() == wx.ID_OK:
file_path = dialog.GetPath()
dialog.Destroy()
return file_path, os.path.exists(file_path)
The problem is that sometimes it takes time to load the FileDialog and the application crashes. what can I do about it?
Related
How to open a window on top of other windows when calling a function?
import wx
def openFile(wildcard="*"):
app = wx.App(None)
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
dialog = wx.FileDialog(None, 'Open', wildcard=wildcard, style=style)
if dialog.ShowModal() == wx.ID_OK:
path = dialog.GetPath()
else:
dialog.Destroy()
path = 'No file'
return f'<div class="notification error">{path}</div>'
dialog.Destroy()
return f'<div id="pathToFile" class="notification">{path}</div>'
The Accepted answer from #VZ is spot on for all normal usage but strictly speaking, your code can be tweaked to work, even if it serves no real purpose but you'll notice, despite passing wx.STAY_ON_TOP, it will not honour it.
Like so:
import wx
def openFile(wildcard="*"):
app = wx.App(None)
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.STAY_ON_TOP
dialog = wx.FileDialog(None, 'Open', wildcard=wildcard, style=style)
if dialog.ShowModal() == wx.ID_OK:
path = dialog.GetPath()
else:
path = 'No file'
dialog.Destroy()
return f'<div class="notification error">{path}</div>'
print(openFile())
To show a dialog on top of some other top level window you need to specify that window as the dialog parent (instead of using None as you do).
There is no support for showing a native dialog, such as the "Open file" one, on top of all windows, this can only be done for custom windows using wx.STAY_ON_TOP flag.
I'm writing a UI for a python app with wxPython. I've handled a few of the OnX functions but I need help with OnNew and OnSave/SaveAs
Here is my Save and SaveAs code:
def OnSave(self, event):
self.dirname = ""
saveFileDialog = wx.FileDialog(self, "Save Operation File", self.dirname, "",
"Operation Files (*.fwr)|*.fwr|All Files (*.*)|*.*", wx.SAVE|wx.OVERWRITE_PROMPT)
if saveFileDialog.ShowModal() == wx.ID_OK:
contents = self.control.GetValue()
self.filename = saveFileDialog.GetFilename()
self.dirname = saveFileDialog.GetDirectory()
filehandle = open(os.path.join(self.dirname, self.filename), 'w')
filehandle.write(contents)
filehandle.close()
else:
sys.exit(1)
saveFileDialog.Destroy()
def OnSaveAs(self, event):
self.dirname = "";
saveAsFileDialog = wx.FileDialog(self, "Save Operation File As", self.dirname, "",
"Operation Files (*.fwr)|*.fwr|All Files (*.*)|*.*",
wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
if saveAsFileDialog.ShowModal() == wx.ID_OK:
contents = self.control.GetValue()
self.filename = saveFileDialog.GetFilename()
self.dirname = saveFileDialog.GetDirectory()
filehandle = open(os.path.join(self.dirname, self.filename), 'w')
filehandle.write(contents)
filehandle.close()
else:
sys.exit(1)
saveFileDialog.Destroy()
# save current contents in the file
# use wxPython output streams
#output_stream = wx.FileOutputStream(saveFileDialog.GetPath())
#if not output_stream.IsOk():
# wx.LogError("Cannot save contents of Operations File '%s'" % saveFileDialog.GetPath())
# return
the commented part at the bottom is another way I found to do it, is using the input and output streams more correct than the way it currently is? Also heres my other question, I got OnNew Working, here is the code:
def OnNew(self, event):
homedir = os.environ['HOME']
if not os.path.exists(homedir):
if getpass.getuser():
homedir = "C:/Users/" + getpass.getuser() + "/"
else:
homedir = "C:/"
newFileDialog = wx.FileDialog(self, "New Operation File", homedir, "",
"Operation Files (*.fwr)|*.fwr|All Files|(*.*)|*.*", wx.FD_CREATE|wx.OVERWRITE_PROMPT)
Everything is great but the OnOpen Method opens an open file dialog, I want a create file dialog (would this be the same as save? Can someone give me an example OnOpen method, and give me some insight into my OnSave and OnSaveAs methods? As you can see there are three aproaches, one in OnSaveAs, one in OnSave, and one commented out at the bottom of OnSaveAs(). As well as many more I didn't write down here. My main question though is how to get the filedialog for new to be a save dialog where you create a file, rather than an open dialog.
Thanks a ton.
SUMMARY:
1) How do you bring up a FileDialog that allows creation of blank files. I assum it will be similar to save, but hwatever ID flags I pass it always gives me an Open button
2) And as for save methods, is it better to do what I showed in the code, or use streams like the commented out section in SaveAs?.
To get the Save dialog, you need to pass the wx.SAVE style flag to your FileDialog object: style=wx.SAVE. You can read more about the save flag here or here.
Here's some example code that worked for me on Xubuntu 14.04 with wxPython 2.8.12.1 and Python 2.7:
import os
import wx
wildcard = "Python source (*.py)|*.py|" \
"All files (*.*)|*.*"
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY,
"File and Folder Dialogs Tutorial")
panel = wx.Panel(self, wx.ID_ANY)
self.currentDirectory = os.getcwd()
saveFileDlgBtn = wx.Button(panel, label="Show SAVE FileDialog")
saveFileDlgBtn.Bind(wx.EVT_BUTTON, self.onSaveFile)
# put the buttons in a sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(saveFileDlgBtn, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
#----------------------------------------------------------------------
def onSaveFile(self, event):
"""
Create and show the Save FileDialog
"""
dlg = wx.FileDialog(
self, message="Save file as ...",
defaultDir=self.currentDirectory,
defaultFile="", wildcard=wildcard, style=wx.FD_SAVE
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
print "You chose the following filename: %s" % path
dlg.Destroy()
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
I don't see anything wrong with your saving approach. In most cases, it's better to use Python's low level operators instead of using wxPython's. I would use Python's with operator though as that follows the newer idiom better:
with open(os.path.join(self.dirname, self.filename), 'w') as filehandle:
filehandle.write(contents)
I've got some code that uses the Gtk+ FileChooserDialog in Python 3.4 to allow a user to select a file.
Then, it's supposed to close the dialog (obviously) and continue executing the code that follows the user choosing a file. However, what happens is that the user selects their file, and the code continues, but the dialog doesn't disappear like it should.
I had this issue previously, and we figured out the reason why it was happening then and resolved it, but now it's happening again and although I know what's causing, I don't know how to actually resolve it.
Here's my code:
from gi.repository import Gtk
class FileChooser():
def __init__(self):
global path
dia = Gtk.FileChooserDialog("Please choose a file", None,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
self.add_filters(dia)
response = dia.run()
if response == Gtk.ResponseType.OK:
print("Open clicked")
print("File selected: " + dia.get_filename())
path = dia.get_filename()
elif response == Gtk.ResponseType.CANCEL:
print("Cancel clicked")
dia.destroy()
def add_filters(self, dia):
filter_any = Gtk.FileFilter()
filter_any.set_name("Any files")
filter_any.add_pattern("*")
dia.add_filter(filter_any)
filter_text = Gtk.FileFilter()
filter_text.set_name('Text files')
filter_text.add_mime_type('text/plain')
dia.add_filter(filter_text)
filter_py = Gtk.FileFilter()
filter_py.set_name('Python files')
filter_py.add_mime_type('text/x-python')
dia.add_filter(filter_py)
filter_img = Gtk.FileFilter()
filter_img.set_name('Image')
filter_img.add_mime_type('image/*')
dia.add_filter(filter_img)
dialog = FileChooser()
# path variable will be used after this point
The issue here is that, for reasons unknown to me, if I have the global path declaration in the FileChooser() class' __init__() function, the dialog won't disappear.
If I remove that global path declaration, the dialog goes away, but I get a NameError: name 'path' is not defined later in the program when I try to access the path variable!
I have also tried making path global right at the start of the program, but I still get the NameError.
What can I do to make this variable accessible later in my program, while still making the dialog disappear?
Consider the path variable as an instance to FileChooser(). It provides a logical end to have path accessed by the dialog that is representing the FileChooser().
class FileChooser():
def __init__(self):
#Stores your path
self.path = None
dia = Gtk.FileChooserDialog("Please choose a file", None,
Gtk.FileChooserAction.OPEN,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
self.add_filters(dia)
response = dia.run()
if response == Gtk.ResponseType.OK:
print("Open clicked")
print("File selected: " + dia.get_filename())
self.path = dia.get_filename()
elif response == Gtk.ResponseType.CANCEL:
print("Cancel clicked")
dia.destroy()
When you create the object.
dialog = FileChooser()
You can access it as follows:
dialog.path
I am trying to get a path with the QtGui.QFileDialog.getExistingDirectory() dialog window in a python program to ease things up for users while the rest of the program is in console output.
I have this piece of code for this purpose:
import sys, os
from PyQt4 import QtGui
def getpath(filename,
noPathFileMsg='',
wrongFolderMsg='',
selectFolderMsg=''):
try:
f = open('./'+filename,'r')
except IOError:
folder = get_new_path(filename,
noPathFileMsg,
selectFolderMsg)
else:
folder = f.readline()
f.close()
currentDir = os.getcwd()
try:
os.chdir(folder)
except:
folder = get_new_path(filename,
wrongFolderMsg,
selectFolderMsg)
else:
os.chdir(currentDir)
finally:
return folder
def get_new_path(filename,
infoMsg,
selectFolderMsg):
app = QtGui.QApplication(sys.argv)
QtGui.QMessageBox.about(None, 'No folder', infoMsg)
folder = QtGui.QFileDialog.getExistingDirectory(None, selectFolderMsg)
app.exit()
if os.name == 'posix':
folder += '/'
elif os.name == 'nt':
folder += '\\'
g = open('./'+filename,'w')
g.write(folder)
g.close()
return folder
if __name__ == '__main__':
folderPath = getpath('pathtofolder.txt',
noPathFileMsg='The path to the folder has not been set',
wrongFolderMsg='The path folder saved cannot be reached',
selectFolderMsg='Please select a folder')
print folderPath
var = input('The program stopped at the input instruction, the dialog window should now be closed!')
If I call the getpath function the dialog window stays open until the script that called the function ends instead of closing just after this instruction:
folder = QtGui.QFileDialog.getExistingDirectory(None, selectFolderMsg)
If you run this code it will create a file that saves the directory saved with the dialog window in the folder where the script is run.
What did I do wrong?
By the way, I am on Ubuntu 12.04.
Thank you!
Cheers
After setting up Ubuntu 12.04 in a VM, I can confirm that the dialog doesn't close properly after clicking "Open".
The problem seems to be caused by attempting to quit the QApplication inside the get_new_path function.
Instead, you should create a single, global QApplication object, and only quit it when the script completes:
def get_new_path(filename, infoMsg, selectFolderMsg):
QtGui.QMessageBox.about(None, 'No folder', infoMsg)
folder = QtGui.QFileDialog.getExistingDirectory(None, selectFolderMsg)
...
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
folderPath = getpath(...)
app.exit()
I want the open dialog to filter files by *.spectrum or not filter it (*.* all files).
I also want the save dialog to suggest a .spectrum extension when saving. The common, new file.ext where the new file is highlighted for us to overwrite.
I have set the wildcard = "*.spectrum" for both options, but please give me a more complete solution.
I've written a couple articles on this subject:
wxPython: Showing 2 Filetypes in wx.FileDialog
The Dialogs of wxPython
Basically what you want for the open and save dialogs is something like this:
wildcard = "Python source (*.spectrum)|*.spectrum|" \
"All files (*.*)|*.*"
Then in the code, you'd do something like this:
def onOpenFile(self, event):
"""
Create and show the Open FileDialog
"""
dlg = wx.FileDialog(
self, message="Choose a file",
defaultDir=self.currentDirectory,
defaultFile="",
wildcard=wildcard,
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
paths = dlg.GetPaths()
print "You chose the following file(s):"
for path in paths:
print path
dlg.Destroy()
#----------------------------------------------------------------------
def onSaveFile(self, event):
"""
Create and show the Save FileDialog
"""
dlg = wx.FileDialog(
self, message="Save file as ...",
defaultDir=self.currentDirectory,
defaultFile="", wildcard=wildcard, style=wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
print "You chose the following filename: %s" % path
dlg.Destroy()
Note: Code taken directly from my blog and only modified slightly.