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等是能夠滿足絕大多數使用場景的。一般來說,真實的使用場景也並不會有多複雜,是我們想得太複雜而已。