Drawing a circle on the current window that moves (Python) - python

I'm facing a problem with python.
i want to draw on my monitor a circle, that can move around.
let's say i have my browser open, i want to be able to make the circle go around on his own AND be able to use the mouse to press any button i want.
the idea is that the circle is connected to my hands movement thanks to Leap Motion, and i want to display the gestures i make while being able to use the mouse.
my worries are that i have to make a trasparent window which doesn't let me to use the mouse because i would clik on the trasparent window.
Thanks!

Found the solution, i used wxPython
Down below the code:
import wx, inspect, os, sys, win32gui
IMAGE_PATH = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) + '\cerchio.png'
class Cursor(wx.Frame):
def __init__(self, parent, log):
self.log = log
self.delta = wx.Point(0,0)
wx.Frame.__init__(self, parent, -1, "Shaped Window",
style =
wx.FRAME_SHAPED
| wx.SIMPLE_BORDER
| wx.FRAME_NO_TASKBAR
| wx.STAY_ON_TOP
)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.update, self.timer)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.x=0
self.y=0
self.hasShape = False
self.SetClientSize( (50, 50) )
image = wx.Image(IMAGE_PATH, wx.BITMAP_TYPE_PNG)
image.SetMaskColour(255,255,255)
image.SetMask(True)
self.bmp = wx.BitmapFromImage(image)
self.SetWindowShape()
self.timer.Start(1)
dc = wx.ClientDC(self)
dc.DrawBitmap(self.bmp, 0, 0, True)
def OnExit(self, evt):
self.Close()
def SetWindowShape(self, *evt):
# Use the bitmap's mask to determine the region
r = wx.RegionFromBitmap(self.bmp)
self.hasShape = self.SetShape(r)
def OnPaint(self, evt):
dc = wx.PaintDC(self)
dc.DrawBitmap(self.bmp, 0, 0, True)
def OnExit(self, evt):
self.Close()
def update(self, event):
#self.x, self.y = win32gui.GetCursorPos()
self.SetPosition((self.x,self.y))
if __name__ == '__main__':
app = wx.App( False )
frm = Cursor(None, -1)
frm.Show()
app.MainLoop()
This maps 50x50 png image with white background (modify IMAGE_PATH) to the cursor position (you won't be able to click though)

Related

Drawing a line in wxPython using mouse position

I'm trying to make program in wxPython, that will draw a line in a position in which I clicked on a window but it doesn't work and I actually don't know why. How could I write this, that it will work?
import wx
global coord
coord = (30, 30)
class MyFrame(wx.Frame):
"""create a color frame, inherits from wx.Frame"""
global coord
def __init__(self, parent):
# -1 is the default ID
wx.Frame.__init__(self, parent, -1, "Click for mouse position", size=(400,300),
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
self.SetBackgroundColour('Goldenrod')
self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL))
# hook some mouse events
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnLeftDown(self, event):
global coord
"""left mouse button is pressed"""
pt = event.GetPosition() # position tuple
print pt
coord = pt
self.SetTitle('LeftMouse = ' + str(pt))
def OnRightDown(self, event):
global coord
"""right mouse button is pressed"""
pt = event.GetPosition()
coord = pt
print pt
self.SetTitle('RightMouse = ' + str(pt))
def OnPaint(self, event):
global coord
dc = wx.PaintDC(self)
dc.Clear()
dc.SetPen(wx.Pen(wx.BLACK, 4))
dc.DrawLine(0, 0, int(str(coord[0])), int(str(coord[1])))
app = wx.PySimpleApp()
frame = MyFrame(None)
frame.Show(True)
app.MainLoop()
Call
self.Refresh()
at the end of OnLeftDown/OnRightDown. Otherwise the system does not know it should redraw so it won't redraw...
(also, generally speaking, it may be better to have coord as a member variable, not a global)

Persistent drawing + temporary overlay with wx.PaintDC

I'm trying to make something of a Microsoft Paint-esque app using wxPython.
Currently, the app 'draws' onto the screen with a circular brush during a mouse left-down event. This is great, and the desired behavior. But I also need a circle of the same radius to 'follow' the mouse, without it drawing persistently onto wx.PaintDC.
That is, a circle of some radius follows the mouse around the screen, but only when the left mouse button is held, should the circle be 'permanently' drawn onto the buffer.
The approaches I've taken either (1) have a circle following the mouse around, but draw onto the PaintDC instance regardless of mouse-down, (2) follow the mouse around but never draw persistently onto the PaintDC instance, or (3) do not follow the mouse around, but appear and are drawn persistently on left-mouse down (see the example below).
Thank you!
import wx
class MyPanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, -1)
self.draw = False
self.radius = 50
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_MOTION, self.Draw)
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
def OnPaint(self, event):
dc = wx.PaintDC(self)
def Draw(self, event):
if self.draw == True:
x = event.GetX()
y = event.GetY()
dc = wx.ClientDC(self)
pen = wx.Pen(wx.Colour(192,192,192,128), 2)
brush = wx.Brush(wx.Colour(192,192,192,128))
dc.SetPen(pen)
dc.SetBrush(brush)
dc.DrawCircle(x,y,self.radius)
def OnLeftDown(self, event):
self.draw = True
def OnLeftUp(self, event):
self.draw = False
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Test",style=wx.DEFAULT_FRAME_STYLE,size=wx.Size(400, 300))
self.main_panel = MyPanel(self)
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm()
frame.Show()
app.MainLoop()
There is the wx.Overlay class that does a pretty good job assisting with drawing temporary things on top of more permanent stuff. See the Overlay sample in the demo: https://github.com/wxWidgets/Phoenix/blob/master/demo/Overlay.py

wxPython - cannot hide wxFrame for a desktop screenshot

I'm very new to wxPython and working on a desktop screenshot utility. In short, user selects a rectangular region on their screen from and produce an image from it as most screenshot tools already do. Its all working except for the fact that I cannot get the main frame, and all it contains, to hide or close, so the screenshot image produced contains the overlay mask and dashed selection box.
FYI, screenshots are triggered by pressing the ENTER key. I have tried a vast number of ways to achieve this without luck. Hiding the frame, or destroying the panel first etc. makes no difference. However, if I break things up to two steps with button to proceed it all works fine so I am betting it's something small. I tried Refresh on the frame and panel as well. For what it's worth, my desktop environment if Linux KDE (latest ArchLinux rolling release).
Here is my code in full.
#!/usr/bin/env python2
import wx, time
#--------------------------------------------------------------------------------------------------------#
class SelectableFrame(wx.Frame):
c1 = None
c2 = None
def __init__(self, parent=None, id=-1, title=""):
wx.Frame.__init__(self, parent, id, title, pos=(0, 0), size=wx.DisplaySize(), style=wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.STAY_ON_TOP)
self.panel = wx.Panel(self, size=self.GetSize())
self.panel.Bind(wx.EVT_MOTION, self.OnMouseMove)
self.panel.Bind(wx.EVT_LEFT_DOWN, self.OnMouseSelect)
self.panel.Bind(wx.EVT_RIGHT_DOWN, self.OnReset)
self.panel.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
self.panel.Bind(wx.EVT_PAINT, self.OnPaint)
self.panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
self.panel.SetBackgroundColour(wx.Colour(0, 0, 0))
self.panel.SetBackgroundStyle(wx.BG_STYLE_COLOUR)
self.SetTransparent(150)
def OnClose(self, event):
self.Destroy()
def OnMouseMove(self, event):
if event.Dragging() and event.LeftIsDown():
self.c2 = event.GetPosition()
self.Refresh()
def OnMouseSelect(self, event):
self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
self.c1 = event.GetPosition()
def OnMouseUp(self, event):
self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
def OnKeyDown(self, event):
key = event.GetKeyCode()
if key == wx.WXK_ESCAPE:
self.Close()
elif (key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER) and self.RegionSelected():
self.TakeScreenshot()
event.Skip()
def OnReset(self, event=None):
wx.PaintDC(self.panel).Clear()
self.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
def OnPaint(self, event):
if not self.RegionSelected():
return
dc = wx.PaintDC(self.panel)
dc.SetPen(wx.Pen("white", 1, wx.LONG_DASH))
dc.SetBrush(wx.Brush(wx.Colour(100, 100, 100), wx.SOLID))
dc.DrawRectangle(self.c1.x, self.c1.y, self.c2.x - self.c1.x, self.c2.y - self.c1.y)
def RegionSelected(self):
if self.c1 is None or self.c2 is None:
return False
else:
return True
def TakeScreenshot(self):
if not self.RegionSelected():
return
wx.PaintDC(self.panel).Clear()
self.Hide()
self.Refresh()
dcScreen = wx.ScreenDC()
bmp = wx.EmptyBitmap(self.c2.x - self.c1.x, self.c2.y - self.c1.y)
memDC = wx.MemoryDC()
memDC.SelectObject(bmp)
memDC.Blit(0, 0, self.c2.x - self.c1.x, self.c2.y - self.c1.y, dcScreen, self.c1.x, self.c1.y)
memDC.SelectObject(wx.NullBitmap)
img = bmp.ConvertToImage()
filename = "/tmp/ocr-screenshot-" + time.strftime('%Y%m%d-%H%M%S') + ".png"
img.SaveFile(filename, wx.BITMAP_TYPE_PNG)
self.Close()
#--------------------------------------------------------------------------------------------------------
class SelectableApp(wx.App):
def OnInit(self):
self.frame = SelectableFrame()
self.frame.Show(True)
self.SetTopWindow(self.frame)
return True
#--------------------------------------------------------------------------------------------------------#
app = SelectableApp(False)
app.MainLoop()

wxPython Background image on frame

MMGP Answerd but wont let me credit him right ;-) So I will at least mention him here.
(And I did finally get to credit him... 8-)
His linked discussion on Double Buffering provided a base code that worked with the following modifications:
Insert this beginning at line 106 (overwritting existing code until you get to the last line shown here):
# Here's the actual drawing code.
cliWidth, cliHeight = self.GetClientSize()
bmp=wx.Bitmap("Logo16x9.png")
bmpWide = bmp.GetWidth()
bmpHeight = bmp.GetHeight()
img = bmp.ConvertToImage()
scaleFactor = cliWidth/bmpWide
bmp = wx.BitmapFromImage(img.Scale(int(bmpWide * scaleFactor), int(bmpHeight * scaleFactor)))
bmpWide = bmp.GetWidth()
bmpHeight = bmp.GetHeight()
xPos = (cliWidth - (bmpWide))/2
yPos = (cliHeight - (bmpHeight))/2
# altered by me
dc.DrawBitmap(bmp, xPos, yPos)
class TestFrame(wx.Frame):
I've been beating my head against this all day.
I'm new to drawing graphics with the wxPython modules, and when I needed to draw a background image on a frame I found this code which works well if the image is the full size of the window.
However, I need to place a company logo as the background, and have it remain centered through resizes. In it's current form the resize causes a graphic artifact the size of a small nation to appear on the screen with any resize event.
The logo image file (used on line 43 of the code) is a 400x300 (WxH) image.
I am looking for a way to either: resize my image on the fly to match wx.GetClientSize(),
or a way to avoid/remove the artifact. Preferably without involving PIL or ImageMagick. App has to function on a local level only, and be system agnostic (Win, Lin and Mac), none of this involves network activities or mapped drives.
Python 2.7 and wxPython 2.8
The code I am using (with my modification annotated) is as follows:
import wx
########################################################################
class MainPanel(wx.Panel):
""""""
#----------------------------------------------------------------------
def __init__(self, parent):
"""Constructor"""
wx.Panel.__init__(self, parent=parent)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.frame = parent
sizer = wx.BoxSizer(wx.VERTICAL)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
for num in range(4):
label = "Button %s" % num
btn = wx.Button(self, label=label)
sizer.Add(btn, 0, wx.ALL, 5)
hSizer.Add((1,1), 1, wx.EXPAND)
hSizer.Add(sizer, 0, wx.TOP, 100)
hSizer.Add((1,1), 0, wx.ALL, 75)
self.SetSizer(hSizer)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
#----------------------------------------------------------------------
def OnEraseBackground(self, evt):
"""
Add a picture to the background
"""
# yanked from ColourDB.py
dc = evt.GetDC()
# Added by me
cliWidth, cliHeight = self.GetClientSize()
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
# added by me
xPos = (cliWidth - 400)/2
yPos = (cliHeight - 300)/2
# altered by me
dc.DrawBitmap(bmp, xPos, yPos)
#dc.DrawBitmap(bmp, 0, 0)
########################################################################
class MainFrame(wx.Frame):
""""""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
wx.Frame.__init__(self, None, size=(600,450))
panel = MainPanel(self)
self.Center()
########################################################################
class Main(wx.App):
""""""
#----------------------------------------------------------------------
def __init__(self, redirect=False, filename=None):
"""Constructor"""
wx.App.__init__(self, redirect, filename)
dlg = MainFrame()
dlg.Show()
#----------------------------------------------------------------------
if __name__ == "__main__":
app = Main()
app.MainLoop()
Update: Latest Failure - Modified lines 37 to 52
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
img = bmp.ConvertToImage()
scaleFactor = cliWidth/400
bmp = wx.BitmapFromImage(img.Scale(int(400*scaleFactor),int(300*scaleFactor)))
# added by me
#xPos = (cliWidth - 400)/2
#yPos = (cliHeight - 300)/2
# altered by me
#dc.DrawBitmap(bmp, xPos, yPos)
dc.DrawBitmap(bmp, 0, 0)
Another attempt and another fail. No difference in the output to screen. Additionally, the referenced document on double buffering does not address this issue, but does suffer from the same result. This code modifies lines 36 through 57 of the original.
brsh = wx.Brush('#000000')
if not dc:
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
dc.SetBackground(brsh)
dc.SetDeviceOrigin(0,0)
dc.DestroyClippingRegion()
dc.Clear()
# use a 400x300 image
bmp = wx.Bitmap("Logo4x3.png")
img = bmp.ConvertToImage()
scaleFactor = cliWidth/400
bmp = wx.BitmapFromImage(img.Scale(int(400*scaleFactor),int(300*scaleFactor)))
# added by me
#xPos = (cliWidth - 400)/2
#yPos = (cliHeight - 300)/2
# altered by me
#dc.DrawBitmap(bmp, xPos, yPos)
dc.DrawBitmap(bmp, 0, 0)
From the comments I suggested using double buffered drawing, but I didn't see that in the edited post. Also, I had several drawing issues when self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) was used. But this line might be helpful in other systems beyond mine, so I wanted to keep it. So, in order to handle the situation, here is a updated code that uses double buffered drawing and works fine here:
import wx
class MainPanel(wx.Panel):
def __init__(self, parent, bg_img='Logo4x3.png'):
wx.Panel.__init__(self, parent=parent)
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.bg = wx.Bitmap(bg_img)
self._width, self._height = self.bg.GetSize()
sizer = wx.BoxSizer(wx.VERTICAL)
hSizer = wx.BoxSizer(wx.HORIZONTAL)
for num in range(4):
btn = wx.Button(self, label="Button %s" % num)
sizer.Add(btn, 0, wx.ALL, 5)
hSizer.Add((1,1), 1, wx.EXPAND)
hSizer.Add(sizer, 0, wx.TOP, 100)
hSizer.Add((1,1), 0, wx.ALL, 75)
self.SetSizer(hSizer)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
def OnSize(self, size):
self.Layout()
self.Refresh()
def OnEraseBackground(self, evt):
pass
def OnPaint(self, evt):
dc = wx.BufferedPaintDC(self)
self.Draw(dc)
def Draw(self, dc):
cliWidth, cliHeight = self.GetClientSize()
if not cliWidth or not cliHeight:
return
dc.Clear()
xPos = (cliWidth - self._width)/2
yPos = (cliHeight - self._height)/2
dc.DrawBitmap(self.bg, xPos, yPos)
app = wx.App()
frame = wx.Frame(None, size=(400,300))
panel = MainPanel(frame)
frame.Show()
app.MainLoop()
The method OnEraseBackground is intentionally empty.

Python - Bitmap won't draw/display on button

I have been working on this project for some time now - it was originally supposed to be a test to see if, using wxPython, I could build a button 'from scratch.' From scratch means: that i would have full control over all the aspects of the button (i.e. controlling the BMP's that are displayed... what the event handlers did... etc.)
I have run into several problems (as this is my first major python project.) Now, when the all the code is working for the life of me I can't get an image to display.
Basic code - not working
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.DrawBitmap(wx.Bitmap("/home/wallter/Desktop/Mouseover.bmp"), 100, 100)
self.Refresh()
self.Update()
Full Main.py
import wx
from Custom_Button import Custom_Button
from wxPython.wx import *
ID_ABOUT = 101
ID_EXIT = 102
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition, wxSize(400, 400))
self.CreateStatusBar()
self.SetStatusText("Program testing custom button overlays")
menu = wxMenu()
menu.Append(ID_ABOUT, "&About", "More information about this program")
menu.AppendSeparator()
menu.Append(ID_EXIT, "E&xit", "Terminate the program")
menuBar = wxMenuBar()
menuBar.Append(menu, "&File");
self.SetMenuBar(menuBar)
# The call for the 'Experiential button'
self.Button1 = Custom_Button(parent, -1,
wx.Point(100, 100),
wx.Bitmap("/home/wallter/Desktop/Mouseover.bmp"),
wx.Bitmap("/home/wallter/Desktop/Normal.bmp"),
wx.Bitmap("/home/wallter/Desktop/Click.bmp"))
# The following three lines of code are in place to try to get the
# Button1 to display (trying to trigger the Paint event (the _onPaint.)
# Because that is where the 'draw' functions are.
self.Button1.Show(true)
self.Refresh()
self.Update()
# Because the Above three lines of code did not work, I added the
# following four lines to trigger the 'draw' functions to test if the
# '_onPaint' method actually worked.
# These lines do not work.
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.DrawBitmap(wx.Bitmap("/home/wallter/Desktop/Mouseover.bmp"), 100, 100)
EVT_MENU(self, ID_ABOUT, self.OnAbout)
EVT_MENU(self, ID_EXIT, self.TimeToQuit)
def OnAbout(self, event):
dlg = wxMessageDialog(self, "Testing the functions of custom "
"buttons using pyDev and wxPython",
"About", wxOK | wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def TimeToQuit(self, event):
self.Close(true)
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(NULL, -1, "wxPython | Buttons")
frame.Show(true)
self.SetTopWindow(frame)
return true
app = MyApp(0)
app.MainLoop()
Full CustomButton.py
import wx
from wxPython.wx import *
class Custom_Button(wx.PyControl):
def __init__(self, parent, id, Pos, Over_BMP, Norm_BMP, Push_BMP, **kwargs):
wx.PyControl.__init__(self,parent, id, **kwargs)
self.Bind(wx.EVT_LEFT_DOWN, self._onMouseDown)
self.Bind(wx.EVT_LEFT_UP, self._onMouseUp)
self.Bind(wx.EVT_LEAVE_WINDOW, self._onMouseLeave)
self.Bind(wx.EVT_ENTER_WINDOW, self._onMouseEnter)
self.Bind(wx.EVT_ERASE_BACKGROUND,self._onEraseBackground)
self.Bind(wx.EVT_PAINT,self._onPaint)
self.pos = Pos
self.Over_bmp = Over_BMP
self.Norm_bmp = Norm_BMP
self.Push_bmp = Push_BMP
self._mouseIn = False
self._mouseDown = False
def _onMouseEnter(self, event):
self._mouseIn = True
def _onMouseLeave(self, event):
self._mouseIn = False
def _onMouseDown(self, event):
self._mouseDown = True
def _onMouseUp(self, event):
self._mouseDown = False
self.sendButtonEvent()
def sendButtonEvent(self):
event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
event.SetInt(0)
event.SetEventObject(self)
self.GetEventHandler().ProcessEvent(event)
def _onEraseBackground(self,event):
# reduce flicker
pass
def Iz(self):
dc = wx.BufferedPaintDC(self)
dc.DrawBitmap(self.Norm_bmp, 100, 100)
def _onPaint(self, event):
# The printing functions, they should work... but don't.
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.DrawBitmap(self.Norm_bmp)
# This never printed... I don't know if that means if the EVT
# is triggering or what.
print '_onPaint'
# draw whatever you want to draw
# draw glossy bitmaps e.g. dc.DrawBitmap
if self._mouseIn: # If the Mouse is over the button
dc.DrawBitmap(self.Over_bmp, self.pos)
else: # Since the mouse isn't over it Print the normal one
# This is adding on the above code to draw the bmp
# in an attempt to get the bmp to display; to no avail.
dc.DrawBitmap(self.Norm_bmp, self.pos)
if self._mouseDown: # If the Mouse clicks the button
dc.DrawBitmap(self.Push_bmp, self.pos)
This code won't work? I get no BMP displayed why? How do i get one? I've gotten the staticBitmap(...) to display one, but it won't move, resize, or anything for that matter... - it's only in the top left corner of the frame?
Note: the frame is 400pxl X 400pxl - and the "/home/wallter/Desktop/Mouseover.bmp"
Are your sure you code is working without exceptions because when I run it i get many errors, read the points below and you should have a button which at least draws correctly
When O run it it gives error because Custom_Button is passed NULL parent instead pass frame e.g. Custom_Button(self, ...)
Your drawBitmap call is also wrong, it throws exception, instead of dc.DrawBitmap(self.Norm_bmp) it should be dc.DrawBitmap(self.Norm_bmp, 0, 0)
dc.DrawBitmap(self.Over_bmp, self.pos) also throws error as pos should be x,y not a tuple so instead do dc.DrawBitmap(self.Over_bmp, *self.pos)
and lastly you do not need to do "from wxPython.wx import *" instead just do "from wx import *" and instead of wxXXX class names use wx.XXX, instead of true use True etc
here is my working code
from wx import *
ID_ABOUT = 101
ID_EXIT = 102
class Custom_Button(wx.PyControl):
def __init__(self, parent, id, Pos, Over_BMP, Norm_BMP, Push_BMP, **kwargs):
wx.PyControl.__init__(self,parent, id, **kwargs)
self.Bind(wx.EVT_LEFT_DOWN, self._onMouseDown)
self.Bind(wx.EVT_LEFT_UP, self._onMouseUp)
self.Bind(wx.EVT_LEAVE_WINDOW, self._onMouseLeave)
self.Bind(wx.EVT_ENTER_WINDOW, self._onMouseEnter)
self.Bind(wx.EVT_ERASE_BACKGROUND,self._onEraseBackground)
self.Bind(wx.EVT_PAINT,self._onPaint)
self.pos = Pos
self.Over_bmp = Over_BMP
self.Norm_bmp = Norm_BMP
self.Push_bmp = Push_BMP
self._mouseIn = False
self._mouseDown = False
def _onMouseEnter(self, event):
self._mouseIn = True
def _onMouseLeave(self, event):
self._mouseIn = False
def _onMouseDown(self, event):
self._mouseDown = True
def _onMouseUp(self, event):
self._mouseDown = False
self.sendButtonEvent()
def sendButtonEvent(self):
event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
event.SetInt(0)
event.SetEventObject(self)
self.GetEventHandler().ProcessEvent(event)
def _onEraseBackground(self,event):
# reduce flicker
pass
def Iz(self):
dc = wx.BufferedPaintDC(self)
dc.DrawBitmap(self.Norm_bmp, 100, 100)
def _onPaint(self, event):
# The printing functions, they should work... but don't.
dc = wx.BufferedPaintDC(self)
dc.SetFont(self.GetFont())
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.DrawBitmap(self.Norm_bmp, 0, 0)
# This never printed... I don't know if that means if the EVT
# is triggering or what.
print '_onPaint'
# draw whatever you want to draw
# draw glossy bitmaps e.g. dc.DrawBitmap
if self._mouseIn: # If the Mouse is over the button
dc.DrawBitmap(self.Over_bmp, *self.pos)
else: # Since the mouse isn't over it Print the normal one
# This is adding on the above code to draw the bmp
# in an attempt to get the bmp to display; to no avail.
dc.DrawBitmap(self.Norm_bmp, *self.pos)
if self._mouseDown: # If the Mouse clicks the button
dc.DrawBitmap(self.Push_bmp, *self.pos)
class MyFrame(wx.Frame):
def __init__(self, parent, ID, title):
wx.Frame.__init__(self, parent, ID, title,
wx.DefaultPosition, wx.Size(400, 400))
self.CreateStatusBar()
self.SetStatusText("Program testing custom button overlays")
menu = wx.Menu()
menu.Append(ID_ABOUT, "&About", "More information about this program")
menu.AppendSeparator()
menu.Append(ID_EXIT, "E&xit", "Terminate the program")
menuBar = wx.MenuBar()
menuBar.Append(menu, "&File");
self.SetMenuBar(menuBar)
# The call for the 'Experiential button'
s = r"D:\virtual_pc\mockup\mockupscreens\embed_images\toolbar\options.png"
self.Button1 = Custom_Button(self, -1,
wx.Point(100, 100),
wx.Bitmap(s),
wx.Bitmap(s),
wx.Bitmap(s))
self.Button1.Show(True)
EVT_MENU(self, ID_ABOUT, self.OnAbout)
EVT_MENU(self, ID_EXIT, self.TimeToQuit)
def OnAbout(self, event):
dlg = wxMessageDialog(self, "Testing the functions of custom "
"buttons using pyDev and wxPython",
"About", wxOK | wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def TimeToQuit(self, event):
self.Close(true)
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, "wxPython | Buttons")
frame.Show(True)
self.SetTopWindow(frame)
return True
app = MyApp(0)
app.MainLoop()

Categories

Resources