Durante le prove di produzione di una StringGrid con righe di testa, di fine e di dettaglio, mi sono imbattuto in un inaspettato cambio di Font, come si può vedere nell'immagine allegata.
Come faccio di solito, le righe di testa o di fine di una mia StringGrid presentano le loro celle con colori di fondo e di testo diversi dalle righe di dettaglio ed a volte anche con uno style di tipo Bold.
Nella StringGrid attuale ho utilizzato per le singole celle il Font Noto Mono grande 11 e di stile Regolare
Dentro l'evento OnDrawCell ho intercettato quello relativo ad alcune celle dellle righe di Testa e di Fine della StringGrid per impostare uno stile Bold del Testo ed un colore diverso per lo sfondo ed testo:
procedure TForm6.GridStmpDrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
type
Tsfondo = TColor;
const
grigio: Tsfondo = clGray;
var
lun: Integer;
ixRg: Integer = 0;
cellaSel: String;
allin : TTextStyle; // tipo di allineamento
begin
if (aRow >= 1) then
begin
case aCol of
2, 3, 4, 5:
begin
cellaSel:= GridStmp.Cells[aCol, aRow]; // punta alla casella selezionata
ixRg:= aRow;
if (GridStmp.Cells[1, aRow] = '') and (GridStmp.Cells[3, aRow] = '') and (GridStmp.Cells[4, aRow] = '') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
allin.Alignment:= taLeftJustify;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.Font.Color:= clBlack; // colora il testo
GridStmp.Canvas.Font.Height:= 14;
GridStmp.Canvas.TextRect(aRect, aRect.Left + 2, aRect.Top + 6, CellaSel, allin); // riscrive il testo nella casella
end
else begin
if (GridStmp.Cells[2, aRow] = 'TOT.Sottoconto') or (GridStmp.Cells[2, aRow] = 'TOTALI Conto') or (GridStmp.Cells[2, aRow] = 'T O T A L I') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
allin.Alignment:= taRightJustify;
GridStmp.Canvas.Brush.Color := grigio;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.Font.Color:= clWhite; // colora il testo
GridStmp.Canvas.Font.Name:= 'Noto Mono';
GridStmp.Canvas.Font.Height:= 14;
GridStmp.Canvas.TextRect(aRect, aRect.Right + 12, aRect.Top + 2, CellaSel, allin); // riscrive il testo nella casella
end;
end;
end;
end;
end;
end;
Ebbene in tutte le celle interessate mi sono ritrovato il Font diverso da quello che avevo impostato io nella fase di disegno della StringGrid, con conseguente disallineamento dei valori monetari presenti nelle righe di dettaglio.
Ho provato a reimpostarlo da codice, dentro l'evento OnDrawCell, ma non ci sono riuscito.
Mi potreste illuminare in proposito?
Se definisci il Font.Name per qualche cella, allora lo devi definire anche in TUTTE le altre celle, perchè non sai la canvas con che sequenza "disegnerà" le celle.
Ho seguito il tuo consiglio:
procedure TForm6.GridStmpDrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
type
Tsfondo = TColor;
const
grigio: Tsfondo = clGray;
var
lun: Integer;
ixRg: Integer = 0;
cellaSel: String;
allin : TTextStyle; // tipo di allineamento
begin
WriteLn('TForm6.GridStmpDrawCell');
if (aRow >= 1) then
begin
case aCol of
2, 3, 4, 5:
begin
cellaSel:= GridStmp.Cells[aCol, aRow]; // punta alla casella selezionata
ixRg:= aRow;
if (GridStmp.Cells[1, aRow] = '') and (GridStmp.Cells[3, aRow] = '') and (GridStmp.Cells[4, aRow] = '') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
allin.Alignment:= taLeftJustify;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.Font.Color:= clBlack; // colora il testo
GridStmp.Canvas.Font.Name:= 'Noto Mono';
GridStmp.Canvas.TextRect(aRect, aRect.Left + 2, aRect.Top + 6, CellaSel, allin); // riscrive il testo nella casella
end
else begin
if (GridStmp.Cells[2, aRow] = 'TOT.Sottoconto') or (GridStmp.Cells[2, aRow] = 'TOTALI Conto') or (GridStmp.Cells[2, aRow] = 'T O T A L I') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
allin.Alignment:= taRightJustify;
GridStmp.Canvas.Brush.Color := grigio;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.Font.Color:= clWhite; // colora il testo
GridStmp.Canvas.Font.Name:= 'Noto Mono';
GridStmp.Canvas.TextRect(aRect, aRect.Right + 12, aRect.Top + 2, CellaSel, allin); // riscrive il testo nella casella
end;
end;
end;
end;
end;
end;
Nonostante la modifica in entrambi i rami dell'evento, puoi constatare che il Font.Name impostato da codice viene assolutamente ignorato. Ho provato anche a non impostare alcun Font.Name ed il risultato è sempre lo stesso: Quando viene impostato, tramite canvas, lo stile Bold, il Font.Name cambia automaticamente.
Assolutamente INSPIEGABILE.
Ciao, io penso che:
1) Potrebbe essere che tu non veda il carattere in formato Bold perché è bianco su grigio, dovresti provare scrivendo i totali nero su bianco.
2)Tu hai tre tipi di riga nella StringGrid, testata, dettaglio e totali/subtotali mentre il tuo codice contempla solo due tipi: testata e totali/subtotali.
Tieni presente che quindi lasci così la riga di dettaglio con le impostazioni definite nel sorgente.
3)Nel caso di tipo di riga totale/subtotale tu sposti la scrittura con quel "+12" e "+2" nell'istruzione:
GridStmp.Canvas.TextRect(aRect, aRect.Right + 12, aRect.Top + 2, CellaSel, allin); // riscrive il testo nella casella
Per questo le cifre dei totali/subtotali non ti vengono allineate. Infatti per le righe "normali" cioè quelle di dettaglio non è stato definito questo spostamento.
4)Non si dovrebbe mai cambiare il font in una riga di totali. Un font diverso da quello usato nel dettaglio, a parità di dimensione (size), potrebbe occupare più o meno spazio e sfalsare l'allineamento. Mettere soltanto in grassetto i totali invece crea meno problemi.
4)Non si dovrebbe mai cambiare il font in una riga di totali. Un font diverso da quello usato nel dettaglio, a parità di dimensione (size), potrebbe occupare più o meno spazio e sfalsare l'allineamento. Mettere soltanto in grassetto i totali invece crea meno problemi.
Scusa Livio, forse non hai letto quello che ho scritto alla fine del mio precedente post. Lo riporto qui sotto
Ho provato anche a non impostare alcun Font.Name ed il risultato è sempre lo stesso: Quando viene impostato, tramite canvas, lo stile Bold, il Font.Name cambia automaticamente.
Per dimostrare la validità del mio operato, ho modificato il codice attinente alla produzione della riga dei totali, lasciando soltanto il comando di impostazione dell'allineamento a destra.
procedure TForm6.GridStmpDrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
type
Tsfondo = TColor;
const
grigio: Tsfondo = clGray;
var
lun: Integer;
ixRg: Integer = 0;
cellaSel: String;
allin : TTextStyle; // tipo di allineamento
begin
WriteLn('TForm6.GridStmpDrawCell');
if (aRow >= 1) then
begin
case aCol of
2, 3, 4, 5:
begin
cellaSel:= GridStmp.Cells[aCol, aRow]; // punta alla casella selezionata
ixRg:= aRow;
if (GridStmp.Cells[1, aRow] = '') and (GridStmp.Cells[3, aRow] = '') and (GridStmp.Cells[4, aRow] = '') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
allin.Alignment:= taLeftJustify;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.Font.Color:= clBlack; // colora il testo
GridStmp.Canvas.TextRect(aRect, aRect.Left, aRect.Top, CellaSel, allin); // riscrive il testo nella casella
end
else begin
if (GridStmp.Cells[2, aRow] = 'TOT.Sottoconto') or (GridStmp.Cells[2, aRow] = 'TOTALI Conto') or (GridStmp.Cells[2, aRow] = 'T O T A L I') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
allin.Alignment:= taRightJustify;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.TextRect(aRect, aRect.Right, aRect.Top, CellaSel, allin); // riscrive il testo nella casella
end;
end;
end;
end;
end;
end;
Allego anche la vista della griglia dopo quest'ultima modifica.
Come è chiaramente visibile il Font.Name è cambiato da solo, oppure é cambiata la sua dimensione.
Il disallineamento degli importi dei totali rispetto alle righe di dettaglio è dovuto soltanto al cambio automatico del Font.Name o del Font.Height. Nient'altro. Quindi, secondo me, c'è qualcosa che NON funziona in Lazarus.
Per come la vedo io, l'unico modo che hai per capire se qualcosa non va nel tuo codice o in Lazarus, è questo:
- lancia il tuo programma, ed annotati la posizione di una delle caselle che non ti funziona (supponiamo colonna 2, riga 5), ricordandoti che il conteggio parte da 0
- nella GridStmpDrawCell, disabilita tutto quello che c'è adesso, e metti un semplice
if (aCol = 2) and (aRow = 5) then begin
end;
e dentro gli metti le impostazioni del carattere come le vuoi tu per quella singola casella.
A questo punto, se funziona, significa che c'è qualcosa che non va in come hai impostato le if ed il case in questo momento, se non funziona, potrebbe anche essere un problema di quel font, vedi se ad esempio aprendo un documento, e provando ad impostare quel font con quelle dimensioni lo vedi bene.
Ciao, Mario
Ciao,
ho eseguito delle istruzioni simili su di una mia stringgrid e sono arrivato alla conclusione che un comportamento strano di Lazarus c'è ma si potrebbe superare così:
-Inserire l'allineamento dentro la procedura OnDrawCell crea problemi. Nel tuo caso la riga:
allin.Alignment:= taRightJustify;
può essere tolta, l'allineamento a destra è già impostato nel sorgente.
-OnDrawCell si deve "occupare" di tutte le righe, anche quelle del dettaglio. Infatti il modo di allineare a destra è diverso a seconda se la cella viene o meno ridisegnata dentro OnDrawCell.
Penso che dovresti provare a scrivere la procedura così:
procedure TForm6.GridStmpDrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
type
Tsfondo = TColor;
const
grigio: Tsfondo = clGray;
var
lun: Integer;
ixRg: Integer = 0;
cellaSel: String;
allin : TTextStyle; // tipo di allineamento
begin
WriteLn('TForm6.GridStmpDrawCell');
if (aRow >= 1) then
begin
case aCol of
2, 3, 4, 5:
begin
cellaSel:= GridStmp.Cells[aCol, aRow]+' '; // punta alla casella selezionata
ixRg:= aRow;
if (GridStmp.Cells[1, aRow] = '') and (GridStmp.Cells[3, aRow] = '') and (GridStmp.Cells[4, aRow] = '') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
allin.Alignment:= taLeftJustify;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.Font.Color:= clBlack; // colora il testo
GridStmp.Canvas.Font.Name:= 'Noto Mono';
GridStmp.Canvas.TextRect(aRect, aRect.Left + 2, aRect.Top + 6, CellaSel, allin); // riscrive il testo nella casella
end
else begin
if (GridStmp.Cells[2, aRow] = 'TOT.Sottoconto') or (GridStmp.Cells[2, aRow] = 'TOTALI Conto') or (GridStmp.Cells[2, aRow] = 'T O T A L I') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
GridStmp.Canvas.Brush.Color := grigio;
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.Font.Color:= clWhite; // colora il testo
end;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.TextRect(aRect, aRect.Right, aRect.Top, CellaSel); // riscrive il testo nella casella
end;
end;
end;
end;
end;
allin.Alignment:= taRightJustify;
può essere tolta, l'allineamento a destra è già impostato nel sorgente.
-OnDrawCell si deve "occupare" di tutte le righe, anche quelle del dettaglio. Infatti il modo di allineare a destra è diverso a seconda se la cella viene o meno ridisegnata dentro OnDrawCell.
Ho riportato le modifiche che mi hai suggerito, ma è saltato l'allineamento a destra nelle colonne contenenti valori numerici. Ciò è determinato dal fatto che dovendo impostare soprattutto il colore di sfondo delle caselle interne alle colonne 3, 4, 5, sono costretto ad eseguire sempre la riga di riscrittura del testo nella casella. In quella riga è contenuto il parametro allin che, evidentemente, ha un suo default, diverso da quello dichiarato in fase di disegno per le colonne 3, 4, 5.
else begin
if (GridStmp.Cells[2, aRow] = 'TOT.Sottoconto') or (GridStmp.Cells[2, aRow] = 'TOTALI Conto') or (GridStmp.Cells[2, aRow] = 'T O T A L I') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
GridStmp.Canvas.Font.Color:= clWhite; // colora il testo
GridStmp.Canvas.Brush.Color := grigio;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.TextRect(aRect, aRect.Right - 10, aRect.Top, CellaSel, allin); // riscrive il testo nella casella
end;
end;
A dimostrazione di quanto detto sopra, riporto in allegato la schermata con la StrigGrid incriminata
Il metodo TextRect può essere usato anche con 4 argomenti.
Se scrivi
GridStmp.Canvas.TextRect(aRect, aRect.Right - 10, aRect.Top, CellaSel)
non avrai questi problemi.
Infatti nelle modifiche suggerite io avevo usato solo 4 argomenti e non 5.
Buon lavoro
Il metodo TextRect può essere usato anche con 4 argomenti.
Ho fatto come mi hai indicato, tuttavia la dimensione del carattere è comunque diversa da quella impostata per le colonne 2, 3, 4, 5, durante la fase di disegno.
Il codice modificato è:
procedure TForm6.GridStmpDrawCell(Sender: TObject; aCol, aRow: Integer;
aRect: TRect; aState: TGridDrawState);
type
Tsfondo = TColor;
const
grigio: Tsfondo = clGray;
var
lun: Integer;
ixRg: Integer = 0;
cellaSel: String;
allin : TTextStyle; // tipo di allineamento
begin
WriteLn('TForm6.GridStmpDrawCell');
if (aRow >= 1) then
begin
case aCol of
2, 3, 4, 5:
begin
cellaSel:= GridStmp.Cells[aCol, aRow]; // punta alla casella selezionata
ixRg:= aRow;
if (GridStmp.Cells[1, aRow] = '') and (GridStmp.Cells[3, aRow] = '') and (GridStmp.Cells[4, aRow] = '') then
begin
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
GridStmp.Canvas.Font.Color:= clBlack; // colora il testo
GridStmp.Canvas.Font.Style:= [fsBold];
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.Font.Name:= 'Noto Mono';
GridStmp.Canvas.TextRect(aRect, aRect.Left, aRect.Top, CellaSel); // riscrive il testo nella casella
end
else begin
if (GridStmp.Cells[2, aRow] = 'TOT.Sottoconto') or (GridStmp.Cells[2, aRow] = 'TOTALI Conto') or (GridStmp.Cells[2, aRow] = 'T O T A L I') then
begin
cellaSel:= cellaSel + ' ';
lun:= GridStmp.Canvas.TextWidth(cellaSel); // determina la lunghezza del testo presente nella casella
GridStmp.Canvas.Font.Color:= clWhite; // colora il testo
GridStmp.Canvas.Brush.Color := grigio;
GridStmp.Canvas.Font.Name:= 'Noto Mono';
GridStmp.Canvas.Font.Height:= 11;
GridStmp.Canvas.FillRect(aRect);
GridStmp.Canvas.TextRect(aRect, aRect.Right - 105, aRect.Top, CellaSel); // riscrive il testo nella casella
end;
end;
end;
end;
end;
end;
Ho dovuto modificare il parametro aRect.Right - 10 in aRect.Right - 105 perchè il testo nella cella della colonna 2 era sparito.
Allego anche un'immagine tipo relativa all'impostazione del Font e quella della vista dopo la modifica di stamani.
Devo dire che sono alquanto deluso, ma devo accontentarmi di quanto ottenuto, grazie a tutti voi.
Relativamente alla
- Rendere la larghezza della colonna proporzionata al contenuto della cella, ma non oltre ad un certo limite massimo;
ho risolto con:
case GridStmp.Columns[1].Title.Caption of
'DESCRIZIONE':
begin
for i:= 1 to totRgStmp do
begin
cellasel:= GridStmp.Cells[2, i];
w:= GridStmp.Canvas.TextWidth(cellasel); // determina la lunghezza del testo presente nella casella
if (w > lun) then
begin
lun:= w;
end;
end;
lun:= lun + 10;
GridStmp.Columns[1].Width:= lun;
end;
end;
Resta da capire come rendere una cella multiriga.
la classe TCanvas ha un metodo che si chiama TextWidth
https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tcanvas.textwidth.html (https://lazarus-ccr.sourceforge.io/docs/lcl/graphics/tcanvas.textwidth.html)
questo metodo ritorna la lunghezza di una stringa quando disegnata su quel canvas.
quindi puoi fare qualcosa tipo:
var l: integer;
begin
l := StringGrid1.Canvas.TextWidth('ciao mondo!');
if l > 250 then
l:=250;
end;
Edit:
mi hai battuto sul tempo ;)