2010-09-22 182 views
7

我使用QTableView和QItemDelegate的子類來控制tableview單元格的外觀。高效更新QTableView高速更新

每個單元格顯示外部連接設備的名稱和狀態,一次最多可連接100個設備。

每個設備的名稱和類型基本都是靜態的,很少更新(可能每小時一次),但每個單元需要顯示設備輸入的實時值,目前我每50毫秒進行一次輪詢。該值顯示爲由TableView提供給Delegate :: paint()方法的畫家繪製的基本條形圖。

每秒更新我的模型20次的問題是整個表格每次都會重新繪製,這是非常低效的。將繪圖方法限制爲僅繪製條形圖顯示大多數CPU時間專用於繪製每個單元格上的名稱,狀態和關聯圖像,而不是圖形。

我需要找到的方法是定期更新每個單元格的圖形而不重繪單元格,但我無法弄清楚如何去做。

達到此目的的最有效方法是什麼?

編輯:圖像附加幫助。

圖像代表QTableView中的10個傳感器。數字,名稱和狀態幾乎是靜態的,幾乎不會更新。 「傳感器值」文本旁邊的條形圖每隔50ms更新一次。我只想畫這個欄,而不是文字,狀態和單元格背景。狀態燈和背景是複雜的圖像,因此比簡單繪製和填充矩形要花費更多的CPU時間。

alt text

+0

該狀態是否需要與其他所有內容位於相同的小部件中?我的第一個想法是在同一個模型旁邊粘貼一個ListView。 – 2010-09-22 14:14:50

+0

是的,不幸的是它。每個設備都有一些參數需要放在圖的旁邊。我確實想過有兩種觀點,可能是重疊的,但它看起來像是一種非常混亂的方式來實現我想要的東西,並且使得改變模型,編輯等變得更加困難。 – Dani 2010-09-22 14:48:07

回答

6

因爲你QTableView中繼承了QWidget,你可以調用它的下面:

setUpdatesEnabled(false); 
changeAllYourData(); 
setUpdatesEnabled(true); 

當setUpdatesEnabled是假的,任何油漆()或update()調用它沒有任何效果。所以,你可以阻止它更新,改變你的所有數據,然後重新啓用它,可能通過手動調用paint()或update()來實現,我不確定這部分。

以下是setUpdatesEnabled方法的文檔。

QWidget updatesEnabled

希望這會有所幫助。從用戶的評論後

編輯:

你可以實現自己的setUpdatesEnabled(布爾)爲您QItemDelegate子類執行原稿前(因爲它沒有繼承QWidget的,沒有之一)通過測試標誌paint()或update()。 之後,您可以爲QTableView的每個單元格(或行或列)指定是否必須更新或重新繪製它們。

通過這樣做,除非您更改手動創建的setUpdatesEnabled標誌,而是在包含圖形的單元格上保留更新,否則可以阻止其他單元(委託)進行重新繪製。

我必須說我從來沒有測試過這個或其他類似的東西,所以我希望它能像我認爲的那樣工作。從用戶編輯後

最好的運氣

編輯:

按照我以前的評論,而不是設置標誌,每一個細胞(我想你的圖是在一個單獨的單元格),你可以爲每個代表設置一個標誌,只繪製您的圖形或整個圖像。

希望這有助於

編輯:

我的Qt 4.7偶然發現了一個新的功能(我不知道是否有可能爲你使用它,但它可以解決你的一些問題)。 該功能是QStaticText。它是一個允許您緩存文本(字體和效果)並更快地繪製它們的類。請參閱鏈接here

希望它能解決您的問題。

+1

我實際上已經這樣做了,所以我只更新模型每秒20次,而不是20×numberOfDevices,但它不能解決問題以及圖形,我正在繪製背景圖像,名稱字符串,狀態字符串以及各種其他顯示器,這些顯示器本身只會以低得多的速率更新。 – Dani 2010-09-22 14:45:58

+0

是你想單獨寫在單元格中的圖表嗎? – Live 2010-09-22 14:48:59

+0

不,它包含在其他信息中。我已將圖像附加到原始問題以幫助可視化GUI。 – Dani 2010-09-22 15:02:50

1

將背景圖像(單元格背景圖像,狀態和名稱)作爲QPixmap緩存到模型中。僅在狀態或名稱更改時重新繪製像素圖。在常見情況下,您只需要繪製緩存的QPixmap和傳感器值就可​​以了。

編輯:

添加fullRepaintNeeded標誌,以您的數據類。當狀態或名稱更改時,fullRepaintNeeded設置爲true。

委託人在繪製物品時,委託人首先檢查物品的fullRepaintNeeded標誌。如果fullRepaintNeeded爲true,則創建一個新的QPixmap,並將所有內容都繪製到最終繪製到tableview的QPixmap上。然後將QPixmap與模型的setData函數(但不調用dataChanged)緩存到模型(這意味着您的數據類)。 fullRepaintNeeded現在設置爲false。

但是,如果在委託的繪圖函數中fullRepaintNeeded爲false,則先前緩存的QPixmap會從模型中被詢問,然後繪製到tableview,最後傳感器值將被繪製在最上面。

+0

太好了,沒有想到這一點。 – Live 2010-09-22 16:10:18

+0

這就是我想要做的,但我該如何去做呢?只有一個繪畫例程,並且只有一個dataChanged()插槽。理想情況下,我需要兩個,但是我使用哪一個QPainter對象作爲另一個? 我已經開始使用Live的標誌方法實現這一點,我會看看它是如何實現的。 – Dani 2010-09-22 16:20:22

+0

我剛試過這個。繪圖程序的工作原理與您所描述的完全相同,結果如下:設置標誌時,單元格被清除,然後繪製圖形。在更新其他值(或更改選擇)時,它只有最多50ms,直到下一個圖形更新,然後清除單元格並再次繪製條形圖。 – Dani 2010-09-22 16:45:51

2

我很少會提出這條道路,而不是代表,但在您的情況下它可能是值得的。我會考慮製作我自己的視圖,這足以讓我們更新屏幕上需要更新的部分。像這樣的視圖小部件顯然比通常情況下更具特殊用途,但如果您真的需要效率,那麼這是一條可行的路。

如果您只需要提高效率,還需要考慮其他事項,以確保您只標記實際更改的行(如果傳感器值不會經常更改並且僅經常進行輪詢)或考慮添加一個滯後值,在這個值之間,它實際上沒有重繪(如果傳感器值沒有足夠快地改變以否定這個)。

+0

這是我去過的路線;創造我自己的觀點。我已經採取了Roku的建議,並使用QGLWidget來處理渲染,因此我看到數百個設備的CPU使用率爲3%,比以前更短的時間間隔刷新。 – Dani 2010-09-28 09:16:42

+0

@Dani晚會有點晚,但這個問題可以從你在這種方法中學到的東西中大大受益。 – UmNyobe 2016-03-08 10:47:43