Makro zum öffnen einer Datei

Hi
Ich versuche gerade ein Makro zu finden/basteln ,dass dafür sorgt, dass beim drücken einer Schaltfläche in einem Übersichtsformular, eine Textdatei (.odt) geöffnet wird, deren Dateiname den Namen beinhaltet, der im ersten Feld (Namen) des ausgewähllten Datensatzes steht und die im selben Verzeichnis liegt, wie die Datenbank. Meine Versuche mich anzunähern scheitern kläglich, weil schon der Versuch, das Makro “Datei öffnen” des Handbuches zu verwenden, damit endet, das das Objekt “DrawPage” nicht gefunden wird …

Da habe ich das Problem, dass ich das Makro nicht finde. Im aktuellen Handbuch steht eins zum Betrachten von Inhalten, was ja im Prinzip dasselbe ist.

Wenn Du bereits die Drawpage nicht finden kannst, dann versuchst Du vermutlich das Makro nicht aus einem Formular heraus zu starten. Testest Du das vielleicht gerade direkt vom Makroeditor aus?

Hyperlink buttons for files, emails and other URLs ist ein sehr einfaches aber universell einsetzbares Makro für Emailadressen, Dateien und sonstige URLs sofern letztere vollständig sind.
Öffne die angehängte Datenbank, so dass darin enthaltene Makros ausgeführt werden können.
Öffne das Formular PythonCode und klicke auf die Schaltfläche [Install].
Für Dateien würde ich wie folgt vorgehen:

  1. Binde dein Formular an eine Abfrage wie: SELECT "Tabelle".*, 'C:\pfad\' || "Dateiname" AS "SysPfad" FROM "Tabelle" oder hänge halt das verkettete Feld “SysPfad” an eine bestehende Abfrage an.
  2. Erstelle eine Schaltfläche. Die Schaltfäche hat eine Eigenschaft “Zusatzinfo”, wo du den Namen der Spalte mit dem Dateipfad einträgst. Im obigen Beispiel “SysPfad”.
  3. Binde das Ereignis “Aktion bestätigen” an das Makro “Meine Makros” → pyDBA → URLButton → FileButton_Approve.

Das Makro liest den kompletten Dateipfad aus der Spalte, die du angegeben hast, konvertiert den Pfad in eine Datei-URL und wandelt die Schaltfläche in eine Hyperlink-Schaltfläche mit eben dieser URL um.
Angenommen, du verwendest in deiner Tabelle oder Abfrage reguläre URLs mit file:// beginnend, dann ist das Makro in Schritt 3 “URLButton_Approve” statt “FileButton_Approve”. Die Umwandlung entfällt dabei.

@RobertG

Testest du das vielleicht gerade direkt vom Makroeditor aus?

Hi - So ist es - aber es funktioniert vom Formular aus auch nicht - was kein Wunder ist, weil ich keine wirkliche Ahnung habe, das umzuschreiben …
LOBase Gesamtband V76 S589

@Villeroy
Danke für den Link
Allerdings möchte ich auch verstehen was genau abläuft und habe kein gutes Gefühl aus einem Webdownload etwas zu “installieren” und auszuführen, ohne vorher behirnt zu haben, was da genau passiert … aber vielleicht erhellt sich mir das noch, bei intensiverer Beschäftigung.

@libels : Wo bleibt das Makro denn stehen, wenn Du es vom Formular aus auslöst? Da sind eigentlich nur zwei Einstellmöglichkeiten drin: Der Name des Formulars und der Name des Formularfeldes, in dem der Link steht.

@RobertG
Naja, nach dem drücken der Schaltfläche erscheint:

BASIC-Laufzeitfehler.
Es ist eine Ausnahme aufgetreten 
Type: com.sun.star.container.NoSuchElementException
Message: at ./forms/source/misc/InterfaceContainer.cxx:697.

Aber ich wundere mich nicht, da ich zum Testen einfach das Makro ohne den mailteil genommen habe und direkt Formular und Feld eingetragen habe und in der Tabelle dem Pflanzennamen des Datensatzes, den ich auswähle den Namen der Datei geschrieben habe, die geöffnet werden soll - also steht da statt Bibernelle Bibernelle.odt und die .odt befindet sich im selben Verzeichnis wie die Datenbank …

Das Gebastelte sieht so aus:


SUB Link_oeffnen
DIM oDoc AS OBJECT
DIM oDrawpage AS OBJECT
DIM oForm AS OBJECT
DIM oFeld AS OBJECT
DIM oShell AS OBJECT
DIM stFeld AS STRING
oDoc = thisComponent
oDrawpage = oDoc.Drawpage
oForm = oDrawpage.Forms.getByName("frm_Anzeige_Art")
oFeld = oForm.getByName("int_tbl_Art.Pflanze")
stFeld = oFeld.Text
IF stFeld = "" THEN
EXIT SUB
END IF
oShell = createUnoService("com.sun.star.system.SystemShellExecute")
oShell.execute(stFeld,,0)
END SUB

Tja und eigentlich ist die Vorstellung, dass das Makro im “fertigen” Zustand …
Wenn die Schaltflläche ausgelöst wird selbst erkennt in welchem Formular es ist, den Feldnamen aus den Zusatzinformationen liest und dann aus dem dort befindlichen Pflanzennamen den Dateinamen kreiert indem es das .odt (oder wenn nicht vorhanden, dann .doc oder .txt …) anhängt (oder aus einem Unterordner des Datenbankverzeichnisses) und das dafür vom System vorgesehene Programm mit der Datei öffnet …
:man_shrugging: :upside_down_face: :slightly_smiling_face:

oFeld = oForm.getByName("int_tbl_Art.Pflanze")

Mich irritiert diese Zeile. Ist das der Name des Feldes mit dem Punkt? Ich denke nein. Das kann so nicht funktionieren.

@libels: Wenn die Basic Fehlermeldung kommt, dann wird der Macrocode geöffnet. Wechsele zum Macrocode. Da steht dann der Cursor auf der Zeile, die ein Problem ist. Da schein ja ein Element zu sein, das nicht existiert. Ist frm_Anzeige_Art vielleicht kein Hauptformular? Zeige einmal einen Screenshot des geöffneten Formularnavigators mit Formularnamen und Feldnamen.

Du hast in dem Code leider auch stFeld = convertToUrl(stFeld) raus genommen. Dadurch muss der Inhalt von oFeld auf jeden Fall sicher ein Link mit file:/// sein.

Schau dir doch einfach den Quellcode an. Er liegt offen vor dir. Die 6 Zeilen Python machen einfach nur genau das, was ich oben beschrieben habe. Das Installations-Makro (Basic) kannst Du dir sparen, indem Du das Formular mit dem Python-Code ohne jede Änderung als einfache Textdatei in deinem Nutzerprofil speicherst. Die entscheidenden Zeilen Basic, die das machen sind:

	Dim p(0) as new com.sun.star.beans.PropertyValue
	p(0).Name = "FilterName"
	p(0).Value = "Text"
	ThisComponent.storeToURL(sFull, p())

Davor wird der Pfad des Nutzerverteichnises ermittelt, der Unterpfad und Dateiname aus dem Textfeld ermittelt und gegebenenfalls der Unterpfad angelegt.

Python-Code mit dt. Kommentierung

def URLButton_Approve(oEv):
    openURL(oEv, False) #Ausführung ohne URL-Konvertierung

def FileButton_Approve(oEv):
    openURL(oEv, True) #Auführung mit URL-Konvertierung

def openURL(oEv, bConvertToURL):
    oModel = oEv.Source.getModel() #Zufriff auf Eigenschaften der aufrufenden Schaltfläche
    oModel.ButtonType = URL # Aktion: "Öffne Dokument oder URL"
    oForm = oModel.getParent() # Das Elternelement einer Schaltfläche ist das Formular
    oColumn = oForm.Columns.getByName(oModel.Tag) #oModel.Tag ist Eigenschaft "Zusatzinformationen". Zugriff auf Spalte, deren Name dort angegeben ist.
    if bConvertToURL:
        sURL = uno.systemPathToFileUrl(oColumn.getString()) #konvertiere zu URL
    else:
        sURL = oColumn.getString() #nimm den Spalteninhalt wie er ist
    oModel.TargetURL = sURL # Die URL unserer Schaltfläche mit Aktion "Öffne Dokument oder URL"

@RobertG
Ich habe das convertToUrl wieder belassen …

SUB Link_oeffnen
DIM oDoc AS OBJECT
DIM oDrawpage AS OBJECT
DIM oForm AS OBJECT
DIM oFeld AS OBJECT
DIM oShell AS OBJECT
DIM stFeld AS STRING
oDoc = thisComponent
oDrawpage = oDoc.Drawpage
oForm = oDrawpage.Forms.getByName("IntArt")
oFeld = oForm.getByName("fn_Name")
stFeld = oFeld.Text
IF stFeld = "" THEN
EXIT SUB
END IF
IF InStr(stFeld,"@") THEN
stFeld = "mailto:"+stFeld
ELSE
stFeld = convertToUrl(stFeld)
END IF
oShell = createUnoService("com.sun.star.system.SystemShellExecute")
oShell.execute(stFeld,,0)
END SUB

aber es kommt immer wieder die Fehlermeldung

BASIC-Laufzeitfehler.
Es ist eine Ausnahme aufgetreten 
Type: com.sun.star.container.NoSuchElementException
Message: at ./forms/source/misc/InterfaceContainer.cxx:697.

Im Makro wird folgende Zeile Markiert:
oForm = oDrawpage.Forms.getByName("IntArt")

Wobei ich es mit allen mir denkbaren möglichkeiten für “Formular” versucht habe:

Das Fomular in dem das alles passiert heißt: frm_Anzeige_Art
Wenn ich in den Formularnavigator sehe, Habe ich als oberstes Formular ein Formular, das den Namen “Art” trägt und dessen Dateninhalt die Tabelle tbl_Art ist.
Das Unterformular trägt den Namen intArt und hat als Dateninhalt die Tabelle int_tbl_Art (die Zwischentabelle mit den Primärschlüsseln)- In dieser Formularhierarchieebene ist auch die Schaltfläche mit dem Makro angesiedelt Die darin befindlichen Felder sind Listenfelder, die sich mittels SQL auf die Inhalte der Pflanzentabelle beziehen.
Das Feld, dessen Inhalt im aktuellen Datensatz bearbeitet werden soll, trägt den Namen: fn_Name und den Titel: Pflanze der Dateninhalt ist PflanzenID und das Listenfeld hat den Inhalt:

"SELECT "Name", "PflanzenID" FROM "tbl_Pflanzen" ORDER BY "Name" ASC"

Ich habe es im Makro in der Zeile wo man das Formular eintragen soll mit intArt, int_tbl_Art und sogar mit “Tabellen-Steuerelement 1”, weil dieses die Spaltenfelder beinhaltet, versucht …
Es bleibt bei obiger Fehlermeldung …

  • wobei das ja ohnehin ein Punkt ist, den ich so nicht belassen möchte, denn ich möchte das Makro in mehreren Formularen nutzen und dann nicht für jedes Formular ein eigenes Makro erstellen - mit dem jeweils eingetragenem Formular und Feld …

Es gibt eine Beispieldatenbank zum Handbuch, dass sich Beispiel_Formular_Eingabekontrolle_Firebird nennt - da gibt es ein Makro (bzw. dern mehrere) das so aussieht und das ich aber nicht wirklich verstehe

SUB LinkOpen(oEvent AS OBJECT)
	DIM oField AS OBJECT, oShell AS OBJECT, oDoc AS OBJECT
	DIM i AS INTEGER
	DIM stUrl AS STRING, stField AS STRING
	DIM a()
	IF oEvent.Modifiers = 2 THEN	'Modifiers: Strg-Taste = 2, Alt-Taste = 4, Shift-Taste = 1 
		' https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1KeyModifier.html
		' Aufruf eines Links, öffnen des dazugehörigen Programms
		oField = oEvent.Source.Model
		'Bei einem ImageControl gibt es keine Eigenschaft "Text", deshalb hier der Bezug auf die zugrundeliegende Tabelle und den dortigen Link		
		stField = oField.BoundField.String
		IF stField = "" THEN
			EXIT SUB
		END IF
		IF InStr(stField,"@") THEN
			stField = "mailto:"+stField
		ELSE
			IF InStr(stField,"http") = 0 THEN 'http-Links sind komplett
				IF InStr(stField,"file:///") = 0 THEN 'absolute Links wurden mit file:/// abgespeichert, relative Links müssen zu absoluten umgewandelt werden
					oDoc = ThisComponent
					a = split(oDoc.Parent.Url,"/")	'Dateinamen abtrennen, geht nicht einfach über den Dateinamen, da der nicht Url-konform sein kann.
					FOR i = LBound(a()) TO UBound(a()) - 1	'-1 lässt das letzte Element ausfallen (- Dateinamen), könnte um die Aufwärtsschritte gemindert werden
						stUrl = stUrl & a(i) & "/"
					NEXT
					stField = stUrl & stField
				END IF
			END IF
		END IF
		'Start des Files mit der entsprechenden URL-Verbindung
		oShell = createUnoService("com.sun.star.system.SystemShellExecute")
		oShell.execute(stField,,0)
	END IF
END SUB

SUB MapPosition(oEvent AS OBJECT)
	'Mit dieser Prozedur kann zu einer Adresse, die in einem Formular steht, eine Karte auf nominatim.openstreetmap.org
	'geöffnet und das entsprechende haus angezeigt werden, sofern es bei Openstreetmap verzeichnet ist https://operations.osmfoundation.org/policies/nominatim/
	DIM oForm AS OBJECT, oShell AS OBJECT
	DIM i AS INTEGER
	DIM stLink AS STRING, stTag AS STRING
	DIM arFields()
	stTag = oEvent.Source.Model.Tag
	oForm = oEvent.Source.Model.Parent
	arFields = Split(stTag,",")
	FOR i = LBound(arFields) TO UBound(arFields)
		IF stLink = "" THEN
			stLink = oForm.getByName(arFields(i)).CurrentValue
		ELSE
		stLink = stLink & "+" & oForm.getByName(arFields(i)).CurrentValue
		END IF
	NEXT i
	IF stLink <> "" THEN
		stLink = "https://nominatim.openstreetmap.org/search.php?q=" & Join(Split(stLink),"+") & "&polygon_geojson=1&viewbox="
		'Start des Files mit der entsprechenden URL-Verbindung
		oShell = createUnoService("com.sun.star.system.SystemShellExecute")
		oShell.execute(stLink,,0)
	END IF
END SUB
  • wenn ich es "verwende " kommt die Fehlermeldung “no such Modifier” …

Tja :man_shrugging:

@getobject.de
Tja, was ist “der Name des Feldes” ? Wie es in den Eigenschaften genannt wird, oder ist sein Titel gemeint oder ist der Feldname der zugrunde liegenden Tabelle oder des Tabellenfeldes des SQL-Codes gemeint ? → siehe meine Antwort auf @RobertG

Nur um diesen Namen geht es. Liegt denn in diesem Formular das Feld “fn_Name”? Der Name muss dann im Formularnavigator direkt unterhalb des Formulars “Art” liegen.

Ich vermisse den Screenshot, aus dem ich die Namen im Formularnavigator ersehen kann.

@RobertG


Kräuter_Indikationen.odb (257.8 KB)

Da sind gleich mehrere Haken drin: Bei dem Formular handelt es sich um ein Unterformular.

In dem Unterformular liegt das Feld, das Du auslesen willst in einem Listenfeld innerhalb eines Kontrollfeldes. Von dem Listenfeld willst Du außerdem nicht den Wert, sondern den angzeigten Inhalt auslesen. Und wie Du mit dem angezeigten Inhalt zu einem lesbaren Link kommen willst erschließt sich mir auch nicht.

Das Formular könntest Du über

oDrawpage.Forms.getByName("Art").getByName("intArt")

oder auch über den auslösenden Button ermitteln.
Das Feld kommst Du eventuell über

oFeld = oForm.getByName("Tabellensteuerelement 1").getByName("fn_Name")

Aber weiter komme ich damit auch nicht, weil Du ein Tabellenkontrollelement mit lauter Listenfeldern voll gepackt hast, die alle mit dem gleichen Fremdschlüsselfeld verbunden sind.

Warum machst Du nicht eine Abfrage, auf der dieses Unterformular basiert - ganz ohne Listenfelder?

Meine Güte, Du kannst doch eh nicht programmieren. Nimm doch einfach mein Makro, das hundertfach bewährt ist und mit jedem Element in jedem Ober- oder Unterformular einfach so funktioniert. Es funktioniert sogar in Basic, obwohl das schwieriger zu installieren ist, weshalb ich das in Python verbreite.
Der Code ist bis auf die Basic-Syntax identisch:

REM  *****  BASIC  *****

Sub URLButton_Approve(oEv)
    openURL(oEv, False)
End Sub

Sub FileButton_Approve(oEv)
    openURL(oEv, True)
End Sub

Sub openURL(oEv, bConvertToURL)
    oModel = oEv.Source.getModel()
    oModel.ButtonType = com.sun.star.form.FormButtonType.URL
    oForm = oModel.getParent()
    oColumn = oForm.Columns.getByName(oModel.Tag)
    if bConvertToURL then
        sURL = convertToUrl(oColumn.getString())
    else
        sURL = oColumn.getString()
    endif
    oModel.TargetURL = sURL
End Sub

@Villeroy
Das sind ja, soweit ich es sehe 3 Makros - wie binde ich die ein ?
lg

@RobertG

Kurz gesagt: Weil ich nicht wusste, dass das ein Problem darstellt :slight_smile: und nicht daran gedacht habe.

Aber auch wenn ich das auf eine Abfrage statt der Listenfelder “umschnitze” - Ich habe statt dem int_table mit den Listenfeldern eine Abfrage des tbl_Pflanzen mit der Art_Id aus dem int_tbl_Art generiert (Art_Pflanzen) und diese statt dem jetzigen UF eingebunden (heißt jetzt: “ArtPflanzen”) … funktioniert auch :slight_smile: … aber…

oDrawpage.Forms.getByName("ArtPflanzen").getByName("Art_Pflanzen")

… produziert die gleiche Fehlermeldung.

BASIC-Laufzeitfehler.
Es ist eine Ausnahme aufgetreten 
Type: com.sun.star.container.NoSuchElementException
Message: at ./forms/source/misc/InterfaceContainer.cxx:697.

lg

Eben das ist das Problem: Du versuchst alles Mögliche nach der Methode Trial- and Error. Das wird nie zu einem Erfolg führen. Da Du auch noch gar nicht irgendwo sichtbar einen Link in einer Deiner Tabelle hast weiß ich nicht mehr, was das Ganze soll. Da ist jede Hilfe von mir vergeblich.

@RobertG
Ich hatte das Eingangs des Thread geschrieben. Es liegen Dokumente im selben Verzeichnis wie die Datenbank. Diese haben den Namen der Pflanze und die Endung .odt. Das Makro sollte nun aus dem Namen im Feld den Pflanzennamen auslesen, an diesen Namen ein “.odt” anhängen und es mit dem vom System für .odt vorgesehenen Programm öffnen. (Als Erweiterung evt. wenn es keine Datei mit .odt gibt es mit .doc oder .txt versuchen). Da bräuchte ich eben kein Feld mit einem Link, da der Link eben einer wiederkehrenden Logik unterliegt, nämlich Name + .odt im selben Verzeichnis wie die Datenbank. (Variante: Im Unterverzeichnis “Dokumente” des Datenbankverzeichnisses).