📄 joystick.py
字号:
#----------------------------------------------------------------------------
# Name: Joystick.py
# Purpose: Demonstrate use of wx.Joystick
#
# Author: Jeff Grimmett (grimmtoo@softhome.net), adapted from original
# .wdr-derived demo
#
# Created: 02-Jan-2004
# RCS-ID: $Id: Joystick.py 30229 2004-11-01 19:39:09Z RD $
# Copyright:
# Licence: wxWindows license
#----------------------------------------------------------------------------
#
import math
import wx
haveJoystick = True
if wx.Platform == "__WXMAC__":
haveJoystick = False
#----------------------------------------------------------------------------
# Once all supported versions of Python support 32-bit integers on all
# platforms, this can go up to 32.
MAX_BUTTONS = 16
#----------------------------------------------------------------------------
class Label(wx.StaticText):
# A derived StaticText that always aligns right and renders
# in a bold font.
def __init__(self, parent, label):
wx.StaticText.__init__(self, parent, -1, label, style=wx.ALIGN_RIGHT)
self.SetFont(
wx.Font(
parent.GetFont().GetPointSize(),
parent.GetFont().GetFamily(),
parent.GetFont().GetStyle(),
wx.BOLD
))
#----------------------------------------------------------------------------
class JoyGauge(wx.Panel):
def __init__(self, parent, stick):
self.stick = stick
size = (100,100)
wx.Panel.__init__(self, parent, -1, size=size)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None)
self.buffer = wx.EmptyBitmap(*size)
dc = wx.BufferedDC(None, self.buffer)
self.DrawFace(dc)
self.DrawJoystick(dc)
def OnSize(self, event):
# The face Bitmap init is done here, to make sure the buffer is always
# the same size as the Window
w, h = self.GetClientSize()
self.buffer = wx.EmptyBitmap(w,h)
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
self.DrawFace(dc)
self.DrawJoystick(dc)
def DrawFace(self, dc):
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
def OnPaint(self, evt):
# When dc is destroyed it will blit self.buffer to the window,
# since no other drawing is needed we'll just return and let it
# do it's thing
dc = wx.BufferedPaintDC(self, self.buffer)
def DrawJoystick(self, dc):
# draw the guage as a maxed square in the center of this window.
w, h = self.GetClientSize()
edgeSize = min(w, h)
xorigin = (w - edgeSize) / 2
yorigin = (h - edgeSize) / 2
center = edgeSize / 2
# Restrict our drawing activities to the square defined
# above.
dc.SetClippingRegion(xorigin, yorigin, edgeSize, edgeSize)
# Optimize drawing a bit (for Win)
dc.BeginDrawing()
dc.SetBrush(wx.Brush(wx.Colour(251, 252, 237)))
dc.DrawRectangle(xorigin, yorigin, edgeSize, edgeSize)
dc.SetPen(wx.Pen(wx.BLACK, 1, wx.DOT_DASH))
dc.DrawLine(xorigin, yorigin + center, xorigin + edgeSize, yorigin + center)
dc.DrawLine(xorigin + center, yorigin, xorigin + center, yorigin + edgeSize)
if self.stick:
# Get the joystick position as a float
joyx = float(self.stick.GetPosition().x)
joyy = float(self.stick.GetPosition().y)
# Get the joystick range of motion
xmin = self.stick.GetXMin()
xmax = self.stick.GetXMax()
if xmin < 0:
xmax += abs(xmin)
joyx += abs(xmin)
xmin = 0
xrange = max(xmax - xmin, 1)
ymin = self.stick.GetYMin()
ymax = self.stick.GetYMax()
if ymin < 0:
ymax += abs(ymin)
joyy += abs(ymin)
ymin = 0
yrange = max(ymax - ymin, 1)
# calc a ratio of our range versus the joystick range
xratio = float(edgeSize) / xrange
yratio = float(edgeSize) / yrange
# calc the displayable value based on position times ratio
xval = int(joyx * xratio)
yval = int(joyy * yratio)
# and normalize the value from our brush's origin
x = xval + xorigin
y = yval + yorigin
# Now to draw it.
dc.SetPen(wx.Pen(wx.RED, 2))
dc.CrossHair(x, y)
# Turn off drawing optimization
dc.EndDrawing()
def Update(self):
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
self.DrawFace(dc)
self.DrawJoystick(dc)
#----------------------------------------------------------------------------
class JoyPanel(wx.Panel):
def __init__(self, parent, stick):
self.stick = stick
wx.Panel.__init__(self, parent, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
fn = wx.Font(
parent.GetFont().GetPointSize() + 3,
parent.GetFont().GetFamily(),
parent.GetFont().GetStyle(),
wx.BOLD
)
t = wx.StaticText(self, -1, "X - Y Axes", style = wx.ALIGN_CENTRE)
t.SetFont(fn)
sizer.Add(t, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_HORIZONTAL, 1)
self.control = JoyGauge(self, self.stick)
sizer.Add(self.control, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_HORIZONTAL, 1)
self.SetSizer(sizer)
sizer.Fit(self)
def Update(self):
self.control.Update()
#----------------------------------------------------------------------------
class POVGauge(wx.Panel):
#
# Display the current postion of the POV control
#
def __init__(self, parent, stick):
self.stick = stick
self.size = (100, 100)
self.avail = False
self.fourDir = False
self.cts = False
wx.Panel.__init__(self, parent, -1, size=self.size)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None)
self.buffer = wx.EmptyBitmap(*self.size)
dc = wx.BufferedDC(None, self.buffer)
self.DrawFace(dc)
self.DrawPOV(dc)
def OnSize(self, event):
# calculate the size of our display and make a buffer for it.
w, h = self.GetClientSize()
s = min(w, h)
self.size = (s, s)
self.buffer = wx.EmptyBitmap(w,h)
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
self.DrawFace(dc)
self.DrawPOV(dc)
def DrawFace(self, dc):
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
def OnPaint(self, evt):
# When dc is destroyed it will blit self.buffer to the window,
# since no other drawing is needed we'll just return and let it
# do it's thing
dc = wx.BufferedPaintDC(self, self.buffer)
def DrawPOV(self, dc):
# draw the guage as a maxed circle in the center of this window.
w, h = self.GetClientSize()
diameter = min(w, h)
xorigin = (w - diameter) / 2
yorigin = (h - diameter) / 2
xcenter = xorigin + diameter / 2
ycenter = yorigin + diameter / 2
# Optimize drawing a bit (for Win)
dc.BeginDrawing()
# our 'raster'.
dc.SetBrush(wx.Brush(wx.WHITE))
dc.DrawCircle(xcenter, ycenter, diameter/2)
dc.SetBrush(wx.Brush(wx.BLACK))
dc.DrawCircle(xcenter, ycenter, 10)
# fancy decorations
dc.SetPen(wx.Pen(wx.BLACK, 1, wx.DOT_DASH))
dc.DrawLine(xorigin, ycenter, xorigin + diameter, ycenter)
dc.DrawLine(xcenter, yorigin, xcenter, yorigin + diameter)
if self.stick:
if self.avail:
pos = -1
# use the appropriate function to get the POV position
if self.fourDir:
pos = self.stick.GetPOVPosition()
if self.cts:
pos = self.stick.GetPOVCTSPosition()
# trap invalid values
if 0 <= pos <= 36000:
vector = 30
else:
vector = 0
# rotate CCW by 90 so that 0 is up.
pos = (pos / 100) - 90
# Normalize
if pos < 0:
pos = pos + 360
# Stolen from wx.lib.analogclock :-)
radiansPerDegree = math.pi / 180
pointX = int(round(vector * math.cos(pos * radiansPerDegree)))
pointY = int(round(vector * math.sin(pos * radiansPerDegree)))
# normalise value to match our actual center.
nx = pointX + xcenter
ny = pointY + ycenter
# Draw the line
dc.SetPen(wx.Pen(wx.BLUE, 2))
dc.DrawLine(xcenter, ycenter, nx, ny)
# And a little thing to show the endpoint
dc.SetBrush(wx.Brush(wx.BLUE))
dc.DrawCircle(nx, ny, 8)
# Turn off drawing optimization
dc.EndDrawing()
def Update(self):
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
self.DrawFace(dc)
self.DrawPOV(dc)
def Calibrate(self):
s = self.stick
self.avail = s.HasPOV()
self.fourDir = s.HasPOV4Dir()
self.cts = s.HasPOVCTS()
#----------------------------------------------------------------------------
class POVStatus(wx.Panel):
#
# Displays static info about the POV control
#
def __init__(self, parent, stick):
self.stick = stick
wx.Panel.__init__(self, parent, -1, size=(100, 100))
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add((20,20))
self.avail = wx.CheckBox(self, -1, "Available")
sizer.Add(self.avail, 0, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 2)
self.fourDir = wx.CheckBox(self, -1, "4-Way Only")
sizer.Add(self.fourDir, 0, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 2)
self.cts = wx.CheckBox(self, -1, "Continuous")
sizer.Add(self.cts, 0, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 2)
self.SetSizer(sizer)
sizer.Fit(self)
# Effectively makes the checkboxes read-only.
self.Bind(wx.EVT_CHECKBOX, self.Calibrate)
def Calibrate(self, evt=None):
s = self.stick
self.avail.SetValue(s.HasPOV())
self.fourDir.SetValue(s.HasPOV4Dir())
self.cts.SetValue(s.HasPOVCTS())
#----------------------------------------------------------------------------
class POVPanel(wx.Panel):
def __init__(self, parent, stick):
self.stick = stick
wx.Panel.__init__(self, parent, -1, size=(100, 100))
sizer = wx.BoxSizer(wx.HORIZONTAL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -