I'm looking for a way to get the value or text of all the user inputs/lineedits of the app
I'm creating an app that creates multiple folders at once. There are multiple user inputs to write in the name of the folders, that I create by calling the same function multiple times. Using this "self.le2.text()" only gets the value of the first user input created.
Here's my code so far. Essentially I want the "create folders" button to create all the folders from all the user inputs created by the "new_folder" function. Right now its only getting the value of the first one created.
import sys
import os
from PySide6 import QtWidgets, QtCore, QtGui
from PySide6.QtWidgets import QApplication
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
#set central widget and layout
self.setWindowTitle("Amazing Folder Generator")
self.generalLayout = QtWidgets.QVBoxLayout()
self.centralWidget = QtWidgets.QWidget()
self.setCentralWidget(self.centralWidget)
self.centralWidget.setLayout(self.generalLayout)
self.le1 = QtWidgets.QLineEdit()
self.file_path()
self.button1 = QtWidgets.QPushButton("New Folder")
self.generalLayout.addWidget(self.button1)
self.button1.pressed.connect(self.new_folder)
self.button2 = QtWidgets.QPushButton("Create Folders")
self.generalLayout.addWidget(self.button2)
self.button2.pressed.connect(self.create_files)
self.new_folder()
self.new_folder()
self.new_folder()
def file_path(self):
self.le1 = QtWidgets.QLineEdit()
self.le1.setFixedHeight(20)
self.le1.setAlignment(QtCore.Qt.AlignRight)
self.path_layout = QtWidgets.QFormLayout()
self.path_layout.addRow("Folder Path: ", self.le1)
self.generalLayout.addLayout(self.path_layout)
def new_folder(self):
self.le2 = QtWidgets.QLineEdit()
self.le2.setFixedHeight(20)
self.le2.setAlignment(QtCore.Qt.AlignRight)
self.path_layout = QtWidgets.QFormLayout()
filename = "File: "
self.path_layout.addRow(filename, self.le2)
self.generalLayout.addLayout(self.path_layout)
def create_files(self):
path = self.le1.text() + "\\"
filename = self.le2.text()
newpath = path + filename
if not os.path.exists(newpath):
os.makedirs(newpath)
else:
print("folder already exists")
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The simple solution is to store the QLineEdits in a list and then iterate to get the text. In this case I have rewritten your code to make it more readable.
import sys
import os
import os.path
from PySide6 import QtWidgets, QtCore, QtGui
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle("Amazing Folder Generator")
self.folder_le = QtWidgets.QLineEdit(alignment=QtCore.Qt.AlignRight)
self.folder_le.setFixedHeight(20)
self.add_row_button = QtWidgets.QPushButton("New Folder")
self.create_button = QtWidgets.QPushButton("Create Folders")
self.files_layout = QtWidgets.QFormLayout()
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
self.form_layout = QtWidgets.QFormLayout(central_widget)
self.form_layout.addRow("Folder Path:", self.folder_le)
self.form_layout.addRow(self.add_row_button)
self.form_layout.addRow(self.create_button)
self.form_layout.addRow(self.files_layout)
self._files_le = []
self.add_row_button.clicked.connect(self.add_row)
self.create_button.clicked.connect(self.create_files)
for _ in range(3):
self.add_row()
#property
def folder(self):
return self.folder_le.text()
#property
def filenames(self):
return [le.text() for le in self._files_le]
def add_row(self):
le = QtWidgets.QLineEdit(alignment=QtCore.Qt.AlignRight)
le.setFixedHeight(20)
self.files_layout.addRow("File:", le)
self._files_le.append(le)
def create_files(self):
for filename in self.filenames:
newpath = os.path.join(self.folder, filename)
if not os.path.exists(newpath):
os.makedirs(newpath)
else:
print("folder already exists")
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I want to let users create files by dragging items from PyQt to the system file explorer. Since some of the files will be very large, I also need to delay setting the data to when the user finishes the drop instead of immediately on start of drag.
This example seems to be what I need: https://doc.qt.io/archives/4.6/draganddrop-delayedencoding.html
I tried converting that to a simple PyQt5 version where dragging a QPushButton into a folder will create a plain text file, but it's not working for me... when I run it dropping does nothing and my cursor looks like this:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import typing
import time
class MimeData(QtCore.QMimeData):
dataRequested = QtCore.pyqtSignal(str)
def formats(self) -> typing.List[str]:
return QtCore.QMimeData.formats(self) + ["text/plain"]
def retrieveData(self, mime_type: str, preferred_type: QtCore.QVariant.Type):
self.dataRequested.emit(mime_type)
return QtCore.QMimeData.retrieveData(self, mime_type, preferred_type)
class SourceWidget(QtWidgets.QWidget):
mimeData: MimeData = None
def __init__(self, parent=None):
super().__init__(parent)
layout = QtWidgets.QVBoxLayout()
button = QtWidgets.QPushButton("Drag Me")
button.pressed.connect(self.start_drag)
layout.addWidget(button)
self.setLayout(layout)
#QtCore.pyqtSlot()
def create_data(self, mime_type):
if mime_type == "text/plain":
time.sleep(0.25) # Simulate large file
self.mimeData.setData("text/plain", b"my text file contents")
#QtCore.pyqtSlot()
def start_drag(self):
self.mimeData = MimeData()
self.mimeData.dataRequested.connect(self.create_data)
drag = QtGui.QDrag(self)
drag.setMimeData(self.mimeData)
drag.exec(QtCore.Qt.CopyAction)
if __name__ == "__main__":
app = QtWidgets.QApplication.instance() or QtWidgets.QApplication(sys.argv)
w = SourceWidget()
w.show()
app.exec_()
Here's what I ended up with for dragging and dropping files from PyQt5 into file explorer, and only having the file write once the mouse is released to finalize the drop.
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
import tempfile
import os
# Use win32api on Windows because the pynput and mouse packages cause lag
# https://github.com/moses-palmer/pynput/issues/390
if os.name == 'nt':
import win32api
def mouse_pressed():
return win32api.GetKeyState(0x01) not in [0, 1]
else:
import mouse
def mouse_pressed():
return mouse.is_pressed()
class DelayedMimeData(QtCore.QMimeData):
def __init__(self):
super().__init__()
self.callbacks = []
def add_callback(self, callback):
self.callbacks.append(callback)
def retrieveData(self, mime_type: str, preferred_type: QtCore.QVariant.Type):
mp = mouse_pressed()
if not mp:
for callback in self.callbacks.copy():
self.callbacks.remove(callback)
callback()
return QtCore.QMimeData.retrieveData(self, mime_type, preferred_type)
class Navigator(QtWidgets.QTreeWidget):
def __init__(self):
super().__init__()
self.setHeaderLabels(["Name"])
QtWidgets.QTreeWidgetItem(self, ['Test1'])
QtWidgets.QTreeWidgetItem(self, ['Test2'])
QtWidgets.QTreeWidgetItem(self, ['Test3'])
self.setAcceptDrops(True)
self.setDragEnabled(True)
self.setDragDropMode(self.DragDrop)
self.setDefaultDropAction(Qt.MoveAction)
self.setSelectionMode(self.ExtendedSelection)
self.setSelectionBehavior(self.SelectRows)
self.setContextMenuPolicy(Qt.CustomContextMenu)
def startDrag(self, actions):
drag = QtGui.QDrag(self)
names = [item.text(0) for item in self.selectedItems()]
mime = DelayedMimeData()
path_list = []
for name in names:
path = os.path.join(tempfile.gettempdir(), 'DragTest', name + '.txt')
os.makedirs(os.path.dirname(path), exist_ok=True)
print(path)
def write_to_file(path=path, name=name, widget=self):
with open(path, 'w+') as f:
print("Writing large file(s)...")
time.sleep(2) # Sleep to simulate long file write
f.write(f"Contents of {name}")
mime.add_callback(write_to_file)
path_list.append(QtCore.QUrl.fromLocalFile(path))
mime.setUrls(path_list)
mime.setData('application/x-qabstractitemmodeldatalist',
self.mimeData(self.selectedItems()).data('application/x-qabstractitemmodeldatalist'))
drag.setMimeData(mime)
drag.exec_(Qt.MoveAction)
super().startDrag(actions)
app = QtWidgets.QApplication([])
nav = Navigator()
nav.show()
app.exec_()
I am using QFileDialog.getOpenFileName(self,'Remove File', "path", '*.pdf') to select a file and get the path in order to remove it from my application. The issue is the QFileDialog.getOpenFileName window button says 'Open' when selecting a file which will be confusing to the user.
Is there any way to change the button text from 'Open' to 'Remove'/'Delete'
When using the static method QFileDialog::getOpenFileName() the first thing is to obtain the QFileDialog object and for that we use a QTimer and the findChild() method:
# ...
QtCore.QTimer.singleShot(0, self.on_timeout)
filename, _ = QtWidgets.QFileDialog.getOpenFileName(...,
options=QtWidgets.QFileDialog.DontUseNativeDialog)
def on_timeout(self):
dialog = self.findChild(QtWidgets.QFileDialog)
# ...
Then you can get the text iterating over the buttons until you get the button with the searched text and change it:
for btn in dialog.findChildren(QtWidgets.QPushButton):
if btn.text() == "&Open":
btn.setText("Remove")
That will work at the beginning but every time you interact with the QTreeView they show, update the text to the default value, so the same logic will have to be applied using the currentChanged signal from the selectionModel() of the QTreeView but for synchronization reasons it is necessary Update the text later using another QTimer.singleShot(), the following code is a workable example:
import sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Press me")
button.clicked.connect(self.on_clicked)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button)
#QtCore.pyqtSlot()
def on_clicked(self):
QtCore.QTimer.singleShot(0, self.on_timeout)
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
"Remove File",
"path",
"*.pdf",
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
def on_timeout(self):
dialog = self.findChild(QtWidgets.QFileDialog)
dialog.findChild(QtWidgets.QTreeView).selectionModel().currentChanged.connect(
lambda: self.change_button_name(dialog)
)
self.change_button_name(dialog)
def change_button_name(self, dialog):
for btn in dialog.findChildren(QtWidgets.QPushButton):
if btn.text() == self.tr("&Open"):
QtCore.QTimer.singleShot(0, lambda btn=btn: btn.setText("Remove"))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
The first step can be avoided if the static method is not used and create the dialog using an instance of QFileDialog:
import sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Press me")
button.clicked.connect(self.on_clicked)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button)
#QtCore.pyqtSlot()
def on_clicked(self):
dialog = QtWidgets.QFileDialog(
self,
"Remove File",
"path",
"*.pdf",
supportedSchemes=["file"],
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
self.change_button_name(dialog)
dialog.findChild(QtWidgets.QTreeView).selectionModel().currentChanged.connect(
lambda: self.change_button_name(dialog)
)
if dialog.exec_() == QtWidgets.QDialog.Accepted:
filename = dialog.selectedUrls()[0]
print(filename)
def change_button_name(self, dialog):
for btn in dialog.findChildren(QtWidgets.QPushButton):
if btn.text() == self.tr("&Open"):
QtCore.QTimer.singleShot(0, lambda btn=btn: btn.setText("Remove"))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
While I appreciate the solution provided by #eyllanesc, I'd like to propose a variation.
Under certain circumstances, the code for that answer might fail, specifically:
the delay that X11 suffers from mapping windows;
the checking of localized button strings;
the selection using the file name edit box;
Considering the above, I propose an alternate solution, based on the points above.
For obvious reasons, the main point remains: the dialog must be non-native.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class FileDialogTest(QWidget):
def __init__(self):
super().__init__()
layout = QHBoxLayout(self)
self.fileEdit = QLineEdit()
layout.addWidget(self.fileEdit)
self.selectBtn = QToolButton(icon=QIcon.fromTheme('folder'), text='…')
layout.addWidget(self.selectBtn)
self.selectBtn.clicked.connect(self.showSelectDialog)
def checkSelectDialog(self):
dialog = self.findChild(QFileDialog)
if not dialog.isVisible():
# wait for dialog finalization, as testOption might fail
return
# dialog found, stop the timer and delete it
self.sender().stop()
self.sender().deleteLater()
if not dialog.testOption(dialog.DontUseNativeDialog):
# native dialog, we cannot do anything!
return
def updateOpenButton():
selection = tree.selectionModel().selectedIndexes()
if selection and not tree.model().isDir(selection[0]):
# it's a file, change the button text
button.setText('Select my precious file')
tree = dialog.findChild(QTreeView)
button = dialog.findChild(QDialogButtonBox).button(
QDialogButtonBox.Open)
# check for selected files on open
updateOpenButton()
# connect the selection update signal
tree.selectionModel().selectionChanged.connect(
lambda: QTimer.singleShot(0, updateOpenButton))
def showSelectDialog(self):
QTimer(self, interval=10, timeout=self.checkSelectDialog).start()
path, filter = QFileDialog.getOpenFileName(self,
'Select file', '<path_to_file>',
"All Files (*);;Python Files (*.py);; PNG Files (*.png)",
options=QFileDialog.DontUseNativeDialog)
if path:
self.fileEdit.setText(path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
ex = FileDialogTest()
ex.show()
sys.exit(app.exec())
Obviously, for PyQt6 you'll need to use the proper Enum namespaces (i.e. QFileDialog.Option.DontUseNativeDialog, etc.).
I am working on a small GUI for managing virtual environments. In the main window, I want to display existing virtual environments from a default directory in a table view. This works so far.
Now I've noticed that if I choose a different default directory, I have to close the GUI and open it again to see the content. Unfortunately, I did not consider that in my plans (I'm still a bit inexperienced in Python).
I would like to add a button with which you can update the contents of the table view. At the same time, the existing button okButton in settings.py (which confirms the input of the selected standard directory) should also update the table view.
I tried to use pyqtsignal() and pyqtslot(), but I don't understand how to apply that to my code. The data (for example: version, path ...) for the table view comes from a loop located in organize.py. The items are collected in a list and then displayed in the table.
How can I refresh the view with a button click? Do I have to revise my code structure?
Here are the minimal reproducable parts of the code:
You can also take look at the repository here if you want. There is no commercial background.
main_ui.py
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import organize
import settings
class Ui_MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setupUi()
def setupUi(self):
self.selectDefaultDir = settings.SetDefaultDirectory()
self.setWindowTitle("MainWindow")
self.setGeometry(430, 335, 750, 330)
centralwidget = QWidget(self)
self.v_Layout_1 = QVBoxLayout()
self.v_Layout_2 = QVBoxLayout(centralwidget)
selectButton = QPushButton(
"Set default dir", clicked=self.selectButton_clicked
)
# venv table
venvTable = QTableView(centralwidget)
venvTable.verticalHeader().setVisible(False)
venvTable.setSelectionBehavior(QAbstractItemView.SelectRows)
venvTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
venvTable.setAlternatingRowColors(True)
# adjust vertical headers
v_HeaderTV2 = venvTable.verticalHeader()
v_HeaderTV2.setVisible(False)
v_HeaderTV2.setDefaultSectionSize(27.5)
# adjust (horizontal) headers
h_HeaderTV2 = venvTable.horizontalHeader()
h_HeaderTV2.setDefaultAlignment(Qt.AlignLeft)
h_HeaderTV2.setDefaultSectionSize(180)
h_HeaderTV2.setStretchLastSection(True)
# set table view model
self.modelTV2 = QStandardItemModel(centralwidget)
self.modelTV2.setColumnCount(3)
self.modelTV2.setHorizontalHeaderLabels(
["Venv Name", "Version", "Path"]
)
venvTable.setModel(self.modelTV2)
self.v_Layout_1.addWidget(venvTable)
self.v_Layout_1.addWidget(selectButton)
self.v_Layout_2.addLayout(self.v_Layout_1)
self.setCentralWidget(centralwidget)
def popVenvTable(self):
"""
Populate the venv table view.
"""
for i in range(len(organize.venvDirs)):
self.modelTV2.insertRow(0)
self.modelTV2.setItem(0, 0, QStandardItem(organize.venvDirs[i]))
self.modelTV2.setItem(0, 1, QStandardItem(organize.venvVers[i]))
self.modelTV2.setItem(0, 2, QStandardItem(organize.venvPath[i]))
def selectButton_clicked(self):
self.selectDefaultDir.exec_()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
ui = Ui_MainWindow()
ui.popVenvTable()
ui.show()
sys.exit(app.exec_())
organize.py
# -*- coding: utf-8 -*-
from subprocess import Popen, PIPE
import os
#]===========================================================================[#
#] GET VENVS FROM DEFAULT DIRECTORY [#=======================================[#
#]===========================================================================[#
venvDirs, venvVers, venvPath = [], [], []
def getVenvs():
"""
Get the sub directories (venv directories) from the default directory.
"""
# get the path (str) to the default dir from file
with open("def/default", 'r') as default:
defDir = default.read()
default.close()
# get all folders inside the selected default dir
subDirs = os.listdir(defDir)
# loop over the subdirs of the selected default dir
for i, _dir in enumerate(subDirs):
# if there's a 'bin' folder within the subdir, and if it contains a
# file named 'python', then try to get the version
if ("bin" in os.listdir('/'.join([defDir, _dir]))
and "python" in os.listdir('/'.join([defDir, _dir, "bin"]))):
try:
getVers = Popen(
['/'.join([defDir, _dir, "bin", "python"]), "-V"],
stdout=PIPE, universal_newlines=True
)
venvVersion = getVers.communicate()[0].strip()
except Exception as err:
# in case there's a file named 'python' but
# isn't a python executable
print(
err.args[1]+':',
"[list index:", str(i)+']',
'/'.join([defDir, _dir, "bin"])
)
continue
venvDirs.append(_dir)
venvVers.append(venvVersion)
venvPath.append(defDir)
getVenvs()
if __name__ == "__main__":
for i in range(len(venvDirs)):
print(venvDirs[i])
print(venvVers[i])
print(venvPath[i])
settings.py
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class SetDefaultDirectory(QDialog):
"""
Set the default directory, where to look for virtual environments.
"""
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
#]===================================================================[#
#] WINDOW SETTINGS [#================================================[#
#]===================================================================[#
self.setWindowTitle("Set Default Directory")
self.setGeometry(600, 365, 500, 100)
self.setFixedSize(500, 100)
v_Layout = QVBoxLayout(self)
h_Layout = QHBoxLayout()
gridLayout = QGridLayout()
defaultDirLabel = QLabel("Default Venv Directory:")
self.defaultDirLineEdit = QLineEdit()
defaultDirLabel.setBuddy(self.defaultDirLineEdit)
folder_icon = QIcon.fromTheme("folder")
selectDirToolButton = QToolButton(
toolTip="Browse",
clicked=self.selectDirTButton_clicked
)
selectDirToolButton.setFixedSize(26, 27)
selectDirToolButton.setIcon(folder_icon)
horizontalLine = QFrame()
horizontalLine.setFrameShape(QFrame.HLine)
horizontalLine.setFrameShadow(QFrame.Sunken)
cancelButton = QPushButton(
"Cancel", clicked=self.close
)
okButton = QPushButton(
"OK", clicked=self.okButton_clicked
)
spacerItem = QSpacerItem(
40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum
)
gridLayout.addWidget(defaultDirLabel, 0, 0, 1, 1)
gridLayout.addWidget(self.defaultDirLineEdit, 0, 1, 1, 1)
gridLayout.addWidget(selectDirToolButton, 0, 2, 1, 1)
h_Layout.addItem(spacerItem)
h_Layout.addWidget(okButton, 0, Qt.AlignBottom)
h_Layout.addWidget(cancelButton, 0, Qt.AlignBottom)
v_Layout.addLayout(gridLayout)
v_Layout.addWidget(horizontalLine)
v_Layout.addLayout(h_Layout)
def selectDirTButton_clicked(self):
"""
Select directory which should be set as default.
"""
fileDiag = QFileDialog()
directory = fileDiag.getExistingDirectory()
self.defaultDirLineEdit.setText(directory)
def okButton_clicked(self):
"""
Store the absolute path (as str) to the selected dir in 'def/default'.
"""
with open("def/default", 'w') as default:
default.write(self.defaultDirLineEdit.text())
default.close()
self.close()
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
settingsUI = SetDefaultDirectory()
settingsUI.show()
sys.exit(app.exec_())
Your code has the following errors or problems:
The function that the venvs look for should not fill a list but return a list, so you can call it whenever you need it
Your method that returns the vens has errors like for example it does not verify if "bin" exists or not, also do not build the routes joining with "/", instead it uses os.path.join().
Do not use relative paths but build absolute paths.
Create a data structure that stores the information of the venvs
Considering the above, the solution is:
main_ui.py
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
import organize
import settings
class Ui_MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setupUi()
def setupUi(self):
self.selectDefaultDir = settings.SetDefaultDirectory()
self.setWindowTitle("MainWindow")
self.setGeometry(430, 335, 750, 330)
centralwidget = QtWidgets.QWidget(self)
self.v_Layout_1 = QtWidgets.QVBoxLayout()
self.v_Layout_2 = QtWidgets.QVBoxLayout(centralwidget)
selectButton = QtWidgets.QPushButton(
"Set default dir", clicked=self.selectButton_clicked
)
# venv table
venvTable = QtWidgets.QTableView(
centralwidget,
selectionBehavior=QtWidgets.QAbstractItemView.SelectRows,
editTriggers=QtWidgets.QAbstractItemView.NoEditTriggers,
alternatingRowColors=True,
)
# adjust vertical headers
v_HeaderTV2 = venvTable.verticalHeader()
v_HeaderTV2.hide()
v_HeaderTV2.setDefaultSectionSize(27.5)
# adjust (horizontal) headers
h_HeaderTV2 = venvTable.horizontalHeader()
h_HeaderTV2.setDefaultAlignment(QtCore.Qt.AlignLeft)
h_HeaderTV2.setDefaultSectionSize(180)
h_HeaderTV2.setStretchLastSection(True)
# set table view model
self.modelTV2 = QtGui.QStandardItemModel(0, 3, centralwidget)
self.modelTV2.setHorizontalHeaderLabels(["Venv Name", "Version", "Path"])
venvTable.setModel(self.modelTV2)
self.v_Layout_1.addWidget(venvTable)
self.v_Layout_1.addWidget(selectButton)
self.v_Layout_2.addLayout(self.v_Layout_1)
self.setCentralWidget(centralwidget)
def popVenvTable(self):
"""
Populate the venv table view.
"""
self.modelTV2.setRowCount(0)
for info in organize.get_venvs_default():
self.modelTV2.insertRow(0)
for i, text in enumerate((info.name, info.version, info.directory)):
self.modelTV2.setItem(0, i, QtGui.QStandardItem(text))
print(info)
def selectButton_clicked(self):
if self.selectDefaultDir.exec_() == QtWidgets.QDialog.Accepted:
self.popVenvTable()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = Ui_MainWindow()
ui.popVenvTable()
ui.show()
sys.exit(app.exec_())
organize.py
# -*- coding: utf-8 -*-
import os
from subprocess import Popen, PIPE
from dataclasses import dataclass
#dataclass
class VenvInfo:
name: str
directory: str
version: str
def get_venvs(path):
if not os.path.isdir(path):
return []
infos = []
for i, _dir in enumerate(os.listdir(path)):
bin_folder = os.path.join(path, _dir, "bin")
if not os.path.isdir(bin_folder):
continue
python_binary = os.path.join(bin_folder, "python")
if not os.path.isfile(python_binary):
continue
try:
res = Popen([python_binary, "-V"], stdout=PIPE, universal_newlines=True)
out, _ = res.communicate()
version = out.strip()
info = VenvInfo(_dir, path, version)
infos.append(info)
except Exception as err:
print(f"{err.args[1]} : [list index: {i} ] {python_binary}")
return infos
def get_venvs_default():
current_dir = os.path.dirname(os.path.realpath(__file__))
default_file = os.path.join(current_dir, "def", "default")
if os.path.isfile(default_file):
with open(default_file, "r") as f:
default_dir = f.read()
return get_venvs(default_dir)
return []
if __name__ == "__main__":
for venv in get_venvs_default():
print(venv.name, venv.version, venv.directory)
settings.py
# -*- coding: utf-8 -*-
import os
from PyQt5 import QtCore, QtGui, QtWidgets
class SetDefaultDirectory(QtWidgets.QDialog):
"""
Set the default directory, where to look for virtual environments.
"""
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# ]===================================================================[#
# ] WINDOW SETTINGS [#================================================[#
# ]===================================================================[#
self.setWindowTitle("Set Default Directory")
self.move(600, 365)
self.setFixedSize(500, 100)
v_Layout = QtWidgets.QVBoxLayout(self)
h_Layout = QtWidgets.QHBoxLayout()
gridLayout = QtWidgets.QGridLayout()
defaultDirLabel = QtWidgets.QLabel("Default Venv Directory:")
self.defaultDirLineEdit = QtWidgets.QLineEdit()
defaultDirLabel.setBuddy(self.defaultDirLineEdit)
folder_icon = QtGui.QIcon.fromTheme("folder")
selectDirToolButton = QtWidgets.QToolButton(
toolTip="Browse", clicked=self.selectDirTButton_clicked, icon=folder_icon
)
selectDirToolButton.setFixedSize(26, 27)
horizontalLine = QtWidgets.QFrame(
frameShape=QtWidgets.QFrame.HLine, frameShadow=QtWidgets.QFrame.Sunken
)
cancelButton = QtWidgets.QPushButton("Cancel", clicked=self.reject)
okButton = QtWidgets.QPushButton("OK", clicked=self.okButton_clicked)
gridLayout.addWidget(defaultDirLabel, 0, 0, 1, 1)
gridLayout.addWidget(self.defaultDirLineEdit, 0, 1, 1, 1)
gridLayout.addWidget(selectDirToolButton, 0, 2, 1, 1)
h_Layout.addStretch()
h_Layout.addWidget(okButton, 0, QtCore.Qt.AlignBottom)
h_Layout.addWidget(cancelButton, 0, QtCore.Qt.AlignBottom)
v_Layout.addLayout(gridLayout)
v_Layout.addWidget(horizontalLine)
v_Layout.addLayout(h_Layout)
def selectDirTButton_clicked(self):
"""
Select directory which should be set as default.
"""
directory = QtWidgets.QFileDialog.getExistingDirectory()
self.defaultDirLineEdit.setText(directory)
def okButton_clicked(self):
"""
Store the absolute path (as str) to the selected dir in 'def/default'.
"""
current_dir = os.path.dirname(os.path.realpath(__file__))
default_file = os.path.join(current_dir, "def", "default")
with open(default_file, "w") as default:
default.write(self.defaultDirLineEdit.text())
self.accept()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
settingsUI = SetDefaultDirectory()
settingsUI.show()
sys.exit(app.exec_())
I'm pretty new with Qt in Python, and I need to know how could I get from a file dialog one directory path and show it in a text box inside my ui.
class ControllerLibraryUI(QtWidgets.QDialog):
def __init__(self):
super(ControllerLibraryUI, self).__init__()
self.setWindowTitle('Controller Window')
self.buildUI()
def buildUI(self):
layout = QtWidgets.QVBoxLayout(self)
textWidget = QtWidgets.QWidget()
textLayout = QtWidgets.QHBoxLayout(textWidget)
layout.addWidget(textWidget)
self.saveNameField = QtWidgets.QTextEdit()
textLayout.addWidget(self.saveNameField)
btnWidget = QtWidgets.QWidget()
btnLayout = QtWidgets.QHBoxLayout(btnWidget)
layout.addWidget(btnWidget)
importBtn = QtWidgets.QPushButton('Import')
importBtn.clicked.connect(self.load)
btnLayout.addWidget(importBtn)
closeBtn = QtWidgets.QPushButton('Close')
closeBtn.clicked.connect(self.close)
btnLayout.addWidget(closeBtn)
def load(self ):
filename = QtWidgets.QFileDialog.getOpenFileName()[0]
print filename
def showUI():
try:
ui.close()
except:
ui = ControllerLibraryUI()
ui.show()
return ui
ui = showUI()
This is the basic concept.
for the file dialog :
directory = QtGui.QFileDialog.getExistingDirectory(self, 'Select directory')
and then you assign the directory variable to the setText method from your text box