🙏 Helfen Sie jetzt mit, unser LibreOffice Forum zu erhalten! 🙏
Mit Ihrer Spende sichern Sie den Fortbestand, den Ausbau und die laufenden Kosten dieses Forums. 🌱

🍀 Jeder Beitrag zählt – vielen Dank für Ihre Unterstützung!🍀

❤️ DANKE >> << DANKE ❤️

>> Dank Ihrer Unterstützung -> Keine Werbung für alle registrierten LibreOffice-Forum User! <<
🤗 Als Dankeschön werden Sie im Forum als LO-SUPPORTER gekennzeichnet. 🤗

Formular bei Start einer ODS-Datei

Alles zur Programmierung im LibreOffice.
jg-n-py
Beiträge: 17
Registriert: Mi 7. Mai 2014, 21:24

Formular bei Start einer ODS-Datei

Beitrag von jg-n-py » Di 20. Mai 2014, 17:57

Hallo zusammen.

Viele Arbeitsabläufe waren früher mittels VBA und MS-Excel realisiert. Leider können die VBA-Kenntnisse nicht direkt übertragen werden, insbesondere Formulare :( Das Ganze wollen wir in Python schreiben, da ein bischen Know how vorhanden ist - zudem wurden bereits Makros und Zellfunktionen in Python und LibreOffice geschrieben.

Also folgendes Anliegen bzw. der gewünschte Ablauf im Stenogramm:

1) User öffnet neue Datei mittels einer Vorlage
2) Beim Dateistart öffnet sich Formular zur Datenabfrage.
3) Abhängig von der Usereingabe im Formular werden Daten aus anderen Dateien in das Dokument eingebunden.
4) Erst jetzt kann der User das Dokument (Spreadsheet) wie gewohnt bearbeiten.

Wie kann sowas realisiert werden.

Vielen Dank im Voraus

pstoelzg
Beiträge: 9
Registriert: Fr 8. Aug 2014, 10:38

Re: Formular bei Start einer ODS-Datei

Beitrag von pstoelzg » Fr 8. Aug 2014, 16:16

Hallo jg-n-py,

ich hatte mich auch schon mal mit LibreOffice/ Python/ einfachen grafischen Benutzeroberflächen beschäftigt... Angeblich sollen sich selbige mit Hilfe von TkInter realisieren lassen (https://wiki.python.org/moin/TkInter), das ist eine Bibliotheksstruktur, die bei Python standardmäßig dabei ist. Ich muss jedoch gestehen, dass ich mit meinen Versuchen gescheitert bin, die TkInter Module überhaupt anzusprechen...

Das Programmieren mit TkInter an sich ist gut dokumentiert, nicht besonders kompliziert und ähnelt einigen anderen Grafikbibliotheken.

Vielleicht solltest Du es auf Deinem speziellen System (Windows, Linux, Mac, etc.) mit Deiner speziellen Konfiguration (Python 2.7, Python 3.0; LibreOffice x.y) einfach mal ausprobieren. Die Informationen in diversen Foren geben jedoch nicht viel Grund zur Hoffnung: https://forum.openoffice.org/en/forum/v ... hp?t=31426



So long,
Peter

jg-n-py
Beiträge: 17
Registriert: Mi 7. Mai 2014, 21:24

Re: Formular bei Start einer ODS-Datei

Beitrag von jg-n-py » Di 12. Aug 2014, 14:01

Danke @pstolzg,

wir sind bereits mit Tkinter vertraut und haben das Formular bereits erstellt.

Was wir bisher noch nicht erreicht haben (aber auch weil momentan andere Aufgaben im Vordergrund stehen):
  • Wo muss ich die Startsequenz für das Formular platzieren, so dass es beim Starten der Datei/Vorlage automatisch die Datenabfrage macht?
    Das Formular wird mit mehreren Daten gefüllt, die ins Dokument an verschiedenen Stellen eingetragen werden sollen. Wie schafft man das?
Danke im Voraus

pstoelzg
Beiträge: 9
Registriert: Fr 8. Aug 2014, 10:38

Re: Formular bei Start einer ODS-Datei

Beitrag von pstoelzg » Mi 13. Aug 2014, 15:50

Hallo jg-n-py

ich werde die beiden Fragen aus Deinem letzten Beitrag der Reihe nach beantworten. So gut ich kann.

Dazu sei aber folgendes angemerkt:
1. Deine Formulierungen sind sehr allgemein gehalten
2. Für die meisten Probleme gibt es mehr als eine Lösung

---

F1
Wo muss ich die Startsequenz für das Formular platzieren, so dass es beim Starten der Datei/Vorlage automatisch die Datenabfrage macht?
A1
Wenn ich die Frage richtig verstehe, suchst Du nach dem Event, dass beim Öffnen der Datei automatisch die Routine ausführt, die das Formular (mit all seinen Unterobjekten) erzeugt. Falls meine Vermutung zutrifft, so findest Du auf folgender Website Informationen, die Dir weiterhelfen werden:
http://www.starbasicfaq.de/WiekannmanMa ... ument.html

---

F2
Das Formular wird mit mehreren Daten gefüllt, die ins Dokument an verschiedenen Stellen eingetragen werden sollen. Wie schafft man das?
A2
Bei der Programmierung von Grafischen Benutzeroberflächen mit Hilfe von entsprechenden Bibliotheken (wie z.B. tkinter) handelt es sich wohl (beinahe) immer um objektorientierte Programmierung. Des weiteren spricht man im Zusammenhang mit objektorientierte Programmierung häufig von (Objekt-) Hierarchien. Im Falle von selbstgestalteten Dialogen heißt das:
* erst wird ein Frame erzeugt (Elternobjekt)
* diesem Objekt, dass ich mir gerne als eine Art von Container vorstelle, werden Unter- oder Kindobjekte bzw. Grupen von Kindobjekten zugeordnet

Der Zugriff auf Objekte erfolgt über die Punktnotation, hier ein Beispiel:
sCustomerName = oFrame.oTextBox_CustomerName.getText()
Der o.a. Befehl soll lediglich das Konzept verdeutlichen! Mit seiner Hilfe kann man den Text aus dem TextBox Objekt 'CustomerName' auslesen, welches dem Elternobjekt 'oFrame' zugeordnet ist.



Ich hoffe, dass ich Deine Frage verstanden habe und Dir mit meiner Antwort weiterhelfen konnte,
Peter

jg-n-py
Beiträge: 17
Registriert: Mi 7. Mai 2014, 21:24

Re: Formular bei Start einer ODS-Datei

Beitrag von jg-n-py » Fr 15. Aug 2014, 16:44

Hallo @pstoelzg

Vielen Dank - und ich habe mich wahrscheinlich sehr undeutlich ausgedrückt. Ich werde es nun etwas genauer Versuchen.

Was wir wollen:

Wir haben bereits eine geeignete Vorlage erstellt mit deren Hilfe ein neues Dokument erzeugt wird. In das dadurch neu zu erstellende Dokument sind eine ganze Menge an Daten einzugeben Da es sich dabei um abhängige Daten handelt, werden diese Teils aus anderen Dokumenten/Datenbanken etc ausgelesen

Der Ablauf ist eigentlich dem eines Datenwizards nicht unähnlich. Schritt für Schritt werden vom User Daten eingetragen und auf der Eingabe basierend andere, relevante Daten in andere Felder/Tabs/Seiten des Wizards eingetragen. Wird am Ende dieser Wizard geschlossen, und die gesamten Daten werden dann in das eigentiche Dokument (die *.ods-Datei) eingetragen.

=> also in Kürze der Ablauf:

1. Neue Datei per Vorlage starten
2. Tkinter-Formular (Wizard) anzeigen
3. User gibt dort die Kundennummer ein, woraufhin automatisch all dessen Stammdaten (u.a.) eingetragen und alle weiteren Seiten des Tkinter-Formulars (Wizards) gefüllt werden. Auf den weiteren Seiten sind weitere Daten zu bestätigen...


Fragen:

Wo muss ich das Makro einhängen, damit der Wizard gleich zu Beginn (aber nur bei der Dokumentenerzeugung) startet? Ich weiß aus der LibreOffice-Hilfe, dass es unter Extras>Anpassen die entsprechenden Events gibt, aber welcher ist der Richtige - meine Vermutung "Neues Dokument"?

Ich habe ein stark vereinfachtes Tkinter-Formular zum Testen des Vorhabens erstellt. Der Aufruf unter Python selbst funktioniert einwandfrei, aber in der Laufzeitumgebung von LibreOffice tritt ein Fehler auf.
Fehleranzeige beim Start der Vorlage
Fehleranzeige beim Start der Vorlage
macrofehler.png (17.31 KiB) 5309 mal betrachtet

Hier die Datei formulartest.py, die im entsprechenden Verzeichnis für die Makromodule gespeichert ist:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! Dies ist nur ein Testmodul !!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
"""

import unohelper
import locale
import os
import ttk  # enthaelt Tkinter als ttk.Tkinter


tk = ttk.Tkinter
ENC = locale.encodings.codecs.lookup(locale.getdefaultlocale()[1]).name


class Kunde(object):
    def __init__(self):
        self.nr = ""
        self.name = ""
        self.vorname = ""

    def __unicode__(self):
        return u"[%s] %s %s" % (self.nr, self.name, self.vorname)

    def __str__(self):
        return self.__unicode__().encode(ENC)


def run():

    _window_ = tk.Tk()
    _window_.title("Kundendaten")
    _window_.geometry("400x100")
    _body_ = tk.Frame(_window_)


    class Model(Kunde):
        def __init__(self):
            Kunde.__init__(self)

            self._nummer_ = tk.StringVar()
            self._nummer_.set("2KP259TKX")      # FIXME: TESTPHASE

            self._name_ = tk.StringVar()
            self._name_.set("Meier")            # FIXME: TESTPHASE

            self._vorname_ = tk.StringVar()
            self._vorname_.set("Josef")         # FIXME: TESTPHASE

        def transfer(self):
            self.nr = self._nummer_.get()
            self.name = self._name_.get()
            self.vorname = self._vorname_.get()

            # logging falls noetig (interner Aufruf von __str__())
            print self

            _window_.quit()
    mydata = Model()

    # Kundennummer

    tk.Label(_body_, text="KuNr.:").grid(row=1, column=0)

    txtKunr = tk.Entry(_body_)
    txtKunr.config(textvariable=mydata._nummer_)
    txtKunr.grid(row=1, column=1)

    # Kundenname

    tk.Label(_body_, text="Name:").grid(row=2, column=0)

    txtName = tk.Entry(_body_)
    txtName.config(textvariable=mydata._name_)
    txtName.grid(row=2, column=1)

    # Kundenvorname

    tk.Label(_body_, text="Vorname:").grid(row=3, column=0)

    txtVorname = tk.Entry(_body_)
    txtVorname.config(textvariable=mydata._vorname_)
    txtVorname.grid(row=3, column=1)

    # Buttons

    _ok_ = tk.Button(_body_,
                     text="OK",
                     command=mydata.transfer)
    _cancel_ = tk.Button(_body_,
                         text="CANCEL",
                         command=_window_.quit)
    _ok_.grid(row=4, column=1)
    _cancel_.grid(row=4, column=0)

    _body_.grid()
    _window_.mainloop()

    # FIXME:
    #   schreibe die Daten an passender Stelle in die
    #   Datei ein:
    #                   1. Spalte       2.Spalte
    #       1. Zeile:   Kundennummer:   ________
    #
    #       3. Zeile:   Name:           ________
    #       4. Zeile:   Vorname:        ________
    #

    try:
        doc = XSCRIPTCONTEXT.getDocument()
        sheet = doc.Sheets.getByName("Tabelle1")

        cellNummer = sheet.getCellByPosition(1, 2)
        cellNummer.String = mydata.nr

        cellName = sheet.getCellByPosition(3, 2)
        cellName.String = mydata.name

        cellVorname = sheet.getCellByPosition(4, 2)
        cellVorname.String = mydata.vorname

    except NameError:
        pass

    return mydata.nr, mydata.name, mydata.vorname


g_exportedScripts = run,


# Test des Pythoncodes
if __name__ == "__main__": run()


Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2539
Registriert: Fr 10. Dez 2010, 10:01

Re: Formular bei Start einer ODS-Datei

Beitrag von karolus » Fr 15. Aug 2014, 17:48

Hallo

Du rufst die Funktion aus LO heraus vmtl. über eine Schaltfläche oder über irgendein anderes Event auf.
Dieses Event wird an die aufgerufene Funktion als Argument durchgereicht***.
Lösung:
Trag in der Funktionssignatur ein optionales Argument ein:

Code: Alles auswählen

def run( *event ):
    .... 
***dieses Verhalten hat den Vorteil das man in der Funktion differenziert auf Informationen aus event.Source...whatever reagieren kann, wie ich das bsplw. hier mit den 'Namen' des auslösenden Optionsbuttons gemacht habe.

Karolus
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)

jg-n-py
Beiträge: 17
Registriert: Mi 7. Mai 2014, 21:24

Re: Formular bei Start einer ODS-Datei

Beitrag von jg-n-py » Fr 15. Aug 2014, 18:23

Vielen Dank @karolus,

diesen Fehler hatte ich schon behoben, aber dafür schenkte mir LibreOffice nun einen neuen Fehler - yipii:
Neuer Fehler
Neuer Fehler
macrofehler2.png (28.76 KiB) 5299 mal betrachtet
An dem habe ich mir die letzten eineinhalb Stunden die Zähne ausgebissen... :( Vor allem die Info, dass das Modul kein Attribut 'argv' besitzt kann ich nicht zuordnen, denn das Modul sys hat sehr wohl ein Member argv.

Ich zeige mal den relevanten Ausschnitt des Tkinter-Moduls - den Konstruktor __init__ (bei mir ab Zeile 1661 in python2.7/lib-tk/Tkinter.py):

Code: Alles auswählen

class Tk(Misc, Wm):
    """Toplevel widget of Tk which represents mostly the main window
    of an application. It has an associated Tcl interpreter."""
    _w = '.'
    def __init__(self, screenName=None, baseName=None, className='Tk',
                 useTk=1, sync=0, use=None):
        """Return a new Toplevel widget on screen SCREENNAME. A new Tcl interpreter will
        be created. BASENAME will be used for the identification of the profile file (see
        readprofile).
        It is constructed from sys.argv[0] without extensions if None is given. CLASSNAME
        is the name of the widget class."""
        self.master = None
        self.children = {}
        self._tkloaded = 0
        # to avoid recursions in the getattr code in case of failure, we
        # ensure that self.tk is always _something_.
        self.tk = None
        if baseName is None:
            import sys, os
            baseName = os.path.basename(sys.argv[0])
            baseName, ext = os.path.splitext(baseName)
            if ext not in ('.py', '.pyc', '.pyo'):
                baseName = baseName + ext
        interactive = 0
        self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
        if useTk:
            self._loadtk()
        self.readprofile(baseName, className)

Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2539
Registriert: Fr 10. Dez 2010, 10:01

Re: Formular bei Start einer ODS-Datei

Beitrag von karolus » Fr 15. Aug 2014, 18:52

Hallo

Aber im Kontext des Libreofficeprozesses gibts kein sys.argv

möchtest du wirklich mit TKinter und Libreoffice gleichzeitig jonglieren 8-)

ersetze sys.argv[0] durch __file__
oder besser gleich durch uno.fileUrlToSystemPath(__file__)
(uno ggf.vorher importieren )

edit: vergiss die letzten drei Zeilen, du kannst ja nicht im TKinter-modul rumpfuschen,
evtl. reicht es wenn du beim konstruieren von Tk gleich einen Basename mitgibst



Karolus
Zuletzt geändert von karolus am Fr 15. Aug 2014, 19:21, insgesamt 1-mal geändert.
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)

jg-n-py
Beiträge: 17
Registriert: Mi 7. Mai 2014, 21:24

Re: Formular bei Start einer ODS-Datei

Beitrag von jg-n-py » Fr 15. Aug 2014, 19:10

Warum hat den das Modul sys im Kontext von LO kein argv?
möchtest du wirklich mit TKinter und Libreoffice gleichzeitig jonglieren
- So haben wir uns das vorgestellt - **schien** uns am einfachsten!!! :o

Gibt es denn eine andere, einfachere Lösung?

Was ist mit dem wirklich üblen Hack, dem Modul sys schlicht ein argv zu verpassen und um Tkinter an besagter Stelle zu beruhigen?

Ein Versuch dessen hat das Formular gezeigt, dieses war dann aber nicht mehr ansprechbar:

Code: Alles auswählen

def run(event):
    # uebler Tkinter-hack
    sys.__dict__["argv"] = ["",]
    ...
Tschuldige @karolus - habe Deinen Hack von sys.argv wohl übersehen... - ich probier ihn mal aus.

Benutzeravatar
karolus
* LO-Experte *
Beiträge: 2539
Registriert: Fr 10. Dez 2010, 10:01

Re: Formular bei Start einer ODS-Datei

Beitrag von karolus » Fr 15. Aug 2014, 19:25

Hallo

Nein, probier den nicht aus versuch lieber in deiner run()-funktion gleich einen basename mit zugeben:

Code: Alles auswählen

def run(*event):

    _window_ = tk.Tk(baseName='irgendwas_passendes') 
und setze *event optional damit der Aufruf auch noch funktioniert ohne Libreofficekontext.
LO7.4.7.5 debian 12(bookworm) auf Raspberry4b 8GB (64bit)
LO24.8.0.3 flatpak debian 12(bookworm) auf Raspberry4b 8GB (64bit)


An alle, die das LibreOffice-Forum gern nutzen und unterstützen wollen:


Bitte helfen Sie uns mit 7 Euro pro Monat.
Durch Ihren Beitrag tragen Sie dazu bei, unsere laufenden Kosten für die kommenden Monate zu decken.
Unkompliziert per Kreditkarte oder PayPal.
Als ein kleines Dankeschön werden Sie im LO-Forum als SUPPORTER gekennzeichnet.



Antworten