PyQt中wx的空闲和UI更新事件
wx(和 wxPython)有两个我在 PyQt 中错过的事件:
- 被发送到框架的
EVT_IDLE
。 它可用于根据应用程序的状态 EVT_UPDATE_UI
更新各种小部件,该状态在必须重新绘制和更新时发送到小部件,因此我可以在处理程序中计算其状态
现在,PyQt 不这样做似乎没有这些,PyQt 书建议编写一个 updateUi 方法并手动调用它。 我什至最终每 0.1 秒从计时器调用一次,以避免从可能更新 GUI 的方法中进行许多手动调用。 我错过了什么吗? 有更好的方法来实现这一目标吗?
一个例子:我有一个简单的应用程序,带有一个“开始”按钮,可以启动一些处理。 仅当使用菜单打开文件时才应启用开始按钮。 此外,状态栏上还有一个显示信息的永久小部件。
我的应用程序有状态:
- 在文件打开之前(在这种状态下,状态栏显示一些特殊的内容,并且禁用开始按钮)
- 文件已打开,但处理未开始:启用开始按钮,状态栏显示其他内容
- 处理正在运行:开始按钮现在显示“停止”,状态栏报告进度
在 Wx 中,我让按钮的更新 UI 事件处理其状态:其上的文本以及是否启用,具体取决于应用程序状态。 状态栏也是如此(或者我会使用 EVT_IDLE)。
在 Qt 中,我必须在可能影响状态的几种方法中更新按钮,或者只是创建一个 update_ui 方法并在计时器中定期调用它。 更“QT”的方式是什么?
wx (and wxPython) has two events I miss in PyQt:
EVT_IDLE
that's being sent to a frame. It can be used to update the various widgets according to the application's stateEVT_UPDATE_UI
that's being sent to a widget when it has to be repainted and updated, so I can compute its state in the handler
Now, PyQt doesn't seem to have these, and the PyQt book suggests writing an updateUi
method and calling it manually. I even ended up calling it from a timer once per 0.1 seconds, in order to avoid many manual calls from methods that may update the GUI. Am I missing something? Is there a better way to achieve this?
An example: I have a simple app with a Start button that initiates some processing. The start button should be enabled only when a file has been opened using the menu. In addition, there's a permanent widget on the status bar that displays information.
My application has states:
- Before the file is opened (in this state the status bar show something special and the start button is disabled)
- File was opened and processing wasn't started: the start button is enabled, status bar shows something else
- The processing is running: the start button now says "Stop", and the status bar reports progress
In Wx, I'd have the update UI event of the button handle its state: the text on it, and whether it's enabled, depending on the application state. The same for the status bar (or I'd use EVT_IDLE for that).
In Qt, I have to update the button in several methods that may affect the state, or just create a update_ui method and call it periodically in a timer. What is the more "QT"-ish way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在 wxWidgets 中使用 EVT_UPDATE_UI 似乎突出了 wxWidgets 和 Qt 期望开发人员在其代码中处理事件的方式的根本区别之一。
使用 Qt,您可以在用户界面中的小部件之间连接信号和槽,处理每个槽中的“业务逻辑”或将其委托给专用方法。 您通常不必担心对 GUI 中的每个小部件进行单独的更改,因为任何重绘请求都将被放置在事件队列中,并在控制权返回到事件循环时传递。 为了提高效率,一些绘制事件甚至可以合并在一起。
因此,在使用信号和槽来处理状态更改的普通 Qt 应用程序中,基本上不需要有一个空闲机制来监视应用程序的状态并更新小部件,因为这些更新应该自动发生。
您必须多说一些您正在做的事情,以解释为什么您需要与 Qt 中的此事件等效的事件。
The use of EVT_UPDATE_UI in wxWidgets seems to highlight one of the fundamental differences in the way wxWidgets and Qt expect developers to handle events in their code.
With Qt, you connect signals and slots between widgets in the user interface, either handling "business logic" in each slot or delegating it to a dedicated method. You typically don't worry about making separate changes to each widget in your GUI because any repaint requests will be placed in the event queue and delivered when control returns to the event loop. Some paint events may even be merged together for the sake of efficiency.
So, in a normal Qt application where signals and slots are used to handle state changes, there's basically no need to have an idle mechanism that monitors the state of the application and update widgets because those updates should occur automatically.
You would have to say a bit more about what you are doing to explain why you need an equivalent to this event in Qt.
我会发送 Qt 信号来指示状态更改(例如 fileOpened、processingStarted、processingDone)。 管理开始按钮和状态栏小部件(或子类)的对象中的插槽可以连接到这些信号,而不是在空闲事件中“轮询”当前状态。
如果您希望信号稍后在事件循环中延迟而不是立即延迟(例如,因为需要花费一些时间来做某事),则可以使用“排队”信号槽连接而不是普通类型。
http://doc.trolltech.com/4.5/signalsandslots.html#signals
连接类型是 connect() 函数的可选参数:
http://doc.trolltech.com/4.5/qobject.html#connect , http://doc.trolltech.com/4.5/qt.html# ConnectionType-枚举
I would send Qt signals to indicate state changes (e.g. fileOpened, processingStarted, processingDone). Slots in objects managing the start button and status bar widget (or subclasses) can be connected to those signals, rather than "polling" for current state in an idle event.
If you want the signal to be deferred later on in the event loop rather than immediately (e.g. because it's going to take a bit of time to do something), you can use a "queued" signal-slot connection rather than the normal kind.
http://doc.trolltech.com/4.5/signalsandslots.html#signals
The connection type is an optional parameter to the connect() function:
http://doc.trolltech.com/4.5/qobject.html#connect , http://doc.trolltech.com/4.5/qt.html#ConnectionType-enum
据我了解,当应用程序消息队列为空时,会发送 EVT_IDLE 。 Qt 中没有这样的事件,但是如果您需要在 Qt 中没有待处理事件时执行某些操作,则应该使用 0 超时的 QTimer。
As far as I understand EVT_IDLE is sent when application message queue is empty. There is no such event in Qt, but if you need to execute something in Qt when there are no pending events, you should use QTimer with 0 timeout.
一般来说,更接近 Qt 的方式是在任何需要更新的功能中根据需要更新按钮/工具栏,或者合并一些功能并在程序需要时直接调用该功能(例如 updateUi 功能)。
您应该知道,在 Qt 中,更改 Ui 元素的属性不会导致立即重绘,而是在事件系统中对重绘进行排队,并且在可能的情况下将多个重绘调用压缩为一个。
至于与状态相关的多个更改,请查看 这篇博文介绍了 Qt 即将推出的新功能,以更轻松地处理状态。 看起来这会解决你的很多抱怨,因为在你的多个函数中,你可以只转换状态变量,并且 UI 的其他部分应该更新以匹配。 不确定这是否会进入下一个 Qt 版本(尽管我打赌它或类似的东西),而且我不知道 PyQt 跟踪 Qt 版本的密切程度。 或者,您可以使用该概念并创建自己的类来根据需要跟踪状态。
In general, the more Qt-ish way is to update the button/toolbar as necessary in whatever functions require the update, or to consolidate some of the functionality and directly call that function when the program needs it (such as an updateUi function).
You should be aware that in Qt, changing an attribute of a Ui element doesn't cause an immediate redraw, but queues a redraw in the event system, and multiple redraw calls are compressed into one where possible.
As for the multiple changes relating to state, have a look at this blog post about a hopefully-upcoming addition to Qt to more easily handle states. It looks like this would take care of a lot of your complaints, because in your multiple functions, you could just transition the state variable, and the other parts of the UI should update to match. It's not positive this will make it into the next Qt release (although I would bet on it, or something similar), and I have no idea how closely PyQt tracks the Qt releases. Or alternately, you could use the concept and create your own class to track the state as needed.