Calc: Basic-Makro: Problem mit XModifyListener

Programmierung unter AOO/LO (StarBasic, Python, Java, ...)

Moderator: Moderatoren

preklov
***
Beiträge: 76
Registriert: Mo, 29.06.2009 09:04
Wohnort: Ruhrgebiet

Calc: Basic-Makro: Problem mit XModifyListener

Beitrag von preklov »

openSUSE 11.3, KDE 4.4.4, OOo 3.2.1(Originalversion)

In einer Calc-Arbeitsmappe habe ich eine gewisse Anzahl Datentabellen mit gleicher Struktur, dazu genau eine Statistiktabelle. Die Anzahl der Datentabellen und der jeweiligen Zeilenanzahl ist variabel.

Die Benutzung erfolgt über selbst geschriebene Makros, auch das Einfügen und Entfernen von Zeilen und Datentabellen.

Für bestimmte Zellen in den Datentabellen benötige ich den erwähnten Listener. Beim Öffnen einer Arbeitsmappe wird allen betreffenden Zellen in allen Datentabellen der Listener hinzugefügt (das modify-Event aktualisiert eine bestimmte Zelle):

Code: Alles auswählen

dim oModListener as object

Sub InitListener()
REM Is invoked, when the document is opened.

	dim oSheets as object
	dim iStatSheetIndex as integer
	dim i as integer

	oModListener = _
		createUnoListener("Mod_", "com.sun.star.util.XModifyListener")
	oSheets = ThisComponent.getSheets()
	iStatSheetIndex = oSheets.getByName("Jahresstatistik").RangeAddress.Sheet
	for i = 0 to oSheets.getCount() - 1
		if i <> iStatSheetIndex then
			SetModListener(oSheets(i))
		end if
	next
End Sub

Sub SetModListener(oSheet)
	dim iBottom as integer
	dim i as integer

	iBottom = oSheet.getCellByPosition(RECNR_COL, RECNR_ROW).Value + 2
	oSheet.unprotect("")
	for i = STARTROW to iBottom
		oSheet.getCellByPosition(2, i).addModifyListener(oModListener)
		oSheet.getCellByPosition(5, i).addModifyListener(oModListener)
		oSheet.getCellByPosition(8, i).addModifyListener(oModListener)
		oSheet.getCellByPosition(10, i).addModifyListener(oModListener)
		oSheet.getCellByPosition(14, i).addModifyListener(oModListener)
		oSheet.getCellByPosition(16, i).addModifyListener(oModListener)
	next
	oSheet.protect("")
End Sub
Das funktioniert für die vorhandenen Tabellen problemlos. Wenn ich aber eine neue Tabelle einfüge (die als Kopie einer vorhandenen erzeugt wird, mit Löschung der vorhandenen Daten und Zeilen bis auf 2) und darauf den SetModListener anwende, greift er nicht (keine Fehlermeldung). Wenn ich dann die Datei speichere, funktioniert das auch. Aber wenn ich sie schließe, stürzt OpenOffice komplett ab. Wenn ich die Datei wieder öffne, funktioniert der Listener in allen Tabellen (ohne Absturz beim Schließen).

Was mache ich falsch?

Gruß
Volker
Schöne Grüße
Volker
DPunch
*******
Beiträge: 1112
Registriert: Mo, 02.11.2009 16:16
Wohnort: Marburg

Re: Calc: Basic-Makro: Problem mit XModifyListener

Beitrag von DPunch »

Aloha
preklov hat geschrieben:Das funktioniert für die vorhandenen Tabellen problemlos. Wenn ich aber eine neue Tabelle einfüge (die als Kopie einer vorhandenen erzeugt wird, mit Löschung der vorhandenen Daten und Zeilen bis auf 2) und darauf den SetModListener anwende, greift er nicht (keine Fehlermeldung). Wenn ich dann die Datei speichere, funktioniert das auch. Aber wenn ich sie schließe, stürzt OpenOffice komplett ab. Wenn ich die Datei wieder öffne, funktioniert der Listener in allen Tabellen (ohne Absturz beim Schließen).
Das hört sich an, als ob Du "SetModListener" im neuen Tabellenblatt nicht aus der Prozedur "InitListener" heraus aufrufen würdest und als Onload-Event des Dokuments die Prozedur "InitListener" ausführen lässt.
Wenn dem so sein sollte:
Ändere die Zeile

Code: Alles auswählen

dim oModListener as object
in

Code: Alles auswählen

Global oModListener as object
Im momentanen Fall enthält die Variable oModListener nur eine Referenz auf den Listener, solange die Prozedur InitListener läuft.
Rufst Du SetModListener von einer anderen Stelle auf, ohne oModListener vorher eine neue Referenz auf einen Listener mitzugeben, wird also eine Null-Referenz als Listener in den Zellen der neuen Tabelle hinterlegt. Beim schliessen sollen diese Listener disposed ("entsorgt") werden, was durch die Null-Referenz zum Absturz von OpenOffice führt.
Daher brauchst Du eine Variable, die auch nach Abschluss der Prozedur InitListener noch gültig ist, sprich eine globale Variable.
Eine andere Möglichkeit wäre, die Prozedur SetModListener folgendermaßen zu ändern:

Code: Alles auswählen

Sub SetModListener(oSheet)
   dim iBottom as integer
   dim i as integer
   '**********Ab hier
   If isNull(oModListener) Then
      oModListener = _
          createUnoListener("Mod_", "com.sun.star.util.XModifyListener")
   End If
   '**********Bis hier
   iBottom = oSheet.getCellByPosition(RECNR_COL, RECNR_ROW).Value + 2
   (...)
Zudem wird wärmstens empfohlen, jedem Listener die "disposing"-Methode zur Verfügung zu stellen - solltest Du das noch nicht getan haben, pack einfach noch

Code: Alles auswählen

Sub Mod_disposing

End Sub
in das Modul. Die Prozedur muss keine Anweisungen enthalten, sollte aber trotzdem zur Verfügung stehen (kann sonst zu Abstürzen kommen).
preklov
***
Beiträge: 76
Registriert: Mo, 29.06.2009 09:04
Wohnort: Ruhrgebiet

Re: Calc: Basic-Makro: Problem mit XModifyListener

Beitrag von preklov »

Hab Dank.
Global oModListener as object
Das war's. Wie du aus meinem Listing sehen konntest, habe ich die Variable zwar modulweit (außerhalb der Prozeduren) deklariert, aber mit der dim-Anweisung. Das habe ich mit globalen Variablen immer so gemacht und nie ein Problem damit gehabt. Ich glaube, ich muss mich einmal mit dem Unterschied befassen.
Zudem wird wärmstens empfohlen, jedem Listener die "disposing"-Methode zur Verfügung zu stellen
War selbstverständlich vorhanden.

Gruß
Volker
Schöne Grüße
Volker
Antworten