C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1] 2   Вниз
  Печать  
Автор Тема: TStringGrid и ее ячейки...  (Прочитано 19964 раз)
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« : 11 Август 2011, 06:44:41 »

Привет! Подскажите, возможно ли в вышеуказанном компоненте заблокировать запись в определенную ячейку?
Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #1 : 11 Август 2011, 08:00:04 »

в событии OnSelectCell пропиши
Код:
void __fastcall TMainForm::StringGrid1SelectCell (TObject *Sender, int ACol, int ARow, bool &CanSelect)
{
// запрет модификации ячеек в таблице
TStringGrid *Grid = (TStringGrid*) Sender;
Grid->Options = (/* условие, запрещающее редактирование */) ? (Grid->Options >> goEditing) : (Grid->Options << goEditing);
}
//---------------------------------------------------------------------------
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #2 : 11 Август 2011, 18:17:38 »

Спасибо большое  А можно вас попросить прокомментировать код. Мало что понятно... 
Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #3 : 11 Август 2011, 19:48:35 »

1. пользователь выбирает ячейку в гриде
2. vcl выдает гриду сообщение в выборе новой ячейки (StringGrid1SelectCell)
3. процедура берет грид, которому выдано сообщение (TStringGrid *Grid = (TStringGrid*) Sender;)
4. производится проверка, доступна ли ячейка на запись ("условие")
5. по результатам проверки из настроек грида удаляется/добавляется параметр "таблица доступна на запись" ((Grid->Options >> goEditing) : (Grid->Options << goEditing); )
6. готово
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #4 : 11 Август 2011, 20:05:09 »

Ясно. Мне понятно как моя таблица привязана к Grid (полагаю, что так TStringGrid *Grid = (TStringGrid*) Sender;). А как переменная Grid привязана к моей таблице?
Нельзя ли сделать так (запрет редактирования второго столбца):
Код
void __fastcall TForm1::StringGrid1SelectCell(TObject *Sender, int ACol, int ARow,
         bool &CanSelect)
{
if(ACol == 2) StringGrid1->Options >> goEditing;
else StringGrid1->Options << goEditing;
}
« Последнее редактирование: 11 Август 2011, 20:20:19 от d7d1cd » Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #5 : 11 Август 2011, 20:52:10 »

можно. но рекомендуется использовать переменную Sender, где указан нужный грид.
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #6 : 12 Август 2011, 06:35:14 »

Спасибо за помощь!
А еще такой вопрос: возможно ли индивидуально для каждой ячейки применять различный стили шрифта, его выравнивание, цвет, а так же индивидуально устанавливать высоту и ширину ячейки?
Записан
S0mbre
Глобальный модератор


Сказали спасибо: +1113/-22
Offline

Сообщений: 2132

S0mbre


« Ответ #7 : 12 Август 2011, 07:34:06 »

Спасибо за помощь!
А еще такой вопрос: возможно ли индивидуально для каждой ячейки применять различный стили шрифта, его выравнивание, цвет, а так же индивидуально устанавливать высоту и ширину ячейки?

Со шрифтом и заливкой можно делать все, что угодно, т.к. при ручной отрисовке мы "рисуем" что хотим в каждой ячейке (координаты ячейки задаются как параметры для обработчика OnDrawCell). Что касается изменения ширины и высоты отдельной ячейки - как ты себе это представляешь? Грид - это же таблица, изменишь высоту ячейки - должна измениться высота всей строки, то же самое с шириной.
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #8 : 12 Август 2011, 13:52:33 »

Можно пример изменения шрифта?
Записан
S0mbre
Глобальный модератор


Сказали спасибо: +1113/-22
Offline

Сообщений: 2132

S0mbre


« Ответ #9 : 12 Август 2011, 15:51:49 »

Код
void __fastcall TForm1::StringGrid2DrawCell(TObject *Sender, int ACol,
int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid* Grid = static_cast<TStringGrid*>(Sender);
 
switch(ACol) {
case 0:
case 1:
Grid->Canvas->Brush->Color = (TColor)0x080FF80; // заливка в зависимости от столбца
break;
case 2:
Grid->Canvas->Brush->Color = clMoneyGreen;
break;
case 3:
Grid->Canvas->Brush->Color = clSkyBlue;
break;
default:
Grid->Canvas->Brush->Color = Grid->Color;
}
 
if (Grid->Cells[ACol][ARow].IsEmpty())
Grid->Canvas->Brush->Color = clPurple; // заливка пустых ячеек
Grid->Canvas->FillRect(Rect); // применить заливку
 
if (State.Contains(gdFixed)) { // обработка фиксированных ячеек
Grid->Canvas->Brush->Color = (TColor)0x080FF80; // заливка
Grid->Canvas->FillRect(Rect);
Grid->Canvas->Font->Color = clBlue; // цвет шрифта (синий)
Grid->Canvas->Font->Style = TFontStyles() << fsBold; // жирный шрифт
}
else {
Grid->Canvas->Font->Color = clBlack; // цвет шрифта (черный)
Grid->Canvas->Font->Style = TFontStyles(); // обычный шрифт
}
 
if (State.Contains(gdFocused)) {
Grid->Canvas->DrawFocusRect(Rect); // если фокус, рисуем прямоугольник
}
 
if (State.Contains(gdSelected)) { // если выделена ячейка
// Grid->Canvas->Font->Color = clRed;
Grid->Canvas->Brush->Color = clYellow;
Grid->Canvas->FillRect(Rect);
// Grid->Canvas->Font->Color = clFuchsia;
Grid->Canvas->Font->Style = TFontStyles() << fsBold;
}
 
// рисуем текст
int n = (State.Contains(gdFixed)) ? 4 : 5; // оффсет для фиксированных ячеек
Grid->Canvas->TextOut(Rect.Left + n, Rect.Top + n, Grid->Cells[ACol][ARow]); // вывод текста ячейки
}
 
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #10 : 12 Август 2011, 20:57:18 »

Отлично! А как сделать выравнивание текста? 
Записан
Zor
Глобальный модератор


Сказали спасибо: +158/-30
Offline

Сообщений: 2946


« Ответ #11 : 12 Август 2011, 21:12:05 »

Код:
TCanvas *C = Grid->Canvas;
AnsiString S = Grid->Cells[ACol][ARow];
C->TextRect(Rect, Rect.left + (Rect.Width() - C->TextWidth(S)) / 2, Rect.top + (Rect.Height() - C->TextHeight(S)) / 2, S);
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #12 : 13 Август 2011, 09:51:02 »

То есть все действия с ячейками необходимо проводить через канву таблицы?
Записан
S0mbre
Глобальный модератор


Сказали спасибо: +1113/-22
Offline

Сообщений: 2132

S0mbre


« Ответ #13 : 13 Август 2011, 11:38:52 »

Если хочешь рисовать вручную, то как же еще? "Действия с ячейками" только для вывода на канву, кончено.
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #14 : 20 Сентябрь 2011, 18:37:45 »

В своей программе для StringGrid-a установил свойство DrawingStyle в gdsGradient для отображения фиксированных ячеек в градиенте. Еще мне необходимо в фиксированных ячейках выводить текст особого начертания, а так же выравнивание текста во всех ячейках сделать по центру. В обработке события OnDrawCell написал:
Код
String text = sgEnergy->Cells[ACol][ARow];
 
//Рисуем фиксированные ячейки:
if(State.Contains(gdFixed))
 {
  sgEnergy->Canvas->Font->Color = clBlue;                  //Цвет шрифта (синий)
  sgEnergy->Canvas->Font->Style = TFontStyles() << fsBold; //Жирный шрифт
  sgEnergy->Canvas->Font->Size  = 10;                      //Размер шрифта
 }
 
//Выравниваем текст по центру:
sgEnergy->Canvas->TextOut(Rect.Left + (Rect.Width() - sgEnergy->Canvas->TextWidth(text))/2,
  Rect.Top + (Rect.Height() - sgEnergy->Canvas->TextHeight(text))/2, text);

Однако в этом случае текст выводится так, как на картинке. Что я не так делаю?
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #15 : 20 Сентябрь 2011, 19:57:54 »

Я бы все-таки добавил заполнение градиентом (или не градиентом, смотря какая ячейка) ячейки, и только потом - поверх очищенного поля - вывод текста. Что-то типа:
Код
#include 
 
... // Обработчик OnDrawCell
TStringGrid *myGrid = (TStringGrid*)Sender;
String text = myGrid->Cells[ACol][ARow];
 
//Рисуем фиксированные ячейки:
if(State.Contains(gdFixed))
{
   myGrid->Canvas->Font->Color = clBlue;                  //Цвет шрифта (синий)
   myGrid->Canvas->Font->Style = TFontStyles() << fsBold; //Жирный шрифт
   myGrid->Canvas->Font->Size  = 10;                      //Размер шрифта
   GraphUtil::GradientFillCanvas(myGrid->Canvas, myGrid->GradientStartColor,
myGrid->GradientEndColor, Rect, gdVertical);
}
else // Не фиксированная ячейка, заполняется без градиента
{
   myGrid->Canvas->FillRect(Rect);
}
 
// Выравниваем текст по центру:
myGrid->Canvas->TextOut(Rect.Left + (Rect.Width() - myGrid->Canvas->TextWidth(text))/2,
Rect.Top + (Rect.Height() - myGrid->Canvas->TextHeight(text))/2, text);

(проверить не могу, ибо у меня здесь только 2009, тут градиента еще нет. Тестируй, говори, если что не так)
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #16 : 20 Сентябрь 2011, 20:09:09 »

Работает!!!  Просто я не знал функцию градиентной заливки канвы. 
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #17 : 21 Сентябрь 2011, 18:22:02 »

Снова вопрос. Наверное еще много будет по этому компоненту... 

Когда в программе производится ввод текста в ячейки, то все отлично! Но когда начинаешь работать с другим объектом на форме, например начинаешь вводить текст в TEdit, то последняя редактируемая ячейка в таблице подсвечивается синим цветом и текст в ней рисуется совсем не по правилам события OnDrawCell.

1. Как сделать так, чтобы последняя редактируемая ячейка отображалась так, как мне надо?
2. Как сделать, чтобы при вводе текста в ячейку он сразу был выравнен по середине?

Заранее благодарен за помощь... 
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #18 : 21 Сентябрь 2011, 21:40:10 »

1. Как только ты переключился на другой контрол - ячейка уже не редактируемая, а просто выбранная. Если ее содержимое не отображается так, как надо (по центру) - это только
a) проблема OnDrawCell (ты выставил дополнительные условия, и по gdSelected ячейка просто не отрисовывается, как положено)
или
b) у тебя для StringGrid-а опция goAlwaysShowEditor выставлена в True, сбрось ее в False, тогда при потере фокуса гридом ячейка станет Selected, и будет отрисовываться как положено (если пункт (а) сделан верно)

2. Подменяй Inplace-Editor своим контролом, например, TEdit-ом с нужным выравниванием: при выборе ячейки внутри нее рисуешь TEdit, в который записываешь содержимое ячейки. Даешь пользователю возможность заменить это значение на другое. При переходе на другую ячейку (или при потере фокуса гридом) удаляешь этот TEdit, перенеся его содержимое в саму ячейку. Как менять InplaceEditor на комбобокс - можешь посмотреть здесь, с TEdit-ом еще проще...
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #19 : 23 Сентябрь 2011, 06:51:35 »

Не получается нарисовать выделенную ячейку таблицы, когда фокус на другом контроле.  Вот мой код рисования:
Код
//*** РИСОВАНИЕ ТАБЛИЦЫ
void __fastcall TMainForm::sgEnergyDrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid *Grid = (TStringGrid*)Sender;
 
//--- Сохраняем текст ячейки -----------------------------------------------------------------------------------------------------------------------
String text = Grid->Cells[ACol][ARow];
 
//--- Если рисуется фиксированная ячейка -----------------------------------------------------------------------------------------------------------
if(State.Contains(gdFixed))
 {
  GradientFillCanvas(Grid->Canvas, Grid->GradientStartColor, //Градиентно заливаем ячейку
  Grid->GradientEndColor, Rect, gdVertical);
  Grid->Canvas->Font->Color = clBlue;                        //Устанавливаем цвет шрифта
  Grid->Canvas->Font->Style = TFontStyles() << fsBold;       //Устанавливаем начертание шрифта
  Grid->Canvas->Font->Size  = 10;                            //Устанавливаем размер шрифта
 }
 
//--- Если рисуется обычная ячейка, заливаем ее цветом по умолчанию --------------------------------------------------------------------------------
else Grid->Canvas->FillRect(Rect);
 
//--- Выводим текст в ячеку по центру
Grid->Canvas->TextOut(Rect.Left+(Rect.Width()-Grid->Canvas->TextWidth(text))/2, Rect.Top+(Rect.Height()-Grid->Canvas->TextHeight(text))/2, text);
 
}
 

А вот как рисуется выделенная ячейка с текстом "тут":
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #20 : 25 Сентябрь 2011, 09:38:35 »

Подскажите кто-нибудь...
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #21 : 25 Сентябрь 2011, 10:40:20 »

А вот как рисуется выделенная ячейка с текстом "тут":
Не воспроизводится. При goAlwaysShowEditor = False все рисуется прекрасно. В крайнем случае можно добавить:

Код
void __fastcall TForm1::sgEnergyDrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect,
         TGridDrawState State)
{
TStringGrid *Grid = (TStringGrid*)Sender;
String text = Grid->Cells[ACol][ARow];
 
// Рисуем фиксированные ячейки:
if(State.Contains(gdFixed))
{
GradientFillCanvas(Grid->Canvas, Grid->GradientStartColor,
Grid->GradientEndColor, Rect, gdVertical);
Grid->Canvas->Font->Color = clBlue;
Grid->Canvas->Font->Style = TFontStyles() << fsBold;
Grid->Canvas->Font->Size  = 10;
}
else // Вот этот кусок
{
if(State.Contains(gdSelected))
{
Grid->Canvas->Brush->Color = clSkyBlue; // Или любой другой цвет
}
Grid->Canvas->FillRect(Rect); // это выполнится и для обычной и для выбранной ячейки
// но не для Fixed
}
 
// Выравниваем текст по центру:
Grid->Canvas->TextOut(
Rect.Left + (Rect.Width() - Grid->Canvas->TextWidth(text))/2,
Rect.Top + (Rect.Height() - Grid->Canvas->TextHeight(text))/2, text
);
}
, но это ничего не изменит - "масло масляное" получается. То же самое должно быть и в твоем коде.
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #22 : 25 Сентябрь 2011, 14:36:57 »

Методом пошаговой отладки выяснил следующее:
1. Если goAlwaysShowEditor = true, то "двойное" рисование текста не происходит, но и по центру его вывод так же не происходит. Текст выводится слева.
2. Если сделать goAlwaysShowEditor = false, то при пошаговой отладке сначала ячейка заполняется цветом выделения (у меня по умолчанию синий), потом при выполнении строки
Код
else Grid->Canvas->FillRect(Rect);
в нее, с выравниванием по левому краю, выводится текст, затем при выполнении строки
Код
Grid->Canvas->TextOut(
Rect.Left + (Rect.Width() - Grid->Canvas->TextWidth(text))/2,
Rect.Top + (Rect.Height() - Grid->Canvas->TextHeight(text))/2, text
в ячейку по центру выводится текст.
И получается что в ячейку текст выводится 2 раза. Но такое только при потере фокуса таблицей.
Может это так в XE? Попробую сделать принудительную обработку выделенной ячейки...
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #23 : 25 Сентябрь 2011, 14:52:40 »

Спасибо за помощь, volvo877. Сделал код "рисования" так:
Код
void __fastcall TMainForm::sgEnergyDrawCell(TObject *Sender, int ACol, int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid *Grid = (TStringGrid*)Sender;
 
//--- Сохраняем текст ячейки -----------------------------------------------------------------------------------------------------------------------
String text = Grid->Cells[ACol][ARow];
 
//--- Если рисуется фиксированная ячейка -----------------------------------------------------------------------------------------------------------
if(State.Contains(gdFixed))
 {
  GradientFillCanvas(Grid->Canvas, Grid->GradientStartColor, //Градиентно заливаем ячейку
  Grid->GradientEndColor, Rect, gdVertical);
  Grid->Canvas->Font->Color = clBlue;                        //Устанавливаем цвет шрифта
  Grid->Canvas->Font->Style = TFontStyles() << fsBold;       //Устанавливаем начертание шрифта
  Grid->Canvas->Font->Size  = 10;                            //Устанавливаем размер шрифта
 }
 
//--- Если рисуется выделенная ячейка --------------------------------------------------------------------------------------------------------------
if(State.Contains(gdSelected))
 {
  Grid->Canvas->Brush->Color = Grid->Color;
  Grid->Canvas->Font->Color = Grid->Font->Color;
 }
 
//--- Заливаем ячейку цветом -----------------------------------------------------------------------------------------------------------------------
Grid->Canvas->FillRect(Rect);
 
//--- Выводим текст в ячеку по центру с цветом в соответствии с флагом "Записать накопленную энергию" ----------------------------------------------
if(!chbEnergy->Checked ||
  (ACol == 2 & !chbTariff2->Checked) ||
  (ACol == 3 & !chbTariff3->Checked) ||
  (ACol == 4 & !chbTariff4->Checked))  Grid->Canvas->Font->Color = clGrayText;
DrawText(Grid->Canvas->Handle, text.w_str(), -1, &Rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}

Теперь все правильно отображается  

P.S. Но только если свойство таблицы DrawingStyle = gdsGradient...
« Последнее редактирование: 25 Сентябрь 2011, 15:21:18 от d7d1cd » Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #24 : 25 Сентябрь 2011, 15:03:12 »

В моей таблице несколько столбцов и несколько строк. В ячейки можно ввести только числа. Крайний правый столбец запрещен для редактирования: в него должна выводится сумма всех ячеек строки, так как на картинке. Как это проще всего сделать в режиме реального времени, то есть: ввели число в ячейку, выделили другую (или нажали Enter) - сумма автоматически пересчиталась?
Записан
S0mbre
Глобальный модератор


Сказали спасибо: +1113/-22
Offline

Сообщений: 2132

S0mbre


« Ответ #25 : 25 Сентябрь 2011, 15:32:22 »

Функция для подсчета суммы по данной строке
Код
void __fastcall TForm1::SumRow(int Row)
{
int sum(0);
for (int i=0; i<Grid1->ColCount-1; i++)
sum += StrToInt(Grid1->Cells[i][Row]);
Grid1->Cells[Grid1->ColCount-1][Row] = IntToStr(sum);
}
 

Вызывай в обработчике события OnSetEditText грида (передавай параметр ARow в функцию).
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #26 : 25 Сентябрь 2011, 15:47:05 »

Спасибо большое. Как раз то, что надо! 
А как мне сделать код, чтобы при нажатии на Enter редактирование текущей ячейки завершалось и начиналось редактирование следующей (той, что ниже предыдущей, либо той, если внизу нет ячеек, что находится справа от предыдущей)?
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #27 : 25 Сентябрь 2011, 17:44:37 »

Цитировать
Функция для подсчета суммы по данной строке
Опасно. OnSetEditText выстреливается каждый раз, когда меняется содержимое ячейки, а не один раз при окончании редактирования. Попробуй выделить ячейку, и сразу (без дополнительного клика по ячейке, чтоб открылся редактор, и без снятия выделения в редакторе) начать вводить число. Вылет гарантирован. ("" - не целое число). Лучше воспользоваться
Код
sum += StrToIntDef(Grid1->Cells[i][Row], 0);
, чтоб хотя бы таких сбоев не допускать...
Записан
d7d1cd
Участник


Сказали спасибо: +59/-24
Offline

Сообщений: 1005


« Ответ #28 : 11 Октябрь 2011, 20:40:31 »

Привет снова. Ребята, подскажите как ячейку таблицы, которая выделена, заменить на компонент TDateTimePicker, то есть, чтобы в ячейку можно было ввести только дату...
Записан
volvo877
Глобальный модератор


Сказали спасибо: +736/-1
Offline

Сообщений: 891


« Ответ #29 : 11 Октябрь 2011, 22:45:26 »

http://www.kansoftware.ru/?tid=5144
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  




....

Powered by SMF 1.1.21 | SMF © 2025, Simple Machines
Страница сгенерирована за 0.229 секунд. Запросов: 19.