TGraphic派生类的问题?(300分)

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

陈冲伟

Unregistered / Unconfirmed
GUEST, unregistred user!
我从TGraphic派生了一个类TMyGraphic用来处理我自定义的图像格式*.abc.
TMyGraphic里重载了Create(override), LoadFromStream(override)等方法,
大致如下:

TMyGraphic = class(TGraphic)
public
constructor Create; override;
destructor Destroy; override;
procedure LoadFromStream(Stream: TStream); override;
end;

然后我在如下语句中调用:
var
GraphicClass: TGraphicClass;
Graphic: TGraphic:
begin
GraphicClass := TMyGraphic;
Graphic := GraphicClass.Create;
Graphic.LoadFromFile('mypicture.abc'); //每次执行到此就说Access Violatiion
end;
进一步研究发现在第二句GraphicClass.Create调用中没有调用TMyGraphic.Create方法.

而如果改为:
begin
Graphic := TMyGraphic.Create;
Graphic.LoadFromFile('mypicture.abc');
end;

则载入完全正常,请问这是怎么回事?
 
GraphicClass: TGraphicClass 是什么玩艺?
 
应按下面来写
TMyGraphic = class(TGraphic)
public
constructor Create; override;
destructor Destroy; override;
procedure LoadFromStream(Stream: TStream); override;
end;

var
GraphicClass: TMyGraphic;
begin
GraphicClass:= TMyGraphic.create;
Graphic.LoadFromFile('mypicture.abc'); //每次执行到此就说Access Violatiion
end;
 
试试这样写:
var
GraphicClass: class of TMyGraphic;
Graphic: TGraphic:
begin
Graphic := GraphicClass.Create;
Graphic.LoadFromFile('mypicture.abc');
end;
 
TGraphic 是抽象类你还创建实例,这怎么行?废了我半天功夫居然是这种错误,我要
加分!!!!
 
to antic_ant, barton:
你们提出的方法都是事先知道TMyGraphic类,但是我的情况是这样的,已经定义了
TMyGraphic1, TMyGraphic2, TMyGraphic3等类,然后在运行时才能够确定TGraphicClass
究竟是那个图像类。

to vickowang:
对TGraphicClass赋值后就不是抽象类了,可以创建实例的。将TMyGraphic用TBitmap替
换,然后你试一下,就发现是可以运行的,但是如果你改用TJpegImage等第三方提供的类,
就无法正常运行,如我所说的问题。
 
我追踪了一下源代码,发现LoadFromFile用到了一个抽象方法LoadFromStream,
在对LoadFromFile重载以后也要对LoadFronStream重载。
 
to vickowang:
我的TMyGraphic类中只重载LoadFromStream虚方法,而不重载LoadFromFile。在以后调用
LoadFromFile时自动会调用合适的LoadFromStream方法。问题是我在跟踪以下语句:

GraphicClass := TMyGraphic;
Graphic := GraphicClass.Create;

时,发现在第二句对图像类进行创建时没有调用TMyGraphic.Create方法,而只是调用了抽象
类TGraphic的Create方法,这样创建的Graphic当然无法正确载入相应的文件。但是我不理解
TMyGraphic.Create明明是一个重载的方法,为什么不会被调用?
 
你看一下TGraphic的构造函数,那是一个保护方法,
因此,当你从外部引用GraphicClass.Create;的时候,
编译器根本就找不到合适的方法,实际上是以TObject的Create替代的。

然而根据Object Pascal的封装级别,除了子类之外,还有同一文件中的其他类可以调用保护方法,
因此,同属Graphis.pas的TPicture类就可以使用这种方式来实现多种文件类型的封装。
也就是说,VCL在这一点的设计上,就禁止从外部调用TGraphic的构造函数,
强迫你必须使用TPicture这套机制来实现多种图像文件类型的处理。
 
陈冲伟 你好:

我照你的代码执行很好,没有问题啊。TMyGraphic.Create也执行了。是不是你
程序中代码有点错误?我的TMyGraphic.Create和TMyGraphic.LoadFromStream可是
空无一句啊。
 
to Huzzz:
如果TMyGraphic.Create和TMyGraphic.LoadFromStream是空的,就不会有问题。但是如果
其中有实际的语句,如用TJpegImage代替TMyGraphic,就很可能发生Access Violation,即使
没有Access Violation,载入的图像也是无效的。

to 温柔一刀:
的确如你所说,我跟踪Graphic := GraphicClass.Create; 时发现它只调用了
TObject.Create方法。请问有无解决的方法?

 

恕我愚昧,我不太懂“用TJpegImage代替TMyGraphic”是什么意思,能否解释一下?
 
to Huzzz:
我这里的TMyGraphic只是指一个TGraphic的派生类,用于处理特定的图像格式,你完全
可以在出现TMyGraphic的地方用实际的TJpegImage等第三方提供的图像类去代替它然后试
运行,因为哪些图像类的Create和LoadFromStream方法是非空的,有实际的语句,所以通
常运行时会出现错误。
 
TJpegImage也是TGraphic的一个派生类,你所说的替代是不是在TMyGraphic中又包含地
创建一个TJpegImage,然后在TMyGraphic的LoadFromStream中调用此JpegImage的方法?
我试过这样也不会出错啊。是不是JpegImage在创建后又被FREE掉了?
 
to Huzzz:
不好意思,我试了TJpegImage却没有发现问题。但是用其它类就有问题了,那个GifImage
控件你有没有,如果有试试以下语句:
procedure TForm1.Button1Click(Sender: TObject);
var
GraphicClass: TGraphicClass;
Graphic: TGraphic;
begin
GraphicClass := TGifImage;
Graphic := GraphicClass.Create;
try
Graphic.LoadFromFile('F:/App/test/de.gif');
Image1.Picture.Graphic := Graphic;
finally
Graphic.Free;
end;
end;

在调用LoadFromFile(当然换成你机器上的一个有效的gif文件)后就会有Access Violation.
而将第二句Graphic := GraphicClass.Create;改为Graphic := TGifImage.Create;就运行正
常。这里就是将问题中的TMyGraphic用TGifImage替换一下。
 
TJpegImage没有问题那肯定是那个GIFIMAGE有问题了。

我没有GIFIMAGE,即使有也不知道是哪个,这种控件太多了。

你看看那个GIFIMAGE是否Graphics.TGraphic的子类(八成不是),另外它单
独LoadFromFile是否有问题。我看剩下的问题我是帮不了你了。
 
to Huzzz:
首先,这个GIFIMAGE正是从Graphics.TGraphic直接派生的子类。这个TGifImage是目前
最好的Gif控件,所以不会在这么普通的操作上就出现问题。而且我在前一篇文章中也指出
过,如果将Graphic := GraphicClass.Create;改为Graphic := TGifImage.Create;就可以
正常运行了。
其次,我这里用TGifImage只是举个例子,实际上,我试过很多从TGraphic派生的图像类,
几乎都有问题。没出现问题的只有Borland提供的TBitmap, TIcon,和TJpegImage等几个类,
温柔一刀曾说TBitmap能正常运行是因为与TGraphic处于同一个文件中,作为友元可以相互
调用,那么Jpeg类是单独存在于另一个文件中,为什么也可以正常运行。这是我所不能理解
的。
 
唉,真失败,你说的问题我没有碰过,搞不懂,我觉得不应该出错啊。
另:既然改为Graphic := TGifImage.Create;就正常,那对你写程序应该没大影响吧。
 
to Huzzz:
当然在这个简单的问题上将GraphicClass改为TGifImage就能够解决问题,但是如果要
写一个函数,其参数是TGraphicClass,例如:
function MyGraphicFunction(GraphicClass: TGraphicClass)
var
Graphic: TGraphic;
begin
Graphic := GraphicClass.Create;
....

end;
就无法实现了,这使代码的可重用性降低。
 
HI,你这个问题可以做个应急代码:
function MyGraphicFunction(GraphicClass: TGraphicClass)
var
Graphic: TGraphic;
begin
if GraphicClass = TGifImage then
Graphic := TGifImage.Create
else
Graphic := GraphicClass.Create;
....

end;
这只是权宜之计,等到以后搞清楚问题解决到再改回来,不会影响函数的独立性。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部