Как записать в переменную и передать ее вводимый текст из QLineEdit в QStandardItemModel data?
Я пытаюсь создать таблицу с использованием Pandas в качестве источника данных, отформатировать её согласно значениям данных, а также добавить фильтр, чтобы при фильтрации была выделена та часть текста, которая соответствует фильтру.
Я не могу понять, как передать значение
QLineEdit->text() в QStandardItemModel->data()
без использования QStyledItemDelegate?
Может быть, с помощью сигналов и слотов? Мне кажется, это должно выглядеть очень просто, но пока не пойму как.
Как добавить переменную QLineEdit->text() в QStandardItemModel->data(), чтобы я мог использовать?
import numpy as np
import pandas as pd
from datetime import datetime
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
Stylesheet = """
#WIN {background:rgba(50,50,50,.05); border:1 solid #373737; border-radius:3;}
#filter {background-color:rgba(44,44,44,.35); padding:.5 .5 .5 20; margin:1; border-radius:3; color:#999999; selection-color:#2d2d2d;}
#filter:hover {background-color:rgba(44,44,44,.5);} #filter:focus {background-color:rgba(44,44,44,.7); font:italic;}
#TABLE {background:#323232; color:#b1b1b1; padding:-1; alternate-background-color:transparent; gridline-color:#2d2d2d; border:1 solid #323232; border-radius:3; font:italic large 'Nunito';}
#TABLE::item::hover {background:#323232; color:#0080ff; border:1 solid #323232;}
#TABLE::item::selected {background:#323232; color:#3399ff; border-bottom:1 solid #2d2d2d; border-top:1 solid #2d2d2d;}
QTableCornerButton::section {background:rgba(44,44,44,.3); border:1 solid #323232;} QTableCornerButton::section:hover {background:rgba(44,44,44,.5);}
QTableCornerButton::section:pressed {background:rgba(44,44,44,.6); border:0;}
QHeaderView {background:transparent; color:#cccccc;font:italic large 'Nunito';} QHeaderView::section {border:0;}
QHeaderView::section::horizontal {background:rgba(44,44,44,.3); border-right:1 solid #323232; border-bottom:1 solid #323232; margin:-1 0 0 0;}
QHeaderView::section::horizontal::last {border-right:0;} QHeaderView::section::horizontal:pressed {background:rgba(44,44,44,.6); color:#0080ff;}
QHeaderView::section::horizontal:hover {background:rgba(44,44,44,.5); color:#3399ff; font:bold;}
QHeaderView::section::vertical {background:rgba(44,44,44,.3); border-bottom:1 solid #323232; border-right:1 solid #323232; color:#b1b1b1; margin:-1 0 0 0;}
QHeaderView::section::vertical:checked, QHeaderView::section::vertical:hover {color:#0080ff; font:bold;}
QScrollBar:horizontal {background:transparent; max-height:6} QScrollBar:vertical {background:transparent; width:6;}
QScrollBar::handle:horizontal, QScrollBar::handle:vertical {background:rgba(170,170,170,51); border-radius:3;}
QScrollBar::handle:horizontal:hover, QScrollBar::handle:vertical:hover {background:rgba(170,170,170,68)}
QScrollBar::sub-line:horizontal, QScrollBar::add-line:horizontal, QScrollBar::sub-line:vertical, QScrollBar::add-line:vertical,
QScrollBar::sub-page:horizontal, QScrollBar::add-page:horizontal, QScrollBar::sub-page:vertical, QScrollBar::add-page:vertical {background:none;}
QScrollBar::corner {background:transparent;}
"""
class Table(QWidget):
def __init__(self):
super().__init__(objectName='WIN')
self.setStyleSheet(Stylesheet)
self.layout = QVBoxLayout(self, spacing=0)
self.layout.setContentsMargins(0, 0, 0, 0)
self.table = MyTableView()
self.filter_line = QLineEdit(textChanged=self.table.filter, clearButtonEnabled=True, placeholderText='Search:', objectName='filter')
self.layout.addWidget(self.filter_line)
self.layout.addWidget(self.table)
self.layout.setSizeConstraint(QLayout.SetFixedSize)
class PandasTableModel(QStandardItemModel):
def __init__(self, data):
super().__init__()
self._data = data
for row in data.values.tolist():
data_row = [QStandardItem("{}".format(x)) for x in row]
self.appendRow(data_row)
def data(self, index, role=Qt.DisplayRole):
value = self._data.iloc[index.row(), index.column()]
if role == Qt.DisplayRole:
return str(value)
if role == Qt.TextAlignmentRole and index.column() != 0:
return Qt.AlignVCenter + Qt.AlignRight
if role == Qt.ToolTipRole and index.column() == 0:
return self._data.iloc[index.row(), 1]
################################################################################
# На что заменить str('-1'), чтобы использовать вводимый текст из QLineEdit??? #
################################################################################
if role == Qt.ForegroundRole and str('-1') in str(value):
return QColor('#3399ff')
if role == Qt.ForegroundRole and index.column() != 0:
val = self._data.iloc[index.row(), 0]
return QColor('#339933') if val > 0 else QColor('#CC0000')
if role == Qt.FontRole and (index.column() == 0):
font = QFont()
font.setBold(True)
return font
def rowCount(self, index):
return self._data.shape[0]
def columnCount(self, index):
return self._data.shape[1]
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[col]
if orientation == Qt.Vertical and role == Qt.DisplayRole:
return self._data.index[col]
class MyTableView(QTableView):
def __init__(self):
super().__init__(objectName='TABLE', alternatingRowColors=True, sortingEnabled=True, cornerButtonEnabled=False)
rng = np.random.default_rng()
df = pd.DataFrame(rng.integers(-100, 100, size=(100, 10)), columns=list('QWERTYUIOP'))
self.verticalHeader().setDefaultAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setFocusPolicy(Qt.NoFocus)
self.filter_proxy_model = QSortFilterProxyModel(filterKeyColumn=-1, sortCaseSensitivity=False)
self.filter_proxy_model.setSourceModel(PandasTableModel(df))
self.setModel(self.filter_proxy_model)
self.setColumnHidden(1, True)
self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.verticalHeader().setDefaultSectionSize(0)
self.verticalScrollBar().setFixedWidth(7)
self.resizeColumnsToContents()
self.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.setFixedWidth(self.viewportSizeHint().width() + self.verticalScrollBar().width())
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.content_resize()
self.setMaximumHeight(QDesktopWidget().height() / 2)
def content_resize(self):
self.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
if self.filter_proxy_model.rowCount() > 0:
self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
else:
self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
def filter(self, text):
reg_text = QRegExp(text, Qt.CaseInsensitive, QRegExp.Wildcard)
self.filter_proxy_model.setFilterRegExp(reg_text)
self.parentWidget().adjustSize()
if __name__ == '__main__':
start_time = datetime.now()
app = QApplication([])
w = Table()
w.show()
print(f'{datetime.now() - start_time}')
app.exec()
Буду рад Вашей критике, подсказкам, объяснениям, а также любой помощи. Заранее спасибо.
Ответы (1 шт):
Если я вас правильно понял. Я отметил для вас строки, в которые внес изменения. Проверьте.
import sys
import numpy as np # numpy.__version__ ---> '1.20.1'
import pandas as pd
from datetime import datetime
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class PandasTableModel(QStandardItemModel):
def __init__(self, data):
super().__init__()
self._data = data
self.f_l_t = '' # +++
for row in data.values.tolist():
data_row = [QStandardItem("{}".format(x)) for x in row]
self.appendRow(data_row)
def data(self, index, role=Qt.DisplayRole):
value = self._data.iloc[index.row(), index.column()]
if role == Qt.DisplayRole:
return str(value)
if role == Qt.TextAlignmentRole and index.column() != 0:
return Qt.AlignVCenter + Qt.AlignRight
if role == Qt.ToolTipRole and index.column() == 0:
return self._data.iloc[index.row(), 1]
################################################################################
# На что заменить str('-1'), чтобы использовать вводимый текст из QLineEdit??? #
################################################################################
# Кисть переднего плана (обычно цвет текста), используемая для элементов,
# отображаемых с помощью делегата по умолчанию. (QBrush)
# if role == Qt.ForegroundRole and str('-1') in str(value): # ---
if role == Qt.ForegroundRole and self.f_l_t in str(value): # +++ self.f_l_t
return QColor('#3399ff')
if role == Qt.ForegroundRole and index.column() != 0:
val = self._data.iloc[index.row(), 0]
return QColor('#339933') if val > 0 else QColor('#CC0000')
if role == Qt.FontRole and (index.column() == 0):
font = QFont()
font.setBold(True)
return font
def rowCount(self, index):
return self._data.shape[0]
def columnCount(self, index):
return self._data.shape[1]
def headerData(self, col, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self._data.columns[col]
if orientation == Qt.Vertical and role == Qt.DisplayRole:
return self._data.index[col]
def _set_f_l_t(self, text): # +++
# print(f'text -> {text}')
self.f_l_t = text # +++
class MyTableView(QTableView):
def __init__(self): # filter_line_text filter_line
super().__init__(
objectName='TABLE',
alternatingRowColors=True,
sortingEnabled=True,
cornerButtonEnabled=False
)
rng = np.random.default_rng()
df = pd.DataFrame(rng.integers(-100, 100, size=(100, 10)), columns=list('QWERTYUIOP'))
self.verticalHeader().setDefaultAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setFocusPolicy(Qt.NoFocus)
self.filter_proxy_model = QSortFilterProxyModel(filterKeyColumn=-1, sortCaseSensitivity=False)
self.pandasTableModel = PandasTableModel(df)
self.filter_proxy_model.setSourceModel(self.pandasTableModel) #(PandasTableModel(df))
self.setModel(self.filter_proxy_model)
self.setColumnHidden(1, True)
self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.verticalHeader().setDefaultSectionSize(0)
self.verticalScrollBar().setFixedWidth(7)
self.resizeColumnsToContents()
self.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.setFixedWidth(self.viewportSizeHint().width() + self.verticalScrollBar().width())
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.content_resize()
self.setMaximumHeight(QDesktopWidget().height() / 2)
def content_resize(self):
self.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
if self.filter_proxy_model.rowCount() > 0:
self.horizontalHeader().setSectionResizeMode(QHeaderView.Fixed)
self.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
else:
self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
def filter(self, text):
reg_text = QRegExp(text, Qt.CaseInsensitive, QRegExp.Wildcard)
self.filter_proxy_model.setFilterRegExp(reg_text)
self.parentWidget().adjustSize()
self.pandasTableModel._set_f_l_t(text) # +++ !!!
class Table(QWidget):
def __init__(self):
super().__init__(objectName='WIN')
# self.setStyleSheet(Stylesheet)
self.table = MyTableView()
self.filter_line = QLineEdit(
textChanged=self.table.filter,
clearButtonEnabled=True,
placeholderText='Search:',
objectName='filter'
)
self.layout = QVBoxLayout(self, spacing=0)
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.addWidget(self.filter_line)
self.layout.addWidget(self.table)
self.layout.setSizeConstraint(QLayout.SetFixedSize)
Stylesheet = """
#WIN {background:rgba(50,50,50,.05); border:1 solid #373737; border-radius:3;}
#filter {background-color:rgba(44,44,44,.35); padding:.5 .5 .5 20; margin:1; border-radius:3; color:#999999; selection-color:#2d2d2d;}
#filter:hover {background-color:rgba(44,44,44,.5);} #filter:focus {background-color:rgba(44,44,44,.7); font:italic;}
#TABLE {background:#323232; color:#b1b1b1; padding:-1; alternate-background-color:transparent; gridline-color:#2d2d2d; border:1 solid #323232; border-radius:3; font:italic large 'Nunito';}
#TABLE::item::hover {background:#323232; color:#0080ff; border:1 solid #323232;}
#TABLE::item::selected {background:#323232; color:#3399ff; border-bottom:1 solid #2d2d2d; border-top:1 solid #2d2d2d;}
QTableCornerButton::section {background:rgba(44,44,44,.3); border:1 solid #323232;} QTableCornerButton::section:hover {background:rgba(44,44,44,.5);}
QTableCornerButton::section:pressed {background:rgba(44,44,44,.6); border:0;}
QHeaderView {background:transparent; color:#cccccc;font:italic large 'Nunito';} QHeaderView::section {border:0;}
QHeaderView::section::horizontal {background:rgba(44,44,44,.3); border-right:1 solid #323232; border-bottom:1 solid #323232; margin:-1 0 0 0;}
QHeaderView::section::horizontal::last {border-right:0;} QHeaderView::section::horizontal:pressed {background:rgba(44,44,44,.6); color:#0080ff;}
QHeaderView::section::horizontal:hover {background:rgba(44,44,44,.5); color:#3399ff; font:bold;}
QHeaderView::section::vertical {background:rgba(44,44,44,.3); border-bottom:1 solid #323232; border-right:1 solid #323232; color:#b1b1b1; margin:-1 0 0 0;}
QHeaderView::section::vertical:checked, QHeaderView::section::vertical:hover {color:#0080ff; font:bold;}
QScrollBar:horizontal {background:transparent; max-height:6} QScrollBar:vertical {background:transparent; width:6;}
QScrollBar::handle:horizontal, QScrollBar::handle:vertical {background:rgba(170,170,170,51); border-radius:3;}
QScrollBar::handle:horizontal:hover, QScrollBar::handle:vertical:hover {background:rgba(170,170,170,68)}
QScrollBar::sub-line:horizontal, QScrollBar::add-line:horizontal, QScrollBar::sub-line:vertical, QScrollBar::add-line:vertical,
QScrollBar::sub-page:horizontal, QScrollBar::add-page:horizontal, QScrollBar::sub-page:vertical, QScrollBar::add-page:vertical {background:none;}
QScrollBar::corner {background:transparent;}
"""
if __name__ == '__main__':
start_time = datetime.now()
app = QApplication(sys.argv)
app.setStyleSheet(Stylesheet) # +++
w = Table()
w.show()
print(f'{datetime.now() - start_time}')
sys.exit(app.exec_())
