tkinter- subclass of button not placing on screen from inside another class - python

I'm making a ide for brainf*ck in python using tkinter and I'm adding a recent projects section but when I'm placing the buttons they do not appear on the screen.
Here is the code for the Scene:
from tkinter import *
from tkinter import filedialog as File
import tkinter as tk
class HoverButton(tk.Button):
def __init__(self, master, **kw):
tk.Button.__init__(self, master=master, **kw)
self.defaultBackground = "#5d5d5d"
self['background'] = self.defaultBackground
self['activebackground'] = "#6d6d6d"
self.bind("<Enter>", self.on_enter)
self.bind("<Leave>", self.on_leave)
def on_enter(self, e):
self['background'] = "#6d6d6d"
def on_leave(self, e):
self['background'] = self.defaultBackground
class ProjectPage(Frame):
def __init__(self, master, projects=[]):
super().__init__(master)
self.projects = projects
self.buttons = []
self.mstr = self.master.master
self.title = "PesolIde: Projets"
self.width = 800
self.height = 500
self.color = "#4d4d4d"
self.projectFrame = tk.Frame(self.mstr,width=800,height=50,bg="#5d5d5d")
self.newProject = HoverButton(self.mstr,text="New Project", height=1, bg="#6d6d6d")
self.openProject = HoverButton(self.mstr,text="Open Project", height=1,bg="#6d6d6d", command=OpenAsk)
self.projectdisplay = tk.Frame(self.mstr, width=700, height=300, bg="#5d5d5d", highlightbackground="black", highlightthickness=1)
for i in range(len(self.projects)):
self.buttons.append(HoverButton(master, text=self.projects[i].split(':')[0], width=50, height=1))
if len(self.buttons)>=40:
break
self.loaded = False
def show(self):
self.projectFrame.place(x=0, y=0)
self.newProject.place(x=20, y=10)
self.openProject.place(x=120, y=10)
self.projectdisplay.place(x=50,y=100)
self.y = 100
print(len(self.buttons))
for i in range(len(self.buttons)):
print("placing " + str(self.buttons[i]))
self.buttons[i].place(x=50,y=100+(20*i))
self.master.set(title=self.title,width=self.width,height=self.height)
self.master.master['bg'] = self.color
def hide(self):
self.newProject.place_forget()
self.openProject.place_forget()
def load(self):
if not self.loaded:
self.newProject.place_forget()
self.openProject.place_forget()
self.loaded = True
def unload(self):
self.newProject.destroy()
self.openProject.destroy()
def OpenAsk():
name = File.askopenfilename()
and here is the code for main.py:
from tkinter import *
import src.framework.modules.Window.Window as windows
import src.framework.src.Scenes.all as Scenes
import tkinter as tk
root = tk.Tk()
window = windows.window(root, "", 800, 500)
window.place()
projects = open("projects.txt",'r').read().split("\n")
start = Scenes.ProjectPage.ProjectPage(window,projects)
start.show()
window.mainloop()
When I make a HoverButton outside the ProjectPage class in the ProjectPage file, it appears as expected but not when initialised from within the class of directly from the main file.
Here are some screenshots.
The output from running main.py:
The output from running from outside the ProjectPage class with the code on the left:

Try to insert values for relx, rely, relwidth, relheight as attributes in "place" or you can as well insert height, width as attributes for place.
Check out the documentation: https://www.tutorialspoint.com/python/tk_place.htm

Related

My tkinter window isn't showing all the elements that are present in it [duplicate]

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed last month.
I have created a window class and when it is imported into the main file it doesn't render all the objects that are associated with the main window class.
This is the code that I am using.
The window class:
from tkinter import *
base_path = "img/"
def btn_clicked():
print("Button clicked ")
def center_coordinates(screen_width:int,screen_height:int,width:int,height:int):
window_x = int((screen_height/2) - (75+(height/2)))
window_y = int((screen_width/2) - (width/2))
return f"{width}x{height}+{window_y}+{window_x}"
class scan_code_screen(Tk):
def __init__(self):
Tk.__init__(self)
self.wm_overrideredirect(False)
self.geometry(center_coordinates(self.winfo_screenwidth(),self.winfo_screenheight(),550,350))
self.title(" ")
self.iconbitmap("img\icon.ico")
self.resizable(False,False)
def window(self):
background_img = PhotoImage(file=base_path+"background.png")
bg = Label(self, image=background_img).place(x=-2,y=-2)
button_image = PhotoImage(file=base_path+"button.png")
button =Button(self,image=button_image,borderwidth=0,highlightthickness=0,command=btn_clicked,relief=FLAT)
button.place(x=210,y=253)
The main file:
from windows.scan_code import *
if __name__ == "__main__":
testObj2 = scan_code_screen()
testObj2.window()
testObj2.mainloop()
You need to keep a reference to the PhotoImage you created, it is getting garbage collected. Try something like this:
from tkinter import *
base_path = "img/"
def btn_clicked():
print("Button clicked ")
def center_coordinates(screen_width:int,screen_height:int,width:int,height:int):
window_x = int((screen_height/2) - (75+(height/2)))
window_y = int((screen_width/2) - (width/2))
return f"{width}x{height}+{window_y}+{window_x}"
class scan_code_screen(Tk):
def __init__(self):
Tk.__init__(self)
self.wm_overrideredirect(False)
self.geometry(center_coordinates(self.winfo_screenwidth(),self.winfo_screenheight(),550,350))
self.title(" ")
self.iconbitmap("img\icon.ico")
self.resizable(False,False)
def window(self):
self.background_img = PhotoImage(file=base_path+"background.png")
bg = Label(self, image=self.background_img).place(x=-2,y=-2)
self.button_image = PhotoImage(file=base_path+"button.png")
button =Button(self,image=self.button_image,borderwidth=0,highlightthickness=0,command=btn_clicked,relief=FLAT)
button.place(x=210,y=253)
The center_coordinates and btn_clicked should be inside class module. Use self for all widgets.
Btw, I didn't not add photo. I leave it up to you.
I modified code:
from tkinter import *
base_path = "img/"
class scan_code_screen(Tk):
def __init__(self):
Tk.__init__(self)
self.wm_overrideredirect(False)
self.geometry(self.center_coordinates(self.winfo_screenwidth(),self.winfo_screenheight(),550,350))
self.title("icon.ico")
self.iconbitmap("img\icon.ico")
self.resizable(False,False)
def center_coordinates(self, screen_width:int,screen_height:int,width:int,height:int):
window_x = int((screen_height/2) - (75+(height/2)))
window_y = int((screen_width/2) - (width/2))
return f"{width}x{height}+{window_y}+{window_x}"
def btn_clicked(self):
print("Button clicked ")
self.bg.configure(text="Button clicked ")
def window(self):
background_img = PhotoImage(file=base_path+"background.png")
self.bg = Label(self, text='Text')
self.bg.place(x=-2,y=-2)
button_image = PhotoImage(file=base_path+"button.png")
self.button =Button(self, text='button',
borderwidth=0,
highlightthickness=0,
command=self.btn_clicked,
relief=FLAT)
self.button.place(x=210,y=253)
if __name__ == "__main__":
testObj2 = scan_code_screen()
testObj2.window()
testObj2.mainloop()
Output before:
Output after:

in a class, how can I call a method onto an object that already has a class?

I'm working with tkinter at the moment, ive needed to call a method onto an object that has a Tk() class. im trying to call the method not in the Tk() class, but from the class ive already created, which the tkinter object is in already.
Ive tried to call .Format() onto l_label, but i think it is trying to find an attribute or method within the Label class from tkinter, because it returns: AttributeError: 'Label' object has no attribute 'Format'
Any thoughts?
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog
thing = Tk()
class App():
def __init__(self, master, _title, back='white'):
self.master = master
self._title = _title
self.back = back
self.master.title(self._title)
self.master.configure(background=back)
def label(self, _text, back='white', w=1, h=1):
self.back = back
self.w = w
self.h = h
self._text = _text
l_label = Label(self.master, text=self._text, bg=self.back, width=self.w, height=self.h)
return l_label
def Format(self, l_label, Row=1, Column=1):
self.Row = Row
self.Column = Column
l_label.grid(row=Row, column=Column)
app = App(thing, 'hello world')
label = app.label('this is a text boc', 'white').Format()
thing.mainloop()
What you are looking for is method chaining. In order for that to work your function needs to return self
class App(object):
def __init__(self, master, _title, back='white'):
self.master = master
self._title = _title
self.back = back
self.master.title(self._title)
self.master.configure(background=back)
self.w = None
self.h = None
self._text = None
self.Row = None
self.Column = None
self.l_label = None
def label(self, _text, back='white', w=1, h=1):
self.back = back
self.w = w
self.h = h
self._text = _text
self.l_label = Label(self.master, text=_text, bg=back, width=w, height=h)
return self
def Format(self, Row=1, Column=1):
self.Row = Row
self.Column = Column
self.l_label.grid(row=Row, column=Column)
return self
Notice how I removed the l_label from Format and assigned Label(self.master, text=_text, bg=back, width=w, height=h) to self.l_label
Then you would be able to do:
thing = Tk()
app = App(thing, 'hello world')
label = app.label('this is a text box', 'white', 15, 15).Format()
thing.mainloop()

communication between tkinter toplevels

I'm working on a little project and made a little on-screen keyboard as a tkinter Toplevel
my application is buildt like this:
Root-Window (Tk-Widget)
input 1 (Entry-Widget)
input 2 (Entry-Widget)
input 3 (Text-Widget)
on_screen-keyboard (Toplevel-Widget)
the Toplevel-Widget contains Buttons, with callbacks that should enter text in the entries (just like keyboard-Buttons)
What I want is a communication between children of the keyboard/the keyboard and the last active input-Widget. My Problem is, that I don't know, how to say the keyboard, to which input-Widget it should send the message.
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.active_input = tk.Variable(value=None)
ttk.Button(self, text="show Keyboard", command=lambda: Keyboard(self)).pack()
self.text = tk.StringVar(value="")
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", lambda e: self.active_input.set(self.input1))
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", lambda e: self.active_input.set(self.input2))
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", lambda e: self.active_input.set(self.input3))
self.input1.pack()
self.input3.pack()
self.input2.pack()
class Keyboard(tk.Toplevel):
OPENED = False
NAME = "- Keyboard -"
NUM = [{"text":"1", "width":1},
{"text":"2", "width":1},
{"text":"3", "width":2}]
CHAR= [{"text":"A", "width":1},
{"text":"B", "width":1},
{"text":"C", "width":2}]
def __init__(self, master):
if not Keyboard.OPENED:
Keyboard.OPENED = True
print("keyboard opened!")
self.master = master
tk.Toplevel.__init__(self, master)
self.title(self.NAME)
self.protocol("WM_DELETE_WINDOW", self.close)
self.keyb_nb = ttk.Notebook(self)
self.keyb_nb.pack()
self.num_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.num_tab, Keyboard.NUM,2)
self.keyb_nb.add(self.num_tab, text="123")
self.char_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.char_tab, Keyboard.CHAR, 2)
self.keyb_nb.add(self.char_tab, text="ABC")
def createPad(self, master, pad:list, max_col):
self.co_count = 0
self.ro = 1
for button in pad:
button["id"] = ttk.Button(master, width=6*button["width"], text=button["text"], command=self.bclicked(button))
if self.co_count >= max_col:
self.ro = self.ro + 1
self.co_count = 0
button["id"].grid(row=self.ro, columnspan=button["width"], column=self.co_count)
self.co_count = self.co_count+button["width"]
def bclicked(self, button:dict):
"""
reciver = self.master.active_input #I think the Problem here is, that the variable contains a string, not a widget
reciever.focus_force()
reciever.insert(index=tk.INSERT, string=button["text"])
"""
pass
def close(self):
Keyboard.OPENED = False
self.destroy()
print("keyboard closed!")
root = MainWindow()
root.mainloop()
Here the init of the Mainwindow and the bclicked of the Keyboard class are important...
the code is debug-ready
I would prefer a solution, similar to the communication in the internet (sender=button, receiver-id, message), but very welcome every working solution
btw: I'm also looking for a solution, how I don't have to force the input to focus and the Toplevel stays an the highest layer of the screen (that if I focus the Tk-Widget/one of the inputs/the button, the keyboard will stay in front of it)
SUMMARY: how do I find out, which of the 3 input-widgets was active at last, when the keyboard-toplevel has already the focus?
I may made more changes than needed, but mainly focus on the method keyboard_triger() and pass_key_to_master(), this two use the idea that the variable master implements, having access to call methods out of scope.
Olso the method set_focused_object() stores a reference to the last object beeng focused, note than it stores the widget and not the event, it's easyer than searching each time the object
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def keyboard_triger(self, key):
# to identify wath object is just use
# isinstance(self.active_input, ttk.Entry)
self.active_input.insert(tk.END, key)
def new_keyboard(self):
Keyboard(self)
def set_focused_object(self, event):
self.active_input = event.widget
def __init__(self):
tk.Tk.__init__(self)
self.active_input = None
ttk.Button(self, text="Show Keyboard", command=self.new_keyboard).pack()
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", self.set_focused_object)
self.input1.pack()
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", self.set_focused_object)
self.input2.pack()
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", self.set_focused_object)
self.input3.pack()
class Keyboard(tk.Toplevel):
def pass_key_to_master(self, key):
self.master.keyboard_triger(key)
def __init__(self, master):
tk.Toplevel.__init__(self, master)
self.master = master
self.title('Keyboard')
# this way of agruping keys stores the kwags
# of the drawing method
keys = {
'A': {'x': 0, 'y': 0},
'B': {'x': 20, 'y': 20},
'C': {'x': 50, 'y': 50}
}
# expected structure
# {string key: reference to the button}
self.buttons = {}
for i in keys:
self.buttons[i] = tk.Button( # i=i is required to make a instance
self, text=i, command=lambda i=i: self.pass_key_to_master(i)
)
self.buttons[i].place(**keys[i])
if __name__ == '__main__':
root = MainWindow()
root.mainloop()
Your code maybe could have a better construction.(But I didn't revise your code construction.)
Followed by your code,I use a global variable.And fix some errors in your code.And it could work normally in my computer.
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.active_input = tk.Variable(value=None)
ttk.Button(self, text="show Keyboard", command=lambda: Keyboard(self)).pack()
global focusedWidget
focusedWidget = None
self.text = tk.StringVar(value="")
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", self.getFocusWidget)
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", self.getFocusWidget)
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", self.getFocusWidget)
self.input1.pack()
self.input3.pack()
self.input2.pack()
def getFocusWidget(self,event): # this function could be a static function
global focusedWidget
focusedWidget = event.widget
class Keyboard(tk.Toplevel):
OPENED = False
NAME = "- Keyboard -"
NUM = [{"text":"1", "width":1},
{"text":"2", "width":1},
{"text":"3", "width":2}]
CHAR= [{"text":"A", "width":1},
{"text":"B", "width":1},
{"text":"C", "width":2}]
def __init__(self, master):
if not Keyboard.OPENED:
Keyboard.OPENED = True
print("keyboard opened!")
self.master = master
tk.Toplevel.__init__(self, master)
self.title(self.NAME)
self.protocol("WM_DELETE_WINDOW", self.close)
self.keyb_nb = ttk.Notebook(self)
self.keyb_nb.pack()
self.num_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.num_tab, Keyboard.NUM,2)
self.keyb_nb.add(self.num_tab, text="123")
self.char_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.char_tab, Keyboard.CHAR, 2)
self.keyb_nb.add(self.char_tab, text="ABC")
def createPad(self, master, pad:list, max_col):
self.co_count = 0
self.ro = 1
for button in pad:
button["id"] = ttk.Button(master, width=6*button["width"], text=button["text"], command=lambda button=button:self.bclicked(button)) # this lambda expression has some errors.
if self.co_count >= max_col:
self.ro = self.ro + 1
self.co_count = 0
button["id"].grid(row=self.ro, columnspan=button["width"], column=self.co_count)
self.co_count = self.co_count+button["width"]
def bclicked(self, button:dict):
global focusedWidget
"""
reciver = self.master.active_input #I think the Problem here is, that the variable contains a string, not a widget
reciever.focus_force()
reciever.insert(index=tk.INSERT, string=button["text"])
"""
if not focusedWidget: # If user hasn't click a entry or text widget.
print("Please select a entry or text")
return
if focusedWidget.widgetName=='ttk::entry': # use if statement to check the type of selected entry.
focusedWidget.insert(index=tk.INSERT,string=button["text"])
else:
focusedWidget.insert("end",button["text"])
def close(self):
Keyboard.OPENED = False
self.destroy()
print("keyboard closed!")
root = MainWindow()
root.mainloop()

Python tkinter threading and window refresh

I'm using python and tkinter to build a visualization tool that can refresh and visualize an updating object. Right now, the object can't change because the threading is not working. Any help or general knowledge would be appreciated. I'm relatively new to threading and tkinter.
example object I want to ingest
class color1:
def __init__(self, color):
self.color = color
def change_col(self, new_color):
self.color = new_color
def pass_col(self):
return(self)
my visualization code
class my_visual(threading.Thread):
def __init__(self, col1):
threading.Thread.__init__(self)
self.start()
self.col1 = col1
def viz(self):
self.root = Tk()
btn1 = Button(self.root, text = 'Refresh', command = self.refresh)
btn1.pack()
frame = Frame(self.root, width = 100, height = 100, bg = self.col1.color)
frame.pack()
btn2 = Button(self.root, text = 'Close', command = self.exit)
btn2.pack()
self.root.mainloop()
def refresh(self):
self.root.quit()
self.root.destroy()
self.col1 = self.col1.pass_col()
self.viz()
def exit(self):
self.root.quit()
self.root.destroy()
Code that works
c = color1('RED')
test = my_visual(c)
test.viz()
Code that doesn't work
In this version, the refresh works, but the threading doesn't. When the threading is working, the refresh won't pick up that the object has changed.
c.change_col('BLUE')
If you extend the threading.Thread class you need to override the run() method with your custom functionality. With no run method, the thread dies immediately. You can test whether a thread is alive with my_visual.is_alive().
The problem is that your test.viz() is an infinite loop because of self.root.mainloop(), so you cannot do anything once you called that function. The solution is to use a thread for test.viz(), and your thread for the class my_visual is no more necessary.
I added a time.sleep of 2 seconds before the refresh makes it blue, otherwise the color is blue at beginning.
Here you go :
import threading
from tkinter import *
import time
class color1:
def __init__(self, color):
self.color = color
def change_col(self, new_color):
self.color = new_color
def pass_col(self):
return(self)
class my_visual():
def __init__(self, col1):
self.col1 = col1
def viz(self):
self.root = Tk()
btn1 = Button(self.root, text = 'Refresh', command = self.refresh)
btn1.pack()
frame = Frame(self.root, width = 100, height = 100, bg = self.col1.color)
frame.pack()
btn2 = Button(self.root, text = 'Close', command = self.exit)
btn2.pack()
self.root.mainloop()
def refresh(self):
self.root.quit()
self.root.destroy()
self.col1 = self.col1.pass_col()
print("self.col1", self.col1, self.col1.color)
self.viz()
def exit(self):
self.root.quit()
self.root.destroy()
c = color1('RED')
test = my_visual(c)
t2 = threading.Thread(target = test.viz)
t2.start()
time.sleep(2)
print('Now you can change to blue when refreshing')
c.change_col('BLUE')

python tkinter with a simple web wrapper

I am writing a simple python program with a UI, and i can't find out how to put a web page inside the program. I tried searching on Google, but i can't find any simple implementations.
Any links would be great. Just to recap, i just want a simple GUI python program with a webpage embeded inside it, basically like this:
# File: hello1.py
from Tkinter import *
root = Tk()
w = Label(root, text="This is where i was the web page embeded")
w.pack()
root.mainloop()
Thanks,
EDIT:
Solved the problem, used webkit
#!/usr/bin/env python
import gtk
import webkit
import gobject
gobject.threads_init()
win = gtk.Window()
bro = webkit.WebView()
bro.open("http://www.google.com")
win.add(bro)
win.show_all()
gtk.main()
Jack
You can both embed HTML and open full web-pages (with CSS and javascript even) in tkinter. With the cefpython module you can embed a full-blown Chromium browser in a tk window.
from cefpython3 import cefpython as cef
import ctypes
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import sys
import platform
import logging as _logging
# Fix for PyCharm hints warnings
WindowUtils = cef.WindowUtils()
# Platforms
WINDOWS = (platform.system() == "Windows")
LINUX = (platform.system() == "Linux")
MAC = (platform.system() == "Darwin")
# Globals
logger = _logging.getLogger("tkinter_.py")
class MainFrame(tk.Frame):
def __init__(self, root):
self.browser_frame = None
self.navigation_bar = None
# Root
root.geometry("900x640")
tk.Grid.rowconfigure(root, 0, weight=1)
tk.Grid.columnconfigure(root, 0, weight=1)
# MainFrame
tk.Frame.__init__(self, root)
self.master.title("Tkinter example")
self.master.protocol("WM_DELETE_WINDOW", self.on_close)
self.master.bind("<Configure>", self.on_root_configure)
self.bind("<Configure>", self.on_configure)
self.bind("<FocusIn>", self.on_focus_in)
self.bind("<FocusOut>", self.on_focus_out)
# NavigationBar
self.navigation_bar = NavigationBar(self)
self.navigation_bar.grid(row=0, column=0,
sticky=(tk.N + tk.S + tk.E + tk.W))
tk.Grid.rowconfigure(self, 0, weight=0)
tk.Grid.columnconfigure(self, 0, weight=0)
# BrowserFrame
self.browser_frame = BrowserFrame(self, self.navigation_bar)
self.browser_frame.grid(row=1, column=0,
sticky=(tk.N + tk.S + tk.E + tk.W))
tk.Grid.rowconfigure(self, 1, weight=1)
tk.Grid.columnconfigure(self, 0, weight=1)
# Pack MainFrame
self.pack(fill=tk.BOTH, expand=tk.YES)
def on_root_configure(self, _):
logger.debug("MainFrame.on_root_configure")
if self.browser_frame:
self.browser_frame.on_root_configure()
def on_configure(self, event):
logger.debug("MainFrame.on_configure")
if self.browser_frame:
width = event.width
height = event.height
if self.navigation_bar:
height = height - self.navigation_bar.winfo_height()
self.browser_frame.on_mainframe_configure(width, height)
def on_focus_in(self, _):
logger.debug("MainFrame.on_focus_in")
def on_focus_out(self, _):
logger.debug("MainFrame.on_focus_out")
def on_close(self):
if self.browser_frame:
self.browser_frame.on_root_close()
self.master.destroy()
def get_browser(self):
if self.browser_frame:
return self.browser_frame.browser
return None
def get_browser_frame(self):
if self.browser_frame:
return self.browser_frame
return None
class BrowserFrame(tk.Frame):
def __init__(self, master, navigation_bar=None):
self.navigation_bar = navigation_bar
self.closing = False
self.browser = None
tk.Frame.__init__(self, master)
self.bind("<FocusIn>", self.on_focus_in)
self.bind("<FocusOut>", self.on_focus_out)
self.bind("<Configure>", self.on_configure)
self.focus_set()
def embed_browser(self):
window_info = cef.WindowInfo()
rect = [0, 0, self.winfo_width(), self.winfo_height()]
window_info.SetAsChild(self.get_window_handle(), rect)
self.browser = cef.CreateBrowserSync(window_info,
url="http://www.google.com") #todo
assert self.browser
self.browser.SetClientHandler(LoadHandler(self))
self.browser.SetClientHandler(FocusHandler(self))
self.message_loop_work()
def get_window_handle(self):
if self.winfo_id() > 0:
return self.winfo_id()
elif MAC:
from AppKit import NSApp
import objc
return objc.pyobjc_id(NSApp.windows()[-1].contentView())
else:
raise Exception("Couldn't obtain window handle")
def message_loop_work(self):
cef.MessageLoopWork()
self.after(10, self.message_loop_work)
def on_configure(self, _):
if not self.browser:
self.embed_browser()
def on_root_configure(self):
# Root <Configure> event will be called when top window is moved
if self.browser:
self.browser.NotifyMoveOrResizeStarted()
def on_mainframe_configure(self, width, height):
if self.browser:
if WINDOWS:
ctypes.windll.user32.SetWindowPos(
self.browser.GetWindowHandle(), 0,
0, 0, width, height, 0x0002)
elif LINUX:
self.browser.SetBounds(0, 0, width, height)
self.browser.NotifyMoveOrResizeStarted()
def on_focus_in(self, _):
logger.debug("BrowserFrame.on_focus_in")
if self.browser:
self.browser.SetFocus(True)
def on_focus_out(self, _):
logger.debug("BrowserFrame.on_focus_out")
if self.browser:
self.browser.SetFocus(False)
def on_root_close(self):
if self.browser:
self.browser.CloseBrowser(True)
self.clear_browser_references()
self.destroy()
def clear_browser_references(self):
self.browser = None
class LoadHandler(object):
def __init__(self, browser_frame):
self.browser_frame = browser_frame
def OnLoadStart(self, browser, **_):
if self.browser_frame.master.navigation_bar:
self.browser_frame.master.navigation_bar.set_url(browser.GetUrl())
class FocusHandler(object):
def __init__(self, browser_frame):
self.browser_frame = browser_frame
def OnTakeFocus(self, next_component, **_):
logger.debug("FocusHandler.OnTakeFocus, next={next}"
.format(next=next_component))
def OnSetFocus(self, source, **_):
logger.debug("FocusHandler.OnSetFocus, source={source}"
.format(source=source))
return False
def OnGotFocus(self, **_):
"""Fix CEF focus issues (#255). Call browser frame's focus_set
to get rid of type cursor in url entry widget."""
logger.debug("FocusHandler.OnGotFocus")
self.browser_frame.focus_set()
class NavigationBar(tk.Frame):
def __init__(self, master):
self.back_state = tk.NONE
self.forward_state = tk.NONE
self.back_image = None
self.forward_image = None
self.reload_image = None
tk.Frame.__init__(self, master)
# Back button
back = b'iVBORw0KGgoAAAANSUhEUgAAAGAAAABgBAMAAAAQtmoLAAAAKlBMVEUAAAAyMjIzMzMzMzMyMjIzMzMxMTEzMzMtLS0zMzMkJCQyMjIrKysxMTExeYOJAAAADnRSTlMAgH3/cGlU1BHPDsoMWDQYbKYAAACNSURBVHgB7deBBYBAAIXha4YWaIdXJYlGaJwAzRFojhMarQnO+eWg3g9AvijnXXDZnKuawKpbCEgLA6QOAtLKAKmHgDYIDLuBDDBS4KDA+TsgQmC6IXAZyADpEkA6CogC/AH+SpQIlIAf7v2vYSIGfJBR4ihFmNjx+KHE8AliLjlD6dAFUxqMdX4dcM49/KeCIizV7gUAAAAASUVORK5CYII='
self.back_image = tk.PhotoImage(data=back)
self.back_image = self.back_image.zoom(25).subsample(100)
self.back_button = tk.Button(self, image=self.back_image,command=self.go_back)
self.back_button.grid(row=0, column=0)
# Forward button
forward = b'iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAA1UlEQVR4Ae3cAQbCYBzG4Q6QiI4wYIbtPU1HCAgQSOcLgtBtamHQAb5/43noAu8Pmu37NgAAAAAAAAAAAC0luU7TdNuUMP4lyfv7E6GxefDzMr4IheOL0FiS0zK2CI2N43hcRhahQJJDkqcIhYZh2IsgAiKIgAgi8BPhURiBrut2IoiACCIgggj8WQQR5mHvhRHo+35bEAERBMD4xl8V4/v7iQcw42N842N8L+XxWYrxMb7xMb5TMsZ/GX+Nh/RwTNVBbVxV4LIOXFcDAAAAAAAAAADwAephJFWvaMW3AAAAAElFTkSuQmCC'
self.forward_image = tk.PhotoImage(data=forward)
self.forward_image = self.forward_image.zoom(25).subsample(100)
self.forward_button = tk.Button(self, image=self.forward_image,command=self.go_forward)
self.forward_button.grid(row=0, column=1)
# Reload button
refresh = b'iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAQAAABIkb+zAAADwklEQVR4Ae2aY5jGVhCFZ+3a9iK7+XLPqW23v2rbtm3btm3btm3bbWpN8i0nt83z3Hd+Z+ac6GokEAgEAoFAIBAIBKyIGjkr1sJBuIoP8zV8w6/4Oh/GVTgIayWzRI0yJLiT+COZGjvzZnzLtJ/4Grdg+3gcGRTchqn4oG90bsvHmQ46vsPZycyDke/BgJsUR/IrpkMP3M0lpVaqgE2YFm+ghusNUbyOp9081eQXbqAyIW5hahBXurGz8gs3wOX4KVOjeBuUv+C6TIs2UMfjmVoGvnXLKPnFGWArru9Xzgs8kxu5mX7/53d2xJ2cCytwW57Jl/qx8BO3VfKLMTBVE++tfh9xUtwp/cA+nMbvq15/A9PCDfC8KsW/4IG948og6J0Yh/Pr/CyFG3Bb55b5EvtGY8gQiCfitfRvAAvgp5wiz7hJh/cfw8deDVSmwefZArg8bpNhEo2HW/wZqMGjOQWOkloZAWzgeZ4MuNVz0p9gcFtO8mIgauf72SmA1MoIUfKLM4Dts59u1C4jhEd5+oijdn6iPt1v2GUl34MBbKrTYhdD+R4MPKLSvj5Vk5V8DwZcTybt5jIicDBTjwawh3p9Pu/sMJTvwcD9evCyk+/BQDKanv9UnJ18DwawmEr5gQwb7s3Uv4Gt1BdwgaV8DwZ4gkq5haV8DwZw678TuoWkXOAp9QpNJeWCr6uHOpaUC719NVGLlAu9bo0aS/4KdY0p5YJPl/wjxm3/NpAsLOUCJ6onsKWUC26jfqPnSblwi2cmc+UiatfTaVeRcoH71FdwpBQETlNP+3YRD0tKK9wE/L6QH0Yl0lNct5kUAA7SdfqmEBvwqPW2Su5O9Reqyh1iBTbR9wY7izE8S9dwq4sVE7XoKR2+iTvFkGTm7NGr6bQR25lu7iriNj6Tyb+u9Wjwni6Bq6RWLKjLObZ90Xza7lYzO+BQ8JRsZjePmFPDh+2PmKQWh+RkvViKIO7MO+TjFXHbCHb9bszJ+KlqiLLDLWR5zOqmxStMs+GWEU3RB934AvtyrCH+mPfDj7m5DpJiwTnVWw04/uDEc2V179WfrVCmasL9w232YEMyH07ml0yryWeDGGDSboMZf/+TT9bM8dGdzMKNeIWSruM8qRdP1OmVskEcJTXiEyzFT8zEf+1WE//0TmzU9PdgMrX8R9Rg/RG2Xb7lVjN6dfw3vvJTt4PBVrFZ6/FjQxL/KrY32GX11PytpR+ZzCe1/+P2+2SWP9rvH/qt/f73lsoXcSF3xGLxRGJEIBAIBAKBQCAQCPwM9/tgs3UybYkAAAAASUVORK5CYII='
self.reload_image = tk.PhotoImage(data=refresh)
self.reload_image = self.reload_image.zoom(25).subsample(100)
self.reload_button = tk.Button(self, image=self.reload_image,command=self.reload)
self.reload_button.grid(row=0, column=2)
# Url entry
self.url_entry = tk.Entry(self)
tk.Grid.rowconfigure(self, 0, weight=100)
tk.Grid.columnconfigure(self, 3, weight=100)
# Update state of buttons
self.update_state()
def go_back(self):
if self.master.get_browser():
self.master.get_browser().GoBack()
def go_forward(self):
if self.master.get_browser():
self.master.get_browser().GoForward()
def reload(self):
if self.master.get_browser():
self.master.get_browser().Reload()
def set_url(self, url):
self.url_entry.delete(0, tk.END)
self.url_entry.insert(0, url)
def on_url_focus_in(self, _):
logger.debug("NavigationBar.on_url_focus_in")
def on_url_focus_out(self, _):
logger.debug("NavigationBar.on_url_focus_out")
def on_load_url(self, _):
if self.master.get_browser():
self.master.get_browser().StopLoad()
self.master.get_browser().LoadUrl(self.url_entry.get())
def on_button1(self, _):
"""Fix CEF focus issues (#255). See also FocusHandler.OnGotFocus."""
logger.debug("NavigationBar.on_button1")
self.master.master.focus_force()
def update_state(self):
browser = self.master.get_browser()
if not browser:
if self.back_state != tk.DISABLED:
self.back_button.config(state=tk.DISABLED)
self.back_state = tk.DISABLED
if self.forward_state != tk.DISABLED:
self.forward_button.config(state=tk.DISABLED)
self.forward_state = tk.DISABLED
self.after(100, self.update_state)
return
if browser.CanGoBack():
if self.back_state != tk.NORMAL:
self.back_button.config(state=tk.NORMAL)
self.back_state = tk.NORMAL
else:
if self.back_state != tk.DISABLED:
self.back_button.config(state=tk.DISABLED)
self.back_state = tk.DISABLED
if browser.CanGoForward():
if self.forward_state != tk.NORMAL:
self.forward_button.config(state=tk.NORMAL)
self.forward_state = tk.NORMAL
else:
if self.forward_state != tk.DISABLED:
self.forward_button.config(state=tk.DISABLED)
self.forward_state = tk.DISABLED
self.after(100, self.update_state)
if __name__ == '__main__':
logger.setLevel(_logging.INFO)
stream_handler = _logging.StreamHandler()
formatter = _logging.Formatter("[%(filename)s] %(message)s")
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)
logger.info("CEF Python {ver}".format(ver=cef.__version__))
logger.info("Python {ver} {arch}".format(
ver=platform.python_version(), arch=platform.architecture()[0]))
logger.info("Tk {ver}".format(ver=tk.Tcl().eval('info patchlevel')))
assert cef.__version__ >= "55.3", "CEF Python v55.3+ required to run this"
sys.excepthook = cef.ExceptHook # To shutdown all CEF processes on error
root = tk.Tk()
app = MainFrame(root)
# Tk must be initialized before CEF otherwise fatal error (Issue #306)
cef.Initialize()
app.mainloop()
cef.Shutdown()
Try using Tkinterweb!
https://pypi.org/project/tkinterweb/
Demo code:
from tkinterweb import HtmlFrame #import the HTML browser
try:
import tkinter as tk #python3
except ImportError:
import Tkinter as tk #python2
root = tk.Tk() #create the tkinter window
frame = HtmlFrame(root) #create HTML browser
frame.load_website("http://google.com") #load a website
frame.pack(fill="both", expand=True) #attach the HtmlFrame widget to the parent window
root.mainloop()
How about using pywebview ?
It doesn't run in tkinter. but it is simple.
https://pypi.org/project/pywebview/
import webview
webview.create_window('Hello world', 'https://pywebview.flowrl.com/hello')
webview.start()
the simple answer will be is stop wasting your time please learn electron js for making apps b/c after this when you try to compile your tkinter project will be so ugly so learn js then electron my suggestion

Categories

Resources