【问题标题】:ShowMessage is appearing behind form-DelphiShowMessage出现在form-Delphi后面
【发布时间】:2020-07-11 15:37:23
【问题描述】:

我的程序在代码中有一个 MessageBox。我第一次运行它时它似乎没有出现并且程序冻结了。我花了几个小时阅读论坛,我已经尝试了一切。我在 MessageBox 之前最小化了我的表单,似乎对话框出现在表单后面。我尝试了这段代码,但没有任何效果。

Application.NormalizeTopMosts; MessageBox(Handle,'Test','A message test',MB_SYSTEMMODAL or MB_SETFOREGROUND or MB_TOPMOST or MB_ICONHAND);

P.S.:我在程序中有另一个表单,它在该表单上运行良好,我确保它们都具有相同的设置

编辑:

我刚刚意识到是我的 StringGrid 的 OnCellDraw 功能导致消息被隐藏。我设法通过使 StringGrid 不可见然后再次可见来使其工作。 OnDrawCell 有一个愚蠢的代码,它使用带颜色的单元格显示一年中的预订天数。我想知道是否有更好的方法让消息出现而不使字符串网格不可见。不运行 OnDrawCell,MessageBox 也可以工作

procedure TfrmClient.stgYearPlanDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  k, iMonth, iDay, iStart, iEnd, iSubtract : Integer;
begin
    case iYear of
      2020 :  begin
                iStart := 1;
                iEnd:= 12;
                iSubtract := 0;
              end;
      2021  : begin
                iStart := 13;
                iEnd:= 24;
                iSubtract := 12;
              end;
      2022  : begin
                iStart := 25;
                iEnd := 36;
                iSubtract := 24;
              end;
    end;
    for k := 1 to 31 do
      stgYearPlan.Cells[k,0] := IntToStr(k);

    for k := 1 to 12 do
      stgYearPlan.Cells[0,k] := ShortMonthNames[k];

    for iMonth := iStart to iEnd do
    begin
    for iDay := 1 to 31 do
     begin
          if ar2Booking[iDay,iMonth] = 'Y' then
          begin
            if (ACol = iDay) and (ARow = (iMonth-iSubtract)) then
            begin
              stgYearPlan.Canvas.Brush.Color := clBlack;
              stgYearPlan.Canvas.FillRect(Rect);
              stgYearPlan.Canvas.TextOut(Rect.Left,Rect.Top,stgYearPlan.Cells[ACol, ARow]);
            end;
          end;

          if ar2Booking[iDay,iMonth] = 'D' then
          begin
            if (ACol = iDay) and (ARow = (iMonth-iSubtract)) then
            begin
              stgYearPlan.Canvas.Brush.Color := clSilver;
              stgYearPlan.Canvas.FillRect(Rect);
              stgYearPlan.Canvas.TextOut(Rect.Left+2,Rect.Top+2,stgYearPlan.Cells[ACol, ARow]);
            end;
          end;
     end;
     end;
end;```


【问题讨论】:

  • 你说你使用了ShowMessage函数,但是你的代码使用了MessageBox函数。是哪个?
  • 无论如何,您根本不需要任何技巧。 ShowMessage('Hello, World!') 应该可以完美运行,MessageBox(Handle, 'Hello, World!', 'My App', MB_ICONINFORMATION) 也应该如此。您的应用程序有问题。尝试在新的 VCL 应用程序中显示一个消息框,看看它是否有效。然后从您的应用中一次删除一个部分,直到问题消失。
  • 我想说(但我只是猜测)最可能的原因是您的表单有FormStyle = fsStayOnTop,您使用的是MessageBox(而不是ShowMessage),并且您提供了错误的窗口句柄(第一个参数必须是表单的句柄)。尝试从表单中删除fsStayOnTop,使用ShowMessage 而不是MessageBox,或者提供正确的句柄(您可以明确表示:Form1.Handle)。
  • 对不起,我同时使用了 ShowMessage 和 MessageBox。我想使用 ShowMessage,但我都尝试过让它工作@Andreas Rejibrand
  • 问题是你用OnDrawCell处理程序中的数据填充字符串网格。您只应该在此方法中在画布上绘图;你不应该接触数据。当网格需要重绘时,调用该方法。您在网格中绘制(确定),但您也更改了数据。正因为如此,网格意识到它需要再次重绘自己(因为它的数据已经改变了!),所以调用了这个方法。您在网格中绘制(确定),但您也更改了数据。正因为如此,网格意识到它需要再次重绘自己(因为它的数据已经改变了),所以这个...

标签: delphi


【解决方案1】:

问题是您在其OnDrawCell 处理程序中使用数据填充字符串网格。

您只应该在此方法中在画布上绘图;你不应该接触数据。

当网格需要重新绘制时,会调用其OnDrawCell 处理程序。您在网格中绘制(没关系),但您也更改了数据。正因为如此,网格意识到它需要再次重绘自己(因为它的数据已经改变了!),所以它的OnDrawCell 处理程序被调用。您在网格中绘制(没关系),但您也更改了数据。正因为如此,网格意识到它需要再次重绘自己(因为它的数据已经改变了!),所以它的OnDrawCell处理程序被调用,...

好吧,我就停在那里。

显然,这会导致无限的重绘序列,这将使您的应用程序忙于重绘网格。

您可以很容易地看到这种现象的实际作用。只需创建一个新的 VCL 应用程序,在主窗体上拖放一个 TStringGrid 并添加

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  StringGrid1.Cells[3, 3] := Random(100).ToString;
end;

您会在 (3, 3) 单元格中看到一个不断更新的随机数。

忙于绘制网格会产生很多后果。例如,除了您发现的消息框异常之外,您可能会看到您的进程最大化 CPU 的单个“线程”(例如,如果您有一个四核 HT CPU,您将完全使用一个线程,或 1/8 = 12.5% CPU)。

【讨论】:

  • 顺便说一句,消息框实际上并没有隐藏在表单后面。在您按 Alt 之前,它根本不会显示在屏幕上。但是,它仍然响应 Esc 和 Enter 键。谷歌告诉我这种行为并非闻所未闻,但我仍然不完全了解其背后的确切机制。顺便说一句,当我尝试使用 Alt+Space 调出对话框的系统菜单时,我意识到了这一点。这是访问隐藏在其他窗口下方的窗口的常见技巧。只需打开系统菜单,选择“移动”并使用箭头键使窗口可见。
猜你喜欢
  • 2013-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多