[Gelöst] Excel erstellen mit mehreren Sheets

18. August 2006 17:00

Ich versuche einen Excel-Export zu erstellen, welcher mehrere Sheets enthalten soll. Das heisst, ich laufe über eine Tabelle (REPEAT/UNTIL) und möchte jeden Record in einem einzelnen Sheet in Excel haben. Aber wie ich es auch anstelle, ich erhalte immer nur ein ausgefülltes Sheet mit dem letzten Record aus der Schleife. Die Daten werden immer in das selbe Sheet geschrieben, rsp. überschrieben.

Hat mir jemand einen Tipp?
Zuletzt geändert von rotsch am 26. August 2006 13:28, insgesamt 3-mal geändert.

18. August 2006 17:20

hast du denn jeweils die Befehle zur erstellung eines neuen Sheets und das Aktivieren des Sheets eingebaut?

18. August 2006 17:26

In Tabelle 370 Excel Buffer sind etliche Excel Funktionen. Für die Variable XlWrkSht kann man hier the Methode Activate wählen. Danach sollten die Daten eigentlich in das Sheet laufen. Bei VBA funktioniert das jedenfalls so.

18. August 2006 18:01

Ich bin der Meinung, dass ich die nötigen Befehle eingebaut habe. Jedoch wird jedesmal pro Schleifendurchlauf ein neues Excel erstellt. Gerade habe ich aus dem TaskManager ein dutzend Instanzen rausgekippt. Mein Code sieht ungefähr so aus

Code:
IF DocuObject.FIND('-') THEN BEGIN

  TempExcelBuffer.DELETEALL;
  TempExcelBuffer.CreateBook;

  REPEAT

    ... füllen von ExcelBuffer...

    TempExcelBuffer.CreateNewSheet(FORMAT(DocuObject.ID) +' - '+ DocuObject.Name,
                                   FORMAT(DocuObject.ID) +' - '+ DocuObject.Name,
                                   COMPANYNAME,
                                   USERID);

  UNTIL DocuObject.NEXT = 0;

END;

TempExcelBuffer.GiveUserControl;


Die Funktion CreateNewSheet habe ich selber erstellt. Darin wird jeweils ein neues Sheet erstellt, und dann die Standardfunktion aufgerufen

Code:
XlWrkSht := XlWrkBk.Worksheets.Add;
CreateSheet(SheetName, '', CompanyName, UserID2);


Was auch nicht klappt, ist der Aufruf CreateBook am Anfang. Da motzt er mit einer fehlenden Instanz, und wenn ich CreateBook in die Schleife nehme, erhalte ich pro Durchgang ein neues Excel-File.

19. August 2006 01:22

rotsch hat geschrieben:Was auch nicht klappt, ist der Aufruf CreateBook am Anfang. Da motzt er mit einer fehlenden Instanz, und wenn ich CreateBook in die Schleife nehme, erhalte ich pro Durchgang ein neues Excel-File.


Du hast vermutlich vorher Excel noch nicht gestartet, deswegen fehlende Instanz. Und CreateBook erzeugt ein neues Workbook also sozusagen eine neue Excel-Datei, so als wenn du in Excel auf Datei/Neu klickst.
Was steht denn in Deiner Funktion CreateNewsheet?
Und warum übergibst Du 2mal den Sheetnamen?

Ich vermute mal da fehlt noch der Worksheet.activate Befehl, deswegen schreibt der alles in das erste Sheet.

19. August 2006 08:35

Wenn ich CreateBook for dem REPEAT aufrufe, erhalte ich den Fehler wegen der fehlenden Instanz. Wenn ich CreateBook aber direkt vor CreateNewSheet aufrufe erstellt mir Navision pro Durchlauf durch die Schleife eine neue Excel-Datei. Irgendwie beisst sich das immer.

Das mit dem Sheetnamen, der 2mal übergeben wird, ist noch Fehler meinerseits, hat aber keinen Einfluss.

19. August 2006 09:06

Jetzt hat es funktioniert. Der Activate-Befehl war am falschen Platz, und ich habe die ExcelBuffer-Tabelle auf temporär umgestellt. Hier der Code, falls jemand etwas ähnliches machen muss:

Erstellen der Sheets:

Code:
DocuObject.SETRANGE(Type, DocuObject.Type::Table);

IF DocuObject.FIND('-') THEN BEGIN

    Line := 1;

    TempExcelBuffer.DELETEALL;
    TempExcelBuffer.CreateBook;

  REPEAT

    DocuObject.CALCFIELDS(Name);

    EnterCell(Line, 1, FORMAT(DocuObject.ID) +' - '+ DocuObject.Name, true, italic, false);
    Line := Line + 2;

    EnterCell(Line, 1, 'Fieldlist', true, italic, false);
    Line := Line + 2;

    TempExcelBuffer.CreateNewSheet(FORMAT(DocuObject.ID) +' - '+ DocuObject.Name,
                                   'Objectdocumeantion (Table)',
                                   COMPANYNAME,
                                   USERID);

    TempExcelBuffer.DELETEALL;
    Line := 1;

  UNTIL DocuObject.NEXT = 0;

END;

TempExcelBuffer.GiveUserControl;


Neue Funktion 'CreateNewSheet' in der Excel-Buffer Tabelle

Code:
XlWrkSht := XlWrkBk.Worksheets.Add;
CreateSheet(SheetName, '', CompanyName, UserID2);
XlWrkSht.Activate;


Danke für die Unterstützung

21. August 2006 07:49

Eine kleine Unschönheit habe ich noch festgestellt.

Im erstellten Workbook befinden sich am Schluss jeweils 4 leere Sheets in der Reihenfolge Tabelle 4, Tabelle 1, Tabelle 2, Tabelle 3.

1 - 3 werden ja durch Excel automatisch erstellt, wenn man ein neues Workbook erstellt. Lässt sich das vermeiden?

Woher Tabelle 4 kommt, ist mir schleierhaft. Es sind alle benötigten Sheets vorhanden.

21. August 2006 13:18

du könntest bei den Tabellen 1 bis 3 die vorhandenen Tabellen öffnen und umbenennen, und erst ab der 4. neue erstellen.
warum da aber noch ein weiteres Sheet kommt, ist mir ein Rätsel, es sei denn, in der Excelbuffer befindet sich ein leerer Datensatz....

Excel No of Sheets

22. August 2006 15:44

rotsch hat geschrieben:Eine kleine Unschönheit habe ich noch festgestellt.

Im erstellten Workbook befinden sich am Schluss jeweils 4 leere Sheets in der Reihenfolge Tabelle 4, Tabelle 1, Tabelle 2, Tabelle 3.

1 - 3 werden ja durch Excel automatisch erstellt, wenn man ein neues Workbook erstellt. Lässt sich das vermeiden?


Die Tabelle 1 bis 4 kommen aus einer Excel-Einstellung. Die Sheets 2-4 kannst Du auf jeden Fall mit einer Einstellung in Excel unterdrücken. Die Einstellung ist unter Allgemein und heiß Blätter in neuer Arbeitsmappe. Am besten auf 1 setzen.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

22. August 2006 16:39

Danke für den Tipp mit den Einstellungen. Leider hat das nicht geklappt. Jetzt habe ich anstatt 4 noch 2 leere Sheets (Tabelle 1 und Tabelle 2).

Gibt es eine Möglichkeit festzustellen, ob und wieviel leere Sheets vorhanden sind und diese dann explizit zu aktivieren, sodass diese zuerst gefüllt werden, bevor neue angelegt werden?

23. August 2006 23:09

rotsch hat geschrieben:Gibt es eine Möglichkeit festzustellen, ob und wieviel leere Sheets vorhanden sind und diese dann explizit zu aktivieren, sodass diese zuerst gefüllt werden, bevor neue angelegt werden?


Ja, die Automation vom Typ worksheets oder so ähnlich (auf jeden Fall die Mehrzahl, nicht die Einzahl) enthält die Sheets in einer Auflistung.
ggf musst du mal in der VBA-Hilfe von Excel nachsehen, wie du darauf zugreifen kannst. Ich habe gerade keine vorliegen.....

Excel No. of sheets

25. August 2006 10:07

Ich habe es bei mir noch einmal nachgeschaut. Es bleibt max. 1 Sheet mit dem Namen Tabelle1 übrig. Wieviele Sheets hast Du denn wenn Du Excel ganz normal startest? Es muss wie in Mappe99 aussehen. Welche Office-Version vewendest Du?

Ich verwende Office 11 oder Office 10. Es kann aber sein, das ich die Automation Objekte für Office 9 verwende.

Wenn ich nur 1 Sheet benötige, sieht es bei mir so aus:

CREATE(Excel);
Excel.Visible(TRUE);
Book := Excel.Workbooks.Add;//(-4167);
Sheet := Excel.ActiveSheet;
Sheet.Name := 'Sheetname';

Ich habe dann nur 1 Tabellenblatt mit dem Namen Sheetname.

Wenn ich mehrere Tabellenblätter benötige kann dies so aussehen:
(Trigger1)
CREATE(Excel);
Book := Excel.Workbooks.Add;//(-4167);
Excel.Visible(FALSE);

(Trigger2)
Book.Sheets.Add;
Sheet := Excel.ActiveSheet;
Sheet.Name := Mandant.Name;

In diesem Fall bleibt natürlich 1 Tabellenblatt mit dem Name Tabelle1 übrig.
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

26. August 2006 13:28

Hallo TomTom64,

Danke vielmals für deine Ausführungen. Das auf jeden Fall ein Sheet übrigbleibt, habe ich nicht gewusst.

Ich habe das Problem jetzt gefunden. Dein CodeBeispiel hat mich draufgebracht:

Ich habe ja eine eigene Funktion 'CreateNewSheet' erstellt, mit welcher ich neue Sheets anfüge. Das darf ich jedoch erst ab dem zweiten Durchlauf durch meine Routine tun, da CreatBook bereits ein Sheet erstellt.

Tja, am Schluss wars dann einfach, aber bis ich dahinter kam ein steiniger Weg. Ich war auf jedenfall froh um jeden Tipp hier. :-)

Für alle, die sowas auch mal brauchen, hier der Code in gekürzter Fassung (sozusagen das Gerippe)

Code:
IF Record.FIND('+') THEN BEGIN

    FirstSheet := true;

    TempExcelBuffer.DELETEALL;
    TempExcelBuffer.CreateBook;

  REPEAT

    SheetName := 'Irgendwas';

    ... TempExcelBuffer füllen...

    if FirstSheet then begin
        // Standard aus ExcelBuffer
        TempExcelBuffer.CreateSheet(SheetName, ReportHeader,         COMPANYNAME, USERID);
        FirstSheet := false;
    end
    else begin
      // Eigene Routine
        TempExcelBuffer.CreateSheet(SheetName, ReportHeader,         COMPANYNAME, USERID);
    end;

    TempExcelBuffer.DELETEALL;

    Line := 1;

  UNTIL Record.NEXT(-1) = 0;

END;

TempExcelBuffer.GiveUserControl;

Excel erstellen mit mehreren Sheets

28. August 2006 14:53

Hi Roger,

es muß nicht automatisch ein Sheet übrigbleiben. Du mußt nur dafür sorgen, dass Du das Blatt mit dem Name Tabelle1 umbenennst oder löscht. Man kann zum Beispiel den 1. Durchlauf abfragen und dann anstatt ein neues Sheet anzulegen das aktive Sheet umbenennen.

Gruß Tom :-)

Code:
if FirstSheet then begin
  Sheet := Excel.ActiveSheet;
  Sheet.Name := companyname;
  FirstSheet := false;
  // Eigene Routine
end else begin
  // Eigene Routine
        TempExcelBuffer.CreateSheet(SheetName, ReportHeader,          COMPANYNAME, USERID);
end;

 

16. November 2006 15:12

Hallo,

kann ich da nochmal nachhaken?
Ich fasse mal zusammen, was ich mir nun erlesen habe.
1) Im ExcelBuffer eine neue Funktion "CreateNewSheet" mit dem Code von Rotsch
Code:
XlWrkSht := XlWrkBk.Worksheets.Add;
CreateSheet(SheetName, '', CompanyName, UserID2);
XlWrkSht.Activate;


2) Im 1. Durchlauf die normale ExcelBuffer Funktion
CreateSheet(SheetName, ReportHeader, COMPANYNAME, USERID);
aufrufen.

3) In den folgenden Durchläufen dann die eigene Funktion
CreateNewSheet(SheetName, ReportHeader, COMPANYNAME, USERID);
aufrufen.

Habe ich das soweit richtig verstanden?

Bei mir wird halt am Ende nur 1 Excel Blatt mit dem letzten Sheet geöffnet, aber ich habe mehrere EXCEL.EXE Instanzen.... :-(

Was ich auch noch hinbekomme, ist x Excel Blätter zu öffnen, in denen jeweils das 1. Sheet gefüllt ist, auch nicht so schön... :roll:

Kann da jemand vllt. mal ein Fob zur Verfügung stellen?

Gruss, Otschko

16. November 2006 17:40

Ich poste hier die Main-Routine, die ich erstellt habe. Damit bekomme ich wunderbar eine Excel-Datei mit mehreren Sheets.

Code:
DocuObject.SETRANGE(Version, _ActVersion);
DocuObject.SETRANGE(Type, _ActType);

IF DocuObject.FIND('+') THEN BEGIN

    Line := 1;
    FirstObject := TRUE;

    TempExcelBuffer.DELETEALL;
    TempExcelBuffer.CreateBook;

  REPEAT

    DocuObject.CALCFIELDS(Name);

    // Excel-Sheetname
    SheetName := DELCHR(DocuObject.Name, '=', '/');
    SheetName := DELCHR(SheetName, '=', '\');
    SheetName := DELCHR(SheetName, '=', '*');
    SheetName := DELCHR(SheetName, '=', '?');
    SheetName := DELCHR(SheetName, '=', '[');
    SheetName := DELCHR(SheetName, '=', ']');
    SheetName := DELCHR(SheetName, '=', ':');
    SheetName := FORMAT(DocuObject.ID) +' - '+ SheetName;
    SheetName := COPYSTR(SheetName, 1, 31);

    EnterCell(Line, 1, FORMAT(DocuObject.ID) +' - '+ DocuObject.Name, TRUE, FALSE, FALSE);
    EnterCell(Line, 2, 'Version' +' '+ _ActVersion, TRUE, FALSE, FALSE);
    Line := Line + 2;

    // Generelle Bemerkungen ausgeben
    DocuGeneralDesc.SETRANGE(Version, _ActVersion);
    DocuGeneralDesc.SETRANGE(Type, DocuObject.Type);
    DocuGeneralDesc.SETRANGE(ID, DocuObject.ID);

    IF DocuGeneralDesc.FIND('-') THEN BEGIN

      // Überschrift über Bemerkungen
      EnterCell(Line, 1, 'Comments', TRUE, FALSE, FALSE);
      Line := Line + 1;

      REPEAT
        EnterCell(Line, 1, DocuGeneralDesc.Description, FALSE, FALSE, FALSE);
        Line := Line + 1;
      UNTIL DocuGeneralDesc.NEXT = 0;

      Line := Line + 1;

    END;


    // Felder ausgeben
    DocuTableKey.SETRANGE(Version, _ActVersion);
    DocuTableKey.SETRANGE(Type, DocuObject.Type);
    DocuTableKey.SETRANGE(ID, DocuObject.ID);

    IF DocuTableField.FIND('-') THEN BEGIN

      // Überschrift über Keyliste
      EnterCell(Line, 1, 'Keylist', TRUE, FALSE, FALSE);
      Line := Line + 1;

      // Titel für Keyliste
      EnterCell(Line, 1, DocuTableKey.FIELDNAME("Creation Time"), TRUE, FALSE, FALSE);
      EnterCell(Line, 2, DocuTableKey.FIELDNAME(Activity), TRUE, FALSE, FALSE);
      EnterCell(Line, 3, DocuTableKey.FIELDNAME(Responsible), TRUE, FALSE, FALSE);
      EnterCell(Line, 4, DocuTableKey.FIELDNAME("Key Fields"), TRUE, FALSE, FALSE);
      EnterCell(Line, 5, DocuTableKey.FIELDNAME(SumIndexFields), TRUE, FALSE, FALSE);
      Line := Line + 1;

      REPEAT
        EnterCell(Line, 1, FORMAT(DocuTableKey."Creation Time"), FALSE, FALSE, FALSE);
        EnterCell(Line, 2, FORMAT(DocuTableKey.Activity), FALSE, FALSE, FALSE);
        EnterCell(Line, 3, FORMAT(DocuTableKey.Responsible), FALSE, FALSE, FALSE);
        EnterCell(Line, 4, FORMAT(DocuTableKey."Key Fields"), FALSE, FALSE, FALSE);
        EnterCell(Line, 5, FORMAT(DocuTableKey.SumIndexFields), FALSE, FALSE, FALSE);
        Line := Line + 1;
      UNTIL DocuTableKey.NEXT = 0;

      Line := Line + 1;

    END;

    // Keys ausgeben
    DocuTableField.SETRANGE(Version, _ActVersion);
    DocuTableField.SETRANGE(Type, DocuObject.Type);
    DocuTableField.SETRANGE(ID, DocuObject.ID);

    IF DocuTableField.FIND('-') THEN BEGIN

      // Überschrift über Feldliste
      EnterCell(Line, 1, 'Fieldlist', TRUE, FALSE, FALSE);
      Line := Line + 1;

      // Titel für Feldliste
      EnterCell(Line, 1, DocuTableField.FIELDNAME("Creation Time"), TRUE, FALSE, FALSE);
      EnterCell(Line, 2, DocuTableField.FIELDNAME(Activity), TRUE, FALSE, FALSE);
      EnterCell(Line, 3, DocuTableField.FIELDNAME("Field No."), TRUE, FALSE, FALSE);
      EnterCell(Line, 4, DocuTableField.FIELDNAME("Field Name"), TRUE, FALSE, FALSE);
      EnterCell(Line, 5, DocuTableField.FIELDNAME(Responsible), TRUE, FALSE, FALSE);
      EnterCell(Line, 6, DocuTableField.FIELDNAME(Description), TRUE, FALSE, FALSE);
      EnterCell(Line, 7, DocuTableField.FIELDNAME("Data Type"), TRUE, FALSE, FALSE);
      EnterCell(Line, 8, DocuTableField.FIELDNAME("Field Classe"), TRUE, FALSE, FALSE);
      Line := Line + 1;

      REPEAT
        DocuTableField.CALCFIELDS("Field Name",
                                  Caption,
                                  "Data Type",
                                  "Field Classe");

        EnterCell(Line, 1, FORMAT(DocuTableField."Creation Time"), FALSE, FALSE, FALSE);
        EnterCell(Line, 2, FORMAT(DocuTableField.Activity), FALSE, FALSE, FALSE);
        EnterCell(Line, 3, FORMAT(DocuTableField."Field No."), FALSE, FALSE, FALSE);
        EnterCell(Line, 4, DocuTableField."Field Name", FALSE, FALSE, FALSE);
        EnterCell(Line, 5, DocuTableField.Responsible, FALSE, FALSE, FALSE);
        EnterCell(Line, 6, DocuTableField.Description, FALSE, FALSE, FALSE);
        EnterCell(Line, 7, DocuTableField."Data Type", FALSE, FALSE, FALSE);
        EnterCell(Line, 8, FORMAT(DocuTableField."Field Classe"), FALSE, FALSE, FALSE);
        Line := Line + 1;
      UNTIL DocuTableField.NEXT = 0;

      Line := Line + 1;

    END;

    // Globals ausgeben
    ExportGlobals(DocuObject, _ActVersion);

    // Textkonstanten ausgeben
    ExportTextContants(DocuObject, _ActVersion);

    // Funktionen ausgeben
    ExportFunctions(DocuObject, _ActVersion);

    // Trigger ausgeben
    ExportTriggers(DocuObject, _ActVersion);

    IF FirstObject THEN BEGIN
        TempExcelBuffer.CreateSheet(SheetName,
                                    'Documentation ('+ FORMAT(_ActType) +')',
                                    COMPANYNAME,
                                    USERID);
        FirstObject := FALSE;
    END
    ELSE BEGIN
        TempExcelBuffer.CreateNewSheet(SheetName,
                                       'Documentation ('+ FORMAT(_ActType) +')',
                                       COMPANYNAME,
                                       USERID);
    END;

    TempExcelBuffer.DELETEALL;

    Line := 1;

  UNTIL DocuObject.NEXT(-1) = 0;

END;

TempExcelBuffer.GiveUserControl;

13. September 2007 12:42

Hallo,

Die gefundene Lösung hat mir bisher noch sehr gut gefallen, jedoch stehe ich nun vor einem kleinen Problem.
Ich sollte Inhalte für verschiedene Sheets parallel (bzw. ein Eintrag für sheet1... einer für sheet2 dann wieder einer für sheet1 usw..) angeben können.

Bisher kann ich jedoch nur: Excelbuffer füllen - erstes sheet erstellen -> Excelbuffer leeren - nochmal füllen - zweites sheet erstellen.

Hat jemand einen Lösunsvorschlag für mich?
Danke 8-)

lg
Matthias