Конференция "Media" » Canvas в MDI приложении [D7, WinXP]
 
  • dan-1608 © (19.06.12 15:51) [0]
    Добрый день!
    Делфи начал изучать сравнительно недавно!
    Проблема следующая: хочу рисовать на дочерней форме Form2 произвольную фигуру, допустим, канвой Image1 или Form2 и компилятор Делфи без конца ругается на доступ в запрешенную область. Сделал отрисовку на SDI форме, там все получается без проблем, теперь хочу перейти на MDI форму (все же более продвинуто), где в дочерней Form2 будет рабочая область, а в Form1 меню с кнопками по управлению графикой Form2 (цвет заливки, масштаб фигуры и т.д).

    Форумчане, подскажите можно ли вообще рисовать на канве в дочерней форме, скажем, или может каким другим способом это можно осуществить, код в SDI уже написал.
  • Омлет © (19.06.12 17:02) [1]
    Компилятор же человеческим языком ругается. Что именно говорит? По поводу какого кода?
    А рисовать на дочерней форме можно, имея ссылку на неё.
  • Cobalt © (19.06.12 17:03) [2]
    Как ругается компилятор - это твой самый главный секрет.
  • dan-1608 © (19.06.12 22:05) [3]
    Ошибка появляется когда кликаю на Form2.Image1 и компилятор доходит то строчки Form2.Image1.Canvas.Brush.Color := Form1.ColorBox3.Selected; при нажатии на кнопке создания Form2
    Ошибка следующая:
    Project Batar7ob.exe raised exception class EAccessViolation with message 'Access violation at address 0045CF21 in module 'Batar7ob.exe'.Read of address 000002FC '. Process stopped.  Use Step or Run to continue.


    unit Workspace;

    interface


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

    type
    TForm2 = class(TForm)
     BitBtn1: TBitBtn;
       Image1: TImage;
     procedure BitBtn1Click(Sender: TObject);
     procedure FormClose(Sender: TObject; var Action: TCloseAction);
     procedure FormActivate(Sender: TObject);
     procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
         Shift: TShiftState; X, Y: Integer);

     private
       { Private declarations }
     public
       { Public declarations }
       constructor Create(AOwner: TComponent); override;
     end;

    var
    Form2: TForm2;

    implementation
    uses Basicparty;
    {$R *.dfm}

    constructor TForm2.Create;

    begin
     inherited Create(AOwner);
    end;

    procedure TForm2.BitBtn1Click(Sender: TObject);
    begin
     Close;
    end;

    procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
     Action := caFree;
    end;

    procedure TForm2.FormActivate(Sender: TObject);
    begin
     Form1.ColorBox1.ParentColor := True;
     Form1.ColorBox2.ParentColor := True;
     Form1.ColorBox3.ParentColor := True;
     ColorFon := Form1.ColorBox3.Selected;

     ActiveChanged;        //мои попытки, сделать активной Form2 чтобы рисовалось на ней
     FocusControl(Form2);
     Show;
     SetFocus;

     Form2.Image1.Canvas.Brush.Color := Form1.ColorBox3.Selected;
     Form2.Image1.Canvas.Rectangle(0,0,800,600);

     ArrBatar[i] := Tbatar.Create();
     ArrBatar[i].ColorFig := Form1.ColorBox1.Selected;
     ArrBatar[i].ColorZal := Form1.ColorBox2.Selected;
     ArrBatar[i].Scale := Form1.ComboBox1.ItemIndex;
     ArrBatar[i].SetX(Form1.Width div 2) ;
     ArrBatar[i].SetY(Form1.Height div 2);
     ArrBatar[i].Paint(ArrBatar[i].Scale,ArrBatar[i].X0,ArrBatar[i].Y0);
     ArrBatar[i].DrawText();
    end;

    procedure TForm2.Image1MouseDown(Sender: TObject; Button: TMouseButton;
     Shift: TShiftState; X, Y: Integer);
    var
    deltaX,deltaY: integer;
    begin
     if ssLeft in Shift then             // клик по левой кнопке мыши
      begin
       deltaX := (MyMouse.CursorPos.X-Form2.Image1.Left-4) - ArrBatar[i].X0;
       deltaY := (MyMouse.CursorPos.Y-Form2.Image1.Top-32) - ArrBatar[i].Y0;
       ArrBatar[i].Move(ArrBatar[i],deltaX,deltaY);
       ArrBatar[i].DrawText();
      end;

     if ssRight in Shift then       // клик по  правой кнопке мыши
      begin
       i := i+1;

       ArrBatar[i] := TBatar.create();
       ArrBatar[i].Scale := Form1.ComboBox1.ItemIndex;
       ArrBatar[i].ColorFig := Form1.ColorBox1.Selected;
       ArrBatar[i].ColorZal := Form1.ColorBox2.Selected;
       ArrBatar[i].X0 := MyMouse.CursorPos.X-Form2.Left-4;
       ArrBatar[i].Y0 := MyMouse.CursorPos.Y-Form2.Top-32;
       ArrBatar[i].Paint(ArrBatar[i].Scale,ArrBatar[i].X0,ArrBatar[i].Y0);
       ArrBatar[i].DrawText();
       Form2.Image1.Refresh; //обновляет после изменения масштаба

      end;
    end;

    end.
  • dan-1608 © (19.06.12 22:08) [4]

    > А рисовать на дочерней форме можно, имея ссылку на неё.


    Я вроде так и делаю
    Form2.Image1.Canvas.Brush.Color := Form1.ColorBox3.Selected;


    Поправьте, пожалуйста, если, что то не так...
  • Омлет © (19.06.12 22:29) [5]
    А переменную Form2 нигде не меняешь?

    И в методах класса TForm2 можно обращаться к его полям напрямую. Т.е. вместо
    Form2.Image1.Canvas.Brush.Color := Form1.ColorBox3.Selected;


    должно быть
    Image1.Canvas.Brush.Color := Form1.ColorBox3.Selected;



    Настоятельно советую учебник почитать. Вслепую ты черти что нагородил уже.
  • dan-1608 © (19.06.12 22:41) [6]
    Всмысле не меняю??  
    Form2 создается всякий раз при нажатии на Form1.Button2 (планирую сделать многопоточность воркспейсов) вот код создания Form2.
    procedure TForm1.Button2Click(Sender: TObject);
    begin
     j:= j+1;
     Form2 := TForm2.Create(Application);
     With Form2 do
      begin
       BorderIcons := [biSystemMenu] + [biMinimize];
       Caption:= 'Workspace'+IntToStr(j);
       Width := 800;
       Height := 600;
       Visible := True;
      end;
    end;

  • dan-1608 © (19.06.12 22:49) [7]
    Спасибо за совет - помогло, прошел то место, но проблема с формой не решилась... встало дальше на сточке..

    ArrBatar[i].X0 := MyMouse.CursorPos.X-Form2.Left-4;



    Подсказка, при наводе на слово Form2, пишет Form2=nil , Form2.Left=Inaccessible value
  • Омлет © (19.06.12 22:59) [8]
    Я же говорю - где-то затирается переменная Form2.
    И, повторяю, не обращайся к переменной Form2 внутри её же методов.

    Пиши
    ArrBatar[i].X0 := MyMouse.CursorPos.X - Left - 4;

  • dan-1608 © (20.06.12 00:37) [9]
    Спасибо, заработало, как в том мульфильме))..но на половину решилась, дело в чем, в коде, который находится в процедуре (т.е вне методов Form2) procedure Tbatar.Paint(scale,X,Y:integer); появляется примерно такого содержания, Form2.Image1.Width опять Inaccessible value, вопрос куда девается переменная Form2, никак не могу найти
    if (X2party > Form2.Image1.Width) or (Y2body > Form2.Image1.Height) then
       begin
        Showmessage('Фигура за границами экрана!');
        Exit;
       end;

  • Омлет © (20.06.12 07:23) [10]
    > вопрос куда девается переменная Form2, никак не могу найти

    Диссациирует втуне.
  • Cobalt © (20.06.12 07:44) [11]
    поиск по коду рулит.
  • dan-1608 © (20.06.12 09:53) [12]

    > Диссациирует втуне


    а это как, можно поподробнее?))
  • Cobalt © (20.06.12 10:03) [13]
    Тебе намекают, что ты переменную обнуляешь не вовремя.

    Есть такая замечательная команда в Delphi - Search->Find in files
    указываешь имя переменной, поиск по всему проекту, и проверяешь где и когда ты туда что-то записываешь.
  • dan-1608 © (20.06.12 10:05) [14]
    понял) щас попробую
  • dan-1608 © (20.06.12 10:33) [15]
    В общем прогнал по всем упоминаниям, не заметил затирания, единственно - нашел по вотч листу, что в своих методах класса Image1.Width = 810, а переменная Form2.Image1.Width = Inaccessible value, естественно, что во внешних процедурах Image1.Width =Inaccessible value, а глобальной Form2.Image1.Width то и нету... такое ощущение что, в модуле Basicparty, (так где как раз это злополучная процедура Tbatar.Paint(scale,X,Y:integer)) значение Width нету
  • dan-1608 © (20.06.12 11:07) [16]
    Уважаемые, мастера, посмотрите, пожалуйста, может я просто неправильно прикрутил Form2 (находится в модуле Workspace) к модулю Basicparty поэтому и Form2.Image1.Width = Inaccessible value

    unit Basicparty;

    interface

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

    type
      Tbatar = class   //объявление класса батареек
      private
       FNazv:string;
       FId:integer;
       FX0:integer;
       FY0:integer;  //координаты опорной точки (левый верхний)
       Fwidth: integer;
       Fheight: integer;
       FColorFig:TColor; //цвет фигуры
       FColorZal:TColor; //цвет заливки фигуры
       FScale: Integer;  //цвет фигуры

      public

       procedure Paint(scale,X,Y:integer);
       procedure Move(Batar: TBatar; deltaX,deltaY: integer);
       procedure SetX(X:integer);
       procedure SetY(Y:integer);
       procedure SetScale(Sc:integer);
       procedure SetColorFig(ColFig:TColor);
       procedure SetColorZal(ColZal:TColor);
       procedure DrawText();
       constructor Create();

       property  Nazv: string read FNazv;
       property  X0: integer read FX0 write SetX;
       property  Y0: integer read FY0 write SetY;
       property  Scale: integer read FScale write SetScale;
       property  Width: integer read Fwidth;
       property  Height: integer read Fheight;

       property  ColorFig: TColor read FColorFig write SetColorFig;
       property  ColorZal: TColor read FColorZal write SetColorZal;

       end;

     TForm1 = class(TForm)
       Button1: TButton;
       ComboBox1: TComboBox;
       ColorBox1: TColorBox;
       Label1: TLabel;
       Label2: TLabel;
       Label3: TLabel;
       ColorBox2: TColorBox;
       //Image1: TImage;
       Label4: TLabel;
       ColorBox3: TColorBox;
       ComboBox2: TComboBox;
       Label5: TLabel;
       Label6: TLabel;
       Button2: TButton;
       ListBox1: TListBox;
       Label7: TLabel;
       procedure Button1Click(Sender: TObject);
       procedure ComboBox1Change(Sender: TObject);
       procedure ColorBox1Change(Sender: TObject);
       procedure ColorBox2Change(Sender: TObject);
       procedure ColorBox3Change(Sender: TObject);
       procedure FormCreate(Sender: TObject);

       procedure FormKeyPress(Sender: TObject; var Key: Char);
       procedure Button2Click(Sender: TObject);
       procedure ListBox1KeyPress(Sender: TObject; var Key: Char);


     private

     public
       { Public declarations }
     end;

    var
     Form1: TForm1;
     //Form2: TForm1;
     Batar1: TBatar;
     Batar2: TBatar;

     //scale: integer; // масштаб
     ColorFon: TColor; // цвет фона
     MyMouse: TMouse;
     i,j: byte; // счетчик Объектов Batar
     ArrBatar: array[0..255] of TBatar;
     
    implementation

    {$R *.dfm}

    procedure TForm1.FormCreate(Sender: TObject);
    // и т. д.

  • Cobalt © (20.06.12 11:59) [17]
    Учись отлаживать, использовать стек вызовов (Call Stack) и просмотр локальных переменных
    Примечание:
     в окошке "Local Variables" ты можешь "перейти" к списку локальных переменных по всему стеку вызовов вверх и обнаружить, когда была вызвана та или иная функция.

    Понять, почему вызов той или иной функции в том или ином месте - неверное решение - это уже твоя задача
  • dan-1608 © (20.06.12 14:42) [18]
    Не пременно научусь, надо просто уже работу сдавать, а тут ошибка блин гребанная)
    if (X2party > Form2.Image1.Width) or (Y2body > Form2.Image1.Height) then


    А не могли бы скинуть пример создания дочерней формы, сдается мне проблемма именно в этом, неправильно форму прикрутил и, следовательно, во внешний методах  Form2.Image1.Width и не видно
  • Омлет © (20.06.12 15:54) [19]
    > А не могли бы скинуть пример создания дочерней формы

    http://not-doing.ru/some/form_sample.zip
    1. Ссылка на вторую форму - это приватное поле главной формы. Если равна nil, то формы нет - в методах, где идет обращение ко второй форме, стоит сделать проверку
    if MyForm2 <> nil then
    begin
     MyForm2.Image1.Canvas...
    end;


    2. Нет глобальной переменной для второй формы. Глобальные переменные - зло.
    3. В dpr, естественно, вторая форма не создается при запуске, она создается динамически при нажатии на кнопке главной формы.
  • dan-1608 © (20.06.12 16:14) [20]

    > 3. В dpr, естественно, вторая форма не создается при запуске,
    >  она создается динамически при нажатии на кнопке главной
    > формы.

    Вот в этом и моя промашка была - разобрался в общем у меня получалось обращение к Form2.Image1.Width в процедуре  TForm2.FormCreate (до момонта создания) поэтому Form2 = nil было, теперь заработало

    Мастера Омлет и Cobalt спасибо, что направили на правильный путь
  • Омлет © (20.06.12 16:14) [21]
    Блин, я совсем забыл, что тебе надо MDI.
    По этой теме вагон статей есть.
  • Омлет © (20.06.12 16:15) [22]
    > dan-1608 ©   (20.06.12 16:14) [20]

    Вот правда, почитай какую-нибудь книгу. Гораздо легче будет. И MDI - это отдельная тема.
  • dan-1608 © (20.06.12 16:27) [23]
    Какую посоветуете лучше? так то кое-что было в закладках, но без практики теория мертва))
  • dan-1608 © (20.06.12 16:28) [24]
    хотел реализовать, многопоточность воркспейсов, но теперь уже в следующей курсовой, много ньюансов
  • Омлет © (20.06.12 17:30) [25]

    > dan-1608 ©   (20.06.12 16:27) [23]
    > Какую посоветуете лучше?

    Я по этой учился в своё время: http://rutracker.org/forum/viewtopic.php?t=2422037
    Для D7 практически всё там актуально.
 
Конференция "Media" » Canvas в MDI приложении [D7, WinXP]
Есть новые Нет новых   [134428   +40][b:0][p:0.003]