Here is my sample code. How do I get the html source code of the current page. It only prints 'GString at 0x8875130' . How to convert it to real text contains html?
from gi.repository import WebKit
from gi.repository import Gtk, Gdk
def get_source(webobj, frame):
print "loading..."
x = web.get_main_frame().get_data_source().get_data()
print x
win = Gtk.Window()
web = WebKit.WebView()
web.open("http://google.com")
web.connect("load-finished", get_source)
win.add(web)
win.show_all()
Gtk.main()
print x.str
Data is available as .str member of GLib.String object. For further details try help(GLib.String) on python prompt after importing libraries.
#Before you can use the require_version() method from gi, you need to import the gi module.
import gi
#Specify versions to import from the repository.
gi.require_version('Gtk','3.0')
gi.require_version('WebKit','3.0')
#Import the modules that will give us a Graphical User Interface (GUI) and a WebKit Browser.
from gi.repository import Gtk,WebKit
#Define your function to handle the WebKit's "load-finished" event. The webobj is a reference to the WebKit that triggered the event. The frame is which frame triggered the event (useful if the loaded page has multiple frames like a frameset.
def ShowSource(webobj,frame):
#What you have printed is what results from this line. This line returns a reference to an object, so when you print it's return value, a description is all Python knows to print.
SourceCodeStringObject=frame.get_data_source().get_data()
#You can get the text the object is carrying from it's "str" member property like I do below.
SourceCodeStringText=SourceCodeStringObject.str
#Send the source code string text to the output stream.
print(SourceCodeStringText)
#Create Window object.
Window=Gtk.Window()
#Set the text to display in the window's caption.
Window.set_title("Test of Python GTK and WebKit")
#Set the starting window size in pixels.
Window.set_default_size(480,320)
#Create the WebView object.
WebBrowser=WebKit.WebView()
#Tell the WebView object to load a website.
WebBrowser.open("https://stackoverflow.com/questions/24119290/pygtk-webkit-get-source-html")
#Set the event handler for the WebView's "load-finished" event to the function we have above.
WebBrowser.connect("load-finished",ShowSource)
#Add the WebView to the window.
Window.add(WebBrowser)
#Set the handler of the window closing to cause GTK to exit. Without this, GTK will hang when it quits, because it's main loop that we start later will still be running. Gtk.main_quit will stop the main loop for GTK.
Window.connect("delete-event",Gtk.main_quit)
#Display the window.
Window.show_all()
#Start GTK's main loop.
Gtk.main()
This way works for me.
#!/usr/bin/env python
import webkit, gtk
def get_source(webobj, frame):
print "loading..."
x = web.get_main_frame().get_data_source().get_data()
print x
win = gtk.Window()
win.set_position(gtk.WIN_POS_CENTER_ALWAYS)
win.resize(1024,768)
win.connect('destroy', lambda w: gtk.main_quit())
win.set_title('Titulo')
vbox = gtk.VBox(spacing=5)
vbox.set_border_width(5)
web = webkit.WebView()
vbox.pack_start(web, fill=True, expand=True)
web = webkit.WebView()
web.open("http://www.google.co.ve")
web.connect("load-finished", get_source)
browser_settings = web.get_settings()
browser_settings.set_property('user-agent', 'Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/31.0')
browser_settings.set_property('enable-default-context-menu', True)
browser_settings.set_property('enable-accelerated-compositing', True)
browser_settings.set_property('enable-file-access-from-file-uris', True)
web.set_settings(browser_settings)
win.add(web)
win.show_all()
gtk.main()
Related
I'm trying to port a program I made with pygtk, it's a popup menu launched via global shortcut (using keybinder) to run specific programs and commands. There is no main window in this program, the point is have a simple, fast and light "launcher" available anywhere, whenever I need it.
The old menu.popup used to work even when using 0 as event.time (since keybinder doesn't give an event I'd request a time for), but now I'm getting this error:
Warning: The property GtkStatusIcon:stock is deprecated and shouldn't be used anymore. It will be removed in a future version.
self.icon.new_from_stock(Gtk.STOCK_OPEN)
This is an example I made up to show the problem:
from gi.repository import Gtk, Gdk
from gi.repository import Keybinder
menu_shortcut = "<Super>m"
class TestMenu:
def __init__(self):
self.menu = Gtk.Menu()
item = Gtk.MenuItem('various items')
self.menu.add(item)
item = Gtk.MenuItem('Quit')
item.connect('activate', Gtk.main_quit)
self.menu.append(item)
self.menu.show_all()
self.icon = Gtk.StatusIcon()
self.icon.new_from_stock(Gtk.STOCK_OPEN)
self.icon.set_tooltip_text('MyMenu')
self.icon.connect('popup-menu', self.popup, self.menu)
Keybinder.init()
Keybinder.bind(menu_shortcut, self.popup, 0, 0, self)
def popup(self, widget, button, time, menu):
self.menu.popup(None, None, None, None, button, time)
menu = TestMenu()
Gtk.main()
With this example I'm able to click the status icon and get the menu, but the keyboard shortcut just gives me the aforementioned error.
Note: the stock icon doesn't work, I'm still learning the new API.
I have two callbacks installed for the clicked signal on the done button. Is there a way to take out (not execute) one of them e.g.
import threading
import time
from gi.repository import Gtk, GLib
class Test():
def __init__(self):
win = Gtk.Window()
win.set_title("XYZ")
win.set_border_width(10)
box = Gtk.VBox(spacing=10)
win.add(box)
done_button = Gtk.Button(label="DONE")
done_button.connect("clicked", self.callback1)
#remove callback ??? callback1 should not be called when button is clicked.
done_button.connect("clicked", self.callback2)
box.pack_end(done_button, False, False, 0)
win.show_all()
win.maximize()
win.connect("delete-event", Gtk.main_quit)
def callback1(self, widget):
print "callback1"
def callback2(self, widget):
print "callback2"
if __name__ == '__main__':
test = Test()
Gtk.main()
What can be done to remove callback1.
you need to get the id of the signal in order to be able to disconnect it, so change the connect to:
b_id = done_button.connect("clicked", self.callback1)
and then use the disconnect function of the GObject module:
GObject.signal_handler_disconnect(done_button, b_id)
or as suggested by elya5 (so you don't even have to import GObject):
done_button.disconnect(b_id)
Remember to import the GObject module first (not GLib)
from gi.repository import Gtk, GObject
see python-gtk-3-tutorial.readthedocs.io
If you have lost the “handler_id” for some reason (for example the handlers were installed using Gtk.Builder.connect_signals()), you can still disconnect a specific callback using the function disconnect_by_func():
widget.disconnect_by_func(callback)
Just as some history, I have been using python for about 5 years now and have finally decided to make my first gui app in Glade.
I started with something basic, I have a button, a Gtkentry and gtktextview
This is what I am trying to accomplish:
on button press, take from the text from gtk.entry and have it appended to the gtk.textview
now the main problem I have is that I can not find descent documentation for how to use the widgets, and the examples I find on the Internet reference both a builder variation as well as another variation of glade project which I can only assume has been discontinued. I would like to learn how builder fits into the python / glade collaboration.
my code so far:
import gtk
import pygtk
def onDeleteWindow(self, *args):
Gtk.main_quit(*args)
def hello(button):
text_buffer.set_text(txtinput.get_text())
builder = gtk.Builder()
builder.add_from_file("dagui.glade")
handlers = {
"onDeleteWindow": gtk.main_quit,
"buttondown": hello
}
builder.connect_signals(handlers)
textarea = builder.get_object("textview1")
window = builder.get_object("window1")
txtinput = builder.get_object("entry1")
window.show_all()
gtk.main()
window.show_all()
gtk.main()
now this all works and pressing the button will print what ever is in the gtk.entry but I can not find how to append it to the textview. I also am not sure what to search for to find documentation, I tried "gtk builder gtk.textview" and pygtk build gtk.textview append" and all other variations.
Though knowing how to simply add the text to the text view would be great, having a link to somewhere where I can get in plain english how to use these widgets I would be forever great-full.
Frob the gtk.TextView, you need to get the gtk.TextBuffer by using the textview's buffer property.
From the textbuffer, you need to get the iterator that points to the end of the buffer with the get_end_iter method. With that iterator, and your text, you can use the textbuffer's insert method.
Edit: Since I don't have the dagui.glade file, I couldn't test it, but see the following code:
def hello(button):
global textarea, txtinput
buffer = textarea.get_property('buffer')
i = buffer.get_end_iter()
buffer.insert(i, txtinput.get_text())
# clear the input window after appending the text
txtinput.set_text('')
I figured it out, I have found out the the gtk.textview.get_buffer actually sets the buffer ID and then the textview.set_text(buffer) isall I needed.
here is the full working code, the glade is just a button, an entry and a textview:
#!/usr/bin/python
import os
import sys
import gtk
import pygtk
def onDeleteWindow(self, *args):
Gtk.main_quit(*args)
def hello(button):
textbuffer = textarea.get_buffer()
textbuffer.set_text(txtinput.get_text())
builder = gtk.Builder()
builder.add_from_file("dagui.glade")
handlers = {
"onDeleteWindow": gtk.main_quit,
"buttondown": hello
}
builder.connect_signals(handlers)
textarea = builder.get_object("textview1")
window = builder.get_object("window1")
txtinput = builder.get_object("entry1")
window.show_all()
gtk.main()
Use this to add text :
textarea.set_text('whatever you want')
and this for adding pango markup ( http://goo.gl/94Pkk ) :
textarea.set_markup('<span size="large>Example</span>')
Here's the documentation : http://python-gtk-3-tutorial.readthedocs.org/en/latest/index.html
In my PyGTK app, on button click I need to:
Fetch some html (can take some time)
Show it in new window
While fetching html, I want to keep GUI responsive, so I decided to do it in separate thread. I use WebKit to render html.
The problem is I get empty page in WebView when it is in separated thread.
This works:
import gtk
import webkit
webView = webkit.WebView()
webView.load_html_string('<h1>Hello Mars</h1>', 'file:///')
window = gtk.Window()
window.add(webView)
window.show_all()
gtk.mainloop()
This does not work, produces empty window:
import gtk
import webkit
import threading
def show_html():
webView = webkit.WebView()
webView.load_html_string('<h1>Hello Mars</h1>', 'file:///')
window = gtk.Window()
window.add(webView)
window.show_all()
thread = threading.Thread(target=show_html)
thread.setDaemon(True)
thread.start()
gtk.mainloop()
Is it because webkit is not thread-safe. Is there any workaround for this?
According to my experience, one of the things that sometimes doesn't work as you expect with gtk is the update of widgets in separate threads.
To workaround this problem, you can work with the data in threads, and use glib.idle_add to schedule the update of the widget in the main thread once the data has been processed.
The following code is an updated version of your example that works for me (the time.sleep is used to simulate the delay in getting the html in a real scenario):
import gtk, glib
import webkit
import threading
import time
# Use threads
gtk.gdk.threads_init()
class App(object):
def __init__(self):
window = gtk.Window()
webView = webkit.WebView()
window.add(webView)
window.show_all()
self.window = window
self.webView = webView
def run(self):
gtk.main()
def show_html(self):
# Get your html string
time.sleep(3)
html_str = '<h1>Hello Mars</h1>'
# Update widget in main thread
glib.idle_add(self.webView.load_html_string,
html_str, 'file:///')
app = App()
thread = threading.Thread(target=app.show_html)
thread.start()
app.run()
gtk.main()
I don't know anything about webkit inner workings, but maybe you can try it with multiple processes.
I'm trying to read the text from a popup window.
The title is always the same. I've managed to identify the hwnd and get the title with the code below, but I can't figure out how to read the contents.
import time
import win32gui, win32con
windows = []
def _MyCallback( hwnd, extra ):
extra.append(hwnd)
win32gui.EnumWindows(_MyCallback, windows)
while True:
window = win32gui.GetForegroundWindow()
title = win32gui.GetWindowText(window)
if title == 'Errors occurred': print 'error window'
time.sleep(1)
Here's the working version:
import time
import win32gui
while True:
window = win32gui.GetForegroundWindow()
title = win32gui.GetWindowText(window)
if title == 'Errors occurred':
control = win32gui.FindWindowEx(window, 0, "static", None)
print 'text: ', win32gui.GetWindowText(control)
time.sleep(1)
You will only be able to read this text programmatically if it is contained in a windowed control. You can easily check this with Spy++. Many GUI frameworks don't use windowed controls for their child controls, or only use windowed controls for some children.
If it is a windowed control then you can identify it by calling GetWindow() and walking the child structure (obviously you need to use the win32gui equivalent).
I don't have access to the framework or the error dialog you are using, so I can only say in general what you want.
You need the FindWindowEx function, and use it to find a control whose class name is 'static' (or whatever the class name of the control is). I imagine this would be the line:
control = win32gui.FindWindowEx(window, 0, "Static", 0)
That returns the handle to the control, and you can then use GetWindowText on that to get the text.