使用来自 PyQt5 循环的项目刷新 QTableView 的内容
Refresh content of QTableView with items comming from loop in PyQt5
我正在开发一个用于管理虚拟环境的小型 GUI。在主要 window 中,我想在 table 视图中显示默认目录中的现有虚拟环境。这到目前为止有效。
现在我注意到,如果我选择不同的默认目录,我必须关闭 GUI 并再次打开它才能看到内容。不幸的是,我在我的计划中没有考虑到这一点(我在Python方面还是有点缺乏经验)。
我想添加一个按钮,您可以使用该按钮更新 table 视图的内容。同时,settings.py中已有的按钮okButton
(确认选择标准目录的输入)也应该更新table视图.
我尝试使用 pyqtsignal()
和 pyqtslot()
,但我不明白如何将其应用到我的代码中。 table 视图的数据(例如:版本、路径...)来自位于 organize.py 中的循环。项目收集在列表中,然后显示在 table.
中
如何通过单击按钮刷新视图?我必须修改我的代码结构吗?
以下是代码的最少可重现部分:
如果有需要也可以看看repository here。没有商业背景。
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_())
您的代码存在以下错误或问题:
venvs找的函数不应该填一个list,而是return一个list,需要的时候可以调用
你的方法returns the vens有错误,例如它不验证"bin"是否存在,也不要构建与“/”连接的路由",而是使用 os.path.join().
不要使用相对路径,而是构建绝对路径。
创建一个存储venvs信息的数据结构
综合以上,解决方案是:
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_())
我正在开发一个用于管理虚拟环境的小型 GUI。在主要 window 中,我想在 table 视图中显示默认目录中的现有虚拟环境。这到目前为止有效。
现在我注意到,如果我选择不同的默认目录,我必须关闭 GUI 并再次打开它才能看到内容。不幸的是,我在我的计划中没有考虑到这一点(我在Python方面还是有点缺乏经验)。
我想添加一个按钮,您可以使用该按钮更新 table 视图的内容。同时,settings.py中已有的按钮okButton
(确认选择标准目录的输入)也应该更新table视图.
我尝试使用 pyqtsignal()
和 pyqtslot()
,但我不明白如何将其应用到我的代码中。 table 视图的数据(例如:版本、路径...)来自位于 organize.py 中的循环。项目收集在列表中,然后显示在 table.
如何通过单击按钮刷新视图?我必须修改我的代码结构吗?
以下是代码的最少可重现部分:
如果有需要也可以看看repository here。没有商业背景。
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_())
您的代码存在以下错误或问题:
venvs找的函数不应该填一个list,而是return一个list,需要的时候可以调用
你的方法returns the vens有错误,例如它不验证"bin"是否存在,也不要构建与“/”连接的路由",而是使用 os.path.join().
不要使用相对路径,而是构建绝对路径。
创建一个存储venvs信息的数据结构
综合以上,解决方案是:
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_())