How to open default browser download location with QFileDialog in Python? - python

I would like that QFileDialog in PyQt5 opens in default browser dowload location. I have this code, which opens last used location, because of '' empty third parameter. How can I read this information in Windows and Linux?
def selectfile_Dialog(self, event=None):
fname, _ = QtWidgets.QFileDialog.getOpenFileName(
self, 'Open File', '', 'Binary executable (*.exe)', None)
# sender is object that sends the signal
sender = self.sender()
# write the selected file name into that QLineEdit widget 'list1_lineEdit'
sender.setText(fname)

Here's a possible solution:
import sys
import webbrowser
import os
import winreg
from PyQt5.Qt import * # noqa
def get_download_path():
if os.name == 'nt':
sub_key = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
downloads_guid = '{374DE290-123F-4565-9164-39C4925E467B}'
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, sub_key) as key:
location = winreg.QueryValueEx(key, downloads_guid)[0]
return location
else:
return os.path.join(os.path.expanduser('~'), 'downloads')
def main():
app = QApplication(sys.argv)
fname, _ = QFileDialog.getOpenFileName(
None, 'Open File', get_download_path(), 'Binary executable (*.exe)', None
)
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Related

pyqt5 treeview refresh with nas server

i have create a simple file namager with pyqt5 and QTreeView().
W΅hen my path is local folder ...creating ,deleting etc from the app it show it in treeview without problem , example path
C:\Users\USER\Documents\projects\someFile
but when the path is nas server is not show changes example path
\my-ip-add\web\data\someFile
edit: i made create files and folder to update when change made, now trying for delete and drag and drop
in both cases files/folder are deleted ,created . the issue is in nas is not update treeview in delete function and in drag n drop
import os
import sys
from PyQt5.QtWidgets import QTreeView, QFileSystemModel, QApplication, QMenu, QAbstractItemView,QAction, QFileDialog, QMessageBox
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import options
import shutil
class Tree(QTreeView):
def __init__(self, path):
QTreeView.__init__(self)
self.settings = options.Settings()
self.model_base = QFileSystemModel()
self.path = path
self.model_base.setRootPath(self.path)
self.setModel(self.model_base)
self.setRootIndex(self.model_base.index(self.path))
self.model_base.setReadOnly(False)
self.setSelectionMode(self.SingleSelection)
self.setDragDropMode(QAbstractItemView.InternalMove)
self.setDragEnabled(True)
self.setAcceptDrops(True)
self.setDropIndicatorShown(True)
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.open_menu)
self.doubleClicked.connect(self.OpenFileFromTree)
def dragEnterEvent(self, event):
m = event.mimeData()
if m.hasUrls():
for url in m.urls():
if url.isLocalFile():
event.accept()
return
event.ignore()
def dropEvent(self, event):
if event.source():
QTreeView.dropEvent(self, event)
else:
ix = self.indexAt(event.pos())
if not self.model().isDir(ix):
ix = ix.parent()
pathDir = self.model().filePath(ix)
m = event.mimeData()
if m.hasUrls():
urlLocals = [url for url in m.urls() if url.isLocalFile()]
accepted = False
for urlLocal in urlLocals:
path = urlLocal.toLocalFile()
info = QFileInfo(path)
n_path = QDir(pathDir).filePath(info.fileName())
o_path = info.absoluteFilePath()
if n_path == o_path:
continue
if info.isDir():
QDir().rename(o_path, n_path)
else:
qfile = QFile(o_path)
if QFile(n_path).exists():
n_path += "(copy)"
qfile.rename(n_path)
accepted = True
if accepted:
event.acceptProposedAction()
def open_menu(self):
menu = QMenu()
NewFolderAction = QAction('New Folder', self)
NewFolderAction.triggered.connect(self.create_folder)
# new file action
NewFileAction = QAction('New File', self)
NewFileAction.triggered.connect(self.create_file)
# delete action
DeleteAction = QAction('Delete', self)
DeleteAction.triggered.connect(self.delete_file)
# rename action
RenameAction = QAction('Rename', self)
menu.addAction(NewFolderAction)
menu.addAction(NewFileAction)
menu.addAction(DeleteAction)
menu.exec_(QCursor.pos())
def delete_file(self):
# create QMessageBox to ask if the user is sure to delete the file
box = QMessageBox()
box.setIcon(QMessageBox.Question)
box.setWindowTitle('ΠΡΟΣΟΧΗ!')
box.setText('Are you sure?')
box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
buttonY = box.button(QMessageBox.Yes)
buttonY.setText('Yes')
buttonN = box.button(QMessageBox.No)
buttonN.setText('Cancel')
box.exec_()
if box.clickedButton() == buttonY:
try:
index = self.currentIndex()
file_path = self.model_base.filePath(index)
if os.path.isfile(file_path):
os.remove(file_path)
self.model_base.setRootPath(file_path)
else:
# os.rmdir(file_path)
shutil.rmtree(file_path, ignore_errors=True)
self.model_base.setRootPath(file_path)
except Exception as e:
options.SaveLogs('delete_file' + str(e))
pass
elif box.clickedButton() == buttonN:
pass
def create_file(self):
index = self.currentIndex()
file_path = self.model_base.filePath(index)
file_name = QFileDialog.getSaveFileName(self, "Επιλογή αρχείου", file_path)
# self.model_base.setRootPath(file_path)
if file_name[0]:
with open(file_name[0], 'w') as f:
new_folder_index = self.model_base.index(file_name[0])
# Expand the tree view to the new folder
self.expand(new_folder_index)
self.setCurrentIndex(new_folder_index)
pass
# create a function to open a dialog to create a new folder
def create_folder(self):
try:
global new_folder_path
index = self.currentIndex()
if not self.model_base.isDir(index):
index = index.parent()
# Get the path of the current index
path = self.model_base.filePath(index)
# Create a new folder
new_folder = QFileDialog.getSaveFileName(self, "Select Folder", path)
if new_folder[1]:
new_folder_path = os.path.join(path, new_folder[0])
QtCore.QDir().mkdir(new_folder_path)
# Get the index of the new folder
new_folder_index = self.model_base.index(new_folder_path)
# Expand the tree view to the new folder
self.expand(new_folder_index)
self.setCurrentIndex(new_folder_index)
except Exception as e:
options.SaveLogs('create_folder ' + str(e))
pass
def OpenFileFromTree(self):
try:
index = self.currentIndex()
file_path = self.model_base.filePath(index)
self.model_base.setRootPath(file_path)
p = file_path.replace("//", "\\\\").replace("/", "\\")
os.startfile(p)
except Exception as e:
options.SaveLogs('OpenFileFromTree ' + str(e))
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
tree = Tree(r"\\my-ip\web\data\someFile")
tree.show()
sys.exit(app.exec_())

Python EEL + wxpython: open "parentless" file dialog in front of all other windows and programs

I am developing an EEL project, and I needed to create a file dialog on the python side in order to preprocess data before sending it to javascript.
I tried to use tk.filedialog.askopenfilename, but that somehow froze the javascript event loop.
I found an answer on StackOverflow that used wxpython to create a non-blocking file picker. However, when I run the code below, the file picker always starts minimized.
However, once you use the file picker once, it works perfectly the second time.
Any help appreciated.
import base64
import json
from tkinter import Tk
Tk().withdraw()
from tkinter.filedialog import askopenfilename
import PIL.Image
import eel
import numpy as np
import wx
# Reusable wxpython App instance for the creation of non-blocking popup dialogs
app=wx.App(None)
eel.init("public")
def encode(bts):
return base64.b64encode(bts)
def array_to_json(array):
return json.dumps({
"shape": list(array.shape),
"dtype": str(array.dtype),
"data":list(np.ravel(array).astype(float)) # not efficient but quite clean
})
#eel.expose
def load_image(path):
return array_to_json(np.asarray(PIL.Image.open(path)))
#eel.expose
def pick_image():
# return askopenfilename()
""" --- Adapted from https://stackoverflow.com/a/59177064/5166365"""
style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST | wx.STAY_ON_TOP | wx.DIALOG_NO_PARENT | wx.MAXIMIZE
dialog = wx.FileDialog(None, "Open File", wildcard="*", style=style)
dialog.Iconize(False)
dialog.Maximize()
dialog.Raise()
path = ""
if dialog.ShowModal() == wx.ID_OK:
path = dialog.GetPath()
else:
path = ""
return path
""" --- """
eel.start("index.html")
I was able to get it working with the following code. I used a regular window instead of a wx.Dialog or similar class.
class FancyFilePickerApplication:
def __init__(self):
self.app = wx.App()
self.frame = wx.Frame(None,title="Fancy File Picker")
self.build_ui()
##private
def build_ui(self):
self.vertical_sizer = wx.BoxSizer(wx.VERTICAL)
self.control_panel = wx.Panel(self.frame,wx.ID_ANY)
self.horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.control_panel.SetSizer(self.horizontal_sizer)
self.frame.SetSizer(self.vertical_sizer)
self.dir_ctrl = wx.GenericDirCtrl(self.frame,wx.ID_ANY,wx.EmptyString,wx.DefaultPosition,wx.Size(400,300))
self.vertical_sizer.Add(self.dir_ctrl,wx.SizerFlags().Expand())
self.vertical_sizer.Add(self.control_panel,wx.SizerFlags().Expand())
self.scale_factor_label = wx.StaticText(self.control_panel,wx.ID_ANY,"Scale Factor: ")
self.scale_factor_textbox = wx.TextCtrl(self.control_panel,wx.ID_ANY)
self.open_button = wx.Button(self.control_panel,wx.ID_ANY,"Open")
self.horizontal_sizer.Add(self.scale_factor_label,wx.SizerFlags().Expand())
self.horizontal_sizer.Add(self.scale_factor_textbox,wx.SizerFlags().Expand())
self.horizontal_sizer.Add(self.open_button,wx.SizerFlags().Expand())
self.open_button.Bind(wx.EVT_BUTTON,lambda evt:self.submit())
self.frame.Bind(wx.EVT_CLOSE,self.cancel)
def open(self, file_picked_callback):
self.file_picked_callback = file_picked_callback
self.frame.Fit()
self.frame.Center()
self.frame.Show()
self.frame.Raise()
self.frame.ToggleWindowStyle(wx.STAY_ON_TOP)
self.app.MainLoop()
##private
def submit(self):
filepath =self.dir_ctrl.GetFilePath()
scale_factor_text = self.scale_factor_textbox.GetValue()
scale_factor = 1.0 if not scale_factor_text.strip() else float(scale_factor_text)
self.file_picked_callback(filepath,scale_factor)
self.frame.Destroy()
##private
def cancel(self,evt):
self.file_picked_callback("",0)
self.frame.Destroy()

Converting multiple HTML files to PDF using PyQt5

I tried following this answer: How to use PyQT5 to convert multiple HTML docs to PDF in one loop
I modified it to convert all html files found in a local folder. For example htmls is a list of html files to be converted: [Q:\Ray\test1.html, Q:\Ray\prac2.html]
This is the code. However, when I try to run it, Python just freezes and I have to stop the run.
import os
import glob
from PyQt5 import QtWidgets, QtWebEngineWidgets
class PdfPage(QtWebEngineWidgets.QWebEnginePage):
def __init__(self):
super().__init__()
self._htmls = []
self._current_path = ""
self.setZoomFactor(1)
self.loadFinished.connect(self._handleLoadFinished)
self.pdfPrintingFinished.connect(self._handlePrintingFinished)
def convert(self, htmls):
self._htmls = iter(zip(htmls))
self._fetchNext()
def _fetchNext(self):
try:
self._current_path = next(self._htmls)
except StopIteration:
return False
def _handleLoadFinished(self, ok):
if ok:
self.printToPdf(self._current_path)
def _handlePrintingFinished(self, filePath, success):
print("finished:", filePath, success)
if not self._fetchNext():
QtWidgets.QApplication.quit()
if __name__ == "__main__":
current_dir = os.path.dirname(os.path.realpath(__file__))
folder= current_dir+ '\\*.HTML'
htmls= glob.glob(folder)
app = QtWidgets.QApplication([])
page = PdfPage()
page.convert(htmls)
app.exec_()
print("finished")
It seems that the OP has not understood the logic of my previous solution which is:
Get the resource, in this case files,
Load it on the page,
When the load is finished then print the content of the page,
When the printing is finished then execute step 1 with the next resource.
In this it does not perform step 2, on the other hand it is recommended that the path of the pdf has a name other than the html
import os
import glob
from PyQt5.QtCore import QUrl
from PyQt5 import QtWidgets, QtWebEngineWidgets
class PdfPage(QtWebEngineWidgets.QWebEnginePage):
def __init__(self):
super().__init__()
self._htmls = []
self._current_path = ""
self.setZoomFactor(1)
self.loadFinished.connect(self._handleLoadFinished)
self.pdfPrintingFinished.connect(self._handlePrintingFinished)
def convert(self, htmls):
self._htmls = iter(htmls)
self._fetchNext()
def _fetchNext(self):
try:
self._current_path = next(self._htmls)
except StopIteration:
return False
else:
self.load(QUrl.fromLocalFile(self._current_path))
return True
def _handleLoadFinished(self, ok):
if ok:
self.printToPdf(self._current_path + ".pdf")
def _handlePrintingFinished(self, filePath, success):
print("finished:", filePath, success)
if not self._fetchNext():
QtWidgets.QApplication.quit()
if __name__ == "__main__":
current_dir = os.path.dirname(os.path.realpath(__file__))
folder= current_dir+ '\\*.HTML'
htmls = glob.glob(folder)
print(htmls)
if htmls:
app = QtWidgets.QApplication([])
page = PdfPage()
page.convert(htmls)
app.exec_()
print("finished")

PyQt application closes immediately after start

I'm trying make an exe application from my scripts using py2exe. The problem is that if I run it by doubleclicking on exe file, it closes immediately after open. If I run it from cmd, it works perfect.
I've tried to make a table global but it did not helped. I've already tried to keep the reference - no effect.
Here is the code of GUI in case it helps:
from PyQt4.QtGui import QTableWidget, QTableWidgetItem,QApplication
import sys
from PyQt4.QtGui import *
import os
from meteo import mesiac,den
class MyTable(QTableWidget):
def __init__(self, data, *args):
QTableWidget.__init__(self, *args)
self.data = data
self.setmydata()
self.resizeColumnsToContents()
self.resizeRowsToContents()
def setmydata(self):
horHeaders = []
for n, key in enumerate(['max teplota','min teplota','max vlhkost','min vlhkost','max tlak',
'min tlak','avg teplota','avg vlhkost','avg tlak']):
horHeaders.append(key)
for m, item in enumerate(self.data[key]):
newitem = QTableWidgetItem(str(item))
self.setItem(m, n, newitem)
self.setHorizontalHeaderLabels(horHeaders)
vertical_headers = ['{}.'.format(x+1) for x in xrange(len(self.data.values()[0])-1)]+['Mesiac:']
self.setVerticalHeaderLabels(vertical_headers)
self.setWindowTitle('Meteo')
def show_table():
global table
table = MyTable(data, len(data.values()[0]), len(data.keys()))
table.setFixedHeight(len(data.values()[0])*20)
table.setFixedWidth(len(data.keys())*95)
table.show()
return table
if __name__ == '__main__':
data = {}
os.system("mode con: cols=100 lines=40")
filenames = next(os.walk('mesiac'))[2]
list_of_den = []
for filename in filenames:
list_of_den.append(den(filename,filename[:-4]))
m = mesiac(list_of_den)
for den in list_of_den:
for n,attr in enumerate(['max teplota','min teplota','max vlhkost','min vlhkost','max tlak',
'min tlak','avg teplota','avg vlhkost','avg tlak']):
try:
data[attr].append(den.to_list()[n])
except:
data[attr]=[den.to_list()[n]]
m_list = m.to_list()
for n,attr in enumerate(['max teplota','min teplota','max vlhkost','min vlhkost','max tlak',
'min tlak','avg teplota','avg vlhkost','avg tlak']):
try:
data[attr].append(m_list[n])
except:
data[attr]=[m_list[n]]
app = QApplication(sys.argv)
t = show_table()
sys.exit(app.exec_())
And for sure - here is a setup.py file:
from distutils.core import setup
import py2exe
options ={"py2exe":{"includes":["sip","PyQt4.QtGui","PyQt4.QtCore","meteo"],"dll_excludes": ["MSVCP90.dll", "HID.DLL", "w9xpopen.exe"]}}
setup(window=['table.py'],options=options)
How to make it visible?

Why does QFileSystemWatcher work for directories but not files in Python?

I borrowed this code from another StackOverflow answer:
from PyQt4 import QtCore
#QtCore.pyqtSlot(str)
def directory_changed(path):
print('Directory Changed!!!')
#QtCore.pyqtSlot(str)
def file_changed(path):
print('File Changed!!!')
fs_watcher = QtCore.QFileSystemWatcher(['/path/to/files_1', '/path/to/files_2', '/path/to/files_3'])
fs_watcher.connect(fs_watcher, QtCore.SIGNAL('directoryChanged(QString)'), directory_changed)
fs_watcher.connect(fs_watcher, QtCore.SIGNAL('fileChanged(QString)'), file_changed)
The problem is, file_changed never gets called, no matter what. directory_changed is reliably called when a file is added, for example, but changing the files content does not result in file_changed being called.
I called a few variations of QtCore.SIGNAL('fileChanged(QString)'), eg, QtCore.SIGNAL('fileChanged(const QString &)'), to no avail. There are no warnings, or errors -- it simply does not trigger the function.
Recommendations?
It's hard to be certain what's going wrong, because the example code is incomplete, and so cannot work at all as it stands.
However, assuming the real code you are running is more or less sane/complete, your problem is probably caused by not adding the directory itself to the list of paths.
A basic script should look something like this:
import sys
from PyQt4 import QtCore
def directory_changed(path):
print('Directory Changed: %s' % path)
def file_changed(path):
print('File Changed: %s' % path)
app = QtCore.QCoreApplication(sys.argv)
paths = [
'/path/to',
'/path/to/files_1',
'/path/to/files_2',
'/path/to/files_3',
]
fs_watcher = QtCore.QFileSystemWatcher(paths)
fs_watcher.directoryChanged.connect(directory_changed)
fs_watcher.fileChanged.connect(file_changed)
sys.exit(app.exec_())
import argparse
import configparser
import os
import sys
from PyQt5 import QtCore
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QDesktopWidget, QMessageBox
from PyQt5.QtWidgets import QMainWindow
from ProgressBar_ui import Ui_Form
class ProgressBarWindow(QMainWindow, Ui_Form):
def __init__(self):
super().__init__()
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.progressBar.setMinimum(0)
self.ui.progressBar.setMaximum(0)
self.ui.progressBar.setValue(0)
self.setWindowTitle("Progress Bar")
self.MSversion = ""
self.LOADING_LOG_PATH = ""
mainIco = ("Icons\myIcon.ico")
self.setWindowIcon(QIcon(mainIco))
self.ui.label.setText("")
self.ui.label.setWordWrap(True)
def location_on_the_screen(self):
ag = QDesktopWidget().availableGeometry()
sg = QDesktopWidget().screenGeometry()
widget = self.geometry()
x = ag.width() - widget.width()
y = 2 * ag.height() - sg.height() - widget.height()
self.move(x, y)
def file_changed(self, pathPassed):
if os.path.exists(pathPassed):
f = open(pathPassed, "r")
for x in f:
#print(x)
label =x
self.ui.label.setText(label)
if x == "CloseLoading":
self.close()
def main():
app = QApplication(sys.argv)
w = ProgressBarWindow()
w.setWindowFlags(w.windowFlags() & ~QtCore.Qt.WindowMaximizeButtonHint)
parser = argparse.ArgumentParser()
parser = argparse.ArgumentParser(description='ProgressBar Arguments')
parser.add_argument('version', action="store", type=str)
args = vars(parser.parse_args())
if len(sys.argv) < 1:
msg = QMessageBox()
msg.setIcon(QMessageBox.Critical)
errorMsg = "There are less than 2 command line arguments provided.\nLauncher can not be run."
msg.setText(errorMsg)
msg.setWindowTitle("Save paths..")
msg.exec_()
sys.exit()
p= '/path/toFile/'
paths = [ p ]
fs_watcher = QtCore.QFileSystemWatcher(paths)
#fs_watcher.directoryChanged.connect(w.directory_changed)
fs_watcher.fileChanged.connect(w.file_changed)
w.location_on_the_screen()
w.show()
app.exec_()
if __name__ == "__main__":
sys.exit(main())

Categories

Resources