- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发一个 IRC 客户端。我遇到了一个专业的障碍,直到没有我能够解决。我将在下面显示代码。我遇到的问题是在 idIRC 的事件处理程序中创建 MDI 子窗口。
例如,如果我想创建一个新的 channel 表单(FrmChannel),我可以通过在捕获“/join”命令时调用它的创建过程来轻松完成此操作。
但是,如果我想以正确的方式进行操作,并等到我真正加入 channel ,并从服务器接收确认(通过在 onjoin 事件处理程序中处理它),那么我对表单创建过程的调用会导致要挂起的应用程序。
状态窗口也是如此。例如,如果我将状态窗口创建过程调用放在 TButton 的 onclick 事件上,那很好。子窗体已创建。但是,如果我在实际收到私有(private)消息时尝试同样的事情,通过检查事件处理程序......应用程序挂起,没有异常,也没有 MDI 子级。
这是相关代码(为了解决这个问题,我将只处理查询窗口)。
首先,实际的 MDI Child 创建过程是这样的。我在这里有一个 TComponentList 来管理此类表单的列表(以防您想知道)。这里还有一些其他的东西也可以跟踪表单,尽管将它们注释掉并不能阻止挂起(我已经尝试过)。
procedure TFrmMain.NewQuery(const Server, MsgFrom: String);
var
Child: TFrmMessage;
TN: TTreeNode;
begin
///
/// Create form, set some data so we can reference it later.
///
///
Child := TFrmMessage.Create(Application);
// QueryManager.Add(Child); //TComponent List -- Used to find the Form Later On
with Child do
begin
MyServer := Server; {What server this PM window is on}
QueryWith := MsgFrom; {nickaname of the other person}
Caption := MsgFrom; {Asthetic}
end;
Child.Echo('*** Conversation with ' + MsgFrom); //Herro World
///
/// The following code is working.
/// I'm pretty sure it's not causing the hangs.
///
TN := GetNodeByText(ChanServTree, Server, True); {Find our parent node}
with ChanServTree.Items.AddChild(TN, MsgFrom) do
begin
Selected := True;
Tag := 2; {TYPE OF QUERY}
Data := Pointer(Integer(Child)); //Pointer to Form we created
end;
end;
procedure TFrmMain.IRCPrivateMessage(ASender: TIdContext; const ANicknameFrom,
AHost, ANicknameTo, AMessage: string);
var
CheckVr: String;
aThread: TNQThread;
begin
//DEBUG:
(StatusManager[0] as TFrmStatus).Echo('From: ' + ANickNameFrom + 'AMESSAGE: ' + '''' +AMessage + '''');
///
/// Handle Drone Version Requests!
/// This is REQUIRED on servers like irc.blessed.net - or they won't let you join
/// channels! - It's part of the Registration proccess
///
{The Drones on some server's don't follow specifications, so we need to search
hard for their presence}
CheckVr := AMessage;
StringReplace(CheckVr,' ','',[rfReplaceAll, rfIgnoreCase]);
StringReplace(CheckVr,#1,'',[rfReplaceAll, rfIgnoreCase]);
(StatusManager[0] as TFrmStatus).Echo('Message was: ' + '''' + CheckVr + '''');
if Trim(CheckVr) = 'VERSION' then
begin
IRC.CTCPReply(ANickNameFrom,'VERSION','mIRC v6.01 Khaled Mardam-Bey');
(StatusManager[0] as TFrmStatus).Echo('*** Sent Version Reply to ' + ANickNameFrom);
exit; {Because if we don't, this could mess things up}
end;
///
/// The Following code sends the PM to the appropriate window.
/// If that window does not exist, we will create one first.
///
if Pos('#',Amessage) = 1 then
begin
//Handled Elsewhere
end else {is PM}
begin
if FindQueryFrm(ANickNameTo,IRC.Host) = nil then
begin
NewQuery(IRC.Host, ANickNameFrom);
exit;
end;
end;
// FindChannelFrm(ANickNameTo,IRC.Host).ChannelMessage(ANicknameFrom, AMessage);
end;
最佳答案
As I told you in alt.comp.lang.borland-delphi earlier today ,问题是 Indy 在执行阻塞套接字调用的同一线程中运行其事件处理程序,这与您的 GUI 不同。所有 GUI 操作都必须在同一个线程中进行,但是您正在套接字线程中创建一个新窗口。
为了解决这个问题,您的事件处理程序应该向主线程发布一个通知,主线程将在下一次检查消息时异步处理该通知。
如果你有足够新的 Delphi 版本,你可以试试 TThread.Queue
方法,很像 Synchronize
,除了调用线程不会阻塞等待主线程运行给定的方法。但是,它们在方法参数方面都有相同的限制;他们只接受零参数方法。这使得传输额外信息以供最终调用时使用的方法变得很麻烦。这对于排队的方法尤其不利,因为您为它们提供的任何额外数据都必须在主线程运行它所需的时间内保持不变;调用线程需要确保在调用排队的方法之前它不会覆盖额外的数据。
一个更好的计划可能是只将消息发布到主线程的某个指定窗口。 Application.MainForm
是一个诱人的目标,但 Delphi 表单可能会在没有通知的情况下重新创建,因此您的其他线程使用的任何窗口句柄在他们尝试发布消息时可能无效。并阅读 MainForm.Handle
按需属性也不安全,因为如果表单当时没有句柄,它将在套接字线程的上下文中创建,这将导致以后出现各种问题。相反,让主线程创建一个新的专用窗口,用于接收带有 AllocateHWnd
的线程消息。 .
一旦您有了消息要发送的目标,您就可以安排线程来发布和接收它们。定义消息值并使用 PostMessage
发布它们.
const
am_NewQuery = wm_App + 1;
PostMessage(TargetHandle, am_NewQuery, ...);
type
PNewQuery = ^TNewQuery;
TNewQuery = record
Host: string;
FromNickname: string;
end;
procedure NewQuery(const Server, MsgFrom: string);
var
Data: PNewQuery;
begin
New(Data);
Data.Host := Server;
Data.FromNickname := MsgFrom;
PostMessage(TargetHandle, am_NewQuery, 0, LParam(Data));
end;
class procedure TSomeObject.HandleThreadMessage(var Message: TMessage);
var
NewQueryData: PNewQuery;
begin
case Message.Msg of
am_NewQuery: begin
NewQueryData := PNewQuery(Message.LParam);
try
Child := TFrmMessage.Create(NewQueryData.Host, NewQueryData.FromNickname);
TN := GetNodeByText(ChanServTree, NewQueryData.Host, True); // Find parent node
with ChanServTree.Items.AddChild(TN, NewQueryData.FromNickname) do begin
Selected := True;
Tag := 2; // TYPE OF QUERY
Data := Child; // reference to form we created
end;
finally
Dispose(NewQueryData);
end;
end;
else
Message.Result := DefWindowProc(TargetHandle, Message.Msg, Message.WParam, Message.LParam);
end;
end;
关于multithreading - (Delphi 2009) idIRC、MDI 和挂起问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1734757/
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在开发一个 .NET C# 应用程序,它有一个主窗体,它是 MDI 容器。当用户最大化 MDI 子项时,Windows 会在容器窗体的标题栏下方绘制一个控制条,其中包含子项的图标和右侧的系统按钮。
我有一个用 Delphi 2006 编写的 MDI 应用程序,它以默认主题运行 XP。 有没有办法控制 MDI 子项的外观以避免每个窗口上出现 XP 风格的大标题栏? 我尝试将 MDIChildren
我有一个包含面板的 MDI 父窗体。该面板包括图表和一些其他用户信息。当我从菜单中打开一个窗体时,新打开的窗体显示在 MDI 父面板下。如何显示所有 MDI 父控件上方的子窗体。我正在使用以下代码打开
我有一个 MDI 父窗体,它在运行时创建许多 MDI 子窗体。有没有一种聪明的方法可以在父级内部平均分配这些表格?有什么想法吗? 提前致谢! 最佳答案 **ArrangeIcons** chi
我想知道如何加载子表单,使其大小覆盖整个 MDI 父级的 MDI 容器空间(深灰色的东西)?将子窗体的 WindowState 设置为最大化不是一个选项,因为它也会最大化任何其他窗体。有建议吗? 最佳
我已经创建了一个父表单并为此引发了 ControlAdded 事件。并且还将此父窗体的属性 IsMdiContainer 设置为 true。然后,如果我创建一个名为 ChildForm1 和 Chil
我希望 MDI 父级自动调整子窗体的大小,使其在没有滚动条的情况下适合内部。有人可以提供一些代码吗? 我用它来区分父项和子项的大小,并将其添加到父项的大小,这样我就可以合身了。但它太手动了,制作时间太
我正在打开另一个 MDI 子窗体的 MDI 子窗体,它正在工作,但现在我必须以相同的方式关闭它,但没有任何反应。 这是我正在使用的代码示例: private void checkbox1_Checke
是否可以这样做,如果可以,怎么做? 我的应用程序的屏幕截图 最佳答案 您需要设置 AllowMerge property MenuStrip 的 false。 这将使子窗体上的 MenuStrip 保
我有一个带有多个子项的 MDI 表单,当我最大化一个 MDI 子项时,它会自动最大化所有子项。 我不想使用设置最大大小或设置最小大小属性。有什么办法可以防止mdi child 的这种行为吗? 最佳答案
我正在制作一个小型企业应用程序,我想知道最好的界面是什么。该应用程序本身就是您的普通服务票务跟踪器。将有用于搜索工单(带有结果网格)、创建新的勾选和查看现有工单、管理一些管理内容(用户、一些分类器等)
您好,我想打开来自 MDI Parent 的表格。 如果 For 已经打开,那么它应该被激活或打开新表格..现在我正在使用 foreach 循环。但我不想使用循环。 foreach (Form frm
我有一个 MDI 主窗体,一个显示子窗体的菜单项(我们称它为 frmEmployees),在这个窗体中有一个 Button (btnNew...) , 我如何从这里打开一个对话框 (frmNewEmp
我试图在 MDI 父级上检测我的 MDI 子级窗体何时关闭,并做出相应的 react 。在 MDI 子级关闭之前,MDI 父级不应执行任何操作。这是我的代码,我不确定我做错了什么,但是我添加的表单关闭
如何在正常创建的 MDI 窗口窗体中显示 WPF 窗体。 我们将表单创建为 MDI。增加菜单栏点击菜单会在主容器MDi窗体中显示wpf窗体。 private void newStudentToolS
我在子表单中有一个值(let CompanyId)。我想在 MDI 父窗体的级别中传递此值。 在子窗体中,我在数据 GridView 中从数据库中检索数据。现在我从数据 GridView 中选择一个值
我有一个带有此 FormClosing 事件处理程序的 MDI 父级: private void FrmMdiParent_FormClosing(object sender, FormClosing
有没有办法从用 Delphi 5 编写的 ActiveX dll 创建 MDI 子窗口,并将其嵌入到从 Delphi XE Windows 客户端应用程序创建的 MDI 父窗口中?如果没有,有没有办法
这个问题之前已经发布过,但我找不到一个好的答案。 我想在我的 WPF 应用程序中使用 MDI 子级。我希望这些 child 完全符合 WPF。 .Net WPF 不再有 MDI 子项(主窗口中的窗口)
我是一名优秀的程序员,十分优秀!