I use a QtableView similiar to this one. Everything works fine. My problem is that, that I can't scroll with the mousewheel. Also scrolling with pressing left mouse button and move the scrollbar don't work.
I can only use the arrows to scroll up and down.
Here is the code:
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)
From the main.py it's called like this:
        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()
And how is it possible to fit the size of the QTableView to the width of headers?