Page 1 of 1

Is it possible to place multi-line text on a StringGrid?

PostPosted: Sun Jan 14, 2018 3:11 pm
by Augusto
Hi friends!

Is it possible to place Multi-Line text on a StringGrid?
I was unable to find a property specifying multi-line or word wrap for Cells.

Code:
Form9->StringGrid1->ColCount = 8;
Form9->StringGrid1->RowCount = 2;
Form9->StringGrid1->FixedCols = 0;
Form9->StringGrid1->FixedRows = 1;
Form9->StringGrid1->Cells[0][0] = L"Numero";
Form9->StringGrid1->Cells[1][0] = L"Diametro\nCu in mm";
Form9->StringGrid1->Cells[2][0] = L"Sezione\nin mmq";
Form9->StringGrid1->Cells[3][0] = L"Resistenza\na 20°C\nohm/Km";
Form9->StringGrid1->Cells[4][0] = L"Peso filo\ndi rame\nKgx1Km";
Form9->StringGrid1->Cells[5][0] = L"Diametro\nesterno\ngr1";
Form9->StringGrid1->Cells[6][0] = L"Diametro\nesterno\ngr2";
Form9->StringGrid1->Cells[7][0] = L"Diametro\nesterno\ngr3";
// \n inside the string does not work as expected
Example:
Please, see the attached image.
Thank you.
Image

Exist a simple way to search and found a property?

Best regards,
Augusto

Re: Is it possible to place multi-line text on a StringGrid?

PostPosted: Mon Jan 15, 2018 11:23 am
by rlebeau
Augusto wrote:Is it possible to place Multi-Line text on a StringGrid?
I was unable to find a property specifying multi-line or word wrap for Cells.


There is no such property. You must owner-draw the TStringGrid using its OnDrawCell event, then you can use the Win32 API DrawText() function with the DT_WORDBREAK flag to draw multi-line text onto the TStringGrid's Canvas in the specified rectangle.

Re: Is it possible to place multi-line text on a StringGrid?

PostPosted: Mon Jan 15, 2018 4:21 pm
by Augusto
rlebeau wrote:There is no such property. You must owner-draw the TStringGrid using its OnDrawCell event, then you can use the Win32 API DrawText() function with the DT_WORDBREAK flag to draw multi-line text onto the TStringGrid's Canvas in the specified rectangle.


I've never used Win32 APIs so I'll have to see how to do it.
Anyway I find it very interesting.

Thank you for not having published the code otherwise the pleasure of doing it alone would already be finished.
If I can do so I will return here to propose the code so that you check and if possible even improve it.

Thank you for the help that I greatly appreciated.

Re: Is it possible to place multi-line text on a StringGrid?

PostPosted: Mon Jan 15, 2018 6:10 pm
by rlebeau
Augusto wrote:Thank you for not having published the code otherwise the pleasure of doing it alone would already be finished.


There are plenty of OnDrawCell examples floating around.

Re: Is it possible to place multi-line text on a StringGrid?

PostPosted: Tue Jan 16, 2018 2:19 am
by Augusto
rlebeau wrote:There are plenty of OnDrawCell examples floating around.

I'm already at work.

Re: Is it possible to place multi-line text on a StringGrid?

PostPosted: Thu Jan 18, 2018 12:59 pm
by Augusto
rlebeau wrote:There are plenty of OnDrawCell examples floating around.


Hi Remy Lebeau,
inside the form I have added only one StringGrid:

Image

This is the code:
Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
   StringGrid1->ColCount = 8;
   StringGrid1->RowCount = 9;

   StringGrid1->FixedCols = 0;
   StringGrid1->FixedRows = 1;

   StringGrid1->ColWidths[0] = 60;
   StringGrid1->ColWidths[1] = 60;
   StringGrid1->ColWidths[2] = 60;
   StringGrid1->ColWidths[3] = 60;
   StringGrid1->ColWidths[4] = 60;
   StringGrid1->ColWidths[5] = 60;
   StringGrid1->ColWidths[6] = 60;
   StringGrid1->ColWidths[7] = 60;

   StringGrid1->RowHeights[0] = 60;
   StringGrid1->RowHeights[1] = 20;
   StringGrid1->RowHeights[2] = 20;
   StringGrid1->RowHeights[3] = 20;
   StringGrid1->RowHeights[4] = 20;
   StringGrid1->RowHeights[5] = 20;
   StringGrid1->RowHeights[6] = 20;
   StringGrid1->RowHeights[7] = 20;
   StringGrid1->RowHeights[8] = 20;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::StringGrid1DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
   int i, x, y;
   for (i = 0, x = 4; i < StringGrid1->ColCount; i++) {
      x += 1 + StringGrid1->ColWidths[i];
   }
   for (i = 0, y = 0; i < StringGrid1->RowCount; i++) {
      y += 1 + StringGrid1->RowHeights[i];
   }

   StringGrid1->ScrollBars = ssNone;
   StringGrid1->Width = x;
   StringGrid1->Height = y;

   UnicodeString L;
   UnicodeString S[8];
   S[0] = L"Numero";
   S[1] = L"Diametro\nCu in mm";
   S[2] = L"Sezione\nnominale\nin mmq";
   S[3] = L"Resistenza\nmedia a 25°C\nohm/Km";
   S[4] = L"Tipologia\ndi rame\nrosso";
   S[5] = L"Diametro\nesterno\nmassimo GR1";
   S[6] = L"Diametro\nesterno\nmassimo GR2";
   S[7] = L"Diametro\nesterno\nmassimo GR3";

   for (i = 0; i < StringGrid1->ColCount; i++) {
      L = S[i];
      RECT R = StringGrid1->CellRect(i, 0);
      StringGrid1->Canvas->Rectangle(R.left, R.top, R.right, R.bottom);

      StringGrid1->Canvas->Brush->Color = clBtnFace;
      StringGrid1->Canvas->FillRect(R);

      StringGrid1->Canvas->Pen->Color = clBtnHighlight;
      StringGrid1->Canvas->MoveTo((StringGrid1->ColWidths[i] * i) + i, 0);                                 //(0, 0);
      StringGrid1->Canvas->LineTo((StringGrid1->ColWidths[i] * (i + 1)) + i, 0);                              //(60, 0);
      StringGrid1->Canvas->MoveTo((StringGrid1->ColWidths[i] * i) + i, 0);                                 //(0, 0);
      StringGrid1->Canvas->LineTo((StringGrid1->ColWidths[i] * i) + i, StringGrid1->RowHeights[0]);               //(0, 60);

      StringGrid1->Canvas->Pen->Color = clBtnShadow;
      StringGrid1->Canvas->MoveTo((StringGrid1->ColWidths[i] * (i + 1) - 1) + i, 1);                           //(59, 1);
      StringGrid1->Canvas->LineTo((StringGrid1->ColWidths[i] * (i + 1) - 1) + i, StringGrid1->RowHeights[0]);         //(59, 60);
      StringGrid1->Canvas->MoveTo((StringGrid1->ColWidths[i] * i + 1) + i,  StringGrid1->RowHeights[0] - 1);         //(1, 59);
      StringGrid1->Canvas->LineTo((StringGrid1->ColWidths[i] * (i + 1) - 1) + i, StringGrid1->RowHeights[0] - 1);      //(59, 59);

      R.left += 2;
      R.top += 2;
      StringGrid1->Canvas->Font->Color = clWindowText;
      DrawText(StringGrid1->Canvas->Handle, L.c_str(), L.Length(), &R, DT_WORDBREAK);
   }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::StringGrid1Click(TObject *Sender)
{
   int i, j;
   for (i = 0; i < StringGrid1->ColCount; i++) {
      for (j = 1; j < StringGrid1->RowCount; j++) {
         StringGrid1->Cells[i][j] = L"C" + IntToStr(i) + L" - R" + IntToStr(j);
      }
   }
}
//---------------------------------------------------------------------------


This is the screenshot after run:

Image

This is the screenshot after a click on column 3, row 4:

Image

I hope the code can be useful to other code writers.

Please, check if is possible to improve something.
Thank you in advance.

Augusto

Re: Is it possible to place multi-line text on a StringGrid?

PostPosted: Thu Jan 18, 2018 9:06 pm
by rlebeau
Augusto wrote:This is the code:


DO NOT manipulate the StringGrid's properties while it is being painted, only manipulate its Canvas and nothing else. Your 3 property assignments in the OnDrawCell event (ScrollBars, Width, and Height) belong in your constructor instead, with the rest of the property assignments.

Inside the OnDrawCell event, use the TStringGrid::CellRect() method to get the rectangle of the cell that is currently being drawn, and draw ONLY that cell, no other cells.

Try something more like this instead:

Code: Select all
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
{
    StringGrid1->ColCount = 8;
    StringGrid1->RowCount = 9;

    StringGrid1->FixedCols = 0;
    StringGrid1->FixedRows = 1;

    for(int i = 0; i < StringGrid1->ColCount; ++i) {
        StringGrid1->ColWidths[i] = 60;
    }

    StringGrid1->RowHeights[0] = 60;
    for(int i = 1; i < StringGrid1->RowCount; ++i) {
        StringGrid1->RowHeights[i] = 20;
    }

    int x = 4, y = 0;
    for (int i = 0; i < StringGrid1->ColCount; i++) {
        x += (1 + StringGrid1->ColWidths[i]);
    }
    for (int i = 0; i < StringGrid1->RowCount; i++) {
        y += (1 + StringGrid1->RowHeights[i]);
    }

    StringGrid1->ScrollBars = ssNone;
    StringGrid1->Width = x;
    StringGrid1->Height = y;

    StringGrid1->Cells[0][0] = _D("Numero");
    StringGrid1->Cells[1][0] = _D("Diametro\nCu in mm");
    StringGrid1->Cells[2][0] = _D("Sezione\nnominale\nin mmq");
    StringGrid1->Cells[3][0] = _D("Resistenza\nmedia a 25°C\nohm/Km");
    StringGrid1->Cells[4][0] = _D("Tipologia\ndi rame\nrosso");
    StringGrid1->Cells[5][0] = _D("Diametro\nesterno\nmassimo GR1");
    StringGrid1->Cells[6][0] = _D("Diametro\nesterno\nmassimo GR2");
    StringGrid1->Cells[7][0] = _D("Diametro\nesterno\nmassimo GR3");
}
//---------------------------------------------------------------------------

void __fastcall TForm1::StringGrid1DrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
    TRect R = StringGrid1->CellRect(ACol, ARow);

    if (State.Contains(gdFixed))
    {
        StringGrid1->Canvas->Brush->Color = clBtnFace;
        StringGrid1->Canvas->Font->Color = clBtnText;
    }
    else if (State.Contains(gdSelected))
    {
        StringGrid1->Canvas->Brush->Color = clHighlight;
        StringGrid1->Canvas->Font->Color = clHighlightText;
    }
    else
    {
        StringGrid1->Canvas->Brush->Color = clWindow;
        StringGrid1->Canvas->Font->Color = clWindowText;
    }
    StringGrid1->Canvas->FillRect(R);

    if (State.Contains(gdFixed))
        Frame3D(StringGrid1->Canvas, R, clBtnHighlight, clBtnShadow, 1);

    InflateRect(&R, -2, -2); // or: R.Inflate(-2, -2);

    String L = StringGrid1->Cells[ACol][ARow];
    DrawText(StringGrid1->Canvas->Handle, L.c_str(), L.Length(), &R, DT_WORDBREAK);

    if (State.Contains(gdFocused))
    {
        InflateRect(&R, 1, 1); // or: R.Inflate(1, 1);
        StringGrid1->Canvas->DrawFocusRect(R);
    }
}
//---------------------------------------------------------------------------

void __fastcall TForm1::StringGrid1Click(TObject *Sender)
{
    for (int i = 0; i < StringGrid1->ColCount; i++) {
        for (int j = 1; j < StringGrid1->RowCount; j++) {
            StringGrid1->Cells[i][j] = _D("C") + IntToStr(i) + _D(" - R") + IntToStr(j);
        }
    }
    StringGrid1->Invalidate();
}
//---------------------------------------------------------------------------

Re: Is it possible to place multi-line text on a StringGrid?

PostPosted: Fri Jan 19, 2018 3:35 pm
by Augusto
rlebeau wrote: DO NOT manipulate the StringGrid's properties while it is being painted, only manipulate its Canvas and nothing else. Your 3 property assignments in the OnDrawCell event (ScrollBars, Width, and Height) belong in your constructor instead, with the rest of the property assignments.

Ok.

rlebeau wrote: Inside the OnDrawCell event, use the TStringGrid::CellRect() method to get the rectangle of the cell that is currently being drawn, and draw ONLY that cell, no other cells.

I don't know well VCL therefore I am going to study Grid and other more used controls.
One way is to buy old books, another is to search a lot of informations in internet.
The help inside the Rad is not good enough but I could be wrong.

Your code is clear and well written. Thank you.