![]() |
Stringlänge parsen
Wie kann ich am schnellsten die länge von Strings parsen
so das ich dann den längsten verwenden kann um mein Window in der Weite dementsprechend anzupassen. Ja ich weis Length(string) aber ich suche eine schnelle Methode ;) Habe mein Grund Menu soweit fertig.. und ich benötige die Berechnung um die Sub Menus (weite) auf den längsten String hin anzupassen. Anbei ein shot.! 1 ganzer Tag nur für das Grundmenu. LOL gruss |
AW: Stringlänge parsen
Length(string)
|
AW: Stringlänge parsen
Du suchst doch nicht die Länge des Strings sondern den benötigten Platz zur Darstellung des Strings auf einem Canvas, oder?
Dazu nimmt man ![]() |
AW: Stringlänge parsen
![]() Wenn Canvas oder HDC schon vorhanden sind, dann natürlich das direkt verwenden. Zitat:
Man kann noch über Pointer schneller sein, wenn der String nie leer ist, indem man diese Prüfung überpringt. :stupid: |
AW: Stringlänge parsen
Zitat:
verwenden um mein Sub Menu auf die weite auszurichten. DT_CALCRECT hilft mir nicht ist aber auch nicht wichtig da ich es mit meiner Funktion GDIP_GetTextBound nachher in Pixeln exakt ermittle wenn ich den längsten string habe. Zitat:
gruss |
AW: Stringlänge parsen
Zitat:
Delphi-Quellcode:
function getTextWidth(aForm: TForm; const aString: string): Integer;
begin if aString <> '' then Result := aForm.Canvas.TextWidth(aString) else Result := 0; end; |
AW: Stringlänge parsen
Zitat:
Verschiedene Zeichen sind ja unterschiedlich breit. Zitat:
// EDIT: Die beim Zeichnen längste Zeile wirst du wohl am einfachsten bekommen, wenn du alle Strings in mehreren Zeilen nimmst und gesammelt an die Funktion zur Größenermittlung gibst. Das ist vermutlich nicht besonders schnell, aber zuverlässig und schneller als jeden Text einzeln anzufragen. |
AW: Stringlänge parsen
Zitat:
Da ich den Text mit GDI+ zeichne und ein mix mit der Winapi ist da nicht das wahre. Denke werde es dann wohl doch mit Length(string) in einer schleife machen müssen. Zitat:
Ich mache es hier mit aber erst dann wenn ich den längsten String ermittelt habe. (einmalig..)
Delphi-Quellcode:
gruss
function GetTextBound(UseText: WideString; UseFont: WideString; UseSize: single; var bW: integer;
var bH: integer; UseStrFormat: integer): GPSTATUS; stdcall; var Graphics: cardinal; Fam: GpFontFamily; TempFont: GpFont; DC: HDC; begin result := GenericError; strFormat := nil; Fam := nil; // Create matching font try GdipCheck(GdipCreateFontFamilyFromName(UseFont, nil, Fam)); if Assigned(Fam) then begin GdipCheck(GdipCreateFont(Fam, UseSize, 0, 2, TempFont)); if Assigned(TempFont) then begin DC := GetDC(GetDesktopWindow); GdipCheck(GdipCreateStringFormat(0, 0, strFormat)); GdipCheck(GdipCreateFromHDC(DC, Graphics)); GdipCheck(GdipMeasureString(Graphics, PWideChar(UseText), length(UseText), TempFont, @layoutRect, strFormat, @boundingBox, nil, nil)); if Assigned(strFormat) then GdipCheck(GdipDeleteStringFormat(strFormat)); bW := round(boundingBox.Width - boundingBox.X); bH := round(boundingBox.Height - boundingBox.Y); if UseStrFormat <> 0 then Swap(bW, bH); ReleaseDc(GetDesktopWindow, DC); end; end; finally if Graphics <> 0 then GdipCheck(GdipDeleteGraphics(Graphics)); if Assigned(TempFont) then GdipCheck(GdipDeleteFont(TempFont)); // Lösche das Font Object if Assigned(Fam) then GdipCheck(GdipDeleteFontFamily(Fam)); // Lösche das Font Family Object end; end; |
AW: Stringlänge parsen
Zitat:
Delphi-Quellcode:
Schneller wirds nicht.
test eax, eax
jz +$03 mov eax, [eax-$04] ret Außerdem in extremen Fällen können kürzere Strings (Anzahl der Zeichen) länger (in Pixeln) sein als andere längere Strings (Anzahl der Zeichen) (<-- Verwirrender Satz aber ich hoffe du weißt was ich meine :mrgreen: ) z.B. WWWW (Length = 4) iiiiiiiiiiii (Length = 12) |
AW: Stringlänge parsen
Zitat:
Zitat:
Meine oben genannte Funktion gibt die Länge eines Strings in Pixeln zurück. Mit QuickSort kannst du dann sehr einfach den längsten String raussuchen. |
AW: Stringlänge parsen
Zitat:
gruss |
AW: Stringlänge parsen
Zitat:
Zitat:
|
AW: Stringlänge parsen
Zitat:
mit meiner Funktion bekomme ich die exakte länge über boundingBox noch genauer geht's nicht. Wenn es nicht mit einmalig geht dann muss ich wohl oder übel alle Strings da durchlaufen lassen. Danke. PS: Mit DPI ist kein Problem da habe ich auch eine Funktion die ich schon in meinem C++ Example verwende. Spielt aber keine rolle es passiert gar nichts solange wie ich DPI Aware nicht zulasse. Denn dann wird auch nichts vergrößert. gruss |
AW: Stringlänge parsen
Zitat:
|
AW: Stringlänge parsen
Zitat:
Und ich arbeite mit der Win32API.. aber ich mixe nicht den Font der in GDI+ erstellt wurde mit dem von der Winapi.. denn das sind 2 paar Schuhe. Trotzdem Danke. gruss |
AW: Stringlänge parsen
Liste der Anhänge anzeigen (Anzahl: 1)
Macht WINDOWS das nicht automatisch?
|
AW: Stringlänge parsen
Zitat:
Auch kein Ownerdraw. gruss |
AW: Stringlänge parsen
Zitat:
Weil so kompiliert es zumindest in höheren Versionen (Berlin, Tokyo) nicht. Ggf. unterscheidet sich der dort mitgelieferte übersetzte Header Winapi.GDIAPI.pas (von ![]() Ist die selbstgemacht oder irgendwoher kopiert? Außerdem sind da einige Fehler drin, die ein funktionieren unmöglich gemacht haben. Hier eine entsprechende korrigierte Version:
Delphi-Quellcode:
function GetTextBound(UseText: WideString; UseFont: WideString; UseSize: single; var bW: integer;
var bH: integer; UseStrFormat: integer): GPSTATUS; stdcall; var Graphics: GPGRAPHICS; // Tigü: Hier war ein falscher Typ (Cardinal) Fam: GpFontFamily; TempFont: GpFont; DC: HDC; strFormat: GPSTRINGFORMAT; // Tigü: war nicht definiert boundingBox, layoutRect: TGPRectF; // Tigü: war nicht definiert begin Result := GPSTATUS.GenericError; // Tigü: Result ist immer GenericError?? Wird nirgens auf GPStatus.ok gesetzt strFormat := nil; Fam := nil; TempFont := nil; // Tigü: war nicht initialisiert! // Create matching font try GdipCheck(GdipCreateFontFamilyFromName(PWideChar(UseFont), nil, Fam)); // Tigü: PWideChar fehlte if Assigned(Fam) then begin GdipCheck(GdipCreateFont(Fam, UseSize, 0, 2, TempFont)); if Assigned(TempFont) then begin DC := GetDC(GetDesktopWindow); GdipCheck(GdipCreateStringFormat(0, 0, strFormat)); GdipCheck(GdipCreateFromHDC(DC, Graphics)); FillChar(boundingBox, SizeOf(boundingBox), 0); // Tigü: waren nicht initialisiert, Werte waren "unendlich" klein oder groß FillChar(layoutRect, SizeOf(layoutRect), 0); // Tigü: waren nicht initialisiert, Werte waren "unendlich" klein oder groß // GdipCheck(GdipMeasureString(Graphics, PWideChar(UseText), Length(UseText), TempFont, @layoutRect, strFormat, @boundingBox, nil, nil)); if Assigned(strFormat) then GdipCheck(GdipDeleteStringFormat(strFormat)); bW := round(boundingBox.Width - boundingBox.x); bH := round(boundingBox.Height - boundingBox.y); if UseStrFormat <> 0 then Swap(bW, bH); if (bW <> 0) or (bH <> 0) then Result := GPSTATUS.Ok; // Tigü: Wenns klappt, sollte das so auch per Result mitgeteilt werden!! ReleaseDc(GetDesktopWindow, DC); end; end; finally if Assigned(Graphics) then // Tigü: entsprechend des neuen Typs anpassen GdipCheck(GdipDeleteGraphics(Graphics)); if Assigned(TempFont) then GdipCheck(GdipDeleteFont(TempFont)); // Lösche das Font Object if Assigned(Fam) then GdipCheck(GdipDeleteFontFamily(Fam)); // Lösche das Font Family Object end; end; |
AW: Stringlänge parsen
Zitat:
Suche dir dafür in Zukunft jemand anderen... und ja es funktioniert auch ohne deine Verschlimmbesserungen. Nur mal so zum Mitschreiben..
Delphi-Quellcode:
Quatsch!
Result := GPSTATUS.Ok; // Tigü: Wenns klappt, sollte das so auch per Result mitgeteilt werden!!
GdipCheck liefert die Rückgabe..
Delphi-Quellcode:
Was für ein PWideChar?
function GdipCreateFontFamilyFromName(
name: WideString; fontCollection: Pointer; out FontFamily: GpFontFamily ): GPSTATUS; stdcall; external LibGdiPlus; und so könnte ich weiter machen... aber lassen wir das. gruss |
AW: Stringlänge parsen
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Sind wir heute wieder besonderes dünnhäutig? Anbei noch ein Screenshot des Line Timer von der Nexus Quality Suite ( ![]() Die Funktion habe ich 100 mal aufgerufen und in der linken Spalte siehst du die Zeiten in Millisekunden. Alles größer 0,5 habe ich mal farblich markiert. Du könntest also am meisten Zeit sparen, wenn du - insofern die Schrifteinstellungen für alle Einträge im Menü gleich sind - Das Erstellen der FontFamily, der GDIPlus-Font und das Graphics-Objekt nur einmalig machst und dann über deine Strings iterierst und dir entsprechend die Objekte übergibst.
Delphi-Quellcode:
//Pseudocode:
GdipCheck(GdipCreateFontFamilyFromName(PWideChar(UseFont), nil, Fam)); // PWideChar if Assigned(Fam) then begin GdipCheck(GdipCreateFont(Fam, UseSize, 0, 2, TempFont)); if Assigned(TempFont) then begin DC := GetDC(GetDesktopWindow); GdipCheck(GdipCreateStringFormat(0, 0, strFormat)); GdipCheck(GdipCreateFromHDC(DC, Graphics)); DoFindLongestStringWidth(strFormat, TempFont, Graphics, UseTexts {hier natürlich dann eine Liste oder Array mit den Strings übergeben}, bW, bH, UseStrFormat); ReleaseDc(GetDesktopWindow, DC); ... |
AW: Stringlänge parsen
Zitat:
Zitat:
Ach was soll's gruss |
AW: Stringlänge parsen
Zitat:
Immer diese Unart, die Beiträge nachträglich zu editieren und neues Zeug rein zuschreiben, anstatt einen neuen Beitrag zu erstellen. Kannst du dir das nicht mal abgewöhnen? :roll: Die von dir genannte Funktion ist bspw. bei mir so definiert:
Delphi-Quellcode:
Daher meine Frage, woher deine GDIPlus-Übersetzung stammt.
//----------------------------------------------------------------------------
// FontFamily APIs //---------------------------------------------------------------------------- function GdipCreateFontFamilyFromName(name: PWCHAR; fontCollection: GPFONTCOLLECTION; out FontFamily: GPFONTFAMILY): GPSTATUS; stdcall; {$EXTERNALSYM GdipCreateFontFamilyFromName} Wenn du willst, kann ich dir ja mal meine Pascal-Unit zukommen lassen. |
AW: Stringlänge parsen
Ich habe diese Funktion editiert da sie mit PWCHAR nicht mit meinem Wrapper kompatible ist.
Und nein es gibt keine Problem sonst hätte mir GdipCheck das schon gemeldet. Ich verwende nix von progdigy sondern habe meine eigene Unit erstellt auf der Basis von Win32Api. Delphi hat die Eigenschaft alles unnötig aufzubauschen. Sieht man ja an den Kompilaten ;) mag ja sein das ich ein zwei Sachen nicht initialisiert habe.. meine Regel ist solange der Compiler nicht meckert kompiliert und alles rund läuft sollte das schon gut sein. gruss |
AW: Stringlänge parsen
Ach so das noch ;)
Neue Post! 8-)
Delphi-Quellcode:
war definiert nur nicht in der Funktion daher muss hier auch nix auf NIL gesetzt werden da GLOBAL!
strFormat: GPSTRINGFORMAT; // Tigü: war nicht definiert
boundingBox, layoutRect: TGPRectF; // Tigü: war nicht definiert
Delphi-Quellcode:
Das kannst du natürlich nicht sehen.
var
strFormat: GPSTRINGFORMAT; boundingBox: TGPRectF; layoutRect: TGPRectF; rcLayout: TGPRectF; brush: Pointer; EDIT:
Delphi-Quellcode:
Graphics: GPGRAPHICS; // Tigü: Hier war ein falscher Typ (Cardinal)
Der Typ ist nicht falsch wenn er das wäre würde mein ganzer Quelltext nicht funktionieren. Das ist eine Auslegungs Sache wie ich Graphics definiere. IN VB ist es Long, in PowerBasik ist es DWORD und bei mir ist es Cardinal (DWORD) wenn du so willst. gruss |
AW: Stringlänge parsen
Zitat:
Schau mal hier, wie die Jungs vom Wine-Projekt das gelöst haben: ![]() Du bist ja nun inzwischen etwas sattelfester in C/C++. Was für ein Typ hat das erste Argument? Zitat:
Kann es sein, dass bei dir strFormat, boundingBox und layoutRect globale Variablen sind? :twisted: Die fehlen schlicht und ergreifend in der Funktion und deswegen kann es nicht kompilieren. Wenn ich das nun einfüge und die beiden Rechtecke nicht per FillChar (oder ZeroMemory) initialisiere, haben die zufällige Werte und werden von GdipMeasureString nicht richtig ausgefüllt bzw. falsch übernommen. Das knallt dann spätestens beim berechnen von bH oder bW, weil Round einen "invalid floting point operation"-Fehler wirft. |
AW: Stringlänge parsen
Zitat:
Delphi-Quellcode:
Das ist OK! Habe es addiert.
FillChar(boundingBox, SizeOf(boundingBox), 0);
FillChar(layoutRect, SizeOf(layoutRect), 0); Danke. gruss |
AW: Stringlänge parsen
Zitat:
Das funktioniert wunderbar für 32-Bit bis ans Ende aller Tage. Aber unter 64-Bit wirst du schnell merkwürdige Fehler (höchstwahrscheinlich) bekommen (können). Die GDIPLUS-DLL wird dir 64-Bit Zeiger geben (Länge 8 Byte) und du wirst hart auf 32-Bit Länge casten und damit die Adresse abschneiden. Das führt unweigerlich zu merkwürdigen Fehlern und Zugriffsverletzungen. Das gilt auch für alle anderen Typen wie bpsw. Brush, Texture, Gradienten, Pen, Image, Bitmap, StringFormat, FontFamily etc. pp. |
AW: Stringlänge parsen
Hier mal ein Beispiel was falsche, nicht mitwachsende Typen für Ärger sorgen können:
![]() |
AW: Stringlänge parsen
Das ist korrekt was du sagst deshalb verwende ich für 64Bit ja auch die "normale" GDIPlus vom
![]() Ich weis das Graphics, Image und einige andere variablen Pointer sind. Bei mir sind diese fast alle Cardinal und glaube mir in 32Bit gibt es keine Probleme. Ich hatte einfach keine Lust 5 Units für 3 API Funktionen in meine LIB einzubinden die machen alleine schon 1MB aus. gruss |
AW: Stringlänge parsen
Nun ja wirklich weiter bin ich noch nicht muss mich mal schlau machen was Glados mit QuickSort meint.
Kenn mich damit nicht aus. gruss |
AW: Stringlänge parsen
Zitat:
Da muss man auch nichts sortieren. PseudoCode:
Delphi-Quellcode:
function GetTextWidth(MyStrings: TStrings {ja, nur ein Beispiel, kannst auch Array nehmen}): Integer;
var Result, NewWidth: Integer; MyString: string; begin Result := 0; NewWidth := 0; for MyString in MyStrings do begin NewWidth := GetTextBoundOnlyWidth(MyString); // Platzhalterfunktion zum Ermitteln der Breite des Strings if NewWidth > Result then // Immer wenn die Breite größer ist von diesen String, dann Result entsprechen erhöhen Result := NewWidth; end; end; |
AW: Stringlänge parsen
Zitat:
Was anderes macht dein Code auch nicht! Ob nun dein Vorschlag oder meiner: das Ergebnis ist am Ende dasselbe je nachdem wie man es auswertet. |
AW: Stringlänge parsen
Zitat:
Danach noch zu sortieren ist Unsinn weil man sich in der Schleife auch grad immer merken kann ob das aktuelle Element das (bisher) größte ist:
Delphi-Quellcode:
if NewWidth > Result then // Immer wenn die Breite größer ist von diesen String, dann Result entsprechen erhöhen
Result := NewWidth; |
AW: Stringlänge parsen
Zitat:
TStrings sind ok.. gruss |
AW: Stringlänge parsen
Zitat:
Zitat:
|
AW: Stringlänge parsen
Zitat:
:roll: :wall: :roll: |
AW: Stringlänge parsen
Ich bin wahrscheinlich schon OffTopic weil ich das Problem falsch verstehe,
oder dieser Vorschlag steht hier schonmal irgendwo im Thread: Aber du könntest die Strings einmalig beim Erzeugen parsen und die Längen und was auch immer separat verwalten, z.B. als Liste oder Array, o.ä. Damit könntest du die Länge relativ schnell über das Array finden. Mal so hingeschrieben, ohne Test und Sicherheitsabfragen.
Delphi-Quellcode:
Dazu müsste aber das Array immer mit der Stringliste synchron laufen, ein Insert, Delete, etc. wenn du das gewährleisten kannst.
intMax := SucheMaxLänge(intStart, intAnzahl);
function SucheMaxLänge(intStart, intAnzahl) : Integer; begin Result := 0; while intAnzahl > 0 do begin if FLenArray[intStart+IntAnzahl] > Result then Result := FLenArray[intStart+IntAnzahl]; Dec(intAnzahl); end; end; Rollo |
AW: Stringlänge parsen
Theoretisch ist das machbar praktisch leider nicht weil sich die Menüs immer ändern dynamisch.
Irgendwelche Strings im Speicher halten würde also nicht viel bringen. Bei jeden neuen Film sieht das anders aus. gruss |
AW: Stringlänge parsen
Nur die Längen im Speicher halten ...
|
AW: Stringlänge parsen
Hallo,
gibt es hier überhaupt ein Performance-Problem, oder ist es eine theoretische Diskussion? "Minimal-Bsp." bitte, was das Problem zeigt. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:10 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz