Ein zwei Feinschliffe bezüglich Word

  • Moin moin,
    erst einmal danke für das tolle Forum, ihr habt mir schon sehr gut weiter geholfen, leider konnten noch nicht all meine Probleme gelöst werden.

    Erst einmal zu dem was mein Programm machen soll:
    Ich will die Möglichkeit haben einen Screenshot vom Bildschirm zu machen, diesem eine Nummer geben und ihn kommentieren. Das ganze Produkt speicher ich dann in einer Worddatei, das geht so weiter für jeden Prüfpunkt. Im Header soll der jeweilige Test-Fall, der Namen des Testers und das heutige Datum stehen. Im Footer soll "Seite X von Y" stehen.

    Es funktioniert alles so weit ganz gut. Das größte Problem habe ich mit dem Footer, das will patu nicht klappen. Schön wäre es auch wenn ich den Header schöner erzeugen könnte, das ist aber ein Luxusproblem.

    Hier einmal mein Code

    Spoiler anzeigen
    [autoit]

    #include <ButtonConstants.au3>
    #include <GUIConstantsEx.au3>
    #include <StaticConstants.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ; Implementierung der GUI
    #Region #
    $body = GUICreate("Screenshot-Tool", 307, 332, 193, 124)
    $header = GUICtrlCreateLabel("Screenshot-Tool", 72, 8, 175, 24)
    GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif")
    $wordDocInfo = GUICtrlCreateLabel("Wie soll die Worddatei heißen?", 8, 64, 181, 17)
    GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
    $info = GUICtrlCreateButton("?", 190, 58, 25, 25)
    $doc = GUICtrlCreateInput("Validierung", 8, 88, 289, 21)
    $caseInfo = GUICtrlCreateLabel("Welcher Test Case wird bearbeitet?", 8, 128, 207, 17)
    GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
    $case = GUICtrlCreateInput("Test Case / Test Fall #", 8, 152, 289, 21)
    $nameInfo = GUICtrlCreateLabel("Wie ist Ihr Name?", 8, 192, 105, 17)
    GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
    $name = GUICtrlCreateInput("Max Mustermann", 8, 216, 289, 21)
    $exit = GUICtrlCreateButton("Beenden", 216, 264, 81, 33)
    $pause = GUICtrlCreateLabel("PAUSE drücken:", 8, 264, 99, 17)
    GUICtrlSetFont(-1, 8, 800, 0, "MS Sans Serif")
    $pauseInfo = GUICtrlCreateLabel("Screenshot machen und speichern", 8, 288, 169, 17)
    GUISetState(@SW_SHOW)
    #EndRegion #

    [/autoit] [autoit][/autoit] [autoit]

    ; Das Drücken von "Pause" startet die Function print()
    HotKeySet("{PAUSE}", "print")

    [/autoit] [autoit][/autoit] [autoit]

    Func print()
    Local Const $wdHeaderFooterPrimary = 1
    local $sName = GUICtrlRead($doc) ; liest die Eingabe des Dokumentennamen aus und speichert diese in der Variable sName
    local $sFileName = @ScriptDir & "\" & $sName & ".docx"
    local $sCaseNumber = GUICtrlRead($case) ; liest die Eingabe der Casenummer aus und speichert diese in der Variable sCaseNumber
    local $sUserName = GUICtrlRead($name) ; liest die Eingabe des Testers aus und speichert diese in der Variable sUserName
    local $date = @MDAY & "." & @MON & "." & @YEAR
    ; Der Header musste etwas erschummelt werden um ihn über mehrere Zeilen hin zu bekommen
    $sHeader = "Test Case/ Test Fall #: " & $sCaseNumber & " " & "Durchgeführt von: " & $sUserName & " " & "Datum: " & $date
    $sFooter = 'Seite {PAGE \* Arabic \* MERGEFORMAT} von {NUMPAGES \* Arabic \* MERGEFORMAT}' ;Feldfunktion, kann aber leider nicht als String eingefügt werden

    [/autoit] [autoit][/autoit] [autoit]

    ; prüft ob ein Worddokument mit dem Namen aus dem Textfeld existiert und erstellt andernfals ein solches
    If Not (FileExists($sName & ".docx")) Then
    FileWrite($sName & ".docx","")

    [/autoit] [autoit][/autoit] [autoit]

    ; schreibt header (und hoffentlich bald footer)
    $oWord = ObjCreate("Word.Application")
    $oWord.Visible = False ; bleibt unsichtbar
    $oWord.Documents.Open ($sFileName) ; eine bestehende Datei aufrufen
    $oWord.ActiveDocument.Sections(1).Headers($wdHeaderFooterPrimary).Range.Text = $sHeader
    $oWord.Application.DisplayAlerts = False
    $oWord.ActiveDocument.Save
    $oWord.Quit
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;DRUCK drücken um einen screenshot zu machen
    Send("{PRINTSCREEN}")
    Sleep(200)

    [/autoit] [autoit][/autoit] [autoit]

    ; öffnet ein Eingabefeld in dem ein Kommentar geschrieben werden kann
    local $pruefpunkt = "Prüfpunkt: " & InputBox("Prüfpunkt", "Prüfpunkt eingeben")
    local $command = InputBox("Kommentar", "Kommentar eingeben")

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute($sName & ".docx", "", @ScriptDir, "edit") ; öffnet die Worddatei
    local $window = WinWait($sName,"",2) ;wartet bis zu 2 Sekunden auf das Öffnen der Worddatei, sonst Abbruch
    WinSetState($window, "", @SW_SHOW) ; legt die Worddatei in den Vordergrund

    [/autoit] [autoit][/autoit] [autoit]

    ; ans Ende des Dokumentes springen, wichtig falls es geschlossen wurde oder ähnliches
    SEND("{CTRLDOWN}{END}{CTRLUP}")

    [/autoit] [autoit][/autoit] [autoit]

    Send("{ENTER}")

    [/autoit] [autoit][/autoit] [autoit]

    ; Prüfpunkt als Überschrift des Bildes schreiben
    Send($pruefpunkt)

    [/autoit] [autoit][/autoit] [autoit]

    ; Einfügen des Bildes
    Send("{CTRLDOWN}{v}{CTRLUP}")
    Sleep(200)

    [/autoit] [autoit][/autoit] [autoit]

    ; Einfügen des Kommentars
    Send("{ENTER}")
    Sleep(200)
    Send("Kommentar:")
    Sleep(200)
    Send("{SHIFTDOWN}{ENTER}{SHIFTUP}")
    Sleep(200)
    send($command)
    Sleep(200)

    [/autoit] [autoit][/autoit] [autoit]

    ; neue Seite
    Send("{CTRLDOWN}{ENTER}{CTRLUP}")

    [/autoit] [autoit][/autoit] [autoit]

    ; minimieren der Worddatei
    WinSetState($window, "", @SW_MINIMIZE)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE, $exit
    Exit
    Case $info
    MsgBox(64,"Info","Die Worddatei dient als Dokument, welches die einzelnen Schritte und Prüfpunkte an Hand von Screenshots speichert. Sie dient als Nachweis, dass der jeweilige Test Case bearbeitet wurde.")
    EndSwitch
    WEnd

    [/autoit]
    • Offizieller Beitrag

    Das größte Problem habe ich mit dem Footer


    Dafür hatte ich vor einiger Zeit mal eine Funktion erstellt.

    Spoiler anzeigen
    [autoit]

    ;===============================================================================
    ; Function Name....: _WordDoc_FooterChange
    ; Description......: Ändert in einem Worddokument die Fußzeile
    ; Parameter(s).....: $sPath Pfad zum Word Dokument
    ; $sFooterNew Die neue Fußzeile
    ; optional $fVisible Wordfenster sichtbar, Standard=0 (Nein)
    ; optional $fSave Speichern der Änderung? Standard=1 (Ja)
    ; optional $fQuit Word beenden? Standard=0 (Nein), mit "1" wird auch $fSave=1 gesetzt
    ; Return Value(s)..: Erfolg Den alten Inhalt der Fußzeile
    ; Fehler @error = 1 - Dateipfad existiert nicht
    ; Note.............: Falls Word bereits geöffnet ist, wird in dieser Instanz gearbeitet, anderenfalls wird eine neue Instanz erstellt.
    ; Author(s)........: BugFix ( [email='bugfix@autoit.de'][/email] )
    ;===============================================================================
    Func _WordDoc_FooterChange($sPath, $sFooterNew, $fVisible=0, $fSave=1, $fQuit=0)
    If not FileExists($sPath) Then Return SetError(1,0,0)
    If $fQuit = 1 Then $fSave = 1
    Local Const $wdHeaderFooterPrimary = 1
    Local $sFooterOld, $oWord, $fCreated = 0
    $oWord = ObjGet($sPath, "Word.Application")
    If @error Then
    $oWord = ObjCreate("Word.Application")
    $fCreated = 1
    EndIf
    $oWord.Visible = $fVisible
    If $fCreated Then $oWord.Documents.Open($sPath)
    $sFooterOld = $oWord.ActiveDocument.Sections(1).Footers($wdHeaderFooterPrimary).Range.Text
    $oWord.ActiveDocument.Sections(1).Footers($wdHeaderFooterPrimary).Range.Text = $sFooterNew
    $oWord.Application.DisplayAlerts = False
    If $fSave Then $oWord.ActiveDocument.Save
    If $fQuit Then $oWord.Quit
    Return $sFooterOld
    EndFunc ;==>_WordDoc_FooterChange

    [/autoit]
  • Erstmal Danke :)

    Aber wenn ich deine Funktion richtig verstehe schreibt sie doch "nur" einen String in die Fußzeile. Ich hätte aber gerne, dass die automatische Seitenzahl (z.B Seite 3 von 8) in der Fußzeile steht. Also als Feldfunktion

    Code
    Seite {PAGE  \* Arabic  \* MERGEFORMAT} von {NUMPAGES  \* Arabic  \* MERGEFORMAT}

    nur wenn ich diese als String einfüge klappt es nicht :/

    • Offizieller Beitrag

    OK, habs dir gebastelt.

    Spoiler anzeigen
    [autoit]

    Func _WordDoc_FooterSetAutoText($sPath, $sAutoText="Seite X von Y", $iAlign=2, $fVisible=0, $fSave=1, $fQuit=1) ; iAlign: 0=links, 1=center, 2=rechts
    If not FileExists($sPath) Then Return SetError(1,0,0)
    If $fQuit = 1 Then $fSave = 1
    Local Const $wdHeaderFooterPrimary = 1
    Local $oWord, $fCreated = 0
    $oWord = ObjGet($sPath, "Word.Application")
    If @error Then
    $oWord = ObjCreate("Word.Application")
    $fCreated = 1
    EndIf
    $oWord.Visible = $fVisible
    If $fCreated Then $oWord.Documents.Open($sPath)
    Local $Footers = $oWord.ActiveDocument.Sections(1).Footers($wdHeaderFooterPrimary)
    $Footers.Range.Delete
    $Footers.Range.Select
    With $oWord.Application.Selection
    $oWord.NormalTemplate.AutoTextEntries($sAutoText).Insert(.Range, True)
    .ParagraphFormat.Alignment = $iAlign
    EndWith
    $oWord.Application.DisplayAlerts = False
    If $fSave Then $oWord.ActiveDocument.Save
    If $fQuit Then $oWord.Quit
    Return
    EndFunc

    [/autoit]
  • Moin moin,
    ich hab echt alles probiert, aber deine Funktion schreibt bei mir einfach keine Fußzeile...

    Der eigentlich wichtige Teil darin ist ja:

    Spoiler anzeigen
    [autoit]

    Local $Footers = $oWord.ActiveDocument.Sections(1).Footers($wdHeaderFooterPrimary)
    $Footers.Range.Delete
    $Footers.Range.Select
    With $oWord.Application.Selection
    $oWord.NormalTemplate.AutoTextEntries("Seite x von Y").Insert(.Range, True)
    .ParagraphFormat.Alignment = 1
    EndWith

    [/autoit]

    oder etwas nicht? aber da passiert bei mir gar nichts :/

  • Ich habe eine andere Idee, wenn das möglich wäre.
    Kann ich eine temp.docx erstellen, diese includieren, sodass ich am ende nur meine exe habe und er als template immer diese datei verwendet? wie ich das temp so nutzen könnte weiß ich, aber ich hätte es gerne so, dass ich nur meine exe zum schluss habe und keine weiteren datei.

    • Offizieller Beitrag

    Ich habe da eine Vermutung. Ich verwende ja noch "echtes" Office. Du hast ja das docx- Gedöns. Ich glaube mich zu erinnern, dass die Formatierung dort per xml geregelt wird (deshalb das x). Wäre also nicht verwunderlich, wenn sich dadurch auch der Objektzugriff geändert hat. Aber, wie gesagt, nur eine Vermutung.

  • Doc oder Docx änder nichts am Objeckt Modell.
    Die Suche im Internet nach "word insert page number visual basic" bringt z.B. folgenden Link oder diesen Link.
    Die Umsetzung von VB nach AutoIt sollte einfach sein.

  • Trotzdem ist es verwunderlich, dass die von mir gepostete Funktion in Office 2000 tadellos funktioniert und in einer neueren Version nicht.


    Ich vermute mal, dass es eher an der Weiterentwicklung von Word als am Format der Speicherung (binär oder XML) liegt.

  • Danke für die Hilfe :) von euch beiden.
    ich weiß ich hab schon so viel erfragt, aber könnte mir einer das VB in autoit übersetzen, ich bin da echt total unerfahren :/ :whistling:


    Fang doch selber mal an und wenn es Probleme gibt, dann poste Deinen Code und die Fehlermeldung. Nur so lernst Du beim nächsten Problem den grußen Fundus an VB-Lösungen im Web zu nutzen.

  • Okay, hab was von Bugfix gefunden :)

    ich nutze den VBCode:

    Spoiler anzeigen


    damit habe ich folgendes geschaft:

    Spoiler anzeigen
    [autoit]


    $oWord = ObjCreate("Word.Application")
    $oWord.Visible = False ; bleibt unsichtbar
    $oWord.Documents.Open ($sFileName) ; eine bestehende Datei aufrufen
    Local $oFooters = $oWord.ActiveDocument.Sections(1).Footers($wdHeaderFooterPrimary).Range
    With $oFooters
    .Text = "Seite PAGE von NUMPAGES Seiten"
    .ParagraphFormat.Alignment = 1
    Local $oFooters2 = $oFooters.Words(2)
    Local $oFooters4 = $oFooters.Words(4)
    .ParagraphFormat.Alignment = 1
    EndWith

    With $oFooters2.Find
    .Text = "PAGE"
    .MatchCase = True
    .MatchWholeWord = True
    While .Execute
    $oFooters2.Fields.Add ($oFooters2, -1,"", False)
    $oFooters2.Collapse(0)
    WEnd
    EndWith

    With $oFooters4.Find
    .Text = "NUMPAGES"
    .MatchCase = True
    .MatchWholeWord = True
    While .Execute
    $oFooters4.Fields.Add ($oFooters4, -1,"", False)
    $oFooters4.Collapse(0)
    WEnd
    EndWith

    [/autoit] [autoit][/autoit] [autoit]

    $oWord.Application.DisplayAlerts = False
    $oWord.ActiveDocument.Save
    $oWord.Quit

    [/autoit]

    ich hab dadurch eine schön zentrierte Fußzeile mit dem Text "Seite von Seiten"
    also noch nicht ganz was ich suche :/

    das problem liegt denke ich bei dem vb ausdruck:

    "oRng.Fields.Add oRng, wdFieldEmpty, , False"

    den ich als

    "$oFooters4.Fields.Add ($oFooters4, -1,"", False)"

    geschrieben habe, weil er mich "($oFooters4, -1, , False)" nicht schreiben lassen wollte

    6 Mal editiert, zuletzt von Time2Snowball (9. Januar 2015 um 11:06)

  • Vorher solltest Du noch entscheiden, ob Du mit Range oder Selection arbeiten willst. Selection ist der am Bildschirm angezeigte markierte Text, Range ist fast das selbe nur dass es keine Anzeige am Bildschirm gibt und daher auch den Benutzer nicht verwirrt bzw. er nicht in das Skript reinfunken kann.
    Range ist die empfohlene Vorgangsweise für die Programmierung.

  • Also entweder stehe ich echt verdammt doll auf dem Schlauch, oder wir reden aneinander vorbei.

    .ParagraphFormat.Alignment = 1 zentriert den Text der Fußzeile doch "nur". In wiefern soll das mein Problem lösen? Denn das mache ich doch schon und es funktioniert.

    Mit:

    Spoiler anzeigen
    [autoit]

    With $oFooters2.Find
    .Text = "PAGE"
    .MatchCase = True
    .MatchWholeWord = True
    While .Execute
    $oFooters2.Fields.Add ($oFooters2, -1,"", False)
    $oFooters2.Collapse(0)
    WEnd
    EndWith

    [/autoit]


    Suche ich nach dem PAGE welches ich in die Fußzeile geschrieben habe und will den Feldcode drum schreiben.
    Das würde ich in VB mit dem Befehl oRng.Fields.Add oRng, wdFieldEmpty, , False machen. Meine Problematik ist das ich keinen Plan habe, wie ich die leere Eingabe darstellen soll.
    Ich habe die letzten Tage nichts anderes gemacht als mir die Finger wund zu googlen wie ich das machen kann.
    Ich würde mich ja schon freuen, wenn ihr irgend etwas zu meinem bisherigen Code sagen könntet, ich probiere und probiere, aber ohne Rückmeldung weiß ich nicht was ich machen soll. Wo ich feststecke, oder ob vielleicht doch gar nicht die Zeile das Problem ist, sondern evtl schon mein Aufruf, die Range oder was auch immer.... :(

    • Offizieller Beitrag

    .ParagraphFormat.Alignment = 1


    Kopierst du Code nur oder liest du auch mal durch?! Aus meiner Funktion: ; iAlign: 0=links, 1=center, 2=rechts

    oRng.Fields.Add oRng, wdFieldEmpty, , False


    Was wird denn von der Funktion .Add dort erwartet? Die Parameter findest du in MSDN. Wenn die Funktion intern einen Standardwert vorbelegt kannst du das in AutoIt mit Default belegen. Denk dran, dass beim Funktionsaufruf in AutoIt alle zur Funktion gehörenden Parameter zu übergeben sind, auch wenn diese in VBA optional sein sollten.

  • Beispiel:

    [autoit]

    #include <Word.au3>

    [/autoit][autoit][/autoit][autoit]

    Global Const $wdHeaderFooterPrimary = 1 ; Returns the header or footer on all pages other than the first page of a document or section
    Global Const $wdFieldPage = 33 ; Page field
    Global Const $wdFieldNumPages = 26 ; NumPages field
    $oWord = _Word_Create()
    $oDoc = _Word_DocAdd($oWord)
    $oFooter = $oDoc.Sections(1).Footers($wdHeaderFooterPrimary) ; Object für Fusszeile erzeugen
    $oFooter.Range.Text = "Seite " ; Text in Fusszeile einfügen
    $oRange = _Word_DocRangeSet($oFooter, -2) ; Einfügemarke ans Ende der Zeile
    $oCurrentPage = $oDoc.Fields.Add($oRange, $wdFieldPage) ; Feld für aktuelle Seite einfügen
    $oRange = _Word_DocRangeSet($oFooter, -2) ; Einfügemarke ans Ende der Zeile
    $oRange.Text = " von " ; Text einfügen
    $oRange = _Word_DocRangeSet($oFooter, -2) ; Einfügemarke ans Ende der Zeile
    $oTotalPage = $oDoc.Fields.Add($oRange, $wdFieldNumPages) ; Feld für Anzahl der Seiten einfügen

    [/autoit]