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

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

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

Postby Augusto » Sun Jan 14, 2018 3:11 pm

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
Augusto
Active Poster
Active Poster
 
Posts: 10
Joined: Sun Jan 14, 2018 2:40 pm

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

Postby rlebeau » Mon Jan 15, 2018 11:23 am

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.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1508
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

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

Postby Augusto » Mon Jan 15, 2018 4:21 pm

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.
Augusto
Active Poster
Active Poster
 
Posts: 10
Joined: Sun Jan 14, 2018 2:40 pm

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

Postby rlebeau » Mon Jan 15, 2018 6:10 pm

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.
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1508
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

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

Postby Augusto » Tue Jan 16, 2018 2:19 am

rlebeau wrote:There are plenty of OnDrawCell examples floating around.

I'm already at work.
Augusto
Active Poster
Active Poster
 
Posts: 10
Joined: Sun Jan 14, 2018 2:40 pm

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

Postby Augusto » Thu Jan 18, 2018 12:59 pm

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
Augusto
Active Poster
Active Poster
 
Posts: 10
Joined: Sun Jan 14, 2018 2:40 pm

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

Postby rlebeau » Thu Jan 18, 2018 9:06 pm

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();
}
//---------------------------------------------------------------------------
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1508
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

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

Postby Augusto » Fri Jan 19, 2018 3:35 pm

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.
Augusto
Active Poster
Active Poster
 
Posts: 10
Joined: Sun Jan 14, 2018 2:40 pm


Return to Technical

Who is online

Users browsing this forum: Baidu [Spider], Bing [Bot], Google [Bot] and 7 guests