patternpythonMinor
Simple Python + Gtk.Window
Viewed 0 times
gtksimplewindowpython
Problem
I'm learning Python and Gtk so I decided to write a simple application that will take some image let user annotate with a pen and send results through email or save to a file.
So far I have the skeleton of the interface:
```
from gi.repository import Gtk
import os, sys
class GUI:
image = 0;
def __init__(self):
self.window = Gtk.Window()
self.window.set_title ("Imagine")
self.window.connect_after('destroy', self.destroy)
self.window.set_border_width(10)
self.window.set_default_size(400, 200)
self.window.vbox = Gtk.Box()
self.window.vbox.set_spacing (5)
self.window.vbox.set_orientation (Gtk.Orientation.VERTICAL)
self.window.add (self.window.vbox)
self.window.hbox = Gtk.ButtonBox()
self.window.vbox.add(self.window.hbox)
self.window.new_button = Gtk.Button(label="New")
self.window.new_button.connect("clicked", self.on_new_clicked)
self.window.hbox.pack_start(self.window.new_button, False, False, 0)
self.window.save_button = Gtk.Button(label="Save")
self.window.save_button.connect("clicked", self.on_save_clicked)
self.window.hbox.pack_start(self.window.save_button, False, False, 0)
self.window.email_button = Gtk.Button(label="eMail")
self.window.email_button.connect("clicked", self.on_email_clicked)
self.window.hbox.pack_start(self.window.email_button, False, False, 0)
self.window.pen_button = Gtk.Button(label="Pen")
self.window.pen_button.connect("clicked", self.on_pen_clicked)
self.window.hbox.pack_start(self.window.pen_button, False, False, 0)
self.image = Gtk.Image()
self.window.vbox.pack_start (self.image, False, False, 0)
self.window.show_all()
def on_save_clicked(self, widget):
print("fixme: Save Clicked")
def on_email_clicked(self, widget):
print("fixme: eMail Clicked")
def on_pen_clicked(self, widget):
print("fixme: Pen Clicked")
def on_new_clicked (self, button):
print("fixme: New Clicked")#code below is just to test the
So far I have the skeleton of the interface:
```
from gi.repository import Gtk
import os, sys
class GUI:
image = 0;
def __init__(self):
self.window = Gtk.Window()
self.window.set_title ("Imagine")
self.window.connect_after('destroy', self.destroy)
self.window.set_border_width(10)
self.window.set_default_size(400, 200)
self.window.vbox = Gtk.Box()
self.window.vbox.set_spacing (5)
self.window.vbox.set_orientation (Gtk.Orientation.VERTICAL)
self.window.add (self.window.vbox)
self.window.hbox = Gtk.ButtonBox()
self.window.vbox.add(self.window.hbox)
self.window.new_button = Gtk.Button(label="New")
self.window.new_button.connect("clicked", self.on_new_clicked)
self.window.hbox.pack_start(self.window.new_button, False, False, 0)
self.window.save_button = Gtk.Button(label="Save")
self.window.save_button.connect("clicked", self.on_save_clicked)
self.window.hbox.pack_start(self.window.save_button, False, False, 0)
self.window.email_button = Gtk.Button(label="eMail")
self.window.email_button.connect("clicked", self.on_email_clicked)
self.window.hbox.pack_start(self.window.email_button, False, False, 0)
self.window.pen_button = Gtk.Button(label="Pen")
self.window.pen_button.connect("clicked", self.on_pen_clicked)
self.window.hbox.pack_start(self.window.pen_button, False, False, 0)
self.image = Gtk.Image()
self.window.vbox.pack_start (self.image, False, False, 0)
self.window.show_all()
def on_save_clicked(self, widget):
print("fixme: Save Clicked")
def on_email_clicked(self, widget):
print("fixme: eMail Clicked")
def on_pen_clicked(self, widget):
print("fixme: Pen Clicked")
def on_new_clicked (self, button):
print("fixme: New Clicked")#code below is just to test the
Solution
I don't think your considerations are a big problem.
However what I think is a bigger problem is the amount of verbosity and repetition in your code. While the code is readable as is, adding more elements in the future will make your
This is because you are adding each Element individually. In large applications this is largely unfeasible when you have more than a dozen widgets, for reasons I am sure you can understand.
There are a couple of solutions to this:
Generate Layout using code
instead of doing this:
you can do this
Subclass standard widgets
Often you can also clean up your application by subclassing other widgets:
Seperate Interface and logic by using
I am mentioning this last since this is the best option, but not very frequently worth the effort.
The Gtk 3 Tutorial has a very nice page on GtkBuilder
The Gtk.Builder class offers you the opportunity to design user
interfaces without writing a single line of code. This is possible
through describing the interface by a XML file and then loading the
XML description at runtime and create the objects automatically, which
the Builder class does for you. For the purpose of not needing to
write the XML manually the Glade application lets you create the user
interface in a WYSIWYG (what you see is what you get) manner
This method has several advantages:
There is still code required for handling interface changes triggered by the user,
but Gtk.Builder allows you to focus on implementing that
functionality.
However what I think is a bigger problem is the amount of verbosity and repetition in your code. While the code is readable as is, adding more elements in the future will make your
__init__() method inflate and become unreadable.This is because you are adding each Element individually. In large applications this is largely unfeasible when you have more than a dozen widgets, for reasons I am sure you can understand.
There are a couple of solutions to this:
Generate Layout using code
instead of doing this:
self.window.new_button = Gtk.Button(label="New")
self.window.new_button.connect("clicked", self.on_new_clicked)
self.window.hbox.pack_start(self.window.new_button, False, False, 0)
# ... repeat for all buttonsyou can do this
buttons = [("New", self.on_new_clicked),
("Save", self.on_save_clicked),
("eMail", self.on_email_clicked),
("Pen", self.on_pen_clicked),
]
for name, callback in buttons:
b = Gtk.Button(label=button)
b.connect("clicked", callback)
self.window.hbox.pack_start(b, False, False, 0)Subclass standard widgets
Often you can also clean up your application by subclassing other widgets:
class myButtonBox(Gtk.ButtonBox):
def __init__(self, *args, **kwargs):
# add all buttons to self here
super().__init__(*args, **kwargs)
# note: super() without args works only in new versions of PythonSeperate Interface and logic by using
GtkBuilder xmlI am mentioning this last since this is the best option, but not very frequently worth the effort.
The Gtk 3 Tutorial has a very nice page on GtkBuilder
The Gtk.Builder class offers you the opportunity to design user
interfaces without writing a single line of code. This is possible
through describing the interface by a XML file and then loading the
XML description at runtime and create the objects automatically, which
the Builder class does for you. For the purpose of not needing to
write the XML manually the Glade application lets you create the user
interface in a WYSIWYG (what you see is what you get) manner
This method has several advantages:
- Less code needs to be written.
- UI changes can be seen more quickly, so UIs are able to improve.
- Designers without programming skills can create and edit UIs.
- The description of the user interface is independent from the programming language being used.
There is still code required for handling interface changes triggered by the user,
but Gtk.Builder allows you to focus on implementing that
functionality.
Code Snippets
self.window.new_button = Gtk.Button(label="New")
self.window.new_button.connect("clicked", self.on_new_clicked)
self.window.hbox.pack_start(self.window.new_button, False, False, 0)
# ... repeat for all buttonsbuttons = [("New", self.on_new_clicked),
("Save", self.on_save_clicked),
("eMail", self.on_email_clicked),
("Pen", self.on_pen_clicked),
]
for name, callback in buttons:
b = Gtk.Button(label=button)
b.connect("clicked", callback)
self.window.hbox.pack_start(b, False, False, 0)class myButtonBox(Gtk.ButtonBox):
def __init__(self, *args, **kwargs):
# add all buttons to self here
super().__init__(*args, **kwargs)
# note: super() without args works only in new versions of PythonContext
StackExchange Code Review Q#105830, answer score: 6
Revisions (0)
No revisions yet.