Zeilen einblenden / ausblenden für Livesuche

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

Moderator: Moderatoren

Mobbi
**
Beiträge: 23
Registriert: Do, 11.12.2008 21:52

Zeilen einblenden / ausblenden für Livesuche

Beitrag von Mobbi »

Hallo,

ich bin gerade dabei eine Art Livefilter für Calc zu programmieren.
Dazu kann in einem Formularfeld(Textfeld) im Tabellenkopf Text, Zahlen ...(was auch immer)eingegeben werden. Nach jedem Tastendruck erscheint die Eingabe sofort (ohne "ENTER") in Zelle G1.
Diese Zelle habe überwache ich mit einen Listener (.XModifyListener) der dann jedesmal das Sub Zeilenfilter ausführt.
Das ganze funktioniert auch einwandfrei nur dauert das ausblenden der Zeilen bei vielen Listeneinträgen recht lange.
Das aus- und einblenden wird mit "oSheet.Rows(i).isVisible = True/False" realisiert. siehe Codebeispiel 1

Code: Alles auswählen

Sub Zeilenfilter
  'Liest die Daten aus Zelle G1 (Daten werden dort von Formularfeld abgelegt) und 
  'vergleicht den Suchtext mit Zeilenweise Spalte A bis C
  'bei Fund wird Zeile eingeblendt sonst ausgeblendet
  'Ist G1 "" dann alles eingeblendet.
  'Aufruf des Zeilenfilter über .XModifyListener auf Zelle G1 als Livefilter verwendbar
  'benötigt Fkt. MaxEintraegeBestimmen
  Dim oDoc as Object
  Dim oSheet as Object
  Dim Blatt as String
  Dim x as Integer
  oDoc = thisComponent
  oDoc.LockControllers										'Bildschirmupdate reduzieren
  Blatt ="Prj_Übersicht"
  oSheet=oDoc.Sheets.getByName(Blatt)						'Tabellenblatt definieren
  x = MaxEintraegeBestimmen(Blatt,0, 1)						'Procedur um Anzahl Einträge in Liste bestimmen
  sFil = oSheet.getCellRangeByName("G1").getString			'Suchtext lesen
  'Alles einblenden wenn kein Suchfiltertext vorhanden
  If sFil ="" then											
    oZeilen =oSheet.getcellrangebyposition(0,1,6,x).rows
    ozeilen.isvisible  = True
    oDoc.UnlockControllers									'Bildschirmupdate normal setzen
    Exit Sub
  End if
  'Suchfilter ausführen
  For i = 1 to x											'Schleife über Liste (x = Anzahl der Einträge
    Sichtbar = False
    sA = oSheet.getCellRangeByName("A"&i+1).getString
    sB = oSheet.getCellRangeByName("B"&i+1).getString
    sC = oSheet.getCellRangeByName("C"&i+1).getString
    sichtbar = False
    If InStr(sA,sFil)<>0 then 		'Vergleich G1 mit Zelle A bis der jeweiligen Zeile
      Sichtbar = True
    Elseif InStr(sB,sFil)<>0 then 	' "
      Sichtbar = True
    Elseif InStr(sC,sFil)<>0 then 	' "
      Sichtbar = True
    Endif   
	If Sichtbar = true then
	  oSheet.Rows(i).isVisible = True
	else  
	   oSheet.Rows(i).isVisible = False
    End if
  Next i
  oDoc.UnlockControllers										'Bildschirmupdate normal setzen
End Sub
'------------------------------------
'------------------------------------
Um das ganze zu beschleunigen wollte ich alle Zeilen in einem Gruppenbereich sammeln (Mehrfachselektion) und dann alle mit einmal ausblenden.
Auf dem Tabellenblatt geht das ganz gut (mehrere versch. Zellen markieren dann Format - Zeilen - ausblenden und fertig.
Das gruppieren der Zellen (Zeilen) bekomme ich auch hin Siehe Codebeispiel 2. Und für diese Selektion kann ich auch ohne schwierigkeiten Eigenschaften wie z.B. die Textfarbe etc. ändern.
Finde jedoch keine Möglichkeit die Selektion auszublenden.
Kann mir vielleicht jemand von Euch helfen?

Code: Alles auswählen

Sub Filtertest
    oDoc=thisComponent
	oSheet = odoc.Sheets.getByName("Tabelle1") 
    oRanges = thisComponent.createInstance("com.sun.star.sheet.SheetCellRanges")
    For i = 0 to 30
	  If oSheet.getCellByPosition(1,i).getString <>"" then
   	    oZeilen = osheet.Rows(i) 
   	    'Alternativ oZeilen =oSheet.getCellRangeByPosition(0,i,6,i).rows 'wenn man nur Teile der Zeile auswählen will
   	    oRanges.addRangeAddress(oZeilen.getRangeAddress(),False)	'Gruppierung in Mehrfachauswahl
	  End if	
	Next i  
	'oRanges.CellProtection.IsHidden = True
	oRanges.setPropertyValue( "CharColor", RGB(0,0,255))			'Veränderung Textfarbe der Zeile
	
	'Zeile ausblenden
	'oZeilen =oSheet.getcellrangebyposition(0,7,6,10).rows
    'ozeilen.isvisible  = False	
End Sub
turtle47
*******
Beiträge: 1849
Registriert: Mi, 04.01.2006 20:10
Wohnort: Rheinbach

Re: Zeilen einblenden / ausblenden für Livesuche

Beitrag von turtle47 »

Hallo,
Mobbi hat geschrieben:Finde jedoch keine Möglichkeit die Selektion auszublenden.
Dazu hat Karolus schon einmal eine Lösung aufgezeigt. Guckst Du hier.

Viel Erfolg.

Jürgen
Software hat keinen Verstand - benutze deinen eigenen...!

Win 7 SP1/ LibreOffice 3.4.2 OOO340m1 (Build:203) / Firefox 15.0.1 / Notebook ASUS K70IO 64 Bit-Betriebssytem
Mobbi
**
Beiträge: 23
Registriert: Do, 11.12.2008 21:52

Re: Zeilen einblenden / ausblenden für Livesuche

Beitrag von Mobbi »

Hallo turtle47,

danke für die schnelle Reaktion.
Diesen Lösungsansatz habe ich im 1. Codebeispiel schon verwendet
Ich suche nach einer Lösung mit der ich die einzelnen Zeilen, nach dem erfassen in einem Sammelobjekt mit einem mal ausblenden kann. siehe Code

Code: Alles auswählen

Schleife beginn ....
If oSheet.getCellByPosition(1,i).getString <>"" then
          oZeilen = osheet.Rows(i) 
          oRanges.addRangeAddress(oZeilen.getRangeAddress(),False)   'Gruppierung in Mehrfachauswahl
End if 
Schleife ende ...
Die einzelne Zeile (Variable "oZeilen") auszublenden funktioniert, dauert aber zu lange bei 500 bis 3000 Einträgen
Das Sammelobjekt aller selektierten Zeile (Variable "oRanges") enthält zwar alle Zeilen, diese lassen sich aber nicht ausblenden.
Sonstige Sammelbearbeitung wie Textfarbe, Hintergrund usw. lässt sich machen - Das Sammelobjekt funktioniert demnach. Ich finde nur keine Möglichkeit auf Sichtbarkeit zuzugreifen.

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

Re: Zeilen einblenden / ausblenden für Livesuche

Beitrag von DPunch »

Aloha

Den SheetCellRanges fehlt das Interface XColumnRowRange, daher kannst Du von dort aus nicht direkt auf die Zeilen zugreifen.
Da SheetCellRanges allerdings ein Container für 0 bis unendlich CellRange ist, welche dieses Interface haben, und der Container den Zugriff auf seinen Inhalt per XIndexAccess erlaubt, kannst Du die enthaltenen einzelnen CellRanges wie folgt ansprechen:

Code: Alles auswählen

For i = 0 To oRanges.Count - 1
	oCellRange = oRanges(i)
	REM oCellRange.Rows.isVisible = False
Next i
Im Übrigen würde ich für das Suchen in den Spalten nicht jede Zelle einzeln ansprechen, da das nicht sonderlich performant ist.
Eine gute Möglichkeit wäre da ein SearchDescriptor.

Code: Alles auswählen

	sMySheet = "Prj_Übersicht"
	sMyCell = "G1"
	oDoc = thisComponent
	oDoc.lockControllers
	oSheet = oDoc.Sheets.getByName(sMySheet)
	sSearchString = oSheet.getCellRangeByName(sMyCell).String
	oCursor = oSheet.createCursor
	oCursor.gotoEndOfUsedArea(False)
	nLastRow = oCursor.RangeAddress.EndRow
	oSearchArea = oSheet.getCellRangeByPosition(0,0,2,nLastRow)
	oSearchDesc = oSheet.createSearchDescriptor
	oSearchDesc.SearchString = sSearchString
	oSearchDesc.searchWords = False
	oResult = oSearchArea.findAll(oSearchDesc)
	If isNull(oResult) Then Exit Sub
	For i = 0 to oResult.Count -1
		oResult(i).Rows.isVisible = False
	Next i
	Do While oDoc.hasControllersLocked
		oDoc.unlockControllers
	Loop
Mobbi
**
Beiträge: 23
Registriert: Do, 11.12.2008 21:52

Re: Gelöst: Zeilen einblenden / ausblenden für Livesuche

Beitrag von Mobbi »

Hallo DPunch,

Problem ist gelöst. Danke für die Hilfe.
Also geht es nur wenn man Zeile für Zeile ausblendet.
Ich habe Deinen Vorschlag mit dem SearchDescriptor übernommen. Dadurch gewinne ich enorm an Geschwindigkeit.
Es lag also hauptsächlich an meinem einfachen Suchschleife und nicht an dem einzelnen ausblenden der Zeilen.
Jetzt macht das Suchen in der Tabelle richtig Spaß weil man nicht ewig warten oder den Autofilter bemühen muss.
Anbei für alle interessierten der Code

Code: Alles auswählen

Global oCrngData
Global oDocController
Global x

'------------------------------------------------------------
'Sub zur Aktivierung einen Listener der Zellbereich überwacht
'------------------------------------------------------------
Sub AddListener_Zelle()
	'Dieses Sub ist beim Start des Dokumentes auszuführen
	oDocController = ThisComponent.Sheets.getByName("Tabelle1").GetCellRangeByName("B2")
	oCrngData = CreateUnoListener("CrngListener_","com.sun.star.util.XModifyListener")
	oDocController.addModifyListener(oCrngData)
End Sub
'------------------------------------------------------------
'Sub zur Deaktivierung eines Listener
'------------------------------------------------------------
Sub RemoveListener()
   'Dieses Sub ist beim Schließen des Dokumentes auszuführen
   oDocController = ThisComponent.Sheets.getByName("Tabelle1").GetCellRangeByName("B2")
   oCrngData = CreateUnoListener("CrngListener_","com.sun.star.util.XModifyListener")
   oDocController.RemoveModifyListener(oCrngData)
End Sub

'------------------------------------------------------------
'Auswertung
'------------------------------------------------------------
Sub CrngListener_Modified(oEvent)
	'Dieses Sub wird ausgeführt, sobald in der zu überwachenden Zeile eine Änderung Eintritt
	Call Zeilenfiltern
End Sub
'------------------------------------------------------------
'Sub zum Filtern der Zeilen mit gesuchtem Inhalt
'------------------------------------------------------------
Sub Zeilenfiltern
  'Liest die Daten aus Zelle B3 (Zuordnung uber Formularfeld) und 
  'vergleicht den Suchtext mit Suchbereich
  'Erst werden alle Zeilen ausgeblendet und bei Fund wieder einblendet
  'Ist Suchkriterium "" dann alles eingeblendet.
  'In Kombination mit .XModifyListener auf Zelle G1 als Instantsuche verwendbar
  'Makro benötigt Sub SceenUptate, Sceenlock, StatusText
  Blatt ="Tabelle1"											'Name des Tabellenblattes
  Zelle = "B2"													'Zelle mit Filterkriterium
  oDoc = thisComponent
  oSheet = oDoc.Sheets.getByName(Blatt)
  ColStart = 0													'Angaben zum Suchbereich
  RowStart = 4													   		 	
  ColEnd = 16
  oCursor = oSheet.createCursor
  oCursor.gotoEndOfUsedArea(False)
  RowEnd = oCursor.RangeAddress.EndRow
  sSearchString = oSheet.getCellRangeByName(Zelle).String		'Suchkriterium
  'Aktionen bei leeren Suchstring ------------------
  If sSearchString ="" then								
    oZeilen =oSheet.getcellrangebyposition(ColStart,RowStart,ColEnd,RowEnd).rows
    ozeilen.isvisible  = True
    Call StatusText("")
    Call ScreenUpdate
    Exit Sub
  End if
  'Aktion bei Suchstring <3 Zeichen ----------------
  If len(sSearchString)<3 then
    Call StatusText("Filtern erst ab 3 Zeichen! Suche nach: ''" &sSearchString &"''")
    Call ScreenUpdate
    Exit Sub
  End if
  'Aktion beim Filtern ------------------------------
  Call StatusText("Filter läuft! Suche nach: ''" &sSearchString &"''")
  Call ScreenLock
  oSearchArea = oSheet.getCellRangeByPosition(ColStart,RowStart,ColEnd,RowEnd)
  oSearchDesc = oSheet.createSearchDescriptor
  oSearchDesc.SearchString = sSearchString
  oSearchDesc.searchWords = False
  oResult = oSearchArea.findAll(oSearchDesc)
  If isNull(oResult) Then 
    'Alle Zeilen ausblenden ---
    oZeilen =oSheet.getcellrangebyposition(ColStart,RowStart,ColEnd,RowEnd).rows
    ozeilen.isvisible  = False
    Call StatusText("Livefilter fertig! gefiltert nach: ''" &sSearchString &"'' | keine Treffer")
    Call ScreenUpdate
    Exit Sub
  End if  
  'Alle Zeilen ausblenden ---
  oZeilen =oSheet.getcellrangebyposition(ColStart,RowStart,ColEnd,RowEnd).rows
    ozeilen.isvisible  = False
  'Alle Treffer einblenden ---  
  For i = 0 to oResult.Count -1
    oResult(i).Rows.isVisible = True
  Next i
  Call StatusText("Livefilter fertig! gefiltert nach: ''" &sSearchString &"''")
  Call ScreenUpdate
End sub
'-------------------
Sub ScreenUpdate
  oDoc = ThisComponent
  Do While oDoc.hasControllersLocked
    oDoc.unlockControllers
  Loop
End Sub
'-------------------
Sub ScreenLock
  oDoc = ThisComponent
  oDoc.LockControllers
End Sub
'---------------------------------------
' Funktion zur Anzeige von Statusinfos
'---------------------------------------
Function StatusText(sInformation)
  'Begrenzt auf max 270 Zeichen
  Dim sSpaces As string
  Dim iLen,iRest As Integer
  iLen=Len(sInformation)
  iRest=270-iLen
  ThisComponent.CurrentController.StatusIndicator.start(sInformation+SPACE(iRest),0)
End Function
Anbei noch eine Musterdatei. Ich hab diese mit den PLZ 01xxx bis 09xxx und Ortsnamen von Deutschland gefüllt.
Livefilter.ods
Livefilter mit PLZ und Ortsnamen von Dtl.
(87.52 KiB) 63-mal heruntergeladen
Danke

Gruß
Mobbi
Antworten