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

发布于 2024-09-09 17:59:37 字数 2130 浏览 8 评论 0原文

我有一个主窗体上带有 TPageControl 的应用程序。页面控件有几个选项卡。该应用程序可以最小化为托盘图标。有时,在最小化运行一段时间后,当我恢复主窗口(通过右键单击托盘图标)时,会显示最后显示的选项卡,但我无法选择任何其他选项卡!

如果我单击另一个选项卡,外观会发生变化,以便该选项卡看起来是活动选项卡(即选项卡本身移动到选项卡行的前面),但选项卡的主体保持原样。我还有菜单项和快捷键来选择其他选项卡,它们的行为相同。如果我输入 Alt-O(选项),顶部的选项选项卡将变为活动状态,但我看不到该选项卡主体上的内容 - 我仍然可以看到其他选项卡的内容。

我已经验证,当我单击另一个选项卡时,焦点会从第一个选项卡移开,而当我单击该选项卡时,焦点会移回。

我尚未确定该行为是否仅限于特定选项卡,因为它需要一段时间才能发生。

有什么想法吗?

更新

有趣的注释。我已经确定问题是在这些情况下发生的。应用程序启动,然后最小化到托盘。检测到警报条件,弹出一个窗口并恢复主窗口(这是应用程序的预期行为)。正是在这一点上观察到了错误 - 即当我单击其他选项卡时我看不到它们。

  • 启动应用程序。显示选项卡 1
  • 最小化应用程序。到托盘
  • 等待弹出窗口显示,主窗体恢复
  • 单击选项卡 2 观察到故障(选项卡 2 正文不显示)
  • 在 TWinControl.CreateHandle 中放置断点
  • 单击选项卡 3 - 中断
  • 运行 - 不显示选项卡 3 正文
  • 单击选项卡 1 - 不会中断
  • 单击选项卡 3 - 不会中断
  • 单击选项卡 4 - 中断
  • 运行 - 不会显示选项卡 4 主体
  • 单击选项卡 1、2、3、4 - 不会中断

因此,选项卡似乎正在创建其句柄第一次点击它们时,从那时起,它们认为它们存在,但它们没有显示。如果弹出窗口被禁用,则不会观察到故障。弹出窗口是由 Application.OnIdle 任务触发的。

另一个更新:一些进展。在网上查了一下之后,我做了一些修改。

我删除了以下代码:

procedure RestoreMainWindow ;

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

并将其替换为:

procedure RestoreMainWindow ;

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

我删除了:

procedure TTADMainForm.SendToTray (Sender: TObject) ;

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

并将其替换为:

procedure TTADMainForm.ApplicationEvents1Minimize(Sender: TObject) ;

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

问题似乎已经消失。然而。现在我可以在启动后最小化应用程序,弹出窗口出现并以模式方式显示,主窗体显示,所有选项卡显示并工作。但。我无法再次最小化表单。 OnMinimize 处理程序在第一次后不会被触发。咕噜咕噜。

我仍然无法理解为什么它现在起作用,这有点令人担忧。我怎样才能让它再次最小化?

I have an app with a TPageControl on the main form. 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 (i.e 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.

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 - i.e. I cant see the other tabs when I click on them.

  • Start app. Tab 1 is displayed
  • 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)
  • Put breakpoint in TWinControl.CreateHandle
  • Click on Tab 3 - breaks
  • Run - does not show Tab 3 body
  • Click on Tab 1 - does not break
  • Click on Tab 3 - does not break
  • Click on Tab 4 - breaks
  • Run - does not show Tab 4 body
  • Click on Tab 1, 2, 3, 4 - does not break

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.

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. Grrrrr.

I still can't fathom why it works now, which is a little worrying. And how do I get it to minimize again??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蓝海 2024-09-16 17:59:37

完全根据 5 年前的记忆工作,但这里是这样的:

TPageControl 对其中的每个页面使用不同的窗口句柄。标签栏是它自己的窗口句柄,TPageControl负责监听标签变化并做出相应的页面隐藏/显示。因此,当您单击某个选项卡并且该选项卡跳转到包的前面时,TPageControl 应该隐藏当前页面窗口并显示与所选选项卡对应的页面窗口。

通常,VCL 控件不会创建其窗口句柄,直到实际需要时(例如,当它实际显示时)。这减少了窗口句柄消耗。在 Windows 3.1 和 Win95 中至关重要,但在当今基于 NT 的 32 位操作系统中则不那么重要。

为了最大限度地减少资源负载和启动时间,在创建控件时,TPageControl 不会为其所有隐藏页面创建窗口句柄。页面窗口句柄将在首次显示时创建。

单击选项卡时未绘制页面的原因有以下几种可能:

  1. 耗尽 GDI 窗口句柄池。除非您使用的是 16 位 Windows 操作系统,否则极不可能。 (Win 3.1 或 Win95)
  2. 内存泄漏导致您的应用程序溢出到交换文件中并破坏硬盘。该应用程序将逐渐停止,看起来像是冻结了,并且时不时地出现 UI 活动。
  3. 在没有消息循环的后台线程上创建窗口句柄。您在后台线程中执行任何操作吗?在后台线程中触摸 VCL 控件可能会导致过早创建窗口句柄,并且窗口句柄将绑定到创建它的线程。如果该线程没有消息循环,则该窗口句柄将永远不会接收任何消息,因此它永远不会在屏幕上绘制自己。

第三名是最有可能的罪魁祸首。那么,您在后台线程中做什么? ;>

Working entirely from 5 years ago memory, but here goes:

TPageControl uses a different window handle for each page within it. 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. 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.

Normally, VCL controls don't create their window handle until it is actually needed - when it's actually shown, for example. 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.

To minimize resource load and startup time, TPageControl doesn't create window handles for all its hidden pages when the control is created. 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. Extremely unlikely unless you're on a 16 bit Windows OS. (Win 3.1 or 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.
  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. 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? ;>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文