Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Алгоритм форматирования текста "По ширине" [D6, WinXP]


NailMan ©   (2004-07-11 23:40:00) 

Идея такая:

Пишется аналог листбокса для Direct3D9 приложения, так как в нем нельзя юзать VCL.

Как один из режимов отображения текста в листбоксе необходимо сделать аналог форматирования текста "По ширине"(слочвечко из MS Word), то есть чтобы слова в строке распределялись равномерно в ширине текстового окна. Также надо сделать простой перенос части строки (если он не влез в окно) на строчку(и) ниже.

Что имеется в наличии:
- текст загруженный в TStringList
- ширина окна(в пикселях) в котором текст отображается
- функция вычисления ширины(в пикселях) текста

Бился 2 дня, красивого решения придумать не смог. Хотя бы сделать перенос куска(ов) строки если он не влезает в окно.

Пробовал раскладывать строку на слова(разделение по пробелам) и анализировать суммарную ширину, последовательно складывая их - так пробелы которые в начале строки убиваются, и вообще запутался с циклами перебора.

Помогите алгоритмом(псевдо-кодом или куском кода если есть такой)...плз.


Григорьев Антон   (2004-07-13 16:42:00) [1]

Вот ещё один пример: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=171

В нём, кроме всего прочего, осуществляется перенос русских слов.


Григорьев Антон   (2004-07-13 16:34:00) [2]

Вот ещё один пример: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=171

В нём, кроме всего прочего, осуществляется перенос русских слов.


NailMan   (2004-07-13 16:03:00) [3]

KilkennyCat ©
Может и одно и тоже, но я написал весь ГУЙ и фактически пришел к системе с формой аля Delphi.
Эта бядяга с выравниванием потребовалась для создания
окошечка с текстом(типа ShowMessage), которое на основе урезанного листбокса(фактически из листбокса можно получить аналог TMemo) делается, а там надо в определенные границы влезть(не больше разрешения экрана).

---
WBR, NailMan aka 2:5020/3337.13


KilkennyCat   (2004-07-12 23:37:00) [4]


> NailMan ©   (12.07.04 10:41) [7]


Забавно, я тоже логфонт применил, там где точки - его код и был :)
Мы случайно не одно и тоже делаем? :))


> GrayFace ©   (12.07.04 07:19) [5]


Да вот, блин, просили комментарий заказчики... это еще что, это в начале основного кода, в конце я уже чуть ли не матом комментировал :)
За GetCharABCWidthsFloat спасибо, не знал.


> NAlexey ©   (12.07.04 09:19) [6]


К сожалению, в моем случае не помогло. Не помню уже почему, может скорость не понравилась, может еще что-то... В этом варианте получается итемс, что добавило положительного для дальнейшей работы.


NailMan   (2004-07-12 10:41:00) [5]

KilkennyCat ©
Пасиба за код, сегодня попробую применить к совей задаче.

GrayFace ©

> TextWidth может подвести с наклонным шрифтом(вылезет за
> границы области). Универсальное решение - через GetCharABCWidthsFloat.

Дело в том что я использую собственный растровый шрифт(3 разных высот), который всегда прямой, так что думаю с косым шрифтом проблемы нет, а вот эта функция не прокатит.

---
WBR, NailMan aka 2:5020/3337.13


NAlexey   (2004-07-12 09:19:00) [6]

Хм... А DrawText с DT_CALCRECT разве не поможет?


GrayFace   (2004-07-12 07:19:00) [7]

"Подробный и понятный комментарий" однако! ;-)
TextWidth может подвести с наклонным шрифтом(вылезет за границы области). Универсальное решение - через GetCharABCWidthsFloat.


KilkennyCat   (2004-07-12 00:39:00) [8]

да , еще: шрифт использовался боооольшой, поэтому иногда даже одно слово не вмещалось, оно здесь разрезается, без всяких грамм. правил.


KilkennyCat   (2004-07-12 00:32:00) [9]

// Перенос слов для скроллируемого текста
procedure TMain.wordwraps(tt : TMemoryStream);
var
 BMP : TBitMap;   // Вспомогательный, для определения размера строки
 NewText : tmemorystream; // Новый текст
 TestString : string; // Тестируемая строка
 Bukva : byte; // Байт чтения-записи
 l,ll : int64; // Метки, где можно сделать перенос слова
 Perenos : boolean; // Можно или нельзя переносить слово
const
 BK : word = 3338;  // Перевод строки
begin
 NewText := tmemorystream.Create; // Создаем поток для нового текста
 NewText.SetSize(0);              // и очищаем его (на всякий случай)
 TestString := ''; // Очищаем строку теста
 tt.position := 0; // Устанвливаемся в начало исходного текста
 Perenos := false; // Поскольку только начали, какие переносы?
 l := 0;
 ll := 0;
 bmp := tbitmap.Create; //Создаем битмап
 bmp.width := 1;   // Пусть не жрет память
 bmp.height := 1;
........................................
 setlength(scrolltext.Smes,tt.Size);
 // начали!!!
 repeat
   tt.ReadBuffer(Bukva,1); // Читаем первый байт
   if (Bukva = 13) then begin // А может это перевод строки?
     NewText.WriteBuffer(BK,1); // Точно, перевод. Пишем перевод в новый текст
     tt.ReadBuffer(Bukva,1); // Так как записали два, а прочитали один, компенсируем...
     Perenos := false; // Жизнь с новой строки, однако.
     TestString := '';
   end else begin   // не-а, не перевод... нормальная буква.
     TestString := TestString + chr(Bukva);// прибавим к тестовой строке
     if bmp.canvas.TextWidth(TestString) < 640 then begin // укладываемся в ширину?
       NewText.WriteBuffer(Bukva,1); // ага, уложились, значит добавим этот байтик в новый текст
       if pos(chr(Bukva),' ,.-=!?:;+') <> 0 then begin // а нет ли в тестовой строке символа-переноса?
         l := NewText.Position;  // Ура! есть! запомним это, что он есть, и его позиции в текстах
         ll := tt.Position;
         Perenos := true;
       end
     end else begin // в ширину не уложились. Будем делать перенос.
       if Perenos then begin //Были ли символы переноса?
         NewText.Position := l - 1; // Были. Откатываемся чуть дальше символа переноса
         tt.Position := ll - 1;
         tt.ReadBuffer(Bukva,1);  // Читаем из исходного текста это символ переноса
         NewText.WriteBuffer(Bukva,1); // Пишем его в новый текст
         NewText.WriteBuffer(BK,1); // Пишем в новый текст перевод строки
       end else begin  // Не было символа переноса текста. Режем слово.
         NewText.WriteBuffer(BK,1); //Пишем перенос строки в новый текст
         NewText.WriteBuffer(Bukva,1); //Продолжаем слово в новом тексте
       end;
       Perenos := false; // Перенос сделали
       TestString := ''; // Жизнь с новой строки, однако.
     end; // конец процесса переноса (в ширину не уложились. Будем делать перенос)
   end; // Конец процесса добавления буквы (не-а, не перевод... нормальная буква)
 until tt.Position > tt.Size - 1; // Проверим, не хватит ли начинать? может букв больше нет?
 NewText.Position := 0; // Возвращаемся в новом тексте в начало
 scrolltext.Text.Clear; // 0чищаем содержимое текста для скроллинга
 scrolltext.Text.loadfromstream(NewText); // Загружаем полученный текст
 scrolltext.Text.Insert(0,' '); //Добавляем пару пустых строк в начало (а то придется извращаться при скроллинге)
 scrolltext.Text.Insert(0,' ');
 scrolltext.Text.Insert(0,' '); // Строка-символ начала текста
 scrolltext.Text.Insert(0,' '); // Пивная! Еще парочку!
 scrolltext.Text.Insert(0,' ');
 scrolltext.Text.add(' ');  //Добавляем пару пустых строк в конец
 scrolltext.Text.add(' ');
 scrolltext.Text.add(' '); // Строка-символ конца текста
 scrolltext.Text.add(' '); // комментарии излишни
 scrolltext.Text.add(' ');
 // определяем высоту строки для основного окна (чего зря шрифту и битмапу пропадать?)
 Bhstr := bmp.Canvas.TextHeight('QWERTYUqwertyЯЧСМТЙЦУКЕячсмитьйцукеншщ'); // прочитайте это быстро :)
 bmp.Free;  // Ресурсам - свободу!
 NewText.Free;
end;


во... надо же, чего я налепил тогда :)))

да, на комментарии не обращайте особого внимания - просто при продаже требовали - написал... сейчас смотрю - поражаюсь... можно лучше.

Особенности алгоритма - если есть перевод строки - будет выполнен перевод, даже если строка может еще кучу вместить.


KilkennyCat   (2004-07-12 00:20:00) [10]

а, было и у меня такое...  я вначале использовал в 2D привязку канваса, и в нем уже текстоут, который позволял все это... потом отказался и сделал следующее: брал тест пословно, мерял при этом его ширину. Если ширина превышала ширину поверхности - последнее слово переводилось на следующую строку, полученная текущая стандартно позиционировалось вычислением разности ширин див 2.


KilkennyCat   (2004-07-12 00:20:00) [11]

щас, пощу код... старый проект-то...


Наверх

Титульная страница Поиск, карта сайта Написать письмо