Writer - Textrahmen verlassen

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

Moderator: Moderatoren

Niels
*****
Beiträge: 212
Registriert: Mi, 16.06.2004 06:46
Wohnort: Heikendorf

Writer - Textrahmen verlassen

Beitrag von Niels »

Hallo zusammen,

wenn mein Cursor in einem Rahmen steht, durchsucht mein Makro nur den Rahmen. Also stellt sich mir die Frage, wie ich den Rahmen per Makro verlassen kann.

Danke
Niels

Code: Alles auswählen

sub Farblayout
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(18) as new com.sun.star.beans.PropertyValue
args1(0).Name = "SearchItem.StyleFamily"
args1(0).Value = 2
args1(1).Name = "SearchItem.CellType"
args1(1).Value = 0
args1(2).Name = "SearchItem.RowDirection"
args1(2).Value = true
args1(3).Name = "SearchItem.AllTables"
args1(3).Value = false
args1(4).Name = "SearchItem.Backward"
args1(4).Value = false
args1(5).Name = "SearchItem.Pattern"
args1(5).Value = false
args1(6).Name = "SearchItem.Content"
args1(6).Value = false
args1(7).Name = "SearchItem.AsianOptions"
args1(7).Value = false
args1(8).Name = "SearchItem.AlgorithmType"
args1(8).Value = 0
args1(9).Name = "SearchItem.SearchFlags"
args1(9).Value = 65536
args1(10).Name = "SearchItem.SearchString"
args1(10).Value = "@@Suchtext!!"
args1(11).Name = "SearchItem.ReplaceString"
args1(11).Value = ""
args1(12).Name = "SearchItem.Locale"
args1(12).Value = 255
args1(13).Name = "SearchItem.ChangedChars"
args1(13).Value = 2
args1(14).Name = "SearchItem.DeletedChars"
args1(14).Value = 2
args1(15).Name = "SearchItem.InsertedChars"
args1(15).Value = 2
args1(16).Name = "SearchItem.TransliterateFlags"
args1(16).Value = 1280
args1(17).Name = "SearchItem.Command"
args1(17).Value = 0
args1(18).Name = "Quiet"
args1(18).Value = true

dispatcher.executeDispatch(document, ".uno:ExecuteSearch", "", 0, args1())

rem ----------------------------------------------------------------------
dim args2(1) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Count"
args2(0).Value = 1
args2(1).Name = "Select"
args2(1).Value = false

dispatcher.executeDispatch(document, ".uno:GoRight", "", 0, args2())

rem ----------------------------------------------------------------------
dim args3(1) as new com.sun.star.beans.PropertyValue
args3(0).Name = "Count"
args3(0).Value = 1
args3(1).Name = "Select"
args3(1).Value = false

dispatcher.executeDispatch(document, ".uno:GoLeft", "", 0, args3())

rem ----------------------------------------------------------------------
dispatcher.executeDispatch(document, ".uno:EndOfDocumentSel", "", 0, Array())

rem ----------------------------------------------------------------------
dim args5(0) as new com.sun.star.beans.PropertyValue
args5(0).Name = "Color"
args5(0).Value = 128

dispatcher.executeDispatch(document, ".uno:Color", "", 0, args5())

rem ----------------------------------------------------------------------
dim args6(1) as new com.sun.star.beans.PropertyValue
args6(0).Name = "Count"
args6(0).Value = 1
args6(1).Name = "Select"
args6(1).Value = false

dispatcher.executeDispatch(document, ".uno:GoDown", "", 0, args6())

rem ----------------------------------------------------------------------
dim args7(1) as new com.sun.star.beans.PropertyValue
args7(0).Name = "Template"
args7(0).Value = "dummy"
args7(1).Name = "Family"
args7(1).Value = 8

dispatcher.executeDispatch(document, ".uno:StyleApply", "", 0, args7())

dispatcher.executeDispatch(document, ".uno:GoToStartOfDoc", "", 0, Array())

end sub


Wer lesen kann ist klar im Vorteil.
Toxitom
********
Beiträge: 3768
Registriert: Di, 12.08.2003 18:07
Wohnort: Wiesbaden
Kontaktdaten:

Beitrag von Toxitom »

Hallo Niels,

wieviel erfahrung hast du schon mit Makro-Programmierung? Das Dispatchermodell (und nur das nutzt der Makrorecorder) ist nicht einfach zu verstehen und nicht für alle Aufgaben ideal geeignet.

Also erste Frage: Was willst du erreichen?

Vorab folgende Hinweise:
Textrahmen sind Objekte auf dokument.drawpage, der "normale" Text ist ein Objekt des dokumentes. Du musst also wahrscheinlich durch die verschiedenen möglichen Objekte iterieren und vor allem die unterschiedlichen Objektmöglichkeiten (Text, Tabellen, Rahmen, Grafiken...) abfragen.

Gruss
Thomas
Unterstützer LibreOffice, zertifizierter Trainer und Berater
Bücher: LibreOffice 6- Einstieg und Umstieg
Makros Grundlagen - LibreOffice / OpenOffice Basic
Stephan
********
Beiträge: 12369
Registriert: Mi, 30.06.2004 19:36
Wohnort: nahe Berlin

Beitrag von Stephan »

Hallo Niels,

die Antwort gibst Du Dir selbst mit Deiner letzten Zeile:

Code: Alles auswählen

dispatcher.executeDispatch(document, ".uno:GoToStartOfDoc", "", 0, Array())
das zusätzliche Problem ist aber wahrscheinlich: Dein Dokument hat mehrere Rahmen und alle Rahmen und der "normale" Text sollen durchsucht werden, egal wo anfangs der Cursor steht.
Ich habe mir jetzt nicht genau angesehen was Dein Code macht, aber im Prinzip geht es so:

Code: Alles auswählen

Public oFrame
Public Cursor 

Sub dein_code_rahmen
'hier Deinen Code für Rahmen einfügen
'nur ein Test
FrameCursor = oFrame.createTextCursor()
FrameCursor.String = "Test1"
End Sub

Sub dein_code_normal
'hier Deinen Code normalen Text einfügen
'nur ein Test
Cursor.String = "Test2"
End Sub

Sub start
Cursor = ThisComponent.Text.createTextCursor()
Cursor.gotoStart (false)
dein_code_normal()
oFrames = ThisComponent.getTextFrames() 
for i = 0 to oFrames.Count -1 
  oFrame = oFrames(i) 
  dein_code_rahmen()
next i
End Sub
Starten mußt Du Makro 'start' (*) dieses setzt den Cursor an den Dokumentanfang und arbeitet dann Deinen Code für den "normalen" Textbereich ab, anschließend werden alle Textfelder durchlaufen und der entsprechende Code abgearbeitet.
(*)der (sichtbare) Cursor kann zu diesem Zeitpunkt im Text oder in einem Rahmen stehen, die Position dieses Cursors bleibt unverändert erhalten

Sollen nur bestimmte Textfelder berücksichtigt werden, dann vergib Namen und prüfe auf diese Eigenschaft:

Code: Alles auswählen

...
oFrame = oFrames(i) 
if oFrame.Name = "DeineVorgabe" Then
      'hier Dein Code oder ebend:
      dein_code_rahmen() 
   Else
      'nichts tun oder Meldung
End If
...

Gruß
Stephan
Niels
*****
Beiträge: 212
Registriert: Mi, 16.06.2004 06:46
Wohnort: Heikendorf

Beitrag von Niels »

Toxitom hat geschrieben:Hallo Niels,

wieviel erfahrung hast du schon mit Makro-Programmierung? Das Dispatchermodell (und nur das nutzt der Makrorecorder) ist nicht einfach zu verstehen und nicht für alle Aufgaben ideal geeignet.
Hallo Thomas,

ich mache etwas mit VB6 rum und mit VBA. Und nun halt mit OOBasic. Genau das Dispatchermodul ist mein Problem, da ich mit den Vererbungstaktiken eh auf Kriegsfuss stehe. Das kommt sicher daher, dass ich meine ersten Basic-Schritte auf Atari X (da gab es nicht einmal Funktionen und Gültigkeitsbereiche für Variablen, sondern nur GOTO oder besser GOSUB) gemacht habe und bis vor 2-3 Jahren immer noch erfolgreich meine kleinen Problemchen mit QBasic abgearbeitet habe. Ich schreibe halt nur Makros oder Anwendungen, wenn ich auf normalen Weg nicht weiterkomme oder mir der Weg über Code einfacher vorkommt.
Hier ist Mikiesoft Office natürlich schicker, weil der Makrorecorder einen einfacheren Grundstock liefert, auf dem man aufsetzen kann.
Aber bislang lief das Makro in meinen Formularen recht gut (es durfte nur keine Grafik makiert sein). Ich werde gleich mal Stephan's Tipps anpacken und kann das sogar viel einfacher gestalten:
Das Makro sucht nur den Suchtext (der steht in weiß vor dem zu manipulierenden Text) und formatiert die Farbe um. Sinn der Übung ist das schon mehrfach besprochene Thema verschiedener Kopfbogenlayouts.
1. Kopfbogen farbig für PDF-Erstellung
2. Kopfbogen ausgeblendet für Druck auf Kopfbogen
3. Kopfbogen s/w für Fax
Teilweise kann ich das über das Zuweisen einer anderen Seitenvorlage lösen, jedoch haben die Kopfbögen auch Rahmen mit Inhalten (rechts neben Anschriftenfeld und bei einem anderen sogar auf dem Rand rechts unten). Das heißt also in Stephans Beispiel brauche ich gar nicht alle Rahmen zu durchsuchen, sondern kann gezielt auf die Rahmen positionieren. EIgentlchi brauche ich dann gar nicht mehr zu suchen, denn wenn ich nun auf Position 1 des Rahmens mit dem Cursor stehe, dann brauche ich ja nur noch zu markieren und umzuformatieren.

Danke erstmal
Niels
Wer lesen kann ist klar im Vorteil.
Niels
*****
Beiträge: 212
Registriert: Mi, 16.06.2004 06:46
Wohnort: Heikendorf

Beitrag von Niels »

Hallo Stephan,

erst einmal vielen Dank für Deine Antwort.
Stephan hat geschrieben:Hallo Niels,

die Antwort gibst Du Dir selbst mit Deiner letzten Zeile:

Code: Alles auswählen

dispatcher.executeDispatch(document, ".uno:GoToStartOfDoc", "", 0, Array())
Mein Leitspruch. "Wer lesen kann..." :lol:

Ich konnte das nun, wie bereits gepostet vereinfachen:

Code: Alles auswählen

Public formFrame 
Public formCursor

Sub Faxlayout
	formCursor = ThisComponent.Text.createTextCursor() 
	formCursor.gotoStart (false) 
	formFrames = ThisComponent.getTextFrames() 
	for i = 0 to formFrames.Count -1 
		formFrame = formFrames(i) 
		if formFrame.Name = "Absender" then SW()
	next i 
End Sub

sub SW()
	rem ----------------------------------------------------------------------
	rem define variables
	dim document   as object
	dim dispatcher as object
	rem ----------------------------------------------------------------------
	rem get access to the document
	document   = ThisComponent.CurrentController.Frame
	dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

	rem ----------------------------------------------------------------------
	dispatcher.executeDispatch(document, ".uno:SelectAll", "", 0, Array())

	rem ----------------------------------------------------------------------
	dim argsFarbe(0) as new com.sun.star.beans.PropertyValue
	argsFarbe(0).Name = "Color"
	argsFarbe(0).Value = 0

	dim argsVorlage(1) as new com.sun.star.beans.PropertyValue
	argsVorlage(0).Name = "Template"
	argsVorlage(0).Value = "PT-Fax"
	argsVorlage(1).Name = "Family"
	argsVorlage(1).Value = 8

	dispatcher.executeDispatch(document, ".uno:Color", "", 0, argsFarbe())

	dispatcher.executeDispatch(document, ".uno:GoToStartOfDoc", "", 0, Array())

	dispatcher.executeDispatch(document, ".uno:StyleApply", "", 0, argsVorlage())

end sub
Irgend etwas mache ich jedoch noch falsch. Er formatiert immer meinen Rahmen um, in dem ich mich gerade befinde. Das kann ich ja auch verstehen, da mein dispatcher ja auf formFrame zugreifen muss, und nicht auf CurrentController.Frame, nur wie muss ich das formulieren? Ich habe Null Ahnung :!:
Zudem muss ich ja vermutlich nicht alle Rahmennummern nach dem passenden Namen durchsuchen, sondern kann den Rahmen sicher auch direkt über seinen Namen ansprechen, oder?

Danke
Niels
Wer lesen kann ist klar im Vorteil.
Stephan
********
Beiträge: 12369
Registriert: Mi, 30.06.2004 19:36
Wohnort: nahe Berlin

Beitrag von Stephan »

Hallo Niels,
Irgend etwas mache ich jedoch noch falsch. Er formatiert immer meinen Rahmen um, in dem ich mich gerade befinde. Das kann ich ja auch verstehen, da mein dispatcher ja auf formFrame zugreifen muss, und nicht auf CurrentController.Frame, nur wie muss ich das formulieren?


Du erkennst das schon in etwa, das grundlegende Prinzip ist eigentlich:
Es gibt immer einen sichtbaren Cursor und es kann zusätzlich einen (oder mehrere) "virtuellen" Cursor geben. Du kannst beide benutzen um notwendige Aufgaben zu erledigen, es ist nur die Frage was optisch sichtbar sein soll. Da die Art Makros über die wir hier sprechen so schnell ablaufen das der Benutzer das nicht (am Bildschirm) verfolgen kann reicht der virtuelle Cursor aus, die Position des sichtbaren Cursors bleibt hierbei völlig unverändert, weshalb ich schrieb:
(*)der (sichtbare) Cursor kann zu diesem Zeitpunkt im Text oder in einem Rahmen stehen, die Position dieses Cursors bleibt unverändert erhalten
Du kannst das alles gleichwertig auch mit dem sichtbaren Cursor durchführen, dann steht dieser nach Beendigung des Makros an der Stelle "wo das Makro endet", das kann erwünscht sein. Oder Du kannst die Anfangsposition des sichtbaren Cursors speichern, dann mit dem sichtbaren Cursor arbeiten und ihn anschließend wieder in Anfangsposition bringen - nur ist es dann logischer gleich einen virtuellen Cursor zu verwenden. Also: es kommt eigentlich nur darauf an wo Dein Cursor nach Abarbeitung des Makros sichtbar sein soll.
Wenn das jetzt zu verwirrend war siehe das Dokument "StarBasicFAQ", der link ist hier
viewtopic.php?t=1553 aufgeführt, dort gibt es eine Beschreibung zum Einfügen von Text an Textmarken einmal mit virtuellem und einmal mit sichtbarem Cursor, diese sollte verständlich sein.

Ansonsten ist hier ein Code für Dich:

Code: Alles auswählen

Public formFrame 
Public formCursor 

Sub Faxlayout 
   formCursor = ThisComponent.Text.createTextCursor() 
   formCursor.gotoStart (false) 
   formFrames = ThisComponent.getTextFrames()
  
   for i = 0 to formFrames.Count -1 
      formFrame = formFrames(i) 
      if formFrame.Name = "Absender" then SW() 
   next i
   'der Cursor steht schon vorne, sonst: 
   'formCursor.gotoStart (false)
   formCursor.gotoEnd (true)
   formCursor.ParaStyleName = "PT-Fax"
End Sub 

sub SW()
FrameCursor = formFrame.createTextCursor()
FrameCursor.gotoStart (false)
FrameCursor.gotoEnd (true)
FrameCursor.CharColor = RGB(0,0,255) 'blau
end sub
Was passiert?

Code: Alles auswählen

formCursor = ThisComponent.Text.createTextCursor() 
formCursor.gotoStart (false)
-->es wird ein 'virtueller' (Text)cursor erzeugt und dieser an den Anfang des Textbereiches des aktuellen Dokuments gesetzt, falls hierbei Text quasi "überstrichen" werden sollte wird dieser nicht markiert wegen (false)

Code: Alles auswählen

formFrames = ThisComponent.getTextFrames()
   for i = 0 to formFrames.Count -1 
      formFrame = formFrames(i) 
      if formFrame.Name = "Absender" then SW() 
   next i 
-->der richtige Rahmen wird gesucht (*), wenn er gefunden ist ist er der aktulle inhalt der Objektvariable formFrame (Du kannst Dir vorstellen der Rahmen wäre virtuell markiert) und das ist der Grund das Dein Code nicht arbeitet:
Dein Code nutzt den sichtbaren Cursor, der Zugriff auf den Rahmen ist jedoch mit dem virtuellen Cursor erfolgt UND bisher ist nur der Rahmen gewählt der virtuelle Cursor steht noch nicht im Textbereich des Rahmens, das erledigt:

(*)
da Du VBA programmierst: das ThisComponent.getTextFrames() ist in diesem Sinne eine Objektauflistung wo Du in VBA sinngemäß schreiben könntest:
For each Frame in ThisComponent.getTextFrames()
'...
Next Frame


Code: Alles auswählen

FrameCursor = formFrame.createTextCursor()
-->Zugriff auf den Text im Rahmen ist möglich, FrameCursor ist genau so ein virtueller Cursor wie FormCursor beide existieren im Moment, nach Abarbeitung von sub SW() hört jedoch FrameCursor auf zu existieren da er nicht modulweit deklariert ist wie FormCursor (--> Public formCursor)

Code: Alles auswählen

FrameCursor.gotoStart (false)
FrameCursor.gotoEnd (true)
FrameCursor.CharColor = RGB(0,0,255) 'blau
-->an den Anfang des Textbereich des Rahmens springen (ich bin nicht sicher ob das zwingend erforderlich ist, aber sicher ist sicher), dann zum Ende des Textbereichs gehen und hierbei den Überstrichenen Text markieren (true), somit enthält FrameCursor.String den gesamten Text des Rahmens und diesem kann nun die Schriftfarbe zugewiesen werden

Code: Alles auswählen

formCursor.gotoEnd (true)
formCursor.ParaStyleName = "PT-Fax"
-->das Gleiche wie im Rahmen nur wird keine Schriftfarbe sondern eine Absatzvorlage zugewiesen (eleganter wäre es durch alle Absätze zu interieren)

sondern kann den Rahmen sicher auch direkt über seinen Namen ansprechen, oder?


Ich denke ja, bin aber zu blöd dafür, es ist möglicherweise nur eine Kleinigkeit aber ich weiß nicht wie. Meine Vermutung war:
formFrame = formFrames().GetByName("Absender")
das funktioniert jedoch nicht, liefert aber auch keine Fehlermeldung.



Gruß
Stephan
Stephan
********
Beiträge: 12369
Registriert: Mi, 30.06.2004 19:36
Wohnort: nahe Berlin

Beitrag von Stephan »

Anregung

Hallo Niels,

Ich habe nochmal den Thread gelesen ...
Aber bislang lief das Makro in meinen Formularen recht gut (es durfte nur keine Grafik makiert sein). Ich werde gleich mal Stephan's Tipps anpacken und kann das sogar viel einfacher gestalten:
Das Makro sucht nur den Suchtext (der steht in weiß vor dem zu manipulierenden Text) und formatiert die Farbe um. Sinn der Übung ist das schon mehrfach besprochene Thema verschiedener Kopfbogenlayouts.
1. Kopfbogen farbig für PDF-Erstellung
2. Kopfbogen ausgeblendet für Druck auf Kopfbogen
3. Kopfbogen s/w für Fax
Teilweise kann ich das über das Zuweisen einer anderen Seitenvorlage lösen, jedoch haben die Kopfbögen auch Rahmen mit Inhalten (rechts neben Anschriftenfeld und bei einem anderen sogar auf dem Rand rechts unten).
Was wir bisher bezüglich des Makros besprochen haben ist ja OK, aber immer wenn Du im Dokument Änderungen im Sinne von Objekten vornimmt kann es immer sein das Du das Makro anpassen mußt...
Wenn das Ganze Priorität für Dich hat mach doch einmal "Nägel mit Köpfen" und es gibt nie wieder Probleme mit Anpassungen.

Hierzu:
erstelle Dein Dokument und formatiere alles, aber wirklich alles, mit selbsterstellten Formatvorlagen mit eigenen spezifischen Namen. Speichere das Dokument als z.b pdf.sxw. Ändere nun die entsprechenden Formatvorlagen so wie benötigt und speichere als z.B. druck.sxw. Ändere nochmals und speichere als fax.sxw.
Du kannst nätürlich vor dem Speichern die konkreten Inhalte löschen da nur die Formatvorlagen wichtig sind. Nun hast Du 3 Dokumente mit Formatvorlagen mit spezifischen Namen die jedoch exakt gleich in allen 3 Dokumenten sein müssen.
Nimm jetzt eines der Dokumente und speichere es als Vorlage. In Zukunft rufe diese Vorlage auf und erstelle Deinen Inhalt. Um nun das Layout zu ändern brauchst Du für alle Zeiten nur noch dieses Makro:

Code: Alles auswählen

sub vorlage_laden
rem ----------------------------------------------------------------------
rem define variables
dim document   as object
dim dispatcher as object
rem ----------------------------------------------------------------------
rem get access to the document
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

rem ----------------------------------------------------------------------
dim args1(1) as new com.sun.star.beans.PropertyValue
args1(0).Name = "FileName"
args1(0).Value = "file:///C:/Dokumente%20und%20Einstellungen/internet/Desktop/niels2.sxw"
args1(1).Name = "Flags"
args1(1).Value = 31

dispatcher.executeDispatch(document, ".uno:LoadStyles", "", 0, args1())

end sub
Dieses Makro speicherst Du in 3 Versionen in der StandardBibliothek von OOo und änderst in diesen nur den Ausdruck:
args1(0).Value = "file:///C:/Dokumente%20und%20Einstellungen/internet/Desktop/niels2.sxw"
jeweils auf eine der 3 erstellten Dateien ab. Weise diese 3 Makros 3 Schaltflächen zu und Du kannst in Zukunft Dein Dokument umformatieren egal wo welcher Cursor steht oder was gerade markiert ist usw. - ein Mausklick genügt.
Die einzige Voraussetzung sind selbstdefinierte Formatvorlagen, zumindest für die "relevanten" Teile soweit Du die Konsistenz der anderen Formatvorlagen sichern kannst in dem Du zukünftig die Standard-Vorlage nicht änderst, aber nimm doch für alles benutzerdefinierte Vorlagen und es gibt in Zukunft nie wieder Schwierigkeiten.


Gruß
Stephan
Antworten