如何用TImage实现大图像浏览(200分)

  • 主题发起人 主题发起人 陈冲伟
  • 开始时间 开始时间

陈冲伟

Unregistered / Unconfirmed
GUEST, unregistred user!
我想做这样一个图像浏览程序,当显示的图片大小超过窗口的大小时,用户可以
使用鼠标来拖动图片,以察看图片的其他部分,(就像ACESee里的那样).现在我用
TImage来显示图片,并捕捉鼠标事件,当鼠标移动时,就用TImage的SetBounds
方法来改变TImage的位置,以实现图片的移动,但我在实际调试过程中,发现
TImage闪烁的非常厉害,不知如何才能解决这一问题.或者说有没有现成的类似
与TImage的控件,可以较好的解决这一问题?
 
曾经看到过一个控件,好象叫做TZImage,可以有你所说的功能,但具体能支持多
大的图象,我也没试过.如果它用系统的函数,那是不能支持很大的图象的.

这个控件在深度历险上有的,<a href="http://sunsite.icm.edu.pl/delphi/">DSP</a>也有.可以在DSP的
搜索页上用几个相关的关键字找一下,应该有一大堆,但不要期望它能够有
ACDSEE的性能.ACDSEE可是用DDRAW做的.
 
这是我用来显示超大图片的处理过程(节选)
用到两幅图片,一幅用于显示部分内容,一幅用于保存全部内容(不显示)
其实我自己编有一套动态图片处理控件,可是不能处理Jpeg,所以才有下面
的三个过程,你慢慢看吧。
var
...
DragStart:tpoint;
PointImg1:TPoint;
implementation

...
procedure TfrmJpeg.JPEGImage2MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if (Button = mbLeft) then
begin
JPEGImage2.Tag:=1;//Enabled Drag
DragStart:= TControl(Sender).ClientToScreen(Point(X,Y));
end;
end;

procedure TfrmJpeg.JPEGImage2MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if (Button = mbLeft) then JPEGImage2.Tag:=0;
end;

procedure TfrmJpeg.JPEGImage2MouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var Diff:TPoint;
W,H:integer;
begin
if JPEGImage2.Tag<>1 then exit;
Diff := JPEGImage2.ClientToScreen(Point(X,Y));
Diff := Point(Diff.X-DragStart.X,Diff.Y-DragStart.Y);
W:=JpegImage2.Width;H:=JpegImage2.Height;
if (Diff.x >0) then
begin if (PointImg1.x-Diff.x)<=0 then
Diff.x:=PointImg1.x;
end
else
if (Diff.X <0) then
begin if (PointImg1.x+w-Diff.x)>=JpegImage1.Width then
Diff.x:=PointImg1.x+W-JpegImage1.Width;
end;
if (Diff.y >0) then
begin if (PointImg1.y-Diff.y)<=0 then
Diff.y:=PointImg1.y;
end
else
if (Diff.y<0) then
begin if (PointImg1.y+H-Diff.y)>=JpegImage1.Height then
Diff.y:=PointImg1.y+H-JpegImage1.Height;
end;
SetPoint(PointImg1.x-Diff.x,PointImg1.y-Diff.y);
DragStart.X := DragStart.X+Diff.X;
DragStart.Y := DragStart.Y+Diff.Y;
if JpegImage2.ShowHint then JpegImage2.ShowHint:=False;
end;

procedure TfrmJpeg.SetPoint(NewX:integer;NewY:integer);
begin
PointImg1.x:=NewX;PointImg1.y:=NewY;
With JpegImage2 do
Canvas.CopyRect(Rect(0,0,Width,Height),JpegImage1.Canvas,
Rect(Newx,Newy,Newx+Width,Newy+height));
end;

...
 
1、闪烁的问题可能是因为你的拖动代码导致图象频繁刷新,
我觉得比较好的办法是将TImage放到TScrollBox里面,
TScrollBox会自动适应内部控件大小,
什么代码都不用写,效果也不错。
2、Delphi本身是支持JPEG的。
Step1:安装C:/WINDOWS/SYSTEM/vcljpg40.bpl
Step2:Uses Jpeg
就可以使用TJpegImage类了,它继承自TGraphic,
和TBitmap是同级类。显示Jpeg示例如下:
var
JpegImage:TJpegImage;
begin
JpegImage:=TJpegImage.Create;
//载入JPEG图象
JpegImage.LoadFromFile('XXXX.Jpg');
//转换为Bitmap,显示
Image.Bitmap.Assign(JpegImage);
JpegImage.Free;
end;
 
要支持大图片,就要自己做内存管理。比如把bitmap的数据放到一个
TMemoryStream(如果很大,那就要Cache+TFileStream)里面,然后
根据TImage滚动的消息调出相应的数据
 
我这有一个简单的做法,可以解决你的问题
你可以试试
设置image1.enabled:=false
Code如下:
var ori:Tpoint;
startflag:integer;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var rerect:Trect;
begin
if startflag=1 then
begin
Form1.canvas.draw(x-ori.x,y-ori.y,image1.picture.graphic);
rerect:=rect(0,0,form1.width,y-ori.y);
Form1.canvas.fillrect(rerect);
rerect:=rect(0,0,x-ori.x,form1.height);
Form1.canvas.fillrect(rerect);
rerect:=rect(0,y-ori.y+image1.height,form1.width,form1.height);
Form1.canvas.fillrect(rerect);
rerect:=rect(x-ori.x+image1.width,0,form1.width,form1.height);
Form1.canvas.fillrect(rerect);
end;
edit1.text:=inttostr(x)
end;


procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
ori.x:=x-image1.left;
ori.y:=y-image1.top;
startflag:=1;
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
image1.left:=x-ori.x;
image1.top:=y-ori.y;
startflag:=0;

end;

 
其实不应该用TImage,如果仔细的观察的话,Timage在每次刷新的时候会先画会灰色背景,在重画其原图。按逻辑只有当灰色出现时间小余1/26妙,肉眼才看不见,一般是不可能的。所以只有自己来画。

自己画的时候,可以利用Tpaintbox.onpaint。另外注意重画的时候千万不要呼叫Paintbox.Repaint,或Refresh,这会重倒旧辙,应该直接呼叫PaintboxOnpaint
 
在Timage下放一个panel试试, 可能可以解决图象闪烁的问题.
 
其实这是由于TImage自己造成的,你要截住WM_EraseBkg的消息,什么都不做,
自己重写Paint,最好利用双缓冲机制。
 
我有一段编好的程序,有兴趣的话可来信索要.haoxu@public.cs.hn.cn
程序不大.
 
陈冲伟:
这个问题已经很长时间没有人参加讨论,为保持版面
整洁,节约网友时间,请提问者采取必要处理措施。
关于图形图象版管理细则,请参见<a href="http://www.gislab.ecnu.edu.cn/delphibbs/DispQ.asp?LID=111927">这个</a>问题。如两天
内提问者没有响应,我将采取强制措施。

如有管理建议,请到<a href="http://www.gislab.ecnu.edu.cn/delphibbs/DispQ.asp?LID=111927">这里</a>提出。谢谢!
 
多人接受答案了.
 
后退
顶部