2010-08-13 42 views
3

我想使字符串網格顯示某種垂直光標以突出顯示當前所選列。因此,在MouseDown中我調用setCurPos,然後調用InvalidateCol使當前列無效。這將調用DrawCell。 DrawCell繪製當前列上的光標。調用InvalidateCol()時不會刷新TStringGrid()

問題是這樣的:如果我有更多的格列就可以顯示他們中的一些是不可見的(當然),所以網格的垂直滾動條會自動出現。當我向下滾動查看網格底部的行時,遊標不會繪製在這些行中。它看起來像光標未被繪製的底部行數(現在在屏幕上可見)與網格頂部的不可見行數成比例。

如果我最小化和恢復應用程序,光標很好地畫。所以,顯然invalidateColumn()不起作用。

procedure TmyGrid.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); 
VAR aCol, aRow: Integer; 
begin 
MouseToCell(X, Y, ACol, ARow); 
...                 
    inherited MouseDown(Button, Shift, X, Y); 
    CursorPosFocus:= ACol;       
end; 


procedure TmyGrid.setCurPos(CONST NewColumn: Integer);     
VAR OldPos: Integer; 
begin 
... 
OldPos:= CursorPos; 
FCursorPos:= NewColumn;  
... 
//- This is not working: 
//InvalidateCol(OldPos); 
//InvalidateCol(NewColumn);  
//Update; 

//- THIS WORKS: 
InvalidateGrid; 
end; 


procedure TmyGrid.DrawCell(ACol, ARow: integer; ARect: TRect; AState: TGridDrawState); 
Var TempRect: TRect; 
begin 
inherited; 
    ... 

{DRAW CURSOR} 
if CursorPos= ACol then 
    begin 
    TempRect.Top := 0; 
    TempRect.Left := ARect.Left; 
    TempRect.Right := ARect.Right; 
    TempRect.Bottom:= ClientHeight-2;  
    Frame3D(Canvas, TempRect, $909090, $808080, 1);  
    end; 
end; 

德爾福7,Win XP的

回答

4

你沒有做錯什麼,你剛剛由VCL網格實現中的錯誤已經在德爾福4 VCL(我沒有任何早期CD這裏檢查抓住了,但它甚至可能已經在已經有16位Delphi VCL),並且仍然在Delphi 2009中。

通過計算傳遞給內部InvalidateRect()方法的單元格區域來使整行或列失效的兩種方法都可以做到這一點。該區域始終以列/行0開始,並延伸至第一個完全不可見的行/列。很明顯,這隻會對未捲入的客戶區域正常工作。代碼應該做的是對最後一列/行無效,並讓InvalidateRect()助手中的代碼找出哪些單元格確實可見,並計算出需要使其失效的客戶區。

由於您正在編寫自己的類,您可以輕鬆實現自己的方法來使正確的單元格範圍無效;我在很多年前也做了同樣的事情,還有更多的方法使多列,多行和整個單元塊無效。由於InvalidateRect()是私有的(也有很好的想法),因此您需要使用具有相同名稱的Windows API函數,並使用CellRect()BoxRect()方法計算要失效的矩形。

雖然InvalidateGrid()確實爲你工作,它確實是一種大錘 - 它使整個電網無效,當你開始使用InvalidateCol()時,我認爲這不是你想要的。

對於您的實驗,您應該使每個單元的塗料循環易於可見。每次更新都會導致單元格的背景顏色發生變化,這是檢查您是否只進行最小屏幕重繪的簡單方法。像

StringGrid1.Canvas.Brush.Color := RGB(Random(256), Random(256), Random(256)); 
StringGrid1.Canvas.FillRect(Rect); 

OnDrawCell事件處理程序工作正常。

+0

非常感謝您的回答。多年來我一直在討厭bug的存在。這就是爲什麼我很久以前就停止在Borland的網站上報告錯誤的原因。這是浪費時間。我現在將使用InvalidateGrid。但是,在將來我打算將它用於大型網格,所以我將不得不應用您的解決方案。 – Ampere 2010-08-22 19:33:56

+0

我同意你的觀點,德爾福的bug。關於網格大小 - 網格是大還是小是無關緊要的,因爲只有可見單元受到InvalidateXXX()影響,並且對於繪畫性能而言,可見區域是否爲50%或0.05%是無關緊要的整個電網。但是如果你不需要最大的繪畫性能,只需使用'InvalidateGrid()'或甚至'Invalidate()'。否則,使用自定義的'InvalidateCol()',並在多次調用之間調用'Update()',以防止Windows將多個不相鄰的區域合併爲一個較大的區域。 – mghie 2010-08-22 20:11:45

0

解決方案:
大量實驗後,我意識到,但是InvalidateGrid工作。

我很高興與此解決方案,但我真的不與意外編程同意。我仍然想知道我做錯了什麼。爲什麼列沒有被InvalidateCol()失效。