这个可能是关于现实世界中不需要的东西的问题 。但我想知道我们能做到吗(只是为了知识)
我可以在没有VCL表单的情况下显示vcl组件。我们可以创建和使用非可视化vcl,但我们可以在visual vcl中进行操作并使其在屏幕上可见。
或者至少我们可以将VCL放在使用Windows API创建的表单的旁边,
答案 0 :(得分:6)
不,VCL控件(可视组件)不能存在于VCL表单之外。但是,您可以将VCL控件放在VCL表单中,然后将VCL表单托管在其他类型的窗口中。 Delphi对创建ActiveX控件的支持就是这样--VCL表单(TCustomActiveForm,我认为)提供了分发给ActiveX的窗口句柄。您的VCL组件位于TCustomActiveForm或该类的后代内部,并且永远不会知道其中的差异。
如果您愿意进行一些挖掘和吊装,您可能可以避免ActiveX的开销。首先,查看TCustomForm上的ParentHwnd属性或CreateParented方法。这可能就是你所需要的 - 我无法回想起我的头脑,而且我已经看了几年了。
如果没有,您可以覆盖TCustomForm后代中的CreateParams方法,并将非VCL窗口句柄分配给Params.WndParent字段。在调用继承的CreateParams之后执行此操作,以便在其他所有内容上获得所有正常设置。您可能还需要调整样式和exstyle标志以删除表单的边框,标题等。
在此自定义表单中构造您的VCL控件并调整它以占据整个表单区域。
您可以使用比TCustomForm更低级别的控件(如TCustomWinControl)执行此操作,但您可能会丢失一些击键/加速器窗口消息处理。我知道可以在TCustomForm级别完成。
答案 1 :(得分:4)
示例代码 - 无表格(打开以下.dpr文件并编译):
program Window;
{
This is an example of making an application
without using the Forms unit. Forms.pas is the
Delphi unit that makes your programs so damn
huge! Forms.pas has all the code for translating
the forms you create with Delphi w/components
into windows.
}
uses Windows, Messages;
{$R *.RES}
var
wClass: TWndClass; // class struct for main window
hFont, // handle of font
hInst, // handle of program (hinstance)
Handle, // handle of main window
hEncrypt, // handle of encrypt button
hDecrypt, // handle of decrypt button
hEdit, // handle of main edit
hLabel, // handle of password label
hPW: HWND; // handle of password edit
Msg: TMSG; // message struct
dEncrypt,
dDecrypt: Pointer; // default button procedures
(*------------------------------------------------*)
// This lines everything up
procedure Resize;
var
RCT:TRect;
begin
GetWindowRect(Handle,RCT);
MoveWindow(hPW,230,5,RCT.Right-RCT.Left-245,24,True);
MoveWindow(hEdit,5,34,RCT.Right-RCT.Left-20,RCT.Bottom-RCT.Top-66,True);
end;
(*------------------------------------------------*)
// This is to cleanup and stop the program
procedure ShutDown;
begin
DeleteObject(hFont);
UnRegisterClass('Sample Class',hInst);
ExitProcess(hInst); //end program
end;
(*------------------------------------------------*)
// Decrypts the text in hEdit with the text in hPW
procedure Decrypt;
var
x,i, // count variables
sText,sPW: Integer; // size of Text, PW
Text,PW: PChar; // buffer for Text, PW
begin
sText:=GetWindowTextLength(hEdit)+1;
sPW:=GetWindowTextLength(hPW)+1;
GetMem(Text,sText);
GetMem(PW,sPW);
GetWindowText(hEdit,Text,sText);
GetWindowText(hPW,PW,sPW);
x:=0; // initialize count
for i:=0 to sText-2 do
begin
Text[i]:=Chr(Ord(Text[i])-Ord(PW[x]));
Inc(x);
if x=(sPW-1)then x:=0;
end;
SetWindowText(hEdit,Text);
FreeMem(Text);
FreeMem(PW);
end;
(*------------------------------------------------*)
// Encrypts the text in hEdit with the text in hPW
procedure Encrypt;
var
x,i, // count variables
sText,sPW: Integer; // size of Text, PW
Text,PW: PChar; // buffer for Text, PW
begin
sText:=GetWindowTextLength(hEdit)+1;
sPW:=GetWindowTextLength(hPW)+1;
GetMem(Text,sText);
GetMem(PW,sPW);
GetWindowText(hEdit,Text,sText);
GetWindowText(hPW,PW,sPW);
x:=0; // initialize count
for i:=0 to sText-2 do
begin
Text[i]:=Chr(Ord(Text[i])+Ord(PW[x]));
Inc(x);
if x=(sPW-1)then x:=0;
end;
SetWindowText(hEdit,Text);
FreeMem(Text);
FreeMem(PW);
end;
(*------------------------------------------------*)
// This function processes every message sent to the Encrypt Button
function EncryptProc(hWnd,Msg,wParam,lParam:Longint):Longint; stdcall;
var
i: Integer;
begin
// Always pass the message to the Default procedure
Result:=CallWindowProc(dEncrypt,hWnd,Msg,wParam,lParam);
case Msg of
// If the user presses TAB we're gunna switch the
// focus over to the Decrypt button.
WM_KEYDOWN: if wParam=9 then SetFocus(hDecrypt);
end;
end;
(*------------------------------------------------*)
// This function processes every message sent to the Decrypt Button
function DecryptProc(hWnd,Msg,wParam,lParam:Longint):Longint; stdcall;
begin
// Always pass the message to the Default procedure
Result:=CallWindowProc(dEncrypt,hWnd,Msg,wParam,lParam);
case Msg of
// if the user presses TAB we're gunna switch
// the focus back to the Encrypt button.
WM_KEYDOWN: if wParam=9 then SetFocus(hEncrypt);
end;
end;
(*------------------------------------------------*)
// This function processes every message sent to our Main window
function WindowProc(hWnd,Msg,wParam,lParam:Longint):Longint; stdcall;
begin
// Always pass the message to the Default procedure
Result:=DefWindowProc(hWnd,Msg,wParam,lParam);
case Msg of
WM_SIZE: Resize;
// When buttons are clicked the message is passed to
// the parent window, so we handle it here.
WM_COMMAND: if lParam=hEncrypt then Encrypt
else if lParam=hDecrypt then Decrypt;
WM_DESTROY: ShutDown;
end;
end;
(*------------------------------------------------*)
// This is the main program function (WinMain)
begin
hInst:=GetModuleHandle(nil); // get the application instance
// hInstance returns zilch
with wClass do
begin
Style:= CS_PARENTDC;
hIcon:= LoadIcon(hInst,'MAINICON');
lpfnWndProc:= @WindowProc;
hInstance:= hInst;
hbrBackground:= COLOR_BTNFACE+1;
lpszClassName:= 'Sample Class';
hCursor:= LoadCursor(0,IDC_ARROW);
end;
// Once our class is registered we
// can start making windows with it
RegisterClass(wClass);
// Create our main window
Handle:=CreateWindow(
'Sample Class', // Registered Class Name
'Encrypter', // Title of Window
WS_OVERLAPPEDWINDOW or // Basic Window Style
WS_VISIBLE, // Make it Visible
10, // Left
10, // Top
400, // Width
300, // Height
0, // Parent Window Handle
0, // Handle of Menu
hInst, // Application Instance
nil); // Structure for Creation Data
// Create the Encrypt button
hEncrypt:=CreateWindow(
'Button',
'Encrypt',
WS_VISIBLE or WS_CHILD or BS_PUSHLIKE or BS_TEXT,
5,5,65,24,Handle,0,hInst,nil);
// Create the Decrypt button
hDecrypt:=CreateWindow(
'Button',
'Decrypt',
WS_VISIBLE or WS_CHILD or BS_PUSHLIKE or BS_TEXT,
75,5,65,24,Handle,0,hInst,nil);
// Create the main Edit
hEdit:=CreateWindowEx(
WS_EX_CLIENTEDGE, // this EX style is for the beveled edge
'Edit',
'',
WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or ES_WANTRETURN or ES_AUTOVSCROLL or WS_VSCROLL,
5,34,380,234,Handle,0,hInst,nil);
// Create the password Edit
hPW:=CreateWindowEx(
WS_EX_CLIENTEDGE,
'Edit',
'',
WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or ES_PASSWORD,
230,5,155,24,Handle,0,hInst,nil);
hLabel:=CreateWindow(
'Static',
'Password:',
WS_VISIBLE or WS_CHILD or SS_LEFT,
160,10,70,20,Handle,0,hInst,nil);
// Create a custom font for our window otherwise
// everything would use the system font (blech!)
hFont:=CreateFont(
-12, // Height
0, // Width
0, // Angle of Rotation
0, // Orientation
0, // Weight
0, // Italic
0, // Underline
0, // Strike Out
DEFAULT_CHARSET, // Char Set
OUT_DEFAULT_PRECIS, // Precision
CLIP_DEFAULT_PRECIS, // Clipping
DEFAULT_QUALITY, // Render Quality
DEFAULT_PITCH or FF_DONTCARE, // Pitch & Family
'MS Sans Serif'); // Font Name
// Set the fonts for all our controls
SendMessage(hEncrypt,WM_SETFONT,hFont,0);
SendMessage(hDecrypt,WM_SETFONT,hFont,0);
SendMessage(hEdit,WM_SETFONT,hFont,0);
SendMessage(hPW,WM_SETFONT,hFont,0);
SendMessage(hLabel,WM_SETFONT,hFont,0);
// Subclass Encrypt Button (assign it a custom WindowProc)
dEncrypt:=Pointer(GetWindowLong(hEncrypt,GWL_WNDPROC));
SetWindowLong(hEncrypt,GWL_WNDPROC,Longint(@EncryptProc));
// Subclass Decrypt Button
dDecrypt:=Pointer(GetWindowLong(hDecrypt,GWL_WNDPROC));
SetWindowLong(hDecrypt,GWL_WNDPROC,Longint(@DecryptProc));
// The reason I don't subclass the Edit controls here
// is because they don't do anything custom. If I wanted
// them to Beep or something whenever you typed a "G" then
// I would subclass them.
// Focus on first control (otherwise people with no mouse are screwed)
SetFocus(hEncrypt);
// Now we loop GetMessage to process each Message in
// our main window's message list. Every time the main
// window recieves a message its added to the list, so
// this loop here will eventually process it.
while(GetMessage(Msg,Handle,0,0))do
begin
TranslateMessage(Msg); // Translate any keyboard Msg's
DispatchMessage(Msg); // Send it to our WindowProc
end; // for processing.
end.
答案 2 :(得分:3)
对于VCL 组件,答案显然是肯定的。 组件可以在没有任何麻烦的情况下使用表单上下文,只需通过指定nil
绕过所有权机制并在完成后手动销毁实例
NoLongerDependsOnForm := TSomeComponent.Create(nil);
NoLongerDependsOnForm.This;
NoLongerDependsOnForm.That;
FreeAndNil(NoLongerDependsOnForm);
使用VCL 控件因为任何子窗口都需要父窗口,因此事情变得更加复杂。因此,只能在理论上重用通用窗口中的TWinControl(必须编写VCL存根以使其工作)。所以,答案是轻微的。
我求求你,请停止混淆 form 和 window 这两个词。 (进一步阅读:顶级窗口和子窗口)
答案 3 :(得分:0)
控件可以查找并访问所有者和父容器中的属性,并将其作为VCL类访问。如果不是,VCL控制很有可能无效。
避免这种情况的一种方法是将它们包装为ActiveX控件。然后,您可以使用支持ActiveX控件的任何语言。
答案 4 :(得分:0)
这不仅仅是我自己的代码,而是你所有代码的混音器
只需为 volvox 的回答添加这些代码(我已接受并在顶部)
uses
Windows,
Messages,buttons,stdctrls;
var
abtn:TButton ;
begin
// after all declaration
abtn := TButton.Create(nil) ;
abtn.ParentWindow := hEdit ; // use window handle but i use hedit because my button will be hidden by another button in example
end