Автор: Pavel Stont
{ Код компонента для Delphi на основе стандартного TStringGrid. Компонет позволяет переносить текст в TStringGrid. В качестве исходного текста был использован компонент TWrapGrid. Автор Luis J. de la Rosa. E-mail: delarosa@ix.netcom.com Вы свободны в использовании, распространении и улучшении кода. Пожалуйста шлите любые комментарии и пожелания на адрес delarosa@ix.netcom.com. Далее были внесены изменения в исходный код, а именно добавлены методы вывода текста: 1. atLeft - Вывод текста по левой границе; 2. atCenter - Вывод текста по центру ячейки (по горизонтали); 3. atRight - Вывод текста по правой границе; 4. atWrapTop - Вывод и перенос текста по словам относительно верхней границы ячейки; 5. atWrapCenter - Вывод и перенос текста по словам относительно центра ячейки (по вертикали); 6. atWrapBottom - Вывод и перенос текста по словам относительно нижней границы ячейки; Вносил изменения и тестировал в Delphi 3/4/5: Автор Pavel Stont. E-mail: pavel_stont@mail.ru. Никаких ограничений на использование, распростанение и улучшение кода не налогаются. Буду очень признателен, если о всех замеченных неполадках сообщите по e-mail. Для использования: Выберите в Delphi пункты меню 'Options' - 'Install Components'. Нажмите 'Add'. Найдите и выберите файл с именем 'NewStringGrid.pas'. Нажмите 'OK'. После этого вы увидете компонент во вкладке "Other" палитры компонентов Delphi. После этого вы можете использовать компонент вместо стандартного TStringGrid. Успехов! Несколько дополнительных замечаний по коду: 1. Методы Create и DrawCell были перекрыты. 2. Введены два новых свойства, а именно AlignText и AlignCaption соответсвенно методы выравнивания текста в ячейках данных (обычно - белого цвета) и в фиксированных ячейках (обычно - серого цвета). 3. Свойство Center - центрация текста по горизонтали независимо от метода. } unit NewStringGrid; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids; type TAlignText = (atLeft, atCenter, atRight, atWrapTop, atWrapCenter, atWrapBottom); type TNewStringGrid = class(TStringGrid) private { Private declarations } FAlignText: TAlignText; FAlignCaption: TAlignText; FCenter: Boolean; procedure SetAlignText(Value: TAlignText); procedure SetAlignCaption(Value: TAlignText); procedure SetCenter(Value: Boolean); protected { Protected declarations } procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override; public { Public declarations } constructor Create(AOwner: TComponent); override; published { Published declarations } property AlignText: TAlignText read FAlignText write SetAlignText; property AlignCaption: TAlignText read FAlignCaption write SetAlignCaption; property Center: Boolean read FCenter write SetCenter; end; procedure Register; implementation procedure Register; begin RegisterComponents('Other', [TNewStringGrid]); end; { TNewStringGrid } constructor TNewStringGrid.Create(AOwner: TComponent); begin { Создаем TStringGrid } inherited Create(AOwner); { Задаем начальные параметры компонента } AlignText := atLeft; AlignCaption := atCenter; Center := False; DefaultColWidth := 80; DefaultRowHeight := 18; Height := 100; Width := 408; { Заставляем компонент перерисовываться нашей процедурой по умолчанию DrawCell } DefaultDrawing := FALSE; end; { Процедура DrawCell осуществляет перенос текста в ячейке } procedure TNewStringGrid.DrawCell(ACol, ARow: Integer; ARect: TRect; AState: TGridDrawState); var CountI, { Счетчик } CountWord: Integer; { Счетчик } Sentence, { Выводимый текст } CurWord: string; { Текущее выводимое слово } SpacePos, { Позиция первого пробела } CurXDef, { X-координата 'курсора' по умолчанию } CurYDef, { Y-координата 'курсора' по умолчанию } CurX, { Х-координата 'курсора' } CurY: Integer; { Y-координата 'курсора' } EndOfSentence: Boolean; { Величина, указывающая на заполненность ячейки } Alig: TAlignText; { Тип выравнивания текста } ColPen: TColor; { Цвет карандаша по умолчанию } MassWord: array[0..255] of string; MassCurX, MassCurY: array[0..255] of Integer; LengthText: Integer; { Длина текущей строки } MassCurYDef: Integer; MeanCurY: Integer; procedure VisualCanvas; begin { Прорисовываем ячейку и придаем ей 3D-вид } with Canvas do begin { Запоминаем цвет пера для последующего вывода текста } ColPen := Pen.Color; if gdFixed in AState then begin Pen.Color := clWhite; MoveTo(ARect.Left, ARect.Top); LineTo(ARect.Left, ARect.Bottom); MoveTo(ARect.Left, ARect.Top); LineTo(ARect.Right, ARect.Top); Pen.Color := clBlack; MoveTo(ARect.Left, ARect.Bottom); LineTo(ARect.Right, ARect.Bottom); MoveTo(ARect.Right, ARect.Top); LineTo(ARect.Right, ARect.Bottom); end; { Восстанавливаем цвет пера } Pen.Color := ColPen; end; end; procedure VisualBox; begin { Инициализируем шрифт, чтобы он был управляющим шрифтом } Canvas.Font := Font; with Canvas do begin { Если это фиксированная ячейка, тогда используем фиксированный цвет } if gdFixed in AState then begin Pen.Color := FixedColor; Brush.Color := FixedColor; end { в противном случае используем нормальный цвет } else begin Pen.Color := Color; Brush.Color := Color; end; { Рисуем подложку цветом ячейки } Rectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom); end; end; procedure VisualText(Alig: TAlignText); begin case Alig of atLeft: begin with Canvas do { выводим текст } TextOut(CurX, CurY, Sentence); VisualCanvas; end; atRight: begin with Canvas do { выводим текст } TextOut(ARect.Right - TextWidth(Sentence) - 2, CurY, Sentence); VisualCanvas; end; atCenter: begin with Canvas do { выводим текст } TextOut(ARect.Left + ((ARect.Right - ARect.Left - TextWidth(Sentence)) div 2), CurY, Sentence); VisualCanvas; end; atWrapTop: begin { для каждого слова ячейки } EndOfSentence := FALSE; CountI := 0; while CountI <= SpacePos do begin MassWord[CountI] := ''; CountI := CountI + 1; end; CountI := 0; CountWord := CurY; while (not EndOfSentence) do begin { для получения следующего слова ищем пробел } SpacePos := Pos(' ', Sentence); if SpacePos > 0 then begin { получаем текущее слово плюс пробел } CurWord := Copy(Sentence, 0, SpacePos); { получаем остальную часть предложения } Sentence := Copy(Sentence, SpacePos + 1, Length(Sentence) - SpacePos); end else begin { это - последнее слово в предложении } EndOfSentence := TRUE; CurWord := Sentence; end; with Canvas do begin { если текст выходит за границы ячейки } LengthText := TextWidth(CurWord) + CurX + 2; if LengthText > ARect.Right then begin { переносим на следующую строку } CurY := CurY + TextHeight(CurWord); CurX := CurXDef + 2; end; if CountWord <> CurY then CountI := CountI + 1; MassWord[CountI] := MassWord[CountI] + CurWord; { увеличиваем X-координату курсора } CurX := CurX + TextWidth(CurWord); CountWord := CurY; end; end; with Canvas do begin CountWord := 0; CurY := CurYDef + 2; CurX := CurXDef + 2; while CountWord <= CountI do begin case Center of True: begin CurWord := MassWord[CountWord]; if Copy(CurWord, Length(CurWord) - 1, 1) = ' ' then MassWord[CountWord] := Copy(CurWord, 0, Length(CurWord) - 1); MassCurX[CountWord] := ARect.Left + ((ARect.Right - ARect.Left - TextWidth(MassWord[CountWord])) div 2); MassWord[CountWord] := CurWord; end; False: MassCurX[CountWord] := CurX; end; MassCurY[CountWord] := CurY; { выводим слово } TextOut(MassCurX[CountWord], MassCurY[CountWord], MassWord[CountWord]); CurY := CurY + TextHeight(MassWord[CountWord]); CountWord := CountWord + 1; end; end; VisualCanvas; end; atWrapCenter: begin { для каждого слова ячейки } EndOfSentence := FALSE; CountI := 0; while CountI <= SpacePos do begin MassWord[CountI] := ''; CountI := CountI + 1; end; CountI := 0; CountWord := CurY; while (not EndOfSentence) do begin { для получения следующего слова ищем пробел } SpacePos := Pos(' ', Sentence); if SpacePos > 0 then begin { получаем текущее слово плюс пробел } CurWord := Copy(Sentence, 0, SpacePos); { получаем остальную часть предложения } Sentence := Copy(Sentence, SpacePos + 1, Length(Sentence) - SpacePos); end else begin { это - последнее слово в предложении } EndOfSentence := TRUE; CurWord := Sentence; end; with Canvas do begin { если текст выходит за границы ячейки } LengthText := TextWidth(CurWord) + CurX + 2; if LengthText > ARect.Right then begin { переносим на следующую строку } CurY := CurY + TextHeight(CurWord); CurX := CurXDef + 2; end; if CountWord <> CurY then CountI := CountI + 1; MassWord[CountI] := MassWord[CountI] + CurWord; { увеличиваем X-координату курсора } CurX := CurX + TextWidth(CurWord); CountWord := CurY; end; end; with Canvas do begin CountWord := 0; CurX := CurXDef + 2; while CountWord <= CountI do begin case Center of True: begin CurWord := MassWord[CountWord]; if Copy(CurWord, Length(CurWord) - 1, 1) = ' ' then MassWord[CountWord] := Copy(CurWord, 0, Length(CurWord) - 1); MassCurX[CountWord] := ARect.Left + ((ARect.Right - ARect.Left - TextWidth(MassWord[CountWord])) div 2); MassWord[CountWord] := CurWord; end; False: MassCurX[CountWord] := CurX; end; MassCurY[CountWord] := TextHeight(MassWord[CountWord]); CountWord := CountWord + 1; end; CountWord := 0; MassCurYDef := 0; while CountWord <= CountI do begin MassCurYDef := MassCurYDef + MassCurY[CountWord]; CountWord := CountWord + 1; end; MassCurYDef := (ARect.Bottom - ARect.Top - MassCurYDef) div 2; CountWord := 0; MeanCurY := 0; while CountWord <= CountI do begin MassCurY[CountWord] := ARect.Top + MeanCurY + MassCurYDef; MeanCurY := MeanCurY + TextHeight(MassWord[CountWord]); CountWord := CountWord + 1; end; CountWord := -1; while CountWord <= CountI do begin CountWord := CountWord + 1; if MassCurY[CountWord] < (ARect.Top + 2) then Continue; { выводим слово } TextOut(MassCurX[CountWord], MassCurY[CountWord], MassWord[CountWord]); end; end; VisualCanvas; end; atWrapBottom: begin { для каждого слова ячейки } EndOfSentence := FALSE; CountI := 0; while CountI <= SpacePos do begin MassWord[CountI] := ''; CountI := CountI + 1; end; CountI := 0; CountWord := CurY; while (not EndOfSentence) do begin { для получения следующего слова ищем пробел } SpacePos := Pos(' ', Sentence); if SpacePos > 0 then begin { получаем текущее слово плюс пробел } CurWord := Copy(Sentence, 0, SpacePos); { получаем остальную часть предложения } Sentence := Copy(Sentence, SpacePos + 1, Length(Sentence) - SpacePos); end else begin { это - последнее слово в предложении } EndOfSentence := TRUE; CurWord := Sentence; end; with Canvas do begin { если текст выходит за границы ячейки } LengthText := TextWidth(CurWord) + CurX + 2; if LengthText > ARect.Right then begin { переносим на следующую строку } CurY := CurY + TextHeight(CurWord); CurX := CurXDef + 2; end; if CountWord <> CurY then CountI := CountI + 1; MassWord[CountI] := MassWord[CountI] + CurWord; { увеличиваем X-координату курсора } CurX := CurX + TextWidth(CurWord); CountWord := CurY; end; end; with Canvas do begin CountWord := 0; CurX := CurXDef + 2; while CountWord <= CountI do begin case Center of True: begin CurWord := MassWord[CountWord]; if Copy(CurWord, Length(CurWord) - 1, 1) = ' ' then MassWord[CountWord] := Copy(CurWord, 0, Length(CurWord) - 1); MassCurX[CountWord] := ARect.Left + ((ARect.Right - ARect.Left - TextWidth(MassWord[CountWord])) div 2); MassWord[CountWord] := CurWord; end; False: MassCurX[CountWord] := CurX; end; MassCurY[CountWord] := TextHeight(MassWord[CountWord]); CountWord := CountWord + 1; end; CountWord := 0; MassCurYDef := 0; while CountWord <= CountI do begin MassCurYDef := MassCurYDef + MassCurY[CountWord]; CountWord := CountWord + 1; end; MassCurYDef := ARect.Bottom - MassCurYDef - 2; CountWord := 0; MeanCurY := -MassCurY[CountWord]; while CountWord <= CountI do begin MeanCurY := MeanCurY + MassCurY[CountWord]; MassCurY[CountWord] := MassCurYDef + MeanCurY; CountWord := CountWord + 1; end; CountWord := -1; while CountWord <= CountI do begin CountWord := CountWord + 1; if MassCurY[CountWord] < (ARect.Top + 2) then Continue; { выводим слово } TextOut(MassCurX[CountWord], MassCurY[CountWord], MassWord[CountWord]); end; end; VisualCanvas; end; end; end; begin VisualBox; VisualCanvas; { Начинаем рисование с верхнего левого угла ячейки } CurXDef := ARect.Left; CurYDef := ARect.Top; CurX := CurXDef + 2; CurY := CurYDef + 2; { Здесь мы получаем содержание ячейки } Sentence := Cells[ACol, ARow]; { Если ячейка пуста выходим из процедуры } if Sentence = '' then Exit; { Проверяем длину строки (не более 256 символов) } if Length(Sentence) > 256 then begin MessageBox(0, 'Число символов не должно быть более 256.', 'Ошибка в таблице', mb_OK); Cells[ACol, ARow] := ''; Exit; end; { Узнаем сколько в предложении слов и задаем размерность массивов } SpacePos := Pos(' ', Sentence); { Узнаем тип выравнивания текста } if gdFixed in AState then Alig := AlignCaption else Alig := AlignText; VisualText(Alig); end; procedure TNewStringGrid.SetAlignCaption(Value: TAlignText); begin if Value <> FAlignCaption then FAlignCaption := Value; end; procedure TNewStringGrid.SetAlignText(Value: TAlignText); begin if Value <> FAlignText then FAlignText := Value; end; procedure TNewStringGrid.SetCenter(Value: Boolean); begin if Value <> FCenter then FCenter := Value; end; end.