如何使用wxpython判断剪贴板中的bmp图片是否相同?
How to judge bmp pictures from clipboard whether they are same using wxpython?
我想实现的功能:
从剪贴板获取的bmp图片改变时,刷新window。否则什么都不做。
我遇到的问题:
每次我的程序进入 UpdateMsgShownArea() 函数时,self.oldBmp 将与 self.bmp 不同,但如果它们不同,我已经让 self.oldBmp = self.bmp,并打印“111111”。下一次程序进入 UpdateMsgShownArea() 时,self.oldBmp 将再次与 self.bmp 不同。这让我很困惑。
代码如下:
#!/usr/bin/env python
import wx
import os, sys
#----------------------------------------------------------------------------
# main window
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(600,480))
self.panel = MyPanel(self)
self.CreateStatusBar() # A StatusBar in the bottom of the window
# Setting up the menu.
filemenu= wx.Menu()
# wx.ID_ABOUT and wx.ID_EXIT are standard ids provided by wxWidgets.
menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
# Set events.
self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
self.Show(True)
def OnAbout(self,e):
# A message dialog box with an OK button. wx.OK is a standard ID in wxWidgets.
dlg = wx.MessageDialog( self, "A small text editor", "About Sample Editor", wx.OK)
dlg.ShowModal() # Show it
dlg.Destroy() # finally destroy it when finished.
def OnExit(self,e):
self.Close(True) # Close the frame.
#----------------------------------------------------------------------------
# main panel
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
# shared path boxsizer, DirPickerCtrl is alternative and better realization for textCtrl + btn
sharedPathStaticText = wx.StaticText(self, -1, 'Shared Dir:')
self.sharedPathTextCtrl = wx.TextCtrl(self, -1, 'Please choose a dir', style = wx.TE_READONLY|wx.TE_RICH)
sharedPathBtn = wx.Button(self, -1, 'Browse', name = 'Shared dir button')
box1 = wx.BoxSizer(wx.HORIZONTAL)
box1.Add(sharedPathStaticText, 0, wx.ALIGN_CENTER)
box1.Add(self.sharedPathTextCtrl, 1, wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT, 5) # proportion = 1, border = 5
box1.Add(sharedPathBtn, 0)
self.Bind(wx.EVT_BUTTON, self.OnOpen, sharedPathBtn)
# local path boxsizer
localPathStaticText = wx.StaticText(self, -1, 'Local Dir: ')
self.localPathTextCtrl = wx.TextCtrl(self, -1, 'Please choose a dir', style = wx.TE_READONLY|wx.TE_RICH)
localPathBtn = wx.Button(self, -1, 'Browse', name = 'local dir button')
box2 = wx.BoxSizer(wx.HORIZONTAL)
box2.Add(localPathStaticText, 0, wx.ALIGN_CENTER)
box2.Add(self.localPathTextCtrl, 1, wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT, 5) # proportion = 1, border = 5
box2.Add(localPathBtn, 0)
self.Bind(wx.EVT_BUTTON, self.OnOpen, localPathBtn)
# message show area
messageShowStaticText = wx.StaticText(self, -1, 'Sync info shown area: ')
box5 = wx.BoxSizer(wx.HORIZONTAL)
box5.Add(messageShowStaticText, 0, wx.ALIGN_LEFT)
# size (200,200) don't take effect
#msgShowAreaID = wx.NewId()
#print msgShowAreaID
self.msgShowArea = wx.ScrolledWindow(self, -1, size = (200,200), style = wx.SIMPLE_BORDER)
box3 = wx.BoxSizer(wx.HORIZONTAL)
box3.Add(self.msgShowArea, 1, wx.ALIGN_CENTER, 10)
# sync ctrl buttons
stopSyncBtn = wx.Button(self, -1, 'Stop Sync', name = 'Stop Sync button')
resumeSyncBtn = wx.Button(self, -1, 'Resume Sync', name = 'Resume Sync button')
box4 = wx.BoxSizer(wx.HORIZONTAL)
box4.Add(stopSyncBtn, 0, wx.ALIGN_CENTER|wx.RIGHT, 20)
box4.Add(resumeSyncBtn, 0, wx.ALIGN_CENTER|wx.LEFT, 20)
# sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(box1, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box2, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box5, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box3, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box4, 0, wx.ALIGN_CENTER, 10)
self.SetSizer(sizer)
self.SetAutoLayout(True)
# clipboard
self.clip = wx.Clipboard()
self.x = wx.BitmapDataObject()
self.bmp = None
self.oldBmp = None
self.msgShowArea.Bind(wx.EVT_IDLE, self.UpdateMsgShownArea)
self.msgShowArea.Bind(wx.EVT_PAINT, self.OnPaint)
def OnOpen(self, e):
""" Open a file"""
button = e.GetEventObject()
dlg = wx.DirDialog(self, "Choose a dir", "", wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
if button.GetName() == 'Shared dir button':
self.sharedPathTextCtrl.SetValue(path)
if button.GetName() == 'local dir button':
self.localPathTextCtrl.SetValue(path)
dlg.Destroy()
def UpdateMsgShownArea(self, e):
print "UpdateMsgShownArea"
self.clip.Open()
self.clip.GetData(self.x)
self.clip.Close()
self.bmp = self.x.GetBitmap()
if self.oldBmp == self.bmp:
print "same pic"
return
else:
print "diff pic"
self.oldBmp = self.bmp
if self.oldBmp == self.bmp:
print "111111"
else:
print "222222"
print "abcd"
#self.Refresh()
#self.msgShowArea.Refresh()
def OnPaint(self, evt):
if self.bmp:
dc = wx.PaintDC(self.msgShowArea)
dc.DrawBitmap(self.bmp, 20, 20, True)
#----------------------------------------------------------------------------
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame(None, "EasySync")
app.MainLoop()
不幸的是,wxWidgets 不支持剪贴板更改通知。在 MSW 下添加它会相对简单,但我不太确定其他平台。
无论如何,现在您唯一的选择是轮询剪贴板的更改,即设置一个计时器并在每次触发时检查剪贴板内容。这很丑陋且效率低下,但应该有效。
将位图转换为图像,然后比较图像可以解决这个问题。
self.clip.GetData(self.bmpObj)
self.bmp = self.bmpObj.GetBitmap() # bitmap
self.Img = self.bmp.ConvertToImage().GetData() # convert bmp to image
isDrawBmp = True
if CLIP_TYPE_IMAGE == self.lastClipType:
if self.oldImg == self.Img: # compare images
#print "same pic"
#return
isDrawBmp = False
else:
#print "diff pic"
self.oldImg = self.Img
else:
self.oldImg = self.Img
我想实现的功能: 从剪贴板获取的bmp图片改变时,刷新window。否则什么都不做。
我遇到的问题: 每次我的程序进入 UpdateMsgShownArea() 函数时,self.oldBmp 将与 self.bmp 不同,但如果它们不同,我已经让 self.oldBmp = self.bmp,并打印“111111”。下一次程序进入 UpdateMsgShownArea() 时,self.oldBmp 将再次与 self.bmp 不同。这让我很困惑。
代码如下:
#!/usr/bin/env python
import wx
import os, sys
#----------------------------------------------------------------------------
# main window
class MyFrame(wx.Frame):
def __init__(self, parent, title):
wx.Frame.__init__(self, parent, title=title, size=(600,480))
self.panel = MyPanel(self)
self.CreateStatusBar() # A StatusBar in the bottom of the window
# Setting up the menu.
filemenu= wx.Menu()
# wx.ID_ABOUT and wx.ID_EXIT are standard ids provided by wxWidgets.
menuAbout = filemenu.Append(wx.ID_ABOUT, "&About"," Information about this program")
menuExit = filemenu.Append(wx.ID_EXIT,"E&xit"," Terminate the program")
# Creating the menubar.
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File") # Adding the "filemenu" to the MenuBar
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
# Set events.
self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
self.Show(True)
def OnAbout(self,e):
# A message dialog box with an OK button. wx.OK is a standard ID in wxWidgets.
dlg = wx.MessageDialog( self, "A small text editor", "About Sample Editor", wx.OK)
dlg.ShowModal() # Show it
dlg.Destroy() # finally destroy it when finished.
def OnExit(self,e):
self.Close(True) # Close the frame.
#----------------------------------------------------------------------------
# main panel
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
# shared path boxsizer, DirPickerCtrl is alternative and better realization for textCtrl + btn
sharedPathStaticText = wx.StaticText(self, -1, 'Shared Dir:')
self.sharedPathTextCtrl = wx.TextCtrl(self, -1, 'Please choose a dir', style = wx.TE_READONLY|wx.TE_RICH)
sharedPathBtn = wx.Button(self, -1, 'Browse', name = 'Shared dir button')
box1 = wx.BoxSizer(wx.HORIZONTAL)
box1.Add(sharedPathStaticText, 0, wx.ALIGN_CENTER)
box1.Add(self.sharedPathTextCtrl, 1, wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT, 5) # proportion = 1, border = 5
box1.Add(sharedPathBtn, 0)
self.Bind(wx.EVT_BUTTON, self.OnOpen, sharedPathBtn)
# local path boxsizer
localPathStaticText = wx.StaticText(self, -1, 'Local Dir: ')
self.localPathTextCtrl = wx.TextCtrl(self, -1, 'Please choose a dir', style = wx.TE_READONLY|wx.TE_RICH)
localPathBtn = wx.Button(self, -1, 'Browse', name = 'local dir button')
box2 = wx.BoxSizer(wx.HORIZONTAL)
box2.Add(localPathStaticText, 0, wx.ALIGN_CENTER)
box2.Add(self.localPathTextCtrl, 1, wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT, 5) # proportion = 1, border = 5
box2.Add(localPathBtn, 0)
self.Bind(wx.EVT_BUTTON, self.OnOpen, localPathBtn)
# message show area
messageShowStaticText = wx.StaticText(self, -1, 'Sync info shown area: ')
box5 = wx.BoxSizer(wx.HORIZONTAL)
box5.Add(messageShowStaticText, 0, wx.ALIGN_LEFT)
# size (200,200) don't take effect
#msgShowAreaID = wx.NewId()
#print msgShowAreaID
self.msgShowArea = wx.ScrolledWindow(self, -1, size = (200,200), style = wx.SIMPLE_BORDER)
box3 = wx.BoxSizer(wx.HORIZONTAL)
box3.Add(self.msgShowArea, 1, wx.ALIGN_CENTER, 10)
# sync ctrl buttons
stopSyncBtn = wx.Button(self, -1, 'Stop Sync', name = 'Stop Sync button')
resumeSyncBtn = wx.Button(self, -1, 'Resume Sync', name = 'Resume Sync button')
box4 = wx.BoxSizer(wx.HORIZONTAL)
box4.Add(stopSyncBtn, 0, wx.ALIGN_CENTER|wx.RIGHT, 20)
box4.Add(resumeSyncBtn, 0, wx.ALIGN_CENTER|wx.LEFT, 20)
# sizer
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(box1, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box2, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box5, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box3, 0, wx.EXPAND|wx.ALL, 10)
sizer.Add(box4, 0, wx.ALIGN_CENTER, 10)
self.SetSizer(sizer)
self.SetAutoLayout(True)
# clipboard
self.clip = wx.Clipboard()
self.x = wx.BitmapDataObject()
self.bmp = None
self.oldBmp = None
self.msgShowArea.Bind(wx.EVT_IDLE, self.UpdateMsgShownArea)
self.msgShowArea.Bind(wx.EVT_PAINT, self.OnPaint)
def OnOpen(self, e):
""" Open a file"""
button = e.GetEventObject()
dlg = wx.DirDialog(self, "Choose a dir", "", wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
if button.GetName() == 'Shared dir button':
self.sharedPathTextCtrl.SetValue(path)
if button.GetName() == 'local dir button':
self.localPathTextCtrl.SetValue(path)
dlg.Destroy()
def UpdateMsgShownArea(self, e):
print "UpdateMsgShownArea"
self.clip.Open()
self.clip.GetData(self.x)
self.clip.Close()
self.bmp = self.x.GetBitmap()
if self.oldBmp == self.bmp:
print "same pic"
return
else:
print "diff pic"
self.oldBmp = self.bmp
if self.oldBmp == self.bmp:
print "111111"
else:
print "222222"
print "abcd"
#self.Refresh()
#self.msgShowArea.Refresh()
def OnPaint(self, evt):
if self.bmp:
dc = wx.PaintDC(self.msgShowArea)
dc.DrawBitmap(self.bmp, 20, 20, True)
#----------------------------------------------------------------------------
if __name__ == '__main__':
app = wx.App(False)
frame = MyFrame(None, "EasySync")
app.MainLoop()
不幸的是,wxWidgets 不支持剪贴板更改通知。在 MSW 下添加它会相对简单,但我不太确定其他平台。
无论如何,现在您唯一的选择是轮询剪贴板的更改,即设置一个计时器并在每次触发时检查剪贴板内容。这很丑陋且效率低下,但应该有效。
将位图转换为图像,然后比较图像可以解决这个问题。
self.clip.GetData(self.bmpObj)
self.bmp = self.bmpObj.GetBitmap() # bitmap
self.Img = self.bmp.ConvertToImage().GetData() # convert bmp to image
isDrawBmp = True
if CLIP_TYPE_IMAGE == self.lastClipType:
if self.oldImg == self.Img: # compare images
#print "same pic"
#return
isDrawBmp = False
else:
#print "diff pic"
self.oldImg = self.Img
else:
self.oldImg = self.Img