QTableView: интерактивное изменение размера столбца без QHeaderView

У меня есть QTableView со скрытым горизонтальным заголовком

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

Нет просмотра заголовка

Как видите, текст в центральной колонке обрезан из-за ширины колонки.

Чтобы просмотреть текст, пользователю нужно будет изменить размер столбца, но без заголовка я не могу этого сделать.

То, что я хотел бы сделать, это навести указатель мыши на край столбца и отобразить значок обычного изменения размера, а затем позволить пользователю перетаскивать столбец шире.

Это возможно?


person Steve Lorimer    schedule 09.05.2017    source источник
comment
Возможно, решение состоит в том, чтобы добавить кнопку для изменения размера всех столбцов с помощью ResizeColumnsToContents.   -  person Michael O.    schedule 09.05.2017


Ответы (1)


Есть что-то для работы с использованием фильтров событий и следующих двух классов...

/*
 * 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 в каком-то старом примере кода, который я нашел, дала желаемый эффект — спрайт курсора меняется, когда мышь находится над границей столбца, и соответствующую границу можно перетащить.

Не уверен, насколько это близко к тому, что вам нужно, но...

person G.M.    schedule 09.05.2017