5

I have a QTableView with a hidden horizontal header

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

No header view

As you can see, the text in the central column is clipped because of the column width.

To view the text, the user would need to resize the column, but without a header, I am unable to do this.

What I would like to be able to do is hover my mouse over the edge of the column and have the normal resize icon appear, and then allow the user to drag the column wider.

Is this possible?

Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213

1 Answers1

6

Got something to work using event filters and the following two classes...

/*
 * 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;
};

I ended up splitting it across two classes as it seemed cleaner.

Anyway, simply replacing QTableView with resizable_headerless_table_view in some old example code I found seemed to have the desired effect -- the cursor sprite changes when the mouse is over a column boundary and the relevant boundary can be dragged.

Not sure how close it is to what you're after, but...

G.M.
  • 12,232
  • 2
  • 15
  • 18