3

I'm working at a project in Python3 in which i have both tkinter and a frame in tkinter with cef browser. This is the code.

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')

The problem is:

  1. I leave cef.MessageLoop() and the browser works but buttons don't.
  2. I comment out cef.MessageLoop() and the browser doesn't work but tkinter window does.

I was thinking that maybe threading module wuold help but i tried (you can see the commented lines) and doesn't work (i get no exceptions but browser don't work). How can i sort this out?

Zeno Dalla Valle
  • 957
  • 5
  • 16
  • 1
    Well its a loop inside of a loop. What do you expect to happen? I do not know much about `cefpython3` but I suspect the `MessageLoop()` is never ending until someone forces the loop to end and if this is the case (as it is the case for tkinters mainloop) then you will never get your tkinter to work with `MessageLoop` being inside of it. You will need to use threading and run `MessageLoop` in its own thread. – Mike - SMT Sep 17 '19 at 12:48
  • maybe using [MessageLoopWork](https://github.com/cztomczak/cefpython/blob/master/api/cefpython.md#messageloopwork) with `root.update`, `root.idle_update` you could try to create own loop instead of `MessageLoop` and `root.mainloop()` – furas Sep 17 '19 at 13:48
  • instead of using on closing you can use`g.destroy`. Also you can bind keys to the command. So instead of using Lambda create a function to your message box bind the function with `b2.bind('', message)` – Barb Sep 17 '19 at 14:33

1 Answers1

5

Tkinter runs in a single thread so when you write what is basically an infinite loop inside of it then you will block Tkinter from working. The only reason you screen is coming up at all is because you used update() but that will not fix the issue here.

The solution will be to use threading to manage the MessageLoop in a separate thread while also passing the frame to the function to allow for some interaction between Tkinter and cef.

Note: I also cleaned up your code a bit to better follow PEP8 standards.

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()

Results:

enter image description here

Mike - SMT
  • 14,784
  • 4
  • 35
  • 79