Stringbreite in Pixel ermitteln

Stelle Fragen zur Programmierung mit Autohotkey

Moderator: jNizM

User avatar
Holle
Posts: 187
Joined: 01 Oct 2013, 23:19

Stringbreite in Pixel ermitteln

Post by Holle » 15 Nov 2013, 07:14

Gibt es einen Befehl mit dem man die Breite eines Strings (Schrift = Arial, Größe Variabel) ermitteln kann?

Wenn nicht würde ich auch eine Funktion schreiben, um diese zu errechnen, aber ich finde keine Werte mit denen ich die Breite der einzelnen Buchstaben anhand der Schriftgröße ermitteln kann.
In einem PHP-Forum habe ich etwas gefunden, aber demnach wären die Buchstaben "a,b,c,d,e,g,o, usw." gleich breit. Wenn ich aber "aaaaaaaaaa und darunter "cccccccccc" Schreibe (in Arial), dann ist die Zeile mit dem 10 x c deutlich kürzer als die Zeile mit den 10 x a. Somit können die Werte aus dem PHP-Forum nicht stimmen und etwas anderes finde ich nicht.

Irgendwelche Ideen?

User avatar
nnnik
Posts: 4500
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Stringbreite in Pixel ermitteln

Post by nnnik » 15 Nov 2013, 08:40

Da musst du GDI+ benutzen.
Recommends AHK Studio

User avatar
Holle
Posts: 187
Joined: 01 Oct 2013, 23:19

Re: Stringbreite in Pixel ermitteln

Post by Holle » 15 Nov 2013, 09:06

Danke.
Da ich meine Funktion später auch ohne GDI+ nutzen will bin ich gerade dabei die Breiten der einzelnen Buchstaben (bzw. das Verhältnis zur Höhe) per GDI+ zu ermitteln.
Diese Werte kann ich dann später in meiner Funktion nutzen, so dass ich dafür dann kein GDI+ mehr benötige.

just me
Posts: 9485
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Stringbreite in Pixel ermitteln

Post by just me » 15 Nov 2013, 10:05

Solange es um die Darstellung in einem GUI geht, hilft die Holzfällermethode:

Code: Select all

#NoEnv
Gui, Font, , Arial
Gui, Add, Text, w150 h20, "aaaaaaaaaa"
Gui, Add, Text, w150 h20, "cccccccccc"
Gui, Add, Text, w150 h20, "WWWWWWWWWW"
Gui, Add, Text, ym wp hp, % StrWidth("aaaaaaaaaa", "", "Arial")
Gui, Add, Text, wp hp, % StrWidth("cccccccccc", "", "Arial")
Gui, Add, Text, wp hp, % StrWidth("WWWWWWWWWW", "", "Arial")
Gui, Show, , String Width
Return
GuiClose:
ExitApp

StrWidth(Str, FontOptions, FontName) {
   Gui, StrWidthDummyGUI:Font, %FontOptions%, %FontName%
   Gui, StrWidthDummyGUI:Add, Text, hwndHTX, %Str%
   GuiControlGet, S, StrWidthDummyGUI:Pos, %HTX%
   Gui, StrWidthDummyGUI:Destroy
   Return SW
}

User avatar
Holle
Posts: 187
Joined: 01 Oct 2013, 23:19

Re: Stringbreite in Pixel ermitteln

Post by Holle » 15 Nov 2013, 10:50

Vielen Dank, aber in dem Beispiel sind "a" und "c" identisch.
Wenn ich das nun aber in OpenOffice eingebe sind die 10 x "a" länger als die 10 x "c"

Mit GDI+ komme ich auch nur auf falsche Ergebnisse.
Zwar ist da "a" = "b" und "c" ist kleiner als "a" (soweit alles richtig), aber da ist "1" = "a" obwohl 10 x "1" sogar noch schmäler sind als 10 x "c".

Hier ist mein provisorisch zusammen gebasteltes Script um die Breite zu ermitteln (die Ergebnisse Kopiere ich dann einfach mit Strg+C aus der MsgBox):

Code: Select all

#SingleInstance, Force
#NoEnv
SetBatchLines, -1
#Include, Gdip.ahk
If !pToken := Gdip_Startup()
{
   MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
   ExitApp
}
OnExit, Exit
Width := A_ScreenWidth, Height := A_ScreenHeight
Gui, 1:  -Caption +E0x80000 +LastFound +OwnDialogs +Owner +AlwaysOnTop
Gui, 1: Show, NA
hwnd1 := WinExist()
hbm := CreateDIBSection(Width, Height)
hdc := CreateCompatibleDC()
obm := SelectObject(hdc, hbm)
G := Gdip_GraphicsFromHDC(hdc)
Gdip_SetSmoothingMode(G, 4)
pBrush := Gdip_BrushCreateSolid(0xaa000000)
Gdip_FillRectangle(G, pBrush, 0, 0, Width, Height)
Gdip_DeleteBrush(pBrush)
Font = Arial
If !hFamily := Gdip_FontFamilyCreate(Font)
{
   MsgBox, 48, Font error!, The font you have specified does not exist on the system
   ExitApp
}
Gdip_DeleteFontFamily(hFamily)

hFont := Gdip_FontCreate(hFamily, size, "Arial")
hFormat := Gdip_StringFormatCreate(0x4000)
CreateRectF(RectF, x, y, 0, 0) 

Options = x10p y30p w80p Centre cbbffffff r4 s120
wert := {}
arial =
Loop, 255
{
	text =
	char := chr(a_index)
	Loop, 10
		text .= char
	Gdip_TextToGraphics(G, text, Options, Font, Width, Height)
	wert[Char] := Gdip_MeasureString(G, text, hFont, hFormat, RectF)
	InputVar := wert[Char]
	StringSplit, split, InputVar, |
	result .= a_index " (" Char ") = " wert[Char] "`n --> " (split3 / 10) / split4 "`n"
	arial .= (split3 / 10) / split4 "|"
}
MsgBox % result
MsgBox % arial

UpdateLayeredWindow(hwnd1, hdc, (A_ScreenWidth-Width)//2, (A_ScreenHeight-Height)//2, Width, Height)
SelectObject(hdc, obm)
DeleteObject(hbm)
DeleteDC(hdc)
Gdip_DeleteGraphics(G)
TrayTip, GDip Example, Press ESC to Close Example, 10, 1
Return


Esc::  ; Hotkey to exit example
Exit:
; gdi+ may now be shutdown on exiting the program
Gdip_Shutdown(pToken)
ExitApp
Return 

Die ermittelten Werte nutze ich dann hier (auch noch provisorisch):

Code: Select all

Arial = 0.914669|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026503|0.003571|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026120|0.026834|0.257180|0.321253|0.487919|0.487919|0.764256|0.579900|0.185246|0.302778|0.302778|0.349555|0.511111|0.257180|0.302778|0.257180|0.257180|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.257180|0.257180|0.511111|0.511111|0.511111|0.487919|0.868422|0.579900|0.579900|0.625498|0.625498|0.579900|0.533517|0.671882|0.625498|0.257180|0.441536|0.579900|0.487919|0.717479|0.625498|0.671882|0.579900|0.671882|0.625498|0.579900|0.533517|0.625498|0.579900|0.809460|0.579900|0.579900|0.533517|0.257180|0.257180|0.257180|0.415985|0.487919|0.302778|0.487919|0.487919|0.441536|0.487919|0.487919|0.257180|0.487919|0.487919|0.211190|0.211190|0.441536|0.211190|0.717479|0.487919|0.487919|0.487919|0.487919|0.302778|0.441536|0.257180|0.487919|0.441536|0.625498|0.441536|0.441536|0.441536|0.303957|0.242243|0.303957|0.511111|0.026120|0.026120|0.026120|0.470394|0.470394|0.003571|0.026120|0.470394|0.470394|0.349751|0.721256|0.455841|0.470394|0.913137|0.026120|0.026120|0.026120|0.026120|0.204213|0.204213|0.399157|0.399157|0.026120|0.498353|0.909690|0.326388|0.853007|0.349751|0.248257|0.519801|0.026120|0.026120|0.647338|0.026834|0.302778|0.487919|0.487919|0.487919|0.487919|0.242243|0.487919|0.302778|0.637683|0.333831|0.487919|0.511111|0.026120|0.637683|0.484775|0.358595|0.482023|0.302778|0.302778|0.302778|0.504429|0.472196|0.302778|0.302778|0.302778|0.329507|0.487919|0.718265|0.718265|0.718265|0.533517|0.579900|0.579900|0.579900|0.579900|0.579900|0.579900|0.855844|0.625498|0.579900|0.579900|0.579900|0.579900|0.257180|0.257180|0.257180|0.257180|0.625498|0.625498|0.671882|0.671882|0.671882|0.671882|0.671882|0.511111|0.671882|0.625498|0.625498|0.625498|0.625498|0.579900|0.579900|0.533517|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.764256|0.441536|0.487919|0.487919|0.487919|0.487919|0.257180|0.257180|0.257180|0.257180|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.487919|0.482023|0.533517|0.487919|0.487919|0.487919|0.487919|0.441536|0.487919|0.441536

StringSplit , Arial , Arial , |


FontSize := 18
Zeichen1 = 1
Zeichen2 = a

ascii1 := Asc(zeichen1)
ascii2 := Asc(zeichen2)
Breite1 := FontSize * Arial%ascii1%
Breite2 := FontSize * Arial%ascii2%
zeichen1 := "Zeichen1 = " zeichen1 "`nAscii-Code = " Asc(zeichen1) "`nMultiplikator = " Arial%ascii1% "`nBreite = " Breite1
zeichen2 := "Zeichen2 = " zeichen2 "`nAscii-Code = " Asc(zeichen2) "`nMultiplikator = " Arial%ascii2% "`nBreite = " Breite2

MsgBox % "Schriftgröße = " FontSize "`n`n" zeichen1 "`n`n" zeichen2
Muss nun erst mal aufhören, keine Zeit mehr. Vielleicht bekomme ich durch die Auszeit ja auch wieder einen klaren Kopf ;-)

User avatar
Holle
Posts: 187
Joined: 01 Oct 2013, 23:19

Re: Stringbreite in Pixel ermitteln

Post by Holle » 18 Nov 2013, 07:20

Hmmm, anscheinend funktioniert man Script soweit doch, aber es gibt Probleme mit dem Zeichnen des Textes.
Wenn ich nur 10 x "1" und 10 x "a" zeichnen lasse, dann sind die "Einsen" immer an der gleichen Position der "a"´s, womit natürlichg auch die berechnete Breite identisch ist.
In OpenOffice oder Word sieht das jedoch anders aus, da sind die 10 x "1" kürzer als die 10 x "a".

Woran liegt das? Ein Fehler im GDI+ oder an AHK?


Edit:
Das Beispiel von just me funktioniert doch tadellos. Zwar ist das Ergebnis von "10 x a" das gleiche wie von "10 x c" (und das ist laut OpenOffice / Word nicht der Fall), aber die Darstellung in AHK ist auch gleich (in der MessageBox). Erst wenn ich die Schriftgröße erhöhe weicht die Darstellung voneinander ab, aber dann bekomme ich auch einen anderen Wert.

Das Script zeigt also die tatsächliche Stringlänge an, nur die Darstellung in AHK weicht halt von Textverarbeitungsprogrammen ab.
Das scheint ein Fehler in AHK zu sein.

Nochmals vielen Dank, just me. Dein Script kann ich also doch 1:1 verwenden.

User avatar
Seidenweber
Posts: 17
Joined: 30 Sep 2013, 11:40

Re: Stringbreite in Pixel ermitteln

Post by Seidenweber » 19 Nov 2013, 08:22

Scheinbar haben wir uns so sehr an die WYSIWYG-Darstellung gewöhnt, dass wir das für das Maß aller Dinge halten :-)
So etwas wie die "tatsächliche Stringlänge" gibt es nicht. Es geht nur darum, das spätere Druckergebnis auch schon während der Bearbeitung annähernd so darzustellen, wie es später auf dem Papier aussehen wird.
Und das ist 1) ungenau und 2) je nach Software unterschiedlich. Bei Elementen, die nicht für die Druckausgabe gedacht sind, ist die Ausgabe auf dem Bildschirm naturgemäß anders und ggf auch genauer, als z.B. bei einer Textverarbeitung.
Questions and answers are related to AHK 1.1.13.01 (x64) & Win 7 pro x64

Post Reply

Return to “Ich brauche Hilfe”