Jump to content

goto specific line in rich edit control


Go to solution Solved by argumentum,

Recommended Posts

Posted (edited)

I'm looking for a way to programatically scroll a rich edit control to a specific line (range = first line to last line).
The edit has no scrollbar and that should stay that way, the cursor and selection sould also keep unmodified, is that even possible?

I know about _GUICtrlRichEdit_GetScrollPos but it works with pixels and has no clear way of finding the min and max range..

The goal here is to create a custom scrollbar, made from a label.
Ideally it would also move the scrollbar thumb if I scroll the edit or change the cursor position of the edit.

I have some code, but it's unfinished, it's quite a workaround but the best I can do at the moment (sorry if it looks a little dirty)...
any help or better ideas would be appriciated!

Contributors to this code also get credits on the code of this program in the example script section:

See part of code under here, and for the graphics I'll upload a zip file :)

; colors

const $color_text_white = 0x00ffffff
const $color_text_gray = 0x00C0C0C0
const $color_element_gray = 0x606060
const $color_control_gray = 0x404040
const $color_border_gray = 0x202020
const $color_text_red = 0x006600ff
const $color_text_green = 0x0000ff66
const $color_text_blue = 0x00ff6600
const $color_transparent_background = 0xff00ff

; font names

const $font_handel_gothic_bt = 'handelgothic bt'
const $font_lucida_console = 'lucida console'

; sound effects

const $sound_start = @scriptdir & '\sounds\start.wav'
const $sound_click = @scriptdir & '\sounds\click.wav'
const $sound_alert = @scriptdir & '\sounds\alert.wav'
const $sound_stop = @scriptdir & '\sounds\stop.wav'

; user interface images

const $image_alert = @scriptdir & '\images\alert.bmp'
const $image_blue = @scriptdir & '\images\blue.bmp'
const $image_bold = @scriptdir & '\images\bold.bmp'
const $image_case_off = @scriptdir & '\images\case_off.bmp'
const $image_case_on = @scriptdir & '\images\case_on.bmp'
const $image_close = @scriptdir & '\images\close.bmp'
const $image_exit = @scriptdir & '\images\exit.bmp'
const $image_find = @scriptdir & '\images\find.bmp'
const $image_gray = @scriptdir & '\images\gray.bmp'
const $image_green = @scriptdir & '\images\green.bmp'
const $image_info = @scriptdir & '\images\info.bmp'
const $image_install = @scriptdir & '\images\install.bmp'
const $image_italic = @scriptdir & '\images\italic.bmp'
const $image_link = @scriptdir & '\images\link.bmp'
const $image_minimark = @scriptdir & '\images\minimark.bmp'
const $image_no = @scriptdir & '\images\no.bmp'
const $image_ok = @scriptdir & '\images\ok.bmp'
const $image_open = @scriptdir & '\images\open.bmp'
const $image_options = @scriptdir & '\images\options.bmp'
const $image_red = @scriptdir & '\images\red.bmp'
const $image_remove = @scriptdir & '\images\remove.bmp'
const $image_replace = @scriptdir & '\images\replace.bmp'
const $image_replace_all = @scriptdir & '\images\replace_all.bmp'
const $image_reset = @scriptdir & '\images\reset.bmp'
const $image_save = @scriptdir & '\images\save.bmp'
const $image_scroll = @scriptdir & '\images\scroll.bmp'
const $image_scroll_down = @scriptdir & '\images\scroll_down.bmp'
const $image_scroll_up = @scriptdir & '\images\scroll_up.bmp'
const $image_search = @scriptdir & '\images\search.bmp'
const $image_searcher = @scriptdir & '\images\searcher.bmp'
const $image_settings = @scriptdir & '\images\settings.bmp'
const $image_setup = @scriptdir & '\images\setup.bmp'
const $image_size = @scriptdir & '\images\size.bmp'
const $image_size_down = @scriptdir & '\images\size_down.bmp'
const $image_size_up = @scriptdir & '\images\size_up.bmp'
const $image_sound_off = @scriptdir & '\images\sound_off.bmp'
const $image_sound_on = @scriptdir & '\images\sound_on.bmp'
const $image_strike = @scriptdir & '\images\strike.bmp'
const $image_underline = @scriptdir & '\images\underline.bmp'
const $image_white = @scriptdir & '\images\white.bmp'
const $image_word_off = @scriptdir & '\images\word_off.bmp'
const $image_word_on = @scriptdir & '\images\word_on.bmp'
const $image_yes = @scriptdir & '\images\yes.bmp'

; intro file

const $file_manual = @scriptdir & '\data\MiniMark.mnm'

#notrayicon

#include <guirichedit.au3>
#include <guiconstants.au3>
#include <winapisyswin.au3>



local $x
for $i = 1 to 300
    $x &= $i & @CRLF
Next


$minimark_form = guicreate('MiniMark', 380, 380, default, default, $ws_popup, $ws_ex_layered)
    guisetbkcolor($color_transparent_background)

$minimark_background = guictrlcreatepic($image_minimark, 0, 0, 380, 380)
    guictrlsetstate(default, $gui_disable)

$minimark_title = guictrlcreatelabel('the title.....', 5, 5, 370, 20, bitor($ss_centerimage, $ss_center), $gui_ws_ex_parentdrag) ; use label to drag form
    guictrlsettip(default, 'full path') ; display full path on mouse over
    guictrlsetfont(default, 12, 400, 0, $font_handel_gothic_bt)
    guictrlsetcolor(default, $color_text_gray)
    guictrlsetbkcolor(default, $gui_bkcolor_transparent)

$minimark_edit = _guictrlrichedit_create($minimark_form, $x, 10, 35, 270, 335, bitor($es_multiline, $es_autovscroll, $es_nohidesel), 0) ; $es_nohidesel for visible selection when using search function
    _guictrlrichedit_setbkcolor($minimark_edit, $color_control_gray)
;~  load_file()

    guiregistermsg($wm_command, wm_command)
    func wm_command($hwnd, $imsg, $wparam, $lparam) ; we need this becouse rich edit keeps changing to default style
        if $minimark_edit <> $lparam then return $gui_rundefmsg
        if _guictrlrichedit_istextselected($minimark_edit) then return $gui_rundefmsg
        if _guictrlrichedit_getfont($minimark_edit)[1] <> $font_lucida_console then
            _guictrlrichedit_setfont($minimark_edit, 9, $font_lucida_console)
            _guictrlrichedit_setcharcolor($minimark_edit, $color_text_gray)
        endif
        return $gui_rundefmsg
    endfunc

$button_options = guictrlcreatepic($image_options, 305, 30, 70, 20)
    guictrlsettip(default, 'Open settings.', 'ctrl + o')
$button_open = guictrlcreatepic($image_open, 305, 55, 70, 20)
    guictrlsettip(default, 'Open a new *.mnm file.', 'ctrl + o')
$button_bold = guictrlcreatepic($image_bold, 305, 80, 70, 20)
    guictrlsettip(default, 'Make selection bold.', 'ctrl + b')
$button_italic = guictrlcreatepic($image_italic, 305, 105, 70, 20)
    guictrlsettip(default, 'Make selection italic.', 'ctrl + i')
$button_strike = guictrlcreatepic($image_strike, 305, 130, 70, 20)
    guictrlsettip(default, 'Make selection struck.', 'ctrl + t')
$button_underline = guictrlcreatepic($image_underline, 305, 155, 70, 20)
    guictrlsettip(default, 'Make selection underlined.', 'ctrl + u')
$button_red = guictrlcreatepic($image_red, 305, 180, 70, 20)
    guictrlsettip(default, 'Make selection red.', 'shift + ctrl + r')
$button_green = guictrlcreatepic($image_green, 305, 205, 70, 20)
    guictrlsettip(default, 'Make selection green.', 'shift + ctrl + g')
$button_blue = guictrlcreatepic($image_blue, 305, 230, 70, 20)
    guictrlsettip(default, 'Make selection blue.', 'shift + ctrl + b')
$button_white = guictrlcreatepic($image_white, 305, 255, 70, 20)
    guictrlsettip(default, 'Make selection white.', 'shift + ctrl + w')
$button_gray = guictrlcreatepic($image_gray, 305, 280, 70, 20)
    guictrlsettip(default, 'Make selection default style and gray.', 'shift + ctrl + d')
$button_search = guictrlcreatepic($image_search, 305, 305, 70, 20)
    guictrlsettip(default, 'Find and replace text.', 'ctrl + f')
$button_save = guictrlcreatepic($image_save, 305, 330, 70, 20)
    guictrlsettip(default, 'Save file / save file as.', 'ctrl + s / shift + ctrl + s')
$button_exit = guictrlcreatepic($image_exit, 305, 355, 70, 20)
    guictrlsettip(default, 'Quit the program.', 'escape')

$minimark_scroll_up = GUICtrlCreatePic($image_scroll_up, 290, 30, 10, 10)
$minimark_scroll_thumb = GUICtrlCreatePic($image_scroll, 290, 45, 10, 20) ; scroll background: 290, 45, 10, 315
$minimark_scroll_down = GUICtrlCreatePic($image_scroll_down, 290, 365, 10, 10)

    _guictrlrichedit_seteventmask($minimark_edit, $enm_scrollevents)
    guiregistermsg($wm_notify, wm_notify)
    func wm_notify($hwnd, $imsg, $wparam, $lparam)
        local $tfilter = dllstructcreate($tagmsgfilter, $lparam)
        if $tfilter.hwndfrom = $minimark_edit then _guictrlrichedit_scrolllines($tfilter.hwndfrom, $tfilter.wparam ? 1 : -1)
        return $gui_rundefmsg
    endfunc

_winapi_setlayeredwindowattributes($minimark_form, $color_transparent_background) ;set the transparant gui color

guisetstate(@SW_SHOW, $minimark_form)

#Region scrollbar

    $scroll_drag = False ; are we dragging the scroll button?
    local $scroll_selection, $scroll_new_pos ; remember cursor and selection

    Func check_scroll_clicked()
        Local $scroll_cursor = GUIGetCursorInfo($minimark_form)
        If _
            $scroll_cursor[0] >= 290 And _
            $scroll_cursor[0] <= 300 And _
            $scroll_cursor[1] >= 45 And _
            $scroll_cursor[1] <= 360 _
        Then
            $scroll_drag = True
            $scroll_selection = _GUICtrlRichEdit_GetSel($minimark_edit)
        EndIf
    EndFunc

    Func scroll()
        Local $scroll_x = 290 ; x of $scroll control at all times
        Local $scroll_min_y = 55, $scroll_max_y = 350 ; range of y movement for $scroll (top of frame till bottom - height)

        Local $scroll_cursor = GUIGetCursorInfo($minimark_form)[1] ; get y position of cursor
        if $scroll_cursor < $scroll_min_y then $scroll_cursor = $scroll_min_y
        if $scroll_cursor > $scroll_max_y then $scroll_cursor = $scroll_max_y
        GUICtrlSetPos($minimark_scroll_thumb, $scroll_x, $scroll_cursor-10) ; drag scroll button within range of background bar

        $scroll_ratio = ($scroll_cursor - $scroll_min_y) / ($scroll_max_y - $scroll_min_y) ; calculate scroll position percentage between 0 and 1
        $scroll_last = _GUICtrlRichEdit_GetLineCount($minimark_Edit)

        local $scroll_calculate = $scroll_ratio * $scroll_last ; calculate where to walk to
        local $scroll_line = _GUICtrlRichEdit_GetFirstCharPosOnLine($minimark_Edit, $scroll_calculate)

        _GUICtrlRichEdit_SetSel($minimark_edit, $scroll_line, $scroll_line)

        consolewrite(_GUICtrlRichEdit_GetLineCount($minimark_Edit) & '---' & $scroll_calculate & '---' & $scroll_ratio & @CRLF)
    EndFunc

#endregion

While 1
    switch guigetmsg()

        case $gui_event_close
            soundplay($sound_stop, 1)
            _guictrlrichedit_destroy($minimark_edit)
            guidelete()
            exit

        case $GUI_EVENT_PRIMARYDOWN
            check_scroll_clicked()

        Case $GUI_EVENT_MOUSEMOVE
            If $scroll_drag Then scroll()

        Case $GUI_EVENT_PRIMARYUP
            if $scroll_drag Then
                $scroll_new_pos = _GUICtrlRichEdit_GetScrollPos($minimark_edit)
                _GUICtrlRichEdit_SetSel($minimark_edit, $scroll_selection[0], $scroll_selection[1])
                _GUICtrlRichEdit_SetScrollPos($minimark_edit, $scroll_new_pos[0], $scroll_new_pos[1])
                $scroll_drag = False
            EndIf

        case $minimark_scroll_up
            _guictrlrichedit_scrolllines($minimark_edit, -1)
        case $minimark_scroll_down
            _guictrlrichedit_scrolllines($minimark_edit, 1)

    EndSwitch
WEnd

 

scroller.zip

Edited by TheAutomator
Posted (edited)

https://www.autoitscript.com/autoit3/docs/libfunctions/_GUICtrlRichEdit_FindText.htm

https://www.autoitscript.com/autoit3/docs/libfunctions/_GUICtrlRichEdit_GotoCharPos.htm

Goto 0 and in a loop find carriage return

Probably with those messages you will be able to do this

  • EM_POSFROMCHAR
  • EM_CHARFROMPOS
  • EM_LINEFROMCHAR
  • EM_LINEINDEX
  • EM_LINESCROLL

And the editcontrol functions should work also otherwise you need sendmessage function with windows messages
https://learn.microsoft.com/en-us/windows/win32/controls/about-rich-edit-controls
 

https://www.autoitscript.com/autoit3/docs/libfunctions/_GUICtrlEdit_LineScroll.htm
 

Edited by junkew
Posted (edited)

This seems to work for both controls but you have to set the rich text box first to point 0,0
The reverse order is not working

 

#include <EditConstants.au3>
#include <GuiEdit.au3>
#include <GuiRichEdit.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

Example()

Func Example()
        Local $hGui=GUICreate("My GUI edit and rich edit") ; will create a dialog box that when displayed is centered
        local $someTextLines=stringreplace("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","x", "line" & @crlf)
        Local $idMyedit = GUICtrlCreateEdit($someTextLines & @CRLF, 10, 10, 350, 180, $ES_MULTILINE+$ES_AUTOVSCROLL + $WS_VSCROLL)
        Local $hRichEdit = _GUICtrlRichEdit_Create($hGui, $someTextLines, 10, 210, 350, 180, bitor($ES_MULTILINE, $ES_AUTOVSCROLL, $WS_VSCROLL))

;~ Important line
        _GUICtrlRichEdit_SetSel($hRichEdit, 0, 0)

        GUISetState(@SW_SHOW)
;~ GUICtrlSendMsg ($hRichEdit, $EM_LINESCROLL, 0, 0)
        local $i
        For $i=10 to 20
;~          _GUICtrlEdit_LineScroll($idMyedit, 0, _GUICtrlEdit_GetLineCount($idMyedit))
;~          _GUICtrlEdit_LineScroll($hRichEdit, 0, _GUICtrlEdit_GetLineCount($hRichEdit))
            _GUICtrlEdit_LineScroll($idMyedit, 0, $i)
            _GUICtrlEdit_LineScroll($hRichEdit, 0, $i)
;~          GUICtrlSendMsg ($hRichEdit, $EM_LINESCROLL, 0, $i)
;~          Local $nIndex = GUICtrlSendMsg ($hRichEdit, $EM_LINEINDEX, $i, 0)
;~          GUICtrlSendMsg ($hRichEdit, $EM_SETSEL, $nIndex, 0)
;~          ControlCommand ($hGUI, "", $hRichEdit, "SetCurrentSelection", @CRLF)

;~          $iCharPosition = _GUICtrlRichEdit_GetFirstCharPosOnLine($hRichEdit, $i)
;~          _GUICtrlRichEdit_SetSel($hRichEdit, $iCharPosition, $iCharPosition + 4)

            sleep(250)
        next
;~ Important line
;~          _GUICtrlEdit_SetSel($idMyedit, -1, -1)
;~          _GUICtrlRichEdit_SetSel($hRichEdit, -1,-1)
        For $i=10 to 0 step -1
            _GUICtrlEdit_LineScroll($idMyedit, 0, $i)
            _GUICtrlEdit_LineScroll($hRichEdit, 0, $i)
            sleep(250)
        next

        ; Loop until the user exits.
        While 1
                Switch GUIGetMsg()
                        Case $GUI_EVENT_CLOSE
                                ExitLoop
                EndSwitch
        WEnd
        GUIDelete()
EndFunc   ;==>Example

 

Edited by junkew
Posted (edited)
On 3/20/2025 at 3:07 AM, TheAutomator said:

The edit has no scrollbar and that should stay that way

Maybe you will tell us why you don't want to use a native vertical scrollbar in your richedit control, is it simply its color you don't like, or something else ? Because, as you already know, a simple $WS_SCROLL style would solve it all.

Anyway, as you prefer to mimic the scrollbar (by using a vertical movable/resizable label control) , then imho the 1st step should be to constantly check what is the last visible line in your richedit control.

Knowing the 1st visible line is easy, as there is a native windows message EM_GETFIRSTVISIBLELINE which indicates this. With AutoIt, the message is found in the function _GUICtrlRichEdit_GetNumberOfFirstVisibleLine()

But unfortunately there is no "EM_GETLASTVISIBLELINE" Windows message (and it's a pity) but you can calculate it, using a couple of other messages, as shown in the script below.

Now, when you got these 2 variables (1st and last visible lines) then it should be possible to mimic a vertical scrollbar, by comparing constantly the value of the 2 variables to the total number of lines in your richedit control, then move/resize accordingly your vertical label (the "scrollbar thumb")

The script below got a scrollable richedit control (using mousewheel, without scrollbar) as discussed in our preceding posts. The purpose of the script is simply to indicate how to calculate the last visible line of a richedit control, which is (imho) the 1st step that could help to achieve your goal.

Good luck :)

#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>

Opt("MustDeclareVars", 1) ;0=no, 1=require pre-declaration

Global $g_hRichEdit

Example()

Func Example()
    Local $hGui, $idLblMsg, $idBtnNext, $aRect, $iCharIndex, $iLastVisibleLine

    $hGui = GUICreate("Last visible line richedit", 320, 320)
    $g_hRichEdit = _GUICtrlRichEdit_Create($hGui, "Line # 01", 5, 5, 310, 214, _
        BitOR($ES_MULTILINE, $ES_AUTOVSCROLL))
    $idLblMsg = GUICtrlCreateLabel("", 5, 225, 310, 50)
    GUICtrlSetBkColor(-1, 0xFFFF00) ; yellow
    $idBtnNext = GUICtrlCreateButton("Scroll then Check last visible line", 70, 280, 180, 30)

    GUISetState(@SW_SHOW)

    _GUICtrlRichEdit_AppendText($g_hRichEdit, @CRLF & "Line # 02")
    For $i = 3 To 40
        _GUICtrlRichEdit_AppendText($g_hRichEdit, @CRLF & "Line # " & StringFormat("%02i", $i))
    Next
    _GUICtrlRichEdit_SetSel($g_hRichEdit, 0, 129)
    _GUICtrlRichEdit_SetCharAttributes($g_hRichEdit, "+bo")

    _GUICtrlRichEdit_SetEventMask($g_hRichEdit, $ENM_SCROLLEVENTS)
    GUIRegisterMsg($WM_NOTIFY, WM_NOTIFY)

    While True
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                _GUICtrlRichEdit_Destroy($g_hRichEdit)
                Exit

            Case $idBtnNext
                $aRect = _GUICtrlRichEdit_GetRECT($g_hRichEdit)
                ; ConsoleWrite("Formatting rectangle : " & $aRect[0] & "  " & $aRect[1] & "  " & $aRect[2] & "  " & $aRect[3] & @crlf)

                $iCharIndex = _GUICtrlRichEdit_GetCharPosFromXY($g_hRichEdit, $aRect[0] + 2, $aRect[3] - 2)
                ; ConsoleWrite("$iCharIndex : " & $iCharIndex & @crlf)

                $iLastVisibleLine = _GUICtrlRichEdit_GetLineNumberFromCharPos($g_hRichEdit, $iCharIndex)
                ; ConsoleWrite("$iLastVisibleLine : " & $iLastVisibleLine & @crlf & "=================" & @crlf)

                GUICtrlSetData($idLblMsg, "First  Visible Line : " & _GUICtrlRichEdit_GetNumberOfFirstVisibleLine($g_hRichEdit) & @crlf & _
                    "Last  Visible Line : " & $iLastVisibleLine & @crlf & _
                    "Count of all lines  : " & _GUICtrlRichEdit_GetLineCount($g_hRichEdit))

                ControlFocus($hGUI, "", $g_hRichEdit)
        EndSwitch
    WEnd
EndFunc   ;==>Example

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $tFilter = DllStructCreate($tagMSGFILTER, $lParam)
    If $tFilter.hwndFrom = $g_hRichEdit Then _GUICtrlRichEdit_ScrollLines($g_hRichEdit, $tFilter.wParam ? 1 : -1)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Lastvisiblelinerichedit.png.e57002cf6d4170d30748a17117dc4cb2.png

 

Edited by pixelsearch
added "count of all lines"

"I think you are searching a bug where there is no bug..."

Posted (edited)

Hi everyone,
thanks for the replys!

Normally I reply whitin a day, but I have been sick the last few days..

junkew,

Thanks, it's a good start for me to experiment with :) The messages you listed are the ones that should work somehow if I combine them the right way yes.

pixelsearch,

Thanks for the effort :) I want a custom colored scrollbar is the reason, not the ugly white standart one that hurts your eyes when using a dark gui (like in my project). Your code has no scrollbar at all but the code can be helpfull for calculations!

I already made the graphics to fit the dark theme, but the code is still a bit buggy and not completely working:
image.png.813ad3f612b196fd43187cf8d91be387.png

image.png.d276310408b12b6054689ed9b6e4330f.png

I wish i could just hide the default one but send messages to it and get from it instead of reinventing the wheel to have a custom color...

I'm gonna experiment a little more with the code and see how good i can get it for general use, for now my bar just moves the cursor and resets the selection when done scrolling (it works pretty well too but you can see the cursor move when you scroll and the bar stays on the same spot when you change the text).

So what I already have now:
- an image for the background and one for the thumb
- the ability to drag the thumb image over the background and get the result als a value between 0 and 1 according to the position dragged
- some code that works a bit but not fully as i would like (like a real scrollbar)

When I have a few finished scripts i'll post them here
 

Edited by TheAutomator
edit for pixelsearch
Posted
Just now, TheAutomator said:

Your code has no scrollbar at all

Yes I know :D
The purpose of my preceding post was just to indicate how to calculate precisely the number of the last visible line, which seems to me a very important step before doing anything else : remember the height of the scroll thumb should be recalculated when comparing the number of visible lines to the number of total lines, which will constantly change while the user adds/removes lines.

In a 2nd step, I went a bit further, adding a registered WM_COMMAND message to take care of $EN_CHANGE or $EN_UPDATE, which could call a function dedicated to resize/move the scroll thumb (or hide it when all lines are visible in the richedit area)

Maybe $EN_UPDATE is a better choice than $EN_CHANGE because the scrolling function will be called only from this place ($EN_UPDATE) . Because if you choose instead to monitor $EN_CHANGE, then you'll have to call the scrolling function from several other places (for example from inside WM_NOTIFY while you're using the mouse wheel to scroll [this triggers $EN_UPDATE but not $EN_CHANGE], or from a resize function, in case one day you allow the richedit control to be resized while you resize the GUI etc...)

The annoyance with $EN_UPDATE is that it's called more often than $EN_CHANGE, which means the scrolling function will also be called more often when using $EN_UPDATE (compared to $EN_CHANGE)

Anyway, all this is challenging for educational purpose. If I succeed achieving some working code, I"ll post it here.

21 minutes ago, TheAutomator said:

Normally I reply whitin a day, but I have been sick the last few days..

Glad to know you're feeling better :)

"I think you are searching a bug where there is no bug..."

Posted (edited)
39 minutes ago, pixelsearch said:

Yes I know :D
The purpose of my preceding post was just to indicate how to calculate precisely the number of the last visible line, which seems to me a very important step before doing anything else : remember the height of the scroll thumb should be recalculated when comparing the number of visible lines to the number of total lines, which will constantly change while the user adds/removes lines.

In a 2nd step, I went a bit further, adding a registered WM_COMMAND message to take care of $EN_CHANGE or $EN_UPDATE, which could call a function dedicated to resize/move the scroll thumb (or hide it when all lines are visible in the richedit area)

Maybe $EN_UPDATE is a better choice than $EN_CHANGE because the scrolling function will be called only from this place ($EN_UPDATE) . Because if you choose instead to monitor $EN_CHANGE, then you'll have to call the scrolling function from several other places (for example from inside WM_NOTIFY while you're using the mouse wheel to scroll [this triggers $EN_UPDATE but not $EN_CHANGE], or from a resize function, in case one day you allow the richedit control to be resized while you resize the GUI etc...)

The annoyance with $EN_UPDATE is that it's called more often than $EN_CHANGE, which means the scrolling function will also be called more often when using $EN_UPDATE (compared to $EN_CHANGE)

Anyway, all this is challenging for educational purpose. If I succeed achieving some working code, I"ll post it here.

Glad to know you're feeling better :)

the code you provided is already helpfull for calculations, but seeing all this makes me think if it's worth all the trouble..
if _GUICtrlRichEdit_ScrollLines($hWnd, $iQlines) would have the ability to work in a non relative way, the problem would be a lot more easy! I don't get why such functionality does'nt exist..

Maybe I need to keep it basic and just save the current selection, move the cursor to the targetline and when done dragging the scroller restore the selection (like I already have code for) and to set the scroll thumb to the right place while editing -> check if cursorpos is changed in the gui loop?

other alternative: somehow change transparancy of the real scrollbar

Edited by TheAutomator
Posted
3 hours ago, TheAutomator said:

 I want a custom colored scrollbar is the reason, not the ugly white standart one that hurts your eyes when using a dark gui (like in my project).

If it's running on Windows 10 or 11, you can add a win32-darkmode scrollbar. It isn't quite the same aesthetic as your custom-made scrollbar, but it likely wont have all of the other issues that you are experiencing with your custom scrollbar that you mentioned.

I added one to your MiniMark.au3 and it works really well. I've added a video within a spoiler so that you can see.

Spoiler

 

 

 

 

  • Solution
Posted (edited)
Spoiler
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
#include "GUIDarkMode_v0.02mod.au3" ; https://www.autoitscript.com/forum/applications/core/interface/file/attachment.php?id=76109&key=ecd9ab7288a19d16e4d006193fba0763

Example()

Func Example()
    Local $hGui, $hRichEdit, $iMsg, $iW = 400, $iH = 200
    $hGui = GUICreate("Example (" & StringTrimRight(@ScriptName, StringLen(".exe")) & ")", $iW, $iH, -1, -1)
    $hRichEdit = _GUICtrlRichEdit_Create($hGui, "", 0, 0, $iW, $iH, _
            BitOR($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL), 0)
    _GUICtrlRichEdit_SetBkColor($hRichEdit, 0x212121)
    _GUICtrlRichEdit_SetCharColor($hRichEdit, 0xFFFFFF)
    set_W11GuiColor($hGUI, 0x121212, 35) ; for Win 11 22H2 onwards ; Caption background
    GuiDarkmodeApply($hGUI)
    GUISetState(@SW_SHOW)
    Local $sText = ""
    For $n = 1 To 40
        $sText &= "This is appended text." & @CRLF
    Next
    _GUICtrlRichEdit_AppendText($hRichEdit, $sText)

    While True
        $iMsg = GUIGetMsg()
        Select
            Case $iMsg = $GUI_EVENT_CLOSE
                _GUICtrlRichEdit_Destroy($hRichEdit)                 ; needed unless script crashes
                ; GUIDelete()   ; is OK too
                Exit
        EndSelect
    WEnd
EndFunc   ;==>Example

;~ set_W11GuiColor($gui_hwnd, 0x00ff00) ; for Win 11 22H2 onwards
Func set_W11GuiColor($hwnd, $iBorderColor = 0xFFffffff, $DWMWA_BORDER_COLOR = 34) ; default is 0xffFFFFFF ; else use 0x00rrggbb
;~     $DWMWA_BORDER_COLOR = 34 ; https://www.purebasic.fr/english/viewtopic.php?t=78732
;~          Enumeration DWMWINDOWATTRIBUTE
;~            #DWMWA_USE_IMMERSIVE_DARK_MODE = 20
;~            #DWMWA_BORDER_COLOR = 34
;~            #DWMWA_CAPTION_COLOR = 35
;~            #DWMWA_TEXT_COLOR = 36
;~          EndEnumeration
    dllcall( _
        'dwmapi.dll', _
        'long',   'DwmSetWindowAttribute', _
        'hwnd',   $hwnd, _
        'dword',  $DWMWA_BORDER_COLOR, _
        'dword*', $iBorderColor, _
        'dword', 4 )
EndFunc

image.png.820417a3a6f7b7a8247282bff9c5a5cf.png     image.png.63d885b1adfd2554d8da4b84e3f3641b.png

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
18 hours ago, WildByDesign said:

If it's running on Windows 10 or 11, you can add a win32-darkmode scrollbar. It isn't quite the same aesthetic as your custom-made scrollbar, but it likely wont have all of the other issues that you are experiencing with your custom scrollbar that you mentioned.

I added one to your MiniMark.au3 and it works really well. I've added a video within a spoiler so that you can see.

  Reveal hidden contents

 

 

How did you do that? That's a huge improvement!

Posted
16 hours ago, argumentum said:
  Reveal hidden contents
#include <GUIConstantsEx.au3>
#include <GuiRichEdit.au3>
#include <WindowsConstants.au3>
#include "GUIDarkMode_v0.02mod.au3" ; https://www.autoitscript.com/forum/applications/core/interface/file/attachment.php?id=76109&key=ecd9ab7288a19d16e4d006193fba0763

Example()

Func Example()
    Local $hGui, $hRichEdit, $iMsg, $iW = 400, $iH = 200
    $hGui = GUICreate("Example (" & StringTrimRight(@ScriptName, StringLen(".exe")) & ")", $iW, $iH, -1, -1)
    $hRichEdit = _GUICtrlRichEdit_Create($hGui, "", 0, 0, $iW, $iH, _
            BitOR($ES_MULTILINE, $WS_VSCROLL, $ES_AUTOVSCROLL), 0)
    _GUICtrlRichEdit_SetBkColor($hRichEdit, 0x212121)
    _GUICtrlRichEdit_SetCharColor($hRichEdit, 0xFFFFFF)
    set_W11GuiColor($hGUI, 0x121212, 35) ; for Win 11 22H2 onwards ; Caption background
    GuiDarkmodeApply($hGUI)
    GUISetState(@SW_SHOW)
    Local $sText = ""
    For $n = 1 To 40
        $sText &= "This is appended text." & @CRLF
    Next
    _GUICtrlRichEdit_AppendText($hRichEdit, $sText)

    While True
        $iMsg = GUIGetMsg()
        Select
            Case $iMsg = $GUI_EVENT_CLOSE
                _GUICtrlRichEdit_Destroy($hRichEdit)                 ; needed unless script crashes
                ; GUIDelete()   ; is OK too
                Exit
        EndSelect
    WEnd
EndFunc   ;==>Example

;~ set_W11GuiColor($gui_hwnd, 0x00ff00) ; for Win 11 22H2 onwards
Func set_W11GuiColor($hwnd, $iBorderColor = 0xFFffffff, $DWMWA_BORDER_COLOR = 34) ; default is 0xffFFFFFF ; else use 0x00rrggbb
;~     $DWMWA_BORDER_COLOR = 34 ; https://www.purebasic.fr/english/viewtopic.php?t=78732
;~          Enumeration DWMWINDOWATTRIBUTE
;~            #DWMWA_USE_IMMERSIVE_DARK_MODE = 20
;~            #DWMWA_BORDER_COLOR = 34
;~            #DWMWA_CAPTION_COLOR = 35
;~            #DWMWA_TEXT_COLOR = 36
;~          EndEnumeration
    dllcall( _
        'dwmapi.dll', _
        'long',   'DwmSetWindowAttribute', _
        'hwnd',   $hwnd, _
        'dword',  $DWMWA_BORDER_COLOR, _
        'dword*', $iBorderColor, _
        'dword', 4 )
EndFunc

image.png.820417a3a6f7b7a8247282bff9c5a5cf.png     image.png.63d885b1adfd2554d8da4b84e3f3641b.png

This is the best solution so far, i'll think i'm gonna stick with this one :)
I'll have to extract out of the udf only what is needed, but the original udf gets credits (if that's an ok way to burrow code on this forum)

Posted
1 hour ago, TheAutomator said:

How did you do that? That's a huge improvement!

Mine is the same as argumentum’s, so I would follow that code. That one also has the advantage of making the titlebar dark as well but I believe that part only works on Windows 11.

Posted

Here another approach using my latest UDF :

image.png.9abd2dc7687ee01448c98e6b4476fc0e.png

You can scroll with mouse wheel and kb arrows.  See the example posted in my thread.

BTW, with my UDF, you don't need all those tens of images, you can do everything with it.

 

Posted (edited)
4 hours ago, TheAutomator said:

...but the original udf gets credits (if that's an ok way to burrow code on this forum)

I very much doubt that you'll stop the copy'n'paste because is not yours :lol:

Spoiler

image.png.a03f4ec059b2c7e2ab23cfda926d027d.png

PS: I don't care much about credits :) 

Edited by argumentum
image

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Posted
Posted
On 3/27/2025 at 11:21 PM, Nine said:

Here another approach using my latest UDF :

image.png.9abd2dc7687ee01448c98e6b4476fc0e.png

You can scroll with mouse wheel and kb arrows.  See the example posted in my thread.

BTW, with my UDF, you don't need all those tens of images, you can do everything with it.

 

Dude...! :D

This would be perfect!
Tomorrow i'm gonna have a look at your udf, thanks for posting!

Posted (edited)
On 3/27/2025 at 11:21 PM, Nine said:

Here another approach using my latest UDF :

image.png.9abd2dc7687ee01448c98e6b4476fc0e.png

You can scroll with mouse wheel and kb arrows.  See the example posted in my thread.

BTW, with my UDF, you don't need all those tens of images, you can do everything with it.

 

Hi Nine,

Would it be to much to ask to show us a trimmed down version / function just to make a label behave like a thumb, like in this example? :whistle:
I tried to do it myself, but i'm afraid i'm messing up inportant calls and create memory leaks :tv_horror:...

What I understand about your code is that it makes use of _WinAPI_SetWindowSubclass to hook the RichEdit control to handle custom scrollbar behavior?
$hProc is a callback function (RichEditProc), which processes scroll messages right?

Local $hProc = DllCallbackRegister(__RGUI_ScrollBarProc, 'lresult', 'hwnd;uint;wparam;lparam;uint_ptr;dword_ptr')
  _WinAPI_SetWindowSubclass(GUICtrlGetHandle($idScroll), DllCallbackGetPtr($hProc), $idScroll, $idCtrl)
  Local $aScroll = [$fCall, $hProc, $iTop + 5, $iSize - 54]
  $mScroll[$idScroll] = $aScroll
  Return $idScroll

This is like chinese to me.
Noob asking for help here, I know (no pressure tho).

Edited by TheAutomator

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...