Python - PyQt5 - QTableWidget set constraint while resizing header sections

20 Views Asked by At

File: table.py

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.resize(515, 285)
        self.gridLayout = QtWidgets.QGridLayout(Dialog)
        self.tableWidget = QtWidgets.QTableWidget(Dialog)
        self.tableWidget.setColumnCount(4)
        self.tableWidget.setRowCount(0)
        item = QtWidgets.QTableWidgetItem()
        item.setText("Column 1")
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        item.setText("Column 2")
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        item.setText("Column 3")
        self.tableWidget.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        item.setText("Column 4")
        self.tableWidget.setHorizontalHeaderItem(3, item)
        self.tableWidget.horizontalHeader().setCascadingSectionResizes(False)
        self.tableWidget.horizontalHeader().setStretchLastSection(False)
        self.gridLayout.addWidget(self.tableWidget, 0, 0, 1, 1)

File: run_me.py

from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from table import Ui_Dialog

class Run_me:
    
    def __init__(self):     
        self.app = QtWidgets.QApplication(sys.argv)
        self.Dialog = QtWidgets.QDialog()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self.Dialog)
        self.Dialog.show()

        self.ui.tableWidget.resizeColumnsToContents()
        self.find_table_column_min_width()

        horizontal_header = self.ui.tableWidget.horizontalHeader()
        self.ui.tableWidget.setHorizontalHeader(CustomHeader(self.ui.tableWidget,self.columns_min_width))
        self.ui.tableWidget.updateGeometries()        
        
        sys.exit(self.app.exec_())

    def find_table_column_min_width(self):
        total_columns = self.ui.tableWidget.columnCount()
        self.columns_min_width = []
        for column_index in range(0,total_columns):
            column_width = self.ui.tableWidget.columnWidth(column_index)
            self.columns_min_width.append(column_width)

        
class CustomHeader(QtWidgets.QHeaderView):
    def __init__(self,table,columns_min_width):
        self.columns_min_width = columns_min_width
        self.total_columns = len(self.columns_min_width)
        self.header_labels = []
        for column_index in range(0,self.total_columns):
            column_text = table.horizontalHeaderItem(column_index).text()
            self.header_labels.append(column_text)
        super().__init__(QtCore.Qt.Horizontal,table)
        self.table = self.parentWidget()
        for column_index in range(0,self.total_columns):
            header_item = self.parentWidget().horizontalHeaderItem(column_index)
            header_item.setText(self.header_labels[column_index])
        self.track_move = False
        self.setVisible(True)
        self.updateGeometries()
        
    def mousePressEvent(self,event):
        self.track_move = False
        self.click = event.pos()
        self.click_original = event.pos()

        self.currentSectionRects = []
        for column_index in range(0,self.total_columns):
            self.updateGeometries()
            self.currentSectionRects.append(QtCore.QRect())
            self.currentSectionRects[column_index].setRect(self.sectionViewportPosition(column_index), 0, self.sectionSize(column_index), self.viewport().height())
            if abs(self.currentSectionRects[column_index].right()-self.click.x())<4:
                self.track_move = True
                self.click = QtCore.QPoint(self.currentSectionRects[column_index].right(),0)

        for column_index in range(0,self.total_columns):
            self.setSectionResizeMode(column_index,QtWidgets.QHeaderView.Interactive)
        QtWidgets.QHeaderView.mousePressEvent(self, event)
        
        cursor_shape = self.cursor().shape()
        if cursor_shape == QtCore.Qt.CursorShape.SplitHCursor:
            self.track_move = True
        else:
            self.track_move = False
            
        if self.track_move:
            self.distances_from_right = []
            for column_index in range(0,self.total_columns):
                right = self.currentSectionRects[column_index].right()
                distance = abs(right - self.click.x())
                self.distances_from_right.append(distance)
            
            min_distance = 10000
            min_index = -1
            for column_index in range(0,self.total_columns):
                distance = self.distances_from_right[column_index]
                if distance<min_distance:
                    min_index = column_index
                    min_distance = distance
            self.min_index = min_index
    
    def mouseMoveEvent(self,event):
        self.moved = event.pos()
        if self.track_move:
            column_index = self.min_index
            self.updateGeometries()
            currentSectionRect = QtCore.QRect()
            currentSectionRect.setRect(self.sectionViewportPosition(column_index), 0, self.sectionSize(column_index), self.viewport().height())
            if self.click.x()>self.moved.x():
                column_width = self.table.columnWidth(column_index)
                if column_width<=self.columns_min_width[column_index]:
                    event.ignore()
                    self.setSectionResizeMode(column_index,QtWidgets.QHeaderView.Interactive)
                    self.table.setColumnWidth(column_index,self.columns_min_width[column_index])
                    self.setSectionResizeMode(column_index,QtWidgets.QHeaderView.Fixed)
                    return None
                else:
                    self.setSectionResizeMode(column_index,QtWidgets.QHeaderView.Interactive)
                    QtWidgets.QHeaderView.mouseMoveEvent(self, event)           
            else:
                self.setSectionResizeMode(column_index,QtWidgets.QHeaderView.Interactive)
                QtWidgets.QHeaderView.mouseMoveEvent(self, event)           
        else:
            QtWidgets.QHeaderView.mouseMoveEvent(self, event)
        
    def mouseReleaseEvent(self,event):
        self.track_move = False
        QtWidgets.QHeaderView.mouseReleaseEvent(self, event)
        for column_index in range(0,self.total_columns):
            self.setSectionResizeMode(column_index,QtWidgets.QHeaderView.Interactive)       

        
if __name__ == "__main__":
    program = Run_me()

With this scripts i want to set a minimum width constraint when the user decides to resize a column.

The problem with this scripts is: Sometimes while pressing in resize area with the SplitHCursor and resize starts, the resize proccess stops but the cursor shape is still SplitHCursor. I don't know why this is happens.

If you find any other bug, or simpler solution feel free to answer or comment.

0

There are 0 best solutions below