Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.07.25;
Скачать: CL | DM;

Вниз

Алгоритм форматирования текста "По ширине"   Найти похожие ветки 

 
NailMan ©   (2004-07-11 23:40) [0]

Идея такая:

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

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

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

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

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

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


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

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


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

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


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

// Перенос слов для скроллируемого текста
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:39) [4]

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


 
GrayFace ©   (2004-07-12 07:19) [5]

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


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

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


 
NailMan ©   (2004-07-12 10:41) [7]

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

GrayFace ©

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

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

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


 
KilkennyCat ©   (2004-07-12 23:37) [8]


> 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-13 16:03) [9]

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

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


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

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

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


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

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

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



Страницы: 1 вся ветка

Текущий архив: 2004.07.25;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.041 c
11-1076696337
Владимир Кладов
2004-02-13 21:18
2004.07.25
Новый дизайн главного сайта KOL


1-1089520403
TUser
2004-07-11 08:33
2004.07.25
CreateProcess+AssignFile


1-1089435746
Глеб
2004-07-10 09:02
2004.07.25
Программное добавление в TMainMenu элементов


14-1089102042
DiamondShark
2004-07-06 12:20
2004.07.25
А меня вот сомненья мучают


9-1080968934
Voland2000
2004-04-03 09:08
2004.07.25
Движение спрайта