Site Sponsors:
Basic Subject Editor 
Building upon the techniques presented in our Graphical Command Line Editor, we decided to create a basic note-taking interface:



Here is the code:


#!/usr/bin/python3
from tkinter import *
from collections import OrderedDict
# Mission: Create a way to edit the subject & content of a message.

class EditorParams:
EDITBOX = "ZEDIT:"
def __init__(self, *fields):
self.params = OrderedDict()
for field in fields:
self.params[field] = ''
self.params[EditorParams.EDITBOX] = ''


class Editor:
def __init__(self):
self._dict = None
self._isOk = None
self.last_row = None
self.text = None
self.eparams = None

def _okay(self):
self._isOk = True
self.tk.quit()

def _cancel(self):
self._isOk = False
self.tk.quit()

@staticmethod
def Begin(eparams, title="Input"):
if not isinstance(eparams, EditorParams):
raise Exception("Begin: Instance of EditorParams expected.")

''' Create the frame, add the title, as well as the input fields.'''
self = Editor()
self.tk = Tk()

self.eparams = eparams
if self.eparams.params[EditorParams.EDITBOX] is None:
self.eparams.params[EditorParams.EDITBOX] = ""

self._dict = OrderedDict()

if title:
self.tk.title(title)

self.last_row = 0
# zFields (A Label, plus an Entry, in a grid layout)
for ref in self.eparams.params:
if ref == EditorParams.EDITBOX:
continue
obj = Label(master=self.tk, text=str(ref))
obj.grid(row=self.last_row, column=0)

if self.eparams.params[ref] is None:
self.eparams.params[ref] = ''

obj = Entry(master=self.tk, bd=5, width=50)
obj.grid(row=self.last_row, column=1)
obj.insert(0, self.eparams.params[ref])

self._dict[ref]=obj
self.last_row += 1
return self

@staticmethod
def End(prompter):
''' Add the closing edit area, buttons, center, and pack the Frame.'''
if prompter.last_row is None:
return False
if isinstance(prompter, Editor) is False:
return False

# zNotepad
bottom = Frame(prompter.tk)
bottom.grid(row=prompter.last_row, columnspan=2)
prompter.text = Text(bottom, height=25, width=50)
prompter.text.pack()
prompter.text.insert(END, prompter.eparams.params[EditorParams.EDITBOX])
prompter.last_row += 1

# zButtons (A Frame in the grid, plus the properly-centered pair of buttons)
bottom = Frame(prompter.tk)
bottom.grid(row=prompter.last_row, columnspan=2)
btn = Button(bottom, text="Okay", command=prompter._okay)
btn.pack(side=LEFT, pady=12)

btn = Button(bottom, text="Cancel", command=prompter._cancel)
btn.pack(side=RIGHT, padx=10)

# zCenter (Close enough to make no odds?)
width = prompter.tk.winfo_screenwidth()
height = prompter.tk.winfo_screenheight()
x = (width - prompter.tk.winfo_reqwidth()) / 2
y = (height - prompter.tk.winfo_reqheight()) / 2
prompter.tk.geometry("+%d+%d" % (x, y))

return True

def show(self):
from collections import OrderedDict
self.tk.mainloop()
try:
results = OrderedDict()
if self._isOk is not True:
return results

for ref in self._dict.keys():
results[ref] = (self._dict[ref]).get()
results[EditorParams.EDITBOX] = self.text.get("1.0", "end-1c")
return results
finally:
try:
self.tk.destroy()
except:
pass

@staticmethod
def Prompt(*fields, title="Input"):
''' Basic mission statement completed. '''
self = Editor.Begin(*fields, title=title)
if Editor.End(self) is False:
raise Exception("AddButtons: Unexpected Error.")
return self.show()


if __name__ == "__main__":
# Here is how we would use the Editor from a Console Program:
order = EditorParams("Preamble:", "Subject:")
order.params["Subject:"] = "of a modern ..."
order.params["Preamble:"] = "I am the very model ..."
order.params[EditorParams.EDITBOX] = "Python interface."
results = Editor.Prompt(order, title="Just Do It!")
if len(results) is 0:
print("Pressed Cancel - no values!")
else:
print("Pressed Okay - got values!")
for ref in results:
print(ref, results[ref])


New to this edition is the "Model View Controller" flavor, wherein we need to create + provide an EditorParams so as to support the mission statement (i.e. adding notes to a data record.)

Enjoy!

(NEW TODAY: Code now available on GitHub)


[ view entry ] ( 145 views )   |  permalink  |  related link
OpenSCAD ... and the True Type Font! 
We went looking to create a few 'logoed projects recently. Since printing text can be a problem in 3D (strange looking 'As, 'Os, 'Qs, etc.), for best results when hollow-rendering one should us a STENCIL font.



Sadly, far from being universally supported, at the moment modern operating systems never provide any type of stencil-family fonts.

Arriving to the rescue however, today we should note that OpenSCAD will allow us to 'import' a font for ourselves.

Here is an example of using a True Type Font (.ttf) with OpenSCAD:
line1="Randall Nagy";
line2="foo@bar.net";
line3="Soft9000.com";
border=12;

zlength = 10;

zscale = 4;
zscale2 = 7;
zscale3 = 8;

use </d_archive_static/Ttf_2016_002/allerta_stencil.ttf>

difference() {
$fn=32;
minkowski() {
union(){
cube([max(len(line1), len(line2), len(line3)) * zscale + border, zlength, 0.75], center=true);
if(line2||line3) {
translate([0,-15,0]) cube([max(len(line1),len(line2),len(line3))*zscale2+border,15,0.75], center=true);
}
if(line3) {
translate([0,-30,0]) cube([max(len(line1),len(line2),len(line3))*zscale3+border,15,0.75], center=true);
}
}
cylinder(r=3,h=1);
}

font_name = "Allerta";
zhi = 3;
szfont = 8;
union() {
linear_extrude(height = zhi, center=true)
text(line1, font = font_name, "center", size = szfont, valign="center", halign="center");
if(line2) {
translate([0,-15,0]) linear_extrude(height = zhi, center=true)
text(line2, font = font_name, "center", size = szfont, valign="center", halign="center");
}
if(line3) {
translate([0,-30,0]) linear_extrude(height = zhi, center=true)
text(line3, font = font_name, "center", size = szfont, valign="center", halign="center");
}
}
}

Sharing is caring!




[ view entry ] ( 345 views )   |  permalink  |  related link
Pythonic Content Generation & Yield-based Enumeration 
Very few jewels in Python's crown sparkle so brilliantly as the gem of Content Management.

Using 'with'


While ever-confusing to those who know another programming language, those interested in demonstrating genuine Pythonic mastery simply love to make their classes operate like they can "with files!"
        with open("/Projects.txt", "r") as fh:
line = fh.readline()
while len(line) is not 0:
row = line.split('|')
if len(row) is 2:
self._add(row[0], row[1])
line = fh.readline()

While tricky enough to get working properly, the key to using Python's 'with' keyword is understanding the meta-methods (or "magic methods") that are invoked beind the scenes:
    def  __enter__(self):
with open(self.projectFile, "r") as fh:
lines = fh.readlines()
for line in lines:
row = line.split('|')
if len(row) is 2:
self._add(row[0], row[1])
return self

def __exit__(self, type, value, tb):
self.files.clear()
return False


Using 'yield'


Of course once we have generated our content, what could be more Pythonic than to use Pythons 'yield' capability to serve-up your managed 'info?
    def enumerate(self):
for result in self.files:
yield result[0], result[1]


Real-World Example


The objective was to load file content every time its representational class was used:
""" Context manager designed to serve-up the script titles + file names
as present in an external text-file definition:

Projects.txt Example:

Common Header File | C:/Users/Randall/Desktop/ProdSet/NewGnuActivities/Module3000/Cpp3000d01s01p01/SloType/01_era_hpp
The File Header | C:/Users/Randall/Desktop/ProdSet/NewGnuActivities/Module3000/Cpp3000d01s01p01/SloType/02_file_hpp
The File Implementation | C:/Users/Randall/Desktop/ProdSet/NewGnuActivities/Module3000/Cpp3000d01s01p01/SloType/03_file_cpp
The Test Driver | C:/Users/Randall/Desktop/ProdSet/NewGnuActivities/Module3000/Cpp3000d01s01p01/SloType/04_main_cpp
The Make File | C:/Users/Randall/Desktop/ProdSet/NewGnuActivities/Module3000/Cpp3000d01s01p01/SloType/05_makefile
"""

class ProjectReader:

""" Project file content must be in the above format. """
def __init__(self, projectFile):
self.projectFile = projectFile
self.files = []

""" Internal array is emptied & filled on-demand. Needs to be private. """
def _add(self, title, file_name):
row = [title.strip(), file_name.strip()]
self.files.append(row)

""" Reload the project file each and every time we are asked to manage the File's content """
def __enter__(self):
with open(self.projectFile, "r") as fh:
lines = fh.readlines()
for line in lines:
row = line.split('|')
if len(row) is 2:
self._add(row[0], row[1])
return self

""" Enumerate through the Project File's content. """
def enumerate(self):
for result in self.files:
yield result[0], result[1]

""" Be sure to clean-up after any content-managed activity """
def __exit__(self, type, value, tb):
self.files.clear()
return False # Exceptions okay



if __name__ == "__main__":
with ProjectReader("./Projects.txt") as inst:
for title, file in inst.enumerate():
print (title, file, sep=' = ')

I hope you will find the example useful! -If this type of mastery is what you are looking for, then you can learn more on-line today.



[ view entry ] ( 338 views )   |  permalink  |  related link

| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Next> Last>>