47 / 27 / 8
Регистрация: 11.05.2010
Сообщений: 169
1

Рассчитать ширину колонок с учетом ScrollBar в StringGrid на всю ширину StringGrid

20.09.2014, 22:27. Показов 5365. Ответов 7
Метки нет (Все метки)

Здравствуйте,

Требуется в StringGrid-ах автоматически рассчитать ширину колонок - что бы не было горизонтальной полосы прокрутки и не было справа не используемого места (то есть, занять всю ширину StringGrid-а).

В рассматриваемом примере StringGrid-ы одинаковые, но в одном есть ScrollBar (строки не вмещаются все), в другом - ScrollBar отсутствует.

Как работать со ScrollBar-ом уже объяснялось в теме Как обратиться к ScrollBar в StringGrid?.
Вроде бы все делаю по инструкции, но почему-то в одном случае ScrollBar учитывается, в другом - нет (во второй таблице справа от колонки с заголовком Col_5 - пустое место).
Такое ощущение, что какой-то важный момент упустил

Картинка того, что получилась в итоге - ниже, во вложении.
Так же и полностью весь проект во вложении.

Оба StringGrid требуется обработать в одном цикле.
По факту - у меня в разрабатываемом проекте StringGrid-ов несколько больше двух и требуется как-то автоматизировать процесс расчета ширины колонок для каждого StringGrid-а, в зависимости от того, есть или нет у него ScrollBar.

Может быть есть другой, более правильный, способ как достигнуть результата - буду признателен если мне его расскажут.

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids;
 
type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    StringGrid2: TStringGrid;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.FormCreate(Sender: TObject);
var
  I, J, K,
  SB_Width: Integer;
  ControlName: String;
  Edit_Control: TObject;
  TSG: TStringGrid;
begin
  for I := 1 to 2 do
  begin
    ControlName := 'StringGrid' + IntToStr(I);
    Edit_Control := FindComponent(ControlName);
    TSG := TStringGrid(Edit_Control);
 
    SB_Width := 0;
    if (GetWindowlong(TSG.Handle, GWL_STYLE) and WS_VSCROLL) <> 0
    then   //Вертикальный ScrollBar виден
      SB_Width := GetSystemMetrics(SM_CXVSCROLL);
 
    TSG.ColWidths[0] := 40;
    k := TSG.ColWidths[0] + TSG.BevelWidth * 2 + TSG.GridLineWidth * 6;
    J := (TSG.Width - k - SB_Width) div 4;
    TSG.ColWidths[1] := J;
    TSG.ColWidths[2] := J;
    TSG.ColWidths[3] := J;
    TSG.ColWidths[4] := TSG.Width - J * 3 - k - SB_Width;
          //заголовки столбцов
    TSG.Cells[0, 0] := 'Col_1';
    TSG.Cells[1, 0] := 'Col_2';
    TSG.Cells[2, 0] := 'Col_3';
    TSG.Cells[3, 0] := 'Col_4';
    TSG.Cells[4, 0] := 'Col_5';
 
    for J := 1 to TSG.RowCount - 1 do
    begin
      TSG.Cells[0,J] := IntToStr(J);
    end;
  end;
end;
 
end.
Миниатюры
Рассчитать ширину колонок с учетом ScrollBar в StringGrid на всю ширину StringGrid  
Вложения
Тип файла: rar Project1.rar (84.2 Кб, 9 просмотров)
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.09.2014, 22:27
Ответы с готовыми решениями:

Delphi 7 Stringgrid Нужно сделать цикл для заполнения Stringgrid данными из другого Stringgrid
Нужно чтобы из Stringgrid1 данные переносились в Stringgrid2 Но ТОЛЬКО ПО УСЛОВИЮ Таблицы...

При запуске форма растягивается во всю ширину
При редактировании проекта форма имеет размеры 200х500, но при запуске программы растягивается во...

ScrollBar и StringGrid
Добрый вечер, такая проблемка: имеется таблица StringGrid и горизонтальная полоса ScrollBar с...

Stringgrid и его ScrollBar
Имеется Stringgrid с огромным множеством строк! Использую процедуру SelectRow, для программного...

7
837 / 732 / 342
Регистрация: 22.09.2012
Сообщений: 5,034
21.09.2014, 07:59 2
Цитата Сообщение от il-ir Посмотреть сообщение
Требуется в StringGrid-ах автоматически рассчитать ширину колонок - что бы не было горизонтальной полосы прокрутки и не было справа не используемого места
Я так делал в эдиты записывал число строк и число колонок и создавал ее в размер этих строк и колонок
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var
  Form1: TForm1;
  N, M: Integer;
//................................
//................................
 
  if (Edit1.text = '') or (Edit2.text = '') then
  ShowMessage('Введите кол-во строк или колонок таблицы')
  else
  begin
    N := StrToInt(Edit1.text); //столбцов
    M := StrToInt(Edit2.text); //строк
    StringGrid1.ColCount := N;
    StringGrid1.RowCount := M;
    StringGrid1.ClientWidth := StringGrid1.DefaultColWidth * N; //ширина
    StringGrid1.ClientHeight := StringGrid1.DefaultRowHeight * M; //высота
    StringGrid1.Visible := True;
  end;
1
47 / 27 / 8
Регистрация: 11.05.2010
Сообщений: 169
21.09.2014, 10:34  [ТС] 3
Цитата Сообщение от NIKOLAYY Посмотреть сообщение
создавал ее в размер этих строк и колонок
у меня задача в другую сторону - есть StringGrid, есть количество колонок и строчек, надо исходя из имеющейся ширины StringGrid посчитать ширину колонок.
0
837 / 732 / 342
Регистрация: 22.09.2012
Сообщений: 5,034
21.09.2014, 11:42 4
il-ir,
Аа ну понятно, тебе значит нужно взять не ширину StringGrid-а а клиентскую область ширины StringGrid-а и поделить ее на кл-во колонок и со строками сделать тоже самое. Вобщем тебе нужно придумать формулу если не лень, если лень поджди мож кто и придумает напишет.
0
47 / 27 / 8
Регистрация: 11.05.2010
Сообщений: 169
21.09.2014, 12:00  [ТС] 5
Сделал с предложенной NIKOLAYY, идеей - использовать StringGrid1.ClientWidth.

код (проект с обновленным кодом - во вложении):
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  for I := 1 to 2 do
  begin
    ControlName := 'StringGrid' + IntToStr(I);
    Edit_Control := FindComponent(ControlName);
    TSG := TStringGrid(Edit_Control);
 
    TSG.ColWidths[0] := 40;
    k := TSG.ColWidths[0] + TSG.GridLineWidth * 4;
    J := (TSG.ClientWidth - k) div 4;
    TSG.ColWidths[1] := J;
    TSG.ColWidths[2] := J;
    TSG.ColWidths[3] := J;
    TSG.ColWidths[4] := TSG.ClientWidth - J * 3 - k;
          //заголовки столбцов
    TSG.Cells[0, 0] := 'Col_1';
    TSG.Cells[1, 0] := 'Col_2';
    TSG.Cells[2, 0] := 'Col_3';
    TSG.Cells[3, 0] := 'Col_4';
    TSG.Cells[4, 0] := 'Col_5';
 
    for J := 1 to TSG.RowCount - 1 do
    begin
      TSG.Cells[0,J] := IntToStr(J);
    end;
  end;
Работает но при условии, что для StringGrid, где мало строк, установлено свойство ScrollBars = ssNone.
Если же в обоих StringGrid-ах свойство ScrollBars = ssVertical, то почему-то ClientWidth вычисляется не правильно (скорее всего, вычисляется правильно, только не так как мне надо ): несмотря на то, что в StringGrid-е скролбар отсутствует, параметр ClientWidth рассчитывается так, словно скролбар должен быть.

В моем исходном коде (в самом первом сообщении) - та же самая фигня: если у таблицы, где мало строк, заранее установить свойство ScrollBars = ssNone - все работает как надо.

Посему, вопрос может быть несколько изменен: как при создании таблицы определить, должен быть ScrollBars или нет. Или это не правильный путь?

Ниже на картинке приводятся параметры, полученные при создании формы и после того, как форма уже создана (получены нажатием на кнопку "Загрузить параметры") - в ситуации, когда у обоих StringGrid-ов при создании свойство ScrollBars = ssVertical.
Линией подчеркнуто различие в свойствах ClientWidth.

Можно попробовать, используя свойство RowCount, узнать сколько всего строк должно быть. Далее, рассчитать, строки все влезут или нет (свойства ClientHeight, RowHeights и GridLineWidth). и соответственно, перед расчетом ширины колонок установить свойство ScrollBars = ssVertical (если все строки не вмещаются) и ScrollBars = ssNone (если все строки поместились в StringGrid-е)...
Или этот путь - неправильный и ведет в никуда?
Миниатюры
Рассчитать ширину колонок с учетом ScrollBar в StringGrid на всю ширину StringGrid  
Вложения
Тип файла: rar Project1_2.rar (84.7 Кб, 3 просмотров)
0
47 / 27 / 8
Регистрация: 11.05.2010
Сообщений: 169
21.09.2014, 12:58  [ТС] 6
Цитата Сообщение от il-ir Посмотреть сообщение
Можно попробовать, используя свойство RowCount, узнать сколько всего строк должно быть. Далее, рассчитать, строки все влезут или нет (свойства ClientHeight, RowHeights и GridLineWidth). и соответственно, перед расчетом ширины колонок установить свойство ScrollBars = ssVertical (если все строки не вмещаются) и ScrollBars = ssNone (если все строки поместились в StringGrid-е)...
реализовал эту идею. Все работает.
Вопрос только в том, есть ли путь правильнее лучше красивее, чем реализованный.
Полностью код решения приведу тут, вдруг кому еще потребуется?
Может быть кто-нибудь предложит другой вариант получения требуемого результата - буду благодарен.

Полностью проект - в приложении.

Решение:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
procedure TForm1.FormCreate(Sender: TObject);
var
  I, J, K: Integer;
  ControlName: String;
  Edit_Control: TObject;
  TSG: TStringGrid;
begin
  for I := 1 to 2 do
  begin
    ControlName := 'StringGrid' + IntToStr(I);
    Edit_Control := FindComponent(ControlName);
    TSG := TStringGrid(Edit_Control);
 
    K := TSG.RowHeights[0];
    for J := 1 to TSG.RowCount - 1 do
      K := K + TSG.RowHeights[J];
    K := K + (TSG.RowCount - 1) * TSG.GridLineWidth;
 
    if K > TSG.ClientHeight
    then
      TSG.ScrollBars := ssVertical
    else
      TSG.ScrollBars := ssNone;
 
    TSG.ColWidths[0] := 40;
    K := TSG.ColWidths[0] + TSG.GridLineWidth * 4;
    J := (TSG.ClientWidth - K) div 4;
    TSG.ColWidths[1] := J;
    TSG.ColWidths[2] := J;
    TSG.ColWidths[3] := J;
    TSG.ColWidths[4] := TSG.ClientWidth - J * 3 - K;
          //заголовки столбцов
    TSG.Cells[0, 0] := 'Col_1';
    TSG.Cells[1, 0] := 'Col_2';
    TSG.Cells[2, 0] := 'Col_3';
    TSG.Cells[3, 0] := 'Col_4';
    TSG.Cells[4, 0] := 'Col_5';
 
    for J := 1 to TSG.RowCount - 1 do
      TSG.Cells[0,J] := IntToStr(J);
  end;
end;
Вложения
Тип файла: rar Project3.rar (84.2 Кб, 3 просмотров)
0
47 / 27 / 8
Регистрация: 11.05.2010
Сообщений: 169
22.09.2014, 18:48  [ТС] 7
опять требуется помощь форумчан...

Еще одно изменение (дополнение) предложенного выше решения.
У меня заголовок таблицы форматируется в несколько строк, если не вмещается по ширине. И произошел ляпсус, когда в некоторых ситуациях вертикального скроллбара по расчету быть не должно было, но он нагло появлялся

Если использовать форматирование, когда в ячейке текст будет отображаться в несколько строк (как это сделать, решение предложено в частности в теме Форматирование текста в несколько строк в StringGrid), то может получиться не совсем то, что требовалось.

Как я вычислил, проблема в том, что при обработке процедуры TForm1.FormCreate заголовок еще не форматируется в несколько строк и высота строки с заголовком не меняется (так как по событию OnDrawCell процедуры StringGrid1DrawCell и StringGrid2DrawCell выполняются ПОСЛЕ процедуры FormCreate). А после того, как мы в FormCreate рассчитали ширину столбцов (например, с учетом отсутствия вертикального скроллбара), то изменение высоты строки с заголовком может инициировать появление этого самого скроллбара - и часть последней ячейки окажется за видимым полем.
В примере количество строк в StringGrid2 подобрано таким образом, что если заголовок в одну строку отображать, то вертикальный скроллбар не нужен. Если форматировать заголовок, что бы текст в заголовке отображался целиком в несколько строк - то вертикальный скроллбар требуется.

Что бы избежать такой неприятной загогулины, пришлось несколько изменить код процедуры FormCreate:
1. Значения ячеек заголовка таблицы устанавливаются ДО расчета ширины колонок.
2. Вместо банального оператора K := TSG.RowHeights[0]; пришлось вычислять высоту для каждой ячейки заголовка (в каждой ячейке нулевой строки).

Но почему-то, несмотря на то, что делаю вроде по инструкции, не работает так как надо

Картинка той фигни, что получилось - ниже, во вложении.
В идеале, в StringGrid2 ширина столбцов должна рассчитываться исходя из посыла, что вертикальный скроллбар есть. Но почему-то, при расчете ширины столбцов таблицы считается, что вертикального скроллбара не должно быть ...

Полный текст проекта так же во вложении.
Что-то я, похоже, пропустил - вот и не работает как надо

Код процедуры FormCreate:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
procedure TForm1.FormCreate(Sender: TObject);
var
  TextHeight,
  I, J, K: Integer;
  ControlName: String;
  Edit_Control: TObject;
  TSG: TStringGrid;
  Rect: TRect;
  pStr: PChar;
  Format: Word;
begin
  for I := 1 to 2 do
  begin
    ControlName := 'StringGrid' + IntToStr(I);
    Edit_Control := FindComponent(ControlName);
    TSG := TStringGrid(Edit_Control);
 
          //заголовки столбцов
    TSG.Cells[0, 0] := 'Col_1 Col_1 Col_1 Col_1';
    TSG.Cells[1, 0] := 'Col_2';
    TSG.Cells[2, 0] := 'Col_3';
    TSG.Cells[3, 0] := 'Col_4';
    TSG.Cells[4, 0] := 'Col_5';
 
 
//  Ниже закомментированный оператор можно использовать,
//  если заголовок StringGrid'а в одну строку.
//    K := TSG.RowHeights[0];
 
      //Определяем высоту строки-заголовка таблицы.
    K := 0;
    for J := 0 to TSG.ColCount - 1 do
    begin
      pStr := pchar(TSG.Cells[J, 0]);
      Rect := TSG.CellRect(J, 0);
      Format := DT_NOCLIP or DT_WORDBREAK or DT_CALCRECT;
      TextHeight := DrawText(TSG.Canvas.Handle, pStr, StrLen(pStr), Rect, Format);
      K := max(K, TextHeight);
    end;
 
    for J := 1 to TSG.RowCount - 1 do
      K := K + TSG.RowHeights[J];
    K := K + (TSG.RowCount - 1) * TSG.GridLineWidth;
 
    if K > TSG.ClientHeight
    then
      TSG.ScrollBars := ssVertical
    else
      TSG.ScrollBars := ssNone;
 
    TSG.ColWidths[0] := 40;
    K := TSG.ColWidths[0] + TSG.GridLineWidth * 4;
    J := (TSG.ClientWidth - K) div 4;
    TSG.ColWidths[1] := J;
    TSG.ColWidths[2] := J;
    TSG.ColWidths[3] := J;
    TSG.ColWidths[4] := TSG.ClientWidth - J * 3 - K;
 
     //Можно сохранить исходное значение ScrollBars ранее, и тут
     //восстановить. Мне это не требуется, так как у меня по умолчанию
     //установлен ScrollBars := ssVertical.
    TSG.ScrollBars := ssVertical;
 
    for J := 1 to TSG.RowCount - 1 do
      TSG.Cells[0,J] := IntToStr(J);
  end;
end;
Миниатюры
Рассчитать ширину колонок с учетом ScrollBar в StringGrid на всю ширину StringGrid  
Вложения
Тип файла: rar Project4.rar (85.3 Кб, 15 просмотров)
0
47 / 27 / 8
Регистрация: 11.05.2010
Сообщений: 169
23.09.2014, 13:10  [ТС] 8
УРА!!! я победил эту ситуацию
так как у нас сейчас чуть больше, чем половина четвертого утра, то подробно напишу уже днем - ошибка смешная, но неприятная.

немножко пришлось но я ее нашел

Добавлено через 12 часов 29 минут
решение оказалось очень простое.
У меня ширина первой колонки устанавливается в коде программы абсолютным значением (не зависимо от ширины StringGrid'а), ширина остальных колонок вычислялась в зависимость от ширины StringGrid'а.
Соответственно, требовалось установить ширину этой первой колонки, а затем измерять высоту строки с заголовком.
Я же сначала измерил высоту строки, а затем изменил ширину колонки - что в свою очередь повлекло возможное увеличение высоты строки, так как ширина колонки уменьшилась.


исправленный код процедуры (полностью проект можно скачать в моем сообщении - только в проекте заменить текст процедуры TForm1.FormCreate на приведенный ниже).

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
procedure TForm1.FormCreate(Sender: TObject);
var
  TextHeight,
  I, J, K: Integer;
  ControlName: String;
  Edit_Control: TObject;
  TSG: TStringGrid;
  Rect: TRect;
  pStr: PChar;
  Format: Word;
begin
  for I := 1 to 2 do
  begin
    ControlName := 'StringGrid' + IntToStr(I);
    Edit_Control := FindComponent(ControlName);
    TSG := TStringGrid(Edit_Control);
 
          //заголовки столбцов
    TSG.Cells[0, 0] := 'Col_1';
    TSG.Cells[1, 0] := 'Col_2';
    TSG.Cells[2, 0] := 'Col_3';
    TSG.Cells[3, 0] := 'Col_4';
    TSG.Cells[4, 0] := 'Col_5';
 
//  Ниже закомментированный оператор можно использовать,
//  если заголовок StringGrid'а в одну строку.
//    K := TSG.RowHeights[0];
 
    TSG.ColWidths[0] := 40;
 
      //Определяем высоту строки-заголовка таблицы.
    K := 0;
    for J := 0 to TSG.ColCount - 1 do
    begin
      pStr := pchar(TSG.Cells[J, 0]);
      Rect := TSG.CellRect(J, 0);
      InflateRect(Rect, -2, 0);
      Format := DT_NOCLIP or DT_WORDBREAK or DT_CALCRECT;
      TextHeight := DrawText(TSG.Canvas.Handle, pStr, StrLen(pStr), Rect, Format);
      K := max(K, TextHeight);
    end;
 
    for J := 1 to TSG.RowCount - 1 do
      K := K + TSG.RowHeights[J];
    K := K + (TSG.RowCount - 1) * TSG.GridLineWidth;
 
    if K > TSG.ClientHeight
    then
      TSG.ScrollBars := ssVertical
    else
      TSG.ScrollBars := ssNone;
 
    K := TSG.ColWidths[0] + TSG.GridLineWidth * 4;
    J := (TSG.ClientWidth - K) div 4;
    TSG.ColWidths[1] := J;
    TSG.ColWidths[2] := J;
    TSG.ColWidths[3] := J;
    TSG.ColWidths[4] := TSG.ClientWidth - J * 3 - K;
 
     //Можно сохранить исходное значение ScrollBars ранее, и тут
     //восстановить. Мне это не требуется, так как у меня по умолчанию
     //установлен ScrollBars := ssVertical.
    TSG.ScrollBars := ssVertical;
 
    for J := 1 to TSG.RowCount - 1 do
      TSG.Cells[0,J] := IntToStr(J);
  end;
end;
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.09.2014, 13:10

Как обратиться к ScrollBar в StringGrid?
Когда соотв. св-во выставлено, и он таки появляется, это же контрол на форме? Как его проперти...

Непонятки с шириной колонок у StringGrid
Здравствуйте еще раз) Перелез с Delphi 7 на Delphi 10 Seattle и никак не могу понять как сделать...

Сравнение колонок StringGrid по строкам
Здравствуйте. Есть StringGrid1 и в нем есть колонки КолA, КолB, кол-во повторов по строкам (см....

Закрашивает не всю ячейку StringGrid
Проблема в следующем: закрашиваю ячейку стринггрида на событие OnDrawCell, а она закрашивается не...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.