Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

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

Moderator: Moderatoren

marcel_at_work
****
Beiträge: 195
Registriert: Sa, 24.04.2010 15:51
Wohnort: Basel [CH]

Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

Beitrag von marcel_at_work »

Liebe Gemeinde,

da ich letztens selbst gern diese Informationen im Forum vorgefunden hätte, stelle ich sie nun einfach selber mal bereit.
"Ein Tabellen-Grid Steuerelement wie bei Formularen gibt es im Dialogdesigner nicht [...]. Mit der Version 3.3 von OpenOffice (und damit auch mit der Version 3.3 von LibreOffice) wurde allerdings das Steuerelement in der API verankert und steht seitdem auch für eigene Programmierungen zur Verfügung." (Thomas Krumbein)
Auf einer der Internetseiten von Thomas Krumbein ist die Einbindung eines Tabellenkontrollelements in einen Basic-Dialog beschrieben, deren kurze Dokumentation dort auch als .pdf verfügbar ist.

Leider existierte letztens die zum Download ausgewiesene Beispieldatei nicht mehr, weshalb ich selbst Funktionen dafür geschrieben habe und hier bereitstellen möchte - in der Hoffnung, anderen ein wenig Zeit und Nerven damit zu ersparen. 8)

Die Initialisierung des Tabellenkontrollelements besteht nur aus ein paar wenigen Zeilen...

1) Es wird ein multidimensionales Array erzeugt und mit den Daten der Spaltenköpfe initiiert: Spaltentitel, Spaltenbreite und Ausrichtung.
Bemerkung: Für mehr Spalten als im angegebenen Beispiel, muss arrColumnValues() einfach noch um einen zusätzlichen Eintrag erweitert werden.
2) In einem weiteren Array werden die PosSize-Eigenschaften für die Anzeige auf dem Bildschirm festgelegt.
3) Das Kontrollelement wird mittels Dialog, Step, Titel und der vorher definierten Listen initiiert.
4) Eine Objekt-Variable wird mit dem Kontrollelement referenziert, um später damit arbeiten zu können.

Code: Alles auswählen

'Zuweisung von Titel, Breite und Ausrichtung für die Spaltenköpfe des Tabellen-Kontrollelements
arrColumnValues() = DimArray(2,3)
arrColumnValues(0,0) = "ID"		: arrColumnValues(1,0) = 21  : arrColumnValues(2,0) = 1
arrColumnValues(0,1) = "Vorname"	: arrColumnValues(1,1) = 15  : arrColumnValues(2,1) = 1
arrColumnValues(0,2) = "Nachname"	: arrColumnValues(1,2) = 85  : arrColumnValues(2,2) = 0

'Zuweisung von Rahmengrösse und Positionierung
arrPosSize() = Array(50, 170, 506, 253)
'Erstellung des Tabellen-Kontrollelements
call buildGridControl(oDLG_Basic, 2, "gclOverview", arrColumnValues(), arrPosSize())
oGclOverview = oDLG_Basic.getControl("gclOverview")
Wie man in der späteren Funktionsbeschreibung von buildGridControl() sieht, ist der Parameter arrRows() optional. Dieser beinhaltet die Daten für das Tabellenkontrollelement und hätte sowohl direkt bei der vorhergehenden Initialisierung mitübergeben werden können, als auch in einer eigenen Funktion, wie weiter unten beschrieben - so bestückt man dann auch während der Laufzeit das Kontrollelement.

Das Datenobjekt arrRows() ist dabei ein Array, das wiederum aus weiteren Arrays besteht (also ein Array aus Zeilen mit den jeweiligen Spaltenelementen) und müsste wie folgt aussehen...

Code: Alles auswählen

arrRows() = Array(Array(1, Müller, Peter),_
		  Array(2, Weber, Martin),_
		  Array(3, Heller, Hans))
Über eine Datenbankabfrage mittels RowSet (analog einer Schleife über eine Calc-Tabelle) könnte die Erstellung von arrRows() auch so aussehen...

Code: Alles auswählen

With oQueryOverview
	If Not isNull(oQueryOverview) Then
		While .Next()
			Redim Preserve arrRows(n)
			arrRows(n) = Array(.getInt(1), .getString(2), .getString(3))
			n = n + 1
		Wend
	End If
End With
Dies ist nun die eigentliche Funktion zur Erzeugung des Kontrollelements.
Es sind alle modifizierbaren Eigenschaften darin integriert, teilweise aber auskommentiert, da ich standardmäßig nicht alle verwende.
Diese Eigenschaften lassen sich natürlich auch jederzeit mittels z.B. .setPropertyValues() nachträglich noch verändern.
Details zu einzelnen Eigenschaften finden sich in den Kommentaren, der API-Referenz sowie der oben beschriebenen Dokumentation...

Code: Alles auswählen

'#buildGridControl(oDialog As Object, nStep As Integer, sGridControlName As String, arrColumnValues() As Variant, arrPosSize() As Variant,_
'		optional arrRows() As Variant)
'Die Funktion erzeugt anhand der mitgelieferten Inhalte und Eigenschaften ein Tabellen-Kontrollelement.

'#Param1: oDialog As Object > der Dialog, auf dem das Kontrollelement erzeugt werden soll
'#Param2: nStep As Integer > der Step des Dialoges
'#Param3: sGridControlName As String > der Titel des neuen Kontrollelements
'#Param4: arrColumnValues() As Variant > ein dreidimensionales Array mit Spalteneinstellungen: Titel, Breite und Ausrichtung
'#Param5: arrPosSize() As Variant > Position X und Y auf dem Dialog, Breite und Höhe des Kontrollelements
'#Param6: arrRows() As Variant > (optional) ein Array aus Zeilen, deren Inhalt ein Array aus Spaltenelementen darstellt
'*************************************************************************************************************************************************************
Public Sub buildGridControl(oDialog As Object, nStep As Integer, sGridControlName As String, arrColumnValues() As Variant, arrPosSize() As Variant,_
		optional arrRows() As Variant)

	If isNull(oDialog.getControl(sGridControlName)) Then 'Überprüfung, ob das Kontrollelement schon einmal initialisiert wurde
		Dim oColumnModel As Object
		Dim oDataModel As Object
		Dim oGridModel As Object
		Dim oGridControl As Object
		Dim nColumns As Integer
		Dim n As Integer

		nColumns = uBound(arrColumnValues(), 2) 'Extrahierung der Spaltenzahl durch die Elemente der 2. Dimension

		'Erzeugung des Spaltenmodells
		oColumnModel = createUnoService("com.sun.star.awt.grid.DefaultGridColumnModel")
		'*****************************************************************************************************************************************************
		Dim arrColumns(nColumns) As Variant

		For n = 0 To nColumns
			'Erzeugung eines Spaltenobjektes
			arrColumns(n) = createUnoService("com.sun.star.awt.grid.GridColumn")
			'Zuweisung von Spalteneigenschaften
			With arrColumns(n)
				.Title = arrColumnValues(0, n) 'Bezeichnung der Spalte
				.ColumnWidth = arrColumnValues(1, n) 'Spaltenbreite
				.Resizeable = True 'Spaltenbreite ist durch den Benutzer veränderbar (Voreinstellung ist "True": Spalte kann dann auch auto. durch ".Flexibility" angepasst werden)
'				.MinWidth = 50 'Mindestbreite (nur aktiv, wenn die Breite vom Benutzer verändert werden kann)
'				.MaxWidth = 200 'Maximalbreite (nur aktiv, wenn die Breite vom Benutzer verändert werden kann)
				.HorizontalAlign = arrColumnValues(2, n) 'horizontale Ausrichtung: 0 = linksbündig, 1 = zentriert, 2 = rechtsbündig
				.Flexibility = False
			End With
			oColumnModel.addColumn(arrColumns(n))
		Next
		'*****************************************************************************************************************************************************
		'Erzeugung eines Daten-Modells
		oDataModel = createUnoService("com.sun.star.awt.grid.DefaultGridDataModel")
		If Not isMissing(arrRows()) Then
			For n = 0 To uBound(arrRows())
				oDataModel.addRow("", arrRows(n)) 'Erstellung einer neuen Zeile im Daten-Modell
			Next
		End If
		'*****************************************************************************************************************************************************
		'Erzeugung des Tabellen-Modells
		oGridModel = oDialog.Model.createInstance("com.sun.star.awt.grid.UnoControlGridModel")
		'Zuweisung von allgemeinen Eigenschaften
		With oGridModel
'			.BackgroundColor = RGB(255, 255, 255) 'als Hintergrund wird der Bereich definiert, welcher zwischen Rahmen und Inhalt zu sehen ist, wenn z.B. die Spalten kleiner sind, als der äussere Rahmen
			.Border = 1
			.ColumnHeaderHeight = 12
			.ColumnModel = oColumnModel 'Zuweisung des Spalten-Modells

'			.FontName = "" '--> Diese Eigenschaft hat leider keine Auswirkung! WO der Font genau geändert werden kann, ist mir noch unbekannt.

			.GridDataModel = oDataModel 'Zuweisung des Daten-Modells
'			.GridLineColor = RGB(0, 255, 0)
'			.HeaderBackgroundColor = RGB(255, 0, 0)
			.HScroll = False
			.Name = sGridControlName 'dieser Name wird in der Ereignisbehandlung (.Model.Name) ausgelesen (GridControl.Name und GridModel.Name sollten sich also entsprechen!)
'			.RowBackgroundColors = Array(RGB(235, 235, 235), RGB(255, 255, 255))
'			.RowHeaderWidth = 10
			.RowHeight = 12
			.SelectionModel = 1 '0 = NONE, 1 = SINGLE, 2 = MULTI, 3 = RANGE
			.ShowColumnHeader = True
			.ShowRowHeader = False
			.Sizeable = True
			.Step = nStep
			.TabIndex = -1
			.Tabstop = False
'			.TextColor = RGB(255, 0, 0)
			.UseGridLines = False
			.VerticalAlign = 1 '0 = oben, 1 = mittig, 2 = unten
			.VScroll = False
		End with
		'*****************************************************************************************************************************************************
		'Erzeugung des Tabellen-Kontrollelements
		oGridControl = createUnoService("com.sun.star.awt.grid.UnoControlGrid")
		oGridControl.setModel(oGridModel) 'Zuweisung des Grid-Modells

		oDialog.addControl(sGridControlName, oGridControl) 'Erzeugung des Elements auf dem Dialog
		With oGridControl.Model
			.PositionX = arrPosSize(0)
			.PositionY = arrPosSize(1)
			.Width = arrPosSize(2)
			.Height = arrPosSize(3)
		End With
		'*****************************************************************************************************************************************************
		'Initialisierung der Ereignisbehandlung
		Dim oListener As Object
		oListener = createUnoListener("MouseListener_", "com.sun.star.awt.XMouseListener")
		oDialog.getControl(sGridControlName).addMouseListener(oListener)
	End If
End Sub
Die Funktion zur Integration der Daten in das Kontrollelement sieht wie folgt aus...
Bemerkung: Voraussetzung ist hierfür das vorhandene Datenobjekt arrRows().

Code: Alles auswählen

Public Sub swapGridRows(oControl As Object, arrRows() As Variant)
	Dim n As Integer

	With oControl.Model.GridDataModel
		.removeAllRows() 'Entfernung des gesamten Inhalts im Daten-Modell

		For n = 0 To uBound(arrRows())
			.addRow("", arrRows(n)) 'Erstellung einer neuen Zeile
		Next
	End With
End Sub
Für Click-Events auf dem Tabellenkontrollelement sollte man zwingend noch eine Prüfung der Mausposition integrieren, da z.B. der Spaltenkopf keine Zeilennummer hat und ein Klick auf diesen somit einen Fehler generieren würde.
Im Beispiel wird bei Doppelklick das erste Element der selektierten Zeile ausgegeben...

Code: Alles auswählen

Sub MouseListener_disposing(oEvent)
End Sub

Sub MouseListener_MousePressed(oEvent)
	Select Case Left(oEvent.Source.Model.Name, 3) 'Prüfung, ob das Objekt ein Tabellenkontrollelement ist
	Case "gcl"
		With oEvent.Source
			If oEvent.Y >= .Model.ColumnHeaderHeight * 2 And .CurrentRow > -1 Then 'Prüfung, ob die Mausposition unterhalb des Spaltenkopfes liegt
				If oEvent.ClickCount = 2 Then 'Prüfung, ob ein Doppelklick durchgeführt wurde
					msgbox CInt(oEvent.Source.Model.GridDataModel.getCellData(0, oEvent.Source.getCurrentRow))
				End If
			End If
		End With
	Case Else

	End Select
End Sub

Sub MouseListener_MouseReleased(oEvent)
End Sub

Sub MouseListener_MouseEntered(oEvent)
End Sub

Sub MouseListener_MouseExited(oEvent)
End Sub
... und zum Abschluss noch eine Funktion zur spezifischen Anzeige einer selektierten Zeile.

Code: Alles auswählen

'#displaySelectedGridRow(oGridControl As Object, nColumnIndex As Integer, nRowIndex As Integer)
'Die Funktion markiert eine Zeile im übergebenen GridControl und zeigt diese als erste in der Ansicht an.

'#Param1: oGridControl As Object	 >
'#Param2: nColumnIndex As Integer	 >
'#Param3: nRowIndex As Integer		 >
'*************************************************************************************************************************************************************
Public Sub displaySelectedGridRow(oGridControl As Object, nColumnIndex As Integer, nRowIndex As Integer)
	oGridControl.selectRow(nRowIndex)
	oGridControl.gotoCell(nColumnIndex, nRowIndex + 10)
End Sub
Die Ansteuerung des Tabellenkontrollelements (wie z.B. Zellen auslesen, markieren, Daten schreiben, etc.) geschieht analog zum Calc-Tabellenblatt und sollte hier deshalb keine weitere Beachtung finden.

Viel Spaß bei der Implementierung!

Liebe Grüße,

Marcel
Zuletzt geändert von marcel_at_work am Fr, 03.01.2020 17:29, insgesamt 16-mal geändert.
[Win 10 Pro x64/Downgrade 7, AOO 4.1.6 und LO 6.3.0.4]
Toxitom
********
Beiträge: 3768
Registriert: Di, 12.08.2003 18:07
Wohnort: Wiesbaden
Kontaktdaten:

Re: Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

Beitrag von Toxitom »

Hallo Marcel,
Leider existierte die zum Download ausgewiesene Beispieldatei nicht mehr, ....
Klar existiert die Datei dort noch:) Link anklicken, Kontextmenü, Datei speichern unter --> Fertig. Lediglich der Direktklick auf den Link führt zu ner 404 Seite. Da passt wohl was nicht mehr im Framework. Die Datei ist aber problemlos herunterladbar:)

Viele Grüße
Tom

Edit: ich korrigiere mich - die Datei war tatsächlich nicht ladbar. Ein Fehler wohl im Web-Framework. Ist jetzt aber wieder korrigiert und die Datei kann ganz normal herunter geladen werden ;) Einfach Klick auf den Link.
Unterstützer LibreOffice, zertifizierter Trainer und Berater
Bücher: LibreOffice 6- Einstieg und Umstieg
Makros Grundlagen - LibreOffice / OpenOffice Basic
marcel_at_work
****
Beiträge: 195
Registriert: Sa, 24.04.2010 15:51
Wohnort: Basel [CH]

Re: Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

Beitrag von marcel_at_work »

Hallöchen Tom,

hab' Dank, jetzt geht's. 8)

Dann hier nun auch deine beschriebene Beispieldatei (basierend auf einer Calc-Tabelle, mit Wechsel der Datensätze sowie auch des Spaltenmodells):

Bsp_TableGridDlg.ods
(22.96 KiB) 252-mal heruntergeladen
Viele Grüße,

Marcel
[Win 10 Pro x64/Downgrade 7, AOO 4.1.6 und LO 6.3.0.4]
Henser
Beiträge: 2
Registriert: Do, 19.12.2019 05:12

Re: Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

Beitrag von Henser »

Hi , darf ich dazu mal eine Frage stellen .
Alle wichtigen Eigenschaften sind ja dargestellt . Mir fehlt nur noch die Schriftgröße im Grid . Beim Setzen eines Wertes mit .FontHeigh passiert überhaupt nix .Kann mir da jemand weiterhelfen .
Gruß Henrik
marcel_at_work
****
Beiträge: 195
Registriert: Sa, 24.04.2010 15:51
Wohnort: Basel [CH]

Re: Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

Beitrag von marcel_at_work »

Hallo Henrik,

wie ich es oben im Code schon kommentiert habe, ist mir nicht bewusst, wo genau man erfolgreich auf die Eigenschaften des Textes zugreifen kann.

Ich habe gerade noch einmal ein paar Stunden vergeblich mit der API-Dokumentation und einigen Versuchen verbracht, aber nichts scheint zu funktionieren. Im OpenOffice.org-Wiki ist zu lesen: seit 2010 steht sowohl Font als auch Align des GridControls in der QA-Phase. Desweiteren findet man in der API die Bemerkung, daß bestimmte Eigenschaften gezeichneter Elemente eine andere Priorität haben und teils nicht verändert werden können.

Aber selbst bei einem in der IDE erstellten GridControl schlägt die Textformatierung fehl - scheinbar ist dies noch nicht implementiert?!

Viele Grüße,

Marcel
[Win 10 Pro x64/Downgrade 7, AOO 4.1.6 und LO 6.3.0.4]
Henser
Beiträge: 2
Registriert: Do, 19.12.2019 05:12

Re: Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

Beitrag von Henser »

Sehr schade , aber vielen Dank für Deine Bemühungen . Frohe Weihnachten und schöne Feiertage .
marcel_at_work
****
Beiträge: 195
Registriert: Sa, 24.04.2010 15:51
Wohnort: Basel [CH]

Re: Einführung: Tabellensteuerelement für Dialoge [UnoControlGrid]

Beitrag von marcel_at_work »

Hallo Henrik,

vielleicht hilft dir dies hier weiter.

Viele Grüße,

Marcel
[Win 10 Pro x64/Downgrade 7, AOO 4.1.6 und LO 6.3.0.4]
Antworten