Что нового

[Данные, строки] Получить длину строки в пикселях.

gora

Знающий
Сообщения
315
Репутация
19
Искал код для получения длины строки в пискелях. Нашел решение от CreatoR здесь. Функция __GUICtrlLabelGetTextWidth позволяет получить длину строки в пискелях, но если в строке есть символы табуляции, то результат получается неверный.
Можно ли подправить функцию, или есть другое решение для получения достоверных результатов с учетом символов табуляции?

Спасибо.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
если в строке есть символы табуляции, то результат получается неверный.
Можно заменять символы табуляции на пробелы (например 4 пробела на один @TAB).
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
CreatoR [?]
Можно заменять символы табуляции на пробелы (например 4 пробела на один @TAB).
Нельзя. Например эти две строки должны иметь одинаковую длину, а получатся разные.
Код:
$s_Data1='AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'A'
$s_Data2='A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
gora
Посмотрите функцию
Код:
_WinAPI_GetTextExtentPoint32

Возможно это то, что вы ищите.
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
inververs
Насколько я понял, именно она и используется в __GUICtrlLabelGetTextWidth от CreatoR
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
эти две строки должны иметь одинаковую длину
Это как? :scratch:
Они изначально не одинаковой длины.

Вот пример с этими строками, функцию для получения длины текста изменил:

Код:
#include <GUIConstantsEx.au3>
#include <FontConstants.au3>
#include <WinAPI.au3>

Global $iFontSize = 9
Global $iFontWeight = 400
Global $iFontAttribs = 0
Global $sFontName = 'Arial'

$s_Data1 = 'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'A'
$s_Data2 = 'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'

$GUI = GUICreate('_GUICtrlLabelGetTextWidth Demo', 500, 200)

$Label1 = GUICtrlCreateLabel('', 20, 30)
GUICtrlSetFont(-1, $iFontSize, $iFontWeight, $iFontAttribs, $sFontName)
GUICtrlSetBkColor(-1, 0x00FFFF)

$Label2 = GUICtrlCreateLabel('', 20, 70)
GUICtrlSetFont(-1, $iFontSize, $iFontWeight, $iFontAttribs, $sFontName)
GUICtrlSetBkColor(-1, 0x00FFFF)

_GUICtrlSetDataEx($Label1, $s_Data1, $iFontSize, $iFontWeight, $iFontAttribs, $sFontName)
_GUICtrlSetDataEx($Label2, $s_Data2, $iFontSize, $iFontWeight, $iFontAttribs, $sFontName)

GUISetState(@SW_SHOW, $GUI)

While 1
	$nMsg = GUIGetMsg()
	
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

Func _GUICtrlSetDataEx($iCtrlID, $sData, $iFontSize = 8.5, $iFontWeight = $FW_NORMAL, $iFontAttribs = 0, $sFontName = 'Arial')
	$sData = StringReplace($sData, @TAB, '    ')
	
	Local $aCtrl_Pos = ControlGetPos(GUICtrlGetHandle($iCtrlID), '', '')
	Local $aData_Len = _GUICtrlLabelGetTextWidth($sData, $iFontSize, $iFontWeight, $iFontAttribs, $sFontName, 0)
	
	GUICtrlSetPos($iCtrlID, $aCtrl_Pos[0], $aCtrl_Pos[1], $aData_Len[0], $aData_Len[1])
	GUICtrlSetData($iCtrlID, $sData)
EndFunc

Func _GUICtrlLabelGetTextWidth($sData, $iFontSize = 8.5, $iFontWeight = $FW_NORMAL, $iFontAttribs = 0, $sFontName = 'Arial', $iFixTabs = 0)
	Local $sTabs, $sAdd, $bFItalic, $bFUnderline, $bFStrikeout, $h_GDW_GUI, $hDC, $intDeviceCap, $intFontHeight, $hFont, $tSIZE, $aRet
	
	If $iFixTabs Then
		$sData = StringReplace($sData, @TAB, '     ')
		
		If @extended Then
			For $i = 1 To @extended + 1
				$sTabs &= '    ' & $sAdd
				$sAdd &= ' '
			Next
		EndIf
		
		$sData &= $sTabs
	EndIf
	
	$bFItalic = BitAND($iFontAttribs, 2) = 2
	$bFUnderline = BitAND($iFontAttribs, 4) = 4
	$bFStrikeout = BitAND($iFontAttribs, 8) = 8
	
	$h_GDW_GUI = GUICreate("Get Data Width", 10, 10, -100, -100, 0x80880000, 0x00000080)
	$hDC = _WinAPI_GetDC($h_GDW_GUI)
	$intDeviceCap = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)
	$intFontHeight = _WinAPI_MulDiv($iFontSize, $intDeviceCap, 72)
	$hFont = _WinAPI_CreateFont(-$intFontHeight, 0, 0, 0, $iFontWeight, $bFItalic, $bFUnderline, $bFStrikeout, $DEFAULT_CHARSET, $OUT_CHARACTER_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $FIXED_PITCH, $sFontName)
	_WinAPI_SelectObject($hDC, $hFont)
	$tSIZE = _WinAPI_GetTextExtentPoint32($hDC, $sData)
	
	Dim $aRet[2] = [DllStructGetData($tSIZE, 'X'), DllStructGetData($tSIZE, 'Y')]
	
	GUIDelete($h_GDW_GUI)
	Return $aRet
EndFunc
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
gora
Длина строки в пикселях будет зависеть от используемого шрифта. Например, ваши 2 строки одинаковы по длинне в консоле SciTE.
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
CreatoR [?]
Это как?
think.gif

Они изначально не одинаковой длины.
Как-то так:
Код:
#include <WinAPI.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>

$s_Data1='AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'A'
$s_Data2='A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'
$len1=__GUICtrlLabelGetTextWidth($s_Data1)
$len2=__GUICtrlLabelGetTextWidth($s_Data2)
$preskey=MsgBox(1+256,'test', _
	$s_Data1&@LF& _
	'$len1[0]='&$len1[0]&@LF& _
	$s_Data2&@LF& _
	'$len2[0]='&$len2[0]&@LF& _
	@LF)
If $preskey=2 Then Exit

; Get test width for the label control#
Func __GUICtrlLabelGetTextWidth($s_Data, $i_FontSize = 8.5, $i_FontWeight = -1, $s_TextFont = "Arial")
	Local Const $DEFAULT_CHARSET = 1 ; 0 = ANSI character set
	Local Const $OUT_CHARACTER_PRECIS = 2
	Local Const $CLIP_DEFAULT_PRECIS = 0
	Local Const $PROOF_QUALITY = 2
	Local Const $FIXED_PITCH = 1
	Local Const $RGN_XOR = 3
	Local Const $LOGPIXELSY = 90
	
	If $i_FontWeight = "" Or $i_FontWeight = -1 Then
		$i_FontWeight = 400 ; default Font weight
	EndIf
	
	Local $hDC = _WinAPI_GetDC(0)
	Local $intDeviceCap = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)
	Local $intFontHeight = _WinAPI_MulDiv($i_FontSize, $intDeviceCap, 72)
	Local $hFont = _WinAPI_CreateFont(-$intFontHeight, 0, 0, 0, $i_FontWeight, 0, 0, 0, _
		$DEFAULT_CHARSET, $OUT_CHARACTER_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $FIXED_PITCH, $s_TextFont)
	
	_WinAPI_SelectObject($hDC, $hFont)
	Local $stRet = _WinAPI_GetTextExtentPoint32($hDC, $s_Data)
	
	_WinAPI_DeleteObject($hFont)
	_WinAPI_ReleaseDC(0, $hDC)
	
	Local $a_RetLen[2] = [DllStructGetData($stRet, 1), DllStructGetData($stRet, 2)]
	Return $a_RetLen
EndFunc
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Может так будет нагляднее
Код:
#include <WinAPI.au3>
$s_Data1='AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'A' ; (6*8+1*8)*6 + 8 = 344 Для Arial
$Form1 = GUICreate("Form1", 615, 438, 192, 124)
$Label1 = GUICtrlCreateLabel("Label1", 8, 80, 600, 18)
GUICtrlSetFont(-1, 8, 400, 0, "Arial")
$Label2 = GUICtrlCreateLabel("Label2", 8, 112, 600, 17)
GUICtrlSetFont(-1, 8, 400, 0, "Calibri")
$Label3 = GUICtrlCreateLabel("Label2", 8, 144, 600, 17)
GUICtrlSetFont(-1, 8, 400, 0, "Comic Sans MS")
$Label4 = GUICtrlCreateLabel("Label2", 8, 176, 600, 17)
GUICtrlSetFont(-1, 8, 400, 0, "Lucida Console")
GUISetState(@SW_SHOW)

$f1=__GUICtrlLabelGetTextWidth($s_Data1,8,-1,"Arial")
$f2=__GUICtrlLabelGetTextWidth($s_Data1,8,-1,"Calibri")
$f3=__GUICtrlLabelGetTextWidth($s_Data1,8,-1,"Comic Sans MS")
$f4=__GUICtrlLabelGetTextWidth($s_Data1,8,-1,"Lucida Console")

GUICtrlSetData($Label1,"Arial "&$s_Data1&" Длина = "&$f1[0])
GUICtrlSetData($Label2,"Calibri "&$s_Data1&" Длина = "&$f2[0])
GUICtrlSetData($Label3,"Comic Sans MS "&$s_Data1&" Длина = "&$f3[0])
GUICtrlSetData($Label4,"Lucida Console "&$s_Data1&" Длина = "&$f4[0])

MsgBox(0,'','Нажми для выхода')

; Get test width for the label control#
Func __GUICtrlLabelGetTextWidth($s_Data, $i_FontSize = 8.5, $i_FontWeight = -1, $s_TextFont = "Arial")
    Local Const $DEFAULT_CHARSET = 1 ; 0 = ANSI character set
    Local Const $OUT_CHARACTER_PRECIS = 2
    Local Const $CLIP_DEFAULT_PRECIS = 0
    Local Const $PROOF_QUALITY = 2
    Local Const $FIXED_PITCH = 1
    Local Const $RGN_XOR = 3
    Local Const $LOGPIXELSY = 90

    If $i_FontWeight = "" Or $i_FontWeight = -1 Then
        $i_FontWeight = 400 ; default Font weight
    EndIf

    Local $hDC = _WinAPI_GetDC(0)
    Local $intDeviceCap = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)
    Local $intFontHeight = _WinAPI_MulDiv($i_FontSize, $intDeviceCap, 72)
    Local $hFont = _WinAPI_CreateFont(-$intFontHeight, 0, 0, 0, $i_FontWeight, 0, 0, 0, _
        $DEFAULT_CHARSET, $OUT_CHARACTER_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $FIXED_PITCH, $s_TextFont)

    _WinAPI_SelectObject($hDC, $hFont)
    Local $stRet = _WinAPI_GetTextExtentPoint32($hDC, $s_Data)

    _WinAPI_DeleteObject($hFont)
    _WinAPI_ReleaseDC(0, $hDC)

    Local $a_RetLen[2] = [DllStructGetData($stRet, 1), DllStructGetData($stRet, 2)]
    Return $a_RetLen
EndFunc
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
inververs
Я знаю про зависимость длины строки в пикселях от шрифта. Но я не об этом. В пределах окна у меня будет один шрифт, а длины строк мне нужны с учетом табуляции. Длина используется для расчета размера окна (и не только), а табуляция используется для форматирования текста в окне.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Ясно. Тогда вам этот способ не подходит, нужно искать что то другое.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
Длина используется для расчета размера окна (и не только), а табуляция используется для форматирования текста в окне.
Оно нужно только для MsgBox?
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
CreatoR
Нет. Окна будут свои.
Вот одно из них в котором табуляция используется для форматирования текста:
options.PNG
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
gora
Посмотрите это
http://msdn.microsoft.com/en-us/library/dd144930(v=VS.85).aspx
или вместо форматирования табуляцией используйте
Код:
StringFormat
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
Вот одно из них в котором табуляция используется для форматирования текста:
Можно увидеть полный пример, где проявляется проблема поставленной задачи?
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
CreatoR [?]
Можно увидеть полный пример
Боюсь, что я не смогу выдрать код окна из общего кода. Оно у меня универсальное и в нем много всего накручено и много внешних переменных, это только запутает... :(
Но проблема то вроде ясна. Когда в строке нет табуляции, то размер вычисляется правильно, а символы табуляции приводят к неверному результату. Это видно из кода в посте 7.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
gora [?]
Когда в строке нет табуляции, то размер вычисляется правильно
Чтобы подобрать размер окна под размер текста, можно просто получать длину текста (StringLen), и соответственно указывать размер окна (добавлять немного с каждого края).
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
CreatoR [?]
Чтобы подобрать размер окна под размер текста, можно просто получать длину текста (StringLen), и соответственно указывать размер окна (добавлять немного с каждого края).
И что это даст? Результаты то все равно зависят от наличия табуляции в строке:
Код:
#include <WinAPI.au3>
#include <GUIConstants.au3>
#include <WindowsConstants.au3>

$s_Data1='AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'AAAAAA'&@TAB&'A'
$s_Data2='A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'&@TAB&'A'
$len1=__GUICtrlLabelGetTextWidth($s_Data1)
$len2=__GUICtrlLabelGetTextWidth($s_Data2)
$len11=StringLen($s_Data1)
$len21=StringLen($s_Data2)
$preskey=MsgBox(1+256,'test', _
	$s_Data1&@LF& _
	'$len1[0]='&$len1[0]&@LF& _
	'$len11='&$len11&@LF& _
	$s_Data2&@LF& _
	'$len2[0]='&$len2[0]&@LF& _
	'$len21='&$len21&@LF& _
	@LF)
If $preskey=2 Then Exit

; Get test width for the label control#
Func __GUICtrlLabelGetTextWidth($s_Data, $i_FontSize = 8.5, $i_FontWeight = -1, $s_TextFont = "Arial")
	Local Const $DEFAULT_CHARSET = 1 ; 0 = ANSI character set
	Local Const $OUT_CHARACTER_PRECIS = 2
	Local Const $CLIP_DEFAULT_PRECIS = 0
	Local Const $PROOF_QUALITY = 2
	Local Const $FIXED_PITCH = 1
	Local Const $RGN_XOR = 3
	Local Const $LOGPIXELSY = 90
	
	If $i_FontWeight = "" Or $i_FontWeight = -1 Then
		$i_FontWeight = 400 ; default Font weight
	EndIf
	
	Local $hDC = _WinAPI_GetDC(0)
	Local $intDeviceCap = _WinAPI_GetDeviceCaps($hDC, $LOGPIXELSY)
	Local $intFontHeight = _WinAPI_MulDiv($i_FontSize, $intDeviceCap, 72)
	Local $hFont = _WinAPI_CreateFont(-$intFontHeight, 0, 0, 0, $i_FontWeight, 0, 0, 0, _
		$DEFAULT_CHARSET, $OUT_CHARACTER_PRECIS, $CLIP_DEFAULT_PRECIS, $PROOF_QUALITY, $FIXED_PITCH, $s_TextFont)
	
	_WinAPI_SelectObject($hDC, $hFont)
	Local $stRet = _WinAPI_GetTextExtentPoint32($hDC, $s_Data)
	
	_WinAPI_DeleteObject($hFont)
	_WinAPI_ReleaseDC(0, $hDC)
	
	Local $a_RetLen[2] = [DllStructGetData($stRet, 1), DllStructGetData($stRet, 2)]
	Return $a_RetLen
EndFunc
 
Автор
G

gora

Знающий
Сообщения
315
Репутация
19
AZJIO
Результат аналогичен вариантам протестированным ранее. Т.е., для двух табулированных строк (из примера выше) размер получается разный, а должен быть один.
 
Верх