1 (изменено: MandarinKa02, 2017-11-18 13:18:14)

Тема: AHK: Edit(Scrolling)

Всем привет, хочу сделать что-то вроде консоли из контрола Edit.
Почти каждую секунду срабатывает GuiControl и в Edit добавляется еще текст и каждый раз скроллинг сбрасывается и падает на первую строку. Как можно сохранить местоположение ползунка при добавлении текста?
Вот пример:


Gui, New
Gui, Color, 111111
Gui, Font, s7 cFFFFFF, Georgia
Gui, Add, Edit, w200 h300 hwndhEdit ReadOnly
Gui, Show
GoSub, AddText
return

GuiClose:
ExitApp

AddText:
i=0
While(1) {
	Sleep, 100
	i++
	msg .= "text #" i "`n"
	GuiControl,, % hEdit, % msg
}
Return

F5::Reload

2

Re: AHK: Edit(Scrolling)

Про костыли с Page Up, Wheel Up и пр. знаю.

3 (изменено: serzh82saratov, 2017-11-18 18:59:04)

Re: AHK: Edit(Scrolling)

Чтобы можно было спокойно редактировать текст, наверное не получится, хотя в примере и так ReadOnly.


#SingleInstance Force
#NoEnv
VarSetCapacity(start, 4), VarSetCapacity(end, 4)
Gui, Color, 111111
Gui, Font, s7 cFFFFFF, Georgia
Gui, Add, Edit, w200 h100 hwndhEdit ReadOnly
Gui, Show

AddText:
	Loop {
		Sleep, 100
		msg := "text #" A_Index "`r`n"
		GuiControl, -Redraw, %hEdit%
		SendMessage, 0xB0, &start, &end, , ahk_id %hEdit%  ; EM_GETSEL
		SendMessage, 0x0E, , , , ahk_id %hEdit%    ;  WM_GETTEXTLENGTH
		SendMessage, 0x00B1, Errorlevel, Errorlevel, , ahk_id %hEdit%    ;  EM_SETSEL
		; Control, EditPaste, %msg%, , ahk_id %hEdit%
		SendMessage, 0x00C2 , TRUE, &msg,, ahk_id %hEdit%  ;	EM_REPLACESEL
		SendMessage, 0x0B1, NumGet(start), NumGet(end), , ahk_id %hEdit%  ; EM_SETSEL
		GuiControl, +Redraw, %hEdit%
	}
	Return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

4

Re: AHK: Edit(Scrolling)

Обновление текста в стандартном Edit разрушает состояния каретки и скролла.
Вполне возможно, что в нестандартных Edit контролах есть способы обновлять содержимое без разрушения состояния.

Можно сохранять эти два состояния перед обновлением и восстанавливать после:

Gui Color, 111111
Gui Font, s7 cFFFFFF, Georgia
Gui Add, Edit, w200 h150 hwndhEdit ReadOnly
Gui Show

i:=0
Loop {
	Sleep 300
	ScrPos := SB_GetPos(hEdit)
	EM_GETSEL(hEdit, start, end)

	GuiControl,, % hEdit, % msg .= "text #" ++i "`n"

	EM_SETSEL(hEdit, start, end)
	; SB_SetPos(hEdit,, ScrPos)
	SetScrollPos(hEdit, true, ScrPos)
	; PostMessage, WM_VSCROLL := 0x115, SB_LINEUP := 0,,, ahk_id %hEdit%
}

GuiClose:
	ExitApp


; ======================================================================================================================
; Gets the starting and ending character positions of the current selection in an edit control.
; Start  -  receives the start of the current selection
; End    -  receives the end of the current selection
; ======================================================================================================================
EM_GETSEL(HWND, ByRef Start, ByRef End) {
   ; EM_GETSEL = 0x00B0 -> msdn.microsoft.com/en-us/library/bb761598(v=vs.85).aspx
   Start := End := 0
   DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B0, "UIntP", Start, "UIntP", End, "Ptr")
   ++Start, ++End
   Return True
}
; ======================================================================================================================
; Selects a range of characters in an edit control.
; Start  -  the character index of the start of the selection.
; End    -  the character index of the end of the selection.
; ======================================================================================================================
EM_SETSEL(HWND, Start, End) {
   ; EM_SETSEL = 0x00B1 -> msdn.microsoft.com/en-us/library/bb761661(v=vs.85).aspx
   Return DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B1, "Ptr", Start - 1, "Ptr", End - 1, "Ptr")
}


SB_GetPos(hwnd, Which:="V"){
    Which := (Which="V" || Which=1) ? 1 : (Which="H" || Which=0) ? 0 : 1
    Return DllCall("GetScrollPos", "UInt", Hwnd, "Int", Which)                
}

SB_SetPos(hwnd, Which:="V", To:="0"){
    Which := (Which="V" || Which=1) ? 1 : (Which="H" || Which=0) ? 0 : 1
    Return DllCall("SetScrollPos", "UInt", Hwnd, "Int", Which, "Int", To, "UInt", 1)
}


SetScrollPos(hwnd, fnBar, nPos)
{
    VarSetCapacity(si, 28, 0) ; SCROLLINFO si
    NumPut(28  , si,  0)    ; si.cbSize := sizeof(SCROLLINFO)
    NumPut(0x4 , si,  4)    ; si.fMask := SIF_POS
    NumPut(nPos, si, 20)    ; si.nPos := nPos
 
    ; Use SetScrollInfo first because it supports 32-bit positions.
    ; If an application supports positions < 0 or > 65535, it most likely
    ; ignores WM_#SCROLL's wParam and uses GetScrollPos or GetScrollInfo
    ; to get the actual scroll position.
    DllCall("SetScrollInfo", "uint", hwnd, "int", fnBar, "uint", &si, "int", 0)
    
    ; WM_HSCROLL or WM_VSCROLL must be sent for the window to update it's contents.
    msg := (fnBar=0) ? 0x114 : 0x115
    wParam := 4 ; SB_THUMBPOSITION
        | ((nPos&0xFFFF)<<16)
    SendMessage, msg, wParam,,, ahk_id %hwnd%
    
    return (ErrorLevel != "FAIL")
}

GetScrollInfo(hwnd, fnBar, ByRef nPos=0, ByRef nTrackPos=0, ByRef nMin=0, ByRef nMax=0, ByRef nPage=0)
{
    WinGet, Style, Style, ahk_id %hwnd%
    if !(Style & (fnBar ? 0x200000 : 0x100000))
        return false ; Fix for some controls which report {min:0,max:100} even though scroll bar doesn't exist.

    VarSetCapacity(si, 28, 0) ; SCROLLINFO si
    NumPut(28  , si, 0) ; si.cbSize := sizeof(SCROLLINFO)
    NumPut(0x17, si, 4) ; si.fMask := SIF_ALL
    
    if ! DllCall("GetScrollInfo", "uint", hwnd, "int", fnBar, "uint", &si)
        return false
    
    nPos        := NumGet(si, 20)
    nTrackPos   := NumGet(si, 24)
    nMin        := NumGet(si,  8)
    nMax        := NumGet(si, 12)
    nPage       := NumGet(si, 16)
    return true
}

5 (изменено: MandarinKa02, 2017-11-18 18:39:37)

Re: AHK: Edit(Scrolling)

Спасибо за ответы. stealzy, Ваш пример подошел. За SB_LINEUP отдельное спасибо Не знал, что и такое есть. Пригодится когда консоль будет забиваться.

6

Re: AHK: Edit(Scrolling)

Поправил пост, оказалось если в конце добавлять не "`n"  а "`r`n" то даже на 100мс мельканий нет.
Главное отличие способов в том, что у меня в буфере будет только строка для добавления, в отличие от постоянно растущего буфера со всем содержимым.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

7

Re: AHK: Edit(Scrolling)

serzh82saratov, у меня буфер будет размером в 50 строк. И при каждом добавлении 51-ой строки, первая будет убираться. В итоге буфер не будет превышать 50 строк.

8

Re: AHK: Edit(Scrolling)

Тогда метод stealzy удобнее, можно сразу из msg удалять 1 строку.
В вашем случае надо будет ещё позицию каретки пересчитывать исходя из удалённых данных.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

9 (изменено: MandarinKa02, 2017-12-21 19:51:22)

Re: AHK: Edit(Scrolling)

serzh82saratov пишет:

В вашем случае надо будет ещё позицию каретки пересчитывать исходя из удалённых данных.

Уже работаю.

10 (изменено: MandarinKa02, 2017-12-21 19:49:42)

Re: AHK: Edit(Scrolling)

Сделал вот такое(вроде на костыль не похоже).


Gui Color, 111111
Gui Font, s7 cFFFFFF, Georgia
Gui Add, Edit, w200 h150 hwndhConsole ReadOnly
Gui Show

i:=0, line := 0
Loop {
	Sleep 100
    value := "text" ++i
    len := 0
    ScrPos := SB_GetPos(hConsole)
    EM_GETSEL(hConsole, start, end)



    if(line = 50) {
        len := GetFirstLineLength(msg)
        msg := RegExReplace(msg, "U).*`n",,,1), msg .= value "`n"
    }
    else msg .= value "`n", line++
    GuiControl,, % hConsole, % msg



    EM_SETSEL(hConsole, start-len, end-len)
    SB_SetPos(hConsole,, ScrPos)
    SetScrollPos(hConsole, true, ScrPos)
    if(line = 50)
        PostMessage, WM_VSCROLL := 0x115, SB_LINEUP := 0,,, ahk_id %hConsole%
}

GuiClose:
	ExitApp
f5::reload
GetFirstLineLength(line) {
    return Strlen(RegExReplace(line, "U)`n.*",,,1))
}
; ======================================================================================================================
; Gets the starting and ending character positions of the current selection in an edit control.
; Start  -  receives the start of the current selection
; End    -  receives the end of the current selection
; ======================================================================================================================
EM_GETSEL(HWND, ByRef Start, ByRef End) {
   ; EM_GETSEL = 0x00B0 -> msdn.microsoft.com/en-us/library/bb761598(v=vs.85).aspx
   Start := End := 0
   DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B0, "UIntP", Start, "UIntP", End, "Ptr")
   ++Start, ++End
   Return True
}
; ======================================================================================================================
; Selects a range of characters in an edit control.
; Start  -  the character index of the start of the selection.
; End    -  the character index of the end of the selection.
; ======================================================================================================================
EM_SETSEL(HWND, Start, End) {
   ; EM_SETSEL = 0x00B1 -> msdn.microsoft.com/en-us/library/bb761661(v=vs.85).aspx
   Return DllCall("User32.dll\SendMessage", "Ptr", HWND, "UInt", 0x00B1, "Ptr", Start - 1, "Ptr", End - 1, "Ptr")
}


SB_GetPos(hwnd, Which:="V"){
    Which := (Which="V" || Which=1) ? 1 : (Which="H" || Which=0) ? 0 : 1
    Return DllCall("GetScrollPos", "UInt", Hwnd, "Int", Which)                
}

SB_SetPos(hwnd, Which:="V", To:="0"){
    Which := (Which="V" || Which=1) ? 1 : (Which="H" || Which=0) ? 0 : 1
    Return DllCall("SetScrollPos", "UInt", Hwnd, "Int", Which, "Int", To, "UInt", 1)
}


SetScrollPos(hwnd, fnBar, nPos)
{
    VarSetCapacity(si, 28, 0) ; SCROLLINFO si
    NumPut(28  , si,  0)    ; si.cbSize := sizeof(SCROLLINFO)
    NumPut(0x4 , si,  4)    ; si.fMask := SIF_POS
    NumPut(nPos, si, 20)    ; si.nPos := nPos
 
    ; Use SetScrollInfo first because it supports 32-bit positions.
    ; If an application supports positions < 0 or > 65535, it most likely
    ; ignores WM_#SCROLL's wParam and uses GetScrollPos or GetScrollInfo
    ; to get the actual scroll position.
    DllCall("SetScrollInfo", "uint", hwnd, "int", fnBar, "uint", &si, "int", 0)
    
    ; WM_HSCROLL or WM_VSCROLL must be sent for the window to update it's contents.
    msg := (fnBar=0) ? 0x114 : 0x115
    wParam := 4 ; SB_THUMBPOSITION
        | ((nPos&0xFFFF)<<16)
    SendMessage, msg, wParam,,, ahk_id %hwnd%
    
    return (ErrorLevel != "FAIL")
}

GetScrollInfo(hwnd, fnBar, ByRef nPos=0, ByRef nTrackPos=0, ByRef nMin=0, ByRef nMax=0, ByRef nPage=0)
{
    WinGet, Style, Style, ahk_id %hwnd%
    if !(Style & (fnBar ? 0x200000 : 0x100000))
        return false ; Fix for some controls which report {min:0,max:100} even though scroll bar doesn't exist.

    VarSetCapacity(si, 28, 0) ; SCROLLINFO si
    NumPut(28  , si, 0) ; si.cbSize := sizeof(SCROLLINFO)
    NumPut(0x17, si, 4) ; si.fMask := SIF_ALL
    
    if ! DllCall("GetScrollInfo", "uint", hwnd, "int", fnBar, "uint", &si)
        return false
    
    nPos        := NumGet(si, 20)
    nTrackPos   := NumGet(si, 24)
    nMin        := NumGet(si,  8)
    nMax        := NumGet(si, 12)
    nPage       := NumGet(si, 16)
    return true
}

Только, если выделять текст во время добавление строчки то он будет прыгать. Но то не существенно.

11 (изменено: MandarinKa02, 2017-12-21 19:49:56)

Re: AHK: Edit(Scrolling)

Еще в конце можно переделать условие,


if(line = 50 && ScrPos != 38)
        PostMessage, WM_VSCROLL := 0x115, SB_LINEUP := 0,,, ahk_id %hConsole%

Тогда, если строка будет равна последней(38-ая), то LINEUP работать не будет

12

Re: AHK: Edit(Scrolling)

serzh82saratov пишет:

Тогда метод stealzy удобнее, можно сразу из msg удалять 1 строку.

А может и неудобнее.


maxlines := 10
VarSetCapacity(start, 4), VarSetCapacity(end, 4)
Gui, Color, 111111
Gui, Font, s7 cFFFFFF, Georgia
Gui, Add, Edit, w200 h100 hwndhEdit ReadOnly
Gui, Show

AddText:
	Loop {
		Sleep, 100
		GuiControl, -Redraw, %hEdit%
		SendMessage, 0xB0, &start, &end, , ahk_id %hEdit%  ; EM_GETSEL
		SendMessage, 0x0E, , , , ahk_id %hEdit%    ;  WM_GETTEXTLENGTH
		msg := (Errorlevel ? "`r`n" : "") "text #" A_Index
		SendMessage, 0x00B1, Errorlevel, Errorlevel, , ahk_id %hEdit%    ;  EM_SETSEL
		SendMessage, 0x00C2 , TRUE, &msg,, ahk_id %hEdit%  ;	EM_REPLACESEL
		SendMessage, 0x00BA, 0, 0,, ahk_id %hEdit% ; EM_GETLINECOUNT
		If (Errorlevel > maxlines)
		{
			SendMessage, 0xBB, 1,,,ahk_id %hEdit%    ;  EM_LINEINDEX
			SendMessage, 0x00B1, 0, Off := Errorlevel, , ahk_id %hEdit%    ;  EM_SETSEL
			SendMessage, 0x00C2 , TRUE, 0,, ahk_id %hEdit%  ;	EM_REPLACESEL
		}
		SendMessage, 0x0B1, NumGet(start), NumGet(end), , ahk_id %hEdit%  ; EM_SETSEL
		GuiControl, +Redraw, %hEdit%
	}
	Return

Тут вопрос, где должен оставатся курсор, если длинны строк разные.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

13

Re: AHK: Edit(Scrolling)

serzh82saratov пишет:

Тут вопрос, где должен оставатся курсор, если длинны строк разные.

ООооо.. Ну здесь вы попались Вам по-любому нужен буфер и Strlen.

14

Re: AHK: Edit(Scrolling)

Не понял какой буфер, вопрос то не про - как, а про - что должно получится.
Сейчас остаётся в том же месте от начала текста, а если длинны строк разные, то получится что может визуально смещатся.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

15

Re: AHK: Edit(Scrolling)

ControlGet, Line, CurrentLine,,, ahk_id %hEdit%
ControlGet, Col, CurrentCol,,, ahk_id %hEdit%

16

Re: AHK: Edit(Scrolling)

MandarinKa02 пишет:

ООооо.. Ну здесь вы попались Вам по-любому нужен буфер и Strlen.

Так что за буфер такой?

maxlines := 20
VarSetCapacity(start, 4), VarSetCapacity(end, 4)
Gui, Color, 111111
Gui, Font, s12 cFFFFFF, Georgia
Gui, Add, Edit, w400 r18 hwndhEdit ReadOnly, 8`nлд
Gui, Show
Str = ########## ######## #############

AddText:
	Loop {
		Sleep, 200
		GuiControl, -Redraw, %hEdit%
		SendMessage, 0xB0, &start, &end, , ahk_id %hEdit%  ; EM_GETSEL
		ControlGet, Line, CurrentLine,,, ahk_id %hEdit%
		ControlGet, Col, CurrentCol,,, ahk_id %hEdit%
		SendMessage, 0x0E, , , , ahk_id %hEdit%    ;  WM_GETTEXTLENGTH
		random, rand, 0, 33
		msg := (Errorlevel ? "`r`n" : "") SubStr(Str, 1, rand) 
		SendMessage, 0x00B1, Errorlevel, Errorlevel, , ahk_id %hEdit%    ;  EM_SETSEL
		SendMessage, 0x00C2 , TRUE, &msg,, ahk_id %hEdit%  ;	EM_REPLACESEL
		SendMessage, 0x00BA, 0, 0,, ahk_id %hEdit% ; EM_GETLINECOUNT
		If ((LINECOUNT := Errorlevel) > maxlines)
		{
			SendMessage, 0xBB, 1,,,ahk_id %hEdit%    ;  EM_LINEINDEX
			SendMessage, 0x00B1, 0, Off := Errorlevel, , ahk_id %hEdit%    ;  EM_SETSEL
			SendMessage, 0x00C2 , TRUE, 0,, ahk_id %hEdit%  ;	EM_REPLACESEL
		}
		SendMessage, 0xBB, Line - 1,,,ahk_id %hEdit%    ;  EM_LINEINDEX
		_start := Errorlevel + Col - 1
		SendMessage, 0xBB, Line,,,ahk_id %hEdit%    ;  EM_LINEINDEX
		If (_start > (__start := Errorlevel - 2))
			_start := __start
		SendMessage, 0x0B1, _start, NumGet(end) - NumGet(start) + _start, , ahk_id %hEdit%  ; EM_SETSEL
		GuiControl, +Redraw, %hEdit%
		ToolTip % Line
	}
	Return
По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

17

Re: AHK: Edit(Scrolling)

Буфер - всмысле переменная, где хранится весь текст

18

Re: AHK: Edit(Scrolling)

Но тут нет буфера, нет Strlen.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

19

Re: AHK: Edit(Scrolling)

serzh82saratov, вижу)

20 (изменено: serzh82saratov, 2017-11-19 19:57:40)

Re: AHK: Edit(Scrolling)

MandarinKa02 пишет:

ООооо.. Ну здесь вы попались Вам по-любому нужен буфер и Strlen.

Обычно мне фиолетово.
Но вот в чём смысл радости от того, что один из любезно предложенных вам методов для решения вашей задачи оказался, по вашему скромному мнению, нерабочим.
К чему эти "ООооо..", "попались", смайлик, если велика вероятность того что вы же сами ошибаетесь, и если в итоге вы ошибетесь, а вы ошиблись, то тогда такое утверждение будет выглядеть ещё глупее.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

21

Re: AHK: Edit(Scrolling)

MandarinKa02, поставьте точки в конце предложений.

22

Re: AHK: Edit(Scrolling)

http://forum.script-coding.com/viewtopi … 29#p121329
http://forum.script-coding.com/viewtopi … 28#p121328
http://forum.script-coding.com/viewtopi … 20#p121320
http://forum.script-coding.com/viewtopi … 61#p120861
http://forum.script-coding.com/viewtopi … 10#p120710
http://forum.script-coding.com/viewtopi … 01#p120701
http://forum.script-coding.com/viewtopi … 65#p120165
http://forum.script-coding.com/viewtopi … 27#p120127
http://forum.script-coding.com/viewtopi … 36#p119436
http://forum.script-coding.com/viewtopi … 70#p118270
http://forum.script-coding.com/viewtopi … 43#p118143
http://forum.script-coding.com/viewtopi … 33#p118033
http://forum.script-coding.com/viewtopi … 43#p117843
http://forum.script-coding.com/viewtopi … 01#p117301
http://forum.script-coding.com/viewtopi … 05#p110005
http://forum.script-coding.com/viewtopi … 82#p109982