GetStringMetricsOnDC()

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

GetStringMetricsOnDC()

Beitrag von Kekskiller »

Erklärung:
Gibt die Größe und Breite eines Strings mit vorher festgelegten Font (DrawingFont()) in Pixeln auf einem DC zurück (StartDrawing()). Verarbeitet Zeilenumbrüche in den Formen Chr(13)+Chr(10) und Chr(13).

Parameter:
hdc.l = Device Context mit Font-Infos
*stringAD = Adresse der Null-terminierten Strings, deren Größe ermittelt werden soll
*metrics.SIZE = Adresse der SIZE-Variable, in welcher die Stringröße gespeichert werden soll
[optional] *string_memory = Adresse des Speichers, wo alle gefilterten Zeilen des Strings abgelegt werden
[optional] memsize.l = Größe des String-Ablage-Speichers

Rückgabewert
Die Funktion gibt die Anzahl der Zeilen im zu berechnenden String zurück.

Die Stringablage ist dazu da, alle Zeilen in einer Auslese-freundlichen Form dem Benutzer zu übergeben. Alle Zeilen sind als mit PeekS() leicht lesbaren Strings abgespeichert. In Kombination mit den Pixelgrößen und der per GetTextMetrics_() ermittelten Zeilenhöhe kann so der Text unkompliziert mehrzeilig auf dem Bildschirm ausgegeben werden

Die Größe der String-Ablage kann ganz einfach errechnet werden.
Bei durchgängig 2-Zeichen-Zeilenumbruch:

Code: Alles auswählen

Größe = Textlänge - Zeilen
Bei durchgängig 1-Zeichen-Zeilenumbruch:

Code: Alles auswählen

Größe = Textlänge + 1

Code: Alles auswählen

Procedure GetStringMetricsOnDC(hdc.l, *stringAD, *metrics.SIZE, *string_memory=-1, memsize.l=0);optionaler parameter: die gefilterten strings in einem speicher ablegen
  Protected checkstring$, checkstring_len.l, c.c, chars_in_string.l, next_char.c, mempos.l
  Protected longest_string$, longest_len.l, string_found.b
  Protected new_string$, new_len.l, new_metrics.SIZE, breaks_found.l
  Protected *proofAD, *stringstartAD
  
  ;berechnung des benötigten speichers:
  ;anzahl zeichen + zeilenumbrüche * 3 (für return, line feed und für jeden string die 0-terminierung) 
  
  If hdc <> 0 And *stringAD <> 0 And *metrics <> 0
    
    ;/kram zurücksetzen
    longest_len = -1
    longest_string$ = ""
    *proofAD = *stringAD
    *stringstartAD = *proofAD
    mempos = 0
    
    ;/string nach längstem string durchsuchen
    Repeat
      ;char einlesen
      c = PeekC(*proofAD)
      Debug "c=" + Str(c)
      ;/zeilenende ("return") gefunden
      If c = 13; return entdeckt
        ;string extrahieren (wir haben die startposition vorher zwischengespeichert)
        new_string$ = PeekS(*stringstartAD, chars_in_string)
        new_len = chars_in_string
        GetTextExtentPoint32_(hdc, @new_string$, new_len, @new_metrics);metrics holen
        
        ;/string zwischenspeichern
        If *string_memory <> -1
          Debug "memory overflow: " + Str(mempos + new_len)
          If mempos + new_len <= memsize ;wenn der string den speicher nicht überschreitet
            Debug "stored a string @ " + Str(*stringstartAD)
            CopyMemory(*stringstartAD, *string_memory + mempos, new_len)
            mempos + new_len + 1
          EndIf
        EndIf
        
        ;/vergleichen
        ;prüfen, ob länge höher als die bisherige, größste länge
        If new_metrics\cx > *metrics\cx
          Debug "#RECORD!!!"
          longest_string$ = new_string$
          longest_len = new_len
          *metrics\cx = new_metrics\cx
          *metrics\cy = new_metrics\cy
        EndIf
        
        breaks_found + 1
        string_found = #True;"string gefunden" setzen
        
        Debug "new_string$=" + new_string$
        Debug "new_len=" + Str(new_len)
        Debug "new_metrics\cx=" + Str(new_metrics\cx)
        Debug "new_metrics\cy=" + Str(new_metrics\cy)
        
        ;-nächstes zeichen analysieren
        next_char = PeekC(*proofAD+1)
        If next_char = 10;wenn ein line fedd mit angehängt wurde, müssen wir dieses mit in die neue strinposition einrechnen
          Debug "line feed (10), next line"
          *proofAD = *stringstartAD + chars_in_string + 2;adresse auf nächsten string setzen
          *stringstartAD = *proofAD;start des strings setzen
          
        ElseIf next_char = 0;stringende entdeckt, vorgang abbrechen
          Debug "string end"
          Break
          
        Else;kein linefeed, normal weitergehen im string
          Debug "no line feed (!= 10), next line"
          *proofAD = *stringstartAD + chars_in_string + 1;adresse auf nächsten string setzen
          *stringstartAD = *proofAD ;start des strings setzen
        EndIf
        
        ;chars im string zurücksetzen
        chars_in_string = 0
      
      ;/STRING-ENDE
      ElseIf c = 0;stringende entdeckt, vorgang abbrechen
        ;letzter string ohne return/linefeed
        new_string$ = PeekS(*stringstartAD, chars_in_string+1)
        new_len = chars_in_string
        GetTextExtentPoint32_(hdc, @new_string$, new_len, @new_metrics);metrics holen
        
        ;/string zwischenspeichern
        If *string_memory <> -1
          Debug "memory overflow: " + Str(mempos + new_len)
          If mempos + new_len <= memsize ;wenn der string den speicher nicht überschreitet
            Debug "stored a string @ " + Str(*stringstartAD)
            CopyMemory(*stringstartAD, *string_memory + mempos, new_len)
            PokeC(*string_memory + mempos + new_len + 1, 0);<-string-ende poken
          EndIf
        EndIf
        
        ;/string zwischenspeichern
        ;prüfen, ob länge höher als die bisherige, größste länge
        If new_metrics\cx > *metrics\cx
          longest_string$ = new_string$
          longest_len = new_len
          *metrics\cx = new_metrics\cx
          *metrics\cy = new_metrics\cy
        EndIf
        
        Debug "new_string$=" + new_string$
        Debug "new_len=" + Str(new_len)
        
        chars_in_string = 0
        string_found = #True;"string gefunden" setzen
        Break
      Else
        chars_in_string + 1
        *proofAD + 1
      EndIf
      Debug "----------------------"
    ForEver
    
    ;/string zurückgeben
    If string_found = #True
      ;wir müssen nur noch die metrics in den vom benutzer angegebenen pointer kopieren und die höhe multiplizieren
      *metrics\cy * (breaks_found+1);+1 wegen z.b. der einzelnen zeile die auch ohne umbruch da sein muss (sonst wäre höhe=0)
      ProcedureReturn breaks_found + 1
    Else
      *metrics\cx = 0
      *metrics\cy = 0
      ProcedureReturn 0
    EndIf
  Else
    *metrics\cx = 0
    *metrics\cy = 0
    ProcedureReturn 0
  EndIf
EndProcedure
Hat bisher allen meinen Test standgehalten, würde gerne wissen, ob bei euch Fehler auftreten und wenn ja, welche?