Listener will nicht so wie ich

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

Moderator: Moderatoren

guenther
*
Beiträge: 19
Registriert: Mo, 26.04.2010 07:11

Re: Listener will nicht so wie ich

Beitrag von guenther »

dim Feld()

ein eigener listener muss alle vorgesehen funktionen aufweisen!

siehe Bsp04.odb http://members.aon.at/schardinger/openo ... piele.html

servus, günther
Stephan
********
Beiträge: 12368
Registriert: Mi, 30.06.2004 19:36
Wohnort: nahe Berlin

Re: Listener will nicht so wie ich

Beitrag von Stephan »

Keiner mehr eine Idee?
Kann doch nicht so ein kompliziertes Problem sein...?
Versuche das Problem und den derzeitigen Stand der Lösung erneut zusammenzufassen, inklusiv Code.
Stelle vorzugsweise eine Testdatei mit integriertem Code zur Verfügung.

WArum?
Das Problem ist wohl nicht unlösbar, aber z.B. ich verstehe erstens nicht was Du im DEtail willst und zum Zweiten überblicke ich zwar das Ganze insgesamt, weiß aber das das ausgetestet werden müßte was zeitaufwendig ist und wozu noch weniger Lust seitens der Helfer besteht wenn sie sich erst noich alles zum Testen (letzlich also eine Beispieldatei) selbst zusammenstellen müssen.

Ob das hilft weiß ich nicht, nur Du solltest immer bedenken das Du es den Helfern so bequem machen solltest wie möglich da das ggf. die Antwortschance erhöht.


Gruß
Stephan
DPunch
*******
Beiträge: 1112
Registriert: Mo, 02.11.2009 16:16
Wohnort: Marburg

Re: Listener will nicht so wie ich

Beitrag von DPunch »

Aloha
Jason hat geschrieben:Da mein Code aber selbst auch etwas in eine überwachte Zelle schreiben soll, ist es unerlässlich den ModifyListener davor zu beenden, weil er sich sonst selbst wieder aufruft.
Dafür muss man den Listener nicht unbedingt beenden, das lässt sich auch mit einer Hilfsvariable umsetzen.
Jason hat geschrieben:Da mein Makro universell einsetzbar sein soll, weis ich vorher nicht, für wie viele Tabellen ich einen XModifyListener öffnen muss.
Es reicht ein einziger Listener, der auf mehrere Zellbereiche angesetzt wird.
Der Listener bietet seine Funktionalität so oder so, ob nun einer oder mehrere - es kommt nur darauf an, dass der betroffene Zellbereich überhaupt weiss, dass er einen Listener benachrichtigen soll und welchen.
Als globale Variablen musst Du also die Referenz auf den Listener sowie auf die mit einem Listener versehenen Zellbereiche haben.
Jason hat geschrieben:aber wie definiert man ein unbestimmtes Array? Wenn ich ein bestimmtes globales Array versuche mit redim zu ergänzen, so scheinen alle neuen Einträge des Arrays nicht als Global zu gelten und werden dem entsprechend nicht gespeichert.
Ein Redim erzeugt ein neues leeres Array mit der neuen Dimension.
Was Du benötigen würdest, wäre ein "ReDim Preserve", welches bewirkt, dass die alten Inhalte / Referenzen des Arrays erhalten bleiben.
Jason hat geschrieben:und ich hab wirklich eine Stunde gesucht -, welche Funktionen, bzw. Events der "com.sun.star.util.XModifyListener"
Eine Google-Suche mit dem Suchbegriff "com.sun.star.util.XModifyListener" spuckt direkt als erstes einen Verweis auf die API aus, in der die Methoden (in diesem Fall nur die Methode) zu finden ist ;)
Dort sieht man, dass das Interface die Methode "modified" zur Verfügung stellt.
Zusätzlich erbt das XModifyListener-Interface noch (wie alle Listener) vom com.sun.star.lang.XEventListener die Methode "disposing".
Für einen Einsteiger sicher nicht wirklich überschaubar, aber für die Zukunft möglicherweise ja irgendwann gut, das mal gehört zu haben.
Fazit: Dein Listener muss also die Methoden "disposing" und "modified" bereithalten.

Damit haben wir eigentlich alles, was Du benötigst:
-Du musst dem Listener die Methoden "disposing" und "modified" zur Verfügung stellen
-Du musst die Referenz auf den Listener global hinterlegen
-Du musst die Zellbereiche global hinterlegen, vornehmlich in einem Array

Schau mal, ob Du mit dem Beispielcode hier was anfangen kannst:

Code: Alles auswählen

Global myModLis as Object REM Der Listener
Global myCellArray(0) as Object REM Globales Array für die betroffenen Zellbereiche
Global bManuallyCalled as Boolean REM Hilfsvariable, damit man den Listener nicht durch seine eigenen Änderungen aufruft
Global bListenerAlreadyAdded as Boolean REM Um zu verhindern, dass der Listener möglicherweise mehrmals gestartet wird
Private Const sCellRange as String = "A1:A10" REM Zellbereich, der überwacht werden soll
Private Const sLookupTable as String = "Lookup" REM Tabelle, in der nach möglichen Vorschlägen gesucht werden soll
Private Const nSearchColumn as Integer = 3 REM In welcher Spalte soll in der Tabelle nach dem Begriff gesucht werden
Private Const nStartRow as Integer = 8 REM Ab wecher Zeile gibt es Ergebnisse?
Private Const nEndRow as Integer = 41 REM Bis zu welcher Zeile?

Sub AddMyListener
	bManuallyCalled = False
   If bListenerAlreadyAdded Then Exit Sub
	oDoc = thisComponent
	nSheetCount = oDoc.Sheets.Count-1
	ReDim myCellArray(nSheetCount) as Object
	myModLis = CreateUnoListener( "MyListener_", "com.sun.star.util.XModifyListener" )
	For x = 0 To nSheetCount
		oSheet = oDoc.Sheets(x)
		myCellArray(x) = oSheet.getCellRangeByName(sCellRange)
		myCellArray(x).addModifyListener(myModLis)
	Next x
   bListenerAlreadyAdded = True
	MsgBox "ModifyListener gestartet für Bereich " & sCellRange & " in allen Tabellen"
End Sub

Sub AutoComplete(Cell as Object)
	If NOT Cell.supportsService("com.sun.star.sheet.SheetCell") Then Exit Sub REM Mehrere Zellen markiert
	oSheet = thisComponent.Sheets.getByName(sLookupTable)
	oSD = oSheet.createSearchDescriptor
	sSearch = Cell.String
	With oSD
		.SearchString = "^" & sSearch
		.SearchRegularExpression = True
	End With
	oSearchArea = oSheet.getCellRangeByPosition(nSearchColumn,nStartRow,nSearchColumn,nEndRow)
	oResult = oSearchArea.findAll(oSD)
	If isNull(oResult) Then REM Kein Ergebnis
		MsgBox("Der Zauber konnte nicht gefunden werden. Eine Eigenkreation?")
		Exit Sub
	End If
	If oResult.Count > 1 Then REM Mehrere Ergebnisse, nicht unbedingt zusammenhängend
		MsgBox("Sorry, aber das reicht nicht. Der Zaubername muss genauer angegeben werd.")
		Exit Sub
	End If
	nRow = oResult.RangeAddresses(0).StartRow
	If nRow <> oResult.RangeAddresses(0).EndRow Then REM Mehrere Ergebnisse, die direkt aufeinanderfolgen in der Lookup-Tabelle
		MsgBox("Sorry, aber das reicht nicht. Der Zaubername muss genauer angegeben werd.")
		Exit Sub
	End If
	nCol = oResult.RangeAddresses(0).StartColumn
	sNewString = oSheet.getCellByPosition(nCol,nRow).String
	If MsgBox("Zauber" & Chr(13) & sNewString & Chr(13) & "gefunden, soll der Rest ergänzt werden?", 3, "Jason's Frage:") = 6 Then
		bManuallyCalled = True
		Cell.String = sNewString
	End If
End Sub

Sub MyListener_disposing(oEvent)
	
End Sub

Sub MyListener_modified(oEvent)
	If bManuallyCalled Then
		bManuallyCalled = False
		Exit Sub
	End If
	AutoComplete(thisComponent.CurrentSelection(0))
End Sub

Sub RemoveMyListener
	If isNull(myModLis) Then Exit Sub
	oDoc = thisComponent
	nSheetCount = oDoc.Sheets.Count-1
	For x = 0 To nSheetCount
		myCellArray(x).removeModifyListener(myModLis)
	Next x
   bListenerAlreadyAdded = False
	MsgBox "ModifyListener aus allen Tabellen entfernt"
End Sub
Bei Fragen dazu einfach nochmal melden.
DPunch
*******
Beiträge: 1112
Registriert: Mo, 02.11.2009 16:16
Wohnort: Marburg

Re: Listener will nicht so wie ich

Beitrag von DPunch »

Aloha
Jason hat geschrieben:Eine Frage hab ich dahingehend noch: Wann kann ein Zellbereich noch nicht kopiert werden, außer wenn schon Inhalt in den Zellen ist und Zellen zusammengefügt sind? (...)
Bei der Frage kann ich Dir ehrlich gesagt nicht ganz folgen.
Um die Eingabe des Anwenders in die Zelle mit den Daten aus meinem "Datenbereich" abzugleichen hast du einen regulären Ausdruck verwendet.(...)Gibt es bei größeren Datenmengen (ein paar hundert Datensätzen) gegenüber deiner Variante starke Performance-Unterschiede?
Ja, da gibt es gewaltige Unterschiede - logischerweise je mehr Datensätze es sind, desto größer der Unterschied. Das einzelne Ansprechen jeder Zelle ist bei OOo-Basic elendig langsam.
Ob der Unterschied sich in Deinem Fall auch so deutlich bemerkbar macht, kannst natürlich nur Du beurteilen.
Du musst übrigens keine regulären Ausdrücke verwenden - der SearchDescriptor bietet viele Möglichkeiten an (siehe API: Service SearchDescriptor).
Im Endeffekt kannst Du den SearchDescriptor haargenau so einsetzen wie die normale Suchfunktion der OOo-GUI.
Und zu meinem Code auch gleich noch: Gibt es einen Unterschied zwischen diesen vier Varianten(...)
Nein, da gibt es keinen Unterschied.
"Step" gibt die Schrittweite an, um die nach jedem Schleifendurchlauf hochgezählt werden soll - gibt man dort nichts an, wird automatisch "Step 1" verwendet.
Das Ergänzen von "Next" um die Laufvariable dient nur der Leserlichkeit, bei mehreren verschachtelten Schleifen dann auch der Übersichtlichkeit.
Letzte Frage: Gleich am Anfang deiner Funktion Autocomplete verwendest du(...)
Ist das notwendig? Sollte die Funktion nicht nur ausgeführt werden, wenn eine Zelle inhaltlich verändert wurde und somit als einzige markiert ist?
Nun, highlighte mal mehrere Zellen (per gedrückter Maustaste) und tippe dann etwas ein, ohne vorher die Markierung aufzuheben.
Der Modified-Event wird ausgelöst, aber die aktuelle Selektion gibt nur den markierten Bereich her, nicht, in welcher Zelle genau die Änderung stattgefunden hat.
DPunch
*******
Beiträge: 1112
Registriert: Mo, 02.11.2009 16:16
Wohnort: Marburg

Re: Listener will nicht so wie ich

Beitrag von DPunch »

Aloha
Jason hat geschrieben:Meine erste Frage bezog sich darauf, dass rangecopy meinen Zellenbereich A nicht in den Zellenbereich B kopiert, wenn in B zwei oder mehrere Zellen miteinander verbunden sind (wohl gemerkt sind die Zellen genauso verbunden, wie sie das auch in A sind). Wann kopiert "rangecopy" den Zellenbereich A ebenfalls nicht über den Zellenbereich B?
Ich persönlich habe rangecopy noch nie benutzt, daher kann ich Dir bei der Frage im Detail leider nicht weiterhelfen.
Aber prinzipiell kannst Du dafür doch einfach wieder die Hilfsvariable benutzen - wenn Du am Ende jeder Prozedur, die *potenziell* den Modified-Event auslösen könnte, bManuallyCalled präventiv wieder auf False stellst, ist es egal, ob nun tatsächlich etwas geschehen ist oder nicht.

Code: Alles auswählen

Sub CopyMyRange
bManuallyCalled = True
.......(Kopier die Range oder was auch immer)
bManuallyCalled = False
End Sub
Auf diese Weise kannst Du im Übrigen auch auf einen Integer als Hilfsvariable verzichten, wenn Du noch den Listener-Event so anpasst

Code: Alles auswählen

If bManuallyCalled Then
REM ***Das brauchts dann nicht mehr*** bManuallyCalled = False
      Exit Sub
End If
Das kann ich durchaus machen, aber dann passiert einfach garnichts... ich überlege mir, ob ich motiviert genug bin deine Abfrage der Selektion wieder aufzunehmen, um etwaigen Fehlern aus dem Weg zu gehen :D
Bei mir (OOo 3.11) hat das beschriebene Vorgehen immer zu einem Fehler geführt, weil "sSearch = Cell.String" dann logischerweise nicht mehr funktionieren kann.
Bei der Arbeit mit eigenen Listenern solltest Du um jeden Preis versuchen, jeden möglichen Fehler abzufangen, da es sonst z.B. vorkommen kann, dass die Listener ihre Referenzierung verlieren und sich somit nicht mehr deaktivieren lassen, weil sie zwar noch existieren, aber nicht mehr angesprochen werden können.
Antworten