如何创建无模式对话框并在用户单击确定时将其关闭?

时间:2012-09-18 10:34:16

标签: delphi

用户坚持在应用程序中为每个“重要事件”弹出一个框。在备忘录或列表框中添加一行是不可接受的。

我使用标准模式盒bceuase PC经常是未经过限制的,我的应用程序将等待用户在继续之前单击“确定”。

我是否可以使用备忘录组件和确定按钮动态创建表单并传递一些文本以显示在备忘录中?

我试过了,点击“确定”后出现了访问冲突。

问题:

  • 是否需要启动一个线程来显示表单,因为它是无模式显示的?
  • 我应该传递什么作为构造函数参数(prent)?没有,因为这种形式会破坏自己吗?
  • 当用户点击OK时,我应该拨打什么电话?关闭()或免费()?单击“确定”后,其中任何一个都会在大约1/2秒内发出访问冲突,但如果我在函数中没有执行任何操作,则代码运行正常(当然存在内存泄漏)

Google没有那么有用,因为表单应该自我毁灭,而示例的创建者会破坏它。


主要形式:

     theDialogForm := TDialogFormForm.Create(Nil);
     theDialogForm.ShowTheForm('Database error '+#13+#10+''+#13+#10+
                E.ClassName+#13+#10+
                E.Message);

和对话框表单......

unit fDialogForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TDialogFormForm = class(TForm)
    Memo1: TMemo;
    OkButton: TButton;
    procedure OkButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
      procedure ShowTheForm(const theMessage : String);
  end;

implementation

{$R *.dfm}

// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
procedure TDialogFormForm.FormCreate(Sender: TObject);
begin
   Visible := False;
end;

// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
procedure TDialogFormForm.OkButtonClick(Sender: TObject);
begin
//   Close();
   Free();
end;

// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=
procedure TDialogFormForm.ShowTheForm(const theMessage : String);
begin
   Memo1.Text := theMessage;
   Show();
end;

end.

调用堆栈

main thread ($630):
005164e3 +013 StoreRoom.exe Vcl.Controls          TControl.WMLButtonUp
00515b30 +2d4 StoreRoom.exe Vcl.Controls          TControl.WndProc
0051a47b +5b3 StoreRoom.exe Vcl.Controls          TWinControl.WndProc
00537bf0 +06c StoreRoom.exe Vcl.StdCtrls          TButtonControl.WndProc
00519ad0 +02c StoreRoom.exe Vcl.Controls          TWinControl.MainWndProc
0048dea4 +014 StoreRoom.exe System.Classes        StdWndProc
76677885 +00a USER32.dll                          DispatchMessageW
005b7c63 +0f3 StoreRoom.exe Vcl.Forms             TApplication.ProcessMessage
005b7ca6 +00a StoreRoom.exe Vcl.Forms             TApplication.HandleMessage
005b7fd9 +0c9 StoreRoom.exe Vcl.Forms             TApplication.Run
00823616 +17a StoreRoom.exe StoreRoom      56 +24 initialization
75c43398 +010 kernel32.dll                        BaseThreadInitThunk

4 个答案:

答案 0 :(得分:7)

要关闭表单,您可以

  • 通过调用Close关闭它并在OnClose事件中将操作设置为caFree
  • 调用Release,这是Free的特殊风格,特别是对于表单。

调用Free的问题是,当您仍然在关闭按钮上处理click事件时,表单会立即释放。在该过程中,表单和因此按钮被释放,导致访问冲突。 Release在内部向表单发送一条消息,导致其在处理完后关闭

答案 1 :(得分:4)

  1. 您不需要线程来显示表单。但是,由于表单应该仍然可见,我建议您将其设置为FormStylefsStayOnTop
  2. 由于您要销毁表单,因此可以将nil传递给Create()
  3. 要销毁表单,请致电Close并在表单的OnClose事件中,将Action设为caFree

答案 2 :(得分:2)

为什么不让自己轻松自如,制作一个看起来像对话框的隐形面板,当重大事件发生时变为可见,当用户点击确定时看不见?

答案 3 :(得分:1)

  

是否需要启动一个线程来显示表单,因为它是无模式显示的?

VCL不是多线程的。您应该始终在主线程中运行表单。 您可能可以在额外线程dunno中调用Win32 API ShowMessageBox,但仅适用于单个消息。无法将事件累积到TMemo或网格中。

  

我应该传递什么作为构造函数参数(prent)?

我会通过应用程序,但这没什么大不了的。

  

当用户点击“确定”时,我应该拨打什么电话?关闭()或免费()?

两者都没有创建/删除表单的意义。 只有当你可以拥有同一类的多种形式时才有意义。 这一次,只需让Delphi自动创建并在程序开始/结束时自动处理它。

您只应展示或隐藏它。无需手动创建和处理。


现在,关于线程 - 你为什么要阻止你的申请? 将该窗口设为AlwaysOnTop,然后使用TApplication.OnActivate事件检查用户何时切换到该窗口并将该窗口置于屏幕/主窗口的前方和中心。所以用户会看到它。

或者您可以尝试第三方通知工具,例如Snarl,以及永不过期的邮件选项。