小妹的毕业设计做得差不多了,是一个delphi+oralce的数据查询系统。中间碰到了很多困难,通过大家的帮助,感觉长进了不少。不过也有被教训的时候,前几天在这里发帖子请教问题,还被人家骂作“不想付出,只想收获的混蛋”。郁闷了很久,一气之下,重新看了一遍资料,总算把那个问题解决了。详情请看:《毕业真的成问题了:在数据库中存取word文档,上40K就报错!》http://expert.csdn.net/Expert/topic/1821/1821292.xml?temp=.654339现在数据库的大体功能都可以实现,只剩下两个问题1。怎么把select出来的记录,通过ole显示出来。因为我的数据库支持模糊查询,有可能一次返回多条数据,我的想法是,移到某条记录时,点击button按钮就可以通过ole显示出文档或者图片。用ole从文件中读取ole的语句是这样的olecontainner1.loadfromfile('tmp')   (是这样,没错吧?)那么,问题就集中在如何把我选中的文件savetofile出来。我手头上这几本讲delphi数据库操作的书上,都没有提到这个方法,大家可以指点指点吗?我自己也接着找找看,看有没有更好的方法。2。ole似乎不支持pdf 文档,可是我这里大多数资料都是pdf的,有解决的办法么?安装插件?谢谢了:)

解决方案 »

  1.   

    阿柯,我不知道你一般怎么用olecontainner这个控件,但是我觉得你应该养成一个习惯就是起文件名的时候最好保留真实的扩展名,这样你也好让olecontainner自动调用相应的程序。例如存储一个excel的文件最好存储为xls扩展名的文件,这样可以自动指向excel的连接。我感觉pdf文件如果你做了正确的扩展名和windows关联之后应该可能自动调用reader这个程序。
    你的毕业设计好像很复杂啊,看来我能从你这里获得不少分啊!呵呵。没分了就在qq上问我把!
      

  2.   

    把select出来的记录,通过ole显示出来
    ~~我还真没有这样用过,学习
    太阳雨兄,不如我加你的qq吧,keke:)
      

  3.   

    我贴代码给大家吧
    BLOB在数据库的表中实际上是以二进制数据的形式存放的。由于BLOB的特殊性,一般的程序都无法处理它。比如,如果在一张表中存在BLOB,当用Dattabase Desktop(Delphi在带的数据库管理工具)打开它时,BLOB列将只显示BLOB字样。至于该列中实际存的是什么数据是单靠Database DeskTop是无法得到的。如果在我们编制的程序中,用DBGrid控件打开一个有BLOB字段的表,效果也一样。我们的程序无法直接显示、编辑以及插入BLOB字段。可见,常规的方法是不能满足要求的。
      如何处理BLOB字段,可以借鉴一些可视的桌面数据库的方法。如Access中,BLOB字段是可以通过双击该字段的方式打开。Access是通过OLE的方式实现BLOB数据的编辑及处理的,所以我们也可以在通过程序中设置OLE控件的方法来处理BLOB。下面,我们先讨论操作BLOB的关键问题,然后给出一个简单的例子。操作BLOB的关键
    要在程序中自如地操作BLOB数据,无非是解决以下几个问题:
    1. BLOB数据的入库操作
    2. BLOB数据的显示
    3. BLOB数据的编辑、修改
      由于数据的类型可能千变万化,所以,采用OLE方式是较方便的选择。我们可以在程序中放置一个OLE控件,用于显示、编辑各种BLOB数据。那么,问题的关键就是BLOB数据如何入库,以及数据库如何与OLE控件之间传递数据。
    第一种解决方案是在库中直接保存原始数据。具体方法如下:
      BLOB数据的入库:要把BLOB数据入库,不能向普通的数据那样直接赋值;而是利用BLOB字段的LoadFromfile方法。采用这个方法,可以直接将各种数据的数据文件存入数据库。代码如下:
    AblobField.LoadFromfile(aFileName);
      数据库与OLE控件间的数据传递也要通过数据文件。即,BLOB字段先将数据存盘;然后,OLE从将数据文件中创建所需要的OLE对象。代码如下:
    AblobField.SaveToFile(aFileName);
    AOleContainer.CreateObjectFromFile(aFileName);
    注意:OLE对象不能直接使用LoadFromFile方法,因为,数据库中存放的BLOB对象的格式是文件原来的格式,而不? E格式,是不能直接读取的。直接读取将导致运行错误。   第二种方案是在库中以OLE格式保存数据。具体方法如下:
      本方案的不同之处,在于数据入库前先进行格式的转换。格式的转换是通过OLE控件完成的。即,先创建OLE对象,然后入库。示例代码如下:
    AOleContainer.CreateObjectFromFile(aFileName);
    AoleContainer.SaveToFile(tmpFileName);
    AblobField.LoadFromfile(tmpFileName);
      这样作的好处是,由于库中直接存储的是OLE格式,所以,在库与OLE控件之间的数据传递将非常方便。在这种情况下,可以通过文件直接传递:数据字段先将数据存到一个临时文件中,然后,OLE控件从临时文件中读取。即:
    AblobField.SaveToFile(aFileName);
    AOleContainer.LoadFromFile(aFileName);
    另外,还可以通过内存流来完成。使用内存流,可减少磁盘操作,大大提高运行效率。即:
    AblobField.SaveToStream(aStream);
    AOleContainer.LoadFromStream(aStream);下面是一个简单的例子。一个简单的例子
      本例中,采用Paradox数据库。库中有两个字段,一个是字符型,另一个是BLOB型。我们在主Form上放一个OLE控件用于编辑及转换数据。一个ADOTable控件操作数据库。源代码如下:unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, OleCtnrs, DB, ADODB, Grids, DBGrids;type
      TForm1 = class(TForm)
        ADOTable1: TADOTable;
        ADOTable1DocuID: TWideStringField;
        ADOTable1DocuContent: TBlobField;
        OleContainer1: TOleContainer;
        Button1: TButton;
        OpenDialog1: TOpenDialog;
        DBGrid1: TDBGrid;
        DataSource1: TDataSource;
        OpenTable: TButton;
        CloseTable: TButton;
        procedure Button1Click(Sender: TObject);
        procedure OpenTableClick(Sender: TObject);
        procedure ADOTable1AfterScroll(DataSet: TDataSet);
        procedure CloseTableClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
    fn: string;
    begin
    ADOTable1.Edit; 
    if OpenDialog1.Execute then begin //打开文件
    fn := ExtractFileName(OpenDialog1.FileName);
    ADOTable1DocuID.AsString := fn;
    OleContainer1.CreateObjectFromFile(OpenDialog1.FileName, False); //创建OLE对象
    OleContainer1.SaveToFile('tmp'); //将OLE数据存入临时文件
    ADOTable1DocuContent.LoadFromFile('tmp'); //将OLE数据存入数据库
    ADOTable1.UpdateRecord;
    end;
    end;procedure TForm1.OpenTableClick(Sender: TObject);
    begin
        ADOTable1.Open ;
    end;procedure TForm1.ADOTable1AfterScroll(DataSet: TDataSet);
    begin
    if not ADOTable1DocuContent.IsNull then begin
    ADOTable1DocuContent.SaveToFile('tmp'); //数据存入临时文件
    OleContainer1.LoadFromFile('tmp'); //从临时文件中读取OLE对象
    end;
    end;procedure TForm1.CloseTableClick(Sender: TObject);
    begin
        ADOTable1.Close ;
    end;procedure TForm1.FormCreate(Sender: TObject);
    beginend;end.
      

  4.   

    刚重温了“数据集的导航”一节,发现了一个叫afterscroll的事务,从没用过,看字面的意思是,往下滚动导航条,不知道这个方法可以不?procedure tform1.query1afterscroll(dataset:tddataset);
    begin 
       if not query1files.isnull then begin
            query1files.savetofile('temp');
            olecontainer1.loadfromfile('temp');
       end;
    end;
      

  5.   

    不行,单步调试,到最后一个end的地方报错。:(
      

  6.   

    csdn的女人一下了怎就多了:)
      

  7.   

    也許對你有幫助,太忙了,沒加注釋了procedure TForm1.Button1Click(Sender: TObject);
    var SFileName: string;
      function FileToString(const FileName: string): string;
      begin
        with TFileStream.Create(FileName, fmOpenRead) do
        try
          setLength(Result, size);
          Read(pointer(Result)^, size);
        finally
          free;
        end;
      end;
    begin
      if OpenDialog1.Execute then
      begin
        SFileName := OpenDialog1.FileName;
        ADODataSet1.Edit;
        ADODataSet1.FieldByName('FileMatter').AsString := filetostring(SFileName);
        Adodataset1.Post;
      end;
    end;procedure TForm1.Button2Click(Sender: TObject);
    var SFileName: string;
      BS: TAdoBlobStream;
    begin
     BS := TAdoBlobStream.Create(TBlobField(ADODataSet1.FieldByName('FileMatter')), bmRead);
     try
       SFileName := Extractfilepath(application.ExeName) + 'tempfile.' + ADODataSet1.fieldbyname('FileExtra').AsString;
       BS.SaveToFile(SFileName);
        OleContainer1.CreateObjectFromFile(SFileName, false);
     finally
       BS.free;
     end;
    end;
      

  8.   

    afterscroll Occurs after an application scrolls from one record to another.mm不懂英文啊~~:)gg来教你好了
      

  9.   

    口合口合口合口合口合口合口合口合口合口合口合,变通了一下,不用query,用table,终于实现了。源代码如下:unit oleUnit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, OleCtnrs, StdCtrls, DB, DBTables;type
      TForm1 = class(TForm)
        Table1: TTable;
        OpenDialog1: TOpenDialog;
        Button1: TButton;
        Button2: TButton;
        OleContainer1: TOleContainer;
        DBNavigator1:TDBNavigator;
        Database1: TDatabase;
        Button3: TButton;
        Button4: TButton;
        Table1NAME: TStringField;
        Table1SIZE1: TStringField;
        Table1DOC: TBlobField;
        Edit1:TEdit;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    var
      memsize:integer;
      buffer:pchar;
      myfile:tfilestream;
      stream:tblobstream;
    begin
        myfile:=tfilestream.Create('c:\temp.tmp',fmcreate);
        with table1 do
        begin
          open;
          stream:=tblobstream.Create(fieldbyname('doc')as tblobfield,bmread);
          memsize:=stream.Size;
          inc(memsize);
          buffer:=allocmem(memsize);
          try
          stream.Read(buffer^,memsize);
          myfile.Write(buffer^,memsize);
          finally
            myfile.Free;
            stream.Free;
          end;
        end;
        if fileexists('c:\temp.doc') then
            deletefile('c:\temp.doc');
        if fileexists('c:\temp.tmp') then
        begin
          renamefile('c:\temp.tmp','c:\temp.doc');
          OleContainer1.CreateObjectFromFile('c:\temp.doc',false);
          OleContainer1.Run;
          end;
    end;procedure TForm1.Button2Click(Sender: TObject);
    var
      memsize:integer;
      buffer:pchar;
      myfile:tfilestream;
      stream:tblobstream;
      filename:string;
    begin
       opendialog1.filter:='(*.doc)|*.doc';
       if opendialog1.Execute then
       begin
       filename:=opendialog1.FileName;
       myfile:=tfilestream.Create(filename,fmopenread);
       with table1 do
       begin
         open;
         edit;
         stream:=tblobstream.Create(fieldbyname('doc')as tblobfield,bmwrite);
         memsize:=myfile.Size;
         inc(memsize);
         buffer:=allocmem(memsize);
         try
           stream.Seek(0,sofrombeginning);
           myfile.Read(buffer^,memsize);
           stream.Write(buffer^,memsize);
           fieldbyname('name').AsString:=extractfilename(filename);
           fieldbyname('size1').AsString:=inttostr(memsize-1);
            finally
            myfile.Free;
            stream.Free;
            end;
            try
            table1.Post;
            except
            showmessage('保存失败');
            halt;
            end;
            showmessage('保存成功');
             OleContainer1.createobjectfromfile(filename,false);
             OleContainer1.run;
            end;
            end;
    end;procedure TForm1.Button3Click(Sender: TObject);
    begin
      OleContainer1.CleanupInstance;
      OleContainer1.Refresh;
    end;
    procedure TForm1.Button4Click(Sender: TObject)
        begin
            with table1 do
            begin 
               indexfieldnames:='name';
               if findkey([edit1.text]) then
                end
             end;
          end;end.呵呵,这样就可以在edit1里输入你想查找的name,然后点击button4,查找到后,点击button1,激活ole,查看了。任务算是完成了,但是还有两点不足:
    1. table的查询功能不如query强大,我希望还是可以用query来实现
    2。ole不支持pdf的问题没有解决。嘿嘿,帖子暂时不结。等我进一步完善了再来和大家讨论吧。大家也要想想啊。
      

  10.   

    用query是一樣的,請參考下面一段if MessageDlg('桌面設計完畢,是否保存?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
      begin
        DeskTopStream := TMemoryStream.Create;
        dxFlowChart1.SaveToStream(DeskTopStream);
        M0.pas_m.Close;
        M0.pas_m.SQL.Text := 'select * from  PAS_M where pas_m_id=' + '''' + sysuser + '''';
        M0.pas_m.Open;
        if not M0.pas_m.Eof then
        begin
          M0.pas_m.Edit;
          TBlobField(M0.pas_m.FieldByName('Cust_DeskTop')).LoadFromStream(DeskTopStream);
          M0.pas_m.FieldByName('Cust_BKColor').AsInteger := dxFlowChart1.Color;
          M0.pas_m.UpdateBatch;
          M0.pas_m.Close;
        end;
        DeskTopStream.Position := 0;
        Mdi.dxFlowChart1.LoadFromStream(DeskTopStream);
        Mdi.dxFlowChart1.Color := dxFlowChart1.Color;
        Mdi.dxFlowChart1.Zoom := 0;
        DeskTopStream.Free;
      end;  action := cafree;
    end;
      

  11.   

    應該有可以顯示pdf文件的元件吧
      

  12.   

    我正在个偏僻的小山村拨号上网
    1。使用query肯定是没有问题的
    2。ole显示 pdf应该是可以的,实在不行,acr提供了一个ocx,pdf.ocx ,acr开头的
      

  13.   

    又郁闷了:(本来用table都已经实现了查询后再删除的功能。昨天晚上在研究oracle数据库,七七八八改了一堆权限和设置,结果现在运行同样的程序,一删除,就报错,说table不可以编辑。我保证,在系统权限里授予了GRANT ANY PRIVILEGE,为我的用户授予了DBA,对table授予了所有的对象权限。这是怎么搞的啊?
      

  14.   

    阿柯姐:
      我按照你说的方式对word文档进行存储,可是执行以后,数据库中午任何内容,不知怎么回事?还有那个database控件的用处是什么?如何设置?
       我的毕业设计也快验收了,麻烦你给我讲一下。谢谢。
      

  15.   

    大家又无聊了不是?程序是难写,工作偶可不用操心,有组织给安排呢。至于嫁人…………我的口号是:自力更生,艰苦奋斗。
    Hid(海涛) ,你说的问题我也发现了,后来改用loadfromfile,一句话搞定。你自己试试
      

  16.   

    我刚学Delphi,水平很有限,不知楼上阿姐在那改用loadfromfile,还请悉心指明啊~0~,我的毕业设计也快验收了 ,急死我了,阿柯姐啊,救人要紧。要不我给你发邮件,
      

  17.   

    easy!
    savetofile就是query的一个字段名的savetofile。
    OLE可以承载 PDF.
      

  18.   

    啧啧!   阿柯MM快成材了~~~~~   教教我哟@_@
    帮你U~~~~~~~~~~~~~~~~~P!
      

  19.   

    Hid(海涛) ,程序如下,其实我也是刚学delphi的,接手这个毕业设计之前,我甚至连delphi都没有听说过,不过现在倒是对delphi编程产生了浓厚的兴趣,我个人认为,还是要先自救。begin
      if OpenDialog.Execute then
      begin
        DataModule2.FILES.LoadFromFile(OpenDialog.FileName);
      end;
        
    end;用这个取代存入的那段代码。
      

  20.   

    meng2002(网宁) ,ole可以么?我后来用的是windows的api函数shellexcute,
    我正在写论文,中间比较了这两种方法,请你讲讲ole怎么承载pdf.
      

  21.   

    天啊,还没有解决阿,要不要我把我原来做的一个扫描程序发给你啊,里面详细处理了delphi和oracle数据库的使用,还有一些该注意的东西,照片的显示等等!具体的数据操作我会省略的,因为我做的这个程序是一个保密系统的一个模块。如果需要,给你保留一些技巧的东西,可能还有很多照片处理的技巧是你需要的!阿柯,如果需要,qq给我留言!
      

  22.   

    阿柯姐:
        我还是不明白,可否把你的那段存取word文档的代码发给我看看,我只是学习一下,并无它意。我的毕业设计快验收了,我真的很上火啊。我现在只想知道怎么存取word文档。[email protected]
      

  23.   

    保存:
    ---
    var
      MS:TMemoryStream;
      sSQL,sSpecialityID:String;
    begin
          MS:=TMemoryStream.Create;
          TJPEGImage(Image.Picture.Graphic).SaveToStream(MS);//将图像数据写入内存流
          MS.Position:=0;      ADOQuery.Open;
          ADOQuery.Append;
          TBlobField(ADOQuery.FieldbyName('Photo')).LoadFromStream(MS);
          ADOQuery.Post;
          MS.Free;
       except
          Application.MessageBox('保存信息失败,请重试!', '系统提示', MB_OK +      
           mb_IconExclamation);
       end;end;--------读取:
    ---
    var
       MyJPEG:TJPEGImage;
       MS:TMemoryStream;
       bs:TBlobStream;
    begin   
        {**取出相片**}
        MyJPEG:=TJPEGImage.Create;
        MS:=TMemoryStream.Create;
        try
           TBlobField(ADOQuery.FieldByName('Photo')).SaveToStream(MS);
           MS.position :=0;
           MyJPEG.LoadFromStream(MS);
           //DBImage.picture.assign(MyJPEG);该控件的使用
           Image.picture.assign(MyJPEG);
         finally
           MyJPEg.free;
           MS.free;
         end;
         
    end;
      

  24.   

    今天终于可以结帖了和oracle数据库相连,用select返回的数据集是不能修改的。必须用缓存更新的技术。我今天才走通。谢谢诸位。
      

  25.   

    我纠正一下,柯柯最后的问题,其实 不然,用select返回的数据集也可以修改,只要把RequestLive属性设置为true就可以了!