DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: 19137911446
今日帖子: 15
在线用户: 19
导航: 论坛 -> 移动应用开发 斑竹:flyers,iamdream  
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/29 19:50:50
标题:
新手求助控件继承的问题 浏览:1055
加入我的收藏
楼主: 比如界面上有一个控件Memo1
我想写个TMyMemo的类继承自TMemo
在这个类的构造函数里做一些操作 比如设置text画条直线 
但是会报错 程序在附件里面 请问如何改写 感谢
此帖子包含附件:mp654kk_2023829195048.rar 大小:5.51M
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/29 21:26:56
1楼: 可以了 犯了低级错误 应该另外动态定义一个paintbox 
paintbox1已经在设计器定义好了 应该是不能直接改paintbox1的了
 画图的部分应该写在onpaint事件里面不然canvas是nil
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/29 22:14:11
2楼: 现在又有个新问题 在MemoPaint事件里面假如我想使用ClientToScreen这个函数是报错的 原因是delphi不支持多重继承吗 假如我非要用ClientToScreen这个函数应该怎么办呢 请看附件
此帖子包含附件:mp654kk_2023829221410.rar 大小:5.50M
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/29 22:50:41
3楼: 现在的DELPHI,如果不是必要,不用继承,直接扩展。

TMemoHelper = class Helper for TMemo

end;

ClientToScreen()是老祖宗TControl的方法,怎么涉及多重了?
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/29 23:05:25
4楼: DONT FORGET THIS:

1) when inheriting a class, You can "override" some methods, BUT NEEDS to do reference to "ancestral class" like this:

type
... xxxxClass
....... constructor Create....;  OVERRIDE or OVERLOAD etc... etc.... depending of original definition on ancestral class... VIRTUAL definition

implementation

....
xxxxClass.Create .....
begin
.... INHERITED Create.....   <---- normally when you inherit methods PROTECTED or others....

end; 


ELSE, this method will be HIDED and can not works as expected...

see on HELP about "extends or create a class based on ancesteal classes"

in Delphi, ONLY IS POSSIBLE MULTI-INHERITING of INTERFACES, not classes
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/29 23:33:35
5楼: @janker 谢谢 以前不知道这个 是这样实现的吗

TMemoHelper = class Helper for TMemo
   public
    procedure setalltext123;
  end;


procedure TMemoHelper.setalltext123;
begin
Self.text:='123';
end;

但是这样的话假如我界面有10个memo就要写10次
memo1.setalltext123;
memo2.setalltext123;
......
memo10.setalltext123;
就算遍历也挺麻烦的
可以像继承那样一次搞定吗
class Helper里面可以定义变量吗
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/29 23:49:16
6楼: @emailx45 谢谢,ClientToScreen的祖先类就是fmx.forms吗,已经引用了就是不行.
我是好奇为什么ClientToScreen写在外面就可以,写在继承的事件里就报错了,需要怎么写才能通过呢?
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/30 0:07:48
7楼: 用了继承,不是也一样要10次吗?
一个具体对象,不是要赋值一次吗?除非是类方法。

简单的扩展或修改,用Helper不用创建一个新类。
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/30 0:34:59
8楼: Helper不能定义变量(域),但是可以定义类变量。这个限制比较大。

可以看看系统自带的各种数据类型转换
比如:TStringHelper

写在事件里不行?什么事件?


procedure TForm1.mmo1Click(Sender: TObject);
var
  LP: TPointF;
begin
  LP := ClientToScreen(mmo1.Position.Point);
  lbl1.Text := 'X:' + mmo1.Position.Point.X.ToString +'; Y:' + mmo1.Position.Point.Y.ToString;
  lbl1.Text := lbl1.Text +'===== X:' + lp.X.ToString +'; Y:' + LP.Y.ToString;
end;
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/30 0:47:26
9楼: @janker 好的 就是我发那个附件里面
那个自定义的TMyMemo类的MemoPaint事件里面使用ClientToScreen就会报错但是写在自定义类之外的其他地方可以不知道为什么.
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/30 0:59:28
10楼: 可以啊


procedure TForm1.mmo1Paint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
var
  p: TPointF;
begin
  p := ClientToScreen(mmo1.Position.Point);
  lbl1.Text := p.X.ToString +' ; ' + p.Y.ToString;
end;

我用的是11.1版本
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/30 1:03:53
11楼: @janker不一样 你的MemoPaint是写在tform1里面的 我的是写在TMyMemo里面的
我是11.3

type
  TMyMemo = class(TMemo)
    constructor Create(AOwner: TComponent);
    procedure MemoPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
  end;
{ TMyMemo }

constructor TMyMemo.Create(AOwner: TComponent);
begin
  inherited;
  Self.text := '123';
  Self.OnPaint := MemoPaint;
end;


procedure TMyMemo.MemoPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
var
  p1, p2: TPointF;
  m1: TMyMemo;
  mycanvas: TCanvas;
begin
  m1 := Sender as TMyMemo;
  p1 := m1.Position.Point;
  p2 := TPointF.Create(m1.Position.X + m1.Width, m1.Position.y + m1.height);
  p1 := ClientToScreen(p1); //请问为什么报错
//  p1 := m1.AbsoluteToLocal(p1);
//  p2 := m1.AbsoluteToLocal(p2);
end;
----------------------------------------------
-
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/30 1:18:38
12楼: 肯定啊,FMX框架下,只有TForm才有ClientToScreen()方法,VCL的TControl就有ClientToScreen()方法。
FMX的控件是由TForm负责绘制的,VCL是每个控件自己绘制。
FMX只有TForm才有Handle,VCL的非图形控件都有Handle。

如果你非得在Paint()里执行ClientToScreen(),可以这样:

var
 LC: TControl;
...
  LC := TMemo(Sender).Parent;
while not LC is TForm do
  lc := lc.parent;

if lc is TForm then
.....

细化下
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/30 8:34:08
13楼: I dont know (exactly) what you want to do ... but 

unit Unit2;

interface

uses
  System.SysUtils,
  System.Classes,
  System.Types,
  System.UITypes,
  FMX.Forms,
  FMX.Controls,
  FMX.Graphics,
  FMX.StdCtrls,
  FMX.Memo;

type
  TMyMemoFMX = class(TMemo)
  private
    FFormParent       : TForm;
    FRePaintingCounter: integer;
    //
    FLeft       : single;
    FTop        : single;
    FStrokeBrush: TStrokeBrush;
    //
    procedure MyPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
    procedure myDrawOnCanvas(AControl: TControl);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    //
    property RePaintingCounter: integer read FRePaintingCounter write FRePaintingCounter;
  end;

implementation

uses
  Winapi.Windows;

type
  TMyHelpTPointF = record helper for TPointF
    function PointsToString: string;
  end;

  { TMyHelpTPointF }

function TMyHelpTPointF.PointsToString: string;
begin
  result := 'X=' + Self.X.ToString + ' x Y=' + Self.Y.ToString;
end;

{ TMyMemoFMX }

destructor TMyMemoFMX.Destroy;
begin
  FStrokeBrush.Free;
  //
  inherited;
end;

procedure TMyMemoFMX.myDrawOnCanvas(AControl: TControl);
var
  LineP1, LineP2: TPointF;
  LPosition     : TPointF;
begin
  if (AControl = nil) then
    exit;
  //
  LPosition := AControl.Position.Point;
  //
  if (FFormParent <> nil) then
    begin
      // FFormParent.ClientToScreen(LPosition);
      //
      Lines.Add('Position = ' + Position.Point.PointsToString);
    end;
  //
  // needs update "FLeft/FTop" with current Left/Top position
  // LPosition := LPosition.Subtract(PointF(FLeft, FTop));
  LineP1 := LPosition; // -Left and -Top values...
  LineP2 := PointF(LineP1.X + AControl.Width, LineP1.Y + AControl.Height);
  //
  AControl.Canvas.DrawLine(LineP1, LineP2, 1, FStrokeBrush);
end;

constructor TMyMemoFMX.Create(AOwner: TComponent);
begin
  inherited;
  //
  FRePaintingCounter := 0;
  FLeft          := 0;
  FTop          := 0;
  //
  if (AOwner <> nil) and (AOwner.ClassParent = TForm) then
    FFormParent := TForm(AOwner);
  //
  // used by "AControl.Canvas.DrawLine()"
  FStrokeBrush          := TStrokeBrush.Create(TBrushKind.Solid, TAlphaColorRec.Blue);
  FStrokeBrush.Cap       := TStrokeCap.Flat;
  FStrokeBrush.Join      := TStrokeJoin.Miter;
  FStrokeBrush.Thickness := 3;
  //
  OnPaint := MyPaint; // paint event...
end;

procedure TMyMemoFMX.MyPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
begin
  FRePaintingCounter := FRePaintingCounter + 1; // 2x on create, +/- 4x each "when click into it"...
  //
  if (FFormParent <> nil) then
    FFormParent.Caption := 'Memo repainted = ' + FRePaintingCounter.ToString + 'x';
  //
  myDrawOnCanvas(Self);
end;

end.
此帖子包含附件:
PNG 图像
大小:8.7K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/30 8:36:34
14楼: implementation

{$R *.fmx}

uses
  Unit2;

var
  Memo2: TMyMemoFMX;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Enabled := false;
  //
  Memo2          := TMyMemoFMX.Create(Form1);
  Memo2.Parent     := Form1;
  Memo2.Position.X := 20;
  Memo2.Position.Y := 20;
  Memo2.Width      := 200;
  Memo2.Height     := 200;
  Memo2.Text       := Memo2.ClassName;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if (Memo2 <> nil) then
    Caption := 'Memo2 Paint(s) = ' + Memo2.RePaintingCounter.ToString;
end;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/30 8:40:05
15楼: some object can be created on "onCreate" and destroyed on "OnDestroy",then you dont need create many times...

like:  
LStrokeBrush := TStrokeBrush.Create(TBrushKind.Solid, TAlphaColorRec.Blue);
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/30 8:58:54
16楼: screenshot
此帖子包含附件:
GIF 图像
大小:142.8K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/30 11:37:40
17楼: @janker 原来是这个原因 12楼的代码里的LC定义为窗体才可以用这个方法 我用spy++试了一下果然窗体才有句柄 
   那假如我在fmx窗体上某个memo控件希望它带上句柄可以吗 这样方便其他软件用api函数获取里面的内容 如果不能的话有什么办法获取里面的内容呢 感谢
----------------------------------------------
-
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/30 11:45:19
18楼: @emailx45 感谢这么详细 现在有两个问题

1.假如我希望画出memo的对角线,p1,p2分别是左上角和右下角的坐标,
  Memo1.Position.x :=  100;
  Memo1.Position.y :=  100;
//先调整一下位置
p1 := Memo1.Position.Point;
p2 := TPointF.Create(Memo1.Position.X + Memo1.Width, Memo1.Position.y + Memo1.height);
为什么要使用  
p1 := memo1.AbsoluteToLocal(p1);
p2 := memo1.AbsoluteToLocal(p2);
才能画在正确的位置上,p1,p2不已经是相对容器form1的坐标了吗为什么还要这样转换一次.

2.memo1.canvas跟form1.canvas居然是相等的,这是为什么呢
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/30 20:33:54
19楼: @mp654kk

You need some way to get the values relative to the position of the "memo" in your "container" (in this case the "Form").

Then, you can use some other event of the "memo", to find out if it was "repositioned", and then get the new values for "Left" and "Top", for example.

There are many events that can provide this information, perhaps the best is after there is "movement" on the screen, understand?
I used "FLeft" and "FTop" just to demonstrate that you need to update the values of these positions when necessary.

It is not possible to use "Left" and "Top" directly, due to the fact that they have a fixed value, so maybe that's why it is used to query the value of the "mouse" position and then convert it to values relative to the "container" (AbsoluteToLocal, etc...)
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/30 20:38:33
20楼: The canvas is an object where the drawing is done, however, it is not "thread-safe", that's why you need "BeginScene" or similar.

Each component has its "canvas".

The canvas of the "Form" when updated, send a message so that other components are also updated on the screen...

It's a ripple effect done behind the scenes... very complex, like the messages sent and received in the system.

You should notice that the values change after the object (instance) is created. For example:

xxx = Txx.CREATE()

xxx.PARENT = zzzz   <----- 
xxx.LEFT = aaaa
xxx.COLOR = wwwww

So, you should use some more appropriate event to notice these changes and do the necessary tasks in your component/class;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/30 22:53:27
21楼: @emailx45 谢谢 

if memo1.canvas=form1.canvas then
  showmessage('yes')
else
  showmessage('no');
结果为什么是yes呢,是因为memo没有句柄吗?
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/30 23:35:28
22楼: I'm not an expert in "class creation" (builder), but this reinforces the complexity behind ancestor classes such as "TControl".

If you look at the source code, you will see that the "TForm" is responsible for the "Scene" (TScene) where the other components will be worked on.

The "TControl" has a temporary "TCanvas", very likely to not overload the main class of the "TCanvas" of the "TForm".

So, the controls (TControl), does the necessary temporary service and then updates the main "Canvas" (in the TForm).

Therefore, "TCanvas" is not "thread-safe", that is, all the controls will work temporarily and locally, and, in the end, they will update the parent "canvas", that is, in the "TForm".

Did you understand? This is my view looking at the source code.

In RAD11.3 see the sources at "FMX.Controls.pas, line 2957" and "FMX.Forms.pas, line 6569.

That's why the "canvas" are the same, because one must refer to the other at some point.

function TCustomForm.GetCanvas: TCanvas;
begin
  if FTempCanvas <> nil then
    Result := FTempCanvas
  else
    Result := FCanvas;
end;

function TControl.GetCanvas: TCanvas;
begin
  if FTempCanvas <> nil then
    Result := FTempCanvas
  else
    if FScene <> nil then
      Result := FScene.GetCanvas
    else
      Result := nil;
end;
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 janker (janker) ★☆☆☆☆ -
盒子活跃会员
2023/8/31 0:18:55
23楼: 17#:FMX窗体里的控件带句柄,我是不知道怎么搞,估计也不大可能。句柄只有Window系统才有。
倒是有方法可以让VCL窗体嵌入FMX的窗体,Git上还是Stack overflow上看到过。
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/8/31 3:16:19
24楼: to "incorporate" a VCL Form into FMX project, just use create your Form into a "package" (BPL), then you can access it into FMX project.

FMX project + (VCL package)

and 

VCL project + (FMX package)

NOTE: Not recommended if you dont is a master, of course
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 mp654kk (mp654kk) ▲△△△△ -
普通会员
2023/8/31 14:07:43
25楼: @janker @emailx45 好的 感谢 辛苦了
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行105.4688毫秒 RSS