2010-08-13 3 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, 윈 XP

답변

4

당신은 아무 것도하지 않고 있습니다. 델파이 4 VCL에있는 VCL 그리드 구현의 버그로 인해 막 잡혔습니다 (이전의 CD는 확인하지 않았지만, 이미 16 비트 델파이 VCL을 사용하고 있습니다.

전체 행이나 열을 무효화하는 두 가지 방법 모두 내부 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

답장을 보내 주셔서 감사합니다. 나는 몇 년 동안 버그가있을 때 나는 싫어.이것이 내가 볼랜드의 웹 사이트에 버그를보고하기 위해 오래 전에 중단 한 이유입니다. 그것은 시간 낭비입니다. 나는 지금 InvalidateGrid를 사용할 것이다. 그러나 미래에는 대형 그리드와 함께 사용할 계획이므로 솔루션을 적용해야합니다. – Ampere

+0

나는 당신의 감정과 Delphi 버그에 동의합니다. 그리드 크기와 관련하여 그리드가 크거나 작 으면 보이지 않는 셀은'InvalidateXXX()'의 영향을 받고 그리기 성능은 보이지 않는 영역이 50 % 또는 0.05 %인지 여부와 관계가 없습니다 전체 그리드 그러나 최대 페인트 성능이 필요하지 않다면 단순히 InvalidateGrid() 또는 Invalidate()를 사용하십시오. 그렇지 않으면 커스텀'InvalidateCol()'을 사용하고 여러 호출 사이에'Update()'를 호출하여 Windows가 인접하지 않은 여러 영역을 하나의 큰 영역으로 결합하지 않도록하십시오. – mghie

0

솔루션 :
실험을 많이 한 나는 그러나 InvalidateGrid가 작동하고 있음을 깨달았다.

이 솔루션에 만족하지만 실수로 프로그래밍하는 것에 동의하지 않습니다. 나는 아직도 내가 뭘 잘못하고 있는지 알고 싶다. InvalidateCol()에 의해 열이 무효화되지 않는 이유는 무엇입니까?

관련 문제