Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/21: Рейтинг темы: голосов - 21, средняя оценка - 4.52
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1

Задать изменение ширины всем элементам ввода окна, при изменении ширины самого окна

16.06.2017, 15:40. Показов 4857. Ответов 47
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Товарищи коллеги!
Подскажите, а как подобным образом, задать изменение ширины всем элементам ввода окна, при изменении ширины самого окна?
Пробовал сделать так:
C++
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
int DefWith;//начальный размер
float K=1, K1=1;//коэф-ты соотношения размеров
//---------------------------------------------------------------------------
void __fastcall Tfm_Nastroi::FormResize(TObject *Sender)
{
   if (this->Width > DefWith)//Увеличение ширины окна
   {
      K = this->Width/DefWith;
      K1 = K;
      for( int i = 0; i < this->ComponentCount; i++ )
        if ( this->Components[i]->ClassNameIs( "TComboBox" ) )
           static_cast<TButton*>( this->Components[i] )->Width = K * static_cast<TButton*>( this->Components[i] )->Width;
      for( int i = 0; i < this->ComponentCount; i++ )
        if ( this->Components[i]->ClassNameIs( "TEdit" ) )
           static_cast<TButton*>( this->Components[i] )->Width = K * static_cast<TButton*>( this->Components[i] )->Width;
   }
   if (this->Width == DefWith) //Возврат размера окна в исходное состояние
   {
      for( int i = 0; i < this->ComponentCount; i++ )
        if ( this->Components[i]->ClassNameIs( "TComboBox" ) )
           static_cast<TButton*>( this->Components[i] )->Width = static_cast<TButton*>( this->Components[i] )->Width/K1;
      for( int i = 0; i < this->ComponentCount; i++ )
        if ( this->Components[i]->ClassNameIs( "TEdit" ) )
           static_cast<TButton*>( this->Components[i] )->Width = static_cast<TButton*>( this->Components[i] )->Width/K1;
   }
}
//---------------------------------------------------------------------------
void __fastcall Tfm_Nastroi::FormCreate(TObject *Sender)
{
   DefWith = fm_Nastroi->Width;
}
//---------------------------------------------------------------------------
Результат:
Когда нажимаю кнопку окна "Развернуть", элементы пропорционально расширяются и сдвигаются друг относительно друга по ширине корректно и равномерно.
Но вот при возвращении в исходное состояние окан, они почему-то в свои прежние позиции не становятся, а наезжают друг на друга.

Подскажите, что я возможно забыл задать?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
16.06.2017, 15:40
Ответы с готовыми решениями:

Автоматическое изменение ширины столбца в DBGrid при изменении ширины формы
Подскажите как реализовать или дайте условие автоматического изменение ширины столбца в DBGrid при изменении ширины формы.

Изменение размера картинки при уменьшении ширины окна
Вот пример кода. При уменьшении размера окна появляется скролл снизу и если его подвинуть, изображение залезает под фиксированый блок...

Изменение ширины окна влево
Всем привет) Мне необходимо сделать так, чтобы при наведении форма меняла размер, но не вправо, как это сейчас, а влево, как это можно...

47
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
22.06.2017, 10:28  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от TFullControl Посмотреть сообщение
Не впадает список только в 1 случае - если бокс пуст, если итемы существуют то все выпадает, можете даже не спорить, я так делаю постоянно....у вас Builder 6 у меня RAD Studio 10.1 Berlin.
Вот может по тому у вас этот подход и работает должным образом на 10 билдере, а у меня как-то по другому, т.к. билдер 6? "в 1 случае - если бокс пуст" - в моём случае исключено, т.к. Items боксов я заполнил значениями.
"можете даже не спорить" - Боже упаси! Спорить я не в коем случае не собирался. Я тут не спорить, а прийти к решению поставленной цели пытаюсь Описал свой результат как есть. Ниже приведу код, раз качать проект от B6 вам нет смысла, может по нему заметите чего может не хватать. И дабы не быть голословным, коль проект скидывать нет смысла приложу получившийся экзешник, можете запустить и убедиться, что списки действительно не выпадают.
Код:
C++
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//Unit1.cpp
 
//---------------------------------------------------------------------------
 
#include <vcl.h>
#pragma hdrstop
 
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
 
void TitleStringGrid();
void ComboBoxesInGrid();
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner){}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
   TitleStringGrid();
   ComboBoxesInGrid();
}
//---------------------------------------------------------------------------
void TitleStringGrid()// заполнение шапки таблицы
{
   Form1->sg_SecGrid->Cells[0][0] = "  ¹ ";
   Form1->sg_SecGrid->Cells[0][1] = "   1";
   Form1->sg_SecGrid->Cells[0][2] = "   2";
   Form1->sg_SecGrid->Cells[0][3] = "   3";
   Form1->sg_SecGrid->Cells[0][4] = "   4";
   Form1->sg_SecGrid->Cells[0][5] = "   5";
   Form1->sg_SecGrid->Cells[0][6] = "   6";
   Form1->sg_SecGrid->Cells[0][7] = "   7";
   Form1->sg_SecGrid->Cells[0][8] = "   8";
   Form1->sg_SecGrid->Cells[1][0] = " Наименование ";
   Form1->sg_SecGrid->Cells[2][0] = " Вид секции ";
   Form1->sg_SecGrid->Cells[3][0] = "   СНО ";
   Form1->sg_SecGrid->Cells[4][0] = " № НДС ";
   Form1->sg_SecGrid->Cells[5][0] = " Способ расчёта";
   Form1->sg_SecGrid->Cells[6][0] = " Признак\n предм. расчёта";
   Form1->sg_SecGrid->Cells[7][0] = " Платёжный\n      Агент ";
   Form1->sg_SecGrid->Cells[8][0] = " Поставщик ";
   Form1->sg_SecGrid->Cells[9][0] = " Единицы\n измерения";
}
//---------------------------------------------------------------------------
void ComboBoxesInGrid()// вставка и зполнение ComboBox-ов в ячейки StringGrid'a
{
   int row, col;
   TComboBox *CB;
 
   for (row = 1; row < Form1->sg_SecGrid->RowCount; row++)
   {
      for (col = 2; col < Form1->sg_SecGrid->ColCount; col++)
      {
         CB = new TComboBox(Form1->sg_SecGrid);
         CB->Parent = Form1->sg_SecGrid;
         CB->DropDownCount = 11;
         CB->Style = csDropDownList;
         //CB->Width = Form1->sg_SecGrid->ColWidths[col];
         CB->BoundsRect = Form1->sg_SecGrid->CellRect(col,row);
         if (col == 2)// Вид секции
         {
            CB->Items->DelimitedText=",,";
            CB->Items->Strings[0]="Приход";
            CB->Items->Strings[1]="Закрыта";
            CB->Items->Strings[2]="Расход";
         }
         if (col == 3)// СНО
         {
            CB->Items->DelimitedText=",,,,";    //TODO: переделать значения
            CB->Items->Strings[0]="0";
            CB->Items->Strings[1]="1";
            CB->Items->Strings[2]="2";
            CB->Items->Strings[3]="3";
            CB->Items->Strings[4]="нет";
            CB->ItemIndex = 4;
         }
         if (col == 4)// № НДС
         {
            CB->Items->DelimitedText=",,,,";
            CB->Items->Strings[0]="??";
            CB->Items->Strings[1]="??";
            CB->Items->Strings[2]="??";
            CB->Items->Strings[3]="??";
            CB->Items->Strings[4]="??";
            CB->ItemIndex = 0;
         }
         if (col == 5)// Способ расчёта
         {
            CB->Items->DelimitedText=",,,,,,";
            CB->Items->Strings[0]="нет";
            CB->Items->Strings[1]="Прндопл.100%";
            CB->Items->Strings[2]="Предоплата";
            CB->Items->Strings[3]="Аванс";
            CB->Items->Strings[4]="Полный расчёт";
            CB->Items->Strings[5]="Част.расч. и кредит";
            CB->Items->Strings[6]="Оплата кредит";
            CB->ItemIndex = 0;
         }
         if (col == 6)// Признак предмета расчёта
         {
            CB->Items->DelimitedText=",,,,,,,,,,";
            CB->Items->Strings[0]="нет";
            CB->Items->Strings[1]="Товар";
            CB->Items->Strings[2]="Подакциз. товар";
            CB->Items->Strings[3]="Работа";
            CB->Items->Strings[4]="Услуга";
            CB->Items->Strings[5]="Ставка игры";
            CB->Items->Strings[6]="Выигрыш";
            CB->Items->Strings[7]="Ставка лотереи";
            CB->Items->Strings[8]="Выиг-ш лотереи";
            CB->Items->Strings[9]="Предостав. РНД";
            CB->Items->Strings[10]="Платёж/Выплата";
            CB->ItemIndex = 0;
         }
         if (col == 7)// Платеж. агент
         {
            CB->Items->DelimitedText=",,";
            CB->Items->Strings[0]="нет";
            CB->Items->Strings[1]="1";
            CB->Items->Strings[2]="2";
            CB->ItemIndex = 0;
         }
         if (col == 8)// Поставщик
         {
            CB->Items->DelimitedText=",,";
            CB->Items->Strings[0]="нет";
            CB->Items->Strings[1]="1";
            CB->Items->Strings[2]="2";
            CB->ItemIndex = 0;
         }
         if (col == 9)// Един. измерения
         {
            CB->Items->DelimitedText=",,,,";
            CB->Items->Strings[0]="нет";
            CB->Items->Strings[1]="шт.";
            CB->Items->Strings[2]="л.";
            CB->Items->Strings[3]="кг.";
            CB->Items->Strings[4]="руб.";
            CB->ItemIndex = 0;
         }
      }
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::sg_SecGridDrawCell(TObject *Sender, int ACol,
      int ARow, TRect &Rect, TGridDrawState State)
{//Для переноса строк в шапке странггрида
   String Text;
   if (ARow == 0)
   {
      Text = sg_SecGrid->Cells[ACol][ARow];
      sg_SecGrid->Canvas->FillRect(Rect);
      DrawText(sg_SecGrid->Canvas->Handle, Text.c_str(), Text.Length(), &Rect, DT_WORDBREAK);
   }
}
//---------------------------------------------------------------------------
C++
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
//Unit1.h
 
//---------------------------------------------------------------------------
 
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Grids.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
        TStringGrid *sg_SecGrid;
        void __fastcall FormCreate(TObject *Sender);
        void __fastcall sg_SecGridDrawCell(TObject *Sender, int ACol,
          int ARow, TRect &Rect, TGridDrawState State);
private:    // User declarations
public:     // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
22.06.2017, 11:06  [ТС]
Архив с экзешником проекта
Вложения
Тип файла: zip Исполн.Файл.zip (12.4 Кб, 3 просмотров)
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
22.06.2017, 11:20
Цитата Сообщение от Cha1000000 Посмотреть сообщение
// вставка и зполнение ComboBox-ов в ячейки StringGrid'a
Кто ж так делает? Достаточно заставить GetEditStyle грида вернуть esPickList в тех столбцах, где нужен выпадающий список, и на OnGetPickListitems инплейс-редактора повесить получение собственно списка. Пример приводился здесь: StringGrid, добавить ComboBox в определенный столбец (работает на любой версии Билдера, тестировалось начиная с Portable Builder 6 и заканчивая линейкой XE). Чуть ниже по ссылке - случай, когда для разных столбцов нужно разное содержимое выпадающих списков.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
22.06.2017, 15:56  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Кто ж так делает? Достаточно заставить GetEditStyle грида вернуть esPickList в тех столбцах, где нужен выпадающий список, и на OnGetPickListitems инплейс-редактора повесить получение собственно списка. Пример приводился здесь: StringGrid, добавить ComboBox в определенный столбец (работает на любой версии Билдера, тестировалось начиная с Portable Builder 6 и заканчивая линейкой XE). Чуть ниже по ссылке - случай, когда для разных столбцов нужно разное содержимое выпадающих списков.
Вот с этим вариантом списки выпадают, спасибо! Да и при растягивании ширины ячеек с таким подходом проблем отображения не возникнет. При способе, предлагаемом ранее пришлось бы ещё поплясать с бубном для перерисовки сомбобоксов под новый размер ячейки при изменении ширины окна. Там геморой еще тот, надо как-то уничтожить ранее созданные новые объекты TComboBox, а потом их создавать заново в уже перерисованные с новой шириной ячейки грида...

Добавлено через 1 час 37 минут
Цитата Сообщение от volvo Посмотреть сообщение
выпадающий список
Ну вроде что-то получилось. Однако пока остаётся непонятным, чем можно пользоваться для этих имитированных комбобоксов, аналогично методу ItemIndex оригинальных комбобоксов??? Вот например заполнил я эти списки значениями и хочу по умолчанию задать, чтоб отображался первый элемент (ItemIndex = 0). Как в данной ситуации такое можно сделать?
Или к примеру я буду читать из файла значения, которые указывают на номер элемента в списке Items, который надо будет отобразить в боксе после считывания. Для этого мне опять же подошел бы метод ItemIndex, но его я тут, как понимаю, нет Что делать?
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
22.06.2017, 17:26
Я бы написал еще один метод в классе-перехватчике:
C++
1
2
3
4
5
6
7
8
9
10
11
    class TStringGrid : public Grids::TStringGrid
    {
    public:
        __fastcall void SetCbxByIndex(int ACol, int ARow, int index)
        {
            std::auto_ptr<TStringList> lst(new TStringList);
            GetCbxItems(ACol, ARow, lst.get());
            Cells[ACol][ARow] = lst->Strings[index];
        }
    private:
    // дальше без изменений
, и менял бы, где хочу:

C++
1
2
3
4
5
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    StringGrid1->SetCbxByIndex(1, 1, 4); // будет выставлено значение с индексом = 4 из соответствующего ячейке списка
    StringGrid1->SetCbxByIndex(2, 2, 2); // а тут - с индексом = 2
}
Разумеется, в методе SetCbxByIndex нужны еще проверки, есть ли столько айтемов в списке, и список ли вообще в переданной ячейке, но основа - такая.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
23.06.2017, 11:12  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Я бы написал еще один метод в классе-перехватчике
Классно! Это прям то, что нужно!
Только вот при попытке запуска что-то выдаёт такие ошибки:
C++
1
2
3
4
5
6
Build
  [C++ Error] Unit1.h(19): E2316 'auto_ptr' is not a member of 'std'
  [C++ Error] Unit1.h(19): E2108 Improper use of typedef 'TStringList'
  [C++ Error] Unit1.h(19): E2268 Call to undefined function 'lst'
  [C++ Error] Unit1.h(20): E2294 Structure required on left side of . or .*
  [C++ Error] Unit1.h(21): E2288 Pointer to structure required on left side of -> or ->*
Ну ключевой ошибкой, как я понимаю, является первая, а от неё уже и остальные понеслись... А что вообще собственно такое этот auto_ptr ? Я до сих пор не встречал этой записи нигде... Чего не хватает, чтоб ошибки не было?

Цитата Сообщение от volvo Посмотреть сообщение
Разумеется, в методе SetCbxByIndex нужны еще проверки, есть ли столько айтемов в списке, и список ли вообще в переданной ячейке
Над этим тоже думал, но пока что-то так и не догнал как эту проверку записать... И так ли она необходима? Особенно, когда в конкретной задаче точно знаю сколько в какой колонке у боксов будет айтемов...

Добавлено через 16 минут
Цитата Сообщение от volvo Посмотреть сообщение
Цитата Сообщение от Cha1000000 Посмотреть сообщение
при попытке запуска что-то выдаёт такие ошибки
Пардонте, поторопился с вопросом. Погуглив, нашел, что дело бы в подключении #include <memory>, с ней собралось.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
23.06.2017, 13:26
Цитата Сообщение от Cha1000000 Посмотреть сообщение
пока что-то так и не догнал как эту проверку записать...
C++
1
2
3
4
5
6
7
8
9
10
11
12
        __fastcall void SetCbxByIndex(int ACol, int ARow, int index)
        {
            if(GetEditStyle(ACol, ARow) == esPickList) // Проверяем, список ли
            {
                std::auto_ptr<TStringList> lst(new TStringList);
                GetCbxItems(ACol, ARow, lst.get());
                if(index < lst->Count) // и не вылетим ли за его пределы
                {
                    Cells[ACol][ARow] = lst->Strings[index];
                }
            }
        }
Цитата Сообщение от Cha1000000 Посмотреть сообщение
И так ли она необходима? Особенно, когда в конкретной задаче точно знаю сколько в какой колонке у боксов будет айтемов...
Надежность программы - основной критерий. Сегодня знаю, завтра - забыл, или убрал в одном из списков один элемент, а поправить там, где до этого назначался последний индекс - забыл. Запустил программу, и получил вылет. Это нехорошо. Лучше пускай приложение ничего не занесет в ячейку, чем не запустится вообще.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
23.06.2017, 14:02  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Надежность программы - основной критерий.
Ваша правда! Буду тестировать, спасибо! Если какие вопросы в процессе ещё появятся, напишу позже ;-)
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
25.06.2017, 15:02  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
__fastcall void SetCbxByIndex(int ACol, int ARow, int index)
Таким образом мы выбираем определённые элементы из списка по указанному индексу. Хорошо!
А вот, что бы получить индекс, выбранного из списка элемента (по сути обратная операция, у стандартного комбобокса это - combobox->ItemIndex), для этого тоже следует написать еще один метод в классе-перехватчике? Или можно как-то уже имеющимися средствами получить индекс элемента, выбранного из списка?

P.S. написал этот вопрос заранее, сам предварительно не поэксперементировав, т.к. в данный момент под рукой не на чем "поиграться" (билдер не установлен). Теоретически пока лишь прикинул варианты, опробовать их смогу только завтра на работе. Так, что не сочтите мой вопрос за банальный Просто хочется к моменту, когда снова смогу сесть за ПК со средой, услышать объективное мнение и сразу писать в правильном направлении. Заранее спасибо!
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
25.06.2017, 19:54
Cha1000000, в таком случае проще будет реализовать вот такое свойство:
C++
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
    class TStringGrid : public Grids::TStringGrid
    {
    private:
        int __fastcall GetIndexes(int ACol, int ARow)
        {
            if(GetEditStyle(ACol, ARow) == esPickList)
            {
                std::auto_ptr<TStringList> lst(new TStringList);
                GetCbxItems(ACol, ARow, lst.get());
                return lst->IndexOf(Cells[ACol][ARow]);
            }
            else return (-1);
        }
        void __fastcall SetIndexes(int ACol, int ARow, const int Value)
        {
            if(GetEditStyle(ACol, ARow) == esPickList)
            {
                std::auto_ptr<TStringList> lst(new TStringList);
                GetCbxItems(ACol, ARow, lst.get());
                if(Value < lst->Count)
                {
                    Cells[ACol][ARow] = lst->Strings[Value];
                }
            }
        }
 
    public:
        __property int Indexes[int ACol][int ARow] = {read=GetIndexes, write=SetIndexes};
в классе-перехватчике, и потом его использовать:

C++
1
2
    StringGrid1->Indexes[1][1] = 4; // устанавливаем "ItemIndex"
    ShowMessage(IntToStr(StringGrid1->Indexes[2][2])); // Читаем "ItemIndex"
Можешь обозвать свойство ItemIndex сразу
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
26.06.2017, 09:53  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
вот такое свойство
Ох как здорово! Красота! Весь этот, получившийся, результат теперь даже можно в отдельный кастомный котрол как-то собрать типа в bpl или package (ну как-то так... видеть такое видел, но сам еще не создавал). За одно и что-то новенькое узнал в плане создания кастомных контроллов. Спасибо! Очень продуктивная тема получилась.
Только пока не совсем понял почему функции: virtual TInplaceEdit* __fastcall CreateEditor(void) и DYNAMIC TEditStyle __fastcall GetEditStyle(int ACol, int ARow) вынесены в protected? И для чего используются virtual и DYNAMIC (последний вообще раньше не видел и нигде не встречал...)?
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
26.06.2017, 10:23
У меня в подписи есть ссылка на тему: Классы-перехватчики (interceptor classes) , там в самом низу написано,
Цитата Сообщение от volvo Посмотреть сообщение
как определить, в какой области видимости должны располагаться те или иные методы, и какие методы вообще можно перегружать
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
26.06.2017, 18:25  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
ссылка на тему: Классы-перехватчики (interceptor classes)
Здорово! На досуге обязательно почитаю эту тему, для общего развития, и формы авторизации тоже, пожалуй гляну, может там тоже что интересного и полезного для себя найду.

Добавлено через 7 часов 56 минут
Кстати заметил один неприятный баг сей конструкции... Когда уже в запущенной программе кликаю мышкой на комбобокс, он разворачивается щелчка с третьего: 1 - выделяется ячейка, 2 -становится активным текст бокса (или сам бокс я так и не понял пока), ну а по третьему клику список выпадает, и то если кликнуть именно на кнопку выпадения списка, если просто в центр, курсор устанавливается в положение редактирования текста в ячейке.
Отсюда возникло два вопроса: можно ли как-то сделать так, чтоб по первому клику по комбобоксу список разворачивался, и как запретить редактирование или ввод текста в эти боксы. Список в них чётко установлен и ввод текста в них не предусмотрен, т.к. обработка данных идёт (в моём случае) чисто по ItemIndex-ам.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
26.06.2017, 21:00
Цитата Сообщение от Cha1000000 Посмотреть сообщение
можно ли как-то сделать так, чтоб по первому клику по комбобоксу список разворачивался
Много текста, надеюсь, не бесполезного

C++
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// перед классом формы
namespace SG_ComboBoxes
{
    // Нам нужен метод DropDown у пик-листа,
    // поэтому я сделал отдельный класс
    class TMyInplaceEditList : public TInplaceEditList
    {
    public:
        __fastcall virtual TMyInplaceEditList(Classes::TComponent* Owner) : TInplaceEditList(Owner)
        {
        }
 
        using Grids::TInplaceEditList::DropDown;
    };
 
    class TStringGrid : public Grids::TStringGrid
    {
    private:
        // Это геттер и сеттер для свойства Indexes
        int __fastcall GetIndexes(int ACol, int ARow)
        {
            if(GetEditStyle(ACol, ARow) == esPickList)
            {
                std::auto_ptr<TStringList> lst(new TStringList);
                GetCbxItems(ACol, ARow, lst.get());
                return lst->IndexOf(Cells[ACol][ARow]);
            }
            else return (-1);
        }
        void __fastcall SetIndexes(int ACol, int ARow, const int Value)
        {
            if(GetEditStyle(ACol, ARow) == esPickList)
            {
                std::auto_ptr<TStringList> lst(new TStringList);
                GetCbxItems(ACol, ARow, lst.get());
                if(Value < lst->Count)
                {
                    Cells[ACol][ARow] = lst->Strings[Value];
                }
            }
        }
 
        // Метод, получающий содержимое пик-листа согласно номеру столбца грида
        __fastcall void GetCbxItems(int ACol, int ARow, TStrings *Items)
        {
            Items->Clear();
            switch(ACol)
            {
            case 1:
                Items->CommaText = "item0,item1,item2,item3,item4,item5,item6,item7,item8,item9"; break;
            case 2:
            case 4:
                Items->CommaText = "zero,one,two,three,four,five,six,seven,eight,nine"; break;
            }
        }
 
        // А вот это понадобится, когда мы захотим, чтобы при выборе
        // ячейки с пик-листом, не надо было щелкать еще несколько раз,
        // а он открывался бы немедленно
 
        // с момента, когда была выбрана ячейка с выпадающим списком
        // и до момента, когда этот список будет показан, значение IsMessageSent
        // должно быть выставлено в true, это предотвратит повторную высылку
        // сообщения и вылет приложения
        bool IsMessageSent;
 
        // Назначаем реакцию грида на получение сообщения WM_USER + 1
        // При его получении сработает метод DoDropDownPickList
        BEGIN_MESSAGE_MAP
            VCL_MESSAGE_HANDLER(WM_USER + 1, TMessage, DoDropDownPickList)
        END_MESSAGE_MAP(Grids::TStringGrid);
 
        // Собственно, грид получил уведомление о том, что пользователь
        // выбрал ячейку. И не просто ячейку, а ячейку с пик-листом.
        // Показываем его:
        // 1) переводим ячейку в режим редактирования
        // 2) вызываем у инлайн-редактора метод DropDown, это и покажет список
        // 3) сбрасываем переменную-охранника в обратно в false
        void __fastcall DoDropDownPickList(TMessage& msg)
        {
            EditorMode = true;
            static_cast<TMyInplaceEditList*>(InplaceEditor)->DropDown();
            IsMessageSent = false;
        }
 
    protected:
        // Пользователь выбрал ячейку. Ее индексы уже известны: ACol/ARow,
        // но сама ячейка еще не активировалась, т.е. еще не известен
        // результат метода SelectCell, вдруг он вернет false, и будет
        // запрещено активировать ячейку. Поэтому делаем следующее:
        // проверяем, что это ячейка с выпадающим списком и если да -
        // то "взводим" переменную-охранника и высылаем гриду сообщение.
        // Когда грид получит это сообщение - ячейка уже будет активирована
        // и Col/Row будут хранить правильные координаты ячейки
        virtual bool __fastcall SelectCell(int ACol, int ARow)
        {
            if(!IsMessageSent && GetEditStyle(ACol, ARow) == esPickList)
            {
                IsMessageSent = true;
                ::PostMessage(this->Handle, WM_USER + 1, 0, 0L);
            }
            return Grids::TCustomGrid::SelectCell(ACol, ARow);
        }
 
        // Ну, а дальше - то, что нужно для создания списка в ячейке грида...
        virtual TInplaceEdit* __fastcall CreateEditor(void)
        {
            TInplaceEditList *inplace = new TMyInplaceEditList(this);
            inplace->DropDownRows = 5;
            inplace->OnGetPickListitems = GetCbxItems;
            return inplace;
        }
        DYNAMIC TEditStyle __fastcall GetEditStyle(int ACol, int ARow)
        {
            if(ACol == 1 || ACol == 2 || ACol == 4) return esPickList;
            return esSimple;
        }
    public:
        __fastcall virtual TStringGrid(Classes::TComponent* AOwner)
            : Grids::TStringGrid(AOwner)
        {
        }
 
        __property int Indexes[int ACol][int ARow] = {read=GetIndexes, write=SetIndexes};
 
    __published:
        // Получаем доступ к свойству из предка. Без этого свойства не получится
        // взять инплейс-редактор для текущей ячейки и показать выпадающий список сразу.
        __property InplaceEditor;
    };
}
#define TStringGrid SG_ComboBoxes::TStringGrid


Добавлено через 3 минуты
А что касается
Цитата Сообщение от Cha1000000 Посмотреть сообщение
как запретить редактирование или ввод текста в эти боксы
- так можно в классе TMyInplaceEditList (добавленном выше) перегрузить методы DoKeyDown / DoKeyPress, и в них позапрещать все ненужные кнопки.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
27.06.2017, 10:24  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Много текста, надеюсь, не бесполезного
Ооо! Отнюдь не бесполезного! Наоборот, такие подробные и понятные комментарии я мало где встречал, побольше бы таких... Спасибо большое за столь продуктивные ответы!

Цитата Сообщение от volvo Посмотреть сообщение
перегрузить методы DoKeyDown / DoKeyPress, и в них позапрещать все ненужные кнопки.
С трудом переварив новые модификации в классе, или скорее даже в целом неймспэйсе SG_ComboBoxes, пожалуй для перестраховки, дабы ничего не напутать и не запороть код, уточню:
перегрузить нужно оба метода что ли, или достаточно только DoKeyPress? И перегрузить, в данном случае, имеется в виду оставить имя функции с параметрами как есть (как здесь описано: bool __fastcall DoKeyPress(Winapi::Messages::TWMKey &Message), и лишь в теле функции задать свои условия, или как-то по-другому?? И, запрещая "все ненужные кнопки", в том случае, если ненужными кнопками подразумевется вообще любая кнопка, т.е. в условии запрета не какие-то конкретные кнопки надо указать, а вообще все, для такого случая есть ли какое то "красивое", компактное условие запрета ввода??
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
27.06.2017, 11:04
Упс. Я ошибся, методы DoKey<...> нельзя перегрузить, они не виртуальные. Перегружать надо либо KeyPress, либо KeyDown. Я сделал для KeyDown. На этот раз код будет предельно лаконичным, и длинных комментариев не потребуется:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    class TMyInplaceEditList : public TInplaceEditList
    {
    protected:
        // Это запретит ВСЕ нажатия кнопок в поле ввода выпадающего списка
        DYNAMIC void __fastcall KeyDown(/*System::*/Word &Key, /*System::*/Classes::TShiftState Shift)
        {
            Key = 0;
        }
    public:
        __fastcall virtual TMyInplaceEditList(Classes::TComponent* Owner) : TInplaceEditList(Owner)
        {
        }
 
        using Grids::TInplaceEditList::DropDown;
    };
Это все тестируется на XE4, так что если на ранних версиях будет несоответствие заголовка - то просто зайди в файл Controls.hpp, скопируй из описания класса TWinControl заголовок метода KeyDown, и замени то, что написано в моем коде на версию, подходящую для твоего компилятора. Они должны совпадать.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
27.06.2017, 12:05  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Это запретит ВСЕ нажатия кнопок в поле ввода выпадающего списка
К сожалению не работает Не в смысле не компиллируется, а именно не функционирует. Проект собрался, запустился, выбираю из бокса элемент, но его по-прежнему можно редактировать. Попробовал сделать такой же метод для KeyPress, тоже безрезультатно((
C++
1
2
3
4
5
6
7
8
9
10
protected:
        //Это запретит ВСЕ нажатия кнопок в поле ввода выпадающего списка
        DYNAMIC void __fastcall KeyDown(Word &Key, Classes::TShiftState Shift)
        {
            Key = 0; return;
        }
        DYNAMIC void __fastcall KeyPress(char &Key)
        {
            Key = 0; return;
        }
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
27.06.2017, 12:24
Чуть позже проверю на портабельной версии 6-го Билдера, у меня она где-то на старом компьютере валялась. Но я решительно не понимаю, что там может не работать. Кстати, return у меня не было.
0
6 / 5 / 3
Регистрация: 04.06.2015
Сообщений: 250
Записей в блоге: 1
27.06.2017, 12:51  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Кстати, return у меня не было
Ну это я так для надёжности добавил...
Кстати, пробовал пойти обходным путём, в лоб хотел задать свойству Стринггрида OnKeyPress условия, в его объект-инспекторе, повесил такие обработки:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//глобальные 
int Col, Row;
 
//---------------------------------------------------------------------------
void __fastcall TForm1::sg_SecGridKeyPress(TObject *Sender, char &Key)
{
   for (int c = 2; c < Form1->sg_SecGrid->ColCount; c++)
   if (Col == c)
   {
      Key = 0; return;
   }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::sg_SecGridSelectCell(TObject *Sender, int ACol,
      int ARow, bool &CanSelect)
{
   Col=ACol;
   Row=ARow;
}
//---------------------------------------------------------------------------
Но тоже не прокатило, т.к. перегруженная функция virtual bool __fastcall SelectCell(int ACol, int ARow) уже не даёт получить в глобальные переменные Col и Row индексы. При попытке их поместить в эту перегруженную функцию, а объявление оставив глобальным (по другому пока больше не придумал как ещё можно), получается лютая ошибка...
А что, если по типу virtual bool __fastcall SelectCell(int ACol, int ARow) сделать тоже для стринггридовского KeyPress?
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
27.06.2017, 13:02
Цитата Сообщение от Cha1000000 Посмотреть сообщение
сделать тоже для стринггридовского KeyPress?
Стринггридовский KeyPress в момент, когда показан выпадающий список, неактуален. Ибо у выпадающего списка свой обработчик, и все редактируется именно через него.

Кстати, у меня мой код отработал и на 6-ом Билдере. Так что либо что-то неправильно скопировано, либо какая-то проблема с Билдером (а еще чего хуже - с системой). Я ж говорю: тут нечему НЕ работать - это базовые вещи, на которых построена вся VCL. Если это не будет работать, то и все остальное - тоже.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
27.06.2017, 13:02
Помогаю со студенческими работами здесь

Изменение ширины окна консольного приложения
Доброго времени суток! Наткнулся на тему, но там как - то не особо описано.. Как же всё - таки изменить ширину консольки? Вот тут ещё...

Изменение длины и ширины окна влияет на размеры объектов
Здравствуйте коллеги по цеху, надо сделать простенький текстовый редактор, решил начать с малого, изменения длины и ширины текстового поля...

Пропорциональное изменение высоты CardView при изменении ширины
Используется RecycleView с GrigLayout. Имеется разметка для итемов: &lt;android.support.v7.widget.CardView ...

Изменение масштаба яндекс карты при изменении ширины экрана
Как сделать изменение масштаба яндекс карты при изменении ширины экрана? $this.map.setBounds( $this.branches.getBounds()); В...

Не переносится блок при уменьшении ширины окна
Блочная 2х колоночная резиновая вёрстка При уменьшении ширины окна нужно чтобы правый блок уходил вниз под левый Задал ...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
Установка Emscripten SDK (emsdk) и CMake на Windows для сборки C и C++ приложений в WebAssembly (Wasm)
8Observer8 30.01.2026
Чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. Система контроля версиями Git. . .
Подключение Box2D v3 к SDL3 для Android: физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
Влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru