I've been trying to implement a file browsing widget in the GUI I'm designing. I am using the QFileDialog module, which works great - I can browse and save a file with the following line of code:
filenames = QFileDialog.getOpenFileName()
My widget is set up with a QLineEdit, which I would like to display the name of the file selected, and a QPushButton, which I would like to initiate the above line of code. However, I'd like to know if there's a way I can set a "default" option. If the browse push button is not clicked, I would like the file to be the following:
filenames = str(glob.glob('*.npy')[0])
Which would be saved as the filename in question and show up in my LineEdit. My problem is coming from trying to display a different file name in the LineEdit, depending on whether or not the browse push button has been clicked. If it has been clicked, I would like the LineEdit to show the user-selected file instead of the default option. Here are the applicable lines of code in my retranslate function:
def retranslateUi(self, ROIGUI):
self.lineEdit.setText(_translate("ROIGUI", self.fileSelect(False), None))
self.Browse.setText(_translate("ROIGUI", "Browse...", None))
self.Browse.clicked.connect(self.fileSelect(True))
Which link to the following function. As you can see, this is currently not working correctly because in the LineEdit, tripped is always False. Very silly.
def fileSelect(self,tripped):
filenames = str(glob.glob('*.npy')[0])
if tripped==True:
filenames = QFileDialog.getOpenFileName()
self.lineEdit.setText(_translate("ROIGUI", filenames, None))
return filenames
I've been trying different ways of getting this to work, but everything I tried either (a) never updates my LineEdit after file browsing, or (b) runs file browsing immediately without ever using the default option. Thoughts? I'm sure there's a way of doing this that I'm just not seeing.
Thank you in advance.
Edited To Add
I think I have fixed most of my problem - my Browse button is now connected via buttonGroup to an integer, so my fileSelect looks like this:
def fileSelect(self):
signal = self.buttonGroup2.checkedId()
if signal==-1:
filenames = str(glob.glob('*.npy')[0])
elif signal==1:
filenames = QFileDialog.getOpenFileName()
if (filenames.isNull()):
filenames = str(glob.glob('*.npy')[0])
return filenames
And my "retranslate" browse button and lineEdit look like this:
self.lineEdit.setText(_translate("ROIGUI", str(self.fileSelect()), None))
self.Browse.clicked.connect(self.fileSelect)
My only problem is getting the text of my lineEdit to update; although the file in use itself updates after it's selected with Browse, the text itself doesn't update. Help?
If the cancel button is selected from the QFileDialog filenames variable will be a null QString so, you could:
filenames = QFileDialog.getOpenFileName()
if (filenames.isNull()):
self.lineEdit.setText(_translate("ROIGUI", filenames, None))
else:
# The alternative code. Set the default value here to the QLineEdit.
Reference: QFileDialog.getOpenFileName()
Related
My scrip ist currently using QtWidgets.QFileDialog.getOpenFileNames() to let the user select files within Windows explorer. Now I´m wondering if there is a way to let them select also folders, not just files. There are some similar posts, but none of them provides a working solution. I really dont want to use the QFileDialog file explorer to get around this.
QFileDialog doesn't allow that natively. The only solution is to create your own instance, do some small "patching".
Note that in order to achieve this, you cannot use the native dialogs of your OS, as Qt has almost no control over them; that's the reason of the dialog.DontUseNativeDialog flag, which is mandatory.
The following code works as much as static methods do, and returns the selected items (or none, if the dialog is cancelled).
def getOpenFilesAndDirs(parent=None, caption='', directory='',
filter='', initialFilter='', options=None):
def updateText():
# update the contents of the line edit widget with the selected files
selected = []
for index in view.selectionModel().selectedRows():
selected.append('"{}"'.format(index.data()))
lineEdit.setText(' '.join(selected))
dialog = QtWidgets.QFileDialog(parent, windowTitle=caption)
dialog.setFileMode(dialog.ExistingFiles)
if options:
dialog.setOptions(options)
dialog.setOption(dialog.DontUseNativeDialog, True)
if directory:
dialog.setDirectory(directory)
if filter:
dialog.setNameFilter(filter)
if initialFilter:
dialog.selectNameFilter(initialFilter)
# by default, if a directory is opened in file listing mode,
# QFileDialog.accept() shows the contents of that directory, but we
# need to be able to "open" directories as we can do with files, so we
# just override accept() with the default QDialog implementation which
# will just return exec_()
dialog.accept = lambda: QtWidgets.QDialog.accept(dialog)
# there are many item views in a non-native dialog, but the ones displaying
# the actual contents are created inside a QStackedWidget; they are a
# QTreeView and a QListView, and the tree is only used when the
# viewMode is set to QFileDialog.Details, which is not this case
stackedWidget = dialog.findChild(QtWidgets.QStackedWidget)
view = stackedWidget.findChild(QtWidgets.QListView)
view.selectionModel().selectionChanged.connect(updateText)
lineEdit = dialog.findChild(QtWidgets.QLineEdit)
# clear the line edit contents whenever the current directory changes
dialog.directoryEntered.connect(lambda: lineEdit.setText(''))
dialog.exec_()
return dialog.selectedFiles()
I would say I'm fairly decent with Python, but creating GUIs is a new concept for me. I've used Qt Creator to format the GUI and pyuic to convert the code from the file.ui.
I have most of the GUI coded, but I'm having this problem updating the text for labels for line edits, push buttons etc. So this GUI has an options window that opens from the main program where the user can specify certain parameters. Currently, I open the options, set the values, close, reopen the option window, and the text has not changed to the new values which are variables. Plain strings do work however. Variables will 'stick,' only if the program is restarted.
I'm importing a config.py file where there is a variable containing the string of parameters. These are formatted and set alongside all other labels etc. But there not being set for some reason.
config.py
configAttrs="clientid,oauth,123,source,123"
A nested function of mainProgram.py used to set the text of the labels etc.
def retranslateUi(self, OptionsWindow):
OptionsWindow.setWindowTitle(_translate("OptionsWindow", "OptionsWindow", None))
self.label_MainOptions.setText(_translate("OptionsWindow", "Options", None))
confs = config.configAttrs.split(',')
clientid = str(confs[0])
oauth = str(confs[1])
cache = str(confs[2])
heightAdjust = str(confs[4])
#does NOT work when reopening options window
#does work with restart
self.lineEdit_ClientID.setText(_translate("OptionsWindow", clientid, None))
#does NOT work when reopening options window
#does work with restart
self.lineEdit_ClientID.setText('{0}'.format(clientid))
#does work when reopening options window
#does work with restart
self.lineEdit_ClientID.setText(_translate("OptionsWindow", 'string_clientid', None))
Shortened the code above.*
The problem is caused because although the config.py file is modified this is not automatically reloaded by python, in order to force it you must use reload, in your case:
def retranslateUi(self, OptionsWindow):
[...]
reload(config)
confs = config.configAttrs.split(',')
[...]
I would like to press a button and than open a file browser and write down selected file in a label. I have this function which I call when the button is pressed:
#Slot()
def browse_folder(self):
self.fname = QtGui.QFileDialog.getOpenFileName()
self.statusLabel.setText(self.fname)
However, I get an error:
TypeError: 'PySide.QtGui.QLabel.setText' called with wrong argument types:
PySide.QtGui.QLabel.setText(unicode, unicode)
Supported signatures:
PySide.QtGui.QLabel.setText(unicode)
How do I convert self.fname, which holds selected file name, as unicode?
The PySide docs are not brilliant on this. But the easiest way to answer this sort of question is to build a little test harness. Something like:
from PySide import QtCore,QtGui
def do_file():
fname = QtGui.QFileDialog.getOpenFileName()
print fname
app = QtGui.QApplication([])
button = QtGui.QPushButton("Test File")
button.clicked.connect(do_file)
button.show()
app.exec_()
Running this a little bit will show you that the static getOpenFileName method returns a tuple consisting of the filename first and the chosen filter second. For example, by default, on my system this returns ('C:/Users/Myname/Documents/filename', 'All Files (*.*)').
So you then need to extract the first element of the tuple before calling setText.
I've been trying to implement a file browsing widget in the GUI I'm designing. I am using the QFileDialog module, which works great - I can browse and save a file with the following line of code:
filenames = QFileDialog.getOpenFileName()
My widget is set up with a QLineEdit, which I would like to display the name of the file selected, and a QPushButton, which I would like to initiate the above line of code. However, I'd like to know if there's a way I can set a "default" option. If the browse push button is not clicked, I would like the file to be the following:
filenames = str(glob.glob('*.npy')[0])
Which would be saved as the filename in question and show up in my LineEdit. My problem is coming from trying to display a different file name in the LineEdit, depending on whether or not the browse push button has been clicked. If it has been clicked, I would like the LineEdit to show the user-selected file instead of the default option. Here are the applicable lines of code in my retranslate function:
def retranslateUi(self, ROIGUI):
self.lineEdit.setText(_translate("ROIGUI", self.fileSelect(False), None))
self.Browse.setText(_translate("ROIGUI", "Browse...", None))
self.Browse.clicked.connect(self.fileSelect(True))
Which link to the following function. As you can see, this is currently not working correctly because in the LineEdit, tripped is always False. Very silly.
def fileSelect(self,tripped):
filenames = str(glob.glob('*.npy')[0])
if tripped==True:
filenames = QFileDialog.getOpenFileName()
self.lineEdit.setText(_translate("ROIGUI", filenames, None))
return filenames
I've been trying different ways of getting this to work, but everything I tried either (a) never updates my LineEdit after file browsing, or (b) runs file browsing immediately without ever using the default option. Thoughts? I'm sure there's a way of doing this that I'm just not seeing.
Thank you in advance.
Edited To Add
I think I have fixed most of my problem - my Browse button is now connected via buttonGroup to an integer, so my fileSelect looks like this:
def fileSelect(self):
signal = self.buttonGroup2.checkedId()
if signal==-1:
filenames = str(glob.glob('*.npy')[0])
elif signal==1:
filenames = QFileDialog.getOpenFileName()
if (filenames.isNull()):
filenames = str(glob.glob('*.npy')[0])
return filenames
And my "retranslate" browse button and lineEdit look like this:
self.lineEdit.setText(_translate("ROIGUI", str(self.fileSelect()), None))
self.Browse.clicked.connect(self.fileSelect)
My only problem is getting the text of my lineEdit to update; although the file in use itself updates after it's selected with Browse, the text itself doesn't update. Help?
If the cancel button is selected from the QFileDialog filenames variable will be a null QString so, you could:
filenames = QFileDialog.getOpenFileName()
if (filenames.isNull()):
self.lineEdit.setText(_translate("ROIGUI", filenames, None))
else:
# The alternative code. Set the default value here to the QLineEdit.
Reference: QFileDialog.getOpenFileName()
I'm new to programming & new to python. I've just developed my first script, it prosesses file, but at the moment only from the commandline.
This is just a hobby to me so my job does not depend on it :-)
I've spent a few days now trying to get my head around python gui development & have come to the conclusion that I must be stupid.
I've looked at wxpython & Tkinter & do not understand either, although Tkinter seems to be the easier out of the two. I've even looked at wysiwyg tools like Boa Contrictor & wxglade. I do not even understand how to use those. I would prefer to just stick with my editor & code manually anyway.
My problem is this:
I would like to create a desktop window with either 1 or two objects, depending on what works best. If just one object then a text box of some sort, if 2 objects then a text box & an image.
I want to be able to drag file from a file manager & drop them on my script window, this is just to pass the filenames to my script.
I than want to redirect stdout to an object within my desktop window so that all script output appears within the desktop window.
I'm not sure if one object can do both things or not. If it can than just a text box would suffice, else drop files onto image & have redirected output going to the text box.
I have found drag & drop examples on the web but nothing which incorporates stdout redirect, & I've not been able to successfully modify any of the examples that I've come across.
If somee kind sole has the time to demonstrate how to achieve what I want & explain how its works I would greatfully appreciate it!
----EDIT ----
I've been playing around with 2 examples & have managed to hash the 2 together in order to get what I wanted working. Code is below. It's not cleaned up yet ( old comments etc... ), but it works.
#!/usr/bin/python
# The next two lines are not necessary if you installed TkDnd
# in a proper place.
import os
from Tkinter import *
os.environ['TKDND_LIBRARY'] = '/home/clinton/Python/tkdnd2.6/'
import Tkinter
from untested_tkdnd_wrapper import TkDND
class Redir(object):
# This is what we're using for the redirect, it needs a text box
def __init__(self, textbox):
self.textbox = textbox
self.textbox.config(state=NORMAL)
self.fileno = sys.stdout.fileno
def write(self, message):
# When you set this up as redirect it needs a write method as the
# stdin/out will be looking to write to somewhere!
self.textbox.insert(END, str(message))
root = Tkinter.Tk()
dnd = TkDND(root)
textbox = Tkinter.Text()
textbox.pack()
def handle(event):
event.widget.insert(END, event.data)
content = textbox.get("0.0",Tkinter.END)
filename = content.split()
dnd.bindtarget(textbox, handle, 'text/uri-list')
#Set up the redirect
stdre = Redir(textbox)
# Redirect stdout, stdout is where the standard messages are ouput
sys.stdout = stdre
# Redirect stderr, stderr is where the errors are printed too!
sys.stderr = stdre
# Print hello so we can see the redirect is working!
print "hello"
# Start the application mainloop
root.mainloop()
Examples are: python drag and drop explorer files to tkinter entry widget
And also the example provided kindly by Noelkd.
In order for this code to work you must create the wrapper from first example. Also currently code just displays dragged file in window, however variable is in place to be passed onto the script which runs behind the gui interface.
If you want to use Tkinter:
from Tkinter import *
import tkFileDialog
class Redir(object):
# This is what we're using for the redirect, it needs a text box
def __init__(self, textbox):
self.textbox = textbox
self.textbox.config(state=NORMAL)
self.fileno = sys.stdout.fileno
def write(self, message):
# When you set this up as redirect it needs a write method as the
# stdin/out will be looking to write to somewhere!
self.textbox.insert(END, str(message))
def askopenfilename():
""" Prints the selected files name """
# get filename, this is the bit that opens up the dialog box this will
# return a string of the file name you have clicked on.
filename = tkFileDialog.askopenfilename()
if filename:
# Will print the file name to the text box
print filename
if __name__ == '__main__':
# Make the root window
root = Tk()
# Make a button to get the file name
# The method the button executes is the askopenfilename from above
# You don't use askopenfilename() because you only want to bind the button
# to the function, then the button calls the function.
button = Button(root, text='GetFileName', command=askopenfilename)
# this puts the button at the top in the middle
button.grid(row=1, column=1)
# Make a scroll bar so we can follow the text if it goes off a single box
scrollbar = Scrollbar(root, orient=VERTICAL)
# This puts the scrollbar on the right handside
scrollbar.grid(row=2, column=3, sticky=N+S+E)
# Make a text box to hold the text
textbox = Text(root,font=("Helvetica",8),state=DISABLED, yscrollcommand=scrollbar.set, wrap=WORD)
# This puts the text box on the left hand side
textbox.grid(row=2, column=0, columnspan=3, sticky=N+S+W+E)
# Configure the scroll bar to stroll with the text box!
scrollbar.config(command=textbox.yview)
#Set up the redirect
stdre = Redir(textbox)
# Redirect stdout, stdout is where the standard messages are ouput
sys.stdout = stdre
# Redirect stderr, stderr is where the errors are printed too!
sys.stderr = stdre
# Print hello so we can see the redirect is working!
print "hello"
# Start the application mainloop
root.mainloop()
What this does is creates a window with a button and a text box, with stdout redirect.
Currently in Tkinter you can't drag and drop files on to the open tk window(you can if you use tkdnd), so I have included a different way of getting the path of a file.
The way I have included to select a file is the askopenfilename dialog from tkFileDialog, this opens up a file browser and the path file selected is returned as a string.
If you have any questions or this doesn't quite do what your looking for please leave a comment!
Have a look at GTK. It is a really powerful library. Not the simplest, that's a fact, but once you get to understand how things work, it becomes much easier.
Here's the official tutorial
If oyu are still using Python2, I think you should use PyGTK but it has been replaced by gl (which is described in the above tutorial). A good tutorial for PyGTK can be found here.
For a static interface, you can use glade which produces XML files that are then read by GTKBuilder to create the "real" interface. The first tutorial that I've found is available here