procedure TForm1.Button1Click(Sender: TObject);
var K: Double;
begin
Printer.BeginDoc;
K := Printer.Canvas.Font.PixelsPerInch / Canvas.Font.PixelsPerInch*1.2;
PrintStringGrid(StrGrid,
K, // Коэффициент
200, // отступ от края листа в пихелах по Х
200, // --"-- по Y
200 // отступ снизу
);
Printer.EndDoc;
end;
{----------------------------------------------------------}unit GrdPrn3;
interfaceuses
Windows, Classes, Graphics, Grids, Printers, SysUtils;
const
OrdinaryLineWidth: Integer = 2;
BoldLineWidth: Integer = 4;
procedure PrintStringGrid(Grid: TStringGrid; Scale: Double; LeftMargin,
TopMargin, BottomMargin:
Integer);
function DrawStringGridEx(Grid: TStringGrid; Scale: Double; FromRow,
LeftMargin, TopMargin, Yfloor: Integer; DestCanvas: TCanvas): Integer;
// возвращает номер строки, которая не поместилась до Y = Yfloor// не проверяет, вылезает ли общая длина таблицы за пределы страницы// Слишком длинное слово обрежетсяimplementationprocedure PrintStringGrid(Grid: TStringGrid; Scale: Double; LeftMargin,
TopMargin, BottomMargin: Integer);
var NextRow: Integer;
begin//Printer.BeginDoc;ifnot Printer.Printing thenraise Exception.Create('function
PrintStringGrid must be called between Printer.BeginDoc
and Printer.EndDoc');
NextRow := 0;
repeat
NextRow := DrawStringGridEx(Grid, Scale, NextRow, LeftMargin, TopMargin,
Printer.PageHeight - BottomMargin, Printer.Canvas);
if NextRow <> -1 then Printer.NewPage;
until NextRow = -1;
//Printer.EndDoc;end;
function DrawStringGridEx(Grid: TStringGrid; Scale: Double; FromRow,
LeftMargin, TopMargin, Yfloor: Integer; DestCanvas: TCanvas): Integer;
// возвращает номер строки, которая не поместилась до Y = Yfloorvar
i, j, d, TotalPrevH, TotalPrevW, CellH, CellW, LineWidth: Integer;
R: TRect;
s: string;
procedure CorrectCellHeight(ARow: Integer);
// вычисление правильной высоты ячейки с учетом многострочного текста// Текст рабивается только по словам слишком длинное слово обрубаетсяvar
i, H: Integer;
R: TRect;
s: string;
begin
R := Rect(0, 0, CellH*2, CellH);
s := ':)'; // Одинарная высота строки
CellH := DrawText(DestCanvas.Handle, PChar(s), Length(s), R,
DT_LEFT or DT_TOP or DT_WORDBREAK or DT_SINGLELINE or
DT_NOPREFIX or DT_CALCRECT) + 3*d;
for i := 0 to Grid.ColCount-1 dobegin
CellW := Round(Grid.ColWidths[i]*Scale);
R := Rect(0, 0, CellW, CellH);
//InflateRect(R, -d, -d);
R.Left := R.Left+d;
R.Top := R.Top + d;
s := Grid.Cells[i, ARow];
// Вычисление ширины и высоты
H := DrawText(DestCanvas.Handle, PChar(s), Length(s), R,
DT_LEFT or DT_TOP or DT_WORDBREAK or DT_NOPREFIX or DT_CALCRECT);
текста
if CellH < H + 2*d then CellH := H + 2*d;
// if CellW < R.Right - R.Left then Слишком длинное слово -// не помещается в одну строку; Перенос слов не поддерживаетсяend;
end;
begin
Result := -1; // все строки уместились между TopMargin и Yfloorif (FromRow < 0)or(FromRow >= Grid.RowCount) then Exit;
DestCanvas.Brush.Style := bsClear;
DestCanvas.Font := Grid.Font;
// DestCanvas.Font.Height := Round(Grid.Font.Height*Scale);
DestCanvas.Font.Size := 10;
Grid.Canvas.Font := Grid.Font;
Scale := DestCanvas.TextWidth('test')/Grid.Canvas.TextWidth('test');
d := Round(2*Scale);
TotalPrevH := 0;
for j := 0 to Grid.RowCount-1 dobeginif (j >= Grid.FixedRows) and (j < FromRow) then Continue;
// Fixed Rows рисуются на каждой странице
TotalPrevW := 0;
CellH := Round(Grid.RowHeights[j]*Scale);
CorrectCellHeight(j);
if TopMargin + TotalPrevH + CellH > YFloor thenbegin
Result := j; // j-я строка не помещается в заданный диапазонif Result < Grid.FixedRows then Result := -1;
// если фиксированные строки не влезают на страницу -// это тяж¸лый случай...
Exit;
end;
for i := 0 to Grid.ColCount-1 dobegin
CellW := Round(Grid.ColWidths[i]*Scale);
R := Rect(TotalPrevW, TotalPrevH, TotalPrevW + CellW,
otalPrevH + CellH);
OffSetRect(R, LeftMargin, TopMargin);
if (i < Grid.FixedCols)or(j < Grid.FixedRows) then
LineWidth := BoldLineWidth
else
LineWidth := OrdinaryLineWidth;
DestCanvas.Pen.Width := LineWidth;
if LineWidth > 0 then
DestCanvas.Rectangle(R.Left, R.Top, R.Right+1, R.Bottom+1);
//InflateRect(R, -d, -d);
R.Left := R.Left+d;
R.Top := R.Top + d;
s := Grid.Cells[i, j];
DrawText(DestCanvas.Handle, PChar(s), Length(s), R,
DT_LEFT or DT_TOP or DT_WORDBREAK or DT_NOPREFIX);
TotalPrevW := TotalPrevW + CellW; // Общая ширина всех предыдущих колонокend;
TotalPrevH := TotalPrevH + CellH; // Общая высота всех предыдущих строкend;
end;
end.
Перевод контента на русский язык:
Код - часть приложения Delphi, печатающего TStringGrid на принтере. Главная процедура PrintStringGrid занимается печатанием грида, а функция DrawStringGridEx делает фактическое рисование.
Вот некоторые наблюдения и предложения:
В процедуре PrintStringGrid не обрабатывается ошибка, если принтер не находится в режиме печати. Это может привести к неожиданному поведению.
Функция DrawStringGridEx использует рекурсивный подход для рисования грида. Хотя это может работать для маленьких гридов, оно может потенциально вызвать переполнение стека для более крупных гридов. Более эффективным подходом будет использовать цикл вместо рекурсии.
В процедуре CorrectCellHeight нет проверки, была ли уже рассчитана высота ячейки для данной строки. Это может привести к неправильным расчетам, если та же строка обрабатывается несколько раз.
Функция DrawStringGridEx использует функцию DrawText из Windows API для рисования текста в каждой ячейке. Хотя это работает, это может не быть самым эффективным или гибким подходом. Реализация рисования текста с помощью custom-implementation даст больше контроля над внешним видом и расположением грида.
Нет проверки на переполнение при расчете общей ширины строки. Если строка имеет слишком много ячеек с длинным текстом, это может привести к неправильным расчетам и потенциально вызвать переполнение.
Вот альтернативный подход с использованием цикла вместо рекурсии:
functionDrawStringGridEx(Grid:TStringGrid;Scale:Double;FromRow,LeftMargin,TopMargin,Yfloor:Integer;DestCanvas:TCanvas):Integer;vari,j,d,CellH,CellW,LineWidth:Integer;R:TRect;s:string;beginResult:=-1;// все строки поместятся между TopMargin и Yfloorif(FromRow<0)or(FromRow>=Grid.RowCount)thenExit;DestCanvas.Brush.Style:=bsClear;DestCanvas.Font:=Grid.Font;forj:=FromRowtoHigh(Grid.RowCount)dobeginCellH:=Round(Grid.RowHeights[j]*Scale);CorrectCellHeight(j);ifTopMargin+TotalPrevH+CellH>YFloorthenbeginResult:=j;// j-ая строка не поместится в заданном диапазонеExit;end;fori:=0toGrid.ColCount-1dobeginCellW:=Round(Grid.ColWidths[i]*Scale);R:=Rect(TotalPrevW,TotalPrevH,TotalPrevW+CellW,TopMargin+TotalPrevH+CellH);OffsetRect(R,LeftMargin,0);if(i<Grid.FixedCols)or(j<Grid.FixedRows)thenLineWidth:=BoldLineWidthelseLineWidth:=OrdinaryLineWidth;DestCanvas.Pen.Width:=LineWidth;ifLineWidth>0thenDestCanvas.Rectangle(R.Left,R.Top,R.Right+1,R.Bottom+1);s:=Grid.Cells[i,j];DrawText(DestCanvas.Handle,PChar(s),Length(s),R,DT_LEFTorDT_TOPorDT_WORDBREAKorDT_NOPREFIX);TotalPrevW:=TotalPrevW+CellW;// общая ширина всех предыдущих столбцовend;TotalPrevH:=TopMargin+TotalPrevH+CellH;// общая высота всех предыдущих строкend;end;
Этот код делает то же самое, что и оригинальная функция, но в более эффективном и рекурсивно- свободном виде.
В статье описано, как использовать компонент StringGrid для печати таблицы с помощью приложения Delphi и как обеспечить корректное отображение текста в зависимости от ширины и высоты ячеек.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.