Как записать в переменную и передать ее вводимый текст из 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 шт):

Автор решения: S. Nick

Если я вас правильно понял. Я отметил для вас строки, в которые внес изменения. Проверьте.

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_())

введите сюда описание изображения

→ Ссылка