Add doodle sample

This commit is contained in:
Robin Dunn
2019-04-12 16:29:53 -07:00
parent ce64eb025b
commit bfd7bd588b
12 changed files with 9238 additions and 0 deletions

3
.gitignore vendored
View File

@@ -63,3 +63,6 @@ mydbstub.py*
ubuntu-xenial-16.04-cloudimg-console.log
ubuntu-bionic-18.04-cloudimg-console.log
.pytest_cache
/samples/doodle/build
/samples/doodle/dist

View File

@@ -0,0 +1,61 @@
Recent changes for the SuperDoodle application
==============================================
This is not a real change-log, but rather serves as an example that goes
along with SuperDoodle's example of self-updating functionality. To see it
in action download and unzip either the Windows or Mac version of
SuperDoodle 1.0.0 from http://wxPython.org/software-update-test/. When you
run the 1.0.0 version there will be a "Check for Updates..." item on the
help menu that you can use to see how the self-updating UI works. The
application will download the latest version available, install it, and
will restart SuperDoodle for you. Be sure to check the version numbers in
the About dialog before and after the update so you can see that it is
changing. (That is the only real change in each of the application
updates.)
And now we return you to the totally fake change log, already in
progress...
Version 1.0.3
-------------
* A little of this, a little of that.
* Fixed the foozlehopper.
* Added a whatsamagigit
* There's a wocket in my pocket.
Version 1.0.2
-------------
* "I don't believe there's a power in the 'verse that can stop Kaylee
from being cheerful."
* "Ten percent of nuthin' is...let me do the math here...nuthin' into
nuthin'...carry the nuthin'..."
* "Well, what about you, Shepherd? How come you're flying about with us
brigands? I mean, shouldn't you be off bringing religiosity to the
Fuzzie-Wuzzies or some such?"
* "Do you know what the chain of command is here? It's the chain I go
get and beat you with to show you who's in command."
* "A man walks down the street in that hat, people know he's not afraid
of anything."
Version 1.0.1
-------------
* "Time is an illusion. Lunchtime doubly so."
* "The ships hung in the sky in much the same way that bricks don't."
* "Forty-two."
* "Reality is frequently inaccurate."
Version 1.0.0
-------------
* Initial release.

21
samples/doodle/README.txt Normal file
View File

@@ -0,0 +1,21 @@
Doodle
------
This little sample is a doodle application. It shows you how to draw
on a canvas, deal with mouse events, popup menus, update UI events,
and much more.
doodle.py A class for the main drawing window. You can also
run it directly to see just this window.
superdoodle.py Takes the DoodleWindow from doodle.py and puts it
in a more full featured application with a control
panel, and the ability to save and load doodles.
setup.py This sample also shows you how to make your
applications automatically self-update when new
releases are available. There is a bit of code in
the superdoodle module to use the softwareupdate
module from the library, but the real magic
happens here in the distutils setup module.

258
samples/doodle/doodle.py Normal file
View File

@@ -0,0 +1,258 @@
# doodle.py
"""
This module contains the DoodleWindow class which is a window that you
can do simple drawings upon.
"""
import wx
#----------------------------------------------------------------------
class DoodleWindow(wx.Window):
menuColours = { 100 : 'Black',
101 : 'Yellow',
102 : 'Red',
103 : 'Green',
104 : 'Blue',
105 : 'Purple',
106 : 'Brown',
107 : 'Aquamarine',
108 : 'Forest Green',
109 : 'Light Blue',
110 : 'Goldenrod',
111 : 'Cyan',
112 : 'Orange',
113 : 'Navy',
114 : 'Dark Grey',
115 : 'Light Grey',
}
maxThickness = 16
def __init__(self, parent, ID):
wx.Window.__init__(self, parent, ID, style=wx.NO_FULL_REPAINT_ON_RESIZE)
self.SetBackgroundColour("WHITE")
self.listeners = []
self.thickness = 1
self.SetColour("Black")
self.lines = []
self.pos = wx.Point(0,0)
self.MakeMenu()
self.InitBuffer()
self.SetCursor(wx.Cursor(wx.CURSOR_PENCIL))
# hook some mouse events
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
self.Bind(wx.EVT_MOTION, self.OnMotion)
# the window resize event and idle events for managing the buffer
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_IDLE, self.OnIdle)
# and the refresh event
self.Bind(wx.EVT_PAINT, self.OnPaint)
# When the window is destroyed, clean up resources.
self.Bind(wx.EVT_WINDOW_DESTROY, self.Cleanup)
def Cleanup(self, evt):
if hasattr(self, "menu"):
self.menu.Destroy()
del self.menu
def InitBuffer(self):
"""Initialize the bitmap used for buffering the display."""
size = self.GetClientSize()
self.buffer = wx.Bitmap(max(1,size.width), max(1,size.height))
dc = wx.BufferedDC(None, self.buffer)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
self.DrawLines(dc)
self.reInitBuffer = False
def SetColour(self, colour):
"""Set a new colour and make a matching pen"""
self.colour = colour
self.pen = wx.Pen(self.colour, self.thickness, wx.SOLID)
self.Notify()
def SetThickness(self, num):
"""Set a new line thickness and make a matching pen"""
self.thickness = num
self.pen = wx.Pen(self.colour, self.thickness, wx.SOLID)
self.Notify()
def GetLinesData(self):
return self.lines[:]
def SetLinesData(self, lines):
self.lines = lines[:]
self.InitBuffer()
self.Refresh()
def MakeMenu(self):
"""Make a menu that can be popped up later"""
menu = wx.Menu()
keys = list(self.menuColours.keys())
keys.sort()
for k in keys:
text = self.menuColours[k]
menu.Append(k, text, kind=wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU_RANGE, self.OnMenuSetColour, id=100, id2=200)
self.Bind(wx.EVT_UPDATE_UI_RANGE, self.OnCheckMenuColours, id=100, id2=200)
menu.Break()
for x in range(1, self.maxThickness+1):
menu.Append(x, str(x), kind=wx.ITEM_CHECK)
self.Bind(wx.EVT_MENU_RANGE, self.OnMenuSetThickness, id=1, id2=self.maxThickness)
self.Bind(wx.EVT_UPDATE_UI_RANGE, self.OnCheckMenuThickness, id=1, id2=self.maxThickness)
self.menu = menu
# These two event handlers are called before the menu is displayed
# to determine which items should be checked.
def OnCheckMenuColours(self, event):
text = self.menuColours[event.GetId()]
if text == self.colour:
event.Check(True)
event.SetText(text.upper())
else:
event.Check(False)
event.SetText(text)
def OnCheckMenuThickness(self, event):
if event.GetId() == self.thickness:
event.Check(True)
else:
event.Check(False)
def OnLeftDown(self, event):
"""called when the left mouse button is pressed"""
self.curLine = []
self.pos = event.GetPosition()
self.CaptureMouse()
def OnLeftUp(self, event):
"""called when the left mouse button is released"""
if self.HasCapture():
self.lines.append( (self.colour, self.thickness, self.curLine) )
self.curLine = []
self.ReleaseMouse()
def OnRightUp(self, event):
"""called when the right mouse button is released, will popup the menu"""
pt = event.GetPosition()
self.PopupMenu(self.menu, pt)
def OnMotion(self, event):
"""
Called when the mouse is in motion. If the left button is
dragging then draw a line from the last event position to the
current one. Save the coordinants for redraws.
"""
if event.Dragging() and event.LeftIsDown():
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
dc.SetPen(self.pen)
pos = event.GetPosition()
coords = (self.pos.x, self.pos.y, pos.x, pos.y)
self.curLine.append(coords)
dc.DrawLine(*coords)
self.pos = pos
def OnSize(self, event):
"""
Called when the window is resized. We set a flag so the idle
handler will resize the buffer.
"""
self.reInitBuffer = True
def OnIdle(self, event):
"""
If the size was changed then resize the bitmap used for double
buffering to match the window size. We do it in Idle time so
there is only one refresh after resizing is done, not lots while
it is happening.
"""
if self.reInitBuffer:
self.InitBuffer()
self.Refresh(False)
def OnPaint(self, event):
"""
Called when the window is exposed.
"""
# Create a buffered paint DC. It will create the real
# wx.PaintDC and then blit the bitmap to it when dc is
# deleted. Since we don't need to draw anything else
# here that's all there is to it.
dc = wx.BufferedPaintDC(self, self.buffer)
def DrawLines(self, dc):
"""
Redraws all the lines that have been drawn already.
"""
for colour, thickness, line in self.lines:
pen = wx.Pen(colour, thickness, wx.SOLID)
dc.SetPen(pen)
for coords in line:
dc.DrawLine(*coords)
# Event handlers for the popup menu, uses the event ID to determine
# the colour or the thickness to set.
def OnMenuSetColour(self, event):
self.SetColour(self.menuColours[event.GetId()])
def OnMenuSetThickness(self, event):
self.SetThickness(event.GetId())
# Observer pattern. Listeners are registered and then notified
# whenever doodle settings change.
def AddListener(self, listener):
self.listeners.append(listener)
def Notify(self):
for other in self.listeners:
other.Update(self.colour, self.thickness)
#----------------------------------------------------------------------
class DoodleFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Doodle Frame", size=(800,600),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
doodle = DoodleWindow(self, -1)
#----------------------------------------------------------------------
if __name__ == '__main__':
app = wx.App()
frame = DoodleFrame(None)
frame.Show(True)
app.MainLoop()

Binary file not shown.

BIN
samples/doodle/mondrian.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

8339
samples/doodle/sample.ddl Normal file

File diff suppressed because it is too large Load Diff

73
samples/doodle/setup.py Normal file
View File

@@ -0,0 +1,73 @@
#---------------------------------------------------------------------------
# This setup file serves as a model for how to structure your
# distutils setup files for making self-updating applications using
# Esky. When you run this script use
#
# python setup.py bdist_esky
#
# Esky will then use py2app or py2exe as appropriate to create the
# bundled application and also its own shell that will help manage
# doing the updates. See wx.lib.softwareupdate for the class you can
# use to add self-updates to your applications, and you can see how
# that code is used here in the superdoodle.py module.
#---------------------------------------------------------------------------
import sys, os
from esky import bdist_esky
from setuptools import setup
import version
# platform specific settings for Windows/py2exe
if sys.platform == "win32":
import py2exe
FREEZER = 'py2exe'
FREEZER_OPTIONS = dict(compressed = 0,
optimize = 0,
bundle_files = 3,
dll_excludes = ['MSVCP90.dll',
'mswsock.dll',
'powrprof.dll',
'USP10.dll',],
)
exeICON = 'mondrian.ico'
# platform specific settings for Mac/py2app
elif sys.platform == "darwin":
import py2app
FREEZER = 'py2app'
FREEZER_OPTIONS = dict(argv_emulation = False,
iconfile = 'mondrian.icns',
)
exeICON = None
# Common settings
NAME = "SuperDoodle"
APP = [bdist_esky.Executable("superdoodle.py",
gui_only=True,
icon=exeICON,
)]
DATA_FILES = [ 'mondrian.ico' ]
ESKY_OPTIONS = dict( freezer_module = FREEZER,
freezer_options = FREEZER_OPTIONS,
enable_appdata_dir = True,
bundle_msvcrt = True,
)
# Build the app and the esky bundle
setup( name = NAME,
scripts = APP,
version = version.VERSION,
data_files = DATA_FILES,
options = dict(bdist_esky=ESKY_OPTIONS),
)

View File

@@ -0,0 +1,434 @@
# superdoodle.py
"""
This module implements the SuperDoodle demo application. It takes the
DoodleWindow previously presented and reuses it in a much more
intelligent Frame. This one has a menu and a statusbar, is able to
save and reload doodles, clear the workspace, and has a simple control
panel for setting color and line thickness in addition to the popup
menu that DoodleWindow provides. There is also a nice About dialog
implmented using an wx.html.HtmlWindow.
"""
import sys
import os
from six.moves import cPickle as pickle
import wx
import wx.html
from wx.lib import buttons # for generic button classes
from doodle import DoodleWindow
from wx.lib.mixins.inspection import InspectionMixin
USE_SOFTWARE_UPDATE=False
if USE_SOFTWARE_UPDATE:
from wx.lib.softwareupdate import SoftwareUpdate
HERE = os.path.dirname(os.path.abspath(__file__))
if hasattr(sys, 'frozen') and sys.frozen:
HERE = os.path.dirname(os.path.abspath(sys.argv[0]))
#----------------------------------------------------------------------
# There are standard IDs for the menu items we need in this app, or we
# could have used wx.NewId() to autogenerate some new unique ID values
# instead.
idNEW = wx.ID_NEW
idOPEN = wx.ID_OPEN
idSAVE = wx.ID_SAVE
idSAVEAS = wx.ID_SAVEAS
idCLEAR = wx.ID_CLEAR
idEXIT = wx.ID_EXIT
idABOUT = wx.ID_ABOUT
class DoodleFrame(wx.Frame):
"""
A DoodleFrame contains a DoodleWindow and a ControlPanel and manages
their layout with a wx.BoxSizer. A menu and associated event handlers
provides for saving a doodle to a file, etc.
"""
title = "Do a doodle"
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, self.title, size=(800,600),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
self.SetIcon(wx.Icon(os.path.join(HERE, 'mondrian.ico')))
self.CreateStatusBar()
self.MakeMenu()
self.filename = None
self.doodle = DoodleWindow(self, -1)
cPanel = ControlPanel(self, -1, self.doodle)
# Create a sizer to layout the two windows side-by-side.
# Both will grow vertically, the doodle window will grow
# horizontally as well.
box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(cPanel, 0, wx.EXPAND)
box.Add(self.doodle, 1, wx.EXPAND)
# Tell the frame that it should layout itself in response to
# size events using this sizer.
self.SetSizer(box)
def SaveFile(self):
if self.filename:
data = self.doodle.GetLinesData()
f = open(self.filename, 'wb')
pickle.dump(data, f)
f.close()
def ReadFile(self):
if self.filename:
try:
f = open(self.filename, 'rb')
data = pickle.load(f)
f.close()
self.doodle.SetLinesData(data)
except pickle.UnpicklingError:
wx.MessageBox("%s is not a doodle file." % self.filename,
"oops!", style=wx.OK|wx.ICON_EXCLAMATION)
def MakeMenu(self):
# create the file menu
menu1 = wx.Menu()
# Using the "\tKeyName" syntax automatically creates a
# wx.AcceleratorTable for this frame and binds the keys to
# the menu items.
menu1.Append(idOPEN, "&Open\tCtrl-O", "Open a doodle file")
menu1.Append(idSAVE, "&Save\tCtrl-S", "Save the doodle")
menu1.Append(idSAVEAS, "Save &As", "Save the doodle in a new file")
menu1.AppendSeparator()
menu1.Append(idCLEAR, "&Clear", "Clear the current doodle")
menu1.AppendSeparator()
menu1.Append(idEXIT, "E&xit", "Terminate the application")
# and the help menu
menu2 = wx.Menu()
if hasattr(sys, 'frozen'):
item = menu2.Append(-1, "Check for Update...")
self.Bind(wx.EVT_MENU, self.OnMenuCheckForUpdate, item)
menu2.Append(idABOUT, "&About\tCtrl-H", "Display the gratuitous 'about this app' thingamajig")
# and add them to a menubar
menuBar = wx.MenuBar()
menuBar.Append(menu1, "&File")
menuBar.Append(menu2, "&Help")
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.OnMenuOpen, id=idOPEN)
self.Bind(wx.EVT_MENU, self.OnMenuSave, id=idSAVE)
self.Bind(wx.EVT_MENU, self.OnMenuSaveAs, id=idSAVEAS)
self.Bind(wx.EVT_MENU, self.OnMenuClear, id=idCLEAR)
self.Bind(wx.EVT_MENU, self.OnMenuExit, id=idEXIT)
self.Bind(wx.EVT_MENU, self.OnMenuAbout, id=idABOUT)
wildcard = "Doodle files (*.ddl)|*.ddl|All files (*.*)|*.*"
def OnMenuOpen(self, event):
dlg = wx.FileDialog(self, "Open doodle file...", os.getcwd(),
style=wx.FD_OPEN, wildcard = self.wildcard)
if dlg.ShowModal() == wx.ID_OK:
self.filename = dlg.GetPath()
self.ReadFile()
self.SetTitle(self.title + ' -- ' + self.filename)
dlg.Destroy()
def OnMenuSave(self, event):
if not self.filename:
self.OnMenuSaveAs(event)
else:
self.SaveFile()
def OnMenuSaveAs(self, event):
dlg = wx.FileDialog(self, "Save doodle as...", os.getcwd(),
style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
wildcard = self.wildcard)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPath()
if not os.path.splitext(filename)[1]:
filename = filename + '.ddl'
self.filename = filename
self.SaveFile()
self.SetTitle(self.title + ' -- ' + self.filename)
dlg.Destroy()
def OnMenuClear(self, event):
self.doodle.SetLinesData([])
self.SetTitle(self.title)
def OnMenuExit(self, event):
self.Close()
def OnMenuAbout(self, event):
dlg = DoodleAbout(self)
dlg.ShowModal()
dlg.Destroy()
def OnMenuCheckForUpdate(self, event):
wx.GetApp().CheckForUpdate(parentWindow=self)
#----------------------------------------------------------------------
class ControlPanel(wx.Panel):
"""
This class implements a very simple control panel for the DoodleWindow.
It creates buttons for each of the colours and thickneses supported by
the DoodleWindow, and event handlers to set the selected values. There is
also a little window that shows an example doodleLine in the selected
values. Nested sizers are used for layout.
"""
BMP_SIZE = 16
BMP_BORDER = 3
def __init__(self, parent, ID, doodle):
wx.Panel.__init__(self, parent, ID, style=wx.RAISED_BORDER)
numCols = 4
spacing = 4
btnSize = wx.Size(self.BMP_SIZE + 2*self.BMP_BORDER,
self.BMP_SIZE + 2*self.BMP_BORDER)
# Make a grid of buttons for each colour. Attach each button
# event to self.OnSetColour. The button ID is the same as the
# key in the colour dictionary.
self.clrBtns = {}
colours = doodle.menuColours
keys = list(colours.keys())
keys.sort()
cGrid = wx.GridSizer(cols=numCols, hgap=2, vgap=2)
for k in keys:
bmp = self.MakeBitmap(colours[k])
b = buttons.GenBitmapToggleButton(self, k, bmp, size=btnSize )
b.SetBezelWidth(1)
b.SetUseFocusIndicator(False)
self.Bind(wx.EVT_BUTTON, self.OnSetColour, b)
cGrid.Add(b, 0)
self.clrBtns[colours[k]] = b
self.clrBtns[colours[keys[0]]].SetToggle(True)
# Make a grid of buttons for the thicknesses. Attach each button
# event to self.OnSetThickness. The button ID is the same as the
# thickness value.
self.thknsBtns = {}
tGrid = wx.GridSizer(cols=numCols, hgap=2, vgap=2)
for x in range(1, doodle.maxThickness+1):
b = buttons.GenToggleButton(self, x, str(x), size=btnSize)
b.SetBezelWidth(1)
b.SetUseFocusIndicator(False)
self.Bind(wx.EVT_BUTTON, self.OnSetThickness, b)
tGrid.Add(b, 0)
self.thknsBtns[x] = b
self.thknsBtns[1].SetToggle(True)
# Make a colour indicator window, it is registerd as a listener
# with the doodle window so it will be notified when the settings
# change
ci = ColourIndicator(self)
doodle.AddListener(ci)
doodle.Notify()
self.doodle = doodle
# Make a box sizer and put the two grids and the indicator
# window in it.
box = wx.BoxSizer(wx.VERTICAL)
box.Add(cGrid, 0, wx.ALL, spacing)
box.Add(tGrid, 0, wx.ALL, spacing)
box.Add(ci, 0, wx.EXPAND|wx.ALL, spacing)
self.SetSizer(box)
self.SetAutoLayout(True)
# Resize this window so it is just large enough for the
# minimum requirements of the sizer.
box.Fit(self)
def MakeBitmap(self, colour):
"""
We can create a bitmap of whatever we want by simply selecting
it into a wx.MemoryDC and drawing on it. In this case we just set
a background brush and clear the dc.
"""
bmp = wx.Bitmap(self.BMP_SIZE, self.BMP_SIZE)
dc = wx.MemoryDC()
dc.SelectObject(bmp)
dc.SetBackground(wx.Brush(colour))
dc.Clear()
dc.SelectObject(wx.NullBitmap)
return bmp
def OnSetColour(self, event):
"""
Use the event ID to get the colour, set that colour in the doodle.
"""
colour = self.doodle.menuColours[event.GetId()]
if colour != self.doodle.colour:
# untoggle the old colour button
self.clrBtns[self.doodle.colour].SetToggle(False)
# set the new colour
self.doodle.SetColour(colour)
def OnSetThickness(self, event):
"""
Use the event ID to set the thickness in the doodle.
"""
thickness = event.GetId()
if thickness != self.doodle.thickness:
# untoggle the old thickness button
self.thknsBtns[self.doodle.thickness].SetToggle(False)
# set the new colour
self.doodle.SetThickness(thickness)
#----------------------------------------------------------------------
class ColourIndicator(wx.Window):
"""
An instance of this class is used on the ControlPanel to show
a sample of what the current doodle line will look like.
"""
def __init__(self, parent):
wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
self.SetBackgroundColour(wx.WHITE)
self.SetMinSize( (45, 45) )
self.colour = self.thickness = None
self.Bind(wx.EVT_PAINT, self.OnPaint)
def Update(self, colour, thickness):
"""
The doodle window calls this method any time the colour
or line thickness changes.
"""
self.colour = colour
self.thickness = thickness
self.Refresh() # generate a paint event
def OnPaint(self, event):
"""
This method is called when all or part of the window needs to be
redrawn.
"""
dc = wx.PaintDC(self)
if self.colour:
sz = self.GetClientSize()
pen = wx.Pen(self.colour, self.thickness)
dc.SetPen(pen)
dc.DrawLine(10, sz.height/2, sz.width-10, sz.height/2)
#----------------------------------------------------------------------
class DoodleAbout(wx.Dialog):
""" An about box that uses an HTML window """
text = '''
<html>
<body bgcolor="#ACAA60">
<center><table bgcolor="#455481" width="100%%" cellspacing="0"
cellpadding="0" border="1">
<tr>
<td align="center"><h1>SuperDoodle %s</h1></td>
</tr>
</table>
</center>
<p><b>SuperDoodle</b> is a demonstration program for <b>wxPython</b> that
will hopefully teach you a thing or two. Just follow these simple
instructions: </p>
<p>
<ol>
<li><b>Read</b> the Source...
<li><b>Learn</b>...
<li><b>Do!</b>
</ol>
<p><b>SuperDoodle</b> and <b>wxPython</b> are brought to you by
<b>Robin Dunn</b> and <b>Total Control Software</b>, Copyright
&copy; 1997-2011.</p>
</body>
</html>
'''
def __init__(self, parent):
wx.Dialog.__init__(self, parent, -1, 'About SuperDoodle',
size=(420, 380) )
html = wx.html.HtmlWindow(self, -1)
import version
html.SetPage(self.text % version.VERSION)
button = wx.Button(self, wx.ID_OK, "Okay")
# constraints for the html window
lc = wx.LayoutConstraints()
lc.top.SameAs(self, wx.Top, 5)
lc.left.SameAs(self, wx.Left, 5)
lc.bottom.SameAs(button, wx.Top, 5)
lc.right.SameAs(self, wx.Right, 5)
html.SetConstraints(lc)
# constraints for the button
lc = wx.LayoutConstraints()
lc.bottom.SameAs(self, wx.Bottom, 5)
lc.centreX.SameAs(self, wx.CentreX)
lc.width.AsIs()
lc.height.AsIs()
button.SetConstraints(lc)
self.SetAutoLayout(True)
self.Layout()
self.CentreOnParent(wx.BOTH)
#----------------------------------------------------------------------
#----------------------------------------------------------------------
if not USE_SOFTWARE_UPDATE:
SoftwareUpdate = object
class DoodleApp(wx.App, InspectionMixin, SoftwareUpdate):
def OnInit(self):
if USE_SOFTWARE_UPDATE:
BASEURL='http://wxPython.org/software-update-test/'
self.InitUpdates(BASEURL,
BASEURL + 'ChangeLog.txt',
icon=wx.Icon(os.path.join(HERE, 'mondrian.ico')))
self.Init() # for InspectionMixin
frame = DoodleFrame(None)
frame.Show(True)
self.SetTopWindow(frame)
self.SetAppDisplayName('SuperDoodle')
return True
#----------------------------------------------------------------------
if __name__ == '__main__':
app = DoodleApp(redirect=False)
app.MainLoop()

View File

@@ -0,0 +1,48 @@
# -*- mode: python -*-
#
# This is a spec file for PyInstaller. To make a binary distribution of the
# superdoodle application run a command like this:
#
# pyinstaller superdoodle.spec
#
# And then look in the ./dist folder for the results
#
block_cipher = None
a = Analysis(['superdoodle.py'],
pathex=['.'],
binaries=[],
datas=[('mondrian.ico', '.')],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
[],
exclude_binaries=True,
name='superdoodle',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
console=False )
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name='superdoodle')
app = BUNDLE(coll,
name='superdoodle.app',
icon='mondrian.icns',
bundle_identifier=None)

BIN
samples/doodle/tmp.ddl Normal file

Binary file not shown.

View File

@@ -0,0 +1 @@
VERSION='1.0.3'