Seite 1 von 1

CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Mi, 07.10.2015 15:38
von balu
Hallo liebe Gemeinde,

ich hab da mal wieder zwei Probleme wo ich nicht mehr weiter komme.

Eine normale Formel zwischen 2 Calc-Dateien kann man ja mittels (pseudo-code!)

Code: Alles auswählen

    Dim array2d()
    array2d  = oQuelle.Sheets(1).getcellbyposition(3, 1).getFormulaArray()
    oZiel.Sheets(2).getcellbyposition(3, 1).setFormulaArray(array2d)
kopieren. Das funktioniert ja auch wunderbar.
Aber!
Diese Methode versagt irgendwie, wenn es sich bei der zu kopierenden Formel um eine Matrixformel handelt, wie z.B. {=MAX(...)}. Denn dann steht die Matrixformel in der Zieldatei als Text da, also ohne Funktion gar so als hätte man in den Optionen das Häkchen für Formeln anzeigen gesetzt.

Ich hatte jetzt schon mal mit getArrayFormula und setArrayFormula getestet, aber das haut überhaupt nicht hin, da dann überhaupt keine Formel kopiert wird, weder normale noch Matrix.

Wie kann ich also denn nun eine Matrixformel zwischen 2 Dateien so kopieren das sie in der Zieldatei auch funktioniert?



Und das zweite Problem was mit dem ersten zu tun hat, ist folgendes.
Wie kann ich herausfinden ob es sich bei dem Inhalt der Quellzelle um eine Matrixformel handelt, oder um eine normale Formel?

Ja! Ich arbeite mit xray!
Ich habe auch versucht zwei verschiedene Zellen, einmal mit und einmal ohne Matrixformel, mit xray zu untersuchen. Konnte da aber oberflächlich auf den ersten Blick keinen einfachen Unterschied feststellen, bis auf einen.

Code: Alles auswählen

xray ThisComponent.Sheets.GetByName("Tabelle1").getCellRangeByName("D4")
Normale Zelle ergab bei:
ArrayTokens
[]struct <empty> pseudo-prop

und bei der Matrixzelle bei:
ArrayTokens
[]struct pseudo-prop

Jedoch kann ich momentan damit überhaupt nix anfangen, bezüglich Auswertung.

Also hatte ich dann etwas "tiefer" geforscht, und dachte mir vielleicht geht da ja was mit ImplementationId. Doch da gibt es ja verschiedene Stellen wo die ImplementationId steht, seis z.B. bei .ConditionalFormatLocal.ImplementationId oder .UserDefinedAttributes.ImplementationId (gibt ja noch andere Stellen). Aber das hilft mir auch nicht so weiter, da ich wahrscheinlich noch nicht alle Stellen abgeklappert habe und außerdem auch nicht weiter wüsste wie ich das auswerten kann.


Und was hat das zweite Problem mit dem ersten zu tun?

Nun, wenn ich wüsste wie ich herausfinden kann ob die Quellzelle eine Matrixformel ist, oder nicht, könnte ich dann eine Verzweigung einbauen die dann zu der dementsprechenden richtigen Kopierroutine springt. Denn ich will ja nicht nur Matrixformeln, sondern auch normale Formeln fehlerfrei und funktionsfähig zwischen 2 Dateien kopieren.

Weiss da jemand Rat wie ich da weiter komme?


Ich bedanke mich schon mal für Eure Bemühungen, und seis auch nur für das lesen :-)




Gruß
balu

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Mi, 07.10.2015 16:31
von Stephan
Wie kann ich also denn nun eine Matrixformel zwischen 2 Dateien so kopieren das sie in der Zieldatei auch funktioniert?
kann ich Dir momentan nicht weiterhelfen - schau Dir mal den Code im Thread an auf den ich nachfolgend verweise, vielleicht ergibt sich daraus ein Ansatz. (ich habe gerade keine Zeit mich da weiter einzulesen)
Wie kann ich herausfinden ob es sich bei dem Inhalt der Quellzelle um eine Matrixformel handelt, oder um eine normale Formel?
augenscheinlich mit <Zellobjekt>.ArrayFormula, z.B.:

Code: Alles auswählen

Msgbox ThisComponent.Sheets(0).GetCellRangeByName("C1").ArrayFormula
das gibt "" (Leerstring) für eine Zelle die nicht Teil eines Zellbereichs ist der eine Matrix-Formel enthält, ansonsten die Matrix-Formel.

siehe zweiter post im Thread:
https://forum.openoffice.org/en/forum/v ... rayFormula


Gruß
Stephan

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Mi, 07.10.2015 17:20
von Karolus
Hallo

Ich glaub du verbechselt da etwas, .(get|set)FormulaArray ist eher vergleichbar mit (get|set)DataArray und sinnvoll auf tatsächlichen ZellBereichen weniger auf Einzelzellen anzuwenden.

Du möchtest wohl eher (get|set)ArrayFormula benutzen ?!

Edit: Kurzer Test mit Python ergibt folgendes Bild :
  • .getArrayFormula() liefert die Matrixformel lokalisiert (also mit deutschen Funktionsnamen) mit den geschweiften Klammern drumrum

    Bei .setArrayFormula(...) musst du aber englische Funktionsnamen verwenden und die geschweiften Klammern weglassen

Karolus

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Mi, 07.10.2015 19:32
von balu
Hallo Stephan und Karolus!

Ich bedanke mich erstmal recht Herzlich für Eure Unterstützung.

Stephan, deine Antwort hat mir schon mal so weit geholfen, das eine Denkblokade beseitigt wurde.

Karolus, Du hast mir indirekt aufgezeigt das mein Vorhaben sich so nicht realisieren lässt.


Der Hintergrund an der Geschichte ist nämlich folgender, mal im groben erklärt.
Ich hatte mir ein "Dateirettungstool" erstellt, welches alles aus einer Datei in eine neue leere Datei kopiert. Das hat wohl noch so manche Baustellen, aber einige wichtige Dinge funktionieren schon mal. Nur musste ich gestern abend feststellen, dass die Sache mit dem "Datenbereich" kopieren ein Problem ist, welches ich hier zur Sprache gebracht habe.

Mit (get|set)FormulaArray lassen sich ja Prima Werte, Texte und normale Formeln kopieren.

Code: Alles auswählen

    Dim array2d()
    array2d  = oQuelle.Sheets(ib).getCellRangeByPosition(0, 0, lEndSpalte, lEndZeile).getFormulaArray()
    oZiel.Sheets(ib).getCellRangeByPosition(0, 0, lEndSpalte, lEndZeile).setFormulaArray(array2d)
 
Der Vorteil dieser Kopiermethode liegt halt darin, das damit schon mal die wichtigsten Daten kopiert werden können. Nur wenn da Matrixformeln vorhanden sind, werden diese ja nicht funktionstüchtig in die andere Datei kopiert.
Und ich dachte das durch ändern der get|set auch Matrixformeln kopiert werden, was aber wohl leider nicht wie erhofft geht.

Na ja, kann man nichts machen. Muss ich mir halt etwas anderes überlegen, wie z.B. einen Hinweis das Matrixformeln nicht funktionstüchtig kopiert werden können.



Gruß
balu

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Mi, 07.10.2015 20:26
von Karolus
Hallo

Du könntest ja zunächst mal das ganze per (get|set)FormulaArray erschlagen, und im Nachgang per Regex nach vermeintlichen Matrixformeln suchen, die Fundstellen prüfen obs tatsächlich eine Matrixformel ist (und kein Text), und im Erfolgsfall dann einzeln getFormula() nehmen, die Klammern vorne und hinten entfernen und das dann per .setArrayFormula(...) einfügen.

Ps. Hatten wir das nicht schonmal irgendwann auf höherer Ebene ??

Code: Alles auswählen

ThisComponent.Sheets.importSheet( Quelldokumentobject, Tabellenname, Ziel_index_der_tabelle )
anscheined gibts die Methode aber nur in Libre-Calc


Karolus

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Mi, 07.10.2015 22:28
von balu
Hallo Karolus,

das mit den RegEx werd ich mir demnächst mal zu Gemüte ziehen.
Ps. Hatten wir das nicht schonmal irgendwann auf höherer Ebene ??
Ich meine ja. Aber wie ich wohl schon damals sagte (ich weiß auf die schnelle nicht mehr wann und wo), will ich das mit "importSheet" (oder ähnliche Methoden) vermeiden. Denn damit wird wohl das gesamte Tabellenblatt importiert, und zwar komplett, was aber zu Problemen führen kann. Wenn nämlich sich irgendein Fehler in diesem Blatt eingeschlichen hat, der z.B. dazu führt das die Datei nicht mehr gespichert werden kann, dann wird dieser Fehler ja mit kopiert. Auch wenn noch nicht definitiv[*] fest steht das ein Fehler im Blatt das speichern verhindert, so ist es doch ratsam so viele Fehlerquellen wie nur möglich zu vermeiden.

[*]
Damit meine ich eine offizielle Bestätigung der Projekt-Programmierer. Und nein ich habe deswegen keinen Bug-Report erstellt.

Natürlich kann z.B. das nicht mehr speichern einer Datei verschiedene Gründe haben, aber mit meinem "Dateirettungstool" konnte ich schon 2 mal von so einer betroffenen Datei eine Kopie erzeugen wo ich anschließend nur noch sehr wenig Hand anlegen musste um eine 1:1 Kopie zu haben. Bis zu dem Punkt wo das Tool mit seiner Arbeit fertig war, vergingen so ca. 10 minuten. Hätte ich das alles von Hand machen müssen, so wären garantiert mehrere Stunden mit Spaltenbreite und Zeilenhöhe, Formeln, Formate, Bedingte Formatierungen etc. kopieren beziehungsweise erstellen verstrichen.

Bin mir wohl nicht mehr ganz sicher, aber ich meine das ich es auch mal versucht hatte die einzelnen Tabellenblätter komplett zu kopieren, was aber dazu führte das das Problem mit dem nicht mehr speichern auch in der neuen Datei auftrat.



Gruß
balu

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Fr, 09.10.2015 19:36
von balu
Hallo!

Ich geb allen die sich mit dem kopieren von verschachtelten Matrixformeln via Basic befassen nur einen Rat:
Lasst die Finger davon! :evil:



In Basic ist Matrixformel nicht gleich Matrixformel!

Das folgende Beispiel ist aus der deutschen übersetzung von Andrew Pitonyak (stand 30.10.2014), zu finden unter: "15.4.10. Matrixformeln".

So etwas

Code: Alles auswählen

  oRange = oSheet.getCellRangeByName("J3:J8")
  oRange.setArrayFormula("=G3:G8+H3:H8")
 
macht keine Probleme. In dem dementsprechenden Zellbereich J3 bis J8 wird die gezeigte Formel schön als Matrixformel funktionstüchtig eingetragen. Auch wenn es sich nicht um einen Zellbereich handelt, sondern nur um eine einzige Zelle (J3 als Beispiel), funktioniert es.

Aber wer jetzt auf die Idee kommt: "Mensch pima! Dann setze ich als Formel eine komplexere verschachtelte Calc-Formel rein.", der wird dumm aus der Wäsche schauen.
Denn so was in der Art

Code: Alles auswählen

  oRange = oSheet.getCellRangeByName("J3:J8")
  oRange.setArrayFormula("=MAX((A$2:A$35<=RUNDEN(B$2-SUMME((D$2:D3)*(E$2:E3));5))*A$2:A$35)")
 
funktioniert überhaupt nicht. Denn dann steht in der Zelle die Fehlermeldung #NAME?, und die Formel sieht so aus.

Code: Alles auswählen

{=MAX((A$2:A$35<=runden(B$2-summe((D$2:D3)*(E$2:E3));5))*A$2:A$35)}
 
Diese Formel ist wohl allen anscheind nach nicht eine Basic-typische Arrayformel. Auch wenn wir das erste gezeigte Beispiel als eine Matrixformel interpretieren (weil wir sie mit den Geschweiften Klammern {} sehen), so ist die zweite gezeigte Formel keine "direkt" zulässige Matrixformel auch wenn sie die Klammern hat.

Was wiederum funktioniert ist dies.

Code: Alles auswählen

  oRange = oSheet.getCellRangeByName("J3:J8")
  oRange.setArrayFormula("=MAX(A$2:A$35)")
 

Karolus hat geschrieben: ... und im Erfolgsfall dann einzeln getFormula() nehmen, die Klammern vorne und hinten entfernen und das dann per .setArrayFormula(...) einfügen.
Mittels MID hatte ich die Matrixformel aus der einzulesenden Zelle von den Geschweiften Klammern befreit und diesen String an setArrayFormula übergeben. Ergebnis: Siehe oben zweites Beispiel.

Wenn ich aber die bereingte Matrixformel (also ohne die Geschweiften Klammern) so direkt in eine Zelle schreibe

Code: Alles auswählen

REM tmpx ist das Ergebnis von der MID aktion
ThisComponent.Sheets(0).GetCellRangeByName("I3").FormulaLocal = tmpx
Dann steht in der Zelle.

Code: Alles auswählen

=MAX((A$2:A$35<=RUNDEN(B$2-SUMME((D$2:D3)*(E$2:E3));5))*A$2:A$35)
 
Jetzt müsste man nur noch wissen wie man sie via Basic zur Matrixformel umwandeln kann. :roll:



Gruß
balu

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Fr, 09.10.2015 21:19
von mikeleb
Hallo balu,

unter LO funktioniert bei mir:

Code: Alles auswählen

  oRange = oSheet.getCellRangeByName("J3")
  oRange.setArrayFormula("MAX((A$2:A$35<=Round(B$2-SUM((D$2:D3)*(E$2:E3));5))*A$2:A$35)")
 
sprich man muss die englischen Funktionsbezeichnungen nutzen, auch wenn getArrayFormula die deutschen Bezeichnungen liefert.

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Fr, 09.10.2015 21:55
von mikeleb
Hallo,

auf die Schnelle über eine temporäre Zelle (wie du schon angefangen hast):

Code: Alles auswählen

REM tmpx ist das Ergebnis von der MID aktion
ThisComponent.Sheets(0).GetCellRangeByName("I3").FormulaLocal = tmpx
tmp_en=mid(ThisComponent.Sheets(0).GetCellRangeByName("I3").Formula,2)

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Fr, 09.10.2015 22:07
von balu
Hallo mikeleb,

ja ja! Manchmal braucht man doch ne Pause und einen Stups in die richtige Richtung.
Ich war einfach nicht mehr richtig aufnahmefähig, deshalb hatte ich etwas entscheidendes übersehen.
man muss die englischen Funktionsbezeichnungen nutzen
Na klar doch!
Nur woher nehmen und nicht stehlen?
Ganz einfach. Es gibt doch FormulaLocal und Formula. Also die Zelle nicht per FormulaLocal, so wie ich es bis vorhin gemacht hatte, sondern per Formula einlesen.

Code: Alles auswählen

Sub Main
    mtrx = ThisComponent.Sheets(0).GetCellRangeByName("D2").Formula

    tmpx = MID(mtrx, 2, len(mtrx)-2)
    REM print tmpx
    
    oRange = ThisComponent.Sheets(0).GetCellRangeByName("I4")
    oRange.setArrayFormula(tmpx)
End Sub
Und das funktioniert.


Ich dank dir also für den Stups in die richtige Richtung. :-)



Gruß
balu

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Sa, 10.10.2015 00:12
von Karolus
Hallo

Warum hatte ich wohl ziemlich am Anfang dieses Threads geschrieben, das die Methode .setArrayFormula(...) englische Funktionbezeichnungen benötigt, und später einen konkreten Umsetzungvorschlag gemacht:
Karolus hat geschrieben:... und im Erfolgsfall dann einzeln getFormula() nehmen, die Klammern vorne und hinten entfernen und das dann per .setArrayFormula(...) einfügen.
Genau die Stelle zitierts du selbst, aber tust etwas anderes ??

Re: CALC: 2 Probleme mit Matrixformel zwischen 2 Dateien kopieren?

Verfasst: Sa, 10.10.2015 12:30
von balu
Moin Karolus,

sei mir bitte nicht böse, aber wenn ich ne "Ewigkeit und drei Tage" mich mit nem bestimmten Thema herumschlage, dann kann es schon mal vorkommen das ich etwas übersehe und oder falsch verstehe. Dabei bleibt es dann auch leider nicht aus, dass ich dann auch schlaflose Nächte deswegen hinter mir habe, so wie jetzt mit nur 2 Stunden schlaf.

Das Du dann auch noch Regex erwähnt hattest, versetzte mich noch zusätzlich unter Druck. Denn einerseits wusste ich nicht genau wie Du dir das vorstellst, und anderseits habe ich keine Ahnung davon.
Ich weiss ja jetzt nicht mal ob ich deine Antwort mit Beschwerde überhaupt richtig verstanden habe.

Und ja, ich hatte mir auch noch mal deine Antworten durchgelsen, aber ich konnte das alles nicht mehr in Einklang bringen um einen kurzen 3 Zeiler (so wie ich eingangs zitierte) zu erstellen. Denn so ein 3 Zeiler in der Art mit (get|set)FormulaArray wo in einem Rutsch ein ganzer Datenbereich ratz-fatz erledigt wird, wäre natürlich das schönste und bequemste für mich. Doch momentan läuft es ja dahin hinaus, dass ich jede einzelne Zelle überprüfen muss ob es sich um eine normale oder Matrixformel handelt. Okay, ich weiss jetzt das es fuktioniert, dass ich einzelne Zellen mit Matrixformeln zwischen zwei Dateien kopieren kann. Doch wenn ich daran denke was das für ein gigantischer Zeitaufwand das Makro dafür verbrauchen wird, vergeht mir schon wieder alles da ich noch nicht weiss wie ich das am schnellsten erledigen kann.

aber tust etwas anderes ??
Wollte ja auch mal das grundsätzliche kopieren einer Matrixformel in ein und der gleichen Datei ausprobieren, ohne immer wieder eine neue Datei zu öffnen (das nervt nämlich mit der Zeit bei der Erprobung).


Ich weiss das Stephan hier mal eine Demodatei zur Verfügung gestellt hat, in der er zeigt wie schnell man eine Calc-Datei mit Daten befüllen kann (diese Datei habe ich mir auch gespeichert). Und so etwas muss ich mir jetzt auch einfallen lassen, wenn ich nur den gesamten Ablauf seines Codes endlich richtig verstehen würde.


Mein momentaniges Makro für das kopieren sieht wie folgt aus.

Code: Alles auswählen

Sub Main
    Dim oQuelle as Object, oQuellBlatt as Object, oQuellZelle as Object
    Dim oExterneDatei as Object, oExternesBlatt as Object, oExterneZelle as Object
    Dim mArgs()
    
    oQuelle = ThisComponent
    oExterneDatei = StarDesktop.loadComponentFromURL ("private:factory/scalc","_blank", 0, mArgs())
    oExternesBlatt = oExterneDatei.sheets(0)
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Letzte Zeile/Spalte ermitteln.
'
    oQuellBlatt = oQuelle.sheets(0)
    oCellCursor = oQuellBlatt.createCursor
    oCellCursor.GotoEndOfUsedArea(False)
    iEndZeile = oCellCursor.getRangeAddress().endRow
    iEndSpalte = oCellCursor.getRangeAddress().endColumn
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Daten kopieren
'
    For iSp = 0 to iEndSpalte
        For iZe = 0 to iEndZeile
            
            oQuellZelle = oQuellBlatt.getCellByPosition(iSp, iZe)
            oExterneZelle = oExternesBlatt.getCellByPosition(iSp, iZe)
            
            If oQuellZelle.ArrayFormula <>"" then
                oMatrix = oQuellZelle.Formula
                oExterneZelle.setArrayFormula(MID(oMatrix, 2, len(oMatrix)-2))
            else
                oExterneZelle.FormulaLocal = oQuellZelle.FormulaLocal
            end if
        
        next iZe
    next iSp
'
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
' Endmeldung
'
    print "fäddisch!!!"
End Sub
Der Abschnitt *Daten kopieren* wäre ohne Matrixformel mit den 3 Zeilen (get|set)FormulaArray erledigt, und die zeitliche Dauer dafür wären nur wenige Sekunden. Aber so, wegen der Matrixformel, würde der gleiche Zellbereich bis zu mehrere Minuten, wenn nicht noch länger, dauern.

Hier mal ein paar Zeiten zum vergleichen.
Das obrige Makro braucht für einen bestimmten Zellbereich ca. 43 sekunden.
Ändere ich den Abschnitt *Daten kopieren* auf das hier,

Code: Alles auswählen

Dim array2d()
array2d  = oQuellBlatt.getCellRangeByPosition(0, 0, iEndSpalte, iEndZeile).getFormulaArray()
oExternesBlatt.getCellRangeByPosition(0, 0, iEndSpalte, iEndZeile).setFormulaArray(array2d)
 
so braucht das Makro für den gleichen Zellbereich nur noch ca. 2 sekunden. Natürlich gibt es dann keine funktionsfähige Matrixformeln dabei, aber das spielt keine Rolle.


So, muss jetzt erstmal etwas Schlaf nachholen. :?



Gruß
balu