7-Segmente zum Dritten
Verfasst: Samstag 1. Januar 2005, 16:37
Hallo,
ich hab mich in den letzten Tagen. auch mal an einer 7-Segmentanzeige herangemacht. Herausgekommen ist ein Modul, das sich GUI-Unabhängig verwenden lässt.
und hier ein Beispiel mit gtk2:
Wie zu sehen ist, muss in der Anwendung nur eine Klasse als Interface zum Zeichnen von Polygonen definiert werden. Die Instanz die mit dieser Klasse erzeugt wird, enthält dann alle Informationen um in einem Widget die Segmente zu zeichnen. Auch ein Erweitern um zusätzliche Elemente ist durch Verwendung einer Metaklasse für die Segmentelemente sehr einfach.
Vielleicht hat ja wer lust, noch Beispiele für gt oder wxwidgets oder ... zu machen.
Gruß und gutes neues Jahr,
Dookie
Edit, kleine Änderungen am Code
ich hab mich in den letzten Tagen. auch mal an einer 7-Segmentanzeige herangemacht. Herausgekommen ist ein Modul, das sich GUI-Unabhängig verwenden lässt.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
Modul: SevenSegs
Description: GUI-indipend class for sevensegsdisplays
Version: 0.1
Copyright: 2004 by Fritz Cizmarov fritz@sol.at
Created: 26. Dez. 2004
Last modified: 01. Jän. 2005
License: free
Requirements: Python2.3
Exports: Drawer, Elem, Digit, Point, DPoint, Segments
"""
class Drawer(object):
""" Baseclass for interface to the drawing_area or canvas to draw at """
def __init__(self, *data, **kw):
super(Drawer, self).__init__()
def poly(self, points, color):
""" redefine this in your own Drawerclass """
raise NotImplemented("poly() is not implemented in baseclass!")
def rect(self, x, y, w, h, color):
self.poly(((x, y), (x, y+h), (x+w, y+h), (x+w, y)), color)
class ElemType(type):
__classes = {}
def classes(cls):
return cls.__classes
classes = property(classes)
def __init__(cls, name, bases, dct):
super(ElemType, cls).__init__(name, bases, dct)
for key in dct["idkey"]:
if cls.__classes.has_key(key):
raise ValueError("'%s' already used!" % key)
cls.__classes[key] = cls
def create(cls, key, *args, **kw):
return cls.__classes[key](*args, **kw)
def calc_size(cls, fmt, scale):
w = 0
h = []
for ch in fmt:
tmp = cls.create(ch, " ")
w += tmp.width * scale
h += [tmp.height * scale]
return w, max(h)
class Elem(object):
__metaclass__ = ElemType
idkey = ""
values = ""
shape = {"" : ()}
llcd = {"" : ()}
def __get_value(self):
return self.__value
def __set_value(self, value):
if not value in self.values:
msg = "value can only be one of '%s' not '%s!'"
raise ValueError(msg % (self.values, value))
try:
if value == self.__value:
return
old = self.llcd[self.__value]
except AttributeError:
old = None
self.__value = value
if self.drawer:
self.redraw(old)
value = property(__get_value, __set_value)
def get_width(self):
max_x = 0
for poly in self.shape.itervalues():
max_x = max([a for a, b, in poly] + [max_x])
return (max_x + 1) * self.scale
width = property(get_width)
def get_height(self):
max_y = 0
for poly in self.shape.itervalues():
max_y = max([b for a, b, in poly] + [max_y])
return (max_y + 1) * self.scale
height = property(get_height)
def get_xoffset(self):
xoffset = self.parent.x
if self.parent is not None:
for seg in self.parent:
if seg is self:
break
xoffset += seg.width
return xoffset
xoffset = property(get_xoffset)
def get_yoffset(self):
return self.parent.y
yoffset = property(get_yoffset)
def __init__(self, value="", scale=1, parent=None, drawer=None,
on_color="#00ff00", off_color="#002200", bg_color="#000000"):
super(Elem, self).__init__()
self.scale = scale
self.parent = parent
self.drawer = drawer
self.on_color = on_color
self.off_color = off_color
self.bg_color = bg_color
self.rescale()
self.value = value
def move(self, pts):
xoffset = self.xoffset
yoffset = self.yoffset
return [(a + xoffset, b + yoffset) for a, b in pts]
def redraw(self, old=None):
if self.drawer is None:
return
if old is None:
old = self.polys.keys()
for i in old:
self.drawer.poly(self.move(self.polys[i]),
self.on_color)
for i in [i for i in old if i not in self.llcd[self.value]]:
self.drawer.poly(self.move(self.polys[i]), self.off_color)
for i in [i for i in self.llcd[self.value] if i not in old]:
self.drawer.poly(self.move(self.polys[i]), self.on_color)
def set_drawer(self, drawer):
self.drawer = drawer
self.redraw()
def rescale(self):
scale = self.scale
self.polys = {}
for key, value in self.shape.iteritems():
self.polys[key] = [(a * scale, b * scale) for a, b, in value]
class Digit(Elem):
idkey = "#"
values = "0123456789E+-* "
# - b
# |,| ahc
# - g
# |'| fid
# - e
# polygon coordinates for height=50
shape = {
'a' : (( 1, 6), ( 3, 4), ( 5, 6), ( 5,16), ( 3,18), ( 1,16)),
'b' : (( 6, 1), (16, 1), (18, 3), (16, 5), ( 6, 5), ( 4, 3)),
'c' : ((17, 6), (19, 4), (21, 6), (21,16), (19,18), (17,16)),
'd' : ((17,22), (19,20), (21,22), (21,32), (19,34), (17,32)),
'e' : (( 6,33), (16,33), (18,35), (16,37), ( 6,37), ( 4,35)),
'f' : (( 1,22), ( 3,20), ( 5,22), ( 5,32), ( 3,34), ( 1,32)),
'g' : (( 6,17), (16,17), (18,19), (16,21), ( 6,21), ( 4,19)),
'h' : (( 9,16), ( 9,14), (11,12), (13,14), (13,16)),
'i' : (( 9,22), ( 9,24), (11,26), (13,24), (13,22)),
}
# llcd defines a list of segments to turn on for any particular symbol.
llcd = {
'0' : "abcdef",
'1' : "cd",
'2' : "bcefg",
'3' : "bcdeg",
'4' : "acdg",
'5' : "abdeg",
'6' : "abdefg",
'7' : "bcd",
'8' : "abcdefg",
'9' : "abcdeg",
'-' : "g",
'+' : "ghi",
'E' : "abefg",
' ' : "",
'*' : "abcdefghi"
}
class Point(Elem):
idkey = "."
values = ". "
shape = {"a" : (( 1,37), ( 1,33), ( 5,33), ( 5,37))}
llcd = {"." : "a", " " : ""}
class DPoint(Elem):
idkey = ":"
values = ": "
shape = {"a" : (( 1,16), ( 1,12), ( 5,12), ( 5,16)),
"b" : (( 1,26), ( 1,22), ( 5,22), ( 5,26))}
llcd = {":" : "ab", " " : ""}
class Segments(list):
def get_values(self):
return [x.value for x in self]
def set_values(self, values):
for elem, value in zip(self, values):
elem.value = value
values = property(get_values, set_values)
def get_fmt(self):
return self.__fmt
fmt = property(get_fmt)
def get_x(self):
return self.__x
x = property(get_x)
def get_y(self):
return self.__y
y = property(get_y)
def get_width(self):
return sum([elem.width for elem in self])
width = property(get_width)
def get_height(self):
return max([elem.height for elem in self])
height = property(get_height)
def __init__(self, fmt, values, drawer=None, scale=1, x=0, y=0,
on_color="#00ff00", off_color="#002200", bg_color="#000000"):
super(Segments, self).__init__()
self.__x = x
self.__y = y
self.__fmt = fmt
self.drawer = drawer
self.bg_color = bg_color
for key, value in zip(fmt,values):
self.append(Elem.create(key, value, scale, self, drawer,
on_color, off_color, bg_color))
def redraw(self):
self.drawer.rect(self.x, self.y,
self.width, self.height,
self.bg_color)
for elem in self:
elem.redraw()
def calc_size(fmt, scale):
return Elem.calc_size(fmt, scale)
calc_size = staticmethod(calc_size)
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
Modul: gtk_clock
Description: Clock with big sevensegmentdisplay
Version: 0.1
Copyright: 2004 by Fritz Cizmarov fritz@sol.at
Created: 01. Jän. 2005
Last modified: 01. Jän. 2005
License: free
Requirements: Python2.3
"""
import time
import pygtk
pygtk.require('2.0')
import gtk
import gobject
from SevenSegs import Drawer, Segments
class gtkDrawer(Drawer):
""" interface zu draw filled polygons on an drawable """
def __init__(self, drawable, colormap):
self.drawable = drawable
self.colormap = colormap
self.gc = drawable.new_gc()
black = self.colormap.alloc_color("#000000")
self.colors = {"#000000" : black}
def poly(self, points, color):
""" draw the Poly with pointlist points and color """
if color not in self.colors:
self.colors[color] = self.colormap.alloc_color(color)
self.gc.set_foreground(self.colors[color])
self.drawable.draw_polygon(self.gc, gtk.TRUE, points)
"""
def rect(self, x, y, w, h, color):
if color not in self.colors:
self.colors[color] = self.colormap.alloc_color(color)
self.gc.set_foreground(self.colors[color])
self.drawable.draw_rectangle(self.gc, gtk.TRUE, x, y, w, h)
"""
class APP(object):
def __init__(self):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy)
self.window.set_resizable(gtk.FALSE)
self.window.set_position(gtk.WIN_POS_CENTER)
self.scale = 10
self.drawing_area = gtk.DrawingArea()
sc_width = gtk.gdk.screen_width()
while self.scale:
x, y = Segments.calc_size("##:##:##", self.scale)
if x+20 < sc_width:
break
self.scale -= 1
width = x + self.scale*4
height = y + self.scale*4
self.drawing_area.set_size_request(width, height)
self.drawing_area.connect("expose-event", self.area_expose_cb)
self.drawing_area.show()
self.window.add(self.drawing_area)
self.window.show()
gobject.timeout_add(1000, self.do_clock)
def area_expose_cb(self, area, event):
if not hasattr(self, "segments"):
self.drawer = gtkDrawer(area.window, area.get_colormap())
xoffset = self.scale*2
yoffset = self.scale*2
self.segments = Segments("##:##:##", "00:00:00", self.drawer,
self.scale, xoffset, yoffset)
w, h = self.drawer.drawable.get_size()
self.drawer.rect(0, 0, w, h, "#000000")
self.segments.redraw()
def delete_event(self, widget, event, data=None):
#print "delete_event occured"
return gtk.FALSE
def destroy(self, widget, date=None):
gtk.main_quit()
def do_clock(self):
if hasattr(self, "segments"):
self.segments.values = time.strftime("%H:%M:%S")
return True
def main_loop(self):
gtk.main()
app = APP()
app.main_loop()
Vielleicht hat ja wer lust, noch Beispiele für gt oder wxwidgets oder ... zu machen.
Gruß und gutes neues Jahr,
Dookie
Edit, kleine Änderungen am Code