代码之家  ›  专栏  ›  技术社区  ›  Gediminas

使用垂直网格线通过鼠标调整QTableView列的大小

qt
  •  0
  • Gediminas  · 技术社区  · 7 年前

    我有一个 QTableView 带有隐藏的水平标题

    table->horizontalHeader()->hide();
    

    No header view

    如您所见,由于列宽的原因,中间列中的文本被剪裁。

    要查看文本,用户需要调整列的大小,但如果没有标题,我无法这样做。

    我希望能够做的是将鼠标悬停在列的边缘,并显示正常的调整大小图标,然后允许用户将列拖得更宽。

    这可能吗?

    0 回复  |  直到 9 年前
        1
  •  4
  •   G.M.    9 年前

    使用事件过滤器和以下两个类可以工作。。。

    /*
     * Subclass of QTableView that provides notification when the mouse cursor
     *  enters/leaves a column boundary.
     */
    class headerless_table_view: public QTableView {
      using super = QTableView;
    public:
      explicit headerless_table_view (QWidget *parent = nullptr)
        : super(parent)
        , m_boundary_width(10)
        , m_column_index(-1)
        {
          viewport()->setMouseTracking(true);
          viewport()->installEventFilter(this);
        }
    
      /*
       * @return The index of the column whose right hand boundary the cursor lies
       *         on or -1 if not on a boundary.
       */
      int column_index () const
        {
          return(m_column_index);
        }
    protected:
      virtual bool eventFilter (QObject *obj, QEvent *event) override
        {
          if (event->type() == QEvent::MouseMove) {
            if (auto *e = dynamic_cast<QMouseEvent *>(event)) {
              auto col_left = columnAt(e->pos().x() - m_boundary_width / 2);
              auto col_right = columnAt(e->pos().x() + m_boundary_width / 2);
              bool was_on_boundary = m_column_index != -1;
              if (col_left != col_right) {
                if (m_column_index == -1) {
                  if (col_left != -1) {
                    m_column_index = col_left;
                  }
                }
              } else {
                m_column_index = -1;
              }
              bool is_on_boundary = m_column_index != -1;
              if (is_on_boundary != was_on_boundary) {
                entered_column_boundary(is_on_boundary);
              }
            }
          }
          return(super::eventFilter(obj, event));
        }
    
      /*
       * Called whenever the cursor enters or leaves a column boundary.  if
       * `entered' is true then the index of the column can be obtained using
       * `column_index()'.
       */
      virtual void entered_column_boundary (bool entered)
        {
        }
    private:
      int  m_boundary_width;
      int  m_column_index;
    };
    
    /*
     * Subclass of headerless_table_view that allows resizing of columns.
     */
    class resizable_headerless_table_view: public headerless_table_view {
      using super = headerless_table_view;
    public:
      explicit resizable_headerless_table_view (QWidget *parent = nullptr)
        : super(parent)
        , m_dragging(false)
        {
          viewport()->installEventFilter(this);
        }
    protected:
      virtual bool eventFilter (QObject *obj, QEvent *event) override
        {
          if (auto *e = dynamic_cast<QMouseEvent *>(event)) {
            if (event->type() == QEvent::MouseButtonPress) {
              if (column_index() != -1) {
                m_mouse_pos = e->pos();
                m_dragging = true;
                return(true);
              }
            } else if (event->type() == QEvent::MouseButtonRelease) {
              m_dragging = false;
            } else if (event->type() == QEvent::MouseMove) {
              if (m_dragging) {
                int delta = e->pos().x() - m_mouse_pos.x();
                setColumnWidth(column_index(), columnWidth(column_index()) + delta);
                m_mouse_pos = e->pos();
                return(true);
              }
            }
          }
          return(super::eventFilter(obj, event));
        }
    
      /*
       * Override entered_column_boundary to update the cursor sprite when
       * entering/leaving a column boundary.
       */
      virtual void entered_column_boundary (bool entered) override
        {
          if (entered) {
            m_cursor = viewport()->cursor();
            viewport()->setCursor(QCursor(Qt::SplitHCursor));
          } else {
            viewport()->setCursor(m_cursor);
          }
        }
    private:
      bool    m_dragging;
      QPoint  m_mouse_pos;
      QCursor m_cursor;
    };
    

    最后我把它分成了两个班,因为它看起来更干净。

    不管怎样,只要更换 QTableView 具有 resizable_headerless_table_view 在我发现的一些旧示例代码中,似乎达到了预期效果——当鼠标位于列边界上时,光标精灵会发生变化,并且可以拖动相关的边界。

    不确定它离你想要的有多近,但是。。。