Текст выглядит лучше, если он выровнен по двух краям. Для этого пробелы в каждой строке нужно удлинять или укорачивать так, чтобы все строки имели одну длину.
Здесь создана процедура GetLine, которая возвращает одну строку, начиная с заданного символа. Программа находит разницу между шириной текста и реальной длинной строки и при выводе компенсирует эту разницу удлинением пробелов.
Эта программа выводит на экран текст из файла C:\text.txt, выравнивая его по двум краям.
type
...
TLine = record
s: string;
wrap: boolean;
length: integer;
end;
var
Form1: TForm1;
implementation{$R *.DFM}const
FileName = 'C:\text.txt';
var
s: string;
bm: TBitMap;
LineH: integer;
MaxTextWidth: integer;
procedure TForm1.FormCreate(Sender: TObject);
var
F: TFileStream;
buf: array [0..127] of char;
l: integer;
begin
ScrollBar1.Kind := sbVertical;
bm := TBitMap.Create;
with bm.Canvas.Font dobeginname := 'Serif';
Size := 12;
end;
LineH := bm.Canvas.TextHeight('123');
ifnot FileExists(FileName) thenbegin
ShowMessage('Can not find file ' + FileName);
Exit;
end;
F := TFileStream.Create(FileName, fmOpenRead);
repeat
l := F.read(buf, 128);
if l = 128 then
s := s + buf
else
s := s + copy(buf, 1, l);
until
l < 128;
F.Destroy;
end;
procedure TForm1.FormResize(Sender: TObject);
begin
PaintBox1.Left := 0;
PaintBox1.Top := 0;
PaintBox1.Height := Form1.ClientHeight;
PaintBox1.Width := Form1.ClientWidth - ScrollBar1.Width;
ScrollBar1.Left := PaintBox1.Width;
ScrollBar1.Top := 0;
ScrollBar1.Height := PaintBox1.Height;
bm.Width := PaintBox1.Width;
bm.Height := PaintBox1.Height;
ScrollBar1.Max := 1000;
MaxTextWidth := PaintBox1.Width - 20;
end;
function RealTextWidth(s: string): integer;
var
i: integer;
begin
result := bm.Canvas.TextWidth(s);
for i := 1 to Length(s) doif s[i] = #9 then
inc(result, 40 - bm.Canvas.TextWidth(#9));
end;
function GetLine(index: integer): TLine;
var
i: integer;
s1: string;
first: integer;
beginif (s[index] = #13) and (s[index + 1] = #10) thenbegin
result.s := '';
result.length := 2;
result.wrap := true;
Exit;
end;
first := index;
while (first <= Length(s)) and (s[first] in [#32]) do
inc(first);
i := first;
repeatwhile (i <= Length(s)) and (not (s[i] in [#9, #32])) and (s[i] <> #13) do
inc(i);
s1 := copy(s, first, i - index);
inc(i);
until
(i >= Length(s)) or (s[i-1] = #13) or (RealTextWidth(s1) > MaxTextWidth);
if RealTextWidth(s1) > MaxTextWidth thenbegin
result.wrap := false;
if i < Length(s) thenbegin
dec(i, 2);
while (i > 0) and (not (s[i] in [#9, #32])) do
dec(i);
result.Length := i - index;
while (i > 0) and (s[i] in [#9, #32]) do
dec(i);
end;
result.s := copy(s, first, i - index + 1);
if result.s[length(result.s)] = #32 then
delete(result.s, length(result.s) , 1);
endelsebegin
result.length := i - index + 1;
s1 := copy(s, first, i - index + 1);
if length(s1) > 0 thenbeginif s1[Length(s1)] = #9 then
delete(s1, Length(s1), 1);
if s1[length(s1) - 1] + s1[length(s1)] = #13#10 then
delete(s1, length(s1) - 1, 2);
end;
result.s := s1;
result.wrap := true;
end;
end;
procedure draw;
var
i, j: integer;
line: TLine;
OneWord: string;
LineN: integer;
SpaceCount: integer;
TextLeft: integer;
shift, allshift: integer;
d: integer;
LineCount: integer;
beginwith bm.Canvas dobegin
FillRect(ClipRect);
i := 1;
LineCount := 0;
for j := 1 to Form1.ScrollBar1.Position dobegin
line := GetLine(i);
inc(i, line.length);
inc(LineCount);
end;
LineN := 0;
repeat
line := GetLine(i);
SpaceCount := 0;
TextLeft := 0;
for j := 1 to Length(line.s) doif line.s[j] = #32 then
inc(SpaceCount);
if line.wrap = false then
allshift := MaxTextWidth - RealTextWidth(line.s)
else
allshift := 0;
if allshift > 40 * SpaceCount then
allshift := 0;
shift := 0;
for j := 1 to Length(line.s) dobeginif (not (line.s[j] in [#9, #32])) and (j < Length(line.s)) thenbegin
OneWord := OneWord + line.s[j];
endelsebegin
OneWord := OneWord + line.s[j];
if OneWord = #9 thenbegin
inc(TextLeft, 40);
endelsebeginif OneWord = #13#10 thenbegin
inc(LineN);
endelsebegin
TextOut(10 + TextLeft, LineN * LineH, OneWord);
if SpaceCount = 0 then
d := 0
else
d := (allshift - shift) div (SpaceCount);
inc(shift, d);
inc(TextLeft, TextWidth(OneWord) + d);
dec(SpaceCount);
end;
end;
OneWord := '';
end;
end;
inc(i, line.length);
inc(LineN);
until
(LineN * LineH > Form1.PaintBox1.Height) or (i >= Length(s));
repeat
line := GetLine(i);
inc(i, line.length);
inc(LineCount);
until
i >= Length(s);
inc(LineCount, LineN);
Form1.ScrollBar1.Max := LineCount -
Form1.PaintBox1.Height div LineH;
end;
Form1.PaintBox1.Canvas.Draw(0, 0, bm);
end;
procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
draw;
end;
procedure TForm1.ScrollBar1Change(Sender: TObject);
begin
draw;
end;
Рецензия кода и предложения по улучшению:
Функциональность
Программа читает текстовый файл, разбивает его на строки и затем обертывает каждую строку для вставки в указанный ширина. Обертка выполняется путем вставки пробелов в конце каждой строки до тех пор, пока строка не будет вставлена в указанную ширину.
Организация кода
Код организован в несколько процедур, включая FormCreate, FormResize, GetLine, draw, PaintBox1Paint и ScrollBar1Change. Это делает код легко читаемым и понятным. Однако некоторые из этих процедур выполняют несколько связанных задач, что может сделать их более сложными для понимания.
Предложения по улучшению
Разделение забот: Рассмотрите разделение логики на отдельные единицы или классы, каждый ответственный за конкретную задачу. Например, вы могли бы иметь один класс для чтения текстового файла, другой для обертывания строк и третий для рисования обернутых строк.
Использование констант: Вместо использования жестко закодированных значений, таких как 40 (ширина пробела) или 12 (размер шрифта), рассмотрите определение их как констант вверху единицы.
Улучшение читаемости кода: Некоторые процедуры имеют длинные имена и сложный логик, что может сделать код более трудным для чтения и понимания. Рассмотрите разбиение этих процедур на более управляемые части.
Использование типовых указателей: Delphi поддерживает типовые указатели, которые могут сделать код более читаемым,explicitly指定ая типы переменных и параметров.
Обработка ошибок: Программа не обрабатывает ошибки хорошо. Например, если файл не может быть прочитан или размер шрифта является недопустимым, программа будет терминироваться внезапно. Рассмотрите добавление блоков try-except для обработки этих ситуаций более надежно.
Рецензия кода
Вот некоторые конкретные комментарии к коду:
В FormCreate, вы создаете объект TBitMap и затем сразу же присваиваете его локальной переменной. Вы могли бы упростить это, создавая объект TBitMap напрямую в локальной переменной.
В GetLine, у вас есть сложный цикл, который перебирает символы строки, проверяя различные условия (например, является ли символ пробелом или новой строкой). Рассмотрите разбиение этого цикла на более управляемые части.
В draw, у вас есть длинная процедура с многоуровневыми циклами и условными операторами. Это может сделать код трудным для чтения и понимания. Рассмотрите разбиение этой процедуры на более управляемые части.
В целом, код выглядит как если бы он был хорошо организован и легко читаемым. Однако есть некоторые области, где логика могла быть улучшена, и код мог быть сделан более легким для чтения и поддержки.
Выравнивание текста по ширине в программе на Delphi, схожее с выравниванием в Microsoft Word.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.