【发布时间】:2016-08-07 20:03:05
【问题描述】:
3 个子问题:
[1] python GUI 是基于轮询的?
在我看来,tk 和 qtpy 都是基于轮询的,如果 gui 调用一个需要一段时间才能执行的函数,整个 gui 就会挂起。
很早以前就了解了gui,我记得现代的gui应该是基于中断的,即使gui执行了一些大的事情,gui也应该一直响应。 gui 可能不会显示这些大计算的结果,但它会响应调整大小、显示按钮单击动画等。所以我的问题是,是否有类似的选项:
#psuedo code
root=tkinter.Tk()
root.setInterruptMode(True)
[2] tk.mainloop() 只是一个巨大的循环吗?
如果我的第一个问题是白日梦,我只需要学习线程和多进程,那么我的下一个问题是关于root.mainloop()(或qtpy 的exec_())。
我的印象是 mainloop() 并没有真正在 python 中启动线程或任何东西,它只是将一个巨大且不可见的 tkinter 的 gui polling+painting 循环打包到我的主线中。我的印象正确吗?
[3] 为什么要把 mainloop 放在 Main 行? mainloop() 是否必须驻留在主线中?我可以线程/多处理它吗?这样我的主线就可以专注于大计算,主线控制gui进程和IO进程。我遇到的所有示例在 Main 行中都有 mainloop(),我不确定这是推荐的方法或有什么好处。
下面是我在学习python gui时写的代码:
import tkinter
import random
class myGUI():
def __init__(self, arg_tkroot):
self.GUI_display = tkinter.Label(arg_tkroot, text='init-ed')
self.GUI_button = tkinter.Button(arg_tkroot, text='click')
self.GUI_display.pack()
self.GUI_button.pack()
self.GUI_button.bind('<Button-1>', self.handle_user_interaction)
self.list_bigData = []
#handles GUI interaction, and call bigData_and_bigCalculation()
def handle_user_interaction(self, arg_event):
print(arg_event, ' detected by myGUI')
strResult_toFeedbackToUser = self.bigData_and_bigCalculation()
self.GUI_display.config(text=strResult_toFeedbackToUser)
print('finished handling user interact')
# slow calculations and memory consuming operations
def bigData_and_bigCalculation(self):
self.list_bigData[:]=[]
for i in range(500000):
self.list_bigData.append( ''.join(random.choice('asdfas') for k in range(10)) )
return self.list_bigData[-1]
# Main()
if __name__ == '__main__':
root = tkinter.Tk()
mygui = myGUI(root)
root.mainloop()
【问题讨论】:
-
好吧,如果你将在 GUI 线程中执行一些长时间的工作,那么 GUI 将冻结。为避免这种情况,请为不同的作业生成不同的线程。
-
有趣的问题;我已经在 Tk 中编写了大约 10 个小型和一个平均大小的应用程序(在 Qt 中没有),从来没有出现过响应问题,也从未想过 Tk 的 GUI 方式 :) 我建议总体上遵循 ForceBru adwise;顺便说一句,我已经将 Kivy 用于我的 GUI 应用程序,可以推荐,它比 Tk 更灵活,并且如果需要也可以在 android 和 ios 上很好地工作。
-
我担心不得不使用线程和多进程是不可避免的。但是在我的第一个子问题中,我之前了解了基于“中断”的 gui(当时的 java 小程序),我当时从未遇到过 gui freeze,这是一个错误的印象,因为我们在学习这些东西时从未做过任何大的计算?
-
如果您可以将 1 秒以上的工作分解为 10 甚至 100 毫秒的片段,那么您可以使用 root.after 循环并在对其他事件的响应中穿插工作片段。在 SO 中搜索
[tkinter] root.after以获取示例。
标签: python qt tkinter python-3.5