EditGutter mittels winapi32 implementieren - wie?

jkallup

Erfahrenes Mitglied
Hallo,

ich möchte gerne auf einem Edit-Control, das ich mit CreateWindowEx
erstellt habe einen Gutter auf der linken Seite zeichnen.
Das Zeichnen klappt soweit, leider jedoch nicht auf dem EDIT Window.
mit SendMessage EM_SETRECTNP kann ich bereits das linke margin setzen.
So kann ich also einen Rand setzen.
Wie aber zeichne ich dann auf diesen ein FillRect bzw. TextOut???

Für sachdienliche Hinweise danke ich schonmal.
 
Wow krass, es hat bis jetzt noch keiner geantwortet. o_O

Na dann tue ich das mal :):

Wenn ich dich richtig verstehe ist dein Problem, dass du in ein Child-Window zeichnen möchtest, aber das nicht funktioniert. Warum das nicht geht, erkläre ich jetzt nicht hier, aber wenn du mal nach "WinAPI" und "Window region" googelst findest du bestimmt Einiges dazu ;).

Im Prinzip läuft's darauf hinaus, dass du die "EDIT"-Fensterklasse von Windows als Vorlage benutzt und um deine eigene Funktion (die dann den/das Gutter zeichnet) erweiterst. Und so geht's:

Zuerst speichern wir (statisch) eine WNDPROC für die wir nachher die ursprüngliche Procedure einsetzen, und erstellen uns eine eigene Procedure die das Gutter zeichnet:
C++:
static WNDPROC pFnPrevFunc;
static LRESULT CALLBACK GutterProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    (*pFnPrevFunc)(hwnd, message, wParam, lParam);
    HDC hDC;
    RECT rc;
    switch(message)
    {
        case WM_PAINT:
            /* Sorry,
               ich weiß nicht wie ein "Gutter" aussieht -.-
               hab jetzt einfach mal ein Rechteck gezeichnet.
               */
            hDC = GetDC(hwnd);
            GetClientRect(hwnd, &rc);
            rc.right = 20;
            FillRect(hDC, &rc, (HBRUSH)GetStockObject(GRAY_BRUSH));
            ReleaseDC(hwnd, hDC);
            break;
        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
    }
    return 0;
}

In deinem Create-Case hast du ja schon das Fenster erstellt und den Stil angepasst, außerdem hast du bereits EM_SETRECT gesendet. Das heißt, dein Code sieht (stark vereinfacht) ungefähr so aus:
C++:
        // ZEUGS
        case WM_CREATE:
            hwndEdit = CreateWindowEx(0, "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL |
                                      ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 0, 0,
                                      hwnd, (HMENU)1, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
            SendMessage(hwndEdit, WM_SETFONT, (WPARAM)GetStockObject(ANSI_VAR_FONT), MAKELPARAM(0,TRUE));
            SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)"Hallo, ich bin ein Editfenster.");
            break;
        case WM_SIZE:
            MoveWindow(hwndEdit, LOWORD(lParam)/8, HIWORD(lParam)/8, LOWORD(lParam)/4, HIWORD(lParam)/4, TRUE); // Beispiel!
            SendMessage(hwndEdit, EM_GETRECT, (WPARAM)NULL, (LPARAM)(LPRECT)&rc);
            rc.left += 20; // wir lassen links 20 Pixel Platz
            SendMessage(hwndEdit, EM_SETRECT, (WPARAM)NULL, (LPARAM)(LPRECT)&rc);
            break;
        // NOCH MEHR ZEUGS

Alles was jetzt also noch zu tun bleibt, ist GutterProc an das Fenster zu binden. Wir erhalten dann:
C++:
        // VIELE VIELE ZEILEN
        case WM_CREATE:
            hwndEdit = CreateWindowEx(0, "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL |
                                      ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL, 0, 0, 0, 0,
                                      hwnd, (HMENU)1, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
            SendMessage(hwndEdit, WM_SETFONT, (WPARAM)GetStockObject(ANSI_VAR_FONT), MAKELPARAM(0,TRUE));
            SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM)"Hallo, ich bin ein Editfenster.");
            pFnPrevFunc = (WNDPROC)SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG_PTR)GutterProc); // ÄNDERUNG
            break;
        case WM_SIZE:
            MoveWindow(hwndEdit, LOWORD(lParam)/8, HIWORD(lParam)/8, LOWORD(lParam)/4, HIWORD(lParam)/4, TRUE);
            SendMessage(hwndEdit, EM_GETRECT, (WPARAM)NULL, (LPARAM)(LPRECT)&rc);
            rc.left += 20;
            SendMessage(hwndEdit, EM_SETRECT, (WPARAM)NULL, (LPARAM)(LPRECT)&rc);
            break;
        // UND NOCH VIEL MEHR ZEILEN

Wenn jetzt irgendwelche Messages an das Editfenster gesendet werden, fangen wir sie ab, führen die richtige Procedure aus und zeichnen dann den/das Gutter darüber (was wir jetzt dürfen, schließlich haben wir aus der Procedure heraus Zugriff auf die WindowRegion).

Das ist alles in Allem wesentlich performanter - und auch sauberer - als hier irgendwie mit Timern oder anderen Childwindows zu tricksen.

Hoffe ich konnte helfen :)
Gruß Technipion
 
Danke!!!

ich habs dann so gemacht:

Code:
    call   main
   ret

proc ErrorBox str
   invoke  sprintf,read_buffer,fmtError,[str],[lineno]
   invoke   MessageBox,[mainhwnd],read_buffer,_error_text,MB_OK
   ret
endp

proc main
  invoke  GetModuleHandle,0
  mov  [wc.hInstance],eax
  invoke  LoadIcon,eax,17
  mov  [wc.hIcon],eax
  invoke  LoadCursor,0,IDC_ARROW
  mov  [wc.hCursor],eax
  invoke  RegisterClass,wc
  test  eax,eax
  jz  error
  invoke  LoadMenu,[wc.hInstance],37
  invoke  CreateWindowEx,0,_class,_title,\
     WS_VISIBLE+WS_OVERLAPPEDWINDOW,\
     44,28,\
     CW_USEDEFAULT,CW_USEDEFAULT,\
     NULL,eax,[wc.hInstance],NULL
   mov   [mainhwnd],eax
  test  eax,eax
  jz  error
  msg_loop:
  invoke  GetMessage,msg,NULL,0,0
  cmp  eax,1
  jb  end_loop
  jne  msg_loop
  invoke  TranslateMessage,msg
  invoke  DispatchMessage,msg
  jmp  msg_loop
  error:
  invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
  end_loop:
  invoke  ExitProcess,[msg.wParam]
endp


proc RichEditWindowProc hwnd,msg,wparam,lparam
local   hdc dd ?

   cmp   [msg],WM_PAINT
   je   .wmpaint


   ;cmp   [msg],WM_LBUTTONDOWN
   ;je   .keydown

  .defwndproc:
   invoke  CallWindowProc,[oldWindowProc],[hwnd],[msg],[wparam],[lparam]
  jmp  .finish

  .wmpaint:
   invoke  CallWindowProc,[oldWindowProc],[hwnd],[msg],[wparam],[lparam]
   invoke   GetDC,[hwnd]
   mov   [hdc],eax

   invoke  SendMessage,[hwnd],EM_GETRECT,0,richEditRect
   mov   eax,[richEditRect.bottom]

   mov   [tmpRect.right],48
   mov   [tmpRect.left],0
   mov   [tmpRect.bottom],eax
   mov   [tmpRect.top], 0

   RGB   110,210,40
   mov   [color],eax
   invoke  CreateSolidBrush,[color]
   mov   [brushes],eax
   invoke   FillRect,[hdc],tmpRect,[brushes]

   push   [hdc]
   push   [hwnd]
   call   makeLineNumber

   mov   [tmpRect.bottom],20
   invoke  sprintf,line_bufferA,_numstring,1
   invoke   DrawText,[hdc],line_bufferA,3,tmpRect,DT_RIGHT

   invoke   ReleaseDC,[hdc]
   jmp   .finish

  .keydown:
   ;invoke  MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK
  .finish:
   ret
endp

proc CreateEditGutter hwnd
   invoke  LoadLibrary,_dllRich
  invoke  GetClientRect,[hwnd],client
   invoke   GetModuleHandle,0
   mov  [wc.hInstance],eax
   invoke  CreateWindowEx,WS_EX_WINDOWEDGE,_editRich,NULL,\
     WS_VISIBLE+WS_CHILD+WS_HSCROLL+WS_VSCROLL+\
     ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,\
     0,0,[client.right],[client.bottom],[hwnd],RichEditorID,[wc.hInstance],0
   mov   [edithwnd],eax
  cmp   eax,0
  jle  .failed

  invoke  CreateFont,16,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_RASTER_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH+FF_DONTCARE,NULL
  mov  [editfont],eax
  invoke  SendMessage,[edithwnd],WM_SETFONT,eax,FALSE
  invoke  SendMessage,[edithwnd],EM_SETMARGINS,EC_LEFTMARGIN,52

   RGB  55,200,155
   invoke   SendMessage,[edithwnd],EM_SETBKGNDCOLOR,0,eax

   invoke   SetWindowLong,[edithwnd],GWL_WNDPROC,RichEditWindowProc
   mov   [oldWindowProc],eax

   jmp   .finish
  .failed:
   invoke   MessageBox,[mainhwnd],_thread_error_text,_error_text,MB_OK
  .finish:
   ret
endp

proc SetColor hdc, txtcolor, bgcolor
   invoke  DeleteObject,[edit_brush]
   invoke  SetTextColor, [hdc], [txtcolor]
   invoke   SetBkColor, [hdc], [bgcolor]
   invoke   CreateSolidBrush, [bgcolor]
   mov   [edit_brush], eax
   ret
endp

proc getfileopen
   mov   ebx,openfilename
   cinvoke memset,ebx,0,88

   mov   dword [ebx],88
   mov   eax,[edithwnd]
   mov   [ebx+4],eax
   mov   dword [ebx+28],szFile
   mov  edx,[ebx+28]
   mov  byte [edx],0
   mov  dword [ebx+32],260
   mov  dword [ebx+12],filterstring
   mov  dword [ebx+24],1
   xor  ecx,ecx
   mov  [ebx+36],ecx
   xor  eax,eax
   mov  [ebx+40],eax
   xor  edx,edx
   mov  [ebx+44],edx
   mov  dword [ebx+52],6144
   invoke  GetOpenFileName,ebx
   mov   [openfilename],ebx

;--------------------

   invoke   GetDlgItem,[mainhwnd],RichEditorID
   mov   [edithwnd],eax
   cmp   eax,0
   je   .err

   xor   eax,eax
   mov   [se.codepage],CP_ACP
   mov   [se.flags],eax

   invoke   SendMessage,[edithwnd],WM_SETTEXT,0,0
   invoke  SendMessage,[edithwnd],EM_SETTEXTMODE,TM_PLAINTEXT,0
   invoke  SendMessage,[edithwnd],EM_SETTEXTEX,se,[openfilename.lpstrFile]

   jmp   .noerror
.err:
   invoke   MessageBox,[mainhwnd],_open_error,_error_text,MB_OK
   jmp   .finish
.noerror:
   ;--------------
   ; open file ...
   ;--------------
  invoke  CreateFile,[openfilename.lpstrFile],GENERIC_READ+GENERIC_WRITE,FILE_SHARE_READ+FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
  cmp  eax, INVALID_HANDLE_VALUE
  je  .errorOpenFile
   ;---------------------
   ; set on file list ...
   ;---------------------
  mov  [open_files.file_1], eax

   ;---------------------
   ; get size of file ...
   ;---------------------
   invoke   GetFileSize,eax,fileSize

   ;-------------------
   ; reserve memory ...
   ;-------------------
   invoke   VirtualAlloc,NULL,fileSize,MEM_COMMIT,PAGE_READWRITE
   mov   [sourceAlloc],eax
   cmp   eax,0
   je   .errorAlloc
   
  invoke  ReadFile,[open_files.file_1],[sourceAlloc],fileSize, nBytesRead, NULL
  cmp  eax, 0
  je  .errorReadFile
   invoke  SendMessage,[edithwnd],EM_SETTEXTEX,se,[sourceAlloc]
  invoke  CloseHandle,[open_files.file_1]
   cmp   eax,0
  je   .errorCloseFile

   jmp   .finish

.errorAlloc:
   invoke  MessageBox,[mainhwnd],_cant_alloc_memory,_error_text,MB_OK
   jmp  .finish
.errorReadFile:
   invoke  MessageBox,[mainhwnd],_cant_read_file,_error_text,MB_OK
   jmp  .finish
.errorOpenFile:
  invoke  MessageBox,[mainhwnd],_cant_open_file,_error_text,MB_OK
  jmp  .finish
.errorCloseFile:
  invoke  MessageBox,[mainhwnd],_cant_close_file,_error_text,MB_OK
  jmp  .finish

.finish:
   ret
endp



proc WindowProc hwnd,wmsg,wparam,lparam
  push  ebx esi edi
   cmp   [wmsg],WM_SIZE
   je   .wmsize
  cmp  [wmsg],WM_CREATE
   je   .wmcreate

  cmp  [wmsg],WM_COMMAND
  je  .wmcommand
  cmp  [wmsg],WM_DESTROY
  je  .wmdestroy
  .defwndproc:
  invoke  DefWindowProc,[hwnd],[wmsg],[wparam],[lparam]
  jmp  .finish


  .wmcreate:
   push   [hwnd]
   stdcall   CreateEditGutter

  jmp  .finish
  .wmsize:
  jmp  .finish
  .wmcommand:
  mov  eax,[wparam]
  and  eax,0FFFFh
  cmp  eax,IDM_NEW
  je  .new
  cmp  eax,IDM_ABOUT
  je  .about
  cmp  eax,IDM_EXIT
  je  .wmdestroy
   cmp  eax,IDM_OPEN
   je  .open
   cmp   eax,IDM_RUNAPP
   je   .runapp

   jmp  .defwndproc

;--------------
; open test.prg
;--------------
  .open:
   call   getfileopen
  jmp  .finish
  .runapp:
   call   saveandrun
   jmp   .finish

  .new:
  invoke  SendMessage,[edithwnd],WM_SETTEXT,0,0
  jmp  .finish
  .about:
  invoke  MessageBox,[hwnd],_about_text,_about_title,MB_OK
  jmp  .finish


  .wmdestroy:
   call   FreeProgramMemory
  invoke  PostQuitMessage,0
  xor  eax,eax
  .finish:
  pop  edi esi ebx
  ret
endp

proc makeLineNumber hwnd, hdc
local   oldLine dd ?


;   invoke   RedrawWindow,[hwnd],tmpRect,NULL,RDW_ALLCHILDREN+RDW_INTERNALPAINT

   invoke  SendMessage,[hwnd],EM_GETRECT,0,richEditRect
   mov   eax,[richEditRect.bottom]
   sub   eax,[richEditRect.top]
   mov   [iRectHeight], eax

   invoke   GetTextMetrics,[hdc],tm
   mov   eax,[iRectHeight]
   cdq
   idiv   dword [tm.tmHeight]
   mov   [iMaxNumberOfLines],eax


   invoke    SendMessage,[hwnd],EM_GETFIRSTVISIBLELINE,0,0
   mov   [iFirstVisibleLine],eax

;   invoke sprintf,read_buffer,_numstring,eax
;   invoke  MessageBox,[hwnd],read_buffer,_about_title,MB_OK

   mov   [iLineChar],0
   mov   [iLineNumber],0

   mov   [counter],0
   mov   [oldLine],1
   mov   eax,1
   push   eax
.nextline:
   mov   edi,[counter]
   cmp   edi,[iMaxNumberOfLines]
   je   .finish
   
   add   edi,[iFirstVisibleLine]
   push   edi
   invoke   SendMessage,[hwnd],EM_LINEINDEX,edi,0
   mov   [iLineChar],eax

   invoke   SendMessage,[hwnd],EM_LINEFROMCHAR,[iLineChar],0
   mov   [iLineNumber],eax
   cmp   [iLineNumber],-1
   je   .finish

   mov   eax,[iLineNumber]
   add   eax,1
   mov   [iLineNumber],eax

   invoke  sprintf,read_buffer,_numstring,[iLineNumber]
   invoke  SendMessage,[hwnd],EM_POSFROMCHAR,pl,[iLineChar]

   mov   [tmpRect.right],48
   mov   [tmpRect.left],0
   mov   eax,[richEditRect.bottom]
   mov   [tmpRect.bottom],eax
   mov   eax,[pl.y]

   mov   [tmpRect.top], eax
   invoke   DrawText,[hdc],read_buffer,3,tmpRect,DT_RIGHT


   mov   edi,[counter]
   add   edi,1
   mov   [counter],edi

.fini:

   jmp   .nextline
.finish:
   ret
endp

proc FreeProgramMemory
   invoke   VirtualFree,sourceAlloc,fileSize,MEM_COMMIT+MEM_RELEASE
   ret
endp

proc saveandrun
   invoke   SendMessage,[edithwnd],EM_SETSEL,0,-1
   invoke   SendMessage,[edithwnd],EM_EXGETSEL,0,dword cr
   invoke   VirtualFree,sourceAlloc,fileSize,MEM_COMMIT+MEM_RELEASE

   mov   eax,[cr.cpMax]
   mov   [fileSize],eax

   invoke   VirtualAlloc,NULL,fileSize,MEM_COMMIT,PAGE_READWRITE
   mov   [sourceAlloc],eax
   cmp   eax,0
   je   .errorAlloc

   invoke   SendMessage,[edithwnd],EM_GETSELTEXT,0,[sourceAlloc]
   invoke  MessageBox,[mainhwnd],[sourceAlloc],_about_title,MB_OK

   mov   edi, 0
   call   CallParser
   jmp   .finish

.errorAlloc:
   invoke  MessageBox,[mainhwnd],_cant_alloc_memory,_error_text,MB_OK
.finish:
   ret
endp

proc getchar
   mov   eax,[sourceAlloc]
   movsx   eax,byte [eax+edi]   ; add index + edi
   ret
endp

proc skip_white_space
   mov   edi,0     ; inital index = 0; first character
   push   edi
   jmp   .skiploop
.nextchar:
   pop   edi     ; restore counte, if change edi by some
   add   edi,1     ; function call.
   push   edi     ; save it ...
.skiploop:

   call   getchar
   cmp   eax,0     ; EOF ?
   je   .finish
   cmp   eax,9     ; tab
   je   .nextchar
   cmp   eax,0x0d   ; new line
   je   .isnewline
   cmp   eax,32     ; space
   je   .nextchar
   cmp   eax,'/'
   je   .checkifcomment

   jmp   .nextchar

.eatcommentline:
   pop   edi
   add   edi,1
   push   edi

   call   getchar
   cmp   eax,0
   je   .finish
   cmp   eax,0x0d
   je   .isnewline   ; \n

   jmp   .eatcommentline

.isnewline:
;   call   getchar    ; Windows CRLF
   mov   ebx,[lineno]
   add   ebx,1
   mov   [lineno],ebx
   jmp   .nextchar

.checkifcomment:
   pop   edi
   add   edi,1
   push   edi

   call   getchar
   cmp   eax,'/'    ; c++ comment
   je   .eatcommentline

.unterminated:
   mov   eax,_comment_unterminated
   jmp   .error
.error:
   stdcall   ErrorBox,eax

.finish:
   pop   edi
   ret
endp

proc CallParser
   ;invoke   SetFilePointer,[open_files.file_1],0,NULL,FILE_BEGIN
   mov   [incomment],0
   mov   [lineno],1
   call   skip_white_space
   ret
endp
 

Neue Beiträge

Zurück