【发布时间】:2014-02-26 23:26:00
【问题描述】:
使用 poUnbuffered 选项时,TVirtualStringTree 中的 PaintTree 逻辑似乎存在错误。只有树的第一个节点在输出中可见。我使用 Minimal VST 示例进行了测试,并且行为是相同的。当 poUnbuffered 用作选项时,只有第一个节点可见,删除该选项并正确绘制树。
如果我单步执行代码,那么所有对象都被绘制在画布上,因此看起来像是一个剪切问题,但我使用 VST 的工作不足以确定问题所在。他们在画布原点和剪裁方面发挥了很多作用。
要查看实际问题,只需将以下代码放在任何包含 VST 的表单上,根据需要更改名称以保护无辜者,然后点击离开。
procedure TMainForm.Button2Click(Sender: TObject);
var
saveBitmap: TBitmap;
begin
saveBitmap := TBitmap.Create;
try
saveBitmap.height := 400;
saveBitmap.width := 400;
vst.PaintTree(
saveBitmap.Canvas,
Rect(0, 0, 400, 400),
Point(0, 0),
[poBackground, poColumnColor, poGridLines, poUnbuffered], // Remove poUnbuffered to have the tree paint correctly
pfDevice // pixelformat
);
saveBitmap.SaveToFile('E:\temp\CanvasSave' + FormatDateTime('hhnnsszzz', Now) + '.bmp');
finally
saveBitmap.Free;
end;
end;
以前有人遇到过这种情况吗?
更多细节:
poUnbuffered 的绘制代码和没有它的绘制代码之间几乎没有区别。我没有使用列,所以主要区别是:
if not (poUnbuffered in PaintOptions) then
begin
// Create small bitmaps and initialize default values.
// The bitmaps are used to paint one node at a time and to draw the result to the target (e.g. screen) in one step,
// to prevent flickering.
NodeBitmap := TBitmap.Create;
// For alpha blending we need the 32 bit pixel format. For other targets there might be a need for a certain
// pixel format (e.g. printing).
if MMXAvailable and ((FDrawSelectionMode = smBlendedRectangle) or (tsUseThemes in FStates) or
(toUseBlendedSelection in FOptions.PaintOptions)) then
NodeBitmap.PixelFormat := pf32Bit
else
NodeBitmap.PixelFormat := PixelFormat;
NodeBitmap.Width := PaintWidth;
// Make sure the buffer bitmap and target bitmap use the same transformation mode.
SetMapMode(NodeBitmap.Canvas.Handle, GetMapMode(TargetCanvas.Handle));
PaintInfo.Canvas := NodeBitmap.Canvas;
end
else
begin
PaintInfo.Canvas := TargetCanvas;
NodeBitmap := nil;
end;
和
if not (poUnbuffered in PaintOptions) then
begin
// Adjust height of temporary node bitmap.
with NodeBitmap do
begin
if Height <> PaintInfo.Node.NodeHeight then
begin
// Avoid that the VCL copies the bitmap while changing its height.
Height := 0;
Height := PaintInfo.Node.NodeHeight;
SetCanvasOrigin(Canvas, Window.Left, 0);
end;
end;
end
else
begin
SetCanvasOrigin(PaintInfo.Canvas, -TargetRect.Left + Window.Left, -TargetRect.Top);
ClipCanvas(PaintInfo.Canvas, Rect(TargetRect.Left, TargetRect.Top, TargetRect.Right,
Min(TargetRect.Bottom, MaximumBottom)))
end;
稍后有几个 BitBlt 在不使用 poUnbuffered 时将位图复制到画布的位置。
【问题讨论】:
-
这看起来像一个错误。或者至少是出乎意料的事情。如果您在标题中添加一列,您将使其正常工作,因此当列集合为空时,它与剪辑有关,但它是代码的敏感部分,我不想建议任何修复。我只想添加一个专栏并保持快乐:)
-
刚刚通过添加列进行了测试。使用上面相同的示例和代码,前两行不绘制,其余行绘制:)
-
@TLama 我使用的是 5.1.3。我还使用最新版本进行了测试,它在两种情况下(有和没有列)都有相同的行为。我会做一个比较,看看你拥有的版本和 5.1.3 之间有什么变化。在解决问题之前,让某些东西在此期间正常工作可能会有所帮助。还将记录 VST 的错误。
-
对不起,我已经删除了我之前的评论,因为我意识到我已经修改了您原始代码中的一件事。我使用
Vst.GetTreeRect而不是固定矩形作为PaintTree方法调用的第二个参数。因此,作为记录,仅在您的代码中进行了更改,当我使用 VTV 5.1.0 在标题中添加一列时,我已经能够重现问题并得到正确的结果。 -
@TLama 我在另一个针对 VST 记录的问题中偶然发现了针对此问题的修复。在官方修复之前,我会将其作为答案。
标签: delphi virtualtreeview tvirtualstringtree