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.
Related
I'm making an application that can change certain parameters through a Gtk.Menu. I have a Gtk.MenuButton that pops down a Gtk.Menu with other submenus in it. One of those submenus has Gtk.MenuItems with Gtk.SpinButtons in them. I have gotten the Gtk.SpinButtons to receive input by bringing their associated Gdk.Windows to the front of the Z-order with Gdk.Window.show(), but I can't get the Gtk.Entry part of the Gtk.SpinButton to receive keyboard focus.
I have tried to use Gtk.Widget.grab_focus() and other related methods to no avail. It does highlight the Gtk.Entry text, and I can type in new text, but if I click away or press enter, it doesn't actually update/change the Gtk.SpinButton value. I have connected to the "change-value" and "value-changed" signals but typing anything into the Gtk.SpinButton doesn't fire them.
I've found out that a widget can be the "focus widget" but not have the "global input focus" if its toplevel Gtk.Window doesn't also have the global focus. Therefore, I'm stuck. Is there any way around this? Can I make the Gtk.SpinButton entry field have the keyboard focus if it's in a Gtk.Menu?
Here is a minimal example:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
class Menu(Gtk.Menu):
def __init__(self):
Gtk.Menu.__init__(self)
menu_item = Gtk.MenuItem(label="Submenu")
menu_item2 = Gtk.MenuItem(label="Item")
self.append(menu_item)
self.append(menu_item2)
submenu = Gtk.Menu()
sub_mi = Gtk.MenuItem()
spin_button = Gtk.SpinButton()
spin_adj = Gtk.Adjustment(value=0,lower=0, upper=10, step_increment=1)
spin_button.set_adjustment(spin_adj)
sub_mi.add(spin_button)
submenu.append(sub_mi)
menu_item.set_submenu(submenu)
spin_button.connect("realize", self.on_realize)
spin_button.connect("map-event", self.on_map_event)
submenu.connect("button-release-event", self.on_button_release)
submenu.connect("enter-notify-event", self.on_enter)
self.show_all()
def on_realize(self, spin_button):
spin_button.add_events(Gdk.EventMask.STRUCTURE_MASK)
def on_map_event(self, spin_button, event):
for win in spin_button.get_window().get_children():
win.show()
def on_button_release(self, menu, event):
return True
def on_enter(self, menu, event):
mouse = event.get_device()
mouse.ungrab(event.time)
win = Gtk.Window()
win.set_default_size(100, 20)
win.connect("destroy", Gtk.main_quit)
mb = Gtk.MenuButton()
win.add(mb)
menu = Menu()
mb.set_popup(menu)
win.show_all()
Gtk.main()
I realize this is convoluted, and there's probably a better solution (like not using a Gtk.Menu for this...), but I've come up with a workaround anyway.
Since I can't activate or fully focus the Gtk.SpinButton I am just forcing it to update the text field whenever there is a leave-notify-event fired from it.
spin_button.connect("leave-notify-event", self.on_leave)
def on_leave(self, spin_button, event):
value = spin_button.get_text()
spin_button.set_value(float(value))
spin_button.update()
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()
I'm using python and PyGObjects (the introspection lib) for Gtk 3 here.
Consider the following code:
from gi.repository import Gtk
class InternalWidget(Gtk.Button):
def __init__(self):
super(InternalWidget, self).__init__()
self.set_size_request(100,100)
self.connect("button-press-event", self.on_press)
def on_press(self, *args):
print "The Internal Widget was clicked."
class ExternalEventBox(Gtk.EventBox):
def __init__(self):
super(ExternalEventBox, self).__init__()
self.fixed = Gtk.Fixed()
self.add(self.fixed)
self.internal_widget = InternalWidget()
self.set_size_request(200, 200)
self.connect("button-press-event", self.on_press)
self.connect("enter-notify-event", self.on_enter)
self.connect("leave-notify-event", self.on_leave)
def on_enter(self, *args):
self.fixed.put(self.internal_widget, 50,50)
self.show_all()
def on_leave(self, *args):
self.fixed.remove(self.internal_widget)
def on_press(self,*args):
print "The External Event Box was clicked."
w = Gtk.Window(Gtk.WindowType.TOPLEVEL)
w.connect("delete-event", Gtk.main_quit)
w.add(ExternalEventBox())
w.show_all()
Gtk.main()
Above, whenever the mouse enters the ExternalEventBox, a button (InternalWidget) is added to it as a child. When the mouse leaves the ExternalEventBox, the button is removed as a child of the ExternalEventBox.
Now, if you run the code (which you can), the button appears and disappears properly. However, clicking on the button, contrary to what is expected, only sends a signal to the containing ExternalEventBox, whereas the button receives no signal.
Interestingly, the expected behavior (clicking on the button actually clicks it) happens when the button, rather than being dynamically added and removed, is added once in the constructor of the event box, and never removed.
Is this a bug, or am I just missing something?
Edit: In a nutshell, I only get "The External Event Box was clicked.", but never "The Internal Widget was clicked.".
Update: I filed a bug report.
You need to set the EventBox event window to be below it's children using .set_above_child(false)
Here's the docs for it: GtkEventBox
If the window is above, all events inside the event box will go to the event box. If the window is below, events in windows of child widgets will first got to that widget, and then to its parents.
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
I have a PyGTK program which is hidden most of the time, but with a keypress it shall come up as a popup. Therefore I want the program not to be activated when its opened. I tried several options to to that, with no success:
self.window.show()
self.window.set_focus(None)
Activates the program, but sets no focus.
self.window.set_accept_focus(False)
self.window.show()
self.window.set_accept_focus(True)
With the last command, the window gets activated.
self.window.show()
self.window.unset_flags(gtk.HAS_FOCUS)
Does nothing...
Btw. I am using Ubuntu 9.10 (metacity)
Build the window but don't call show() on it until it is ready to be activated. Then use self.window.present().
EDIT:
If you never want the window to be activated, why not try a notification popup? You need libnotify for this. There are Python bindings. Here is an example: http://roscidus.com/desktop/node/336
In combination with a toolbar applet, this could do what you want -- i.e. the notification is raised when the user either clicks on the applet or presses the key combination.
I figured out how to do it. See the example below:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
import gobject
class HelloWorld:
window=None
def hello(self, widget, data=None, data2=None):
HelloWorld.window.set_accept_focus(True)
HelloWorld.window.present()
def __init__(self):
HelloWorld.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.button = gtk.Entry(50)
self.button.connect("focus-in-event", self.hello, None)
HelloWorld.window.add(self.button)
self.button.show()
HelloWorld.window.set_accept_focus(False)
self.button.connect('button-press-event', self.hello)
HelloWorld.window.show()
def main(self):
gtk.main()
if __name__ == "__main__":
hello = HelloWorld()
hello.main()