[Из песочницы] Как сделать адекватное отображение horizontal scroll bar в QTreeWidget с одной колонкой

habr.png

Привет, Хабр.


В этой статье я решил оставить решение проблемы непонятного поведения QTreeWidget — GUI компонента кроссплатформенного фреймворка Qt. Проблема, мне кажется, актуальная, потому что вопрос задаётся на многих форумах, но верного решения не приводится. Впрочем, если я ошибаюсь, НЛО мне об этом сообщит.


Проблема


В Qt есть компонент QTreeWidget, предназначенный для древовидного отображения информации. Элементом или узлом дерева может быть текст с картинкой, или же другой виджет.


В ходе эксплуатации этого компонента у некоторых пользователей возникает проблема, когда текст элемента или узла не помещается в ширину виджета, и компонент при этом не позволяет пользователю скролить содержимое влево/вправо чтобы тот мог прочитать текст целиком. Вместо этого появляется троеточие в конце текста. Проблема встречается в случаях использования виджета с одной колонкой, или с несколькими (тогда проблема возникает в последней колонке).


Никакое свойство класса QTreeWidget или его предков не даёт возможности активировать автоматическое изменение размера области просмотра колонки. Так что, если вы тоже столкнулись с этим недоразумением, прошу под кат.


Простое решение


Решение снизошло на мою головушку когда я читал документацию к QTreeWidget. Решение состоит в использовании следующего метода (слота) :


void QTreeView::resizeColumnToContents(int column);


Как можно догадаться, метод «подгоняет» размер колонки, номер которой передаётся в виде параметра, под размер содержимого. То, что как раз компонент должен делать сам, но не делает.


Применение решения


Если проблема возникает сразу после создания виджета (то есть пользователь ещё не успел ничего сделать, а текст уже не помещается), то в конструкторе виджета можно запустить цикл с применением этого метода ко всем колонкам (или только к последней) :


//применить ко всем колонкам
for(int i = 0; i < treeWidget->columnCount(); ++i)
        treeWidget->resizeColumnToContents(i);
//или применить только к последней
treeWidget->resizeColumnToContents(treeWidget->columnCount() - 1);


Если же нужно вместо этого (или вместе с этим) изменять размер колонки после раскрытия или сворачивания узла, то нужно воспользоваться следующими событиями (сигналами) :


void QTreeView::expanded(const QModelIndex &index); //раскрытие узла
void QTreeView::collapsed(const QModelIndex &index); //сворачивание узла


Нужно либо самостоятельно создать слоты для реагирования на эти сигналы и соединить их, либо сгенерировать всё это в один клик на форме (ПКМ по виджету на форме, «перейти к слоту», выбрать слот).


Так или иначе, слоты реагирования на события будут содержать только вызов уже знакомого нам метода :


void MainWindow::on_tree_widget_expanded(const QModelIndex &index)
{
    treeWidget->resizeColumnToContents(index.column());
}

void MainWindow::on_tree_widget_collapsed(const QModelIndex &index)
{
    treeWidget->resizeColumnToContents(index.column());
}


Здесь index.column () сообщает методу номер колонки, в которой произошло событие.


Итог


Вот таким костыльным незамысловатым способом можно научить компонент QTreeWidget делать то, что он должен и так уметь. Надеюсь что решение кому-то пригодится. Буду рад ответить на вопросы в комментариях. Спасибо за внимание.

© Habrahabr.ru