【问题标题】:QTableView header word wrapQTableView 标题自动换行
【发布时间】:2017-07-13 15:04:43
【问题描述】:

我正在尝试将 QTableView 中的水平和垂直标题设置为自动换行,但没有任何成功。

我想将所有列设置为相同的宽度(包括垂直标题),并且将具有多行文本的那些列设置为自动换行。如果 word 比列宽,它应该向右省略。 我已经设法使用 QTableView -> Horizo​​ntalHeader() -> setTextElideMode(Qt::ElideRight) 设置了省略号,但是由于 QHeaderView 没有 setWordWrap 方法,所以我不能对自动换行做同样的事情。因此,如果文本是多行的,它只会省略。在表格视图上设置自动换行不会做任何事情。表格单元格仅包含少量数字,因此问题仅在于标题,我想避免使用“/n”,因为标题是动态设置的。是否有其他一些我更改的设置不允许自动换行功能?

【问题讨论】:

    标签: qt


    【解决方案1】:

    我能够整合上述两种方法(c++,Qt 5.12),结果非常好。 (模型上没有隐藏头)

    1. 覆盖 QHeaderView::sectionSizeFromContents() 以使大小考虑文本换行
    QSize MyHeaderView::sectionSizeFromContents(int logicalIndex) const 
    {
        const QString text = this->model()->headerData(logicalIndex, this->orientation(), Qt::DisplayRole).toString();
        const int maxWidth = this->sectionSize(logicalIndex);
        const int maxHeight = 5000; // arbitrarily large
        const auto alignment = defaultAlignment();
        const QFontMetrics metrics(this->fontMetrics());
        const QRect rect = metrics.boundingRect(QRect(0, 0, maxWidth, maxHeight), alignment, text);
    
        const QSize textMarginBuffer(2, 2); // buffer space around text preventing clipping
        return rect.size() + textMarginBuffer;
    }
    
    1. 将默认对齐方式设置为自动换行(可选,居中)
     tableview->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter | (Qt::Alignment)Qt::TextWordWrap);
    

    【讨论】:

      【解决方案2】:

      我已经设法使用QHeaderView 的子类化并在其中重新实现sectionSizeFromContentspaintSection 方法找到了解决方案。这是 PyQt5 中的演示(使用 Python 3.5.2 和 Qt 5.6 测试):

      import sys
      import string
      import random
      from PyQt5 import QtCore, QtWidgets, QtGui
      
      class HeaderViewWithWordWrap(QtWidgets.QHeaderView):
          def __init__(self):
              QtWidgets.QHeaderView.__init__(self, QtCore.Qt.Horizontal)
      
          def sectionSizeFromContents(self, logicalIndex):
              if self.model():
                  headerText = self.model().headerData(logicalIndex,
                                                       self.orientation(),
                                                       QtCore.Qt.DisplayRole)
                  options = self.viewOptions()
                  metrics = QtGui.QFontMetrics(options.font)
                  maxWidth = self.sectionSize(logicalIndex)
                  rect = metrics.boundingRect(QtCore.QRect(0, 0, maxWidth, 5000),
                                              self.defaultAlignment() |
                                              QtCore.Qt.TextWordWrap |
                                              QtCore.Qt.TextExpandTabs,
                                              headerText, 4)
                  return rect.size()
              else:
                  return QtWidgets.QHeaderView.sectionSizeFromContents(self, logicalIndex)
      
          def paintSection(self, painter, rect, logicalIndex):
              if self.model():
                  painter.save()
                  self.model().hideHeaders()
                  QtWidgets.QHeaderView.paintSection(self, painter, rect, logicalIndex)
                  self.model().unhideHeaders()
                  painter.restore()
                  headerText = self.model().headerData(logicalIndex,
                                                       self.orientation(),
                                                       QtCore.Qt.DisplayRole)
                  painter.drawText(QtCore.QRectF(rect), QtCore.Qt.TextWordWrap, headerText)
              else:
                  QtWidgets.QHeaderView.paintSection(self, painter, rect, logicalIndex)
      
      class Model(QtCore.QAbstractTableModel):
          def __init__(self):
              QtCore.QAbstractTableModel.__init__(self)
              self.model_cols_names = [ "Very-very long name of my first column",
                                        "Very-very long name of my second column",
                                        "Very-very long name of my third column",
                                        "Very-very long name of my fourth column" ]
              self.hide_headers_mode = False
              self.data = []
              for i in range(0, 10):
                  row_data = []
                  for j in range(0, len(self.model_cols_names)):
                      row_data.append(''.join(random.choice(string.ascii_uppercase +
                                              string.digits) for _ in range(6)))
                  self.data.append(row_data)
      
          def hideHeaders(self):
              self.hide_headers_mode = True
      
          def unhideHeaders(self):
              self.hide_headers_mode = False
      
          def rowCount(self, parent):
              if parent.isValid():
                  return 0
              else:
                  return len(self.data)
      
          def columnCount(self, parent):
              return len(self.model_cols_names)
      
          def data(self, index, role):
              if not index.isValid():
                  return None
              if role != QtCore.Qt.DisplayRole:
                  return None
      
              row = index.row()
              if row < 0 or row >= len(self.data):
                  return None
      
              column = index.column()
              if column < 0 or column >= len(self.model_cols_names):
                  return None
      
              return self.data[row][column]
      
          def headerData(self, section, orientation, role):
              if role != QtCore.Qt.DisplayRole:
                  return None
              if orientation != QtCore.Qt.Horizontal:
                  return None
              if section < 0 or section >= len(self.model_cols_names):
                  return None
              if self.hide_headers_mode == True:
                  return None
              else:
                  return self.model_cols_names[section]
      
      class MainForm(QtWidgets.QMainWindow):
          def __init__(self, parent=None):
              QtWidgets.QMainWindow.__init__(self, parent)
              self.model = Model()
              self.view = QtWidgets.QTableView()
              self.view.setModel(self.model)
              self.view.setHorizontalHeader(HeaderViewWithWordWrap())
              self.setCentralWidget(self.view)
      
      def main():
          app = QtWidgets.QApplication(sys.argv)
          form = MainForm()
          form.show()
          app.exec_()
      
      if __name__ == '__main__':
          main()
      

      【讨论】:

      • 我能够将您的代码迁移到 C++ 并获得标题来换行文本。但是当重新实现paintSection 方法时,我们只是设置了纯文本,标题中的所有其他内容(如背景、边框等)都消失了,看起来很难看。有没有办法只设置文本而不改变其余的样式?
      • 没有好的通用方法,但我发现了一种略显老套的方法,现在更新了答案。基本上,您可以按如下方式实现paintSection: 1. 告诉模型隐藏标题数据,即返回空数据; 2. 调用父类的paintSection 方法,以便绘制除文本(为空)之外的所有内容; 3. 告诉模型停止隐藏头部数据; 4. 检索标题数据并绘制其文本
      【解决方案3】:

      来自 2010 年的 open Qt issue 表明这可能并不容易。 但是,根据 2015 年的唯一评论,对于这个问题有一个简单的解决方法,如下所示:

         myTable->horizontalHeader()->setDefaultAlignment(Qt::AlignCenter | (Qt::Alignment)Qt::TextWordWrap);
      

      我刚刚使用 Qt 5.12 进行了测试,幸运的是发现它仍然可以工作。

      【讨论】:

        【解决方案4】:

        在python中:

        myTableView.horizontalHeader().setDefaultAlignment(Qt.AlignCenter | Qt.Alignment(Qt.TextWordWrap))

        【讨论】:

        • 您为此使用了哪个导入。是from PyQt5 import QtWidgets, QtCore; from PyQt5.QtCore import Qt; from PyQt5.QtWidgets import *
        • @SAndrew from PyQt5.QtCore import Qt
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-20
        • 2018-07-26
        • 1970-01-01
        相关资源
        最近更新 更多