Python Gtk Tutorial - python

This is example 2 from the GTK tutorial
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
def on_button_clicked(self, widget):
print("Hello World")
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
When I attempt to run, it displays nothing and when I close the window, I receive a message saying the program is still running. I've stripped down the code and by eliminating the buttons, the window will appear so I think that there is a mistake in the button.add.

In your code there was an unexpected indent error from the line containing 'class' and it didn't use the __name__ == '__main__' trick (though that's just a matter of good habit).
This should work. At least it does for Gtk+3 with Python 3.4 on my Ubuntu dist.
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
def on_button_clicked(self, widget):
print("Hello World")
if __name__ == '__main__':
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

Try to import from this way
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
def on_button_clicked(self, widget):
print("Hello World")
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
Then use your ide for reindent all lines
if not work uninstall all your gtk modules, install this
https://sourceforge.net/projects/pygobjectwin32/files/
and try again

Related

Run action after Gtk window is shown

I have a multi-window Gtk application, which is an installer.
During the installation process, which takes some time, I want to show a Window with a label to notify the user that the installation is in progress.
So I tried to bind the respective method to the show event.
However, that causes the appearance of the window to be delayed until the the method finishes, after which the next window is immediately shown.
The result is, that the previous window shows, then the screen goes blank for the duration of the actual installation and then the final window is shown.
I boiled the issue down to the fact, that the show event is obviously triggered, before the window is actually shown.
Here's a minimal snipped to clarify my issue.
The window shows after the call to sleep(), not before.
#! /usr/bin/env python3
from time import sleep
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.ApplicationWindow):
def __init__(self):
"""Initializes the GUI."""
super().__init__(title='Gtk Window')
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid()
self.add(self.grid)
self.label = Gtk.Label()
self.label.set_text('Doing stuff')
self.grid.attach(self.label, 0, 0, 1, 1)
self.connect('show', self.on_show)
def on_show(self, *args):
print('Doing stuff.')
sleep(3)
print('Done stuff.')
def main() -> None:
"""Starts the GUI."""
win = GUI()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
How can I achieve, that the window shows before the method on_show() is called?
The desired program flow is
Show window
run installation
hide window (and show next one)
without any user interaction.
I fixed it by using multiprocessing :
from ast import Gt
from time import sleep
from multiprocessing import Process
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.ApplicationWindow):
def __init__(self):
"""Initializes the GUI."""
super().__init__(title='Gtk Window')
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid()
self.add(self.grid)
self.label = Gtk.Label()
self.label.set_text('Doing stuff')
self.grid.attach(self.label, 0, 0, 1, 1)
def on_show():
print('Doing stuff.')
sleep(3)
print('Done stuff.')
def main() -> None:
"""Starts the GUI."""
win = GUI()
win.connect('destroy', Gtk.main_quit)
win.show_all()
p1 = Process(target = on_show)
p1.start()
Gtk.main()
if __name__ == '__main__':
main()
Basically, what was happening is that Gtk.main() renders your app while show_all() just packs the widgets, so putting a sleep func before it delays the render.
another method is to use threading (which also provides you an easy way to implemant a progress bar) :
from ast import Gt
from time import sleep
import threading
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
class GUI(Gtk.ApplicationWindow):
def __init__(self):
"""Initializes the GUI."""
super().__init__(title='Gtk Window')
self.set_position(Gtk.WindowPosition.CENTER)
self.grid = Gtk.Grid()
self.add(self.grid)
self.label = Gtk.Label()
self.label.set_text('Doing stuff')
self.grid.attach(self.label, 0, 0, 1, 1)
thread = threading.Thread(target=self.on_show)
thread.daemon = True
thread.start()
def on_show(self, *args):
print('Doing stuff.')
sleep(3)
print('Done stuff.')
def main() -> None:
"""Starts the GUI."""
win = GUI()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
if __name__ == '__main__':
main()
Further informations on threads

PyGTK entry.set_placeholder_text doesnt work - missing tex

I am attaching a piece of my code in which I try to display the text in the Entry field with predefined text. I use entry.set_placeholder_text for this, but unfortunately the text does not appear.
Is there an effective solution?
# -*- coding: utf-8 -*-
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super(MyWindow, self).__init__()
entry = Gtk.Entry()
entry.set_placeholder_text("Any text")
self.add(entry)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
The placeholder text is only visible when the entry is empty and unfocused. Adding another widget that can get the focus will make the text appear.
Example:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
super(MyWindow, self).__init__()
entry = Gtk.Entry()
entry.set_placeholder_text("Any text")
box = Gtk.HBox()
self.add(box)
button = Gtk.Button()
box.pack_start(button, False, False, 0)
box.pack_start(entry, True, True, 0)
win = MyWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
I know, I have no idea why it doesn't work.
I usually do:
search_entry.props.placeholder_text = 'Placeholder text'
before calling set_active on the widget

Python GTK+ 3 - Can't set a parent on a toplevel widget

Gtk-WARNING **: 19:18:52.313: Can't set a parent on a toplevel widget
Why do I get this warning? Isn't master win a toplevel widget? What am I doing wrong?
Shouldn't master_win be toplevel? It is created first...
class PluginWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
#some stuff
master_win = Gtk.ScrolledWindow()
master_win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
win = PluginWindow()
master_win.add(win)
win.connect("destroy", Gtk.main_quit)
master_win.show_all()
Gtk.main()
You have the order wrong
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class PluginWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
#some stuff
master_win = Gtk.ScrolledWindow()
master_win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
win = PluginWindow()
win.add(master_win)
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
You're trying to add a Gtk.Window() object into Gtk.ScrolledWindow() object and that is not possible. It's inversed.
A Gtk.Window is a toplevel window which can contain other widgets. Windows normally have decorations that are under the control of the windowing system and allow the user to manipulate the window (resize it, move it, close it,…).
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
class PluginWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Stack Demo")
# some stuff
master_win = Gtk.ScrolledWindow()
master_win.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.ALWAYS)
win = PluginWindow()
# Gtk.ScrolledWindow added to Gtk.Window
win.add(master_win)
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()

How to poll MPD from GTK with mpd.idle() without blocking

I want to use MPD's idle feature to wait for any changes and then display them in the GTK GUI using Python. The problem is that the GUI seems to block and become unresponsive when I use MPD's idle feature (when changing songs the GTK window becomes unresponsive). When I remove self.mpd.idle() it works, but then the function keeps getting run all the time which I find unnecessary.
What is the best way to solve this?
Not working
My initial approach:
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
class GUI:
def __init__(self):
self.mpd = MPDClient()
self.mpd.timeout = 10
self.mpd.connect("localhost", 6600)
self.window = Gtk.Window()
self.window.connect("delete-event", Gtk.main_quit)
self.window.show_all()
GLib.idle_add(self.get_current_song)
Gtk.main()
def get_current_song(self):
self.mpd.idle()
print(self.mpd.currentsong())
return True
app = GUI()
Not working
My second approach using this. Still getting the same results.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
import threading
class GUI:
def __init__(self):
self.mpd = MPDClient()
self.mpd.timeout = 1
self.mpd.connect("localhost", 6600)
self.window = Gtk.Window()
self.window.connect("delete-event", Gtk.main_quit)
self.window.show_all()
self.thread = threading.Thread(target=self.idle_loop)
self.thread.daemon = True
self.thread.start()
Gtk.main()
def get_songs(self):
print(self.mpd.currentsong())
self.mpd.idle()
return True
def idle_loop(self):
GLib.idle_add(self.get_songs)
app = GUI()
WORKING
Leaving out the GLib.idle_add() function seems to be a solution. But I don't know if this is the "proper" way. It feels wrong not knowing why GLib.idle_add() was messing it up and not using it since it's mentioned in the documentation.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
import threading
class GUI:
def __init__(self):
self.mpd = MPDClient()
self.mpd.timeout = 1
self.mpd.connect("localhost", 6600)
self.window = Gtk.Window()
self.window.connect("delete-event", Gtk.main_quit)
self.window.show_all()
self.thread = threading.Thread(target=self.get_songs)
self.thread.daemon = True
self.thread.start()
Gtk.main()
def get_songs(self):
self.mpd.idle()
print(self.mpd.currentsong())
app = GUI()
Let us use the threading module here.
As described in this article : https://pygobject.readthedocs.io/en/latest/guide/threading.html, we can make the following code:
import gi
from threading import Thread
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib
from mpd import MPDClient
class GUI:
def __init__(self):
self.mpd = MPDClient()
self.mpd.timeout = 10
self.mpd.connect("localhost", 6600)
self.window = Gtk.Window()
self.window.connect("delete-event", Gtk.main_quit)
self.window.show_all()
thread = Thread(target=self.get_current_song, args=())
thread.start()
Gtk.main()
def get_current_song(self):
self.mpd.idle()
print(self.mpd.currentsong())
return True
app = GUI()

PyGTK callback function not executing step by step

I'm new to Python and GTK. I'm trying to display a dialog box with some text which looks like a something is loading at the back. Here is the code:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk, gobject, time
class Base:
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
#Progress Bar
self.button=gtk.Button("click")
self.window.add(self.button)
self.button.connect("clicked",self.display)
self.dialog = gtk.Dialog()
self.label = gtk.Label("Text")
self.dialog.vbox.pack_start(self.label,True,True,0)
self.label.show()
self.window.show_all()
def display(self,widget):
self.dialog.show()
for i in range(0,5):
self.label.set_text("Text"+" . "*i)
time.sleep(1)
self.dialog.hide()
def main(self):
gtk.main()
print __name__
if __name__ == "__main__":
base = Base()
base.main()
I want to display text following with 4 dots(.) which appear after 1 second each.The problem I'm facing is when I click the button the dialog box appears after 5 seconds with all the 4 dots. Whats wrong with the code?
It would be great if there is any better way to do this.

Categories