Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.52/25: Рейтинг темы: голосов - 25, средняя оценка - 4.52
0 / 0 / 0
Регистрация: 21.11.2011
Сообщений: 47

Frame, TabSheet и их Free/Destroy кнопкой на форме

28.03.2020, 00:13. Показов 5542. Ответов 35

Студворк — интернет-сервис помощи студентам
Уважаемые специалисты, подскажите в следующем вопросе.
Имеется Фрейм с заготовленной формой, который будет подставляться на закладки PageControl'а. Создавать страниц я могу сколько угодно без проблем, удалять их кнопкой, не являющейся Child'ом PageControl'а могу без проблем, но мне нужно, чтобы эту вкладку я мог закрыть с кнопки, которая находится на ней, а вернее на фрейме, который появляется на этой вкладке, т.е. сделать Free или Destroy страницы изнутри.

Тестовый код
Форма

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
69
70
71
72
73
74
75
unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, cxGraphics, cxControls, cxLookAndFeels,
  cxLookAndFeelPainters, dxSkinsCore, dxSkinCaramel, dxSkinCoffee,
  dxSkinscxPCPainter, dxBarBuiltInMenu, Vcl.Menus, cxPC, Vcl.StdCtrls,
  cxButtons;
 
type
  TForm1 = class(TForm)
    cxPageControl1: TcxPageControl;
    cxButton1: TcxButton;
    cxButton2: TcxButton;
    cxTabSheet1: TcxTabSheet;
    procedure cxButton1Click(Sender: TObject);
    procedure cxButton2Click(Sender: TObject);
    procedure test;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
  f: TFrame;
 
implementation
 
{$R *.dfm}
 
uses FrameUnit;
 
procedure TForm1.cxButton1Click(Sender: TObject);
Var
  nTab: TcxTabSheet;
  n: string;
  page_index: Integer;
begin
  page_index := cxPageControl1.PageCount + 1;
  nTab := TcxTabSheet.Create(cxPageControl1);
  with nTab do
  begin
    n := 'Page_' + IntToStr(page_index);
    PageControl := cxPageControl1;
    Tag := cxPageControl1.PageCount + 1; // Mark for enable to close tab
    Name := n;
    Caption := n;
    // if f <> nil then
    // begin
    // FreeAndNil(f);
    // end;
    f := TFrameFrm.Create(nTab);
    f.Parent := nTab;
    f.Align := alClient;
    f.Visible := true;
  end;
  // nTab.Free
end;
 
procedure TForm1.cxButton2Click(Sender: TObject);
begin
  test;
end;
 
procedure TForm1.test;
begin
  cxPageControl1.CloseTab(cxPageControl1.ActivePageIndex);
end;
 
end.
Фрейм

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
unit FrameUnit;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, cxGraphics,
  cxLookAndFeels, cxLookAndFeelPainters, Vcl.Menus, dxSkinsCore, dxSkinCaramel,
  dxSkinCoffee, Vcl.StdCtrls, cxButtons, cxControls, dxSkinscxPCPainter,
  dxBarBuiltInMenu, cxPC;
 
type
  TFrameFrm = class(TFrame)
    cxButton1: TcxButton;
    procedure cxButton1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
implementation
 
{$R *.dfm}
 
uses Unit1;
 
procedure TFrameFrm.cxButton1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  Form1.test;
end;
 
end.
По кнопке с главной формы всё норм, а при нажатии кнопки с фрейма выдаётся сообщение: "Control '' has no parent window"
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
28.03.2020, 00:13
Ответы с готовыми решениями:

Как программно добавить Frame в другой существующий на форме frame?
Делаю это так: На форме лежит Frame1. на инициализации формы.... Dim mFrame As Object

Перебор всех frame на форме
Здравствуйте. Подскажите, пожалуйста, каким образом перебрать все frame на форме. Мне их нужно сделать все невидимыми. А показывать...

Перемещение по форме кнопкой
Здравствуйте, возникла проблема в реализации программы на WinForms. Сама проблема в чем, есть на форме кнопки При нажатии на кнопку 1, в...

35
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
30.03.2020, 15:57
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от AzAtom Посмотреть сообщение
А если несколько раз создать по несколько вкладок и удалить их?
Попробуй ) у меня никаких ошибок. Исходник в архиве
Миниатюры
Frame, TabSheet и их Free/Destroy кнопкой на форме  
Вложения
Тип файла: zip TABFRAMES.ZIP (644.3 Кб, 16 просмотров)
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
30.03.2020, 16:01
наблюдение: динамически создаваемому фрейму обязательно присваивать свойство Name (разное). иначе ругается
фрейм
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
unit Unit2;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons;
 
type
  TmyFrame = class(TFrame)
    SpeedButton1: TSpeedButton;
    Label1: TLabel;
    procedure CloseClick(Sender: TObject);
  public
    procedure ShowName;
  end;
 
implementation
 
{$R *.dfm}
 
procedure TmyFrame.CloseClick(Sender: TObject);
begin
  Self.Parent.Free;
end;
 
procedure TmyFrame.ShowName;
begin
  Label1.Caption:= Name;
end;
 
end.

форма
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
unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls,
  Unit2;
 
type
  TForm1 = class(TForm)
    PageControl1: TPageControl;
    Button1: TButton;
    procedure AddTab(Sender: TObject);
  end;
 
var
  Form1: TForm1;
  i: integer = 0;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.AddTab(Sender: TObject);
var
  T: TTabSheet;
begin
  T:= TTabSheet.Create(Self);
  Inc(i);
  with T do
  begin
    PageControl:= PageControl1;
    Caption:= 'TabSheet' + IntToStr(i);
  end;
  with TmyFrame.Create(Self) do
  begin
    Name:= 'Frame'+IntToStr(i);
    Parent:= T;
    ShowName;
  end;
end;
 
end.
0
Модератор
4153 / 2362 / 814
Регистрация: 15.11.2015
Сообщений: 9,497
30.03.2020, 19:44
DenNik, пробовал в D7, вылетает независимо от Name. Теперь попробовал и в XE3, не вылетает и без Name.

Добавлено через 28 секунд
Думаю, всё же, уничтожать объект из вызванного им обработчика неправильно.
0
0 / 0 / 0
Регистрация: 21.11.2011
Сообщений: 47
30.03.2020, 21:35  [ТС]
У меня задача сделать похожее на 1С, чтобы при нажатии кнопки "Закрыть" в форме редактирования закрывалась вкладка, которая по совместительству является родителем кнопки. Как, тогда, это можно правильно реализовать?
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
30.03.2020, 21:40
Ну можно сделать, как у формы. Метод close через postmessage в итоге вызывает free, что, по-видимому, гарантирует корректное освобождение памяти
1
Модератор
 Аватар для D1973
9954 / 6490 / 2461
Регистрация: 21.01.2014
Сообщений: 27,495
Записей в блоге: 3
30.03.2020, 21:42
Цитата Сообщение от Wolf6606 Посмотреть сообщение
в форме редактирования закрывалась вкладка
Вот прямо закрывалась, а не скрывалась? А почему? И что, для редактирования очередной записи заново создавать? Не проще ли делать видимой/невидимой, загружая необходимые данные?
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
31.03.2020, 11:53
по мотивам...
Цитата Сообщение от DenNik Посмотреть сообщение
можно сделать, как у формы. Метод close через postmessage в итоге вызывает free
+ наследник TTabSheet с привязанным автоматически создаваемым фреймом.
+ доступ к фрейму извне.
- не разобрался, как PageControl присваивает вкладке Caption с неповторяющимся индексом, но это и не важно.
! насчёт имени фрейма. Как видно из теста, фрейму автоматически присваивается имя класса без Т, соответственно, если Owner у фреймов будет один и тот же, при создании очередного фрейма будет ругаться, что компонент с таким именем уже есть. А, как известно, конструктору передается именно Owner. Поэтому фрейму присваивается Owner - вкладка, на которой он распололжен.

фрейм
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
69
unit Unit2;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ComCtrls;
 
type
  TmyFrame = class;
 
  TMyTabSheet = class(Vcl.ComCtrls.TTabSheet)
  private
    FFrame: TmyFrame;
  protected
    procedure CMRelease(var Msg: TMessage); message CM_RELEASE;
  public
    procedure Release;
    constructor Create(AOwner: TComponent; APageControl: TPageControl);
    property Frame: TmyFrame read FFrame;
  end;
 
  TmyFrame = class(TFrame)
    SpeedButton1: TSpeedButton;
    Label1: TLabel;
    procedure CloseClick(Sender: TObject);
  public
    procedure ShowName;
  end;
 
implementation
 
{$R *.dfm}
 
procedure TmyFrame.CloseClick(Sender: TObject);
begin
  TMyTabSheet(Parent).Release;
end;
 
procedure TmyFrame.ShowName;    {TEST}
begin
  Label1.Caption:= Name;
end;
 
{ TMyTabSheet }
 
procedure TMyTabSheet.CMRelease(var Msg: TMessage);
begin
  Free;
end;
 
constructor TMyTabSheet.Create(AOwner: TComponent; APageControl: TPageControl);
var
  myFrame: TmyFrame;
begin
  inherited Create(AOwner);
  PageControl:= APageControl;
  Caption:= 'TabSheet' + IntToStr(PageIndex+1);
  myFrame:= TmyFrame.Create(Self);
  myFrame.Parent:= Self;
  FFrame:= myFrame;
end;
 
procedure TMyTabSheet.Release;
begin
  PostMessage(Handle,CM_RELEASE,0,0);
end;
 
end.


форма
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
unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls,
  Unit2;
 
type
  TForm1 = class(TForm)
    PageControl1: TPageControl;
    Button1: TButton;
    procedure AddTab(Sender: TObject);
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.AddTab(Sender: TObject);
begin
  TMyTabSheet.Create(Self,PageControl1).Frame.ShowName;
end;
 
end.
Миниатюры
Frame, TabSheet и их Free/Destroy кнопкой на форме  
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
31.03.2020, 11:56
исходник
Вложения
Тип файла: zip TABFRAMES2.ZIP (644.7 Кб, 4 просмотров)
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
31.03.2020, 11:59
подчистил тестовый мусор. Апгрейд процедуры
Delphi
1
2
3
4
5
6
7
8
constructor TMyTabSheet.Create(AOwner: TComponent; APageControl: TPageControl);
begin
  inherited Create(AOwner);
  PageControl:= APageControl;
  Caption:= 'TabSheet' + IntToStr(PageIndex+1);
  FFrame:= TmyFrame.Create(Self);
  FFrame.Parent:= Self;
end;
0
Модератор
4153 / 2362 / 814
Регистрация: 15.11.2015
Сообщений: 9,497
31.03.2020, 14:22
Создание вкладки с Frame и её уничтожение нажатием на кнопку в фрейме.
Код формы:
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
type
  TForm1 = class(TForm)
    Button1: TButton;
    PageControl1: TPageControl;
    ApplicationEvents1: TApplicationEvents;
    procedure Button1Click(Sender: TObject);
    procedure ApplicationEvents1Idle(Sender: TObject; var Done: Boolean);
  private
    { Private declarations }
  public
    { Public declarations }
    TabToFree: TTabSheet;
    procedure OnFrameCloseQuery(Sender: TObject);
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
var
  T: TTabSheet;
begin
  T := TTabSheet.Create(PageControl1);
  T.Parent := PageControl1;
  T.PageControl := PageControl1;
  T.Caption := 'Вкладка';
  with TFrame2.Create(T) do begin
    Parent := T;
    OnCloseQuery := OnFrameCloseQuery; // Обработчик запроса закрытия фрейма
  end;
end;
 
procedure TForm1.ApplicationEvents1Idle(Sender: TObject;
  var Done: Boolean);
begin
  // Событие OnIdle возникает после обработки каждого сообщения и если
  // имеется вкладка для удаления, то она удаляется
  if Assigned(TabToFree) then begin
    TabToFree.Free;
    TabToFree := nil;
  end;
end;
 
procedure TForm1.OnFrameCloseQuery(Sender: TObject);
begin
  // Обработчик запроса на закрытие фрейма.
  // Сохраняет в переменной адрес вкладки, которую нужно закрыть.
  if Sender is TFrame then
    TabToFree := (Sender as TFrame).Parent as TTabSheet;
end;
 
end.
Код фрейма:
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
type
  TFrame2 = class(TFrame)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    FCloseQuery: TNotifyEvent;
  public
    { Public declarations }
    // Добавил событие закрытия фрейма
    property OnCloseQuery: TNotifyEvent read FCloseQuery write FCloseQuery;
  end;
 
implementation
 
{$R *.dfm}
 
procedure TFrame2.Button1Click(Sender: TObject);
begin
  if Assigned(FCloseQuery) then FCloseQuery(Self);
end;
 
end.
Вложения
Тип файла: rar FrameOnPage.rar (2.7 Кб, 4 просмотров)
1
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
31.03.2020, 15:08
Цитата Сообщение от AzAtom Посмотреть сообщение
T.Parent := PageControl1;
табшиту родителя присваивать не обязательно. достаточно
Цитата Сообщение от AzAtom Посмотреть сообщение
T.PageControl := PageControl1;
Добавлено через 3 минуты
так-то норм. только зачем прокладка из AppIdle?
0
Модератор
4153 / 2362 / 814
Регистрация: 15.11.2015
Сообщений: 9,497
31.03.2020, 15:59
Цитата Сообщение от DenNik Посмотреть сообщение
табшиту родителя присваивать не обязательно.
Хай будет. Я привык всем родителя присваивать, не хочу запоминать, кому можно не присваивать.

Цитата Сообщение от DenNik Посмотреть сообщение
зачем прокладка из AppIdle?
Чтобы не делать прокладку из потока, таймера или сообщения. В принципе, сообщением может даже и лучше, можно сразу передать адрес уничтожаемого таба.
1
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
31.03.2020, 16:10
Цитата Сообщение от AzAtom Посмотреть сообщение
сообщением может даже и лучше,
Ну если в исходниках Delphi так - разве может это быть плохо
0
Модератор
4153 / 2362 / 814
Регистрация: 15.11.2015
Сообщений: 9,497
31.03.2020, 16:39
Цитата Сообщение от DenNik Посмотреть сообщение
если в исходниках Delphi так - разве может это быть плохо
Может быть не совсем хорошо. В VCL встречаются сомнительные решения. Самое главное - организация окон приложения. Аж раздражает...
0
Житель Земли
 Аватар для DenNik
3004 / 3026 / 390
Регистрация: 26.07.2011
Сообщений: 11,465
Записей в блоге: 1
31.03.2020, 16:54
Цитата Сообщение от AzAtom Посмотреть сообщение
организация окон приложения. Аж раздражает...
Какая организация?
0
Модератор
4153 / 2362 / 814
Регистрация: 15.11.2015
Сообщений: 9,497
31.03.2020, 17:27
DenNik, у Application есть невидимое окно с кнопкой на панели задач, а видимые окна-формы не имеют своих значков на панели задач. Из-за этого глюк при переключении по Alt+Tab в win7+aero, приходится по 2 раза нажимать Tab.

Такая же ситуация возникает в любом другом нормальном приложении при вызове окна "Открыть"/"Сохранить как..." и попытке переключения по Alt+Tab. Иногда нормально переключается, а иногда приходится Tab жать 2 раза.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
31.03.2020, 17:27

Выполнение макроса кнопкой в форме
Создан макрос, теперь требуется прицепить его к кнопке. В свойствах описываю название макроса, количество выполнения 1, а вот условие никак...

Поворот Label на форме кнопкой
Столкнулся с проблемой,создал форму на ней лейбл и кнопки.Кнопки двигают лейбл во все стороны,еще 2 кнопки увеличивают и уменьшают,а надо...

Создание запроса кнопкой в форме
Можно ли сделать такое: В форме есть кнопка. Нажимаешь кнопку - открывается окно создания нового запроса в конструкторе. Возможно...

Выключение компьютера кнопкой на форме
Как выключить компьютер с помощью кнопки на форме.

Кнопкой открыть кнопку в другой форме
Есть Form1. В ней кнопка с кодом. Необходимо, чтобы при нажатии на нее открывалась Form3. Там есть две кнопки (да и нет). Далее, если мы...


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

Или воспользуйтесь поиском по форуму:
36
Ответ Создать тему
Новые блоги и статьи
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Nekobox - outbounds[0].transport: unknown transport type: raw
damix 01.10.2026
Фикс ошибки Правым кликом по серверу -> отладочная информация -> edit Заменить "net": "raw", на "net": "tcp", Нажать кнопку reload.
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru