PyQt5,无法使用鼠标滚轮在显示熊猫数据帧的QTableView中滚动

问题描述 投票:0回答:1

我使用与this one类似的QtableView。一切正常。我的问题是,我无法使用鼠标滚轮滚动。同时按下鼠标左键滚动并移动滚动条也不起作用。

我只能使用箭头上下滚动。

这里是代码:

class PandasModel(QAbstractTableModel):

    def __init__(self, data, parent=None):
        """

        :param data: a pandas dataframe
        :param parent: 
        """
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=QtCore.Qt.DisplayRole):
        current_column = index.column()
        current_row = index.row()

        gold_color = QColor(235, 201, 52)
        lightred_color = QColor('#FF5858')
        knallrot = QColor('#FF0000')
        shine_yellow = QColor('#FFFF00')
        greeny = QColor(92, 235, 52)

        white_color = QColor(QtCore.Qt.white)
        black_color = QColor(QtCore.Qt.black)

        if index.isValid():
            if role == QtCore.Qt.DisplayRole:
                return str(self._data.iloc[index.row(), index.column()])

        if role == Qt.BackgroundColorRole:   # The role for backgrounbd color of a cell
            if current_column == 7:
                it = self._data.iloc[index.row(), current_column]  # Finds the specific data (second column) to test and assigns it to the variable "it"
                if 20 > it > 10:  
                    return QBrush(gold_color)  
                if it >= 20: 
                    return QBrush(shine_yellow)  

        if role == Qt.BackgroundColorRole:  # The role for backgrounbd color of a cell
            if current_column == 5:
                it = self._data.iloc[index.row(), current_column]  # Finds the specific data (second column) to test and assigns it to the variable "it"
                if  it > 100000:  
                    return QBrush(greeny)
                if 10000 > it >= 1000:  
                    return QBrush(lightred_color) 
                if it < 1000: 
                    return QBrush(knallrot) 

            if current_column == 2:
                it = self._data.iloc[index.row(), current_column]  # Finds the specific data (second column) to test and assigns it to the variable "it"
                if  it > 100000:  
                    return QBrush(greeny)
                if 10000 > it >= 1000:  
                    return QBrush(lightred_color) 
                if it < 1000: 
                    return QBrush(knallrot)    

        if role == Qt.TextColorRole:
            return QColor(39, 68, 209)

        if role == Qt.BackgroundColorRole and index == 7:
            return QColor(235, 201, 52)

        if role == Qt.FontRole and index == 7:
            return QFont("Helvetica", 12, QFont.Bold, );

        return None

    def headerData(self, rowcol, orientation, role):

        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self._data.columns[rowcol]
        if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
            return self._data.index[rowcol]

        if role == Qt.BackgroundColorRole and rowcol == 7:
            return QColor(235, 201, 52) #gold
        elif role == Qt.BackgroundColorRole and rowcol == 6:
            return QColor(235, 67, 52) #red
        elif role == Qt.BackgroundColorRole and rowcol == 5:
            return QColor(235, 67, 52) #red
        elif role == Qt.BackgroundColorRole and rowcol == 4:
            return QColor(235, 67, 52) #red
        elif role == Qt.BackgroundColorRole and rowcol == 3:
            return QColor(92, 235, 52) #green
        elif role == Qt.BackgroundColorRole and rowcol == 2:
            return QColor(92, 235, 52) #green
        elif role == Qt.BackgroundColorRole and rowcol == 1:
            return QColor(92, 235, 52) #green
        return None

    def flags(self, index):
        flags = super(self.__class__, self).flags(index)
        #flags |= QtCore.Qt.ItemIsEditable
        flags |= QtCore.Qt.ItemIsSelectable
        flags |= QtCore.Qt.ItemIsEnabled
        flags |= QtCore.Qt.ItemIsDragEnabled
        flags |= QtCore.Qt.ItemIsDropEnabled
        return flags

    def sort(self, Ncol, order):
        """Sort table by given column number.
        """
        try:
            self.layoutAboutToBeChanged.emit()
            self._data = self._data.sort_values(self._data.columns[Ncol], ascending=not order)
            self.layoutChanged.emit()
        except Exception as e:
            print(e)

在main.py中这样称呼:

        self.tabCrawledresult = QTabWidget()
        self.tabCrawledresult.layout = QGridLayout() 
        self.tabCrawledresult.setLayout(self.tabCrawledresult.layout)
        self.tabs.addTab(self.tabCrawledresult, "Results")

        self.view_minmax = QTableView(self.tabCrawledresult)
        self.modelminmax = gui_pandasModel_sort.PandasModel(df)
        self.view_minmax.setModel(self.modelminmax)  
        self.view_minmax.resize(1000,500)  # is it possible to fit the size to width of headers?  
        self.view_minmax.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)    
        self.view_minmax.setSortingEnabled(True)
        self.view_minmax.sortByColumn(7, Qt.DescendingOrder)
        self.view_minmax.setAlternatingRowColors(True)
        self.view_minmax.setStyleSheet("alternate-background-color: rgb(209, 209, 209)"
                           "; background-color: rgb(244, 244, 244);")

        self.view_minmax.show()

以及如何使QTableView的大小适合标题的宽度?

python-3.x pandas dataframe pyqt5 qtableview
1个回答
0
投票

首先。 PandasModel类正确无误。我在main.py中所做的错误。我在QTabWidget中显示TableView,并希望在其底部有一个导出按钮。所以我的丑陋解决方案是,在Tab上放置一个空QLabelWidgets的“层”,然后在其上放置TableView。这是带有一些数据的完整示例。

import sys
from PyQt5 import QtCore
from PyQt5.QtCore import QAbstractTableModel, Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QTabWidget, QFileDialog, 
    QGridLayout, QPushButton, QTableView, QLabel, QHeaderView
import numpy as np
import pandas as pd
from functools import partial

def createDF():
    df = pd.DataFrame(np.random.randint(0,11,size=(50, 5)), columns=list(['A','B','C', 
            'D','Tree']))
    print(df)
    return df

trees = {  1: 'Arborvitae (Thuja occidentalis)',
             2: 'Black Ash (Fraxinus nigra)',
             3: 'White Ash (Fraxinus americana)',     
             4: 'Bigtooth Aspen (Populus grandidentata)',
             5: 'Quaking Aspen (Populus tremuloides)',
             6: 'Basswood (Tilia americana)', 
             7: 'American Beech (Fagus grandifolia)',  
             8: 'Black Birch (Betula lenta)',  
             9: 'Gray Birch (Betula populifolia)',  
             10: 'Paper Birch (Betula papyrifera)'} 

class PandasModel(QAbstractTableModel):

    def __init__(self, data, parent=None):
        """
        :param data: a pandas dataframe
        :param parent: 
        """
        QtCore.QAbstractTableModel.__init__(self, parent)        
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=QtCore.Qt.DisplayRole):

        if index.isValid():
            if role == QtCore.Qt.DisplayRole:
                return str(self._data.iloc[index.row(), index.column()])    
        return None

    def headerData(self, rowcol, orientation, role):

        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self._data.columns[rowcol]
        if orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
            return self._data.index[rowcol]


    def flags(self, index):
        flags = super(self.__class__, self).flags(index)
        #flags |= QtCore.Qt.ItemIsEditable
        flags |= QtCore.Qt.ItemIsSelectable
        flags |= QtCore.Qt.ItemIsEnabled
        flags |= QtCore.Qt.ItemIsDragEnabled
        flags |= QtCore.Qt.ItemIsDropEnabled
        return flags

    def sort(self, Ncol, order):
        """Sort table by given column number.
        """
        try:
            self.layoutAboutToBeChanged.emit()
            self._data = self._data.sort_values(self._data.columns[Ncol], 
                ascending=not order)
            self.layoutChanged.emit()
        except Exception as e:
            print(e)


class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        self.resize(400, 600)        

        self.tabs = QTabWidget()
        self.tabs.layout = QGridLayout() 
        self.tabs.setLayout(self.tabs.layout)

        self.grid = QGridLayout()
        self.grid.addWidget(self.tabs)
        self.setLayout(self.grid)
        self.setCentralWidget(self.tabs)  

        self.df = createDF()

        self.displayDF()

    def displayDF(self):

        self.result = QTabWidget()
        self.result.layout = QGridLayout() 
        self.result.setLayout(self.result.layout)
        self.tabs.addTab(self.result, 'Dataframe')

        #empty space to put the export button in the bottom of the TableView
        positions = [(i,j) for i in range(20) for j in range(10)]
        space = '              '
        i = 0
        for position, leer in zip(positions, space): 
            emptyLabels = QLabel(leer)
            self.result.layout.addWidget(emptyLabels, *position)

        #export button     
        self.buttonExport = QPushButton("Export", self)
        self.buttonExport.clicked.connect(partial(self.writeToCSV, self.df))
        self.result.layout.addWidget(self.buttonExport, 21, 0)

        # QTableView
        self.view_minmax = QTableView(self.result)
        self.modelminmax = PandasModel(self.df)
        self.view_minmax.setModel(self.modelminmax)
        self.view_minmax.resize(360,500)    
        self.view_minmax.clicked.connect(self.onClickedRow)
        self.view_minmax.sortByColumn(4, Qt.DescendingOrder)
        self.view_minmax.show()    

    def onClickedRow(self, index=None):
        print("Click !")
        print(index.data())

    def writeToCSV(self, df):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getSaveFileName(self,"Export results to a\ 
                csv","","CSV (*.csv);;Text Files (*.txt)", options=options)
        if fileName:
            print(fileName)
            df.to_csv (fileName, index = False, header=True) 
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())

因此,当我在#QTableView部分之后创建#empty空间QLabelWidget并导出Button时,像这样,滚动条会出现奇怪的行为,因为鼠标的信号发送到QLabelWidgets而不是QTabelView。

        # QTableView
        self.view_minmax = QTableView(self.result)
        self.modelminmax = PandasModel(self.df)
        self.view_minmax.setModel(self.modelminmax)
        self.view_minmax.resize(360,500)    
        self.view_minmax.clicked.connect(self.onClickedRow)
        self.view_minmax.sortByColumn(4, Qt.DescendingOrder)
        self.view_minmax.show() 

        #empty space to put the export button in the bottom of the TableView
        positions = [(i,j) for i in range(20) for j in range(10)]
        space = '              '
        i = 0
        for position, leer in zip(positions, space): 
            emptyLabels = QLabel(leer)
            self.result.layout.addWidget(emptyLabels, *position)

        #export button     
        self.buttonExport = QPushButton("Export", self)
        self.buttonExport.clicked.connect(partial(self.writeToCSV, self.df))
        self.result.layout.addWidget(self.buttonExport, 21, 0)

也许会帮助某人。

© www.soinside.com 2019 - 2024. All rights reserved.