Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.07.25;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.5 MB
Время: 0.036 c
4-1086088360
Stany
2004-06-01 15:12
2004.07.25
библиотека для программирования на API


10-1024206158
jo frodo
2002-06-16 09:42
2004.07.25
rebind() в INS


6-1085985359
Ske4er
2004-05-31 10:35
2004.07.25
TIpUDPClient


1-1089784951
stud
2004-07-14 10:02
2004.07.25
использование shellexecute


14-1089257648
Aldor_
2004-07-08 07:34
2004.07.25
Установка ХР





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский