Python 3.x 为什么可以';是否同时运行tkinter mainloop和cefpython3 messageloop?

Python 3.x 为什么可以';是否同时运行tkinter mainloop和cefpython3 messageloop?,python-3.x,tkinter,cefpython,Python 3.x,Tkinter,Cefpython,我在Python3中的一个项目中工作,在这个项目中,我有tkinter和一个带有cef浏览器的tkinter框架。 这是代码 from tkinter import messagebox #import threading from cefpython3 import cefpython as cef import platform import sys from tkinter import * import time def on_closing (): print('closin

我在Python3中的一个项目中工作,在这个项目中,我有tkinter和一个带有cef浏览器的tkinter框架。 这是代码

from tkinter import messagebox
#import threading
from cefpython3 import cefpython as cef
import platform
import sys
from tkinter import *
import time

def on_closing ():
    print('closing')
    r.destroy()
    cef.Shutdown()

r = Tk()
r.geometry('800x600')

r.protocol('WM_DELETE_WINDOW', on_closing)

f = Frame(r, bg = 'blue', height = 200)
f.pack(side = TOP, fill = 'x')

g=Frame(r,bg = 'white',height = 200)
g.pack(side = TOP, fill = 'x')

b1 = Button (g,text='Exit',command = on_closing)
b1.pack (side = LEFT)
b2 = Button (g,text='Show something',command = lambda:messagebox.showinfo('TITLE', 'Shown something'))
b2.pack (side = RIGHT)

sys.excepthook = cef.ExceptHook

rect = [0, 0, 800, 200]
print('browser: ', rect[2],'x',rect[3])
window_info=cef.WindowInfo(f.winfo_id())
window_info.SetAsChild(f.winfo_id(),rect)
cef.Initialize()
browser = cef.CreateBrowserSync(window_info, url='http://www.google.com')

r.update()

cef.MessageLoop()
##_thread = threading.Thread(target=cef.MessageLoop)
##
##_thread.start()
##
##_thread.join()

r.mainloop()

print('end')
问题是:

  • 我离开了cef.MessageLoop(),浏览器可以工作,但按钮不能
  • 我注释掉了cef.MessageLoop(),浏览器不工作,但是 tkinter窗口可以
  • 我想线程模块可能会有帮助,但我试过了(你可以看到注释行),但不起作用(我没有例外,但浏览器不起作用)。
    如何解决这个问题?

    Tkinter在单个线程中运行,因此当您在其中写入基本上是无限循环的内容时,您将阻止Tkinter工作。出现屏幕的唯一原因是您使用了
    update()
    ,但这并不能解决此问题

    解决方案是使用线程在单独的线程中管理MessageLoop,同时将框架传递给函数,以允许Tkinter和cef之间进行一些交互

    注意:为了更好地遵循PEP8标准,我还对您的代码进行了一些清理

    import tkinter as tk
    from tkinter import messagebox
    from cefpython3 import cefpython as cef
    import threading
    import sys
    
    
    def test_thread(frame):
        sys.excepthook = cef.ExceptHook
        window_info = cef.WindowInfo(frame.winfo_id())
        window_info.SetAsChild(frame.winfo_id(), rect)
        cef.Initialize()
        browser = cef.CreateBrowserSync(window_info, url='http://www.google.com')
        cef.MessageLoop()
    
    
    def on_closing():
        print('closing')
        root.destroy()
    
    
    root = tk.Tk()
    root.geometry('800x600')
    root.protocol('WM_DELETE_WINDOW', on_closing)
    frame = tk.Frame(root, bg='blue', height=200)
    frame2 = tk.Frame(root, bg='white', height=200)
    frame.pack(side='top', fill='x')
    frame2.pack(side='top', fill='x')
    
    tk.Button(frame2, text='Exit', command=on_closing).pack(side='left')
    tk.Button(frame2, text='Show something',
              command=lambda: messagebox.showinfo('TITLE', 'Shown something')).pack(side='right')
    
    rect = [0, 0, 800, 200]
    print('browser: ', rect[2], 'x', rect[3])
    
    thread = threading.Thread(target=test_thread, args=(frame,))
    thread.start()
    
    root.mainloop()
    
    结果:


    好吧,这是一个循环中的一个循环。你预计会发生什么?我对
    cefpython3
    了解不多,但我怀疑
    MessageLoop()
    永远不会结束,除非有人强迫循环结束,如果是这种情况(就像tkinters mainloop的情况一样),那么你将永远无法让你的tkinter与
    MessageLoop
    一起工作。您需要使用线程并在自己的线程中运行
    MessageLoop
    。可能与
    root.update
    root.idle\u update
    一起使用。您可以尝试创建自己的循环,而不是
    MessageLoop
    root.mainloop()
    而不是在关闭时使用
    g.destroy
    。还可以将键绑定到命令。因此,不要使用Lambda为消息框创建函数,而是使用
    b2绑定函数。绑定(“”,message)