Change color in qtablewidget (click on) - python

Help implement the code so that when you click on a cell in the table, the widget cell changes its color, and when you click it again, it turns white again
I'm trying to implement the filemanager.
Code:
def onClicked(self, cell):
if not self.highlight_mode:
print(cell)
if cell.text() == '..':
self.path = str(Path(self.path).parent)
print(self.path)
else:
if not os.path.isfile(self.path + "\\" + str(cell.text())):
self.path = self.path + "\\" + str(cell.text())
print(self.path)
try:
os.chdir(self.path)
self.list_dir = os.listdir(self.path)
self.list_dir.insert(0, '..')
except:
buttonReply = QMessageBox.question(self, 'ERROR', "ERROR",
QMessageBox.Ok, QMessageBox.Ok)
self.update_table()
else:
if cell.text() != '..':
self.list_with_select.append(self.path + '\\' + str(cell.text()))
print(self.list_with_select)
def update_table(self):
self.tableWidget.clear()
self.tableWidget.setRowCount(len(self.list_dir))
self.tableWidget.setColumnCount(1)
count = 0
for nel in self.list_dir:
self.tableWidget.setItem(0, count, QTableWidgetItem(nel))
count += 1
def cut(self):
for i in self.list_with_select:
shutil.move(i, self.path + '\\')
self.list_with_select.clear()
def highlight_m(self):
print('recup')
if not(self.highlight_mode):
self.highlight_mode = True
else:
self.highlight_mode = False
print(self.highlight_mode)

You must toggle the QBrush associated with the Qt::BackgroundRole function of each element. You can use itemClicked but this may fail because not all items in QTableWidget have an associated QTableWidgetItem, so it is better to use the clicked signal returned by the associated QModelIndex
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.tableWidget = QtWidgets.QTableWidget()
self.setCentralWidget(self.tableWidget)
self.tableWidget.clicked.connect(self.on_clicked)
self.tableWidget.setRowCount(10)
self.tableWidget.setColumnCount(4)
#QtCore.pyqtSlot(QtCore.QModelIndex)
def on_clicked(self, ix):
alternative_color = QtGui.QColor("salmon")
current_brush = ix.data(QtCore.Qt.BackgroundRole)
new_brush = (
QtGui.QBrush(alternative_color)
if current_brush in (None, QtGui.QBrush())
else QtGui.QBrush()
)
self.tableWidget.model().setData(ix, new_brush, QtCore.Qt.BackgroundRole)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Related

In PyQt5's QListWidget, how can I only show the tooltip for an item when the user chooses it?

I was inspired by this repo to add custom tooltip text to items when they are added to the QListWidget. However, I only want the tooltip message to appear when the item is chosen. How would I implement this?
Here is a GUI example that I have to test this feature:
import serial, time, sys
import serial.tools.list_ports
from PyQt5 import QtGui, QtWidgets, QtCore
import json, time
class GUI(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.__init_ui()
def closeEvent(self, event):
super().closeEvent(event)
def __init_ui(self):
self.setWindowTitle('QListWidgetToolTipDemo')
self.history_log = HistoryList()
self.history_log.itemDoubleClicked.connect(self.history_item_selected)
self.history_log.returnPressed.connect(self.history_item_selected)
self.history_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.line_edit = QtWidgets.QLineEdit()
self.line_edit.returnPressed.connect(self.populate_history)
self.middle_layout = QtWidgets.QHBoxLayout()
self.middle_layout.addWidget(self.history_log)
self.middle_layout.addWidget(self.line_edit)
middle_layout_wrapper = QtWidgets.QWidget()
middle_layout_wrapper.setLayout(self.middle_layout)
middle_layout_wrapper.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# Sets full GUI layout
gui_layout = QtWidgets.QVBoxLayout()
gui_layout.addWidget(middle_layout_wrapper)
gui_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
gui_layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
self.setLayout(gui_layout)
def populate_history(self):
self.history_log.addItem(self.line_edit.text())
self.line_edit.clear()
def history_item_selected(self):
self.line_edit.setText(self.history_log.currentItem().text())
class HistoryList(QtWidgets.QListWidget):
returnPressed = QtCore.pyqtSignal()
def __init__(self) -> None:
super().__init__()
self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.setMouseTracking(True)
self.itemEntered.connect(self.__showToolTip)
def keyPressEvent(self, ev):
super().keyPressEvent(ev)
if ev.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.returnPressed.emit()
def addItem(self, aitem) -> None:
item = ''
text = ''
if isinstance(aitem, str):
item = QtWidgets.QListWidgetItem()
text = aitem
item.setText(text)
elif isinstance(aitem, QtWidgets.QListWidgetItem):
item = aitem
text = item.text()
self.setItemWidget(item, QtWidgets.QWidget())
super().addItem(item)
def __showToolTip(self, item: QtWidgets.QListWidgetItem):
text = item.text()
text_width = self.fontMetrics().boundingRect(text).width()
width = self.width()
info = {"time":str(time.time()), "entry":text}
info = json.dumps(info, indent=4)
item.setToolTip(info)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
console = GUI()
screensize = app.desktop().availableGeometry().size()
console.show()
exit(app.exec_())
Currently, the following is how a tooltip works for any item:
Example where only display tooltip when item is selected:
Expanding on the suggestion from musicamante in the comments, I was able to get tooltip to display only for the selected item by overriding the event method and watch for a tooltip event (inspired from this SO post)
import serial, time, sys
import serial.tools.list_ports
from PyQt5 import QtGui, QtWidgets, QtCore
import json, time
class GUI(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.__init_ui()
def closeEvent(self, event):
super().closeEvent(event)
def __init_ui(self):
self.setWindowTitle('QListWidgetToolTipDemo')
self.history_log = HistoryList()
self.history_log.itemDoubleClicked.connect(self.history_item_selected)
self.history_log.returnPressed.connect(self.history_item_selected)
self.history_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.line_edit = QtWidgets.QLineEdit()
self.line_edit.returnPressed.connect(self.populate_history)
self.middle_layout = QtWidgets.QHBoxLayout()
self.middle_layout.addWidget(self.history_log)
self.middle_layout.addWidget(self.line_edit)
middle_layout_wrapper = QtWidgets.QWidget()
middle_layout_wrapper.setLayout(self.middle_layout)
middle_layout_wrapper.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# Sets full GUI layout
gui_layout = QtWidgets.QVBoxLayout()
gui_layout.addWidget(middle_layout_wrapper)
gui_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
gui_layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
self.setLayout(gui_layout)
def populate_history(self):
self.history_log.addItem(self.line_edit.text())
self.line_edit.clear()
def history_item_selected(self):
self.line_edit.setText(self.history_log.currentItem().text())
class HistoryList(QtWidgets.QListWidget):
returnPressed = QtCore.pyqtSignal()
def __init__(self) -> None:
super().__init__()
self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.setMouseTracking(True)
self.itemEntered.connect(self.__addToolTip)
self.items_tooltip_info_dict = dict()
def keyPressEvent(self, ev):
super().keyPressEvent(ev)
if ev.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.returnPressed.emit()
def event(self, e: QtCore.QEvent) -> bool:
if e.type() == QtCore.QEvent.ToolTip:
if not self.selectedItems():
QtWidgets.QToolTip.hideText()
return True
else:
index = self.indexFromItem(self.currentItem()).row()
info = json.dumps(self.items_tooltip_info_dict[index], indent=4)
QtWidgets.QToolTip.showText(e.globalPos(),info)
e.accept()
return super().event(e)
def addItem(self, aitem) -> None:
item = ''
text = ''
if isinstance(aitem, str):
item = QtWidgets.QListWidgetItem()
text = aitem
item.setText(text)
elif isinstance(aitem, QtWidgets.QListWidgetItem):
item = aitem
text = item.text()
self.setItemWidget(item, QtWidgets.QWidget())
super().addItem(item)
def __addToolTip(self, item: QtWidgets.QListWidgetItem):
text = item.text()
info = {"time":str(time.time()), "entry":text}
index = self.indexFromItem(item).row()
self.items_tooltip_info_dict[index] = info
if __name__ == "__main__":
app = QtWidgets.QApplication([])
console = GUI()
screensize = app.desktop().availableGeometry().size()
console.show()
exit(app.exec_())

Making QCompleter complete every word [duplicate]

I want to have the possibility to use multiple times the auto completer in my QLineEdit, I found example using QTextEdit but I can't find for QLineEdit. here is a piece of code I use (very simple one) :
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
def main():
app = QApplication(sys.argv)
edit = QLineEdit()
strList = ["Germany", "Spain", "France", "Norway"]
completer = QCompleter(strList,edit)
edit.setCompleter(completer)
edit.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
For example, I want the completer to "start predicting" again the words in the same QLineEdit if I add a comma.
Thanks.
I've found the answer if it can help others, I created a class for Completer :
class Completer(QtWidgets.QCompleter):
def __init__(self, parent=None):
super(Completer, self).__init__(parent)
self.setCaseSensitivity(Qt.CaseInsensitive)
self.setCompletionMode(QtWidgets.QCompleter.PopupCompletion)
self.setWrapAround(False)
# Add texts instead of replace
def pathFromIndex(self, index):
path = QtWidgets.QCompleter.pathFromIndex(self, index)
lst = str(self.widget().text()).split(',')
if len(lst) > 1:
path = '%s, %s' % (','.join(lst[:-1]), path)
return path
# Add operator to separate between texts
def splitPath(self, path):
path = str(path.split(',')[-1]).lstrip(' ')
return [path]
And I use it within a class for QLineEdit like :
class TextEdit(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super(TextEdit, self).__init__(parent)
self.setPlaceholderText("example : ")
self._completer = Completer(self)
self.setCompleter(self._completer)
Solution for PyQt4:
from PyQt4 import QtCore, QtGui
class Completer(QtGui.QCompleter):
def __init__(self, *args, **kwargs):
super(Completer, self).__init__(*args, **kwargs)
self.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.setCompletionMode(QtGui.QCompleter.PopupCompletion)
self.setWrapAround(False)
# Add texts instead of replace
def pathFromIndex(self, index):
path = QtGui.QCompleter.pathFromIndex(self, index)
lst = str(self.widget().text()).split(',')
if len(lst) > 1:
path = '%s, %s' % (','.join(lst[:-1]), path)
return path
def splitPath(self, path):
path = str(path.split(',')[-1]).lstrip(' ')
return [path]
class TextEdit(QtGui.QLineEdit):
def __init__(self, parent=None):
super(TextEdit, self).__init__(parent)
words = ["alpha", "omega", "omicron", "zeta"]
self.setPlaceholderText("example : ")
self._completer = Completer(words, self)
self.setCompleter(self._completer)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = TextEdit()
w.show()
sys.exit(app.exec_())
Here is what I found might be helpful to someone:
class LineEdit(QLineEdit):
def __init__(self, *args, **kwargs):
super(LineEdit,self).__init__( *args, **kwargs)
self.multipleCompleter = None
def keyPressEvent(self, event):
QLineEdit.keyPressEvent(self, event)
if not self.multipleCompleter:
return
c = self.multipleCompleter
if self.text() == "":
return
c.setCompletionPrefix(self.cursorWord(self.text()))
if len(c.completionPrefix()) < 1:
c.popup().hide()
return
c.complete()
def cursorWord(self, sentence):
p = sentence.rfind(" ")
if p == -1:
return sentence
return sentence[p + 1:]
def insertCompletion(self, text):
p = self.text().rfind(" ")
if p == -1:
self.setText(text)
else:
self.setText(self.text()[:p+1]+ text)
def setMultipleCompleter(self, completer):
self.multipleCompleter = completer
self.multipleCompleter.setWidget(self)
completer.activated.connect(self.insertCompletion)
def main():
app = QApplication(sys.argv)
w = LineEdit()
completer = QCompleter(["Animals", "Dogs", "Birds", "Cats", "Elephant", "Zebra"])
completer.setCaseSensitivity(Qt.CaseInsensitive)
w.setMultipleCompleter(completer)
w.show()
sys.exit(app.exec_())

QListWidget, rename items with user input

I have contextmenu to a listWidget with delete and rename item. For delete, I used RemoveRow. But, I can't rename with user-input. How can I replace this line item.setText('new_name') by an action allow my change name by user
import sys
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItems('apple orange lemon'.split())
self.listWidget.installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.listWidget)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.ContextMenu and
source is self.listWidget):
menu = QtWidgets.QMenu()
Delete = menu.addAction('Delete')
Rename = menu.addAction('Rename')
#action = menu.exec_(event.globalPos())
action = menu.exec_(self.mapToGlobal(event.pos())) #when inside self
if action == Delete:
item = source.itemAt(event.pos())
source.model().removeRow(source.currentRow())
elif action == Rename:
item = source.itemAt(event.pos())
#
item.setText('new')
"How can I rename by user input, not by setText??"
return True
return super(Dialog, self).eventFilter(source, event)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Dialog()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
You can use QInputDialog.getText() to ask for new text and use it with setText().
elif action == Rename:
text, okPressed = QtWidgets.QInputDialog.getText(self, "New name","New name:")
if okPressed and text != '':
item = source.itemAt(event.pos())
item.setText(text)
You can even copy text from list to QInputDialog so user can edit it.
elif action == Rename:
item = source.itemAt(event.pos())
text, okPressed = QtWidgets.QInputDialog.getText(self, "New name","New name:", text=item.text())
if okPressed and text != '':
item.setText(text)
Full working code
import sys
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItems('apple orange lemon'.split())
self.listWidget.installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.listWidget)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.ContextMenu and
source is self.listWidget):
menu = QtWidgets.QMenu()
Delete = menu.addAction('Delete')
Rename = menu.addAction('Rename')
#action = menu.exec_(event.globalPos())
action = menu.exec_(self.mapToGlobal(event.pos())) #when inside self
if action == Delete:
item = source.itemAt(event.pos())
source.model().removeRow(source.currentRow())
elif action == Rename:
item = source.itemAt(event.pos())
text, okPressed = QtWidgets.QInputDialog.getText(self, "New name","New name:", text=item.text())
if okPressed and text != '':
item.setText(text)
return True
return super(Dialog, self).eventFilter(source, event)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Dialog()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())

Using qHelpEngine

I want to make a help file using QtHelp and QHelpEngine. I currently have some code but I am not sure about my errors and the documentation is a little vague in my opinion. Nonetheless the current issue I am facing is one of connecting signal and slots. The error I currently get is AttributeError: 'builtin_function_or_method' object has no attribute 'linkActivated' Not sure the reason for this as the documentation states that contentWidget does have a signal called linkActivated. And an error occurs here textViewer = QtWidgets.QTextBrowser(helpEngine)
Reference
from PyQt5 import QtCore, QtGui, QtWidgets, QtHelp
import os
class Ui_HelpSetupClass(QtWidgets.QDockWidget):
def __init__(self):
super().__init__()
self.setupUi(self)
def setupUi(self, HelpSetupClass):
qUrl = "qthelp://ut.tool.help/tool/index.html"
HELP_DIR = os.getcwd()
HELP_PATH = HELP_DIR + "\\" + "Help" + "\\" + "help_file.qhc"
helpEngine = QtHelp.QHelpEngine(HELP_PATH)
helpEngine.setupData()
tableWidget = QtWidgets.QTabWidget()
tableWidget.setMaximumWidth(200)
tableWidget.addTab(helpEngine.contentWidget(), "Contents")
tableWidget.addTab(helpEngine.indexWidget(), "Index")
textViewer = QtWidgets.QTextBrowser(helpEngine)
textViewer.setSource(qUrl)
helpEngine.contentWidget.linkActivated(qUrl ).connect(textViewer.setSource(qUrl))
helpEngine.indexWidget.documentActivated(qUrl ).connect(textViewer.setSource(qUrl))
horizSplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
horizSplitter.insertWidget(0, tableWidget)
horizSplitter.insertWidget(1, textViewer)
horizSplitter.hide()
helpWindow = QtWidgets.QDockWidget("Help", self)
helpWindow.setWidget(horizSplitter)
helpWindow.hide()
QtWidgets.QMainWindow.addDockWidget(QtCore.Qt.BottomDockWidgetArea, helpWindow)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ui = Ui_HelpSetupClass()
ui.show()
sys.exit(app.exec_())
In your translation of the C++ code to Python it shows many errors so I will avoid pointing it out and I will only show the correct translation:
import os
from PyQt5 import QtCore, QtGui, QtWidgets, QtHelp
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class HelpBrowser(QtWidgets.QTextBrowser):
def __init__(self, helpEngine, parent=None):
super().__init__(parent)
self.helpEngine = helpEngine
def loadResource(self, _type, name):
if name.scheme() == "qthelp":
return self.helpEngine.fileData(name)
else:
return super().loadResource(_type, name)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.scene = QtWidgets.QGraphicsScene()
self.scene.setSceneRect(0, 0, 400, 200)
self.view = QtWidgets.QGraphicsView(self.scene)
self.view.setDragMode(QtWidgets.QGraphicsView.RubberBandDrag)
self.view.setRenderHints(QtGui.QPainter.Antialiasing)
self.setCentralWidget(self.view)
self.createHelpWindow()
self.createActions()
self.createMenus()
self.createConnections()
self.setWindowTitle(self.tr("QGraphicsScene Help Example"))
self.resize(640, 480)
def createHelpWindow(self):
self.helpEngine = QtHelp.QHelpEngine(
os.path.join(CURRENT_DIR, "documentation", "qgraphicshelpexample.qhc")
)
self.helpEngine.setupData()
tWidget = QtWidgets.QTabWidget()
tWidget.setMaximumWidth(200)
tWidget.addTab(self.helpEngine.contentWidget(), "Contents")
tWidget.addTab(self.helpEngine.indexWidget(), "Index")
textViewer = HelpBrowser(self.helpEngine)
textViewer.setSource(
QtCore.QUrl("qthelp://walletfox.qt.helpexample/doc/index.html")
)
self.helpEngine.setUsesFilterEngine(True)
self.helpEngine.contentWidget().linkActivated.connect(textViewer.setSource)
self.helpEngine.indexWidget().linkActivated.connect(textViewer.setSource)
horizSplitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal)
horizSplitter.insertWidget(0, tWidget)
horizSplitter.insertWidget(1, textViewer)
horizSplitter.hide()
self.helpWindow = QtWidgets.QDockWidget(self.tr("Help"), self)
self.helpWindow.setWidget(horizSplitter)
self.helpWindow.hide()
self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.helpWindow)
def createActions(self):
self.insertEllipseAction = QtWidgets.QAction(self.tr("Insert &Ellipse"), self)
self.insertEllipseAction.setIcon(QtGui.QIcon(":/icons/ellipse.png"))
self.insertRectangleAction = QtWidgets.QAction(
self.tr("Insert &Rectangle"), self
)
self.insertRectangleAction.setIcon(QtGui.QIcon(":/icons/rectangle.png"))
self.helpAction = QtWidgets.QAction(self.tr("Help Contents..."), self)
self.helpAction.setShortcut(QtGui.QKeySequence.HelpContents)
self.aboutAction = QtWidgets.QAction(self.tr("&About"), self)
def createMenus(self):
self.itemMenu = QtWidgets.QMenu(self.tr("&Item"), self)
self.itemMenu.addAction(self.insertEllipseAction)
self.itemMenu.addAction(self.insertRectangleAction)
self.helpMenu = QtWidgets.QMenu(self.tr("&Help"), self)
self.helpMenu.addAction(self.helpAction)
self.helpMenu.addAction(self.aboutAction)
self.menuBar().addMenu(self.itemMenu)
self.menuBar().addMenu(self.helpMenu)
def insertItem(self):
action = self.sender()
if isinstance(action, QtWidgets.QAction):
itemToAdd = None
mPen = QtGui.QPen(QtCore.Qt.black, 3, QtCore.Qt.SolidLine)
eBrush = QtGui.QBrush(QtGui.QColor("#FF7F50"))
rBrush = QtGui.QBrush(QtGui.QColor("#CC0000"))
if action.iconText() == "Insert Ellipse":
itemToAdd = self.scene.addEllipse(0, 0, 150, 75, mPen, eBrush)
elif action.iconText() == "Insert Rectangle":
itemToAdd = self.scene.addRect(0, 0, 100, 100, mPen, rBrush)
if itemToAdd is not None:
itemToAdd.setFlags(
QtWidgets.QGraphicsItem.ItemIsSelectable
| QtWidgets.QGraphicsItem.ItemIsMovable
)
def about(self):
QtWidgets.QMessageBox.about(
self,
self.tr("About QGraphicsScene Help Example"),
self.tr(
"This example demonstrates how to implement\n"
"help for a Qt application."
),
)
def createConnections(self):
self.insertEllipseAction.triggered.connect(self.insertItem)
self.insertRectangleAction.triggered.connect(self.insertItem)
self.helpAction.triggered.connect(self.helpWindow.show)
self.aboutAction.triggered.connect(self.about)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_A:
for item in self.scene.selectedItems():
self.scene.removeItem(item)
else:
super().keyPressEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Note: Using the original file "qgraphicshelpexample.qhp" causes me errors since the "./foo" paths like "./insertobject.html" are not resolved correctly so I change them to "foo".
The complete example can be found here.

How to display parent directory in tree view?

In my application I have a QTreeview. I have a folder named "test" that contains many subfolders. The treeview only shows the subfolders not the test forlder it self!
def create_treeview(self):
self.treeView = QTreeView()
self.treeView.setMinimumSize(QSize(250, 0))
self.treeView.setMaximumSize(QSize(250, 16777215))
self.treeView.setObjectName("treeView")
self.dirModel = QFileSystemModel()
self.dirModel.setRootPath(QDir.rootPath())
self.dirModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
self.treeView.setModel(self.dirModel)
self.treeView.setRootIndex(self.dirModel.index("/home/data/test"))
self.treeView.setHeaderHidden(True)
self.treeView.clicked.connect(self.tree_click)
return self.treeView
The rootIndex of the QTreeView is hidden so it is not shown. One possible solution is to pass the parent of the path and use a QSortFilterProxyModel to hide the other directories and files.
import os
from PyQt5.QtCore import pyqtSlot, QDir, QModelIndex, QSize, QSortFilterProxyModel
from PyQt5.QtWidgets import QApplication, QFileSystemModel, QMainWindow, QTreeView
class ProxyModel(QSortFilterProxyModel):
def __init__(self, parent=None):
super().__init__(parent)
self._root_path = ""
def filterAcceptsRow(self, source_row, source_parent):
source_model = self.sourceModel()
if self._root_path and isinstance(source_model, QFileSystemModel):
root_index = source_model.index(self._root_path).parent()
if root_index == source_parent:
index = source_model.index(source_row, 0, source_parent)
return index.data(QFileSystemModel.FilePathRole) == self._root_path
return True
#property
def root_path(self):
return self._root_path
#root_path.setter
def root_path(self, p):
self._root_path = p
self.invalidateFilter()
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.create_treeview()
self.setCentralWidget(self.treeView)
def create_treeview(self):
path = "/home/data/test"
self.treeView = QTreeView()
self.treeView.setMinimumSize(QSize(250, 0))
self.treeView.setMaximumSize(QSize(250, 16777215))
self.treeView.setObjectName("treeView")
self.dirModel = QFileSystemModel()
self.dirModel.setRootPath(QDir.rootPath())
self.dirModel.setFilter(QDir.NoDotAndDotDot | QDir.AllDirs)
root_index = self.dirModel.index(path).parent()
self.proxy = ProxyModel(self.dirModel)
self.proxy.setSourceModel(self.dirModel)
self.proxy.root_path = path
self.treeView.setModel(self.proxy)
proxy_root_index = self.proxy.mapFromSource(root_index)
self.treeView.setRootIndex(proxy_root_index)
self.treeView.setHeaderHidden(True)
self.treeView.clicked.connect(self.tree_click)
#pyqtSlot(QModelIndex)
def tree_click(self, index):
ix = self.proxy.mapToSource(index)
print(
ix.data(QFileSystemModel.FilePathRole),
ix.data(QFileSystemModel.FileNameRole),
)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Categories

Resources