输入半径,计算圆的周长、面积、球体体积,并画出这个圆。
拖动条、输入框和图像控件的数据保持一致!
Fedora下测试通过
#https://github.com/RobberPhex/GTK-Example-CalcArea<BR>from gi.repository import Gtk, Gdk, GdkPixbuf<BR>from PIL import Image, ImageDraw<BR>from io import BytesIO<BR>from math import pi</P><P>class Model:<BR> '''<BR> 模型类<BR> 存储半径,计算周长、面积、体积<BR> '''</P><P> def __init__(self):<BR> self._radius = 0</P><P> def setRadius(self, radius):<BR> self._radius = float(radius)</P><P> def getRadius(self):<BR> return self._radius</P><P> def getPerimeter(self):<BR> return pi * self._radius * 2</P><P> def getArea(self):<BR> return self._radius ** 2 * pi</P><P> def getVolume(self):<BR> return 4 * pi * self._radius ** 3 / 3</P><P><BR>class Controller:<BR> '''<BR> 控制器类<BR> 控制视图和模型的更新<BR> '''</P><P> def __init__(self, model):<BR> self.model = model<BR> self._observers = []</P><P> def addObserver(self, observer):<BR> self._observers.append(observer)</P><P> def setRadius(self, radius):<BR> model.setRadius(radius)<BR> self.notify()</P><P> def notify(self):<BR> for observer in self._observers:<BR> observer.update()</P><P><BR>class TextView:<BR> '''<BR> 文字视图类<BR> 处理文本输入框的视图<BR> '''</P><P> def __init__(self, model, rEntry, pEntry, aEntry, vEntry):<BR> '''<BR> :type model Model<BR> '''<BR> self.model = model<BR> self.rEntry = rEntry<BR> self.pEntry = pEntry<BR> self.aEntry = aEntry<BR> self.vEntry = vEntry</P><P> def update(self):<BR> self.rEntry.set_text('%2.2f' % self.model.getRadius())<BR> self.pEntry.set_text('%2.2f' % self.model.getPerimeter())<BR> self.aEntry.set_text('%2.2f' % self.model.getArea())<BR> self.vEntry.set_text('%2.2f' % self.model.getVolume())</P><P><BR>class ScaleView:<BR> '''<BR> 拖动条视图<BR> 处理拖动条的视图<BR> '''</P><P> def __init__(self, model, scale):<BR> '''<BR> :type model Model<BR> '''<BR> self.model = model<BR> self.scale = scale</P><P> def update(self):<BR> self.scale.set_value(self.model.getRadius())</P><P><BR>class ImageView:<BR> '''<BR> 图像视图<BR> 处理图像的视图<BR> '''</P><P> @classmethod<BR> def imgToPixbuf(cls, img):<BR> '''<BR> :type img Image<BR> '''<BR> buff = BytesIO()<BR> img.save(buff, 'ppm')<BR> contents = buff.getvalue()<BR> buff.close()</P><P> loader = GdkPixbuf.PixbufLoader.new_with_type('pnm')<BR> loader.write(contents)<BR> pixbuf = loader.get_pixbuf()<BR> loader.close()<BR> return pixbuf</P><P> @classmethod<BR> def ellipse(cls, radius):<BR> '''<BR> :type radius int<BR> '''<BR> image = Image.new("RGBA", (300, 300), "white")<BR> draw = ImageDraw.Draw(image)<BR> minor = 150 - radius<BR> major = 150 + radius<BR> draw.ellipse((minor, minor, major, major), outline='red')<BR> pixbuf = ImageView.imgToPixbuf(image)<BR> return pixbuf</P><P> def __init__(self, model, image):<BR> self.model = model<BR> self.image = image</P><P> def update(self):<BR> radius = self.model.getRadius()<BR> pixbuf = ImageView.ellipse(radius)<BR> self.image.set_from_pixbuf(pixbuf)</P><P><BR>class MainWindow(Gtk.Window):<BR> '''<BR> 主窗口类<BR> 负责整体界面的显示<BR> '''</P><P> def textCallback(self, widget, controller):<BR> '''<BR> 文本输入回调<BR> '''<BR> try:<BR> radius = float(widget.get_text())<BR> controller.setRadius(radius)<BR> except ValueError as e:<BR> pass</P><P> def scaleCallback(self, widget, controller):<BR> '''<BR> 拖动条回调<BR> '''<BR> radius = widget.get_value()<BR> controller.setRadius(radius)</P><P> def __init__(self):<BR> Gtk.Window.__init__(self, title="Title")</P><P> self.set_default_size(600, 400)<BR> self.set_position(Gtk.WindowPosition.CENTER)</P><P> hbox = Gtk.HBox(spacing=5)<BR> self.add(hbox)</P><P> vbox = Gtk.VBox(spacing=5)<BR> hbox.pack_start(vbox, True, True, 2)</P><P> table = Gtk.Table.new(4, 2, False)<BR> vbox.pack_start(table, True, True, 2)</P><P> label = Gtk.Label('半径:')<BR> table.attach_defaults(label, 0, 1, 0, 1)<BR> label = Gtk.Label('周长:')<BR> table.attach_defaults(label, <span>本文来源gaodai#ma#com搞*!代#%^码$网*</span>0, 1, 1, 2)<BR> label = Gtk.Label('面积:')<BR> table.attach_defaults(label, 0, 1, 2, 3)<BR> label = Gtk.Label('体积:')<BR> table.attach_defaults(label, 0, 1, 3, 4)</P><P> self.radiusEntry = Gtk.Entry.new()<BR> self.radiusEntry.connect('changed', self.textCallback, controller)<BR> table.attach_defaults(self.radiusEntry, 1, 2, 0, 1)<BR> self.perimeterEntry = Gtk.Entry.new()<BR> self.perimeterEntry.set_sensitive(False)<BR> self.perimeterEntry.set_text('周长')<BR> table.attach_defaults(self.perimeterEntry, 1, 2, 1, 2)<BR> self.areaEntry = Gtk.Entry.new()<BR> self.areaEntry.set_sensitive(False)<BR> self.areaEntry.set_text('面积')<BR> table.attach_defaults(self.areaEntry, 1, 2, 2, 3)<BR> self.volumeEntry = Gtk.Entry.new()<BR> self.volumeEntry.set_sensitive(False)<BR> self.volumeEntry.set_text('体积')<BR> table.attach_defaults(self.volumeEntry, 1, 2, 3, 4)</P><P> self.scale = Gtk.HScale.new_with_range(0, 100, 1)<BR> self.scale.connect('value-changed', self.scaleCallback, controller)<BR> vbox.pack_start(self.scale, False, False, 2)</P><P> pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 300, 300)<BR> pixbuf.fill(0xaaaaaaaa)<BR> self.image = Gtk.Image.new_from_pixbuf(pixbuf)<BR> hbox.pack_start(self.image, True, True, 2)</P><P> self.connect('delete-event', Gtk.main_quit)</P><P><BR>model = Model()<BR>controller = Controller(model)</P><P>if __name__ == '__main__':<BR> Gdk.threads_init()<BR> Gdk.threads_enter()<BR> win = MainWindow()</P><P> iv = ImageView(model, win.image)<BR> controller.addObserver(iv)</P><P> tv = TextView(model, win.radiusEntry, win.perimeterEntry, win.areaEntry, win.volumeEntry)<BR> controller.addObserver(tv)</P><P> sv = ScaleView(model, win.scale)<BR> controller.addObserver(sv)</P><P> win.show_all()<BR> Gtk.main()<BR> Gdk.threads_leave()<BR>