Консультация № 180630
08.11.2010, 18:10
0.00 руб.
0 7 0
Здравствуйте, уважаемые эксперты.
Мне нужна Ваша помощь.


Мне нужно написать программу для построения электрических схем на Delphi 7. Элементы цепей (резистор, транзистор, конденсатор, диод и т.д.) должны быть нарисованы с помощью свойств Canvas. Эти элементы должны создаваться при нажатии на определенную кнопку и перемещаться при помощи зажатия левой кнопкой мыши (при нажатии правой кнопкой мыши на этот элемент - удалить его).


Я сделал только рисование всех этих элементов цепи при помощи Canvas.


Как сделать создание всех вышеперечисленных элементов цепи при нажатии на определенную кнопку, их перемещение и удаление при помощи кнопок мыши?
Т.е. пользователь нажал на кнопку, и появился определенный элемент в определенной области (например, в верхнем левом углу). Затем еще раз нажал, и этот элемент еще раз появился в этом же углу. И он их перемещает в какой-то рабочей области (например, на самой форме) при помощи мыши.


Желательно (но не обязательно):
Чтобы на рабочей области не было заранее расставленных компонентов: TImage, Tshape и т.д. (кроме кнопок естественно).
Создание элекрической цепи должно осуществляться рисованием (Canvas) при нажатии кнопку, и их перемещение.



Пожалуйста, помогите.
Заранее спасибо.

Приложение:
unit Unit1;

interface

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

type
TForm1 = class(TForm)
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

type
TElement = class
fx,fy:Integer;
Procedure Transistor(Canvas:TCanvas);
Procedure Diod(Canvas:TCanvas);
Procedure Resistor(Canvas:TCanvas);
Procedure Kondensator(Canvas:TCanvas);
end;


Var
A:TElement;


{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
A:=TElement.Create;
end;


// РИСОВАНИЕ ТРАНЗИСТОРА
procedure TElement.Transistor(Canvas: TCanvas);
begin
with Canvas do
begin
Ellipse(fx-40,fy-40,fx+40,fy+40);

MoveTo(fx-60,fy);
LineTo(fx-20,fy);

MoveTo(fx-20,fy-20);
LineTo(fx-20,fy+20);

MoveTo(fx-20,fy-15);
LineTo(fx+10,fy-40);

MoveTo(fx-20,fy+15);
LineTo(fx+10,fy+40);

MoveTo(fx+10,fy-40);
LineTo(fx+10,fy-60);

MoveTo(fx+10,fy+40);
LineTo(fx+10,fy+60);

MoveTo(fx+10,fy+40);
LineTo(fx+6,fy+32);

MoveTo(fx+10,fy+38);
LineTo(fx,fy+36);
end;
end;


// РИСОВАНИЕ ДИОДА
procedure TElement.Diod(Canvas: TCanvas);
begin
with Canvas do
begin
MoveTo(fx-25,fy);
LineTo(fx+20,fy);

MoveTo(fx+10,fy);
LineTo(fx-10,fy+12);

MoveTo(fx-10,fy+12);
LineTo(fx-10,fy-12);

MoveTo(fx-10,fy-12);
LineTo(fx+10,fy);
end;
end;


// РИСОВАНИЕ КОНДЕНСАТОРА
procedure TElement.Kondensator(Canvas: TCanvas);
begin
with Canvas do
begin
MoveTo(fx-20,fy);
LineTo(fx-3,fy);

MoveTo(fx-3,fy+20);
LineTo(fx-3,fy-20);

MoveTo(fx+3,fy+20);
LineTo(fx+3,fy-20);

MoveTo(fx+3,fy);
LineTo(fx+20,fy);
end;
end;


// РИСОВАНИЕ РЕЗИСТОРА
procedure TElement.Resistor(Canvas: TCanvas);
begin
with Canvas do
begin
MoveTo(fx-30,fy);
LineTo(fx-20,fy);

MoveTo(fx-20,fy+7);
LineTo(fx-20,fy-7);

MoveTo(fx-20,fy-7);
LineTo(fx+10,fy-7);

MoveTo(fx+10,fy-7);
LineTo(fx+10,fy+7);

MoveTo(fx+10,fy+7);
LineTo(fx-20,fy+7);

MoveTo(fx+10,fy);
LineTo(fx+20,fy);
end;
end;


// СОЗДАНИЕ ТРАНЗИСТОРА ПРИ НАЖАТИИ НА КНОПКУ
procedure TForm1.Button2Click(Sender: TObject);
begin
with Canvas do
begin
A.fx:=70;
A.fy:=70;
A.Transistor(Form1.Canvas);
end;
end;


// СОЗДАНИЕ ДИОДА ПРИ НАЖАТИИ НА КНОПКУ
procedure TForm1.Button3Click(Sender: TObject);
begin
with Canvas do
begin
A.fx:=30;
A.fy:=20;
A.Diod (Form1.Canvas);
end;
end;


// СОЗДАНИЕ РЕЗИСТОРА ПРИ НАЖАТИИ НА КНОПКУ
procedure TForm1.Button4Click(Sender: TObject);
begin
with Canvas do
begin
A.fx:=40;
A.fy:=20;
A.Resistor(Form1.Canvas);
end;
end;


// СОЗДАНИЕ КОНДЕНСАТОРА ПРИ НАЖАТИИ НА КНОПКУ
procedure TForm1.Button5Click(Sender: TObject);
begin
with Canvas do
begin
A.fx:=30;
A.fy:=25;
A.Kondensator(Form1.Canvas);
end;



end;

end.

Обсуждение

давно
Мастер-Эксперт
425
4118
08.11.2010, 18:32
общий
Цитата: 343561
Я сделал только рисование всех этих элементов цепи при помощи Canvas

Плохая идея использовать рисование. Каждый элемент схемы должен быть отдельным объектом, тогда не надо прикладывать больших усилий, например, для того, чтобы таскать его по форме перемещая в разные места.
Мне кажется, лучше всего создать предопределённый набор компонентов (транзистор, резистор, конденсатор, микросхема, и т. д.) как потомок объекта TShape. У каждого наследника будет собственный фиксированный рисунок элемента схемы. А уж соединения можно рисовать на канве.
Подумайте над этим.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
08.11.2010, 18:46
общий
Извините меня, пожалуйста, sir Henry. Вы бы не могли написать этот кусочек кода с потомком объекта TShape? Как он реализовывается? Я не совсем понял.

Я пытался делать динамическое создание Tshape. Но у меня не получилось... :(
давно
Мастер-Эксперт
425
4118
08.11.2010, 19:20
общий
Полностью потомка я Вам описывать не буду, т.к. за пять минут это не делается. Объясню принцип.
Сначала нам нужно составить список тех свойств и методов, которые должны быть дополнены или изменены по сравнению с уже имеющимся классом TShape. Те предопределённые фигуры, которые там уже есть, нам не подходят. Тип фигур (stRectangle, stSquare, и т.п.) тоже не совсем в тему. Сами типы (TShapeType) тоже надо переназвать теми именами, которые нужны (например stTrasistor, stResistor? и т. п.). Далее, размеры самих фигур должны быть фиксированы. Потом переписываем метод рисования фигур TPaint.
В коде будет что-то вроде этого:
Код:
Type
//Переобъявляем тип фигур
TShapeType = (stResistor, stTransistor, stCondenser, ...);

//Объявляем класс-потомок от TShape
TElement = class(TShape)
...
end;

implementation

...

//Переписываем метод Paint
procedure TElement.Paint;
Begin
...
Case FShape of
//Рисуем резистор
stResistor: Begin
Rectangle(X1, Y1, X2, Y2); //Вместо X1, Y1, X2, Y2 надо подставить реальные координаты, чтобы было похоже на резистор
//Рисуем хвостики по бокам резистора
...
stTransistor: Begin
//Тут рисуем транзистор
...
End;
End;

Когда создан класс-потомок, надо будет просто при нажатии на сответствующую кнопку создавать соответствующий экземпляр класса. Для хранения всех объектов можно использовать специальный клас - список объектов TObjectList.
Код:
procedure TForm1.Button1Click(Sender: TObject);
begin
ObjectList.Add(TElement.Create(NIL);
...
end;

Обращаться к каждому элементу списка объектов можно так же, как и к элементу массива, таким образом заполняя необходимые свойства.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
08.11.2010, 20:36
общий
С переобъявлением типов фигур я разобрался. С объявляем класса - потомка TShape, тоже вроде бы понял.
Но, что за метод переписывания Paint? Как его задать, чтобы он работал? А то у меня выскакивает ошибка. :(


sir Henry, может с моей стороны Вам покажется наглостью, но Вы не могли бы сделать одну любую рабочую кнопку элемента и его перемещение (рисунок - не важно. Я нарисую)? А я, по аналогии, сделаю остальные. И отстану от Вас. Пожалуйста.

Я скажу "спасибо" SMS-сообщением
давно
Мастер-Эксперт
425
4118
09.11.2010, 04:02
общий
Цитата: 343561
А то у меня выскакивает ошибка.

Какая? Текст ошибки...

У TShape метод Paint обозначен как override. Т. е. его можно перекрывать своим методом. Вы создаёте в Вашем потомке класса метод с точно таким же названием, но внутри метода пишете свои собственные команды. В общем случае это будет почти тот же самый метод, того же состава, что и в TShape (его исходник Вы можете посмотреть в своём Delphi, в исходниках, в каталоге VCL. файл extctrls.pas) только немного изменённый в той части, которая относится к рисованию конкретной фигуры, т.е. в той части процедуры, которую я Вам привёл:
Код:
Case FShape Of
stResistor: //Здесь рисуем резистор
stTransistor: //Здесь рисуем транзистор
...

Когда у Вас будет полностью описанный и отлаженый класс (Вы это можете проверить откомпилировав модуль с классом и не получив после компиляции ни одной ошибки ), тогда в процедуре нажатия кнопки Вы просто вписываете ручное создание объекта этого класса.
Код:
Переменная:=TElement.Create();

После создания (Create) Вы заполняете необходимые свойства, например координаты элемента, где он должен располагаться на форме (Left, Top) и делаете его вилимым. Вот, в принципе и всё.
По поводу перемещения фигуры. Почти у каждого дельфийского компоненты есть событие OnMouseMove или, по-русски говоря, событие при движении мышкой. В этом событии, в параметрах X и Y представлены текущие координаты мыши. В этом событии нужно только подставлять в Left и Top компонента координаты X и Y (с поправкой, естественно ). При этом надо сначала зафиксировать факт нажатия левой кнопки мышки, иначе у Вас компонент будет постоянно ползать за мышкой. Зафиксировать факт нажатия можно в событии OnMouseDown, занеся в глобальную переменную факт нажатия. Тогда в OnMouseMove Вы проверяете нажата ли мышка и если да, то меняете координаты компонента, если нет, то координаты не меняются. Всё просто.
Однако лучше сначала подумать над созданием компонента, это труднее всего. Это надо как следует обдумать.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
09.11.2010, 16:48
общий
Здравствуйте, sir Henry. Я решил пойти малость другим путем, но с учетом того, как Вы мне посоветовали.
Но у меня возникла ошибка (Error in module Unit1: declaration of class TForm1 is missing of incorrect.)
Не подскажите, в чем тут дело? Может посоветуете что-нибудь исправить?

Заранее спасибо.


[b]Код программы:[/b]


unit Shape2;

interface

uses
SysUtils, Classes, Controls, ExtCtrls, Graphics, Messages;

type
TShapeType = (stRechteck, stDreieck, stProzess);

TShape1 = class(TShape)
private
{ Private declarations }
FShape : TShapeType;
FCaption : String;
FSelected : Boolean;

rx, ry,
oH, oW,
oL, oT : Integer;

procedure SetShape(Value : TShapeType);
procedure SetCaption(Value : String);
procedure SetSelection(Value : Boolean);
protected
{ Protected declarations }
protected procedure Paint();override;
protected procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override;
protected procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
protected procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override;
public
{ Public declarations }
published
{ Published declarations }
property Shape: TShapeType read FShape write SetShape;
property Caption: String read FCaption write SetCaption;
property Selected: Boolean read FSelected write SetSelection;

end;

type TMyShape = class(TWinControl)
Shape : TShape1;
procedure Exit(var msg:TMessage);message cm_exit;
procedure Button(var msg:TMessage);message wm_lbuttondown;
constructor create(Aowner:Tcomponent);override;
destructor destroy;
end;
procedure Register;

implementation

constructor TMyShape.create;
begin
inherited create(Aowner);
shape:=Tshape1.Create(self);
self.Enabled:=true;
self.TabStop:=true;
with self.Shape do begin
Parent:= self;
Enabled := true;
Shape := stProzess;
Left := 100;
Top := 100;
Height:= 100;
Width := 100;
Brush.Color := $005555FF;
Show;
end;
end;

destructor TMyShape.destroy;
begin
shape.Free;
inherited;
end;

procedure TMyShape.Exit(var msg:TMessage);
begin
self.Shape.Selected := false;
end;

procedure TMyShape.Button(var msg:TMessage);
begin
self.Shape.Selected := true;
self.SetFocus;
end;

procedure Register;
begin
RegisterComponents('Samples', [TShape1]);
end;

procedure TShape1.SetShape(Value : TShapeType);
begin
FShape := Value;
end;

procedure TShape1.SetCaption(Value : String);
begin
FCaption := Value;
// Paint;
end;

procedure TShape1.SetSelection(Value : Boolean);
begin
FSelected := Value;
Paint;
end;

procedure TShape1.Paint();
var sw, sh: Integer;
begin
Canvas.Brush.Color := clWhite;
Canvas.FillRect(Rect(0,0,self.Width, self.Height));
sw := self.Width -1;
sh := self.Height -1;
Canvas.Brush.Color := self.Brush.Color;
Canvas.Font.Color := $00FFFFFF;
Canvas.Font.Style := [fsBold];

if Self.Shape = stRechteck then begin
Canvas.Polygon([Point(4, 4), Point(Self.ClientWidth-4, 4), Point(Self.ClientWidth-4, Self.ClientHeight-4), Point(4, Self.ClientHeight-4)]);
end;

If Self.Shape = stDreieck then begin
Canvas.Polygon([Point(4, Trunc(Self.ClientHeight / 2)-4), Point(Self.ClientWidth-4, 4), Point(Self.ClientWidth-4, Self.ClientHeight-4)]);
end;

If Self.Shape = stProzess then begin
Canvas.Polygon([Point(4,4), Point(Trunc(0.85 * Self.Width),4), Point(Self.Width-4,Trunc(Self.Height / 2)), Point(Trunc(0.85 * Self.Width), Self.Height-4), Point(4,Self.Height-4), Point(Trunc(0.15*Self.Width),Trunc(Self.Height / 2))]);
end;

If Self.Selected = True then begin
Canvas.Pen.Style := psDot;
Canvas.Pen.Color := $00999999;
Canvas.Brush.Style:= bsClear;
Canvas.Polyline([
Point(0,0),
Point(sw,0),
Point(sw,sh),
Point(0,sh),
Point(0,0)
]);

Canvas.Pen.Style := psSolid;
Canvas.Pen.Color := $00000000;
Canvas.Brush.Color := $00FFFFFF;

Canvas.Rectangle(0,0,8,8);
Canvas.Rectangle(self.ClientWidth-8,0,self.ClientWidth,8);
Canvas.Rectangle(0,self.ClientHeight-8,8,self.ClientHeight);
Canvas.Rectangle(self.ClientWidth-8,self.ClientHeight-8,self.ClientWidth,self.ClientHeight);

Canvas.Rectangle(Trunc(self.Width /2)-4,0,Trunc(self.Width /2)+4,8);
Canvas.Rectangle(Trunc(self.Width /2)-4,self.Height-8,Trunc(self.Width /2)+4,self.Height);
Canvas.Rectangle(0,Trunc(Self.Height / 2)-4,8,Trunc(Self.Height / 2)+4);
Canvas.Rectangle(self.Width-8,Trunc(Self.Height / 2)-4,self.Width,Trunc(Self.Height / 2)+4);
end;

Canvas.Brush.Style := bsClear;
Canvas.TextOut(Trunc(self.Width / 2)-Trunc(Canvas.TextWidth(Caption) / 2), Trunc(self.Height / 2) - Trunc(Canvas.TextHeight(Caption) / 2), Self.Caption);
end;

procedure TShape1.MouseDown(Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
begin
rx := X;
ry := Y;

oH := self.Height;
oW := self.Width;
oT := self.Top;
oL := self.Left;

// Self.Selected := True;
Paint;
end;

procedure TShape1.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
if ((ssLeft in Shift) AND (self.Selected = True)) then begin

if ((rx < 9) AND (ry < 9)) then begin
self.Top := Mouse.CursorPos.Y -30 - Parent.Top - ry;
self.Left := Mouse.CursorPos.X -4 - Parent.Left - rx;
self.Height := oH+(oT - self.Top);
self.Width := oW+(oL - self.Left);

end else if ((rx > oW-8) AND (ry < 9)) then begin
self.Top := Mouse.CursorPos.Y - 30 - Parent.Top - ry;
self.Height := oH+(oT - self.Top);
self.Width := Mouse.CursorPos.X -4 - Parent.Left - oL + (oW-rX);

end else if ((rx > oW-8) AND (ry > oH -8)) then begin
self.Top := oT;
self.Left := oL;
self.Height := Mouse.CursorPos.Y - 30 - Parent.Top - oT + (oH-rY);
self.Width := Mouse.CursorPos.X - 4 - Parent.Left - oL + (oW-rX);

end else if ((rx < 9) AND (ry > oH -8)) then begin
self.Top := oT;
self.Left := Mouse.CursorPos.X -4 - Parent.Left - rx;
self.Height := Mouse.CursorPos.Y - 30 - Parent.Top - oT + (oH-rY);
self.Width := oW+(oL - self.Left);

end else if ((rx > Trunc(oW / 2)-4) AND (rx < Trunc(oW / 2)+4) AND (ry < 9)) then begin
self.Top := Mouse.CursorPos.Y -30 - Parent.Top - ry;
self.Height := oH+(oT - self.Top);

end else if ((rx < 9) AND (ry > Trunc(oH/2) -4) AND (ry < Trunc(oH/2)+4)) then begin
self.Left := Mouse.CursorPos.X -4 - Parent.Left - rx;
self.Width := oW+(oL - self.Left);

end else if ((rx > oW-8) AND (ry > Trunc(oH/2) -4) AND (ry < Trunc(oH/2)+4)) then begin
self.Width := Mouse.CursorPos.X -4 - Parent.Left - oL + (oW-rX);

end else if ((rx > Trunc(oW / 2)-4) AND (rx < Trunc(oW / 2)+4) AND (ry > oH -8)) then begin
self.Top := oT;
self.Height := Mouse.CursorPos.Y - 30 - Parent.Top - oT + (oH-rY);

end else begin
self.Top := Mouse.CursorPos.Y - Parent.Top - ry-30;
self.Left := Mouse.CursorPos.X - Parent.Left - rx-4;
end;
end;
end;

procedure TShape1.MouseUp(Button: TMouseButton; Shift: TShiftState; X,Y: Integer);
begin
end;

end.
давно
Мастер-Эксперт
425
4118
09.11.2010, 18:34
общий
Цитата: 343561
Error in module Unit1

А Вы мне привели текст модуля:
Цитата: 343561
unit Shape2;

Как же тут ошибку то найдёшь?
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Форма ответа