How to paint() with QStyledItemDelegate - python

I am using PySide2 and I cant find any documentation on how to use the paint() function in a QStyledItemDelegate subclass. I am rather new to classes but is so far understandable but having trouble with PySide2.
I would like to replace my QtWidgets.QListWidgetItem with my own ListWidgetItem and display them correctly, like this:
So on the left of the ListWidgetItem an icon a bit to the right the name of the ListWidgetItem and underneath the description.
Here is the code:
from PySide2 import QtWidgets, QtCore, QtGui
from PySide2.QtGui import *
import sys
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setWindowTitle('Test Window')
self.setStyleSheet("background-color: rgb(65, 65, 65);")
mainWidget = QtWidgets.QWidget(self)
self.setCentralWidget(mainWidget)
self.boxLayout = QtWidgets.QVBoxLayout()
mainWidget.setLayout(self.boxLayout)
# Add Widgets
self.textField = QtWidgets.QLineEdit()
self.listView = QtWidgets.QListWidget()
self.textField.textChanged.connect(self.onTextChanged)
self.boxLayout.addWidget(self.textField)
self.boxLayout.addWidget(self.listView)
self.textField.setFocus()
def onTextChanged(self, ):
titles = ['Monkey', 'Giraffe', 'Dragon', 'Bull']
descriptions = ['Almost a homo sapiens sapiens', 'I am a Giraffe!', 'Can fly and is hot on spices', 'Horny...']
if self.textField.text() == '' or self.textField.text().isspace() or self.textField.text() == ' ':
if self.listView.count() > 0:
self.listView.clear()
else:
if self.listView.count() > 0:
self.listView.clear()
for x in range(len(titles)):
if self.textField.text() in titles[x]:
item = ListWidgetItem(titles[x])
self.listView.addItem(item)
self.listView.setCurrentRow(0)
continue
class ListWidgetItem(QtWidgets.QListWidgetItem):
def __init__(self, title = '', description = '', icon = QtGui.QIcon()):
super(ListWidgetItem, self).__init__()
self.title = title
self.description = description
self.icon = icon
class ListViewStyle(QtWidgets.QStyledItemDelegate):
def __init__(self, parent, itemModel):
super(ListViewStyle, self).__init__(parent)
self.itemModel = itemModel
def sizeHint(self, option, index):
if index:
return QtCore.QSize(40, 40)
def paint(self, painter, option, index):
super(ListViewStyle, self).paint(painter, option, index)
if __name__ == '__main__':
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
#sys.exit(app.exec_())
Info: In onTextChanged() the ListWidgetItem will be added to the QListWidget but not drawn correctly, basically empty.
Does QListWidgetItem have any notable difference to QListView?

The delegate only paints and is not interested in what element provides the information since that class uses the QModelIndex and the same model to obtain the information, so in my previous solution I used a QStandardItemModel that uses QStandardItem and in your current case a QListWidget with QListWidgetItem is indifferent. My delegate expects only that the information of the title, description and icon are related to TitleRole, DescriptionRole and IconRole, respectively.
On the other hand it is not good to delete the items but it is better to hide or make them visible when necessary.
Considering the above, the solution with QListWidget is as follows:
import sys
from PySide2 import QtWidgets, QtCore, QtGui
TitleRole = QtCore.Qt.UserRole + 1000
DescriptionRole = QtCore.Qt.UserRole + 1001
IconRole = QtCore.Qt.UserRole + 1002
class ListWidgetItem(QtWidgets.QListWidgetItem):
def __init__(self, title="", description="", icon=QtGui.QIcon()):
super(ListWidgetItem, self).__init__()
self.title = title
self.description = description
self.icon = icon
#property
def title(self):
return self.data(TitleRole)
#title.setter
def title(self, title):
self.setData(TitleRole, title)
#property
def description(self):
return self.data(DescriptionRole)
#description.setter
def description(self, description):
self.setData(DescriptionRole, description)
#property
def icon(self):
return self.data(IconRole)
#icon.setter
def icon(self, icon):
self.setData(IconRole, icon)
class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
def sizeHint(self, option, index):
return QtCore.QSize(50, 50)
def paint(self, painter, option, index):
super(StyledItemDelegate, self).paint(painter, option, index)
title = index.data(TitleRole)
description = index.data(DescriptionRole)
icon = index.data(IconRole)
mode = QtGui.QIcon.Normal
if not (option.state & QtWidgets.QStyle.State_Enabled):
mode = QtGui.QIcon.Disabled
elif option.state & QtWidgets.QStyle.State_Selected:
mode = QtGui.QIcon.Selected
state = (
QtGui.QIcon.On
if option.state & QtWidgets.QStyle.State_Open
else QtGui.QIcon.Off
)
iconRect = QtCore.QRect(option.rect)
iconRect.setSize(QtCore.QSize(40, 40))
icon.paint(
painter, iconRect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, mode, state
)
titleFont = QtGui.QFont(option.font)
titleFont.setPixelSize(20)
fm = QtGui.QFontMetrics(titleFont)
titleRect = QtCore.QRect(option.rect)
titleRect.setLeft(iconRect.right())
titleRect.setHeight(fm.height())
color = (
option.palette.color(QtGui.QPalette.BrightText)
if option.state & QtWidgets.QStyle.State_Selected
else option.palette.color(QtGui.QPalette.WindowText)
)
painter.save()
painter.setFont(titleFont)
pen = painter.pen()
pen.setColor(color)
painter.setPen(pen)
painter.drawText(titleRect, title)
painter.restore()
descriptionFont = QtGui.QFont(option.font)
descriptionFont.setPixelSize(15)
fm = QtGui.QFontMetrics(descriptionFont)
descriptionRect = QtCore.QRect(option.rect)
descriptionRect.setTopLeft(titleRect.bottomLeft())
descriptionRect.setHeight(fm.height())
painter.save()
painter.setFont(descriptionFont)
pen = painter.pen()
pen.setColor(color)
painter.setPen(pen)
painter.drawText(
descriptionRect,
fm.elidedText(description, QtCore.Qt.ElideRight, descriptionRect.width()),
)
painter.restore()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setWindowTitle("Test Window")
self.setStyleSheet("background-color: rgb(65, 65, 65);")
mainWidget = QtWidgets.QWidget(self)
self.setCentralWidget(mainWidget)
self.boxLayout = QtWidgets.QVBoxLayout()
mainWidget.setLayout(self.boxLayout)
# Add Widgets
self.textField = QtWidgets.QLineEdit()
self.listView = QtWidgets.QListWidget()
self.textField.textChanged.connect(self.onTextChanged)
self.boxLayout.addWidget(self.textField)
self.boxLayout.addWidget(self.listView)
self.fill_model()
self.textField.setFocus()
self.listView.setItemDelegate(StyledItemDelegate(self))
def fill_model(self):
titles = ["Monkey", "Giraffe", "Dragon", "Bull"]
descriptions = [
"Almost a homo sapiens sapiens",
"I am a Giraffe!",
"Can fly and is hot on spices",
"Horny...",
]
for title, description in zip(titles, descriptions):
it = ListWidgetItem(title=title, description=description)
self.listView.addItem(it)
#QtCore.Slot(str)
def onTextChanged(self, text):
text = text.strip()
if text:
for i in range(self.listView.count()):
it = self.listView.item(i)
if it is not None:
it.setHidden(text.lower() not in it.title.lower())
else:
for i in range(self.listView.count()):
it = self.listView.item(i)
if it is not None:
it.setHidden(False)
if __name__ == "__main__":
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Related

QCheckBox in the QHeaderView of a Qtableview does not work properly

Adapting a code from PyQt4 to PyQt6 I was able to simulate a QCheckBox (select all) in the QHeaderView of a QTableView. However, clicks in regions outside the QCheckBox rectangle in the same column or in other columns of the table, act on the QCheckBox.
class CheckBoxHeader(QtWidgets.QHeaderView):
clicked = QtCore.pyqtSignal(bool)
def __init__(self, orientation = Qt.Orientation.Horizontal, parent = None):
super(CheckBoxHeader,self).__init__(orientation, parent)
self.setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.Stretch)
self.isChecked = False
def paintSection(self, painter, rect, logicalIndex):
painter.save()
super(CheckBoxHeader,self).paintSection(painter, rect, logicalIndex)
painter.restore()
if logicalIndex==3:
option = QtWidgets.QStyleOptionButton()
option.rect= QtCore.QRect(503,1,20,20)
option.state= QtWidgets.QStyle.StateFlag.State_Enabled | QtWidgets.QStyle.StateFlag.State_Active
if self.isChecked:
option.state|= QtWidgets.QStyle.StateFlag.State_On
else:
option.state|= QtWidgets.QStyle.StateFlag.State_Off
self.style().drawControl(QtWidgets.QStyle.ControlElement.CE_CheckBox, option, painter)
def mousePressEvent(self, event):
if self.isChecked:
self.isChecked = False
else:
self.isChecked = True
self.clicked.emit(self.isChecked)
self.viewport().update()
class Ui_teste(object):
def setupUi(self, janela):
janela.setObjectName("cadastro_clientes")
janela.resize(700, 400)
janela.setAccessibleName("")
janela.setTabShape(QtWidgets.QTabWidget.TabShape.Rounded)
data = [
("Joe", "Senior Web Developerrwyeriweyrtiwyrtiwyetrwetruwtruw", "joe#example.com"),
("Lara", "Project Manager", "lara#example.com"),
("David", "Data Analyst", "david#example.com"),
("Jane", "Senior Python Developer", "jane#example.com"),
]
self.tableWidget = QtWidgets.QTableWidget(janela)
self.tableWidget.setGeometry(5,5,600,320)
self.tableWidget.setColumnCount(4)
self.tableWidget.setHorizontalHeaderLabels(["Nome", "Profissão", "Email"," "])
self.tableWidget.setRowCount(len(data))
self.header = CheckBoxHeader(parent=self.tableWidget)
self.header.setMaximumSectionSize(10)
self.header.clicked.connect(self.on_headerClick)
self.tableWidget.setHorizontalHeader(self.header)
self.tableWidget.show()
self.tableWidget.setRowCount(0)
for index, c in enumerate(data):
rows = self.tableWidget.rowCount()
self.tableWidget.setRowCount(rows + 1)
self.tableWidget.setItem(rows, 0, QtWidgets.QTableWidgetItem(str(c[0])))
self.tableWidget.setItem(rows, 1, QtWidgets.QTableWidgetItem(str(c[1])))
self.tableWidget.setItem(rows, 2, QtWidgets.QTableWidgetItem(str(c[2])))
pWidget = QtWidgets.QWidget()
pCheckBox = QtWidgets.QCheckBox()
pCheckBox.clicked.connect(self.on_changeCheckBox)
pLayout = QtWidgets.QHBoxLayout(pWidget)
pLayout.addWidget(pCheckBox)
pLayout.setAlignment(Qt.AlignmentFlag.AlignCenter)
pLayout.setContentsMargins(0,0,0,0)
pWidget.setLayout(pLayout)
self.tableWidget.setCellWidget(rows, 3, pWidget)
def on_headerClick(self,isCheck):
qtde_rows = self.tableWidget.rowCount()
if isCheck:
for i in range(qtde_rows):
self.tableWidget.cellWidget(i, 3).layout().itemAt(0).widget().setChecked(True)
else:
for i in range(qtde_rows):
self.tableWidget.cellWidget(i, 3).layout().itemAt(0).widget().setChecked(False)
#print(isCheck)
def on_changeCheckBox(self, isCheck):
if not isCheck:
self.tableWidget.horizontalHeader().isChecked = False
self.tableWidget.horizontalHeader().viewport().update()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
testes = QtWidgets.QMainWindow()
ui = Ui_teste()
ui.setupUi(testes)
testes.show()
sys.exit(app.exec())
What I need is for only the rectangle region of the QCheckBox to be selectable. Can anybody help me?
QTableView with QHeaderView and select all QCheckBox

How to get item text to wrap using a QListView set to IconMode and model set to QFileSystemModel

I am using a QListView and a QFileSystemModel to display the contents of a directory. I'm trying to emulate the Windows File Explorer, where if the file/folder text is long enough it wraps to display the full name of the object.
As it looks in File Explorer
On my view I've tried setGridSize(QtCore.QSize(80, 80)) to give me enough space, setWordWrap(True), and setTextElideMode(QtCore.Qt.ElideNone)
But the text still gets cropped.
I've looked into using a QStyledItemDelegate in order to wrap the text, but I am unsure how to go about getting the behavior I want.
How can I set the view to show the text wrapping and not cropping any of the text?
Here's the code I've created so far...
import sys
from PySide2 import QtCore
from PySide2 import QtWidgets
from shiboken2 import wrapInstance
class TreeViewDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(TreeViewDialog, self).__init__(parent)
self.setMinimumSize(500, 400)
self.create_widgets()
self.create_layout()
def create_widgets(self):
root_path = r"C:\Users\Documents\Test"
self.model = QtWidgets.QFileSystemModel()
self.model.setRootPath(root_path)
self.list_view = QtWidgets.QListView()
self.list_view.setViewMode(QtWidgets.QListView.IconMode)
self.list_view.setResizeMode(QtWidgets.QListView.Adjust)
self.list_view.setFlow(QtWidgets.QListView.LeftToRight)
self.list_view.setMovement(QtWidgets.QListView.Snap)
self.list_view.setModel(self.model)
self.list_view.setRootIndex(self.model.index(root_path))
self.list_view.setGridSize(QtCore.QSize(80, 80))
self.list_view.setUniformItemSizes(True)
self.list_view.setWordWrap(True)
self.list_view.setTextElideMode(QtCore.Qt.ElideNone)
def create_layout(self):
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.setContentsMargins(2, 2, 2, 2)
main_layout.addWidget(self.list_view)
if __name__ == "__main__":
app = QtWidgets.QApplication.instance()
if not app:
app = QtWidgets.QApplication(sys.argv)
tree_view_dialog = TreeViewDialog()
tree_view_dialog.show()
sys.exit(app.exec_())
So I was able to get the behavior I was looking for by implementing a custom QStyledItemDelegate and implementing the paint() and sizeHint() methods and setting setItemDelegate() on my QListView.
delegate = FileNameDelegate(self)
self.list_view.setItemDelegate(delegate)
Here's my delegate class.
class FileNameDelegate(QtWidgets.QStyledItemDelegate):
"""Delegate to wrap filenames."""
def paint(self, painter, option, index):
if not index.isValid():
return
painter.save()
# Selected
if option.state & QtWidgets.QStyle.State_Selected:
painter.fillRect(option.rect, option.palette.highlight())
# Icon
icon = index.data(QtCore.Qt.DecorationRole)
mode = QtGui.QIcon.Normal
state = QtGui.QIcon.On if option.state & QtWidgets.QStyle.State_Open else QtGui.QIcon.Off
icon_rect = QtCore.QRect(option.rect)
icon_rect.setSize(QtCore.QSize(option.rect.width(), 40))
icon.paint(painter, icon_rect, alignment=QtCore.Qt.AlignCenter | QtCore.Qt.AlignVCenter, mode=mode, state=state)
# Text
text = index.data(QtCore.Qt.DisplayRole)
font = QtWidgets.QApplication.font()
font_metrics = QtGui.QFontMetrics(font)
padding = 8
rect = font_metrics.boundingRect(option.rect.left()+padding/2, option.rect.bottom()-icon_rect.height()+padding/2,
option.rect.width()-padding, option.rect.height()-padding,
QtCore.Qt.AlignHCenter | QtCore.Qt.AlignTop | QtCore.Qt.TextWrapAnywhere,
text)
color = QtWidgets.QApplication.palette().text().color()
pen = QtGui.QPen(color)
painter.setPen(pen)
painter.setFont(font)
painter.drawText(rect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop | QtCore.Qt.TextWrapAnywhere, text)
painter.restore()
def sizeHint(self, option, index):
if not index.isValid():
return super(FileNameDelegate, self).sizeHint(option, index)
else:
text = index.data()
font = QtWidgets.QApplication.font()
font_metrics = QtGui.QFontMetrics(font)
rect = font_metrics.boundingRect(0, 0, option.rect.width(), 0,
QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop | QtCore.Qt.TextWrapAnywhere,
text)
size = QtCore.QSize(option.rect.width(), option.rect.height()+rect.height())
return size
I now get this when running the code.

How to make a QTreeView display more than 10 lines

Using Python 3.7 with pyqt5 on Win10
I am working on getting a QTreeView that uses a QStandardItemModel to display more than 10 lines. I want it to show the maximum number of lines the area can actually handle but it stops short at 10 for some unknown (by me at least) reason.
I have tried numerous solutions (some I have remarked out within the code below along with their apparent results) and there are others that I am not including because they did not compile. As of yet I cannot seem to find a way to get the QTreeView to fill the available space and/or show all the lines it can it just stops at 10 lines. I am including a program that runs and shows the issue simply click "Options" then click "Option 1"
from sys import exit as sysExit
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Line(QFrame):
def __init__(self, parent):
QFrame.__init__(self)
self.setFrameShape(QFrame.HLine)
self.setFrameShadow(QFrame.Sunken)
# Users Widget *************************************************
class Disply1(QFrame):
def __init__(self, parent):
QFrame.__init__(self)
self.setFrameShape(QFrame.StyledPanel)
self.setLineWidth(0.2)
# -------
self.header = QVBoxLayout()
Title = QLabel()
Title.setStyleSheet('font: bold 14px')
Title.setText('Option 1 Configuration Settings')
self.header.addWidget(Title)
self.header.addWidget(Line(self))
# -------
self.TreeVew = QTreeView()
self.TreeVew.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.TreeVew.setAlternatingRowColors(True)
# This adjustment did not fix it
# self.TreeVew.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
# This adjustment made it worse
# self.TreeVew.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.model = QStandardItemModel(0, 6)
self.model.setHorizontalHeaderLabels([' ', 'Column1', 'Column2', 'Column3', 'Column4', 'Column5'])
self.model.setHeaderData(5, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
# This adjustment did not fix it
# self.model.setRowCount(20)
self.TreeVew.setModel(self.model)
self.TreeVew.setColumnWidth(0, 1)
self.TreeVew.setColumnHidden(0, True)
self.TreeVew.header().setSectionResizeMode(0, QHeaderView.Fixed)
self.TreeVew.header().setStretchLastSection(False)
self.TreeVew.header().setSectionResizeMode(1, QHeaderView.Stretch)
self.TreeVew.setColumnWidth(2, 100)
self.TreeVew.setColumnWidth(3, 100)
self.TreeVew.setColumnWidth(4, 100)
self.TreeVew.setColumnWidth(5, 70)
# This adjustment did not fix it
# self.TreeVew.resize(self.sizeHint().width(), self.maximumHeight())
ItmRecSet = [
{'Id':'01', 'Column1':'R01-C1', 'Column2':'R01-C2', 'Column3':'R01-C3', 'Column4':'R01-C5', 'Column5':'R01-C5'},
{'Id':'02', 'Column1':'R02-C1', 'Column2':'R02-C2', 'Column3':'R02-C3', 'Column4':'R02-C5', 'Column5':'R02-C5'},
{'Id':'03', 'Column1':'R03-C1', 'Column2':'R03-C2', 'Column3':'R03-C3', 'Column4':'R03-C5', 'Column5':'R03-C5'},
{'Id':'04', 'Column1':'R04-C1', 'Column2':'R04-C2', 'Column3':'R04-C3', 'Column4':'R04-C5', 'Column5':'R04-C5'},
{'Id':'05', 'Column1':'R05-C1', 'Column2':'R05-C2', 'Column3':'R05-C3', 'Column4':'R05-C5', 'Column5':'R05-C5'},
{'Id':'06', 'Column1':'R06-C1', 'Column2':'R06-C2', 'Column3':'R06-C3', 'Column4':'R06-C5', 'Column5':'R06-C5'},
{'Id':'07', 'Column1':'R07-C1', 'Column2':'R07-C2', 'Column3':'R07-C3', 'Column4':'R07-C5', 'Column5':'R07-C5'},
{'Id':'08', 'Column1':'R08-C1', 'Column2':'R08-C2', 'Column3':'R08-C3', 'Column4':'R08-C5', 'Column5':'R08-C5'},
{'Id':'09', 'Column1':'R09-C1', 'Column2':'R09-C2', 'Column3':'R09-C3', 'Column4':'R09-C5', 'Column5':'R09-C5'},
{'Id':'10', 'Column1':'R10-C1', 'Column2':'R10-C2', 'Column3':'R10-C3', 'Column4':'R10-C5', 'Column5':'R10-C5'},
{'Id':'11', 'Column1':'R11-C1', 'Column2':'R11-C2', 'Column3':'R11-C3', 'Column4':'R11-C5', 'Column5':'R11-C5'},
{'Id':'12', 'Column1':'R12-C1', 'Column2':'R12-C2', 'Column3':'R12-C3', 'Column4':'R12-C5', 'Column5':'R12-C5'},
{'Id':'13', 'Column1':'R13-C1', 'Column2':'R13-C2', 'Column3':'R13-C3', 'Column4':'R13-C5', 'Column5':'R13-C5'},
{'Id':'14', 'Column1':'R14-C1', 'Column2':'R14-C2', 'Column3':'R14-C3', 'Column4':'R14-C5', 'Column5':'R14-C5'},
{'Id':'15', 'Column1':'R15-C1', 'Column2':'R15-C2', 'Column3':'R15-C3', 'Column4':'R15-C5', 'Column5':'R15-C5'},
{'Id':'16', 'Column1':'R16-C1', 'Column2':'R16-C2', 'Column3':'R16-C3', 'Column4':'R16-C5', 'Column5':'R16-C5'},
{'Id':'17', 'Column1':'R17-C1', 'Column2':'R17-C2', 'Column3':'R17-C3', 'Column4':'R17-C5', 'Column5':'R17-C5'},
{'Id':'18', 'Column1':'R18-C1', 'Column2':'R18-C2', 'Column3':'R18-C3', 'Column4':'R18-C5', 'Column5':'R18-C5'},
{'Id':'19', 'Column1':'R19-C1', 'Column2':'R19-C2', 'Column3':'R19-C3', 'Column4':'R19-C5', 'Column5':'R19-C5'},
{'Id':'20', 'Column1':'R20-C1', 'Column2':'R20-C2', 'Column3':'R20-C3', 'Column4':'R20-C5', 'Column5':'R20-C5'}
]
self.model.setRowCount(0)
for Item in ItmRecSet:
Itm1 = QStandardItem(Item['Id'])
Itm1.setTextAlignment(Qt.AlignLeft)
Itm1.isEditable = False
Itm2 = QStandardItem(Item['Column1'])
Itm2.setTextAlignment(Qt.AlignLeft)
Itm2.isEditable = False
Itm3 = QStandardItem(Item['Column2'])
Itm3.setTextAlignment(Qt.AlignLeft)
Itm3.isEditable = False
Itm4 = QStandardItem(Item['Column3'])
Itm4.setTextAlignment(Qt.AlignLeft)
Itm4.isEditable = False
Itm5 = QStandardItem(Item['Column4'])
Itm5.setTextAlignment(Qt.AlignLeft)
Itm5.isEditable = False
Itm6 = QStandardItem(Item['Column5'])
Itm6.setTextAlignment(Qt.AlignCenter)
Itm6.isEditable = False
self.model.appendRow([Itm1, Itm2, Itm3, Itm4, Itm5, Itm6])
# Using this GridLayout versus the VerticalBox did not fix it
# self.Cntnr = QGridLayout()
# -------
# self.Cntnr.addLayout(self.header,0,0)
# self.Cntnr.addWidget(self.TreeVew,1,0)
# self.Cntnr.setRowStretch(2,4)
self.Cntnr = QVBoxLayout()
self.Cntnr.addLayout(self.header)
self.Cntnr.addWidget(self.TreeVew)
# If this stretch is not included only the header gets stretched the QTreeView still only shows 10 lines
self.Cntnr.addStretch(1)
# -------
self.setLayout(self.Cntnr)
# Debug Widget *************************************************
class Disply2(QFrame):
def __init__(self, parent):
QFrame.__init__(self)
self.setFrameShape(QFrame.StyledPanel)
self.setLineWidth(0.2)
# -------
self.Cntnr = QVBoxLayout()
self.Cntnr.addWidget(QTextEdit('Option 2 Settings Shown Here'))
self.Cntnr.addStretch(1)
# -------
self.setLayout(self.Cntnr)
class OptionButtons(QToolButton):
# Class OptionButtons ("Text", Icon, Connector) inherits from QToolButton
def __init__(self, Text, Icon, Connector):
QToolButton.__init__(self)
self.setText(Text)
self.setIcon(Icon)
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.setStyleSheet("font: bold;color: blue;height: 55px;width: 55px;")
self.setIconSize(QSize(32,32))
self.clicked.connect(Connector)
############################## Settings Class ##############################
class OptionSettings(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
line = QFrame()
line.setFrameShape(QFrame.HLine)
line.setFrameShadow(QFrame.Sunken)
# Button Area on Left
# Button 1 *************************************************
self.btnOptn1 = OptionButtons('Option1', QIcon('images/opt1.ico'), self.ShowDisply1)
# Button 2 *************************************************
self.btnOptn2 = OptionButtons('Option2', QIcon('images/opt2.ico'), self.ShowDisply2)
# Vertical Box for Buttons *************************************
self.UpLeft = QVBoxLayout()
self.UpLeft.addWidget(self.btnOptn1)
self.UpLeft.addWidget(self.btnOptn2)
self.UpLeft.addStretch(1)
# Display Area on Right
# Widget Flip Display ******************************************
self.UpRite = QHBoxLayout()
self.Contents = QStackedWidget()
self.Contents.addWidget(QTextEdit('Nothing Selected'))
self.Contents.addWidget(Disply1(self))
self.Contents.addWidget(Disply2(self))
self.Contents.addWidget(QTextEdit('Settings Saved'))
self.Contents.setCurrentIndex(0)
self.UpRite.addWidget(self.Contents)
# Button and Display Area on Top
self.Upper = QHBoxLayout()
self.Upper.addLayout(self.UpLeft)
self.Upper.addLayout(self.UpRite)
# Save and Cancel Area on Bottom
self.btnSave = QPushButton("Save")
self.btnSave.clicked.connect(self.SaveSettings)
self.btnCncl = QPushButton("Cancel")
self.btnCncl.clicked.connect(self.close)
self.Lower = QHBoxLayout()
self.Lower.addStretch(1)
self.Lower.addWidget(self.btnSave)
self.Lower.addWidget(self.btnCncl)
# Entire Options Window Layout
self.OuterBox = QVBoxLayout()
self.OuterBox.addLayout(self.Upper)
self.OuterBox.addLayout(self.Lower)
self.setLayout(self.OuterBox)
self.setWindowTitle('Settings')
#Geometry(Left, Top, Width, Hight)
self.setGeometry(250, 250, 550, 450)
self.setModal(True)
self.exec()
def ShowDisply1(self):
self.Contents.setCurrentIndex(1)
def ShowDisply2(self):
self.Contents.setCurrentIndex(2)
def SaveSettings(self):
self.Contents.setCurrentIndex(3)
class CustomItemModel(QStandardItemModel):
def headerData(self, section, orientation, role):
if role == Qt.ForegroundRole:
brush = QBrush()
brush.setColor(Qt.blue)
brush.setStyle(Qt.SolidPattern)
return brush
elif role == Qt.BackgroundRole:
brush = QBrush()
brush.setColor(Qt.yellow)
brush.setStyle(Qt.SolidPattern)
return brush
elif role == Qt.FontRole:
font = QFont()
font.setBold(True)
font.setPointSize(10)
return font
return super().headerData(section, orientation, role)
class ItemDsplyr(QTreeView):
def __init__(self, CentrPane):
QTreeView.__init__(self, CentrPane)
self.CntrPane = CentrPane
self.setEditTriggers(QTreeView().NoEditTriggers)
self.model = CustomItemModel(0, 3)
self.model.setHorizontalHeaderLabels(['1st Col', '2nd Col', '3rd Col'])
self.model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
self.setModel(self.model)
self.setMinimumWidth(250)
self.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.header().setStretchLastSection(False)
self.header().setSectionResizeMode(0, QHeaderView.Stretch)
self.setColumnWidth(1, 75)
self.setColumnWidth(2, 100)
class CenterPanel(QWidget):
def __init__(self, MainWin):
QWidget.__init__(self)
self.MyEditor = QTextEdit('Editorial')
self.ItemDsply = ItemDsplyr(self)
CntrPane = QSplitter(Qt.Horizontal, self)
CntrPane.addWidget(self.MyEditor)
CntrPane.addWidget(self.ItemDsply)
CntrPane.setSizes([50,200])
CntrPane.setCollapsible(0, False)
CntrPane.setCollapsible(1, False)
hbox = QHBoxLayout(self)
hbox.addWidget(CntrPane)
self.setLayout(hbox)
class MenuToolBar(QDockWidget):
def __init__(self, MainWin):
QDockWidget.__init__(self)
self.MainWin = MainWin
self.MainMenu = MainWin.menuBar()
self.WndowMenu = self.MainMenu.addMenu('Windows')
self.OptnAct = QAction('Options', self)
self.OptnAct.setStatusTip('Open the Options Window')
self.OptnAct.triggered.connect(MainWin.ShowOptions)
self.WndowMenu.addAction(self.OptnAct)
self.InitToolBar(MainWin)
def InitToolBar(self, MainWin):
self.mainToolBar = MainWin.addToolBar("Quick Access")
self.mainToolBar.addAction(self.OptnAct)
class UI_MainWindow(QMainWindow):
def __init__(self, MainDesktop):
super(UI_MainWindow, self).__init__(MainDesktop)
self.setWindowTitle('Main Window')
self.MnDskTop = MainDesktop
# Left, Top, Width, Height
self.setGeometry(200, 200, 550, 550)
self.CenterPane = CenterPanel(self)
self.setCentralWidget(self.CenterPane)
self.MenuToolBar = MenuToolBar(self)
def ShowOptions(self):
self.Options = OptionSettings(self)
if __name__ == '__main__':
MainApp = QApplication([])
MainGui = UI_MainWindow(MainApp.desktop())
MainGui.show()
sysExit(MainApp.exec_())
Again what I had expected is that the QTreeView would fill the available space and/or show as many rows as possible within the given space. However, as stated it stops short and only displays just 10 lines maximum.
I removed the line self.Cntnr.addStretch(1), that's what happened:
from sys import exit as sysExit
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Line(QFrame):
def __init__(self, parent):
QFrame.__init__(self)
self.setFrameShape(QFrame.HLine)
self.setFrameShadow(QFrame.Sunken)
# Users Widget *************************************************
class Disply1(QFrame):
def __init__(self, parent):
QFrame.__init__(self)
self.setFrameShape(QFrame.StyledPanel)
self.setLineWidth(0.2)
# -------
self.header = QVBoxLayout()
Title = QLabel()
Title.setStyleSheet('font: bold 14px')
Title.setText('Option 1 Configuration Settings')
self.header.addWidget(Title)
self.header.addWidget(Line(self))
# -------
self.TreeVew = QTreeView()
self.TreeVew.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.TreeVew.setAlternatingRowColors(True)
# This adjustment did not fix it
# self.TreeVew.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
# This adjustment made it worse
# self.TreeVew.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.model = QStandardItemModel(0, 6)
self.model.setHorizontalHeaderLabels([' ', 'Column1', 'Column2', 'Column3', 'Column4', 'Column5'])
self.model.setHeaderData(5, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
# This adjustment did not fix it
# self.model.setRowCount(20)
self.TreeVew.setModel(self.model)
self.TreeVew.setColumnWidth(0, 1)
self.TreeVew.setColumnHidden(0, True)
self.TreeVew.header().setSectionResizeMode(0, QHeaderView.Fixed)
self.TreeVew.header().setStretchLastSection(False)
self.TreeVew.header().setSectionResizeMode(1, QHeaderView.Stretch)
self.TreeVew.setColumnWidth(2, 100)
self.TreeVew.setColumnWidth(3, 100)
self.TreeVew.setColumnWidth(4, 100)
self.TreeVew.setColumnWidth(5, 70)
# This adjustment did not fix it
# self.TreeVew.resize(self.sizeHint().width(), self.maximumHeight())
## self.TreeVew.resize(400, 600)
ItmRecSet = [
{'Id':'01', 'Column1':'R01-C1', 'Column2':'R01-C2', 'Column3':'R01-C3', 'Column4':'R01-C5', 'Column5':'R01-C5'},
{'Id':'02', 'Column1':'R02-C1', 'Column2':'R02-C2', 'Column3':'R02-C3', 'Column4':'R02-C5', 'Column5':'R02-C5'},
{'Id':'03', 'Column1':'R03-C1', 'Column2':'R03-C2', 'Column3':'R03-C3', 'Column4':'R03-C5', 'Column5':'R03-C5'},
{'Id':'04', 'Column1':'R04-C1', 'Column2':'R04-C2', 'Column3':'R04-C3', 'Column4':'R04-C5', 'Column5':'R04-C5'},
{'Id':'05', 'Column1':'R05-C1', 'Column2':'R05-C2', 'Column3':'R05-C3', 'Column4':'R05-C5', 'Column5':'R05-C5'},
{'Id':'06', 'Column1':'R06-C1', 'Column2':'R06-C2', 'Column3':'R06-C3', 'Column4':'R06-C5', 'Column5':'R06-C5'},
{'Id':'07', 'Column1':'R07-C1', 'Column2':'R07-C2', 'Column3':'R07-C3', 'Column4':'R07-C5', 'Column5':'R07-C5'},
{'Id':'08', 'Column1':'R08-C1', 'Column2':'R08-C2', 'Column3':'R08-C3', 'Column4':'R08-C5', 'Column5':'R08-C5'},
{'Id':'09', 'Column1':'R09-C1', 'Column2':'R09-C2', 'Column3':'R09-C3', 'Column4':'R09-C5', 'Column5':'R09-C5'},
{'Id':'10', 'Column1':'R10-C1', 'Column2':'R10-C2', 'Column3':'R10-C3', 'Column4':'R10-C5', 'Column5':'R10-C5'},
{'Id':'11', 'Column1':'R11-C1', 'Column2':'R11-C2', 'Column3':'R11-C3', 'Column4':'R11-C5', 'Column5':'R11-C5'},
{'Id':'12', 'Column1':'R12-C1', 'Column2':'R12-C2', 'Column3':'R12-C3', 'Column4':'R12-C5', 'Column5':'R12-C5'},
{'Id':'13', 'Column1':'R13-C1', 'Column2':'R13-C2', 'Column3':'R13-C3', 'Column4':'R13-C5', 'Column5':'R13-C5'},
{'Id':'14', 'Column1':'R14-C1', 'Column2':'R14-C2', 'Column3':'R14-C3', 'Column4':'R14-C5', 'Column5':'R14-C5'},
{'Id':'15', 'Column1':'R15-C1', 'Column2':'R15-C2', 'Column3':'R15-C3', 'Column4':'R15-C5', 'Column5':'R15-C5'},
{'Id':'16', 'Column1':'R16-C1', 'Column2':'R16-C2', 'Column3':'R16-C3', 'Column4':'R16-C5', 'Column5':'R16-C5'},
{'Id':'17', 'Column1':'R17-C1', 'Column2':'R17-C2', 'Column3':'R17-C3', 'Column4':'R17-C5', 'Column5':'R17-C5'},
{'Id':'18', 'Column1':'R18-C1', 'Column2':'R18-C2', 'Column3':'R18-C3', 'Column4':'R18-C5', 'Column5':'R18-C5'},
{'Id':'19', 'Column1':'R19-C1', 'Column2':'R19-C2', 'Column3':'R19-C3', 'Column4':'R19-C5', 'Column5':'R19-C5'},
{'Id':'20', 'Column1':'R20-C1', 'Column2':'R20-C2', 'Column3':'R20-C3', 'Column4':'R20-C5', 'Column5':'R20-C5'}
]
self.model.setRowCount(0)
for Item in ItmRecSet:
Itm1 = QStandardItem(Item['Id'])
Itm1.setTextAlignment(Qt.AlignLeft)
Itm1.isEditable = False
Itm2 = QStandardItem(Item['Column1'])
Itm2.setTextAlignment(Qt.AlignLeft)
Itm2.isEditable = False
Itm3 = QStandardItem(Item['Column2'])
Itm3.setTextAlignment(Qt.AlignLeft)
Itm3.isEditable = False
Itm4 = QStandardItem(Item['Column3'])
Itm4.setTextAlignment(Qt.AlignLeft)
Itm4.isEditable = False
Itm5 = QStandardItem(Item['Column4'])
Itm5.setTextAlignment(Qt.AlignLeft)
Itm5.isEditable = False
Itm6 = QStandardItem(Item['Column5'])
Itm6.setTextAlignment(Qt.AlignCenter)
Itm6.isEditable = False
self.model.appendRow([Itm1, Itm2, Itm3, Itm4, Itm5, Itm6])
# Using this GridLayout versus the VerticalBox did not fix it
# self.Cntnr = QGridLayout()
# -------
# self.Cntnr.addLayout(self.header,0,0)
# self.Cntnr.addWidget(self.TreeVew,1,0)
# self.Cntnr.setRowStretch(2,4)
self.Cntnr = QVBoxLayout()
self.Cntnr.addLayout(self.header)
self.Cntnr.addWidget(self.TreeVew)
# If this stretch is not included only the header gets stretched the QTreeView still only shows 10 lines
#--- self.Cntnr.addStretch(1) # <<<=======
# -------
self.setLayout(self.Cntnr)
# Debug Widget *************************************************
class Disply2(QFrame):
def __init__(self, parent):
QFrame.__init__(self)
self.setFrameShape(QFrame.StyledPanel)
self.setLineWidth(0.2)
# -------
self.Cntnr = QVBoxLayout()
self.Cntnr.addWidget(QTextEdit('Option 2 Settings Shown Here'))
self.Cntnr.addStretch(1)
# -------
self.setLayout(self.Cntnr)
class OptionButtons(QToolButton):
# Class OptionButtons ("Text", Icon, Connector) inherits from QToolButton
def __init__(self, Text, Icon, Connector):
QToolButton.__init__(self)
self.setText(Text)
self.setIcon(Icon)
self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.setStyleSheet("font: bold;color: blue;height: 55px;width: 55px;")
self.setIconSize(QSize(32,32))
self.clicked.connect(Connector)
############################## Settings Class ##############################
class OptionSettings(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
line = QFrame()
line.setFrameShape(QFrame.HLine)
line.setFrameShadow(QFrame.Sunken)
# Button Area on Left
# Button 1 *************************************************
self.btnOptn1 = OptionButtons('Option1', QIcon('Ok.png'), self.ShowDisply1)
# Button 2 *************************************************
self.btnOptn2 = OptionButtons('Option2', QIcon('images/opt2.ico'), self.ShowDisply2)
# Vertical Box for Buttons *************************************
self.UpLeft = QVBoxLayout()
self.UpLeft.addWidget(self.btnOptn1)
self.UpLeft.addWidget(self.btnOptn2)
self.UpLeft.addStretch(1)
# Display Area on Right
# Widget Flip Display ******************************************
self.UpRite = QHBoxLayout()
self.Contents = QStackedWidget()
self.Contents.addWidget(QTextEdit('Nothing Selected'))
self.Contents.addWidget(Disply1(self))
self.Contents.addWidget(Disply2(self))
self.Contents.addWidget(QTextEdit('Settings Saved'))
self.Contents.setCurrentIndex(0)
self.UpRite.addWidget(self.Contents)
# Button and Display Area on Top
self.Upper = QHBoxLayout()
self.Upper.addLayout(self.UpLeft)
self.Upper.addLayout(self.UpRite)
# Save and Cancel Area on Bottom
self.btnSave = QPushButton("Save")
self.btnSave.clicked.connect(self.SaveSettings)
self.btnCncl = QPushButton("Cancel")
self.btnCncl.clicked.connect(self.close)
self.Lower = QHBoxLayout()
self.Lower.addStretch(1)
self.Lower.addWidget(self.btnSave)
self.Lower.addWidget(self.btnCncl)
# Entire Options Window Layout
self.OuterBox = QVBoxLayout()
self.OuterBox.addLayout(self.Upper)
self.OuterBox.addLayout(self.Lower)
self.setLayout(self.OuterBox)
self.setWindowTitle('Settings')
#Geometry(Left, Top, Width, Hight)
self.setGeometry(250, 250, 550, 450)
self.setModal(True)
self.exec()
def ShowDisply1(self):
self.Contents.setCurrentIndex(1)
def ShowDisply2(self):
self.Contents.setCurrentIndex(2)
def SaveSettings(self):
self.Contents.setCurrentIndex(3)
class CustomItemModel(QStandardItemModel):
def headerData(self, section, orientation, role):
if role == Qt.ForegroundRole:
brush = QBrush()
brush.setColor(Qt.blue)
brush.setStyle(Qt.SolidPattern)
return brush
elif role == Qt.BackgroundRole:
brush = QBrush()
brush.setColor(Qt.yellow)
brush.setStyle(Qt.SolidPattern)
return brush
elif role == Qt.FontRole:
font = QFont()
font.setBold(True)
font.setPointSize(10)
return font
return super().headerData(section, orientation, role)
class ItemDsplyr(QTreeView):
def __init__(self, CentrPane):
QTreeView.__init__(self, CentrPane)
self.CntrPane = CentrPane
self.setEditTriggers(QTreeView().NoEditTriggers)
self.model = CustomItemModel(0, 3)
self.model.setHorizontalHeaderLabels(['1st Col', '2nd Col', '3rd Col'])
self.model.setHeaderData(1, Qt.Horizontal, Qt.AlignCenter, Qt.TextAlignmentRole)
self.setModel(self.model)
self.setMinimumWidth(250)
self.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.header().setStretchLastSection(False)
self.header().setSectionResizeMode(0, QHeaderView.Stretch)
self.setColumnWidth(1, 75)
self.setColumnWidth(2, 100)
class CenterPanel(QWidget):
def __init__(self, MainWin):
QWidget.__init__(self)
self.MyEditor = QTextEdit('Editorial')
self.ItemDsply = ItemDsplyr(self)
CntrPane = QSplitter(Qt.Horizontal, self)
CntrPane.addWidget(self.MyEditor)
CntrPane.addWidget(self.ItemDsply)
CntrPane.setSizes([50,200])
CntrPane.setCollapsible(0, False)
CntrPane.setCollapsible(1, False)
hbox = QHBoxLayout(self)
hbox.addWidget(CntrPane)
self.setLayout(hbox)
class MenuToolBar(QDockWidget):
def __init__(self, MainWin):
QDockWidget.__init__(self)
self.MainWin = MainWin
self.MainMenu = MainWin.menuBar()
self.WndowMenu = self.MainMenu.addMenu('Windows')
self.OptnAct = QAction('Options', self)
self.OptnAct.setStatusTip('Open the Options Window')
self.OptnAct.triggered.connect(MainWin.ShowOptions)
self.WndowMenu.addAction(self.OptnAct)
self.InitToolBar(MainWin)
def InitToolBar(self, MainWin):
self.mainToolBar = MainWin.addToolBar("Quick Access")
self.mainToolBar.addAction(self.OptnAct)
class UI_MainWindow(QMainWindow):
def __init__(self, MainDesktop):
super(UI_MainWindow, self).__init__(MainDesktop)
self.setWindowTitle('Main Window')
self.MnDskTop = MainDesktop
# Left, Top, Width, Height
self.setGeometry(200, 200, 550, 550)
self.CenterPane = CenterPanel(self)
self.setCentralWidget(self.CenterPane)
self.MenuToolBar = MenuToolBar(self)
def ShowOptions(self):
self.Options = OptionSettings(self)
if __name__ == '__main__':
MainApp = QApplication([])
MainGui = UI_MainWindow(MainApp.desktop())
MainGui.show()
sysExit(MainApp.exec_())

How to highlight a words in QTableWidget from a Searchlist

I want to search a QTableWidget-Table by a list of words, if they've been found i want them to bee highlighted.
I tried to modify the code from here so the table is beeing searched by a list of words, not just one. Unfortunatly my results keep getting overwritten. I always only get the result for the last word in the list.
Does anyone know how to modify the code so it will show the result of the whole list of words ?
Here is the code:
from PyQt5 import QtCore, QtGui, QtWidgets
import random
import html
words_1 = ["Hello dseerfd", "world sdfsdf sdfgsdf sdfsdf", "Stack dasdf", "Overflow", "Hello world", """<font color="red">Hello world</font>"""]
class HTMLDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None):
super(HTMLDelegate, self).__init__(parent)
self.doc = QtGui.QTextDocument(self)
def paint(self, painter, option, index):
substring = index.data(QtCore.Qt.UserRole)
painter.save()
options = QtWidgets.QStyleOptionViewItem(option)
self.initStyleOption(options, index)
res = ""
color = QtGui.QColor("red")
if substring:
substrings = options.text.split(substring)
res = """<font color="{}">{}</font>""".format(color.name(QtGui.QColor.HexRgb), substring).join(list(map(html.escape, substrings)))
else:
res = html.escape(options.text)
self.doc.setHtml(res)
options.text = ""
style = QtWidgets.QApplication.style() if options.widget is None \
else options.widget.style()
style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)
ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
if option.state & QtWidgets.QStyle.State_Selected:
ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
else:
ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
QtGui.QPalette.Active, QtGui.QPalette.Text))
textRect = style.subElementRect(
QtWidgets.QStyle.SE_ItemViewItemText, options)
if index.column() != 0:
textRect.adjust(5, 0, 0, 0)
the_constant = 4
margin = (option.rect.height() - options.fontMetrics.height()) // 2
margin = margin - the_constant
textRect.setTop(textRect.top() + margin)
painter.translate(textRect.topLeft())
painter.setClipRect(textRect.translated(-textRect.topLeft()))
self.doc.documentLayout().draw(painter, ctx)
painter.restore()
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
hlay = QtWidgets.QHBoxLayout()
lay = QtWidgets.QVBoxLayout(self)
self.table = QtWidgets.QTableWidget(5, 5)
lay.addLayout(hlay)
lay.addWidget(self.table)
self.table.setItemDelegate(HTMLDelegate(self.table))
for i in range(self.table.rowCount()):
for j in range(self.table.columnCount()):
it = QtWidgets.QTableWidgetItem(random.choice(words_1))
self.table.setItem(i, j, it)
text_list = ['ello', 'ack']
# clear
allitems = self.table.findItems("", QtCore.Qt.MatchContains)
selected_items =[]
for words in text_list:
for item in allitems:
selected_items = self.table.findItems(words, QtCore.Qt.MatchContains)
selected_items.append(self.table.findItems(words, QtCore.Qt.MatchContains)) ## i tried to make a list which is beeing appened but using this list it returns only the same as the input
item.setData(QtCore.Qt.UserRole, words if item in selected_items else None)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
In the previous case I wanted to filter the cases so as not to have to paint unnecessarily but in this case because it was more complex I decided to implement the highlight logic using QTextCharFormat and not HTML as I show below:
from PyQt5 import QtCore, QtGui, QtWidgets
import random
words = ["Hello dseerfd", "world sdfsdf sdfgsdf sdfsdf", "Stack dasdf", "Overflow", "Hello world", """<font color="red">Hello world</font>"""]
class HighlightDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, parent=None):
super(HighlightDelegate, self).__init__(parent)
self.doc = QtGui.QTextDocument(self)
self._filters = []
def paint(self, painter, option, index):
painter.save()
options = QtWidgets.QStyleOptionViewItem(option)
self.initStyleOption(options, index)
self.doc.setPlainText(options.text)
self.apply_highlight()
options.text = ""
style = QtWidgets.QApplication.style() if options.widget is None \
else options.widget.style()
style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)
ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
if option.state & QtWidgets.QStyle.State_Selected:
ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
else:
ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
QtGui.QPalette.Active, QtGui.QPalette.Text))
textRect = style.subElementRect(
QtWidgets.QStyle.SE_ItemViewItemText, options)
if index.column() != 0:
textRect.adjust(5, 0, 0, 0)
the_constant = 4
margin = (option.rect.height() - options.fontMetrics.height()) // 2
margin = margin - the_constant
textRect.setTop(textRect.top() + margin)
painter.translate(textRect.topLeft())
painter.setClipRect(textRect.translated(-textRect.topLeft()))
self.doc.documentLayout().draw(painter, ctx)
painter.restore()
def apply_highlight(self):
cursor = QtGui.QTextCursor(self.doc)
cursor.beginEditBlock()
fmt = QtGui.QTextCharFormat()
fmt.setForeground(QtCore.Qt.red)
for f in self.filters():
highlightCursor = QtGui.QTextCursor(self.doc)
while not highlightCursor.isNull() and not highlightCursor.atEnd():
highlightCursor = self.doc.find(f, highlightCursor)
if not highlightCursor.isNull():
highlightCursor.mergeCharFormat(fmt)
cursor.endEditBlock()
#QtCore.pyqtSlot(list)
def setFilters(self, filters):
if self._filters == filters: return
self._filters = filters
def filters(self):
return self._filters
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.table = QtWidgets.QTableWidget(30, 6)
self._delegate = HighlightDelegate(self.table)
self.table.setItemDelegate(self._delegate)
for i in range(self.table.rowCount()):
for j in range(self.table.columnCount()):
it = QtWidgets.QTableWidgetItem(random.choice(words))
self.table.setItem(i, j, it)
self.table.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)
le = QtWidgets.QLineEdit()
le.textChanged.connect(self.on_textChanged)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(le)
lay.addWidget(self.table)
le.setText("ello ack")
#QtCore.pyqtSlot(str)
def on_textChanged(self, text):
self._delegate.setFilters(list(set(text.split())))
self.table.viewport().update()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.showMaximized()
sys.exit(app.exec_())

PyQt5 Getting values from Qdialog window to mainwindow after close

I would like to get values from Qdialog window into Qmainwindow after closing Qdailog or Qwidget window. Actually I do not know how to do this.
The idea is when user selects a root value from QtableWidget, as shown below in the figure, Data display on the QWidget and I want to transform or pass these values into my Qmainwindow, and my second window in this case is Circular.py would disappear, but my values should be available in the Qmainwindow.
Visualisation of windows.
The Code, "main.py"
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from Circular import *
class Foo(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
self.setGeometry(QtCore.QRect(200, 100, 600, 360))
self.boo = Boo()
self.setCentralWidget(self.boo)
class Boo(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Boo, self).__init__(parent)
Openbutton = QtWidgets.QPushButton('Getting values')
Alay = QtWidgets.QVBoxLayout(self)
Alay.addWidget(Openbutton)
Openbutton.clicked.connect(self.buttonfunc)
def buttonfunc(self):
app.setStyleSheet(QSS)
subwindow=CircularDialog()
subwindow.setWindowModality(QtCore.Qt.ApplicationModal)
subwindow.show()
subwindow.exec_()
print('Test')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Foo()
w.show()
sys.exit(app.exec_())
Second window code "Circular.py"
Please note that this code is previuosly posted here.
import sys
import os
from PyQt5 import QtCore, QtGui, QtWidgets
iconroot = os.path.dirname(__file__)
ORGANIZATION_NAME = 'Circular App'
ORGANIZATION_DOMAIN = 'Circular shape'
APPLICATION_NAME = 'Circulargeometry program'
SETTINGS_TRAY = 'settings/tray'
QSS = """
QTreeWidget{
border:none;
}
QTreeView::branch:has-siblings:!adjoins-item {
border-image: url(images/vline.png) 0;
}
QTreeView::branch:has-siblings:adjoins-item {
border-image: url(images/branch-more.png) 0;
}
QTreeView::branch:!has-children:!has-siblings:adjoins-item {
border-image: url(images/branch-end.png) 0;
}
QTreeView::branch:has-children:!has-siblings:closed,
QTreeView::branch:closed:has-children:has-siblings {
border-image: none;
image: url(images/branch-closed.png);
}
QTreeView::branch:open:has-children:!has-siblings,
QTreeView::branch:open:has-children:has-siblings {
border-image: none;
image: url(images/branch-open.png);
}
"""
class TreeWidget(QtWidgets.QTreeWidget):
currentTextChanged = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(TreeWidget, self).__init__(parent)
self.currentItemChanged.connect(self.onCurrentItemChanged)
self.setHeaderLabel('Standard Section Library')
self.setRootIsDecorated(True)
self.setAlternatingRowColors(True)
self.readSettings()
self.expandAll()
def onCurrentItemChanged(self, current, previous):
if current not in [self.topLevelItem(ix) for ix in range(self.topLevelItemCount())]:
self.currentTextChanged.emit(current.text(0))
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
values = settings.value("items")
if values is None:
self.loadDefault()
else:
TreeWidget.dataToChild(values, self.invisibleRootItem())
self.customized_item = None
for ix in range(self.topLevelItemCount()):
tlevel_item = self.topLevelItem(ix)
if tlevel_item.text(0) == "Customized":
self.customized_item = tlevel_item
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("TreeWidget")
settings.setValue("items", TreeWidget.dataFromChild(self.invisibleRootItem()))
settings.endGroup()
def loadDefault(self):
standardsectionlist = ["D100","D150","D200","D250","D300","D350","D400","D450","D500",
"D550","D600","D650","D700","D750","D800","D850","D900","D950","D1000"]
rootItem = QtWidgets.QTreeWidgetItem(self, ['Circular shapes'])
rootItem.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
for element in standardsectionlist:
rootItem.addChild(QtWidgets.QTreeWidgetItem([element]))
self.customized_item = QtWidgets.QTreeWidgetItem(self, ["Customized"])
self.customized_item.setIcon(0, QtGui.QIcon(os.path.join(iconroot,"images/circularcolumnnorebar.png")))
#staticmethod
def dataToChild(info, item):
TreeWidget.tupleToItem(info["data"], item)
for val in info["childrens"]:
child = QtWidgets.QTreeWidgetItem()
item.addChild(child)
TreeWidget.dataToChild(val, child)
#staticmethod
def tupleToItem(t, item):
# set values to item
ba, isSelected = t
ds = QtCore.QDataStream(ba)
ds >> item
item.setSelected(isSelected)
#staticmethod
def dataFromChild(item):
l = []
for i in range(item.childCount()):
child = item.child(i)
l.append(TreeWidget.dataFromChild(child))
return {"childrens": l, "data": TreeWidget.itemToTuple(item)}
#staticmethod
def itemToTuple(item):
# return values from item
ba = QtCore.QByteArray()
ds = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
ds << item
return ba, item.isSelected()
class InfoWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(InfoWidget, self).__init__(parent)
hlay = QtWidgets.QHBoxLayout(self)
plabel = QtWidgets.QLabel()
pixmap = QtGui.QPixmap(os.path.join(iconroot, "images/circularcolumnnorebard.png"))\
.scaled(230, 230, QtCore.Qt.KeepAspectRatio)
plabel.setPixmap(pixmap)
hlay.addWidget(plabel)
self.ilabel = QtWidgets.QLabel()
hlay.addWidget(self.ilabel)
hlay.addStretch()
self.readSettings()
#QtCore.pyqtSlot(str)
def setData(self, text):
try:
circular_section = int(text.translate({ord('D'): ""}))
area = (3.1416/4)*(circular_section**2)
inertia = (3.1416/64)*circular_section**4
fmt = "D = {}mm\nA = {:0.2E}mm2\n I = {:0.2E}mm4"
self.ilabel.setText(fmt.format(circular_section, area, inertia))
except ValueError:
pass
return print(circular_section)
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
self.ilabel.setText(settings.value("text", ""))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("InfoWidget")
settings.setValue("text", self.ilabel.text())
settings.endGroup()
class CircularDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(CircularDialog, self).__init__(parent)
self.setWindowTitle("Frequently used shape")
self.setWindowIcon(QtGui.QIcon(os.path.join(iconroot+"/images/circularcolumnnorebar.png")))
grid = QtWidgets.QGridLayout(self)
self.tree = TreeWidget()
self.infoWidget = InfoWidget()
section_lay = QtWidgets.QHBoxLayout()
section_label = QtWidgets.QLabel("Section name: ")
self.section_edit = QtWidgets.QLineEdit('Define en name to section')
section_lay.addWidget(section_label)
section_lay.addWidget(self.section_edit)
self.tree.currentTextChanged.connect(self.infoWidget.setData)
button_layout = QtWidgets.QVBoxLayout()
add_button = QtWidgets.QPushButton("Add")
add_button.clicked.connect(self.addItem)
delete_button = QtWidgets.QPushButton("Delete")
delete_button.clicked.connect(self.removeItem)
button_layout.addWidget(add_button, alignment=QtCore.Qt.AlignBottom)
button_layout.addWidget(delete_button, alignment=QtCore.Qt.AlignTop)
buttonBox = QtWidgets.QDialogButtonBox()
buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
buttonBox.accepted.connect(self.accept)
buttonBox.rejected.connect(self.reject)
self.accepted.connect(self.save_all_data)
self.rejected.connect(self.save_all_data)
grid.addLayout(section_lay, 0, 0)
grid.addWidget(self.tree, 1, 0)
grid.addLayout(button_layout, 1, 1)
grid.addWidget(self.infoWidget, 2, 0, 1, 2)
grid.addWidget(buttonBox, 3, 0, 1, 2)
self.readSettings()
def readSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
self.setGeometry(settings.value("geometry", QtCore.QRect(300, 300, 400, 600)))
self.section_edit.setText(settings.value("SectionInfo", "Define en name to section"))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings()
settings.beginGroup("CircularDialog")
settings.setValue("geometry", self.geometry())
settings.setValue("SectionInfo",self.section_edit.text())
settings.endGroup()
def closeEvent(self, event):
self.save_all_data()
super(CircularDialog, self).closeEvent(event)
def save_all_data(self):
for children in self.findChildren(QtWidgets.QWidget) + [self]:
if hasattr(children, "writeSettings"):
children.writeSettings()
def addItem(self):
text, ok = QtWidgets.QInputDialog.getText(self, "Add custom section",
"Enter section geometry f.ex as D325 or just 325 in mm: ")
if ok:
it = QtWidgets.QTreeWidgetItem([text])
self.tree.customized_item.addChild(it)
def removeItem(self):
it = self.tree.customized_item.takeChild(0)
del it
if __name__ == '__main__':
QtCore.QCoreApplication.setApplicationName(ORGANIZATION_NAME)
QtCore.QCoreApplication.setOrganizationDomain(ORGANIZATION_DOMAIN)
QtCore.QCoreApplication.setApplicationName(APPLICATION_NAME)
app = QtWidgets.QApplication(sys.argv)
app.setStyleSheet(QSS)
w = CircularDialog()
w.show()
sys.exit(app.exec_())
The first thing to do is verify that if you accept or not using exec_ () that returns a code:QDialog::Accepted, if you want to get the text you must use the relationship tree:
def buttonfunc(self):
app.setStyleSheet(QSS)
subwindow=CircularDialog()
subwindow.setWindowModality(QtCore.Qt.ApplicationModal)
if subwindow.exec_() == QtWidgets.QDialog.Accepted:
print('Test', subwindow.infoWidget.ilabel.text())

Categories