ShowMessage 出现在表单后面-Delphi
ShowMessage is appearing behind form-Delphi
我的程序在代码中有一个 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 有一个愚蠢的代码,它使用彩色单元格显示一年中的预订天数。我想知道是否有更好的方法可以在不使 stringgrid 不可见的情况下显示消息。没有 运行 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;```
问题是您使用 OnDrawCell
处理程序中的数据填充字符串网格。
你只应该在这个方法中绘制 canvas;你不应该触摸数据。
当网格需要重新绘制时,调用其 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).
我的程序在代码中有一个 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 有一个愚蠢的代码,它使用彩色单元格显示一年中的预订天数。我想知道是否有更好的方法可以在不使 stringgrid 不可见的情况下显示消息。没有 运行 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;```
问题是您使用 OnDrawCell
处理程序中的数据填充字符串网格。
你只应该在这个方法中绘制 canvas;你不应该触摸数据。
当网格需要重新绘制时,调用其 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).