1 需求描述
设计一个类似于VS的日志输出窗口,点击某一行后内容能够自动展开,改变列宽时,选中行能够根据日志内容自动调整高度。同时提供一些常用的功能,例如复制、显示/隐藏列、日志分类显示、显示状态恢复等。
2 设计思路
这是一个实际项目中的一个控制台功能模块,用于显示日志信息,日志分为错误、警告、消息三大类;当时主要考虑实现要尽可能简单,所以优先想到了QTreeWidget、QTableWidget,使用QTreeWidget效果不大理想,主要是在选中行时和改变列宽时自动展开功能,在网上也查询了一些方案,都不理想。
后来发现Qt提供的一个接口QTableView::resizeRowToContents,好了,一切由此展开。
3 代码实现
这里主要是通过继承QTableWidget实现相关功能,为了实现一定美观,对TableWidget进行下简单的设置:
setShowGrid(false);
setFocusPolicy(Qt::NoFocus);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::SingleSelection);
setEditTriggers(QAbstractItemView::NoEditTriggers);
verticalHeader()->setDefaultSectionSize(DEFAULT_SECTION_SIZE);
首先,关闭网格显示;取消焦点,主要是屏蔽选中时的虚线框;
当然还要设置为单选行、不可编辑模式;同时设置了一个默认的行高。
同时呢,选中行时我们需要设置下选中样式,这里用QSS处理下:
QTableWidget {
selection-background-color: #3399ff;
selection-color: white;
}
当某一行被选中后我们需要处理一下:
void OutputWidget::onCurrentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous)
{
if (previous)
{
setRowHeight(this->row(previous), DEFAULT_SECTION_SIZE);
}
resizeRowToContents(this->row(current));
}
这里设置一个默认的行高,当选中行改变时,上一次选中行恢复默认行高,当然也可以不处理,根据需求来。
当列宽改变时,我们也要做下处理:
QHeaderView *header = horizontalHeader();
header->setHighlightSections(false);
connect(header, &QHeaderView::sectionResized, [=]() {
QTableWidgetItem *currentItem = this->currentItem();
if (!currentItem)
{
return;
}
resizeRowToContents(this->row(currentItem));
});
这里主要通过监听QHeaderView的sectionResized信号实现。
好啦,按逻辑来讲到这里应该就可以了,但是使用过程中发现一点点问题,选中行改变时可能会串,额外处理下:
connect(this, &OutputWidget::itemPressed, this, [=](QTableWidgetItem *item) {
setCurrentItem(item);
});
到此,基本功能就实现了,其他功能需要自行拓展,或者联系我定制开发,哈哈。
4 总结
大道至简,编程也一样,在满足需求的情况下,实现要尽可能简单,Qt提供的一些便捷类,例如QListWidget、QTreeWidget、QTableWidget等是能够满足绝大多数使用场景的。一般来说,真实的使用场景也并不会有多复杂,是我们想得太复杂而已。