终于开始Python学习之旅了,姑且以一个“画图板”小项目开始吧。放慢脚步,一点一点地学习。

1月28日更新  

  第一次遇到的麻烦便是“重绘”,查了好多资料,终于重绘成功了。

#-*- encoding: gbk -*
import wx """ this version use class 'PaintDC' and 'ClientDC' """ class MainFrame(wx.Frame): def __init__(self):
wx.Frame.__init__(self, None, -1, "画图板 - 芒果布丁", (0, 0), (800, 500))
self.Center(wx.BOTH) # 窗口居中显示
self.x1, self.x2, self.y1, self.y2 = 0, 0, 0, 0
self.st = 'line'
self.pos = (0,0)
self.pen = wx.Pen("green", 1, wx.SOLID)
self.brush = wx.Brush('', wx.TRANSPARENT) #透明填充
self.shapes = [] self.SetBackgroundColour("black")
self.b1 = wx.Button(self, -1, label="矩形", pos=(10, 10), size=(50, 30))
self.b2 = wx.Button(self, -1, label="圆形", pos=(10, 50), size=(50, 30))
self.b3 = wx.Button(self, -1, label="直线", pos=(10, 90), size=(50, 30)) self.b1.SetDefault() self.InitBuffer() self.Bind(wx.EVT_BUTTON, self.ToRect, self.b1)
self.Bind(wx.EVT_BUTTON, self.ToOval, self.b2)
self.Bind(wx.EVT_BUTTON, self.ToLine, self.b3) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_PAINT, self.OnPaint) def InitBuffer(self):
size = self.GetClientSize()
self.buffer = wx.EmptyBitmap(size.width, size.height)
dc = wx.BufferedDC(None, self.buffer)
dc.SetPen(self.pen)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.SetBrush(self.brush)
dc.Clear()
self.Draw(dc) def ToRect(self, event):
self.st = 'rect' def ToOval(self, event):
self.st = 'oval' def ToLine(self, event):
self.st = 'line' def OnLeftDown(self, event): self.p1 = event.GetPositionTuple()
self.x1, self.y1 = self.p1 def OnLeftUp(self, event):
self.p2 = event.GetPositionTuple()
self.shapes.append((self.st, self.p1 + self.p2))
dc = wx.ClientDC(self)
self.Draw(dc) def OnPaint(self, event):
dc = wx.PaintDC(self) # 处理一个paint(描绘)请求
self.Draw(dc) def Draw(self, dc):
dc.SetPen(self.pen)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.SetBrush(self.brush)
dc.Clear()
for st,(x1,y1,x2,y2) in self.shapes: if st == 'line':
dc.DrawLine(x1, y1, x2, y2)
elif st == 'oval':
dc.DrawEllipse(x1, y1, x2-x1, y2-y1)
elif st == 'rect':
dc.DrawRectangle(x1, y1, x2-x1, y2-y1) if __name__ =='__main__':
app = wx.PySimpleApp()
frame = MainFrame()
frame.Show()
app.MainLoop()

画图板 version1

#-*- encoding: gbk -*
import wx """ this version use class 'BufferedPaintDC' and 'BufferedDC' """ class MainFrame(wx.Frame): def __init__(self):
wx.Frame.__init__(self, None, -1, "画图板 - 芒果布丁", (0, 0), (800, 500))
self.Center(wx.BOTH) # 窗口居中显示
self.x1, self.x2, self.y1, self.y2 = 0, 0, 0, 0
self.st = 'line'
self.pos = (0,0)
self.pen = wx.Pen("green", 1, wx.SOLID)
self.brush = wx.Brush('', wx.TRANSPARENT) #透明填充
self.shapes = [] self.InitBuffer() self.SetBackgroundColour("black")
self.b1 = wx.Button(self, -1, label="矩形", pos=(10, 10), size=(50, 30))
self.b2 = wx.Button(self, -1, label="圆形", pos=(10, 50), size=(50, 30))
self.b3 = wx.Button(self, -1, label="直线", pos=(10, 90), size=(50, 30)) self.Bind(wx.EVT_BUTTON, self.ToRect, self.b1)
self.Bind(wx.EVT_BUTTON, self.ToOval, self.b2)
self.Bind(wx.EVT_BUTTON, self.ToLine, self.b3) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_PAINT, self.OnPaint) def InitBuffer(self):
size = self.GetClientSize()
self.buffer = wx.EmptyBitmap(size.width, size.height) def ToRect(self, event):
self.st = 'rect' def ToOval(self, event):
self.st = 'oval' def ToLine(self, event):
self.st = 'line' def OnLeftDown(self, event):
self.p1 = event.GetPositionTuple()
self.x1, self.y1 = self.p1 def OnLeftUp(self, event):
self.p2 = event.GetPositionTuple()
self.shapes.append((self.st, self.p1 + self.p2))
self.Draw() def OnPaint(self, event):
dc = wx.BufferedPaintDC(self, self.buffer) # 处理一个paint(描绘)请求 def Draw(self):
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
dc.SetPen(self.pen)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.SetBrush(self.brush)
dc.Clear()
for st,(x1,y1,x2,y2) in self.shapes:
if st == 'line':
dc.DrawLine(x1, y1, x2, y2)
elif st == 'oval':
dc.DrawEllipse(x1, y1, x2-x1, y2-y1)
elif st == 'rect':
dc.DrawRectangle(x1, y1, x2-x1, y2-y1) if __name__ =='__main__':
app = wx.PySimpleApp()
frame = MainFrame()
frame.Show()
app.MainLoop()

画图板 version2

  以上两种方法差别不大,第二种方法用buffer缓冲,据说可以消除画布闪烁,但第一种方法在没有缓冲的情况下也没有出现闪烁的情况。但是有必要对几个DC进行详细说明一下:

如何在屏幕上绘画

要在屏幕上绘画,我们要用到一个名为device context(设备上下文)的wxPython对象。设备上下文代表抽象的设备,它对于所有的设备有一套公用的绘画方法,所以对于不同的设备,你的代码是相同的,而不用考虑你所在的具体设备。设备上下文使用抽象的wxPython的类wx.DC和其子类来代表。由于wx.DC是抽象的,所以对于你的应用程序,你需要使用它的子类。

使用设备上下文

表6.1显示了wx.DC的子类及其用法。设备上下文用来在wxPython窗口部件上绘画,它应该是局部的,临时性的,不应该以实例变量、全局变量或其它形式在方法调用之间保留。在某些平台上,设备上下文是有限的资源,长期持有wx.DC可能导致你的程序不稳定。由于wxPython内部使用设备上下文的方式,对于在窗口部件中绘画,就存在几个有着细微差别的wx.DC的子类。第十二章将更详细地说明这些差别。

表6.1

wx.BufferedDC:用于缓存一套绘画命令,直到命令完整并准备在屏幕上绘画。这防止了显示中不必要的闪烁。

wx.BufferedPaintDC:和wx.BufferedDC一样,但是只能用在一个wx.PaintEvent的处理中。仅临时创建该类的实例。

wx.ClientDC:用于在一个窗口对象上绘画。当你想在窗口部件的主区域上(不包括边框或别的装饰)绘画时使用它。主区域有时也称为客户区。wx.ClientDC类也应临时创建。该类仅适用于wx.PaintEvent的处理之外。

wx.MemoryDC:用于绘制图形到内存中的一个位图中,此时不被显示。然后你可以选择该位图,并使用wx.DC.Blit()方法来把这个位图绘画到一个窗口中。

wx.MetafileDC:在Windows操作系统上,wx.MetafileDC使你能够去创建标准窗口图元文件数据。

wx.PaintDC:等同于wx.ClientDC,除了它仅用于一个wx.PaintEvent的处理中。仅临时创建该类的实例。

wx.PostScriptDC:用于写压缩的PostScript文件。

wx.PrinterDC:用于Windows操作系统上,写到打印机。

wx.ScreenDC:用于直接在屏幕上绘画,在任何被显示的窗口的顶部或外部。该类只应该被临时创建。

wx.WindowDC:用于在一个窗口对象的整个区域上绘画,包括边框以及那些没有被包括在客户区域中的装饰。非Windows系统可能不支持该类。

                                                 ——引自这个网站

  屏幕设备上下文是指临时创建的。这意味你无论你何时需要它们时只应该局部地创建它们,并且使它们能够被正常垃圾回收。你不应该试图以一个实例变量的形式占有一个设备上下文——这是不安全的,并可能导致程序的不稳定。

  通常,你会使用wx.ClientDC或wx.PaintDC来绘制到屏幕上的一个窗口。使用哪个取决于你执行绘制的时机。如果你在一个EVT_PAINT事件处理期间绘制到屏幕,那么你必须使用wx.PaintDC。在其它的时间,你必须使用wx.ClientDC。实际上,无论你何时绑定一个处理器到EVT_PAINT事件,你都必须在该处理器方法中创建一个wx.PaintDC对象,即使你不使用它(不创建一个wx.PaintDC会导致平台认为该事件并未完全处理,并因此会发送另一个事件)。描绘(paint)事件要求不同的设备上下文的原因是,这个wx.PaintDC实例是被优化来只在重绘事件期间的窗口刷新区域中进行绘制的,以便重绘更快。

  屏幕设备上下文是指临时创建的。这意味你无论你何时需要它们时只应该局部地创建它们,并且使它们能够被正常垃圾回收。你不应该试图以一个实例变量的形式占有一个设备上下文——这是不安全的,并可能导致程序的不稳定。

  通常,你会使用wx.ClientDC或wx.PaintDC来绘制到屏幕上的一个窗口。使用哪个取决于你执行绘制的时机。如果你在一个EVT_PAINT事件处理期间绘制到屏幕,那么你必须使用wx.PaintDC。在其它的时间,你必须使用wx.ClientDC。实际上,无论你何时绑定一个处理器到EVT_PAINT事件,你都必须在该处理器方法中创建一个wx.PaintDC对象,即使你不使用它(不创建一个wx.PaintDC会导致平台认为该事件并未完全处理,并因此会发送另一个事件)。描绘(paint)事件要求不同的设备上下文的原因是,这个wx.PaintDC实例是被优化来只在重绘事件期间的窗口刷新区域中进行绘制的,以便重绘更快。

  你可以经由一个简单的构造函数来创建一个客户区(client)或描绘(paint)上下文,构造函数的一个参数是你希望在其上进行绘制的wxPython窗口部件,两者的构造函数分别是wx.ClientDC(window)和wx.PaintDC(window)。当你使用这两个上下文时,你将只能在该窗口部件的客户区中进行绘制。这意味在一个框架中,你不能在边框、标题栏或其它装饰物上进行绘制。

  如果你需要在框架的整个区域上进行绘制,包括边框和装饰物,那么你应该使用wx.WindowDC。创建一个wx.WindowDC的方法和wx.ClientDC相似,相应的构造函数是wx.WindowDC(window)。和wx.ClientDC一样,你不应该在一个描绘(paint)事件期间创建一个wx.WindowDC——边框绘制行为与描绘(paint)设备上下文的局部优化是不兼容的。

  有时,你不愿被限制于只绘制到一个单一的窗口,你想让整个屏幕作为你的画布。在这种情况下,你可以使用wx.ScreenDC。同样地,你不能在一描绘(paint)事件期间创建它。这个构造函数没有参数(因为你不需要再指定绘制到的对象)——wx.ScreenDC()。创建了一个wx.ScreenDC之后,你就可以像使用其它的设备上下文一样使用它了。你绘制的图像将显示在你的显示器中的所有的窗口的上层。

  缓冲使你能够发送单独的绘制命令到缓冲区,然后一次性地把它们绘制到屏幕。当你一下做几个重绘时,这防止了屏幕的闪烁。因此,当做动画或其它屏幕密集绘制时,缓冲是一个常见的技术。

  在wxPython中有两个缓冲设备上下文——wx.BufferedDC,它可被用于缓冲任何的设备上下文(但是通常只用于wx.ClientDC);wx.BufferedPaintDC,它专门被设计用来缓冲一个wx.PaintDC。作为内存设备上下文的一个简单包装,这两个缓冲上下文的工作方式基本上是一样。wxBufferedDC的构造函数要求一个设备上下文和一个可选的位图作为参数——wx.BufferedDC(dc, buffer=None)。另一方面,wx.BufferedPaintDC要求一个窗口和一个可选的位图作为参数——wx.BufferedPaintDC(dc, buffer=None)。参数dc是最终你想要绘制到的设备上下文,对于wx.BufferedPaintDC,窗口参数被用于内在地创建一个wx.PaintDC,buffer参数是一个位图,它被作为临时的缓冲。如果buffer参数没有指定,那么该设备上下文内在地创建它自己的位图。一旦缓冲设备上下文被创建,你就可以像其它的设备上下文样使用它。在内部,缓冲上下文使用一个内存设备上下文和该位图来储存绘制。这样的捷径就是你不需要做任何特别的事来得到缓冲以绘制到实际的设备上下文。当缓冲设备上下文被垃圾回收时(通常当该方法结束且它已经退出作用域时),C++销毁函数触发Blit(),这将绘制缓冲区的内容到实际的设备上下文,而没有更多的工作需要你做

                                                 ——引自这个网址

  用缓冲的方式的重绘部分为什么OnPaint方法只是定义一个BufferedPaintDC即可?

  对于所有的显示要求,都将产生wx.EVT_PAINT事件(描绘事件),并调用我们这里的方法OnPaint进行屏幕刷新(重绘),你可以看到这是出乎意料的简单:创建一个缓存的画图设备上下文。实际上wx.PaintDC被创建(因为我们处在一个Paint请求里,所以我们需要wx.PaintDC而非一个wx.ClientDC实例),然后在dc实例被删除后(函数返回时被销毁),位图被一块块地传送(blit)给屏幕并最终显示。关于缓存的更详细的信息将在随后的段落中提供。

                                                        

 1月31日大年初一更新

  这个版本主要更新了鼠标随动绘画并修正了一些bug。

#-*- encoding: gbk -*
import wx """ this version use class 'BufferedPaintDC' and 'BufferedDC' """ class MainFrame(wx.Frame): def __init__(self):
wx.Frame.__init__(self, None, -1, "画图板 - 芒果布丁", (0, 0), (800, 500))
self.Center(wx.BOTH) # 窗口居中显示
self.x1, self.x2, self.y1, self.y2 = 0, 0, 0, 0
self.st = 'line'
self.pos = (0,0)
self.pen = wx.Pen("green", 1, wx.SOLID)
self.brush = wx.Brush('', wx.TRANSPARENT) #透明填充
self.shapes = [] self.SetBackgroundColour("black")
self.b1 = wx.Button(self, -1, label="矩形", pos=(10, 10), size=(50, 30))
self.b2 = wx.Button(self, -1, label="圆形", pos=(10, 50), size=(50, 30))
self.b3 = wx.Button(self, -1, label="直线", pos=(10, 90), size=(50, 30)) self.b1.SetDefault() self.InitBuffer() self.Bind(wx.EVT_BUTTON, self.ToRect, self.b1)
self.Bind(wx.EVT_BUTTON, self.ToOval, self.b2)
self.Bind(wx.EVT_BUTTON, self.ToLine, self.b3) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_MOTION, self.OnMotion) def InitBuffer(self):
size = self.GetClientSize()
self.buffer = wx.EmptyBitmap(size.width, size.height)
dc = wx.BufferedDC(None, self.buffer)
dc.SetPen(self.pen)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.SetBrush(self.brush)
dc.Clear()
self.Draw(dc) def ToRect(self, event):
self.st = 'rect' def ToOval(self, event):
self.st = 'oval' def ToLine(self, event):
self.st = 'line' def OnLeftDown(self, event):
self.p1 = event.GetPositionTuple()
self.x1, self.y1 = self.p1
self.CaptureMouse()#6 捕获鼠标 def OnMotion(self, event):
if event.Dragging() and event.LeftIsDown():#8 确定是否在拖动
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)#9 创建另一个缓存的上下文
self.drawMotion(dc, event)
event.Skip() def drawMotion(self, dc, event):
self.p2 = event.GetPositionTuple()
self.shapes.append((self.st, self.p1 + self.p2))
self.InitBuffer()
self.shapes.pop(len(self.shapes)-1) def OnLeftUp(self, event):
self.p2 = event.GetPositionTuple()
self.shapes.append((self.st, self.p1 + self.p2))
self.InitBuffer()
self.ReleaseMouse()#7 释放鼠标 def OnPaint(self, event):
dc = wx.BufferedPaintDC(self, self.buffer) # 处理一个paint(描绘)请求 def Draw(self, dc):
for st,(x1,y1,x2,y2) in self.shapes: if st == 'line':
dc.DrawLine(x1, y1, x2, y2)
elif st == 'oval':
dc.DrawEllipse(x1, y1, x2-x1, y2-y1)
elif st == 'rect':
dc.DrawRectangle(x1, y1, x2-x1, y2-y1)
#self.Refresh() # 不能手动刷新 会闪烁 if __name__ =='__main__':
app = wx.PySimpleApp()
frame = MainFrame()
frame.Show()
app.MainLoop()

画图板 version3

#6:CaptureMouse()方法控制了鼠标并在窗口的内部捕获鼠标,即使是你拖动鼠标到窗口边框的外面,它仍然只响应窗口内的鼠标动作,也就是说当画一个图形并将鼠标移到了窗口外,当前图形也有效并被画在屏幕上。在程序的后面必须调用ReleaseMouse()来取消其对鼠标的控制。否则该窗口将无法通过鼠标关闭等,试将#7注释掉。

 2月11日 更新

  这个版本添加了菜单功能、菜单事件、图片打开功能。

#-*- encoding: gbk -*
import wx
import os """ this version use class 'BufferedPaintDC' and 'BufferedDC' """ class MainFrame(wx.Frame): def __init__(self):
wx.Frame.__init__(self, None, -1, "画图板 - 芒果布丁", (0, 0), (800, 500))
self.Center(wx.BOTH) # 窗口居中显示
self.x1, self.x2, self.y1, self.y2 = 0, 0, 0, 0
self.iscaptured = -1
self.p1 = (0, 0)
self.p2 = (0, 0)
self.st = 'line'
self.pos = (0,0)
self.pen = wx.Pen("green", 1, wx.SOLID)
self.img = None
self.brush = wx.Brush('', wx.TRANSPARENT) #透明填充
self.shapes = [] self.SetBackgroundColour("black")
self.b1 = wx.Button(self, -1, label="矩形", pos=(10, 10), size=(50, 30))
self.b2 = wx.Button(self, -1, label="圆形", pos=(10, 50), size=(50, 30))
self.b3 = wx.Button(self, -1, label="直线", pos=(10, 90), size=(50, 30)) self.b1.SetDefault() self.InitBuffer() self.Bind(wx.EVT_BUTTON, self.ToRect, self.b1)
self.Bind(wx.EVT_BUTTON, self.ToOval, self.b2)
self.Bind(wx.EVT_BUTTON, self.ToLine, self.b3) self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_MOTION, self.OnMotion) self.SetMenuBar(self.getMenu()) def InitBuffer(self):
size = self.GetClientSize()
mm = wx.DisplaySize() # 获取屏幕大小
self.buffer = wx.EmptyBitmap(mm[0], mm[1])
dc = wx.BufferedDC(None, self.buffer)
dc.SetPen(self.pen)
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.SetBrush(self.brush)
dc.Clear()
self.Draw(dc) def ToRect(self, event):
self.st = 'rect' def ToOval(self, event):
self.st = 'oval' def ToLine(self, event):
self.st = 'line' def OnLeftDown(self, event):
self.p1 = event.GetPositionTuple()
self.x1, self.y1 = self.p1
self.CaptureMouse()#6 捕获鼠标
self.iscaptured = 1 def OnLeftUp(self, event):
if self.iscaptured == 1:
self.ReleaseMouse()#7 释放鼠标
self.p2 = event.GetPositionTuple()
self.shapes.append((self.st, self.p1 + self.p2))
self.InitBuffer()
self.iscaptured = 0 def OnMotion(self, event):
if event.Dragging() and event.LeftIsDown():#8 确定是否在拖动
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)#9 创建另一个缓存的上下文
self.drawMotion(dc, event)
event.Skip() def drawMotion(self, dc, event):
if self.iscaptured == 1:
self.p2 = event.GetPositionTuple()
self.shapes.append((self.st, self.p1 + self.p2))
self.InitBuffer()
self.shapes.pop(len(self.shapes)-1) def OnPaint(self, event):
wx.BufferedPaintDC(self, self.buffer) # 处理一个paint(描绘)请求 def Draw(self, dc): if self.img != None:
dc.DrawBitmap(self.img, 0, 0, False)
print len(self.shapes)
for st,(x1,y1,x2,y2) in self.shapes:
print x1, y1, x2, y2
if st == 'line':
dc.DrawLine(x1, y1, x2, y2)
elif st == 'oval':
dc.DrawEllipse(x1, y1, x2-x1, y2-y1)
elif st == 'rect':
dc.DrawRectangle(x1, y1, x2-x1, y2-y1) def getMenu(self):
menuBar = wx.MenuBar() menu = wx.Menu()
m11 = menu.Append(-1, "新建")
self.Bind(wx.EVT_MENU, self.newFile, m11)
m12 = menu.Append(-1, "打开")
self.Bind(wx.EVT_MENU, self.openFile, m12)
m13 = menu.Append(-1, "保存") menu.AppendSeparator()
exit = menu.Append(-1, "退出")
menuBar.Append(menu, "文件") menu2 = wx.Menu()
menu2.Append(-1, "撤销")
menu2.Append(-1, "清除")
menuBar.Append(menu2, "编辑") menu3 = wx.Menu()
menuBar.Append(menu3, "图像") menu4 = wx.Menu()
menuBar.Append(menu4, "帮助")
return menuBar def newFile(self, event):
pass def openFile(self, event):
wildcard = "JPEG 图片 (*.jpg)|*.jpg|" \
"PNG 图片 (*.png)|*.png|" \
"BMP 图片 (*.bmp)|*.bmp|" \
"All files (*.*)|*.*"
dialog = wx.FileDialog(None, "选择一个文件", os.getcwd(), "", wildcard, wx.OPEN)
if dialog.ShowModal() == wx.ID_OK:
name = dialog.GetPath()
print dialog.GetPath()
jpg = wx.Image(name, wx.BITMAP_TYPE_ANY).ConvertToBitmap()
self.img = jpg
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
dc.DrawBitmap(jpg, 0, 0, False) if __name__ =='__main__':
app = wx.PySimpleApp()
frame = MainFrame()
frame.Show()
app.MainLoop()

画图板 version4

 3月19日 更新

  这个版本添加了图片保存功能。这个功能的实现是直接使用PIL的截图功能ImageGrab,代码异常简单。

import ImageGrab

rectangle = (x, y, x+w, y+h)
img = ImageGrab.grab(rectangle)
img.save("1.jpg", 'JPEG')

图片保存核心代码

  经过测试发现,虽然这个方法成功截图,但是图片质量会下降,变得稍微模糊。如果画的是纯图形(直线、矩形、圆等),可以直接保存端点坐标到文件,打开的时候读取端点重新画图形就能完美还原。

  

wxPython 画图板的更多相关文章

  1. iOS开发之画图板(贝塞尔曲线)

    贝塞尔曲线,听着挺牛气一词,不过下面我们在做画图板的时候就用到贝塞尔绘直线,没用到绘制曲线的功能.如果会点PS的小伙伴会对贝塞尔曲线有更直观的理解.这篇博文的重点不在于如何用使用贝塞尔曲线,而是利用贝 ...

  2. 很值得学习的java 画图板源码

    很值得学习的java 画图板源码下载地址:http://download.csdn.net/source/2371150 package minidrawpad; import java.awt.*; ...

  3. 【示例代码】HTML+JS 画图板源码分享

    一个有趣的画图板, 用了 HTML5中的本地存储.下载.canvas 等技术,这个项目中用到了canvas 的很多基础功能,初学者可以学习一下 . 建议开发童鞋使用统一开发环境UDE来进行查看.调试. ...

  4. Java版简易画图板的实现

    Windows的画图板相信很多人都用过,这次我们就来讲讲Java版本的简易画板的实现. 基本的思路是这样的:画板实现大致分三部分:一是画板界面的实现,二是画板的监听以及画图的实现,三是画板的重绘.(文 ...

  5. JAVA 画图板实现(基本画图功能+界面UI)二、功能实现及重绘实现

    上篇博客中介绍了界面的实现方法,在这篇博客中将对每个按钮的功能的实现进行讲解并介绍重绘 首先肯定要添加事件监听机制了,那么问题来了,事件源对象是谁?需要添加什么方法?事件接口是什么? 1.我们需要点击 ...

  6. JAVA 画图板实现(基本画图功能+界面UI)一、界面实现

    /*文章中用到的代码只是一部分,需要源码的可通过邮箱联系我 1978702969@qq.com*/ 这段时间在学JAVA的swing界面开发,试着做了个画图板.实现了直线.曲线.喷枪.矩形.圆形.文字 ...

  7. Java编写画图板程序细节-保存已画图形

    没有Java编写画图板程序细节-保存已画图形   一.为何我们要保存画图板上已画图形呢? 有很多人会问,为什么我们一定要保存画图板上已经画好了的图形呢?原因很简单.当我们在画图板上画完自己想画的图形后 ...

  8. Java 从零开始实现一个画图板、以及图像处理功能,代码可复现

    Java 从零开始实现一个画图板.以及图像处理功能,代码可复现 这是一个学习分享博客,带你从零开始实现一个画图板.图像处理的小项目,为了降低阅读难度,本博客将画图板的一步步迭代优化过程展示给读者,篇幅 ...

  9. H TML5 之 (5) 一个在线画图板

    这里加入了点难度了,增加了对HTML很多时间的把握,对象的把握 index.html <!DOCTYPE HTML> <html> <head> <title ...

随机推荐

  1. Endless Spin

    clj的题.图是假的别看 得先做这个[HAOI2015]按位或 本题如果还用[HAOI2015]按位或 的方法,2^50拜拜 但是思路一定是这样的:min-max容斥,考虑每个S的第一触及次数期望 这 ...

  2. move_base代码学习一

    System overview move_base 源码 API nav_core BaseGlobalPlanner BaseLocalPlanner RecoveryBehavior Recove ...

  3. Codeforces Round #385 (Div. 2)A B C 模拟 水 并查集

    A. Hongcow Learns the Cyclic Shift time limit per test 2 seconds memory limit per test 256 megabytes ...

  4. [大数据可视化]-saiku的源码包Bulid常见问题和jar包

    最近在做kylin+mondrian+saiku的二次开发的时候,Bulid saiku的源码出现了很多问题,基本上一大部分问题jar找不到问题,很多jar国内网站都找不到.这时候只有手动下载然后注册 ...

  5. Hbuider制作app升级包的简单办法 (升级官方提供的案例)

    源文档:http://ask.dcloud.net.cn/question/11795 http://ask.dcloud.net.cn/article/199 一.生成移动App资源升级包 5+应用 ...

  6. [DeeplearningAI笔记]序列模型2.8 GloVe词向量

    5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.8 GloVe word vectors GloVe词向量 Pennington J, Socher R, Mannin ...

  7. sourceTree的下载与安装

    一. SourceTree是什么? 一个拥有可视化界面的项目版本控制的软件,适用于git项目管理,在window和mac均可使用. 二. SourceTree下载 下载地址:SourceTree官网 ...

  8. Windows 安装 RabbitMQ

    RabbitMQ概述 RabbitMQ是流行的开源消息队列系统,是AMQP(Advanced Message Queuing Protocol高级消息队列协议)的标准实现,用erlang语言开发.Ra ...

  9. [洛谷P1709] [USACO5.5]隐藏口令Hidden Password

    洛谷题目链接:[USACO5.5]隐藏口令Hidden Password 题目描述 有时候程序员有很奇怪的方法来隐藏他们的口令.Binny会选择一个字符串S(由N个小写字母组成,5<=N< ...

  10. 动态内容的缓存技术:CSI vs SSI vs ESI

    CDN 中动态内容是不太好解决的,通常需要很麻烦的技术和方法来实现这些功能,比如我设计过一种动态缓存的方法,基于 session 栏接,然后根据热点来做动态缓存时间的控制.目前开放的实现 Cache ...