2015-11-30 9 views
1

Я пытаюсь реализовать замороженные (те, которые не прокручиваются, когда остальная часть сетки прокручивается по горизонтали) столбцы в QTreeView - как и в Excel.Каков хороший способ блокировки/замораживания столбцов в QTreeView

Я попытался найти какой-нибудь родной способ Qt, чтобы заморозить столбцы, но единственное, что я мог найти, это упоминание в QAbstractScrollArea::setViewportMargins, как упоминалось в сообщении this. Поэтому я последовал предложению в ответ на сообщение и наложил еще один QTreeView на ту же модель сверху. То есть теперь у меня есть 2 QTreeViews, один показывает только замороженные столбцы, а другой показывает остальные столбцы с горизонтальной прокруткой. Я подклассифицировал полный просмотр, так что пользователь не должен знать о замороженном виде и работать только с полным представлением.

Однако теперь я столкнулся с проблемой синхронизации: все изменения, внесенные в основной вид, и его заголовок должны быть зеркально отражены на замороженном виде и его заголовке соответственно. . если я вызываю mainView->header()->setStretchLastSection(false), тот же вызов должен быть реплицирован в заголовок замороженного представления. Тем не менее, у меня нет уведомлений при вызове метода. События DynamicPropertyChanged вызывается только тогда, когда вызывается setProperty, а не когда отдельный сеттер.

Итак, мои вопросы:

  1. Есть ли способ реализации замороженных столбцов, не имея несколько представлений?
  2. Как реализовать синхронизацию между основным и замороженным представлениями, чтобы замороженная вена соответствовала всем выполняемым в главном представлении и его заголовке?

Большое спасибо!

ответ

2

У меня была аналогичная проблема QTableView. В моем исследовании я не смог найти другой метод для создания замороженной таблицы с использованием единого представления. Поэтому я реализовал свой собственный пользовательский вид, который происходит из QTableview. Вы можете найти его here: файл

заголовка:

#pragma once 

//--- include files ------------------------------------------------------------- 

#include <QtGui/QTableView> 
#include <QtCore/QObject> 

class CustomTableView : public QTableView 
{ 
    Q_OBJECT 

public: 
    CustomTableView(QWidget *parent = 0); 
    ~CustomTableView(); 

    void setDataModel(QAbstractItemModel * model); 

    public slots: 
     void onSortComplete(); 

    private slots: 
     void updateSectionWidth(int logicalIndex,int, int newSize); 
     void updateSectionHeight(int logicalIndex, int, int newSize); 


    signals: 
     void onFrozenRowClicked(QModelIndex index); 

protected: 
    virtual void resizeEvent(QResizeEvent *event); 
    // virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers); 
    void scrollTo (const QModelIndex & index, ScrollHint hint = EnsureVisible); 

private: 

    void init(); 
    void updateFrozenTableGeometry(); 

    QTableView *m_frozenTvLast; 
    QTableView * m_frozenTvFirst; 

}; 

CPP файл

//--- include files ------------------------------------------------------------- 
#include <QtGui/QtGui> 
#include "UI/CustomTableView.h" 
#include "CustomTableView.moc" 

CustomTableView::CustomTableView(QWidget *parent/* = 0*/) 
{ 
    this->setParent(parent); 
    m_frozenTvLast = new QTableView(this); 
    m_frozenTvLast->setSelectionMode(QAbstractItemView::SingleSelection); 

    m_frozenTvFirst = new QTableView(this); 
    m_frozenTvFirst->setSelectionMode(QAbstractItemView::SingleSelection); 

    //connect the headers and scrollbars of both tableviews together 
    connect(horizontalHeader() 
     , SIGNAL(sectionResized(int,int,int)) 
     , this 
     , SLOT(updateSectionWidth(int,int,int))); 

    connect(verticalHeader() 
     , SIGNAL(sectionResized(int,int,int)) 
     , this 
     , SLOT(updateSectionHeight(int,int,int))); 

    connect(m_frozenTvLast->verticalScrollBar() 
     , SIGNAL(valueChanged(int)) 
     , verticalScrollBar() 
     , SLOT(setValue(int))); 

    connect(verticalScrollBar() 
     , SIGNAL(valueChanged(int)) 
     , m_frozenTvLast->verticalScrollBar() 
     , SLOT(setValue(int))); 

    connect(m_frozenTvLast 
     , SIGNAL(clicked(const QModelIndex &)) 
     , this 
     , SIGNAL(onFrozenRowClicked(const QModelIndex &))); 

    connect(m_frozenTvFirst->verticalScrollBar() 
     , SIGNAL(valueChanged(int)) 
     , verticalScrollBar() 
     , SLOT(setValue(int))); 

    connect(verticalScrollBar() 
     , SIGNAL(valueChanged(int)) 
     , m_frozenTvFirst->verticalScrollBar() 
     , SLOT(setValue(int))); 

    connect(m_frozenTvFirst 
     , SIGNAL(clicked(const QModelIndex &)) 
     , this 
     , SIGNAL(onFrozenRowClicked(const QModelIndex &))); 

} 

CustomTableView::~CustomTableView() 
{ 
    delete m_frozenTvLast; 
    delete m_frozenTvFirst; 
} 

void CustomTableView::setDataModel(QAbstractItemModel * model) 
{ 
    setModel(model); 
    init(); 
} 

void CustomTableView::init() 
{ 
    m_frozenTvLast->setModel(model()); 
    m_frozenTvFirst->setModel(model()); 

    m_frozenTvLast->setFocusPolicy(Qt::NoFocus); 
    m_frozenTvLast->verticalHeader()->hide(); 
    m_frozenTvLast->horizontalHeader()->setResizeMode(QHeaderView::Fixed); 

    m_frozenTvFirst->setFocusPolicy(Qt::NoFocus); 
    m_frozenTvFirst->verticalHeader()->hide(); 
    m_frozenTvFirst->horizontalHeader()->setResizeMode(QHeaderView::Fixed); 

    viewport()->stackUnder(m_frozenTvLast); 
    //viewport()->stackUnder(m_frozenTvFirst); 

    m_frozenTvLast->setStyleSheet("QTableView { border: none;" 
     /* "background-color: #8EDE21;"*/ 
      "selection-background-color: #999}"); 

    m_frozenTvFirst->setStyleSheet("QTableView { border: none;" 
     /* "background-color: #8EDE21;"*/ 
     "selection-background-color: #999}"); 

    m_frozenTvLast->setSelectionModel(selectionModel()); 
    m_frozenTvFirst->setSelectionModel(selectionModel()); 

    for(int col=0; col<8; col++) 
     m_frozenTvLast->setColumnHidden(col, true); 

    for(int col=2; col<=8; col++) 
     m_frozenTvFirst->setColumnHidden(col, true); 

    for(int i = 0 ; i+2 <= model()->rowCount() ; i = i+2) 
     m_frozenTvFirst->setSpan(i,0,2,1); 


     //horizontalHeader()->setResizeMode(8, QHeaderView::Fixed); 
     //horizontalHeader()->setResizeMode(1, QHeaderView::Fixed); 
     // frozenTableView->setColumnWidth(0, columnWidth(0)); 
    m_frozenTvLast->setColumnWidth(8, columnWidth(8)); 
    m_frozenTvFirst->setColumnWidth(0, columnWidth(0)); 
    m_frozenTvFirst->setColumnWidth(1, columnWidth(1)); 
    //frozenTableView->setColumnWidth(0, columnWidth(0)); 

    m_frozenTvLast->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    m_frozenTvLast->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    m_frozenTvLast->show(); 


    m_frozenTvFirst->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    m_frozenTvFirst->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    m_frozenTvFirst->show(); 


    updateFrozenTableGeometry(); 

    setHorizontalScrollMode(ScrollPerPixel); 
    setVerticalScrollMode(ScrollPerPixel); 
    m_frozenTvLast->setVerticalScrollMode(ScrollPerPixel); 
    m_frozenTvFirst->setVerticalScrollMode(ScrollPerPixel); 
} 

void CustomTableView::updateSectionWidth(int logicalIndex, int, int newSize) 
{ 

    m_frozenTvLast->setColumnWidth(logicalIndex,newSize); 
    m_frozenTvFirst->setColumnWidth(logicalIndex,newSize); 
    updateFrozenTableGeometry(); 

} 

void CustomTableView::updateSectionHeight(int logicalIndex, int, int newSize) 
{ 
    m_frozenTvLast->setRowHeight(logicalIndex, newSize); 
    m_frozenTvFirst->setRowHeight(logicalIndex, newSize); 
} 

void CustomTableView::resizeEvent(QResizeEvent * event) 
{ 
    QTableView::resizeEvent(event); 
    updateFrozenTableGeometry(); 
} 

/* 
QModelIndex FreezeTableWidget::moveCursor(CursorAction cursorAction, 
              Qt::KeyboardModifiers modifiers) 
{ 
     QModelIndex current = QTableView::moveCursor(cursorAction, modifiers); 

     if(cursorAction == MoveRight 
      && current.column()>0 
      && visualRect(current).topLeft().x() < frozenTableView->columnWidth(8)) 
     { 
      const int newValue = horizontalScrollBar()->value() 
       + visualRect(current).topLeft().x() 
       - frozenTableView->columnWidth(8); 

      horizontalScrollBar()->setValue(newValue); 
     } 
     return current; 
}*/ 

void CustomTableView::scrollTo (const QModelIndex & index, ScrollHint hint) 
{ 
    if(index.column()>0) 
     QTableView::scrollTo(index, hint); 
} 

void CustomTableView::updateFrozenTableGeometry() 
{ 
    int widthToAdd = verticalHeader()->width()+frameWidth()+viewport()->width() - columnWidth(8); 

    int allColumnWidth = verticalHeader()->width() + frameWidth(); 
    for(int col=0; col<8; col++) 
     allColumnWidth += columnWidth(col); 

    int toSet = 0; 
    if(widthToAdd < allColumnWidth) 
     toSet= widthToAdd; 
    else 
     toSet = allColumnWidth; 

    /*verticalHeader()->width()+frameWidth()+viewport()->width() - columnWidth(8)*/ 
    m_frozenTvLast->setGeometry(toSet 
     , frameWidth() 
     , columnWidth(8) +0.1 
     , viewport()->height()+horizontalHeader()->height()); 

    m_frozenTvFirst->setGeometry(verticalHeader()->width()+frameWidth() 
     , frameWidth() 
     , columnWidth(0) + columnWidth(1)+0.1 
     , viewport()->height()+horizontalHeader()->height()); 
} 

void CustomTableView::onSortComplete() 
{ 
    for(int i = 0 ; i+2 <= model()->rowCount() ; i = i+2) 
     m_frozenTvFirst->setSpan(i,0,2,1); 
} 

Как это работает:

  • Все зрения одни и те же DataModel
  • Все виды связаны друг с другом, поэтому, когда одно представление является cl icked другой также щелкается автоматически.
  • Для каждого замороженного столбца мы просто создаем новый вид и скрываем все остальные столбцы.
  • Для каждого вида, который был заморожен, мы отключили прокрутку.
  • Теперь мы должны расположить каждую колонку в нужном месте с информацией из основной таблицы.
  • Каждый раз, когда размер таблицы изменяется, мы пересчитываем положение и размер столбца.