Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   EllipsisCharacter funktioniert nicht (https://www.delphipraxis.net/191732-ellipsischaracter-funktioniert-nicht.html)

EWeiss 14. Feb 2017 21:10


EllipsisCharacter funktioniert nicht
 
Mein Code

Delphi-Quellcode:
      else if UseStrFormat = StringFormatFlagsNoWrap then
      begin
        if GdipCreateStringFormat(0, 0, strFormat) = OK then
        begin
          GdipSetStringFormatFlags(strFormat, UseStrFormat);
          GdipSetStringFormatLineAlign(strFormat, StringAlignmentFar);
          GdipSetStringFormatTrimming(strFormat, StringTrimmingEllipsisCharacter);
        end;
        GdipDrawString(Graphics, sTxt, length(sTxt), curFont, @rcLayout, strFormat, brush)
      end
Wenn ich nun die Column in meiner Anwendung verschiebe so das sie über den zu langen Text steht
sollte dieser eigentlich abgeschnitten werden und Ellipsis (...) addiert werden.
Nur leider funktioniert das nicht, keine Ahnung warum.

am Code kann es nicht liegen es sei denn ich habe noch etwas vergessen.

EDIT:
Es geht grundsätzlich schon aber nur von Hand also eigener Code
was mir da nur nicht gefällt sind die unterschiedlichen Abstände da ich die einzelnen Chars in der Weite nicht gegenprüfe.
Das ist der Grund warum ich diese API verwenden möchte.

gruss

hoika 15. Feb 2017 04:23

AW: EllipsisCharacter funktioniert nicht
 
Hallo,
was ist denn das für eine Komponente,
die das property Column besitzt?

EWeiss 15. Feb 2017 16:07

AW: EllipsisCharacter funktioniert nicht
 
Zitat:

Zitat von hoika (Beitrag 1361603)
Hallo,
was ist denn das für eine Komponente,
die das property Column besitzt?

Sehe nicht das da irgendwas von property steht nur was von ListView.
Damit aber die blinden hier das auch verstehen..

Wenn ich die Spaltenbreite in der Anwendung verändere.. bla, bla.
Aber schlauer bist du deshalb auch nicht so das du helfen könntest oder?

gruss

EWeiss 18. Feb 2017 19:14

AW: EllipsisCharacter funktioniert nicht
 
Thema hat sich erledigt funktioniert nun.
Es war nicht die API selbst sondern die Zuweisung eines nicht Korrekten Rect.

Delphi-Quellcode:
procedure TSkinListView.DrawEllipsisText(DC: HDC; UseText: WideString; rec: TRect;
  ColrARGB: COLORREF; UseFont: WideString; UseSize: single; FontStyle: TFontStyle;
  ShadowOffset: single; UseStrFormat: integer; WordWrap: Bool = False);
var
  Width: Integer;
  Fam: GpFontFamily;
  TempFont: GpFont;
  Graphics: Cardinal;
  rectF: TGPRectF;
  Rect, rc, rc2: Trect;
  strFormat: Pointer;
begin

  Graphics := 0;
  strFormat := nil;
  TempFont := nil;
  Fam := nil;
  if GdipCreateFromHDC(DC, Graphics) = Ok then
  begin
    GdipCreateFontFamilyFromName(UseFont, nil, Fam);
    if Assigned(Fam) then
    begin
      GdipCreateFont(Fam, UseSize, FontStyle, 2, TempFont);
      if Assigned(TempFont) then
      begin
        GdipCreateStringFormat(0, 0, strFormat);
        GdipMeasureString(Graphics, UseText, length(UseText), TempFont, @layoutRect, strFormat,
          @boundingBox, nil, nil);

        GetWindowRect(HeaderHandle, rc);
        GetWindowRect(Handle, rc2);

        Width := (rec.Right - rec.Left) + (rc.Left - rc2.Left);
        if boundingBox.Width > Width then
        begin
          rectF := MakeRect(rec.Left, rec.Top, Width, rec.Bottom);
          Rect.Left := round(rectF.X);
          Rect.Top := round(rectF.Y);
          Rect.Bottom := round(rectF.Height);
          Rect.Right := round(rectF.Width);

          UseStrFormat := ZD_Ellipsis;
          DrawTextToDC(DC, UseText, Rect, ColrARGB, UseFont, UseSize, FontStyle, ShadowOffset,
            UseStrFormat, True);

          GdipDeleteGraphics(Graphics); // Lösche das Graphics Object
          GdipDeleteFont(TempFont);    // Lösche das Font Object
          GdipDeleteFontFamily(Fam);   // Lösche das Font Family Object
          GdipDeleteStringFormat(strFormat); // Lösche das StringFormat
          exit;
        end else
        DrawTextToDC(DC, UseText, rec, ColrARGB, UseFont, UseSize, FontStyle, ShadowOffset,
          UseStrFormat, WordWrap);
      end;
    end;
  end;
  GdipDeleteGraphics(Graphics);
  GdipDeleteFont(TempFont);
  GdipDeleteFontFamily(Fam);
  GdipDeleteStringFormat(strFormat);
end;
coole Musik. Oder? LOL

gruss

freimatz 21. Feb 2017 15:47

AW: EllipsisCharacter funktioniert nicht
 
BTW: schon mal try finally end in Erwägung gezogen?

EWeiss 21. Feb 2017 18:03

AW: EllipsisCharacter funktioniert nicht
 
Zitat:

Zitat von freimatz (Beitrag 1362254)
BTW: schon mal try finally end in Erwägung gezogen?

Nö.. will ich nicht.
Brauch ich nicht. Uninteressant, Müllt meinen Code zu.

Delphi-Quellcode:
if GdipCreateFromHDC(DC, Graphics) = Ok then


Ist für mich try, finally genug.
Abgesehen von Delphi hab ich noch keine Sprache verwendet die ein so Sinnloses Konstrukt nötig hätte.
Schon gar nicht mit der Win32API.
try.. except OK! Dann hört es aber auch schon auf.

gruss

Luckie 21. Feb 2017 20:59

AW: EllipsisCharacter funktioniert nicht
 
Da WinAPI Funktionen in der Regel keine Exceptions werfen, wäre es sinnlos Exceptions behandeln zu wollen. Das gilt natürlich auch für try...finally.

Sie aber als sinnlos bin der objektorientierten Programmierung abzutun hat die objektorientierte Programmierung nicht verstanden. Das sieht man auch sehr schön an deinen Code:
Delphi-Quellcode:
if GdipCreateFromHDC(DC, Graphics) = Ok then
  if Assigned(Fam) then
    if Assigned(TempFont) then
     if boundingBox.Width > Width then
    
     end
     else
       ...;
   end;
  end;
end;
Da Windows API Funktionen nur Fehlercodes zurück geben muss man diese jedes mal prüfen und entsprechend reagieren, was zu solchen Verschachtelungsorgien führt. Btw. wo ist die Fehlerbehandlung, wenn der Funktionsaufruf fehlschlägt bei dir?

In der objektorientierten Programmierung schreibt man den Code einfach runter unter macht im Except-Block eine Fehlerbehandlung für alles. Und in Exyception.message steht dann drin welcher Methodenaufruf aus welchem Grund fehlgeschlagen ist.

EWeiss 21. Feb 2017 21:18

AW: EllipsisCharacter funktioniert nicht
 
Zitat:

Sie aber als sinnlos bin der objektorientierten Programmierung abzutun hat die objektorientierte Programmierung nicht verstanden.
In wie weit.
Was sieht man da sehr schön ?

Wenn ich zu dumm bin zu erkennen wann ich meine Daten Freigeben muss und an welcher stelle dann hilft auch kein try.. finally.
Unnötiger Code.
Würde ich das in jeder Funktion/procedure verwenden wäre 1/3 des Gesamten Code nur mit try.. finally gefüllt.
Wie gesagt brauch ich nicht.

Ob du mich in dem Fall für Dumm hinstellst kann mir egal sein.
Wie gesagt NUR Delphi hat diese komische Angewohnheit alles in Blöcke zu packen.
Nach deiner Schilderung dürften dann alle anderen Sprachen NICHT objektorientiert sein.. Lustig diese Annahme.
Muss dann also davon ausgehen das man nur mit Delphi objektorientiert Programmieren kann. LOL

Ich denke du verstehst nicht das dass nur ein Delphi Ding ist.
Oder brauchst du so was in C++, CSharp, VB, NET usw..

Sorry da kannst du mich nicht überzeugen und die Begründung(Unterstellung) ist quatsch.

gruss

Zacherl 21. Feb 2017 23:10

AW: EllipsisCharacter funktioniert nicht
 
Zitat:

Zitat von EWeiss (Beitrag 1362282)
Ich denke du verstehst nicht das dass nur ein Delphi Ding ist.
Oder brauchst du so was in C++, CSharp, VB, NET usw..

Das stimmt so nicht. Alle diese Sprachen - mit Ausnahme von C++ unterstützen - try..finally Blöcke als Sprachfeature. Das "Delphi Ding" sind Resourcenschutzblöcke bei Verwendung von Objekten:
Delphi-Quellcode:
var
  A: TObject;
begin
  A := TObject.Create;
  try
 
  finally
    A.Free;
  end;
end
Dass man sowas in .NET / C# beispielsweise nicht braucht, liegt daran, dass diese Sprachen eine automatische Referenzzählung bzw. einen Garbage-Collector besitzen, der unreferenzierte Klasseninstanzen automatisch freigibt. C++ wurde zumdem explizit für das RAII Prinzip entwickelt und alloziiert Objekte standardmäßig auf dem Stack (statt auf dem Heap). Hierdurch ist die Lebensdauer durch das aktuelle Scope limitiert und benötigt auch keine zusätzliche Finalisierung.

Es mag Leute geben, die try..finally unter Delphi ausschließlich als Resourcenschutzblock verwenden, aber dennoch sind dies zwei getrennte Dinge und man sollte den Nutzen dieses Sprachkonstrukts im Bezug auf andere Dinge keinesfalls unterschätzen. Grade auch bei Verwendung der WinAPI.

Zitat:

Zitat von EWeiss (Beitrag 1362282)
Was sieht man da sehr schön ?

Dein Code ist fehlerhaft; genauer gesagt gibt er unter Umständen Objekte frei, welche gar nicht korrekt initialisiert wurden (und du vergisst diverse Rückgabewerte zu prüfen). Exemplarisch hier mal nur folgender Abschnitt:
Zitat:

Zitat von EWeiss (Beitrag 1362027)
Delphi-Quellcode:
procedure TSkinListView.DrawEllipsisText(...);
begin
  ...
  if GdipCreateFromHDC(DC, Graphics) = Ok then
  begin
    GdipCreateFontFamilyFromName(UseFont, nil, Fam);
    if Assigned(Fam) then
    begin
      GdipCreateFont(Fam, UseSize, FontStyle, 2, TempFont);
      ...
    end;
  end;
  GdipDeleteGraphics(Graphics);
  GdipDeleteFont(TempFont);
  ...

Was passiert, wenn MSDN-Library durchsuchenGdipCreateFromHDC oder MSDN-Library durchsuchenGdipCreateFontFamilyFromName fehlschlägt? Dann ist
Delphi-Quellcode:
Graphics
bzw.
Delphi-Quellcode:
TempFont
ungültig. Mag sein, dass die GDI+ hier gnädig ist, aber andere APIs z.b. MSDN-Library durchsuchenCloseHandle würden in diesem Falle bereits einen Fehler signalisieren - oder noch schlimmer: Du gibst ein anderes, zufälliges Handle deiner Anwendung frei.

Worauf Luckie allerdings (vermutlich) hinauswollte, ist die tiefe Verschachtelung und die redundante Finalisierung im
Delphi-Quellcode:
if boundingBox.Width > Width then
Block. Beides kannst du nämlich mit try..finally sehr elegant vermeiden:
Delphi-Quellcode:
procedure GdipCheck(Status: GPSTATUS);
begin
  if (Status <> Ok) then raise Exception.Create('GDI+ Exception');
end

...

procedure TSkinListView.DrawEllipsisText(...);
begin
  Graphics := 0;
  Fam := nil;
  TempFont := nil;
  ...
  GdipCheck(GdipCreateFromHDC(DC, Graphics));
  try
    GdipCheck(GdipCreateFontFamilyFromName(UseFont, nil, Fam));
    GdipCheck(GdipCreateFont(Fam, UseSize, FontStyle, 2, TempFont));
    GdipCheck(GdipCreateStringFormat(0, 0, strFormat));
    ...
  finally
    if (Graphics <> 0)  then GdipDeleteGraphics(Graphics);
    if (Fam     <> nil) then GdipDeleteFontFamily(Fam);
    if (TempFont <> nil) then GdipDeleteFont(TempFont);
    ...
  end;
Die Exception-Hilfsfunktion ist hierbei natürlich optional und kann auch durch ein
Delphi-Quellcode:
if (GdipCreateFromHDC(DC, Graphics) <> Ok) then Exit
ersetzt werden, da nach dem
Delphi-Quellcode:
Exit
ebenfalls in jedem Falle der Finally-Block ausgeführt wird.

Noch ein kleiner Nachtrag: Aus eigener Erfahrung kann ich sagen, dass man try..finally wirklich schmerzhaft vermisst, wenn es einem nicht zur Verfügung steht. Ok, C++ hat RAII als Ersatz und da ist es wohl als persönliche Präferenz zu sehen, dass ich dieses Prinzip nicht uneingeschränkt sinnvoll finde (aus zahlreichen Gründen, die hier aber wohl über das Thema hinausschießen), aber selbst pures C wird bei Verwendung der WinAPI teilweise extrem redundant, was Finalisierungen angeht. Kleines (nicht sehr sinnvolles) Beispiel (der Einfachheit halber in Delphi-Code, aber im C-Stil, also ohne try..finally).

Variante 1 (verschachtelt):
Delphi-Quellcode:
begin
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, false, 1337);
  if (hProcess <> 0) then
  begin
    Mem := VirtualAllocEx(hProcess, nil, SizeOf(Value), MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
    if Assigned(Mem) then
    begin
      Value := 0;
      if WriteProcessMemory(hProcess, Mem, @Value, SizeOf(Value), BytesWritten) and
        (BytesWritten = SizeOf(Value)) then
      begin
        hThread := CreateRemoteThread(hProcess, nil, 0,
          GetProcAddress(GetModuleHandle('kernel32.dll'), 'ExitProcess'), Mem, CREATE_SUSPENDED, TID);
        if (hThread <> 0) then
        begin
          ResumeThread(hThread);
          // Das könnte sich hier ewig so weiterschachteln ...
        end;
        CloseHandle(hThread);
      end;
      VirtualFreeEx(hProcess, Mem, 0, MEM_RELEASE);
    end;
    CloseHandle(hProcess);
  end;
end;
Variante 2 (mit Exit/goto):
Delphi-Quellcode:
begin
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, false, 1337);
  if (hProcess <> 0) then
  begin
    Mem := VirtualAllocEx(hProcess, nil, SizeOf(Value), MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
    if not Assigned(Mem) then
    begin
      // 1 Finalisierung
      CloseHandle(hProcess);
      Exit;
    end;
    Value := 0;
    if (not WriteProcessMemory(hProcess, Mem, @Value, SizeOf(Value), BytesWritten)) or
      (BytesWritten <> SizeOf(Value)) then
    begin
      // 2 Finalisierungen
      VirtualFreeEx(hProcess, Mem, 0, MEM_RELEASE);
      CloseHandle(hProcess);
      Exit;
    end;
    hThread := CreateRemoteThread(hProcess, nil, 0,
      GetProcAddress(GetModuleHandle('kernel32.dll'), 'ExitProcess'), Mem, CREATE_SUSPENDED, TID);
    if (hThread = 0) then
    begin
      // 3 Finalisierungen
      CloseHandle(hThread);
      VirtualFreeEx(hProcess, Mem, 0, MEM_RELEASE);
      CloseHandle(hProcess);
      Exit;
    end;
    ResumeThread(hThread);
    // Und am Ende nochmal alles redundant
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, Mem, 0, MEM_RELEASE);
    CloseHandle(hProcess);
  end;
end;
Dahingegen die Variante mit try..finally:
Delphi-Quellcode:
begin
  hProcess := OpenProcess(PROCESS_ALL_ACCESS, false, 1337);
  if (hProcess <> 0) then
  try
    // Mini-Nachteil: Man muss alle Variablen am Anfang nullen
    Mem := nil;
    hThread := 0;
    // Los gehts:
    Mem := VirtualAllocEx(hProcess, nil, SizeOf(Value), MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
    if not Assigned(Mem) then
      Exit;
    Value := 0;
    if (not WriteProcessMemory(hProcess, Mem, @Value, SizeOf(Value), BytesWritten)) or
      (BytesWritten <> SizeOf(Value)) then
      Exit;
    hThread := CreateRemoteThread(hProcess, nil, 0,
      GetProcAddress(GetModuleHandle('kernel32.dll'), 'ExitProcess'), Mem, CREATE_SUSPENDED, TID);
    if (hThread = 0) then
      Exit;
    ResumeThread(hThread);
    // .. kann endlos so weitergehen, ohne immer tiefere Verschachtelung oder Redundanz
  finally
    if (hThread <> 0)  then CloseHandle(hThread);
    if (Mem    <> nil) then VirtualFreeEx(hProcess, Mem, 0, MEM_RELEASE);
    CloseHandle(hProcess);
  end;
end;

EWeiss 21. Feb 2017 23:28

AW: EllipsisCharacter funktioniert nicht
 
Gut erklärt ;) Danke für die Mühe

Dem muss ich zustimmen

Delphi-Quellcode:
if (Graphics <> 0) then GdipDeleteGraphics(Graphics);
if (Fam <> nil) then GdipDeleteFontFamily(Fam);
if (TempFont <> nil) then GdipDeleteFont(TempFont);
Wobei das aber nicht zwingend voraussetzt das ich try..finally Blöcke verwenden muss.
Ich sehe auch nach deiner Erklärung keinen sinn dahinter da man alles auch ohne diese Blöcke erledigen kann.

Andererseits prüfe ich nie auf Nil..
Sondern auf bsp.
Delphi-Quellcode:
if Assigned(Fam) then


Ob ich jetzt hier
Delphi-Quellcode:
if boundingBox.Width > Width then


mit begin.. end else oder mit try.. finally abarbeite ist gehüpft wie gesprungen.
Ich sehe keine Bereicherung bei dieser Verwendung.

Zitat:

Die Exception-Hilfsfunktion ist hierbei natürlich optional
Es ist Gewohnheit die Bedingungen direkt ohne Umwege zu prüfen. (Sehe da kein Manko in irgendeiner weise).

Wenn du mir einen triftigen Grund nennen kannst warum das Konstrukt so lebenswichtig ist lasse ich mich gerne überzeugen.
Ich sehe da aber so wie bei meinem Beispiel zur zeit keinen der mich dazu veranlassen könnte.
Das kann ich alles mit Bedingungen und der korrekten Freigabe von Objekten erledigen.. on the fly ;)

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:45 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz