Графическое окно в форме

Задачка выглядит примерно так: Создаём форму (System.Windows.Forms), помещаем нужные нам элементы управления (меню, кнопки). По команде из меню (или кнопкой) запускаем рисование какого-нибудь графика. Значит, чтобы график рисовался, надо в форму вставить графическое окно. В простых задачках (без Forms) оно создаётся с помощью процедуры InitWindow, а как его вставить в нашу форму?

Если я правильно понял то так: MyForm.Bounds := new Rectangle(x,y,w,h);

Не уверен, да и компилятор ругается на Rectangle, пишет: “Ожидается тип”. Мне нужно создать и вставить в форму элемент управления типа TextBox, но не для текста, а для графики (GraphBox).

System.Drawing.Rectangle*

Тогда делайте элемент System.Windows.Forms.PictureBox или подобный ему и рисуйте на нём. Я лично у себя в программе делаю PictureBox и подключаю к нему OpenGL чтоб рисовать, а как в GraphABC у вас точно не получится, не написав свой GraphABC. Есть так же альтернатива - System.Drawing.Graphics: var gr := System.Drawing.Graphics.FromHwnd(MyForm.Handle). С помощью этого типа, вроде, можно рисовать даже на консольном окне, но больше 20 fps даже на супер компьютере не выжмете. Ну и можно опять же сделать PictureBox и вместо MyForm.Handle скармливать Graphics MyPictureBox.Handle.

Мне сложно вот так мысленно всё это воспринять, хорошо бы конкретный пример.

Вот простейшая программа для Graphics, вам же надо будет то что у меня в процедуре Drawing писать в процедуру эвента нажатия кнопки. В таком случае первая и третья строчки уже не нужны потому что форма давно запущена, ну и вместо MF.Handle на второй строчке надо дескриптор вашего PictureBox или на чём вы собираетесь рисовать.

{$reference System.Windows.Forms.dll}
{$reference System.Drawing.dll}

{$apptype windows}

uses System.Drawing;//Подключено, поэтому можно писать Rectangle и Graphics вместо System.Drawing.Rectangle и System.Drawing.Graphics.

var
  MF: System.Windows.Forms.Form;

procedure Drawing;
begin
  while not MF.Created do Sleep(10);//Ждём пока форма не запустится.
  var gr := Graphics.FromHwnd(MF.Handle);//Привязывает новую переменную для рисования к форме.
  Sleep(100);//Ещё немного ждём, сразу после создания форма не даёт рисовать.
  var Brush := new System.Drawing.SolidBrush(Color.Red);//Это переменная для закрашивания областей.
  gr.FillRectangle(Brush, 100, 100, 200, 200);//Рисуем квадрат, Fill значит закрасить
  var Pen := new System.Drawing.Pen(Color.Black);//Это переменная для рисования линий.
  gr.DrawRectangle(Pen, 100, 100, 200, 200);//Рисуем ещё 1 квадрат, Draw значит не закрашивать.
end;

begin
  MF := new System.Windows.Forms.Form;//Создаём форму.
  MF.Bounds := new Rectangle(50,50,500,500);//Изменяем размеры.
  (new System.Threading.Thread(Drawing)).Start;//создаём отдельный поток в котором будет рисоваться.
  //Для вас это поток эвента нажатия кнопки.
  System.Windows.Forms.Application.Run(MF);//запускаем форму
end.

А какую программу вы делаете? Возможно этот метод будет не к месту. P.S. Эта программа запускается только через Shift+F9.

Пока я отрабатываю учебную задачу: окно с элементами управления (меню, кнопки…) и вывод в этом окне (в заданной мною его части) нужного мне графика. Оказалось, что это не так просто скомпоновать, толковых примеров нет. Есть ToolStripMenuItem, но нет примера простого MenuItem. Нашёл пример вывода простых фигур (http://www.cyberforum.ru/pascalabc-net/thread1207528.html).

А на учебную задачу есть ссылка?

Эту задачку я лично для себя придумал.

А не хотите глянуть исходники FormsABC? Там и меню вроде есть

Кое-какие модули уже нашёл, lj но FormsABC ещё не добрался. А где находится центральное хранилище всех модулей PascalABC? Ведь должно быть таковое.

LibSource

А конкретнее, без снобизма?

C:\Program Files (x86)\PascalABC.NET\LibSource

Нашёл, правда не сразу. Помогло обращение на GitHub, - увидел результаты поиска и догадался заглянуть в директорию PascalABC.NET. Спасибо.

Сделал программку с кнопками, с меню пока не разобрался:

program System_Drawing_Wrk;

{$reference System.Windows.Forms.dll} {$reference System.Drawing.dll} {$apptype windows}

uses System, System.Drawing, System.Windows.Forms;

var myForm: System.Windows.Forms.Form; mbFilled: Button; mbDrawed: Button;

procedure mbFilledClick(sender: Object; e: EventArgs); begin var gr := Graphics.FromHwnd(myForm.Handle);//Привязывает новую переменную для рисования к форме. var Brush := new System.Drawing.SolidBrush(Color.Red);//Это переменная для закрашивания областей. gr.FillRectangle(Brush, 100, 100, 200, 200);//Рисуем квадрат, Fill значит закрасить end;

procedure mbDrawedClick(sender: Object; e: EventArgs); begin var gr := Graphics.FromHwnd(myForm.Handle);//Привязывает новую переменную для рисования к форме. var Pen := new System.Drawing.Pen(Color.Black);//Это переменная для рисования линий. gr.DrawRectangle(Pen, 150, 150, 200, 200);//Рисуем ещё 1 квадрат, Draw значит не закрашивать. end;

begin myForm := new System.Windows.Forms.Form; //Создаём форму. myForm.Bounds := new Rectangle(50,50,600,500); // Задаём размеры

mbFilled := new Button(); mbFilled.Text := ‘Filled’; mbFilled.AutoSize := True; mbFilled.Left := 10; mbFilled.Top := 10; mbFilled.Click += mbFilledClick; mbDrawed := new Button(); mbDrawed.Text := ‘Drawed’; mbDrawed.AutoSize := True; mbDrawed.Left := 100; mbDrawed.Top := 10; mbDrawed.Click += mbDrawedClick;

myForm.Controls.Add(mbFilled); myForm.Controls.Add(mbDrawed);

System.Windows.Forms.Application.Run(myForm);//запускаем форму end.

Теперь надо подумать, как сделать переменную ‘gr’ глобальной, чтобы не создавать её в каждом обработчике. Или это нормально?

Про new System.Threading.Thread(Drawing) - непонятно.

А в чём проблема? сделайте gr глобальной и в каждом обработчике проверяйте её на nil, если nil то инициализировать. Ну а насчёт нормально четно говоря вполне возможно, вряд ли это требует слишком много времени, если только не делать это несколько тысяч раз в секунду ;).

new System.Threading.Thread(Drawing) создаст новый поток который будет выполнятся параллельно с основной программой. На сколько я знаю System.Windows.Forms.Application.Run(myForm); полностью забирает себе поток который его вызвал, если поставить какие то операторы после него они никогда не выполнятся, поэтому если надо что то сделать уже после запуска формы нужен отдельный поток. Ну правда делать как я - инициализировать и стартовать (.Start) на 1 строчке не оч хорошо, лучше присвоить глобальной переменной чтоб потом к нему был доступ.

И ещё, когда пишете код на форум используйте `. По 1 перед и после кода для 1 строчки и по 3 для нескольких. Этот знак находится в англ. раскладке там где ё. Так код будет более читабелен.