Erstmal ein Code der das Problem zeigt:
Code: Alles auswählen
Procedure MakeScintillaText(text.s)
Static sciText.s
CompilerIf #PB_Compiler_Unicode
sciText = Space(StringByteLength(text, #PB_UTF8))
PokeS(@sciText, text, -1, #PB_UTF8)
CompilerElse
sciText = text
CompilerEndIf
ProcedureReturn @sciText
EndProcedure
If OpenWindow(0, 0, 0, 320, 390, "ScintillaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If InitScintilla()
ScintillaGadget(0, 10, 10, 300, 370, 0)
SetActiveGadget(0)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
If OSVersion() >= #PB_OS_Windows_Vista
ScintillaSendMessage(0, #SCI_SETTECHNOLOGY, #SC_TECHNOLOGY_DIRECTWRITE)
EndIf
CompilerEndIf
ScintillaSendMessage(0, #SCI_SETWRAPMODE, #SC_WRAP_WORD)
For i = 0 To 31
Text$ + " line"
append$ = "Line "+Str(i)+": "+Text$+Chr(10)
ScintillaSendMessage(0, #SCI_APPENDTEXT, Len(append$), MakeScintillaText(append$))
Next
TxtLaenge = ScintillaSendMessage(0, #SCI_GETLENGTH , 0, 0)
ScintillaSendMessage(0, #SCI_GOTOPOS, TxtLaenge)
ScintillaSendMessage(0, #SCI_SCROLLTOEND)
EndIf
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
stevie1401 hat geschrieben:Wenn der hinzugefügte Text gebrochen wird, also länger als das Scintillagadget breit ist, dann scrollt es nur bis zu vor oder vorvorletzten Zeile.
Hat jemand eine Idee, wie man das beheben kann?
Das ist leider etwas komplizierter, siehe
Scintilla Documentation - Line Wrapping:
Wrapping is not performed immediately there is a change but is delayed until the display is redrawn. This delay improves performance by allowing a set of changes to be performed and then wrapped and displayed once. Because of this, some operations may not occur as expected. If a file is read and the scroll position moved to a particular line in the text, such as occurs when a container tries to restore a previous editing session, then the scroll position will have been determined before wrapping so an unexpected range of text will be displayed. To scroll to the position correctly, delay the scroll until the wrapping has been performed by waiting for an initial SCN_PAINTED notification.
Das scrollen musst Du also verzögern, bis das Gadget neu gezeichnet wurde. Erst beim zeichnen
werden die Positionen, die durch das Wordwrap anders sind, richtig berechnet.
Für die Umsetzung gibt es sicherlich verschiedene Ansätze. Ich würde sowas wie eine LinkedList machen,
der Du Befehle hinzufügst, die dann bei der Nachricht #SCN_PAINTED im Scintilla-Callback abgearbeitet werden.
Ein simples Beispiel dazu:
Code: Alles auswählen
Global NewList ScintillaPaintedCommands()
Enumeration ScintillaPaintedCommands
#SCROLL_TO_END
#SET_CURSOR_TO_END
EndEnumeration
Procedure MakeScintillaText(text.s)
Static sciText.s
CompilerIf #PB_Compiler_Unicode
sciText = Space(StringByteLength(text, #PB_UTF8))
PokeS(@sciText, text, -1, #PB_UTF8)
CompilerElse
sciText = text
CompilerEndIf
ProcedureReturn @sciText
EndProcedure
Procedure ScintillaCallBack(Gadget, *scinotify.SCNotification)
If *scinotify\nmhdr\code = #SCN_PAINTED;#SCN_UPDATEUI
ForEach ScintillaPaintedCommands()
Select ScintillaPaintedCommands()
Case #SCROLL_TO_END
ScintillaSendMessage(Gadget, #SCI_SCROLLTOEND)
Case #SET_CURSOR_TO_END
ScintillaSendMessage(Gadget, #SCI_GOTOPOS,
ScintillaSendMessage(Gadget, #SCI_GETLENGTH , 0, 0))
;ScintillaSendMessage(Gadget, #SCI_SCROLLCARET)
EndSelect
Next
ClearList( ScintillaPaintedCommands() )
EndIf
EndProcedure
If OpenWindow(0, 0, 0, 320, 390, "ScintillaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If InitScintilla()
ScintillaGadget(0, 10, 10, 300, 370, @ScintillaCallBack())
SetActiveGadget(0)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
If OSVersion() >= #PB_OS_Windows_Vista
ScintillaSendMessage(0, #SCI_SETTECHNOLOGY, #SC_TECHNOLOGY_DIRECTWRITE)
EndIf
CompilerEndIf
ScintillaSendMessage(0, #SCI_SETWRAPMODE, #SC_WRAP_WORD)
For i = 0 To 31
Text$ + " line"
append$ = "Line "+Str(i)+": "+Text$+Chr(10)
ScintillaSendMessage(0, #SCI_APPENDTEXT, Len(append$), MakeScintillaText(append$))
If AddElement( ScintillaPaintedCommands() )
ScintillaPaintedCommands() = #SET_CURSOR_TO_END
EndIf
ScintillaSendMessage(0, #SCI_SCROLLTOEND)
; Zeile zur Verzögerung, um es besser zu sehen
;While WindowEvent():Wend : Delay(400)
Next
EndIf
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf