我的程序处于发布后状态,所以请多多包涵。
设想
我的程序基于办公数据管理系统(面向车辆维护)的不同功能的不同页面的多种布局。这些功能的一个主要类别显然是数据输入。我使用不同的风格来适应不同的受众。
言归正传,其中一个界面具有 excel 样式的网格和 3 个用于打印/保存/重置功能的按钮。我使用 FastReports 打印表单。
我正在为网格列开发一个自定义类,以使它们适应预定义的控件列表而不是动态的单元格,但现在我只是在代码中创建了所需的单元格子控件。
该页面有 3 个部分(布局);
顶部是一种特定于所有页面的目的(添加/修改/添加部分)选择器,在不需要的地方可能不可见。
中间一个是一个控件,用于接收要修改的表单的收据编号,它们的信息嵌入到其他表单中等。它主要在每一页上,但不是全部。
最后一个具有页面内容,即前面提到的网格和 3 个按钮。
代码
这是用于显示其中一个有问题的页面的代码片段。它在所有数据处理完成并且服务器 OK 转换时执行。
传奇
AState : 状态机状态变量;表示显示页面的当前状态。
AMode : 状态机状态枚举器;表示整个应用程序的模式,例如预订(数据输入)等。我跳过了涉及此的代码,因为它在 AState 转换期间被跳过以发生此问题。
fMode:与上面相同,但它是表单的主要字段。
UI_CA_Controls1:包含预订模式的目的选择器(组合列表框)的布局。
EV_Mode:为方便起见的变量;它存储目的选择器的项目索引。
UI_CA_Grid:包含在 UI_CA_Content 中的布局本身包含 UI_CA_FieldGrid (TGrid)。
fEditColumn:具有 TEdits 的网格的第二列。
fGridDataset:网格关联的 TStringList。
//
procedure TUI.SetFormState ( AState : Byte; AMode : TMode = UIM_Unselected );
var
EV_Mode, I : Byte;
begin
// ---------------------------------------------------------------------------
fFormState := AState;
// The children of the grid cells
fCalEdit1.Parent := nil; // Calender Edits
fCalEdit2.Parent := nil;
fVehicleClass.Parent := nil; // Combo List Boxes
fEmployee1.Parent := nil;
fEmployee2.Parent := nil;
fEmployee3.Parent := nil;
fEmployee4.Parent := nil;
// ---------------------------------------------------------------------------
if AState = 0 then
begin
for I := 0 to 20 do
DPCM.fGridDataset.Strings [I] := ''; // The Grid Associated TStringList
UI_CA_ReceiptNo.ReadOnly := False;
UI_CA_ReceiptNo.Text := '';
end;
// ---------------------------------------------------------------------------
UI_CA_Content.BeginUpdate;
case fMode of
// Skipped unrelated modes
UIM_Booking :
begin
UI_CA_Controls1.Visible := True;
EV_Mode := UI_CA_EV_ModeSelect.ItemIndex;
// -----------------------------------------------------------------------
if fFormState = 0 then
begin
// Skipped handling of other EV_Mode values
if EV_Mode < 7 then
begin
UI_CA_ReceiptControl.Visible := True;
UI_CA_Content.Visible := False;
end;
end
// -----------------------------------------------------------------------
else if fFormState = 1 then // The problematic area
begin
if ( EV_Mode = 3 ) or ( EV_Mode = 4 ) then
begin
UI_CA_FieldGrid.RowCount := 6;
UI_CA_Grid.Height := 160;
fCalEdit1.Parent := fEditColumn.CellControlByRow ( 0 );
fCalEdit1.Date := Date;
fCalEdit2.Parent := nil;
fVehicleClass.Parent := fEditColumn.CellControlByRow ( 2 );
fVehicleClass.ItemIndex := 0;
end;
UI_CA_Content.Visible := True;
end;
end;
// -------------------------------------------------------------------------
end;
// ---------------------------------------------------------------------------
// Workaround 1
if UI_CA_Content.Visible then
begin
UI_CA_FieldGrid.UpdateColumns;
UI_CA_Content.EndUpdate;
UI_CA_FieldGrid.SetFocus;
UI_CA_C2_Reset.SetFocus;
UI_CA_C2_Print.SetFocus;
UI_CA_C2_Save.SetFocus;
UI_CA_FieldGrid.SetFocus;
end
else UI_CA_Content.EndUpdate;
end;
问题
问题是,无论何时显示收据部分,内容部分都不会在现场显示。行为是这样的,当我将鼠标悬停在应该显示这些子控件和 3 个按钮的位置时,当我单击它时才显示网格。
这个问题本身就出现了,UI 代码没有变化,这让我困惑了 3 天。我只对网络端的协议和数据处理(独立数据模块)进行了优化。
序列
用户想要修改已经预订的车辆数据。
用户输入预订收据编号。(AState = 0,AMode = UIM_Booking)
客户端查询的服务器和服务器回复完整的数据集(如果存在)。
客户端获取数据并将其复制到 Grid 关联的 TStringlist 和子字段的字符串中。
客户端不显示带有数据和 3 个按钮的网格。(AState = 1,AMode = UIM_Booking)
到目前为止我尝试了什么
使用了 BeginUpdate/EndUpdate,这使得对齐工件变得更糟。
在网格和按钮上使用 SetFocus 会导致其中一些随机显示,有时会完整显示,但并非每次都显示。
使用 Application.ProcessMessages 没有任何变化,而不是 UI 线程有时只是卡在其中永远不会返回。在单独的线程中使用它,每秒调用一次,没有任何变化。
为该方法使用了单独的线程,但问题更多。
回溯和恢复旧的工作代码,没有任何变化(让我很生气)。
更新 1:我试图使网格不可见,然后在代码末尾可见。现在网格的一些单元格随机显示。
解决方法 1
- 当为它们中的每一个调用 SetFocus 方法时,可以显示网格和按钮。
- 按钮的调用顺序是不稳定的。就像我必须先调用重置然后打印并保存 SetFocus 方法,否则只有其中一个被显示。
- 有一个瞬间的重新对齐故障,显示控件正在调整大小,但我认为这是可以忽略的。
解决方法 2
- 进行排队重绘而不是立即重绘。它没有任何警告,但问题在于每次重绘之间都有延迟。链接:https ://stackoverflow.com/a/8424750/1388291
因此,如果你们有任何建议,我将不胜感激。