News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

How to create a window with a scroll bar + best way to make an text editor

Started by gelatine1, June 25, 2014, 11:51:31 PM

Previous topic - Next topic

gelatine1

I have a few questions now. My first is how should I create a window that has the possibility to scroll up and down ?

My second question is about the text editor I am writing right now. Currently my code works like this :


  • If user presses character add it to some allocated memory and increment the bytes to write.
  • If the user presses backspace then just decrement the amount of bytes to write. (if possible)
  • After each key press invalidate the whole window
  • When the window receives WM_PAINT write the current amount of bytes (using DrawText)

Now the problem is that once the user wrote like 15 lines or something it stops (because the window is full). So now I was wondering how I should actually implement this code. Should I invalidate the whole window after each character ? How should the program know which bytes of the allocated memory to show ?
So for example if the user scrolls down 3 times then it shouldn't show from like byte 0-100 anymore but from byte 7-109 (for example). Is the only way to do this to search the next enter character in the allocated memory ? or do I have better options ?

If I'm not clear enough then please ask me :/

And my code is below (the message loop):

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
mov eax,uMsg

cmp eax, WM_DESTROY
jnz __cont3

invoke PostQuitMessage,NULL
jmp __cont

__cont3:
cmp eax,WM_KEYDOWN
jnz __cont2

mov eax,wParam
cmp eax,VK_BACK
jnz __cont

mov ecx,[bytesToWrite]
cmp ecx,0
jz __cont

dec ecx
mov [bytesToWrite],ecx
invoke InvalidateRect,hWnd,NULL,0

jmp __cont

__cont2:
cmp eax,WM_CHAR
jnz __cont1
mov eax,wParam

cmp eax,8 ; backspace
jz __cont

mov ecx,[bytesToWrite]
mov edx,[pmem]
mov [edx+ecx],eax
inc ecx
mov [bytesToWrite],ecx
invoke InvalidateRect,hWnd,NULL,0

jmp __cont

__cont1:
cmp eax,WM_PAINT
jnz __cont0

invoke BeginPaint,hWnd, ADDR ps
mov    hdc,eax
invoke GetClientRect,hWnd, ADDR rect
invoke DrawText, hdc,[pmem],[bytesToWrite], ADDR rect,DT_TOP or DT_LEFT or DT_INTERNAL
invoke EndPaint,hWnd, ADDR ps

jmp __cont

__cont0:
invoke DefWindowProc,hWnd,uMsg,wParam,lParam     ; Default message processing
ret

__cont:
xor eax,eax
ret
WndProc endp


There's a tiny problem in my code though but I don't know what causes it. If the user presses backspace nothing actually happens on the screen. After another key is pressed it gets removed though. Why is this? I thought I invalidated my screen so that it would write the contents of [pmem] again but with 1 character less. Clearly something went wrong ?

EDIT: I think that tiny error is because my background doesn't get erased. How should I remove my background if I use the InvalidateRect function ?

Thanks in advance
Jannes

dedndave

first, seperate the 2 issues
for a beginner, it can be mind-boggling to try and sort out many problems at once

there are 2 main ways to create scrollbars
system scrollbars, or "roll your own"
i prefer the later because you have more control over them
but, i suggest you start with system scroll bars

http://msdn.microsoft.com/en-us/library/windows/desktop/bb787529%28v=vs.85%29.aspx

as for the line-edit problem it has to do with overall design
can you imagine inserting a character at the beginning of a 1 Mb text file ?   :icon_eek:
well - i would handle it by creating line buffers, rather than a single full-text buffer
i haven't done much, in this respect - but Hutch wrote QuickEditor and may have some helpful hints   :t

also, there is Iczelion's tutorials - as you work through each chapter, you create a text editor

gelatine1

What exactly do you mean with the line buffers ? An array of buffers, one for each line of text ? How would I take care of all those ? I mean keeping their sizes and their starting positions ? Or just a fixed size ?

And what about the last error I told about ? I have been doing some research and I still don't see the reason it happens. The way it should go (as I think it should go with this code) is as follows:


  • InvalidateRect 'sends' a WM_PAINT message
  • in the WM_PAINT message BeginPaint is called and this sends an WM_ERASEBKGND message
  • nothing to process the WM_ERASEBKGND message so default DefWindowProc gets called

According to MSDN the DefWindowProc should do this:
QuoteIf an application does not process the message but passes it to DefWindowProc, the system erases the background by filling it with the pattern in the background brush specified by the window's class.

But clearly the letters who were there before the backspace was pressed are still there which means the screen didn't get erased and overwritten again.

Am I missing something ? What am I doing wrong ?

dedndave

sorry - forgot about that one   :biggrin:

show us the initialization code for your WNDCLASSEX structure used to register the window class
and, show us the CreateWindowEx line, also

gelatine1

I didn't actually use the WNDCLASSEX structure. Just 64 consecutive bytes which are in fact representing this WNDCLASSEX structure.


invoke GlobalAlloc,GHND,64
mov hmem,eax

invoke GlobalLock,hmem
mov pmem,eax

mov esi,[pmem]
mov dword ptr [esi],48
mov dword ptr [esi+4],CS_HREDRAW or CS_VREDRAW
mov dword ptr [esi+8],WndProc
mov ecx,1
mov dword ptr [esi+8*ecx+4],NULL
mov dword ptr [esi+8*ecx+8],NULL
inc ecx
mov eax,[hInst]
mov dword ptr [esi+8*ecx+4],eax
mov dword ptr [esi+8*ecx+8],NULL
inc ecx

push ecx
invoke LoadCursor,NULL,IDC_ARROW
pop ecx

mov dword ptr [esi+8*ecx+4],eax
mov dword ptr [esi+8*ecx+8],COLOR_WINDOW+1 ; The HBRUSH
inc ecx
mov dword ptr [esi+8*ecx+4],NULL
mov dword ptr[esi+8*ecx+8],offset ClassName
inc ecx
mov dword ptr [esi+8*ecx+4],NULL

invoke RegisterClassEx, esi
invoke GlobalUnlock,hmem
invoke GlobalFree,hmem


invoke CreateWindowEx, NULL, addr ClassName, addr AppName,  WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, NULL,NULL,hInstance,NULL
mov hwnd,eax

invoke ShowWindow,hwnd,SW_MAXIMIZE
invoke UpdateWindow,hwnd

qWord

Quote from: gelatine1 on June 26, 2014, 03:47:57 AMI didn't actually use the WNDCLASSEX structure. Just 64 consecutive bytes which are in fact representing this WNDCLASSEX structure.
that is utter nonsense - the same as using movable memory here.
Also, why using register scaling (8*ecx...) instead of displacements?
MREAL macros - when you need floating point arithmetic while assembling!

dedndave

yah - ECX = 1 is of little use

at any rate.....
get used to using the structures - you will see them often in Win32 programming

now - the WNDCLASSEX structure is 48 bytes in size
most other forum members prefer to place it in the uninitialized data section (.DATA?) or create it as a local
but, i prefer to place it initialized data (.DATA), and pre-initialize many of the structure members
there are a few reasons for this
1) it takes more bytes of code to initialize it than it does to store it
2) it may be re-usable, to register additional window classes
3) i use it to hold hInstance, rather than creating a seperate DWORD for that

here is a simple window to get you started - 3 main parts to a "standard" GUI window....
1) WndProc
2) RegisterClassEx and CreateWindowEx
3) message loop

you will notice that it's all set up with an INC file, RC file, icon, and a manifest
there is also a batch file that builds the project

dedndave

i've given the text storage problem a little thought

maybe you could create a buffer for the larger text file
then, a smaller one to buffer only the lines to be displayed and worked on

the other forum members have probably worked through this issue and found some elegant solution   :biggrin:

gelatine1

Quote from: dedndave on June 26, 2014, 05:40:23 AM
i've given the text storage problem a little thought

maybe you could create a buffer for the larger text file
then, a smaller one to buffer only the lines to be displayed and worked on

the other forum members have probably worked through this issue and found some elegant solution   :biggrin:

This seems a good idea to me  :t But I think I'll still have to do some ugly things when the user scrolls. But I'll try tomorrow I'm too sleepy now :)

And By the way I found the reason why my background did not get erased. It was because I used invoke InvalidateRect,hWnd,NULL,0 and this last parameter is supposed to do this:

QuoteSpecifies whether the background within the update region is to be erased when the update region is processed. If this parameter is TRUE, the background is erased when the BeginPaint function is called. If this parameter is FALSE, the background remains unchanged.

That's why it didn't work. I changed it to InvalidateRect,hWnd,NULL,1 now and everything works as expected :)

dedndave

 :t

when i have done text stuff, i used ExtTextOut, rather than DrawText
as i recall, it was a little faster