2016-07-16 20 views
2

Ich bin ein Projekt in Delphi erstellen (RAD Studio). In einigen Zeilen werden Bilder in der Datenbanktabelle gespeichert. Ich möchte Bilder zur Laufzeit extrahieren (für die ich Array of TMemoryStream verwende) und sie im frxReport anzeigen.So speichern Sie mehrere Bilder aus der Datenbank in TMemoryStream zur Laufzeit und entpacken sie später

Schnipsel Mein Code wie folgt

Öffentliche Variable TStream als

erklärt

Stream2 : Array of TStream; i,k: integer

-Code-Segment für Schaltfläche klicken Ereignisansicht, die auf Mainform gelegt und zeigen frxReport erwartet.

`

procedure TFrmMain.btnViewClick(Sender: TObject); 
begin 
    i := 0; 
    k := 0; 
    UniTable1.SQL.Text := 'Select * from userplays order by id'; 
    UniTable1.Execute; 

    rowcount := UniTable1.RecordCount; 

    SetLength(myid, rowcount); 
    SetLength(mydesc, rowcount); 
    SetLength(myimg, rowcount); 
    SetLength(Stream2, rowcount); 

     while not UniTable1.Eof do 
     begin 
     try 
      Stream2[k] := TMemoryStream.Create; 
      myid[k] := UniTable1.FieldByName('id').Value; 
      Stream2[k] := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead); 
      mydesc[k] := UniTable1.FieldByName('description').Value; 

     UniTable1.Next; 
     inc(k); 

     finally 
      //Stream2[k].Free; 
     end; 

     end; 

     frxUserDataSet1.RangeEnd := reCount; 
     frxUserDataSet1.RangeEndCount := rowcount; 
     frxReport1.ShowReport; 
     i := 0; 
end; 

`

jedoch dieses Verfahren geladen ist kein Bild auf Stream2 Array. Es gibt eine Option jedoch Array von JPEGImage zu verwenden, wenn JPEGImage verwendet Array dann wäre es Problem sei es bei

procedure TFrmMain.frxReport1GetValue(const VarName: string; var Value: Variant);

`

Graphic := TJPEGImage.Create; 
Graphic.LoadFromStream(Stream2[j]); 
TfrxPictureView(frxreport1.FindObject('Picture1')).Picture.Graphic := Graphic; 

` Bitte lassen Sie mich wissen, auf frxRaport anzuzeigen, wie man mach das.

+0

was genau ist Delphi-Version, die Sie verwenden ??? Mein Vorschlag: Verwenden Sie einen Dateicontainer: .TAR oder .ZIP oder was auch immer - fügen Sie Dateien ein und legen Sie die Datei in das Datenbank-BLOB. In Delphi XE2 können Sie z. B. ZIP über TStream erstellen, ohne die Festplatte zu berühren. So können Sie direkt TMemoryStream oder TBLobStream verwenden, um viele Dateien innerhalb von –

+0

zu enthalten. Ich benutze Delphi Version XE-3 –

+0

dann ist das eine Möglichkeit für Sie, in-memory zip über den Stream zu machen und in DB zu setzen. ein sehr entfernter Code, aber erwähnen einige Klassen Methoden für Sie https://github.com/the-Arioch/avemey.com/blob/master/zexmlss/src/zeZippyXE2.pas –

Antwort

3

jedoch diese Methode wird geladen kein Bild zu Stream2 Array

In Ihrem aktuellen Code, den Sie zunächst ein neu TMemoryStream-Stream2[k] erstellt zuweisen:

 Stream2[k] := TMemoryStream.Create; 

dann werfen Sie die TMemoryStream entfernt (Erstellen eines Speicherlecks) und ersetzen Sie es durch den Blob-Stream, den Sie erstellen:

 Stream2[k] := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead); 

Aber Sie lesen nie aus dem Blob-Stream.

Hier ist die while Schleife umgeschriebenen (ungetestete)

var 
    blobstream: TStream; 
    Stream2: array of TMemoryStream; 

    .... 
    // read 'id', 'description' and 'image' fields to respective arrays 
    while not UniTable1.Eof do 
    begin 
    myid[k] := UniTable1.FieldByName('id').Value; 
    mydesc[k] := UniTable1.FieldByName('description').Value; 

    blobstream := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead); 
    try 
     Stream2[k] := TMemoryStream.Create; 
     Stream2[k].LoadFromStream(blobstream); 
    finally 
     blobstream.Free; 
    end; 

    UniTable1.Next; 
    inc(k); 
    end; 

BTW, würde ich empfehlen, einen Datensatz zu definieren die id, description und image zusammen zu halten, und eine Anordnung von diesen Datensatz dann, anstatt drei getrennte Arrays. Viel einfacher, nur ein Array statt drei zu verwalten.

+0

hi, es funktioniert, aber zeigt das gleiche Bild (insbesondere das letzte im Speicherstream-Array) bei frxReport. Graphic.LoadFromStream (Stream2 [j]); Es scheint, als ob dasselbe Bild (das letzte) im gesamten Array gespeichert wird. –

+0

@NinadAvasare Ich sehe nicht, wie das möglich wäre, es sei denn, Sie haben nur ein Bild in der Datenbank gespeichert. Wenn Sie den Code im Debugger durchlaufen, sehen Sie z. der 'id' Wert ändert sich für jede Runde? Oder die Größe von 'Stream2 [k]' nach 'LoadFromStream()'? –

+0

Hallo Tom, ja ID-Wert ändert sich bei jeder Runde in der Schleife. Auch ID und DESC werden beide erfolgreich aktualisiert und zeigen die Ausgabe auf fastreport an. Problem ist nur mit dem Bildfeld, da ich Stream verwende, um sie zu speichern und zu laden. –

2

Ich denke in Ihrer Situation am naheliegendsten wäre, nur bestehende DataSet (Unitable1) direkt in DataBand in FRXReport verbinden. Ich sehe nicht, warum Sie frxUserDataset anstelle von frxDBDataset mit seiner DataSet-Eigenschaft auf Unitable1 verwenden müssen, da Sie es trotzdem erstellt haben.

Wenn Sie wirklich eine Liste von Objekten benötigen, würde ich einen anderen Ansatz wählen. Ihre mehreren globalen Variablen sehen hässlich aus und sind gefährlich (i, k ...)

ich eine Klasse schaffen würde, die Ihre Daten und fülle diese Daten in einen TObjectList von System.Generics.Collection hält:

unit DataPack; 

interface 
uses ExtCtrls...System.SysUtils; 

type 

TMyDataPack = class(TObject) 

    private 
    Query: TFDQuery; //O r TUniQery 
    _MyId: Integer; 
    _MyDescription: String; 
    _MyImage: TImage; 
    _Loaded: Boolean; 
    function LoadData: boolean; 
    protected 
    public 
    constructor Create(Data: TFDQuery); //Or Uniquery 
    property MyId: Integer read _MyId; 
    property MyDescription: String read _MyDescription; 
    property MyImage: TImage read _MyImage; 
    property Loaded: Boolean read _Loaded; 
end; 

implementation 

{ TMyDataPack } 

constructor TMyDataPack.Create(Data: TFDQuery); 
begin 
    Inherited Create; 
    Query:=Data; 
    _Loaded:=true; 
    if not (LoadData) then 
    _Loaded:=false; 

end; 

function TMyDataPack.LoadData: boolean; 
var 
Stream: TStream; 
begin 
Stream:= TStream.Create; 
    Stream:=Query.CreateBlobStream(TBlobField(Query.FieldByName('image')), bmRead); 

try 
    _MyImage:=TImage.Create(nil); 
    _MyImage.Picture.Bitmap.LoadFromStream(Stream); 
    _MyDescription:=Query.FieldByName('description').AsString; 
    _MyId:=Query.FieldByName('CategoryId').AsInteger; 
except on E: Exception do 
    begin 
    FreeAndNil(Stream); 
    FreeAndNil(_MyImage); 
    Exit(false); 
    end; 

end; 
FreeAndNil(Stream); 
Result:=true; 
end; 

end. 

dann in dem Hauptcode:

procedure TMain.Button2Click(Sender: TObject); 
var 
DataRow: TMyDataPack; 
List: TObjectList<TMyDataPack>; 
Num: integer; 
CurrentImage: TImage; 
CurrentDescription: String; 
CurrentId: integer; 
begin 
    UniTable1.SQL.Text:='SELECT * FROM Userplays'; 
    UniTable1.Open(); 

List:=TObjectList<TMyDataPack>.Create; 
while not (UniTable1.Eof) do 
    begin 
    DataRow:=TMyDataPack.Create(UniTable1); 
    if(DataRow.Loaded) then 
    List.Add(DataRow); 
    UniTable1.Next; 
    End; 


for Num:=0 to List.Count do 
    begin 
    CurrentDescription:=List[Num].MyDescription; 
    CurrentImage:=List[Num].MyImage; 
    CurrentId:=List[Num].MyId; 
    //List[Num].MyImage.Picture.SaveToFile('Some'+IntToStr(Num)+'.bmp'); 
    // You might save it to file then... 
    end; 
    end; 

    end. 

Dann übergeben Sie eine ObjectList weiter, denken Sie daran, sie am Ende freizugeben.

Sie könnten weiter ausbauen nach Klasse Fabrik zu schaffen verschiedene Objekte zu erstellen, wenn Sie zum Beispiel unterschiedliche Datenbank mit gleichen Daten benötigen würde, ausführen überprüfen, ob Bild tatsächlich BMP- oder JPG-und so weiter. Sie könnten sogar eine Abfrage übergeben, ohne SQL zu setzen und die Eigenschaft "TobjectList" als Eigenschaft zu erhalten.