Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Длина строки шириной N пикселов. Как определить? 
:(
    Опции темы
tripsin
  Дата 17.5.2005, 21:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



Как определить, сколько максимально символов заданного шрифта (TrueType или системного) поместится на ширине в пикселах? Т.е. ширина компонента известна, надо определсить длину строки, чтобы она заняла всю ширину компонента.
PM MAIL WWW ICQ   Вверх
Yanis
Дата 17.5.2005, 21:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2937
Регистрация: 9.2.2004
Где: Москва

Репутация: 72
Всего: 111



Код

var
  k: Integer;
begin
  k := 0;
  while Image1.Canvas.TextWidth(stringofchar('a', k)) < Image1.Width do
    inc(k);
  ShowMEssage('Max char count: '+IntToStr(k));
end;

Добавлено @ 21:44
Подсчёт маскимального кол-ва символов помещающихся на Canvas'е TImage.


--------------------
user posted image *щёлк*
PM MAIL WWW ICQ   Вверх
s-mike
Дата 17.5.2005, 23:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



Вместо придумывания велосипеда для переноса текста можно воспользоватся функцией DrawText.
PM MAIL WWW   Вверх
tripsin
Дата 17.5.2005, 23:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



Спасибо Yanis
А что делать, если у окошка известно тольно hWnd?
Я тут покопался в MSDN и нашел, что с помощью GetTextMetrics можно получить структуру TTextMetric, а в ней есть поля tmAveCharWidth: Longint;(ср.ширина символа) и tmMaxCharWidth: Longint;(макс.ширина символа) в относительных единицах. Спрашивается: как эти единицы в пикселы перевести?


Добавлено @ 23:28
s-mike Мне вот именно надо велосипед придумать smile

Это сообщение отредактировал(а) tripsin - 17.5.2005, 23:30
PM MAIL WWW ICQ   Вверх
s-mike
Дата 17.5.2005, 23:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



Цитата(tripsin @ 17.5.2005, 23:27)
s-mike Мне вот именно надо велосипед придумать smile

Функция DrawText может и TextWidth заменить. И в качестве входного параметра ей как раз и нужно DC окна.
PM MAIL WWW   Вверх
tripsin
Дата 18.5.2005, 11:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



А что общественность думает по поводу вот этого кода? :
Код

var
 DC: HDC;
 Metrics: TTextMetric;
 CharInWidth: Integer;
 OldMapMode: Integer;
begin
  DC := GetWindowDC(ListBox1.Handle); // Получаем контекст окна
    SelectObject(DC, ListBox1.Font.Handle);//Выбираем в него шрифт окна
    OldMapMode := GetMapMode(DC);// Запоминаем старый режим отображения
    SetMapMode(DC, MM_TEXT); //Устанавлмваем отображение в пикселях
    GetTextMetrics(DC, Metrics); //Получаем параметры шрифта
    SetMapMode(DC, OldMapMode);//Восстанавливаем режим отображения
  ReleaseDC(ListBox1.Handle, DC); //Освобождаем контекст
  //Получаем количестов средних символов на ширину окна
  CharsInWidth := ListBox1.ClientWidth div Metrics.tmAveCharWidth;
end;

PM MAIL WWW ICQ   Вверх
s-mike
Дата 18.5.2005, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



Цитата(tripsin @ 18.5.2005, 11:47)
А что общественность думает по поводу вот этого кода? :

Больше напоминает изобретание велосипеда smile
PM MAIL WWW   Вверх
tripsin
Дата 18.5.2005, 11:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



Мне кажется это лучше, чем простой подбор.
PM MAIL WWW ICQ   Вверх
s-mike
Дата 18.5.2005, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



tripsin, ну зачем же простой подбор? DrawText с флагом DT_CALCRECT возвращает точные размеры текста.
PM MAIL WWW   Вверх
tripsin
Дата 18.5.2005, 16:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



Мне нужно разбить длинную строку, на кусочки такой ширины, чтобы они влезали в окно (вручную). Выводить их сразу не надо и DrawText (при всех его достоинчтвах) мне не нужен.

З.Ы. С DT_CALCRECT расчитывается прямоугольник вывода, а он как раз известен.
PM MAIL WWW ICQ   Вверх
s-mike
Дата 18.5.2005, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



tripsin, ты все таки не понял, DrawText нужно вычислять длину строки. Она тебе возвратит минимальный прямоугольник, необходимый для вывода строки. Вот и найди ширину этого прямоугольника. Это и будет ширина строки. Есть еще GetTextExtentPoint32, используемая для TextWidth.
PM MAIL WWW   Вверх
tripsin
Дата 18.5.2005, 18:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



s-mike Это ты не понял. Задача в точности до наоборот. У меня уже есть прямоугольник, и надо посчитать сколько символов заданного шрифта влезет в этот прямоугольник по ширине. На выходе должно быть количество символов, а не размеры прямоугольника.
PM MAIL WWW ICQ   Вверх
s-mike
Дата 19.5.2005, 00:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



tripsin, я говорю, что с помощью этих функций, написанных всего одной строкой, можно заменить код, приведенный тут: http://forum.vingrad.ru/index.php?showtopi...ndpost&p=413987. Я думаю, что использовать среднюю ширину символов не стоит, тут нужна точность. Я думаю так. У нас есть слова, разделенные пробелом. Читаем последовательно слова, суммируем их ширину. При добавлении каждого следующего слова, если слова превышают максимальную длину строки, то новое слово не добавляем, а переходим на следующую строку. Я бы и код написал, жаль времени сейчас нет, поздно уже.
PM MAIL WWW   Вверх
tripsin
Дата 19.5.2005, 08:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



Цитата
Я бы и код написал, жаль времени сейчас нет, поздно уже.

Хм... Я подожду smile
PM MAIL WWW ICQ   Вверх
tripsin
Дата 19.5.2005, 09:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



То, что ты описал делает функция WrapText.
Цитата
если слова превышают максимальную длину строки,

Вот ее-то как раз и надо найти.
PM MAIL WWW ICQ   Вверх
s-mike
Дата 19.5.2005, 09:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



Цитата
WrapText function
Splits a string into multiple lines as its length approaches a specified size.

Unit

SysUtils

Category

string handling routines

Добавлено @ 09:35
Но она немного не тем занимается, она по буквам разбивает, а не по ширине слов.
PM MAIL WWW   Вверх
tripsin
Дата 19.5.2005, 10:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



Тем-тем. Все зависит от переданных параметров.

function WrapText(const Line, BreakStr: string; BreakChars: TSysCharSet; MaxCol: Integer): string;overload;

По умолчанию BreakChars = [' ', ' -' , #9], т.е. как раз на слова и разбивается. Но считает она не ширину строки в пикселах, а просто, что бы количество символов было меньше MaxCol.
PM MAIL WWW ICQ   Вверх
s-mike
Дата 19.5.2005, 10:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 425
Регистрация: 16.1.2005
Где: Киев

Репутация: 9
Всего: 16



Цитата(tripsin @ 19.5.2005, 10:36)
Но считает она не ширину строки в пикселах, а просто, что бы количество символов было меньше MaxCol.

Я об этом и говорю:
Цитата(s @ 19.5.2005, 09:33)
Но она немного не тем занимается, она по буквам разбивает, а не по ширине слов.

PM MAIL WWW   Вверх
Girder
Дата 19.5.2005, 12:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



Мдя... уж! smile

tripsin обрати внимание на следующие функции: GetCharWidth32, GetCharABCWidths.

Вот например простейший пример для GetCharWidth32:
Код
procedure TForm1.Button2Click(Sender: TObject);
var a:array [0..255] of DWord;
    w,i,wid:DWord;
    s:string;
    DC:HDC;
begin
 DC:=GetDC(Memo1.Handle);
 Wid:=20; //Типо... заданная ширина
 s:='G'+#9+'irder'; //Типо... заданная строка для которой мы хотим узнать... сколько из неё символов влезет :)
 FillChar(a,SizeOf(a),#0);
 GetCharWidth32(DC,0,255,a);
 w:=0;
 for i:=1 to Length(s) do
  begin
   if s[i]=#9 then w:=w+a[ord(s[i])]*4 else w:=w+a[ord(s[i])]; //Ну мне лень было описывает все "спец" символы :)
   if w>Wid then
    begin
     Caption:=IntToStr(i-1); //Типо... ответ
     break;
    end;
  end;
 ReleaseDC(Memo1.Handle,DC);
end;


Это сообщение отредактировал(а) Girder - 19.5.2005, 12:31


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
tripsin
Дата 19.5.2005, 13:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 38
Регистрация: 10.4.2005
Где: Талица

Репутация: нет
Всего: 3



Girder Твой код не работает! Ты сам-то пробовал. Он до строки "Caption:=IntToStr(i-1); //Типо... ответ" - даже не доходит.
GetCharWidth32(DC,0,255,a); - это че за вызов-то?
Вставь проверку: if not GetCharWidth32(DC,0,255,a) then ShowMessage('Хрена! Не работает!');
Кста. В твоем коде в DC надо выбирать шрифт с помощью SelectObject, иначе будет использоваться системный шрифт.

Ну блииииин!! smile Ну как еще объяснить-то.
Короче нужна функция такого вида:
function Number_Of_Chars_In_Pixel_Width(Pixel_Width_Of_window: Integer; WindowFont: TFont): Integer;
Может хоть так понятнее. Как определить ширину имеющейся строки я и так знаю.

Пока у этой задачи я нашел 2 ответа:
1. Подбор ширины строки в цикле, как показал Yanis(по "среднему" символу, или с помошью функций группы GetCharWidth (но для них нужен конкретный текст)
2. Мой вариант с использованием метрик тескта. Мне только интересно - корректный это код или нет (работает точно).

PM MAIL WWW ICQ   Вверх
Girder
Дата 19.5.2005, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



1.
Цитата
Remarks
GetCharWidth32 cannot be used on TrueType fonts. To retrieve character widths for TrueType fonts, use GetCharABCWidths.

The range is inclusive; that is, the returned widths include the widths of the characters specified by the iFirstChar and iLastChar parameters.

If a character does not exist in the current font, it is assigned the width of the default character.
для TrueType - надо использовать GetCharABCWidths
Цитата
Requirements
  Windows NT/2000/XP: Included in Windows NT 3.5 and later.
  Windows 95/98/Me: Unsupported.
для W9X - GetCharWidth
2.
Цитата(tripsin @ 19.5.2005, 14:53)
Кста. В твоем коде в DC надо выбирать шрифт с помощью SelectObject, иначе будет использоваться системный шрифт.
А я что за тебя должен писать весь код? читай:
Цитата(Girder @ 19.5.2005, 13:27)
Вот например простейший пример для GetCharWidth32

3.
Цитата(tripsin @ 19.5.2005, 14:53)
Кста. В твоем коде в DC надо выбирать шрифт с помощью SelectObject, иначе будет использоваться системный шрифт.
Да пробывал. У меня работает.

Это сообщение отредактировал(а) Girder - 19.5.2005, 15:26


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
Guest
Дата 19.5.2005, 15:18 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Это я, tripsin smile Girder Прошу прощения за наезд. Код действительно рабочий. Просто у меня Win98. Заменил на GetCharWidth и все заработало. smile
Girder Ты уж не обижайся smile , че-то нервный я стал.
  Вверх
Girder
Дата 19.5.2005, 15:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Лентяй 2
***


Профиль
Группа: Участник Клуба
Сообщений: 1993
Регистрация: 12.5.2004

Репутация: 31
Всего: 155



Лови... примерную реализацию smile
Код
function www(lFont:tagLogFonta;TypeFont:integer):DWord;
var a:array [0..255] of DWord;
    b:array [0..255] of ABC;
    w,i,wid,n:DWord;
    s:string;
    DC:HDC;
    FontOld,FontNew:HFont;
begin
FontNew:=CreateFontIndirect(lFont);
Result:=0;
DC:=GetDC(0);
FontOld:=SelectObject(DC,FontNew);
Wid:=50;
s:='Gir'+#9+'der';
if TypeFont<>TRUETYPE_FONTTYPE then
  begin
  FillChar(a,SizeOf(a),#0);
  if GetCharWidth32(DC,0,255,a)=false then
    GetCharWidth(DC,0,255,a);
  w:=0;
  for i:=1 to Length(s) do
    begin
    inc(Result);
    if s[i]=#9 then w:=w+a[ord(s[i])]*4 else w:=w+a[ord(s[i])];
    if w>Wid then break;
    end;
  end else
  begin
  FillChar(b,SizeOf(b),#0);
  GetCharABCWidths(DC,0,255,b);
  w:=0;
  for i:=1 to Length(s) do
    begin
    n:=b[ord(s[i])].abcA+b[ord(s[i])].abcB+b[ord(s[i])].abcC;
    if s[i]=#9 then w:=w+n*4 else w:=w+n;
    if w>Wid then
      begin
      Result:=i-1;
      break;
      end;
    end;
  end;
SelectObject(DC,FontOld);
ReleaseDC(0,DC);
DeleteObject(FontNew);
end;


Это сообщение отредактировал(а) Girder - 19.5.2005, 15:32


--------------------
Как слышим, так и пишим.
Истина где-то там...
PM   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0638 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.