我使用与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的大小适合标题的宽度?
首先。 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)
也许会帮助某人。