🙏 Helfen Sie jetzt mit, unser LibreOffice Forum zu erhalten! 🙏
Mit Ihrer Spende sichern Sie den Fortbestand, den Ausbau und die laufenden Kosten dieses Forums. 🌱

🍀 Jeder Beitrag zählt – vielen Dank für Ihre Unterstützung!🍀

❤️ DANKE >> << DANKE ❤️

>> Dank Ihrer Unterstützung -> Keine Werbung für alle registrierten LibreOffice-Forum User! <<
🤗 Als Dankeschön werden Sie im Forum als LO-SUPPORTER gekennzeichnet. 🤗

[GELÖST] Calc-Datenbereich (Anzeige) aus Code aktualisieren

Alles zur Programmierung im LibreOffice.
devdol
Beiträge: 45
Registriert: Fr 11. Mär 2011, 17:59

[GELÖST] Calc-Datenbereich (Anzeige) aus Code aktualisieren

Beitrag von devdol » Di 12. Aug 2014, 11:32

Hallo beisammen,

an einer größeren Tabelle, die immer wieder in drei verschiedenen "Standard-Sortierungen" betrachtet werden will, habe ich drei gruppierte Optionsfelder angebracht und alle mit dem nachfolgenden Makro verknüpft, um mit einem einzigen Klick (d.h. ohne erst mühsam und fehlerträchtig den Sortierbereich markieren und dann den Sortierdialog bedienen zu müssen) eine Standardsortierung auswählen und anwenden zu können. Das funktioniert grundsätzlich sogar:

Code: Alles auswählen

Sub SortiereDatenbereich()
  Dim aSortFields(1) as New com.sun.star.util.SortField    ' zwei Sortierfelder
  Dim aSortDesc(0) as New com.sun.star.beans.PropertyValue '  Sortierschlüssel
  Dim iRow, iRecordCount  As Integer
  Dim oDoc, oSheet, oRange, oForm, oOptA, oOptB, oOptC, as object

  oDoc=thisComponent
  oSheet = oDoc.sheets.getByName(SHEET_NAME)
  oForm =oSheet.DrawPage.forms.getbyIndex(0)
  oOptA = oForm.getbyname("optA") ' Drei Optionsfelder für drei häufig gebrauchte Sortiereinstellungen
  oOptB = oForm.getbyname("optB")
  oOptC = oForm.getbyname("optC")

  oDoc.lockControllers() ' Bildschirmaktualisierung abschalten
  oDoc.AddActionLock()  ' Berechnungen stoppen

  oRange = oSheet.getCellRangeByPosition(0,FIRST_DATA_ROW , DATA_WIDTH, (FIRST_DATA_ROW + iRecordCount - 1) 'nLeft, nTop. nRight, nBottom; 	     
  thisComponent.CurrentController.Select(oRange) ' Erforderlichen Datenbereich selektieren
		
	  if oOptA.State then 
		     aSortFields(0).Field = iCol_lnr 
		     aSortFields(0).SortAscending = True
		     aSortFields(1).Field = iCol_Nachname
		     aSortFields(1).SortAscending = True
		     aSortFields(2).Field = iCol_Vorname 
		     aSortFields(2).SortAscending = True
		     aSortDesc(0).Name = "SortFields"
		     aSortDesc(0).Value = aSortFields()
		     oRange.Sort(aSortDesc()) 
	  End If 
		
	  if oOptB.State then 
		     ' analog mit anderen Sortiereinstellungen
          End If 	

	  if oOptC.State then 
		     ' analog mit anderen Sortiereinstellungen
          End If 	
     
    oDoc.removeActionLock() ' Updateberechnungen wieder einschalten
    oDoc.unlockControllers() ' Bildschirmaktualisierung wieder einschalten!
    
    'Bildschirmaktualisierung auslösen:
    ' ** Das fehlt leider noch! **
End Sub
Allerdings können Anwender die erfolgte Umsortierung erst sehen, wenn sie mindestens eine Bildschirmseite nach unten und wieder nach oben blättern, d.h. was noch fehlt, wäre aus dem Code heraus eine Bildschirmaktualisierung zu triggern (oDoc.unlockControllers bewirkt jedenfalls per se leider keine, und die Anzeige sieht exakt aus wie vor dem Umsortieren).
Weder konnte ich dazu in den Libre/Open-Office-Foren etwas finden noch per xray auf den verschiedenen Objekten eine Methode wie "repaint", "refresh" oder Ähnliches (in Excel gab/gibt es m.w. etwas wie ".Repaint"). Auch abschließend einen anderen Range zu selektieren funktioniert zwar, aber beläßt ansonsten die alten Daten in der Anzeige.
Auch "oDoc.CalculateAll" oder Einfügen von "DoEvents" an allen denkbaren Stellen ändert nichts daran, daß der Bildschirm nicht aktualisiert wird.

Das einzige, was ich als wirksamen Notbehelf durch Versuch und Irrtum auftreiben konnte, ist:

Code: Alles auswählen

    oDoc.getCurrentController().getFrame().getContainerWindow().Visible= False
    oDoc.getCurrentController().getFrame().getContainerWindow().Visible= True
Doch das ist derart rüde, daß es die Anwender verschreckt, sieht das kurze Verschwinden des ganzen Calc-Fensters doch aus wie ein Absturz...

Daher die Frage: Kennt jemand eine sanftere Möglichkeit, den im Calc-Fenster sichtbaren Datenbereich zu aktualisieren?

Kontext: Libreoffice 4.2.6.2 auf Debian/testing, 64bit
Zuletzt geändert von devdol am Mi 13. Aug 2014, 13:50, insgesamt 2-mal geändert.

balu
* LO-Experte *
Beiträge: 370
Registriert: Mi 1. Jun 2011, 16:21

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von balu » Di 12. Aug 2014, 12:13

Mahlzeit devdol,

keine Ahnung ob es dir hilft, oder nicht, aber mir sind da in deinem Code nur beim anschauen einige Fehler aufgefallen.

Du hast hier falsch und fehlerhaft deine Variablen deklariert.

Code: Alles auswählen

  Dim iRow, iRecordCount  As Integer
  Dim oDoc, oSheet, oRange, oForm, oOptA, oOptB, oOptC, as object
iRow = Variant, während iRecordCount richtig als Integer deklariert ist. Das gleiche gilt für die nächste Zeile.
oDoc, oSheet, oRange, oForm, oOptA, oOptB, oOptC sind alle Variant, jedoch nicht als Object deklariert. Und außerdem hast Du da in dieser Zeile ein Komma zu viel.

Bei jeder Variablendeklaration muss der Zustand eindeutig sein. Wenn Du z.B. wie in der ersten Zeile nur die Letzte als Integer deklarierst, so ist nur diese Integer und die andere wird automatisch auf Variant gesetzt. Und das kann unter Umständen zu ernsthaften Problemen führen.
Besser ist es wenn Du das so machst.

Code: Alles auswählen

  Dim iRow As Integer, iRecordCount As Integer
  Dim oDoc as object, oSheet as object, oRange as object, oForm as object, oOptA as object, oOptB as object, oOptC as object

Code: Alles auswählen

  oSheet = oDoc.sheets.getByName(SHEET_NAME)
Hier hast Du vergessen dem Tabellenblattnamen in doppelte Anführungszeichen zu setzen, also so.

Code: Alles auswählen

  oSheet = oDoc.sheets.getByName("SHEET_NAME")

Code: Alles auswählen

     if oOptA.State then 
Hier fehlt ein eindeutiger Vergleichswert. Besser ist z.B.

Code: Alles auswählen

     if oOptA.State = 1 then 
Alternativ kannst Du auch auf True oder False prüfen. Das gilt auch für die anderen beiden IF...Then.


Code: Alles auswählen

           aSortFields(0).Field = iCol_lnr
           aSortFields(1).Field = iCol_Nachname
           aSortFields(2).Field = iCol_Vorname 
Da Du nicht den gesamten Code zeigst, beziehungsweise eine Beispieldatei angehängst hast, kann ich dir auch nicht sagen ob diese drei "Namen" iCol_... richtig deklariert und zugewiesen sind.

Ändere den Code wie beschrieben um, und probiers dann noch mal erneut. Sollte es nicht geholfen haben, dann melde dich wieder und dann am besten mit einer Beispieldatei worin der gesamte Code für die Sortierung zu sehen ist.



Gruß
balu

Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2538
Registriert: Fr 10. Dez 2010, 10:01

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von karolus » Di 12. Aug 2014, 13:16

Hallo
@Balu
Nach der Beschreibung von devdol funktioniert der Code (mit Ausnahme der Aktualisierung), die gross geschriebenen Namen dürften dann globale Konstanten sein.
und eine explizite Prüfung `if opt.State = 1` ist doppeltgemoppelter Unsinn.

@devdol
Ich würde direkt `orange.DataArray`*** sortieren und das mit orange.setDataArray( out ) zurückschreiben - allerdings geht das nicht mit Basic.
***respective `..FormulaArray` -- das hängt von den konkreten Inhalten ab.

Karolus
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)

balu
* LO-Experte *
Beiträge: 370
Registriert: Mi 1. Jun 2011, 16:21

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von balu » Di 12. Aug 2014, 14:04

Hallo Karolus
und eine explizite Prüfung `if opt.State = 1` ist doppeltgemoppelter Unsinn.
Okay da könnte man jetzt drüber diskutiern, weil es nicht verkehrt wäre sich das anzugewöhnen den Status abzufragen. Denn wenn man nicht aufpasst, so wie bei mir hier geschehen :? , könnte man sich ja vielleicht auch mit nem Markierfeld vertun. Und dies bietet ja die Möglichkeit des Dreifachstatus.

Also ein kleiner Schnellschuss von mir. Und wir brauchen auch nicht weiter darüber zu diskutieren. Okay!? ;-)

die gross geschriebenen Namen dürften dann globale Konstanten sein.
Dürften, das trifft vielleicht als Vermutung bei dir zu. Da ich ja nicht den gesamten Code sehe, habe ich halt meine Vermutung geäußert.

Aber wenn wir schon mal beim Thema sind, hätte ich da eine kleine Bitte an dich.
Da ich mit Globalen Konstanten noch nix am Hute habe, würde es mich in diesem Falle doch sehr interessieren ob dann diese Schreibweise korrekt ist, also ohne doppelte Anführungszeichen?

Code: Alles auswählen

oDoc.sheets.getByName(SHEET_NAME)
Über eine kurze Antwort deinerseits würde ich mich sehr freuen. Danke. :)



Gruß
balu

devdol
Beiträge: 45
Registriert: Fr 11. Mär 2011, 17:59

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von devdol » Di 12. Aug 2014, 14:10

Hallo balu,

Du hast mit allen Syntaxfehlern natürlich recht, die sind auch alle beim Versuch enstanden, durch Vereinfachung des Codes hier im Webeditor mehr Übersicht zu verschaffen. Die nicht deklarierten Variablen sind globale Konstanten aus einem anderen Modul, hatte ich auch übersehen, sorry. Doch das Sortieren funktioniert ja und ist nicht das Problem.

Trotzdem als kleines Dankeschön eine funktionsfähige Demodatei, da die Orginaldaten noch viel umfangreicher sind und auch dem Datenschutz unterliegen.

Man sieht hier: Durch Anklicken einer der drei Optionsfelder läßt sich eine der drei vorgegebenen Sortierungen ausführen. Diese wird aber erst sichtbar, wenn man ene Seite runter- und wieder raufblättert. Ein Repaint des sichbaren Bereichs sollte aber doch irgendwie auch aus Code vernünftig zu machen sein?

Nachtrag: Beim Erstellen der Demodatei fiel mir auf, daß auch Formatierungen, die ich dort anbringe (etwa Schrift fett setzen) erst als solche sichtbar werden, wenn ich zumindest eine Zeile blättere. In neu erstellten Calc-Dateien ist das nicht der Fall, womit irgendein selbstkonfigurierter Unfug (etwa Extras/Optionen/...) eigentlich als Erklärung entfällt. Es könnte also auch eine Dateieigenschaft sein, die ich irgendwann unabsichtlich verändert habe, welche das automatische Screen-Update verhindert? (Insofern hat die kleine Fleißarbeit vielleicht auch ihren Sinn gehabt.) Natürlich würde man auch das gerne per Code auf "aktualisiere dich immer autmatisch" zurückstellen wollen, nur finde ich auch bei den Properties (xray oDoc) nichts, was ich als sachdienlich identifizieren könnte...

Nachtrag 2: Ja,
oSheet = oDoc.sheets.getByName(SHEET_NAME)
ist okay, denn das Tabellenblatt heißt ja nicht "SHEET_NAME", sondern "SHEET_NAME" ist vielmehr der Name einer String-Konstanten (oder -Variablen), welcher den Namen des Tabellenblatts enthält. Da man die Konstante sinnvollerweise in einem Extramodul nur einmal deklariert, muß man bei späteren Änderungen des Tabellennamens nicht 50 Änderungen im Code vornehmen, von denen man typischerweise dreizehn übersieht, sondern nur genau ein Mal. Das Großschreiben von Konstantennamen schließlich ist lediglich eine Konvention, kein Sachzwang. Und ich bin auch kein Programmierer, sondern versuche nur die Arbeiten, die der PC schneller und mit weniger Fehler erledigen kann, dem zu überlassen ,-)

Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2538
Registriert: Fr 10. Dez 2010, 10:01

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von karolus » Di 12. Aug 2014, 14:21

Hallo
ich meinte eigentlich nicht `global` sondern `Const`, mit der Zuweisung auf Modulebene

Code: Alles auswählen

Const SHEET_NAME = "Tabelle2"

Sub Main
    doc = thisComponent
    sheet = doc.sheets.getByName( SHEET_NAME )
    Print sheet.Name

End Sub
@devdol
Ne, es ist dann schon eher eine Konstante - weil variabel ist das Ding ja nicht mehr.
Apropos: Ich lese ständig "Demodatei" :?:

Karolus
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)

devdol
Beiträge: 45
Registriert: Fr 11. Mär 2011, 17:59

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von devdol » Di 12. Aug 2014, 16:19

Hallo karolus,

neuer Versuch mit dem Anhang (Calc_sortieren.ods).
Als hochgeladen angezeigt wird es mir jedenfalls.

* Datei öffnen
* eines der drei Optionsfelder anlklicken: es passiert scheinbar nichts (so jedenfalls bei mir - bin gespannt, ob es sich anderswo auch so verhält)
* anschließend nach unten und wieder nach oben blättern: ei Wunder, es ist doch sortiert worden!

Mit dem "...String-Konstanten (oder -Variablen), ..." wollte ich vorhin lediglich zum Ausdruck bringen, daß man die von balu angefragten Anführungszeichen in keinem Fall erforderlich sind, sofern kein literaler String, sondern der Name einer Konstanten oder Variablen übergeben wird ,-)
Dateianhänge
Calc_sortieren.ods
Testdatei zum Überprüfen der ausbleibenden Anzeigeaktualisierung nach Sortieren per Star Basic
(87.05 KiB) 353-mal heruntergeladen

Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2538
Registriert: Fr 10. Dez 2010, 10:01

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von karolus » Di 12. Aug 2014, 20:21

Hallo
Der Sortiervorgang läuft hier anstandslos in unter 1 Sekunde durch - es gibt keine Probleme mit der Aktualisierung.
Ich hab mir trotzdem erlaubt die Sortierung über folgenden Code auszuführen:

Code: Alles auswählen

from operator import itemgetter

def sortcalc(args):
    """
    Umsetzung aus 
    'http://www.libreoffice-forum.de/viewtopic.php?'
    'f=12&t=13876&start=0&sid=ff17301e163838f03383fd40f56bc7b9'
    'args' ist eins von drei gruppierten Optionsfeldern.
    Die Funktion wird über das Event 'Status geändert' ausgeführt
    """
    
    option = args.Source.Model
    sortkeys = {'optA': (0, 1, 2),
                'optB': (1, 2, 0),
                'optC': (2, 1, 0)}

    doc = option.Parent.Parent.Parent
    optname = option.Name
    sortkey = sortkeys[optname]
    sheet = doc.Sheets.getByName('Namensliste')
    cursor = sheet.createCursor()
    cursor.gotoEndOfUsedArea(False)
    sortrange = sheet.getCellRangeByPosition(0,  # erste Spalte
                                             4, # Erste Zeile
                                             3, # letzte Spalte
                                             cursor.RangeAddress.EndRow) # letzte Zeile
    data = sortrange.DataArray
    out = sorted(data, key=itemgetter(*sortkey))

    sortrange.setDataArray(tuple(out))
 
Calc_sortieren.ods
(92.81 KiB) 372-mal heruntergeladen
Damit läufts etwas schneller - allerdings werden die Formatierungen nicht mitsortiert.

Karolus
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)

devdol
Beiträge: 45
Registriert: Fr 11. Mär 2011, 17:59

Re: Datenbereich (Anzeige) in Calc aus Code aktualisieren

Beitrag von devdol » Mi 13. Aug 2014, 13:37

Hallo Karolus,

from future import money - das ist doch Python...? Darauf habe ich schon aufgehört zu hoffen, aber bei mir ist unter "Extras/Makros/Python Makros" auch heute noch alles deaktiviert bis auf "Schließen" und "Hilfe" (wobei Schließen zwar schließt aber die Hilfe nichts hilft, will sagen: da kommt Python auch nicht vor).

Aber zurück zum Thema. Da scheine ich zwei Tage einem Phantom hinterhergejagt zu sein: als ich mein eigenes Beispiel, das ebenso wie die eigentliche Anwendung gestern definitiv und unter Zeugen nicht aktualisiert hat , zuhause ausprobierte (ebenfalls Linux, gleiche Versionen) - aktualisierte es. Dann habe ich es auf einem Windows-7-Rechner getestet - auch da funktioniert es ohne Nachhilfe. Jetzt kommt der Knaller: auf meinem Rechner hier im Büro funktioniert es heute plötzlich auch, obwohl ich mich nicht mal abgemeldet hatte, geschweige denn den Rechner neu gestartet - lediglich der Bildschirm war gelockt, und "apt-get upgrade" hat natürlich nächtens ein paar neue Pakete eingespült. Ob es daran lag? Keine Ahnung, es war nichts auffällig zu LibreOffice gehörendes dabei.

Die Tatsache, daß man sie eigentlich nicht braucht, würde natürlich äußerst zwanglos erklären, warum es die Refresh-Funktion, die ich zwei Tage lang suchte, nicht gibt...!

Für alle diejenigen, denen trotzdem zwischendurch ähnliche rätselhafte Dinge zuteil werden wie mir gestern, habe ich selber zuletzt noch einen weniger aggressiven Workaround gefunden: Es reicht aus, nur um eine Zeile zu wackeln, auch dann wird das ganze sichtbare Areal aktualisiert:

Code: Alles auswählen

    oViewController = ThisComponent.getCurrentController()
    oViewController.setFirstVisibleRow( oViewController.getFirstVisibleRow()+1 )
    oViewController.setFirstVisibleRow( oViewController.getFirstVisibleRow()-1 )

wäre das dann.

Danke trotzdem allen, die sich das Problem angeschaut haben!

Nachtrag: Es ergab sich noch das eher kosmetische Problem, daß (so auch in der Beispieldatei) der Fokus auf der Optionsfelder-Gruppe verbleibt, man durch Betätigen der PfeilAb-Taste also nicht etwa, wie es scheint, die selektierte Zelle (A5 im Beispiel) unmittelbar bewegen kann (das funktioniert erst, wenn man einmal mit der Maus in die Tabelle klickt), sondern sich unabsichtlich die nächste Standardsortierung "einfängt". Dagegen hilft ein abschließendes
Dim oFrame As Object
oFrame = ThisComponent.CurrentController.Frame
oFrame.ContainerWindow.setFocus
Zuletzt geändert von devdol am Mi 13. Aug 2014, 16:50, insgesamt 1-mal geändert.

Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2538
Registriert: Fr 10. Dez 2010, 10:01

Re: [GELÖST] Calc-Datenbereich (Anzeige) aus Code aktualisie

Beitrag von karolus » Mi 13. Aug 2014, 16:15

Hallo
Darauf habe ich schon aufgehört zu hoffen, aber bei mir ist unter "Extras/Makros/Python Makros" auch heute noch alles deaktiviert bis auf "Schließen" und "Hilfe" (wobei Schließen zwar schließt aber die Hilfe nichts hilft, will sagen: da kommt Python auch nicht vor).
Wenn mein oben angehängtes Beispieldokument über die OptionsButtons funktioniert, funktioniert grundsätzlich auch Python bei dir - hangel dich mal durch zu →Extras→Makros→Makros verwalten→Python→→Libre Office Makros... und probier mal die mitgelieferten Beispiele aus.

Im Übrigen hiesse es:

Code: Alles auswählen

from __future__ import something
Karolus
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)


An alle, die das LibreOffice-Forum gern nutzen und unterstützen wollen:


Bitte helfen Sie uns mit 7 Euro pro Monat.
Durch Ihren Beitrag tragen Sie dazu bei, unsere laufenden Kosten für die kommenden Monate zu decken.
Unkompliziert per Kreditkarte oder PayPal.
Als ein kleines Dankeschön werden Sie im LO-Forum als SUPPORTER gekennzeichnet.



Antworten