Конференция "Начинающим" » TMemo как переменная [D7]
 
  • Dimaxx © (27.03.17 23:45) [0]
    Доброго времени, уважаемые господа дельфисты.

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

    Итак, у меня динамически создается PageControl. На его TabSheet'ах также динамически создаются TMemo. Мне нужно в глобальную переменную CurMemo: TMemo положить найденный мемо-контрол на активной вкладке, чтобы обращаться к его методам и свойствам как CurMemo.Clear.

    var CurMemo: TMemo;
    ...
    procedure TForm1.PageCtrlChange(Sender: TObject);
    begin
     CurMemo:=TMemo(PageCtrl.ActivePage.Controls[0]);
    end;
    ...
    procedure SomeProc;
    begin
     CurMemo.Clear; // AV!!
    end;



    Но ничего не выходит - при вызове CurMemo.Clear получаем AV. Решил проще - как в учебниках, через AS. Но! С контролом можно работать только внутри функции/процедуры, где ты его получил. То есть код

    procedure SomeProc;
    var CurMemo: TControl;
    begin
     CurMemo:=PageCtrl.ActivePage.Controls[0]; // получаем мемо как TControl
     TMemo(CurMemo).Clear; // или (CurMemo as TMemo).Clear
    end;



    работает без проблем, все очищается. Но стоит CurMemo: TControl вынести в глобальную и вызвать Clear из любой другой процедуры/функции как написано выше (без получения контрола), то получаем АВ.

    var CurMemo: TControl;
    ...
    procedure TForm1.PageCtrlChange(Sender: TObject);
    begin
     CurMemo:=PageCtrl.ActivePage.Controls[0];
    end;
    ...
    procedure SomeProc;
    begin
     TMemo(CurMemo).Clear; // или (CurMemo as TMemo).Clear // AV!!
    end;



    Все тоже самое во FPC работает без проблем. А дельфя не соглашается так делать. В чем подвох?
  • Германн © (28.03.17 02:30) [1]

    > Вроде не первый год с дельфи

    Знать все эти годы учебники не читались, а вместо чтения учебников использовался код с помоек.
  • Плохиш © (28.03.17 10:10) [2]
    SomeProc вызывается раньше PageCtrlChange

    Ваш КО.
  • D7 (28.03.17 16:24) [3]
    procedure SomeProc(const CurMemo: TMemo);
  • Sha © (28.03.17 17:03) [4]
    может, забыл создать CurMemo?
  • Dimaxx © (28.03.17 20:25) [5]
    > Знать все эти годы учебники не читались, а вместо чтения учебников использовался код с помоек.
    Я не просил углубляться в историю кто, чего и где читал. Я просил совета. Я с подобным динамическим управлением сталкиваюсь впервые. С динамическими созданиями контролов и заполнениями проблем нет. Я много чего читал, но что-то улетучилось из-за неиспользования и за давностью лет.

    > procedure SomeProc(const CurMemo: TMemo);
    > может, забыл создать CurMemo?
    Нет, КО выиграл. Действительно, я проверял на одной вкладке - ессно там OnChange еще не вызывался (хотя вновь создаваемая вкладка у меня автоматически делается активной и я посчитал, что это вызовет OnChange). Но стоило сделать две и переключиться на другую, как все заработало. Вот в который раз убеждаюсь, что нефига программить поздно вечером на ночь глядя - слона-то я и не заметил. Заработал метод с TMemo как с переменной - CurMemo:=TMemo(Memo1); и CurMemo.Clear;
  • D7 (28.03.17 21:03) [6]
    Просто изначально неудачная идея делать подобную глобальную переменную и работать с нею из обычной функции. Да ещё и Assigned не проверять.
    Сделайте поле класса. Инициализируйте его значение при создании, меняйте при событии, и просто обращайтесь как к полю Self.
  • Dimaxx © (28.03.17 22:22) [7]
    Да надо будет все облагородить - я ж просто для примера сделал, без каких-либо проверок. Как оказалось, делал-то все верно, но забыл, что переменная не проинициализирована. Отсюда АВ. Там много чего еще хранить надо будет, кроме мемо. Ессно придется все это как-то оборачивать для удобства.
  • D7 (29.03.17 02:04) [8]
    Можно либо сделать наследников от PageControl и TTabSheet - создавать сразу с TMemo, создать поле CurMemo и поддерживать его актуальность.
    Ну либо бюджетный вариант:
    unit Unit1;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;

    type
     TForm1 = class(TForm)
       PageControl1: TPageControl;
       Button1: TButton;
       Button2: TButton;
       Button3: TButton;                        
       procedure FormCreate(Sender: TObject);  
       procedure PageControl1Change(Sender: TObject);
       procedure Button1Click(Sender: TObject);
       procedure Button2Click(Sender: TObject);    
       procedure Button3Click(Sender: TObject);
     private
       CurrentMemo: TMemo;
       procedure TabAdd(P: TPageControl; const Activate: Boolean = False);
       procedure TabDeleteActive(P: TPageControl);
       procedure TabDeleteIndex(P: TPageControl; const Index: Integer);
     public
       //
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}  

    const
     NEW_TAB_TITLE = 'New Tab';
     TAB_MEMO_NAME = 'TabMemo';

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    CurrentMemo:=nil;
    end;

    procedure TForm1.TabAdd(P: TPageControl; const Activate: Boolean = False);
    var T: TTabSheet; M: TMemo;
    begin
    if not Assigned(P) then Exit;
    T:=TTabSheet.Create(P);
    T.Caption:=NEW_TAB_TITLE;
    M:=TMemo.Create(T);
    M.Name:=TAB_MEMO_NAME;
    M.Text:='#'+IntToHex(GetTickCount(), 8);
    M.Align:=alClient;
    M.ScrollBars:=ssBoth;
    M.Parent:=T;
    T.PageControl:=P;
    if Activate then
     P.ActivePage:=T;
    P.OnChange(P);
    end;

    procedure TForm1.TabDeleteActive(P: TPageControl);
    begin  
    if not Assigned(P) then Exit;
    if (P.PageCount>0) then
     begin
     P.ActivePage.Free();
     P.OnChange(P);
     end;
    end;

    procedure TForm1.TabDeleteIndex(P: TPageControl; const Index: Integer);
    begin
    if not Assigned(P) then Exit;
    if (P.PageCount>0) and (Index>=0) and (Index<P.PageCount) then
     begin
     P.Pages[Index].Free();
     P.OnChange(P);
     end;
    end;

    procedure TForm1.PageControl1Change(Sender: TObject);
    var M: TComponent;
    begin
    CurrentMemo:=nil;
    with TPageControl(Sender) do
     if (PageCount>0) then
       begin
       M:=ActivePage.FindComponent(TAB_MEMO_NAME);
       if (M is TMemo) then
         CurrentMemo:=TMemo(M);
       end;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    TabAdd(PageControl1, True);
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    begin
    if Assigned(CurrentMemo) then
     ShowMessage(CurrentMemo.Text);
    end;

    procedure TForm1.Button3Click(Sender: TObject);
    begin
    TabDeleteActive(PageControl1);
    end;

    end.
  • Dimaxx © (29.03.17 21:01) [9]
    >> Можно либо сделать наследников от PageControl и TTabSheet - создавать сразу с TMemo
    Я уже думал сделать наследника PageControl с внутренним управлением CurMemo, без внешних вмешательств.

    >> M:=ActivePage.FindComponent(TAB_MEMO_NAME);
    TabSheet возвращает ComponentCount=0 при динамическом размещении контролов на нем, поэтому пришлось через Controls/ControlCount.
  • Dimaxx © (29.03.17 21:06) [10]
    >> ComponentCount=0
    Тьфу, если при создании указывать родителя, то <>0. Я указывал Create(nil).
  • D7 (29.03.17 21:48) [11]
    Причём тут ComponentCount? Представленный в [8] код рабочий и в нём такого нету. :)
    Родитель == nil это с одной стороны допустимо, но тут лучше так не делать, родитель Меме - вкладка.
 
Конференция "Начинающим" » TMemo как переменная [D7]
Есть новые Нет новых   [118591   +45][b:0][p:0.001]