简体   繁体   English

Delphi TPageControl不响应选项卡上的单击

[英]Delphi TPageControl not responding to clicks on tabs

I have an app with a TPageControl on the main form. 我在主窗体上有一个带有TPageControl的应用程序。 The pagecontrol has several tabs. 页面控件有几个选项卡。 The app can be minimized to a tray icon. 该应用程序可以最小化到一个托盘图标。 Sometimes after running minimized for a while, when I restore the main window (via a right-mouse click on the tray icon), the tab that was last displayed is displayed, but I can't select any other tabs! 有时在最小化运行一段时间后,当我还原主窗口时(通过右键单击任务栏图标),将显示最后显示的选项卡,但是我无法选择其他任何选项卡!

If I click on another tab, the appearance changes so that tab then appears to be the active one (ie the tab itself moves to the front of the row of tabs), but the body of the tab remains as it was. 如果单击另一个选项卡,则外观会发生变化,因此该选项卡看起来像是活动的选项卡(即,选项卡本身移至选项卡行的前面),但选项卡的主体保持原样。 I also have menu items and shortcut keys to select the other tabs and they behave the same. 我也有菜单项和快捷键来选择其他选项卡,它们的行为相同。 If I type Alt-O (options) the options tab at the top becomes active but I can't see what is on the body of that tab - I still see the other tab's contents. 如果我键入Alt-O(选项),则顶部的“选项”选项卡将变为活动状态,但看不到该选项卡主体上的内容-我仍然看到另一个选项卡的内容。

I have verified that focus moves off the first tab when I click on another tab and moves back when I click on that tab. 我已经验证,当我单击另一个选项卡时焦点将移出第一个选项卡,而当我单击该选项卡时将焦点移回。

I haven't yet established if the behaviour is confined to a particular tab as it takes a while for it to happen. 我还不确定行为是否仅限于特定选项卡,因为它需要一段时间才能实现。

Any ideas? 有任何想法吗?

Update 更新

Interesting note. 有趣的笔记。 I have established that the problem occurs under these circumstances. 我已经确定在这种情况下会出现问题。 The app is started, then minimized to the tray. 该应用程序已启动,然后最小化到任务栏中。 An alert condition is detected, pops up a window and restores the main window (this is intended behaviour of the app). 检测到警报条件,弹出一个窗口并还原主窗口(这是应用程序的预期行为)。 It is at this point the fault is observed - ie I cant see the other tabs when I click on them. 正是在这一点上可以观察到故障-即单击其他选项卡时看不到它们。

  • Start app. 启动应用程序。 Tab 1 is displayed 显示选项卡1
  • Minimize app. 最小化应用程序。 to tray 到托盘
  • Wait for popup to show, main form is restored 等待弹出窗口显示,主窗体已恢复
  • Click on Tab 2 FAULT OBSERVED (Tab 2 body does not display) 单击选项卡2观察到的故障(选项卡2的主体不显示)
  • Put breakpoint in TWinControl.CreateHandle 将断点放在TWinControl.CreateHandle中
  • Click on Tab 3 - breaks 点击标签3-休息
  • Run - does not show Tab 3 body 运行-不显示Tab 3正文
  • Click on Tab 1 - does not break 单击选项卡1-不中断
  • Click on Tab 3 - does not break 单击选项卡3-不中断
  • Click on Tab 4 - breaks 单击选项卡4-休息
  • Run - does not show Tab 4 body 运行-不显示Tab 4正文
  • Click on Tab 1, 2, 3, 4 - does not break 单击选项卡1、2、3、4-不中断

So it seems the tabs are creating their handles the first time they are clicked on, and from that point on they think they exist, but they don't show. 因此,似乎这些选项卡是在第一次单击时创建其句柄的,从那以后它们就认为它们存在,但不显示。 If the popup is disabled the fault is not observed. 如果禁用了弹出窗口,则不会观察到故障。 The popup is triggered from an Application.OnIdle task. 弹出窗口是从Application.OnIdle任务触发的。

Another update: Some progress. 另一个更新:进展。 After poking around on the web I made some changes. 在网上闲逛之后,我进行了一些更改。

I removed the following code: 我删除了以下代码:

procedure RestoreMainWindow ;

begin
MainForm.WindowState := wsNormal ;
MainForm.visible := true ;
Application.Restore ;
Application.BringToFront ;
ShowWindow (Application.Handle, SW_SHOW) ;  { show the taskbar button }
end ;

and replaced it with: 并替换为:

procedure RestoreMainWindow ;

begin
MainForm.Show () ;
MainForm.WindowState := wsNormal ;
Application.BringToFront () ;
ShowWindow (Application.Handle, SW_SHOW) ;  { show the taskbar button }
end ;

I removed: 我删除了:

procedure TTADMainForm.SendToTray (Sender: TObject) ;

begin
MainForm.visible := false ;
ShowWindow (Application.Handle, SW_HIDE) ;  { hide the taskbar button }
end ;
...
Application.OnMinimize := SendToTray ;    

and replaced it with: 并替换为:

procedure TTADMainForm.ApplicationEvents1Minimize(Sender: TObject) ;

begin
Hide();
WindowState := wsMinimized ;
TrayIcon1.Visible := True;
end ;

and the problem seems to have gone. 而且问题似乎已经消失了。 HOWEVER. 然而。 Now I can minimize the app after startup, the popup occurs and shows modally, the main form shows, all the tabs display and work. 现在,我可以在启动后最小化应用程序,弹出窗口会以模态显示,主窗体会显示,所有选项卡都会显示并工作。 BUT. 但。 I can't minimize the form again. 我无法再次最小化表格。 The OnMinimize handler doesn't get triggered after the first time. 第一次之后,不会触发OnMinimize处理程序。 Grrrrr. Grrrrr。

I still can't fathom why it works now, which is a little worrying. 我仍然无法理解为什么它现在可以工作,这有点令人担忧。 And how do I get it to minimize again?? 以及如何使它再次最小化?

Working entirely from 5 years ago memory, but here goes: 完全从5年前的内存开始工作,但是这里有:

TPageControl uses a different window handle for each page within it. TPageControl对其中的每个页面使用不同的窗口句柄。 The tab bar is its own window handle, and the TPageControl is responsible for listening to tab changes and making the corresponding hide/show of pages. 标签栏是它自己的窗口句柄,TPageControl负责侦听标签的更改并进行相应的页面隐藏/显示。 So, when you click on a tab and the tab jumps to the front of the pack, the TPageControl is supposed to hide the current page window and show the page window corresponding to the selected tab. 因此,当您单击一个选项卡并且该选项卡跳到包的最前面时,TPageControl应该隐藏当前页面窗口并显示与所选选项卡相对应的页面窗口。

Normally, VCL controls don't create their window handle until it is actually needed - when it's actually shown, for example. 通常,VCL控件在实际需要时才创建窗口句柄-例如,在实际显示时。 This reduces window handle consumption. 这减少了窗把手的消耗。 Critically important in Windows 3.1 and Win95, but not so critical in today's NT based 32 bit OS's. 在Windows 3.1和Win95中非常重要,但在当今基于NT的32位操作系统中却不那么重要。

To minimize resource load and startup time, TPageControl doesn't create window handles for all its hidden pages when the control is created. 为了最小化资源负载和启动时间,在创建控件时,TPageControl不会为其所有隐藏页面创建窗口句柄。 The page window handles will be created when they are first shown. 页面窗口句柄将在首次显示时创建。

There are a few possibilities for why the page is not being drawn when the tab is clicked: 单击选项卡时,为什么无法绘制页面有几种可能性:

  1. Exhausting the GDI window handle pool. 耗尽GDI窗口句柄池。 Extremely unlikely unless you're on a 16 bit Windows OS. 除非您使用的是16位Windows操作系统,否则这种情况极不可能发生。 (Win 3.1 or Win95) (Win 3.1或Win95)
  2. Memory leak that causes your app to spill into the swap file and thrash the hard disk. 导致您的应用溢出到交换文件并损坏硬盘的内存泄漏。 The app will grind to a near halt and look like it's frozen, with burps of UI activity every now and then. 该应用程序将磨碎到几乎停止并且看起来像被冻结一样,时不时出现UI活动。
  3. Window handles being created on a background thread that has no message loop. 在没有消息循环的后台线程上创建窗口句柄。 Are you doing anything in background threads? 您在后台线程中做什么? Touching a VCL control in a background thread can cause the window handle to be created prematurely, and the window handle will be bound to the thread it was created on. 在后台线程中触摸VCL控件可能导致过早创建窗口句柄,并且窗口句柄将绑定到在其上创建的线程。 If that thread has no message loop, then that window handle will never receive any messages, so it will never draw itself on screen. 如果该线程没有消息循环,则该窗口句柄将永远不会收到任何消息,因此它将永远不会在屏幕上绘制自身。

No. 3 is your most likely culprit. 第三名是您最有可能的罪魁祸首。 So, what are you doing in that background thread? 那么,您在该后台线程中正在做什么? ;> ;>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM