I'm having trouble moving my functions into a separate file as they access a wxpython gui.
The functions are from "onSaveMovieFile" to "LogThis"
#!/usr/bin/env python
# -*- coding: us-ascii -*-
# generated by wxGlade 0.6.3 on Fri Jul 22 11:53:07 2011
"""
Copyright (c) 2011 Mitchell Lafferty <coolspeedy6 at gmail dot com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
self.Bind(wx.EVT_CLOSE,self.OnClose)
self.Stop_Never.Bind(wx.EVT_TOGGLEBUTTON, self.onToggleNever)
self.On.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggleOn)
self.Compile_every_now.Bind(wx.EVT_BUTTON, self.Compile)
self.Stills_Select.Bind(wx.EVT_BUTTON, self.onDirStills)
self.Movie_Select.Bind(wx.EVT_BUTTON, self.onSaveMovieFile)
self.Cap_every_SpinCtrl.Bind(wx.EVT_SPINCTRL,self.OnSpinUnlimited)
self.Comp_every_SpinCtrl.Bind(wx.EVT_SPINCTRL, self.OnSpinUnlimited)
self.Framerate_SpinCtrl.Bind(wx.EVT_SPINCTRL, self.OnSpinUnlimited)
self.Comp_Frames_SpinCtrl.Bind(wx.EVT_SPINCTRL, self.OnSpinUnlimited)
self.InitSizeAndQuality()
def onSaveMovieFile(self, event=None):
dlg = wx.FileDialog(
self, message="Save file as ...",
defaultFile="Timelapse.avi",
wildcard="Video files (*.avi)|*.avi",
style=wx.SAVE
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
if not path.endswith(".avi"): path += ".avi" # NOTE: Not safe?
self.Movie_Input.SetValue(path)
dlg.Destroy()
def onDirStills(self, event=None):
dlg = wx.DirDialog(self, "Choose a directory:",
style=wx.DD_DEFAULT_STYLE
## | wx.DD_DIR_MUST_EXIST
## | wx.DD_CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
path = dlg.GetPath()
if not path.endswith("/"): path += "/" # NOTE: Not safe?
self.Stills_Input.SetValue(path)
dlg.Destroy()
def onToggleNever(self,event=None):
self.Stop_Date.Enable(not self.Stop_Never.GetValue())
def OnToggleOn(self,event=None):
self.Snap()
self.Compile()
def Snap(self,event=None):
"""
NOTE: returns cause late work,
if "self.CheckDueDate()" is at bottom
this makes it execed deadline also,
late work should be a user option.
"""
# Haha, "Snapshot and save" sounds like a photo discount store!
print "Snapshot and save code here..."
if not self.Latework.GetValue(): self.CheckDueDate() # NOTE: does not cause late work
try:
if self.On.GetValue():
CapUnit = self.Cap_every_append.GetSelection()
CapVal = self.Cap_every_SpinCtrl.GetValue()
CapVal = self.Time2seconds(CapVal,CapUnit)
print CapVal
if CapVal > 0:
CapTimer = threading.Timer(CapVal,self.Snap)
CapTimer.start()
except Exception as err:
print "Error:", err
self.On.SetValue(False)
if not self.On.GetValue():
if 'CapTimer' in vars():
CapTimer.cancel()
return
path = self.Stills_Input.GetValue()
file = ""
if not os.path.exists(path):
print "Error opening: " + path
return
try:
capture = cv.CreateCameraCapture(-1)
if not capture:
print "Error opening: Camera device"
return
#cvSetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH, 640 );
#cvSetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT, 480 );
frame = cv.QueryFrame(capture)
if frame is None: return
file = time.strftime("%Y%m%d%H%M%S", time.gmtime())
file = path + "TS" + file + ".png"
cv.SaveImage(file, frame)
except Exception as err:
print "Error getting/saving frame: ", err
if os.path.isfile(file):
try:
self.Picture.SetBitmap(wx.Bitmap(file, wx.BITMAP_TYPE_ANY))
except Exception as err:
print "Can't show picture!: ", err
else:
print "Error opening: " + file
return
print file
if self.Latework.GetValue(): self.CheckDueDate() # NOTE: causes late work
##if 'CapTimer' in vars(): CapTimer.start()
def Compile(self,event=None):
print "Compile into movie code here.."
if not self.Latework.GetValue(): self.CheckDueDate() # NOTE: does not cause late work
try:
if self.On.GetValue():
CompUnit = self.Comp_every_append.GetSelection()
CompVal = self.Comp_every_SpinCtrl.GetValue()
CompVal = self.Time2seconds(CompVal,CompUnit)
print CompVal
if CompVal > 0:
CompTimer = threading.Timer(CompVal,self.Compile)
CompTimer.start()
except Exception as err:
print "Error:", err
self.On.SetValue(False)
if not self.On.GetValue():
if 'CompTimer' in vars():
CompTimer.cancel()
return
file = self.Movie_Input.GetValue()
path = self.Stills_Input.GetValue()
TimeApart = self.Time2seconds( self.Comp_Frames_SpinCtrl.GetValue(), self.Comp_Frames_append.GetSelection())
if not os.path.exists(path):
self.LogThis("opening: " + path,None,False)
return
try:
fps = self.Framerate_SpinCtrl.GetValue()
if fps<=0: fps = 10
frames = glob.glob(path + "TS*.png")
writer = cvCreateVideoWriter(file, -1, fps, is_color=1) # frame_size=-1
for i in range(len(frames)):
if TimeApart > 0:
frames[i] = re.search('TS(.*)\.png', frames[i]) # find correct file
frames[i] = frames[i].group(0) # grab date
frames[i] = mktime(time.strptime(frames[i], "%Y%m%d%H%M%S")) # make into timestamp
frames[i] += TimeApart # add to timestamp
frames[i] = path + time.strftime("TS%Y%m%d%H%M%S.png", time.gmtime(frames[i])) # make path+file place
if os.path.isfile(frames[i]):
self.ImageResize(frames[i])
cvWriteFrame(writer, frames[i])
except Exception as err:
self.LogThis("Can't make movie: " + str(err),None,False)
if self.Latework.GetValue(): self.CheckDueDate() # NOTE: causes late work
##if 'CompTimer' in vars(): CompTimer.start()
def CheckDueDate(self):
if self.Stop_Never.GetValue(): return
print "Timer duedate code here..."
selected = self.Stop_Date.GetValue()
month = selected.Month + 1
day = selected.Day
year = selected.Year
date_str = "%4d%02d%02d" % (year, month, day)
#?print date_str
#?print time.strftime("%Y%m%d", time.gmtime())
if date_str <= time.strftime("%Y%m%d", time.gmtime()):
print "Deadline reached!"
self.On.SetValue(False)
if 'CapTimer' in vars(): CapTimer.cancel()
if 'CompTimer' in vars(): CompTimer.cancel()
##self.OnToggleOn()
def Time2seconds(self,time,unit):
# errors "long int too large to convert to c long"
# unit == (anything else) # seconds 1
if unit == 1:
time *= 60 # minutes 60
elif unit == 2:
time *= 60 * 60 # hours 60 * 60
elif unit == 3:
time *= 24 * 60 * 60 # days 24 * 60 * 60
elif unit == 4:
time *= 365 * 24 * 60 * 60 # years 365 * 24 * 60 * 60
return time
def OnSpinUnlimited(self,event=None):
obj = event.GetEventObject()
obj.SetRange(0, obj.GetValue() + 100)
def OnClose(self,event=None):
if 'CapTimer' in vars(): CapTimer.cancel()
if 'CompTimer' in vars(): CompTimer.cancel()
self.Destroy()
def ImageResize(self,file):
"""##
try:
from PIL import Image
except Exception as err:
print 'We need This module!: ', err
self.Size_Combo.Enable(False)
self.Quality_SpinCtrl.Enable(False)
self.label_7.Enable(False)
return
##"""
try:
OldImage = Image.open(file)
# pil_image.size pil_image.format pil_image.mode
SizeVal = self.Size_Combo.GetValue()
Size = SizeVal.split('x', 1);
if Size[0] <= 0 or Size[1] <= 0: return
NewImage = OldImage.resize((Size[0], Size[1]), Image.ANTIALIAS)
NewImage.save(file,quality=Quality_SpinCtrl.GetValue())
except Exception as err:
self.Error_GUI_Print_Log('resize: ' + str(err),None,False)
def InitSizeAndQuality(self):
try:
from PIL import Image
except Exception as err:
self.LogThis('We need This module!: ' + str(err))
self.Size_Combo.Enable(False)
self.Quality_SpinCtrl.Enable(False)
self.Size_and_Quality_label.Enable(False)
def LogThis(self,msg,level=None,LOUD=True):
if level == None: level = logging.ERROR
LEVELS ={}
LEVELS[logging.DEBUG]=_('Debug')
LEVELS[logging.INFO]=_('Info')
LEVELS[logging.WARNING]=_('Warning')
LEVELS[logging.ERROR]=_('Error')
LEVELS[logging.CRITICAL]=_('Critical')
print LEVELS[level],":",msg
if LOUD:
try:
wx.MessageBox(msg,LEVELS[level])
except:
pass
if NoLog: return #'NoLog' in vars() and
logger = logging.getLogger('YaTLC')
hdlr = logging.FileHandler('./YaTLC.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
#logger.setLevel(logging.INFO)
logger.log(level,msg)
#logger.shutdown()
PS: I fixed it, all I did was put the function in a different file, imported it, and replaced some "self's" with the name of the different file
I see you are using wxglade for the design of you gui.
The best procedure is to keep the code from glade untouched in a file. Then you import and subclass the wxglade created class in a new file. There you write all your Bind() and functions there.
For example suposse this is your wxglade autogenerated file:
mygui.py
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# generated by wxGlade HG on Tue Jul 26 20:03:16 2011
import wx
# begin wxGlade: extracode
# end wxGlade
class MyFrame(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MyFrame.__init__
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.text_ctrl_1 = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)
self.__set_properties()
self.__do_layout()
# end wxGlade
def __set_properties(self):
# begin wxGlade: MyFrame.__set_properties
self.SetTitle("frame_1")
# end wxGlade
def __do_layout(self):
# begin wxGlade: MyFrame.__do_layout
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_1.Add(self.text_ctrl_1, 1, wx.EXPAND, 0)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.Layout()
# end wxGlade
# end of class MyFrame
Then in your application:
myaplication.py
import wx
from mygui import MyFrame
class MyApplication(MyFrame):
def __init__(self, *args, **kargs):
MyFrame.__init__(self, *args, **kargs)
##**put here all your Bind()**
#**then put all your methods here:**
def onSaveMovieFile(self, evt):
----------------
def LogThis(self, evt):
----------------
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = MyApplication(None)
frame.Show()
app.MainLoop()
Related
I have a code that currently takes one video and show it in screen using the gstreamer bindings for Python. I can seek the video when a "Forward" button is clicked at the player opened, and that is an important feature for me, hence the reason I don't want to use a parse to write a pipeline and send it to gst-launch.
What I want to do now is stream this video not only to a new opened window, but also (or only if I can't have both) via RTSP to open it at VLC or even another client over LAN. Is there any way to do that?
I am sorry, for the long code, but here it is:
import sys, os, time
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject, Gtk
from gi.repository import GdkX11, GstVideo
class GTK_Main(object):
def __init__(self):
window = Gtk.Window(Gtk.WindowType.TOPLEVEL)
window.set_title("Vorbis-Player")
window.set_default_size(500, -1)
window.connect("destroy", Gtk.main_quit, "WM destroy")
vbox = Gtk.VBox()
window.add(vbox)
self.entry = Gtk.Entry()
vbox.pack_start(self.entry, False, False, 0)
hbox = Gtk.HBox()
vbox.add(hbox)
buttonbox = Gtk.HButtonBox()
hbox.pack_start(buttonbox, False, False, 0)
rewind_button = Gtk.Button("Rewind")
rewind_button.connect("clicked", self.rewind_callback)
buttonbox.add(rewind_button)
self.button = Gtk.Button("Start")
self.button.connect("clicked", self.start_stop)
buttonbox.add(self.button)
forward_button = Gtk.Button("Forward")
forward_button.connect("clicked", self.forward_callback)
buttonbox.add(forward_button)
self.time_label = Gtk.Label()
self.time_label.set_text("00:00 / 00:00")
hbox.add(self.time_label)
window.show_all()
self.player = Gst.ElementFactory.make("playbin", "player")
bus = self.player.get_bus()
bus.add_signal_watch()
bus.enable_sync_message_emission()
bus.connect("message", self.on_message)
bus.connect("sync-message::element", self.on_sync_message)
def start_stop(self, w):
if self.button.get_label() == "Start":
filepath = self.entry.get_text().strip()
if os.path.isfile(filepath):
filepath = os.path.realpath(filepath)
self.butto
n.set_label("Stop")
self.player.set_property("uri", "file://" + filepath)
self.player.set_state(Gst.State.PLAYING)
time.sleep(1)
self.forward_callback(60)
else:
self.player.set_state(Gst.State.NULL)
self.button.set_label("Start")
def on_message(self, bus, message):
t = message.type
if t == Gst.MessageType.EOS:
self.player.set_state(Gst.State.NULL)
self.button.set_label("Start")
elif t == Gst.MessageType.ERROR:
self.player.set_state(Gst.State.NULL)
err, debug = message.parse_error()
print ("Error: %s" % err, debug)
self.button.set_label("Start")
def on_sync_message(self, bus, message):
if message.get_structure().get_name() == 'prepare-window-handle':
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_window_handle(self.movie_window.get_property('window').get_xid())
def rewind_callback(self, w):
rc, pos_int = self.player.query_position(Gst.Format.TIME)
seek_ns = pos_int - 10 * 1000000000
if seek_ns < 0:
seek_ns = 0
print ("Backward: %d ns -> %d ns" % (pos_int, seek_ns))
self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, seek_ns)
def forward_callback(self, w):
rc, pos_int = self.player.query_position(Gst.Format.TIME)
if type(w) == int:
seek_ns = w * 1000000000
else:
seek_ns = pos_int + 10 * 1000000000
print ("Forward: %d ns -> %d ns" % (pos_int, seek_ns))
self.player.seek_simple(Gst.Format.TIME, Gst.SeekFlags.FLUSH, seek_ns)
def convert_ns(self, t):
# This method was submitted by Sam Mason.
# It's much shorter than the original one.
s,ns = divmod(t, 1000000000)
m,s = divmod(s, 60)
if m < 60:
return "%02i:%02i" %(m,s)
else:
h,m = divmod(m, 60)
return "%i:%02i:%02i" %(h,m,s)
GObject.threads_init()
Gst.init(None)
GTK_Main()
Gtk.main()
I found this code at this tutorial.
So, I ended up managing to make the link provided work. My problem was with the video's width and height, which must have the exact same values as the video you want to play, maybe something to do with opencv frames passing...also, the "is-live" property, which was set to true due to the use of webcam camera from the link's solution must be set to false (or not used at all since that is the default value) or else the video will begin with a certain delay in black screen. The code ended up being:
import cv2
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GObject
class SensorFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self, **properties):
super(SensorFactory, self).__init__(**properties)
self.cap = cv2.VideoCapture("path/to/video")
self.number_frames = 0
self.fps = 8
self.duration = 1 / self.fps * Gst.SECOND # duration of a frame in nanoseconds
self.launch_string = 'appsrc name=source block=true format=GST_FORMAT_TIME ' \
'caps=video/x-raw,format=BGR,width=1280,height=720,framerate={}/1 ' \
'! videoconvert ! video/x-raw,format=I420 ' \
'! x264enc speed-preset=ultrafast tune=zerolatency ! queue ' \
'! rtph264pay config-interval=1 name=pay0 pt=96 '.format(self.fps)
# streams to gst-launch-1.0 rtspsrc location=rtsp://localhost:8554/test latency=50 ! decodebin ! autovideosink
def on_need_data(self, src, lenght):
if self.cap.isOpened():
ret, frame = self.cap.read()
if ret:
data = frame.tostring()
#print(data)
buf = Gst.Buffer.new_allocate(None, len(data), None)
buf.fill(0, data)
buf.duration = self.duration
timestamp = self.number_frames * self.duration
buf.pts = buf.dts = int(timestamp)
buf.offset = timestamp
self.number_frames += 1
retval = src.emit('push-buffer', buf)
#print('pushed buffer, frame {}, duration {} ns, durations {} s'.format(self.number_frames,
# self.duration,
# self.duration / Gst.SECOND))
if retval != Gst.FlowReturn.OK:
print(retval)
def do_create_element(self, url):
return Gst.parse_launch(self.launch_string)
def do_configure(self, rtsp_media):
self.number_frames = 0
appsrc = rtsp_media.get_element().get_child_by_name('source')
appsrc.connect('need-data', self.on_need_data)
class GstServer(GstRtspServer.RTSPServer):
def __init__(self, **properties):
super(GstServer, self).__init__(**properties)
self.factory = SensorFactory()
self.factory.set_shared(True)
self.get_mount_points().add_factory("/test", self.factory)
self.attach(None)
GObject.threads_init()
Gst.init(None)
server = GstServer()
loop = GObject.MainLoop()
loop.run()
These days I have tried to generate an application using the pythonapp template from the Github project Jumpstarter(https://github.com/aldebaran/robot-jumpstarter) to do the localization of Pepper. My basic idea is to combine the LandmarkDetector module in the generated app „Lokalisierung“(Localization of German).
You can read the whole code of "LandmarkDetector.py","main.py" and"MainLandmarkDetection.py" here:
"LandmarkDetector.py":
#! /usr/bin/env python
# -*- encoding: UTF-8 -*-
"""Example: Demonstrates a way to localize the robot with
ALLandMarkDetection"""
import qi
import time
import sys
import argparse
import math
import almath
class LandmarkDetector(object):
"""
We first instantiate a proxy to the ALLandMarkDetection module
Note that this module should be loaded on the robot's naoqi.
The module output its results in ALMemory in a variable
called "LandmarkDetected".
We then read this ALMemory value and check whether we get
interesting things.
After that we get the related position of the landmark compared to robot.
"""
def __init__(self, app):
"""
Initialisation of qi framework and event detection.
"""
super(LandmarkDetector, self).__init__()
app.start()
session = app.session
# Get the service ALMemory.
self.memory = session.service("ALMemory")
# Connect the event callback.
# Get the services ALMotion & ALRobotPosture.
self.motion_service = session.service("ALMotion")
self.posture_service = session.service("ALRobotPosture")
self.subscriber = self.memory.subscriber("LandmarkDetected")
print "self.subscriber = self.memory.subscriber(LandmarkDetected)"
self.subscriber.signal.connect(self.on_landmark_detected)
print "self.subscriber.signal.connect(self.on_landmark_detected)"
# Get the services ALTextToSpeech, ALLandMarkDetection and ALMotion.
self.tts = session.service("ALTextToSpeech")
self.landmark_detection = session.service("ALLandMarkDetection")
# print "self.landmark_detection" is repr(self.landmark_detection)
self.motion_service = session.service("ALMotion")
self.landmark_detection.subscribe("LandmarkDetector", 500, 0.0 )
print "self.landmark_detection.subscribe(LandmarkDetector, 500, 0.0 )"
self.got_landmark = False
# Set here the size of the landmark in meters.
self.landmarkTheoreticalSize = 0.06 #in meters 0 #.05 or 0.06?
# Set here the current camera ("CameraTop" or "CameraBottom").
self.currentCamera = "CameraTop"
def on_landmark_detected(self, markData):
"""
Callback for event LandmarkDetected.
"""
while markData == [] : # empty value when the landmark disappears
self.got_landmark = False
self.motion_service.moveTo(0, 0, 0.1 * math.pi)
if not self.got_landmark: # only speak the first time a landmark appears
self.got_landmark = True
#stop.motion_service.moveTo
print "Ich sehe eine Landmarke! "
self.tts.say("Ich sehe eine Landmarke! ")
# Retrieve landmark center position in radians.
wzCamera = markData[1][0][0][1]
wyCamera = markData[1][0][0][2]
# Retrieve landmark angular size in radians.
angularSize = markData[1][0][0][3]
# Compute distance to landmark.
distanceFromCameraToLandmark = self.landmarkTheoreticalSize / ( 2 * math.tan( angularSize / 2))
# Get current camera position in NAO space.
transform = self.motion_service.getTransform(self.currentCamera, 2, True)
transformList = almath.vectorFloat(transform)
robotToCamera = almath.Transform(transformList)
# Compute the rotation to point towards the landmark.
cameraToLandmarkRotationTransform = almath.Transform_from3DRotation(0, wyCamera, wzCamera)
# Compute the translation to reach the landmark.
cameraToLandmarkTranslationTransform = almath.Transform(distanceFromCameraToLandmark, 0, 0)
# Combine all transformations to get the landmark position in NAO space.
robotToLandmark = robotToCamera * cameraToLandmarkRotationTransform *cameraToLandmarkTranslationTransform
# robotTurnAroundAngle = almath.rotationFromAngleDirection(0, 1, 1, 1)
# print "robotTurnAroundAngle = ", robotTurnAroundAngle
print "x " + str(robotToLandmark.r1_c4) + " (in meters)"
print "y " + str(robotToLandmark.r2_c4) + " (in meters)"
print "z " + str(robotToLandmark.r3_c4) + " (in meters)"
def run(self):
"""
Loop on, wait for events until manual interruption.
"""
# Wake up robot
self.motion_service.wakeUp()
# Send robot to Pose Init
self.posture_service.goToPosture("StandInit", 0.5)
# Example showing how to get a simplified robot position in world.
useSensorValues = False
result = self.motion_service.getRobotPosition(useSensorValues)
print "Robot Position", result
# Example showing how to use this information to know the robot's diplacement.
useSensorValues = False
# initRobotPosition = almath.Pose2D(self.motion_service.getRobotPosition(useSensorValues))
# Make the robot move
for i in range(1, 12, 1):
self.motion_service.moveTo(0, 0, 0.1 * math.pi)
print "self.motion_service.moveTo(0, 0, (0.1)*math.pi)"
print "Starting LandmarkDetector"
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print "Interrupted by user, stopping LandmarkDetector"
self.landmark_detection.unsubscribe("LandmarkDetector")
#stop
sys.exit(0)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--ip", type=str, default="10.0.0.10",
help="Robot IP address. On robot or Local Naoqi: use
'10.0.0.10'.")
parser.add_argument("--port", type=int, default=9559,
help="Naoqi port number")
args = parser.parse_args()
try:
# Initialize qi framework.
connection_url = "tcp://" + args.ip + ":" + str(args.port)
app = qi.Application(["LandmarkDetector", "--qi-url=" + connection_url])
except RuntimeError:
print ("Can't connect to Naoqi at ip \"" + args.ip + "\" on port " + str(args.port) +".\n"
"Please check your script arguments. Run with -h option for help.")
sys.exit(1)
landmark_detector = LandmarkDetector(app)
landmark_detector.run()
"main.py":
""" A sample showing how to make a Python script as an app. """
version = "0.0.8"
copyright = "Copyright 2015, Aldebaran Robotics"
author = 'YOURNAME'
email = 'YOUREMAIL#aldebaran.com'
import stk.runner
import stk.events
import stk.services
import stk.logging
class Activity(object):
"A sample standalone app, that demonstrates simple Python usage"
APP_ID = "com.aldebaran.lokalisierung"
def __init__(self, qiapp):
self.qiapp = qiapp
self.events = stk.events.EventHelper(qiapp.session)
self.s = stk.services.ServiceCache(qiapp.session)
self.logger = stk.logging.get_logger(qiapp.session, self.APP_ID)
def on_touched(self, *args):
"Callback for tablet touched."
if args:
self.events.disconnect("ALTabletService.onTouchDown")
self.logger.info("Tablet touched: " + str(args))
self.s.ALTextToSpeech.say("Yay!")
self.stop()
def on_start(self):
"Ask to be touched, waits, and exits."
# Two ways of waiting for events
# 1) block until it's called
self.s.ALTextToSpeech.say("Touch my forehead.")
self.logger.warning("Listening for touch...")
while not self.events.wait_for("FrontTactilTouched"):
pass
# 2) explicitly connect a callback
if self.s.ALTabletService:
self.events.connect("ALTabletService.onTouchDown", self.on_touched)
self.s.ALTextToSpeech.say("okay, now touch my tablet.")
# (this allows to simltaneously speak and watch an event)
else:
self.s.ALTextToSpeech.say("touch my tablet ... oh. " + \
"I don't haave one.")
self.stop()
def stop(self):
"Standard way of stopping the application."
self.qiapp.stop()
def on_stop(self):
"Cleanup"
self.logger.info("Application finished.")
self.events.clear()
if __name__ == "__main__":
stk.runner.run_activity(Activity)
"MainLandmarkDetection.py":
#! /usr/bin/env python
# -*- encoding: UTF-8 -*-
"""A sample showing how to make a Python script as an app to localize
the robot with ALLandMarkDetection"""
version = "0.0.8"
copyright = "Copyright 2015, Aldebaran Robotics"
author = 'YOURNAME'
email = 'YOUREMAIL#aldebaran.com'
import stk.runner
import stk.events
import stk.services
import stk.logging
import time
import sys
import math
import almath
class Activity(object):
"A sample standalone app, that demonstrates simple Python usage"
APP_ID = "com.aldebaran.lokalisierung"
def __init__(self, qiapp):
self.qiapp = qiapp
self.events = stk.events.EventHelper(qiapp.session)
self.s = stk.services.ServiceCache(qiapp.session)
self.logger = stk.logging.get_logger(qiapp.session, self.APP_ID)
self.qiapp.start()
session = qiapp.session
# Get the service ALMemory.
self.memory = session.service("ALMemory")
# Connect the event callback.
# Get the services ALMotion & ALRobotPosture.
self.motion_service = session.service("ALMotion")
self.posture_service = session.service("ALRobotPosture")
self.subscriber = self.memory.subscriber("LandmarkDetected")
print "self.subscriber = self.memory.subscriber(LandmarkDetected)"
self.subscriber.signal.connect(self.on_landmark_detected)
print "self.subscriber.signal.connect(self.on_landmark_detected)"
# Get the services ALTextToSpeech, ALLandMarkDetection and ALMotion.
self.tts = session.service("ALTextToSpeech")
self.landmark_detection = session.service("ALLandMarkDetection")
# print "self.landmark_detection" is repr(self.landmark_detection)
self.motion_service = session.service("ALMotion")
self.landmark_detection.subscribe("Activity", 500, 0.0)
print "self.landmark_detection.subscribe(Activity, 500, 0.0 )"
self.got_landmark = False
# Set here the size of the landmark in meters.
self.landmarkTheoreticalSize = 0.06 # in meters 0 #.05 or 0.06?
# Set here the current camera ("CameraTop" or "CameraBottom").
self.currentCamera = "CameraTop"
def on_landmark_detected(self, markData):
"""
Callback for event LandmarkDetected.
"""
while markData == []: # empty value when the landmark disappears
self.got_landmark = False
# self.motion_service.moveTo(0, 0, 0.1 * math.pi)
if not self.got_landmark: # only speak the first time a landmark appears
self.got_landmark = True
# stop.motion_service.moveTo
print "Ich sehe eine Landmarke! "
# self.tts.say("Ich sehe eine Landmarke! ")
# Retrieve landmark center position in radians.
wzCamera = markData[1][0][0][1]
wyCamera = markData[1][0][0][2]
# Retrieve landmark angular size in radians.
angularSize = markData[1][0][0][3]
# Compute distance to landmark.
distanceFromCameraToLandmark = self.landmarkTheoreticalSize / (2 * math.tan(angularSize / 2))
# Get current camera position in NAO space.
transform = self.motion_service.getTransform(self.currentCamera, 2, True)
transformList = almath.vectorFloat(transform)
robotToCamera = almath.Transform(transformList)
# Compute the rotation to point towards the landmark.
cameraToLandmarkRotationTransform = almath.Transform_from3DRotation(0, wyCamera, wzCamera)
# Compute the translation to reach the landmark.
cameraToLandmarkTranslationTransform = almath.Transform(distanceFromCameraToLandmark, 0, 0)
# Combine all transformations to get the landmark position in NAO space.
robotToLandmark = robotToCamera * cameraToLandmarkRotationTransform * cameraToLandmarkTranslationTransform
# robotTurnAroundAngle = almath.rotationFromAngleDirection(0, 1, 1, 1)
# print "robotTurnAroundAngle = ", robotTurnAroundAngle
print "x " + str(robotToLandmark.r1_c4) + " (in meters)"
print "y " + str(robotToLandmark.r2_c4) + " (in meters)"
print "z " + str(robotToLandmark.r3_c4) + " (in meters)"
def run(self):
"""
Loop on, wait for events until manual interruption.
"""
# Wake up robot
self.motion_service.wakeUp()
# Send robot to Pose Init
self.posture_service.goToPosture("StandInit", 0.5)
# Example showing how to get a simplified robot position in world.
useSensorValues = False
result = self.motion_service.getRobotPosition(useSensorValues)
print "Robot Position", result
# Example showing how to use this information to know the robot's diplacement.
useSensorValues = False
# initRobotPosition = almath.Pose2D(self.motion_service.getRobotPosition(useSensorValues))
# Make the robot move
for i in range(1, 20, 1):
self.motion_service.moveTo(0, 0, 0.1 * math.pi)
print "self.motion_service.moveTo(0, 0, (0.1)*math.pi)"
print "Starting Activity"
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print "Interrupted by user, stopping Activity"
self.landmark_detection.unsubscribe("Activity")
# stop
sys.exit(0)
def stop(self):
"Standard way of stopping the application."
self.qiapp.stop()
def on_stop(self):
"Cleanup"
self.logger.info("Application finished.")
self.events.clear()
if __name__ == "__main__":
stk.runner.run_activity(Activity)
landmark_detector = Activity()
landmark_detector.run()
This is how it worked in cmd.exe:
And I have a question to the parameter by ”landmark_detector = Activity()” in line 157 at almost the end of the program because of the Error in the image, which I should pass. After reading the answers to the similar question here by StackoverflowPython: TypeError: __init__() takes exactly 2 arguments (1 given), I am still confused. I think it should be a value which is given to the "qiapp", but what value?
Best regards,
Frederik
Actually, when you call
stk.runner.run_activity(Activity)
... it will instantiate that activity object for you, with the right parameters, you don't need to landmark_detector = Activity() etc. in MainLandmarkDetector.py
And if this object has a method called on_start, that method will be called once everything is ready (so you may only need to rename your run() method to on_start()
Note also that instead of calling sys.stop(), you can just call self.stop() or self.qiapp.stop() (which is a bit cleaner in terms of letting the cleanup code in on_stop to be called, if you need to unsubscribe to things etc.)
See here for some documentation on stk.runner.
Note also that instead of doing
self.motion_service = session.service("ALMotion")
(...)
transform = self.motion_service.getTransform(self.currentCamera, 2, True)
you can directly do
transform = self.s.ALMotion.getTransform(self.currentCamera, 2, True)
... which (in my opinion) makes it easier to see what is being done exactly (and reduces the number of variables).
I have a python program that controls a Brookstone Rover 2.0 from a computer through openCV and pygame and I've been working on this for 7 hours now and it has been nothing but errors after errors and this is what it's showing me now
PS C:\users\sessi\desktop> C:\Users\sessi\Desktop\rover\ps3rover20.py
Traceback (most recent call last):
File "C:\Users\sessi\Desktop\rover\ps3rover20.py", line 168, in <module>
rover = PS3Rover()
File "C:\Users\sessi\Desktop\rover\ps3rover20.py", line 58, in __init__
Rover20.__init__(self)
File "C:\Program Files\Python 3.5\lib\site-packages\roverpylot-0.1-py3.5.egg\rover\__init__.py", line 182, in __init__
Rover.__init__(self)
File "C:\Program Files\Python 3.5\lib\site-packages\roverpylot-0.1-py3.5.egg\rover\__init__.py", line 47, in __init__
self._sendCommandIntRequest(0, [0, 0, 0, 0])
File "C:\Program Files\Python 3.5\lib\site-packages\roverpylot-0.1-py3.5.egg\rover\__init__.py", line 149, in _sendCommandIntRequest
bytevals.append(ord(c))
TypeError: ord() expected string of length 1, but int found
These are the two files that it's getting errors from
ps3rover20.py
#!/usr/bin/env python
'''
ps3rover20.py Drive the Brookstone Rover 2.0 via the P3 Controller, displaying
the streaming video using OpenCV.
Copyright (C) 2014 Simon D. Levy
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
'''
# You may want to adjust these buttons for your own controller
BUTTON_LIGHTS = 3 # Square button toggles lights
BUTTON_STEALTH = 1 # Circle button toggles stealth mode
BUTTON_CAMERA_UP = 0 # Triangle button raises camera
BUTTON_CAMERA_DOWN = 2 # X button lowers camera
# Avoid button bounce by enforcing lag between button events
MIN_BUTTON_LAG_SEC = 0.5
# Avoid close-to-zero values on axis
MIN_AXIS_ABSVAL = 0.01
from rover import Rover20
import time
import pygame
import sys
import signal
# Supports CTRL-C to override threads
def _signal_handler(signal, frame):
frame.f_locals['rover'].close()
sys.exit(0)
# Try to start OpenCV for video
try:
import cv
except:
cv = None
# Rover subclass for PS3 + OpenCV
class PS3Rover(Rover20):
def __init__(self):
# Set up basics
Rover20.__init__(self)
self.wname = 'Rover 2.0: Hit ESC to quit'
self.quit = False
# Set up controller using PyGame
pygame.display.init()
pygame.joystick.init()
self.controller = pygame.joystick.Joystick(0)
self.controller.init()
# Defaults on startup: lights off, ordinary camera
self.lightsAreOn = False
self.stealthIsOn = False
# Tracks button-press times for debouncing
self.lastButtonTime = 0
# Try to create OpenCV named window
try:
if cv:
cv.NamedWindow(self.wname, cv.CV_WINDOW_AUTOSIZE )
else:
pass
except:
pass
self.pcmfile = open('rover20.pcm', 'w')
# Automagically called by Rover class
def processAudio(self, pcmsamples, timestamp_10msec):
for samp in pcmsamples:
self.pcmfile.write('%d\n' % samp)
# Automagically called by Rover class
def processVideo(self, jpegbytes, timestamp_10msec):
# Update controller events
pygame.event.pump()
# Toggle lights
self.lightsAreOn = self.checkButton(self.lightsAreOn, BUTTON_LIGHTS, self.turnLightsOn, self.turnLightsOff)
# Toggle night vision (infrared camera)
self.stealthIsOn = self.checkButton(self.stealthIsOn, BUTTON_STEALTH, self.turnStealthOn, self.turnStealthOff)
# Move camera up/down
if self.controller.get_button(BUTTON_CAMERA_UP):
self.moveCameraVertical(1)
elif self.controller.get_button(BUTTON_CAMERA_DOWN):
self.moveCameraVertical(-1)
else:
self.moveCameraVertical(0)
# Set treads based on axes
self.setTreads(self.axis(1), self.axis(3))
# Display video image if possible
try:
if cv:
# Save image to file on disk and load as OpenCV image
fname = 'tmp.jpg'
fd = open(fname, 'w')
fd.write(jpegbytes)
fd.close()
image = cv.LoadImage(fname)
# Show image
cv.ShowImage(self.wname, image )
if cv.WaitKey(1) & 0xFF == 27: # ESC
self.quit = True
else:
pass
except:
pass
# Converts Y coordinate of specified axis to +/-1 or 0
def axis(self, index):
value = -self.controller.get_axis(index)
if value > MIN_AXIS_ABSVAL:
return 1
elif value < -MIN_AXIS_ABSVAL:
return -1
else:
return 0
# Handles button bounce by waiting a specified time between button presses
def checkButton(self, flag, buttonID, onRoutine=None, offRoutine=None):
if self.controller.get_button(buttonID):
if (time.time() - self.lastButtonTime) > MIN_BUTTON_LAG_SEC:
self.lastButtonTime = time.time()
if flag:
if offRoutine:
offRoutine()
flag = False
else:
if onRoutine:
onRoutine()
flag = True
return flag
# main -----------------------------------------------------------------------------------
if __name__ == '__main__':
# Create a PS3 Rover object
rover = PS3Rover()
# Set up signal handler for CTRL-C
signal.signal(signal.SIGINT, _signal_handler)
# Loop until user hits quit button on controller
while not rover.quit:
pass
# Shut down Rover
rover.close()
__ init__.py
'''
Python classes for interacting with the Brookstone Rover 2.0
and Rover Revolution
Copyright (C) 2015 Simon D. Levy
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
'''
import struct
import threading
import socket
import time
from blowfish import Blowfish
from adpcm import decodeADPCMToPCM
from byteutils import *
class Rover:
def __init__(self):
''' Creates a Rover object that you can communicate with.
'''
self.HOST = '192.168.1.100'
self.PORT = 80
TARGET_ID = 'AC13'
TARGET_PASSWORD = 'AC13'
self.TREAD_DELAY_SEC = 1.0
self.KEEPALIVE_PERIOD_SEC = 60
# Create command socket connection to Rover
self.commandsock = self._newSocket()
# Send login request with four arbitrary numbers
self._sendCommandIntRequest(0, [0, 0, 0, 0])
# Get login reply
reply = self._receiveCommandReply(82)
# Extract Blowfish key from camera ID in reply
cameraID = reply[25:37].decode('utf-8')
key = TARGET_ID + ':' + cameraID + '-save-private:' + TARGET_PASSWORD
# Extract Blowfish inputs from rest of reply
L1 = bytes_to_int(reply, 66)
R1 = bytes_to_int(reply, 70)
L2 = bytes_to_int(reply, 74)
R2 = bytes_to_int(reply, 78)
# Make Blowfish cipher from key
bf = _RoverBlowfish(key)
# Encrypt inputs from reply
L1,R1 = bf.encrypt(L1, R1)
L2,R2 = bf.encrypt(L2, R2)
# Send encrypted reply to Rover
self._sendCommandIntRequest(2, [L1, R1, L2, R2])
# Ignore reply from Rover
self._receiveCommandReply(26)
# Start timer task for keep-alive message every 60 seconds
self._startKeepaliveTask()
# Set up vertical camera controller
self.cameraVertical = _RoverCamera(self, 1)
# Send video-start request
self._sendCommandIntRequest(4, [1])
# Get reply from Rover
reply = self._receiveCommandReply(29)
# Create media socket connection to Rover
self.mediasock = self._newSocket()
# Send video-start request based on last four bytes of reply
self._sendRequest(self.mediasock, 'V', 0, 4, map(ord, reply[25:]))
# Send audio-start request
self._sendCommandByteRequest(8, [1])
# Ignore audio-start reply
self._receiveCommandReply(25)
# Receive images on another thread until closed
self.is_active = True
self.reader_thread = _MediaThread(self)
self.reader_thread.start()
def close(self):
''' Closes off commuincation with Rover.
'''
self.keepalive_timer.cancel()
self.is_active = False
self.commandsock.close()
if self.mediasock:
self.mediasock.close()
def turnStealthOn(self):
''' Turns on stealth mode (infrared).
'''
self._sendCameraRequest(94)
def turnStealthOff(self):
''' Turns off stealth mode (infrared).
'''
self._sendCameraRequest(95)
def moveCameraVertical(self, where):
''' Moves the camera up or down, or stops moving it. A nonzero value for the
where parameter causes the camera to move up (+) or down (-). A
zero value stops the camera from moving.
'''
self.cameraVertical.move(where)
def _startKeepaliveTask(self,):
self._sendCommandByteRequest(255)
self.keepalive_timer = \
threading.Timer(self.KEEPALIVE_PERIOD_SEC, self._startKeepaliveTask, [])
self.keepalive_timer.start()
def _sendCommandByteRequest(self, id, bytes=[]):
self._sendCommandRequest(id, len(bytes), bytes)
def _sendCommandIntRequest(self, id, intvals):
bytevals = []
for val in intvals:
for c in struct.pack('I', val):
bytevals.append(ord(c))
self._sendCommandRequest(id, 4*len(intvals), bytevals)
def _sendCommandRequest(self, id, n, contents):
self._sendRequest(self.commandsock, 'O', id, n, contents)
def _sendRequest(self, sock, c, id, n, contents):
bytes = [ord('M'), ord('O'), ord('_'), ord(c), id, \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, n, 0, 0, 0, 0, 0, 0, 0]
bytes.extend(contents)
request = ''.join(map(chr, bytes))
sock.send(request)
def _receiveCommandReply(self, count):
reply = self.commandsock.recv(count)
return reply
def _newSocket(self):
sock = socket.socket()
sock.connect((self.HOST, self.PORT))
return sock
def _sendDeviceControlRequest(self, a, b) :
self._sendCommandByteRequest(250, [a,b])
def _sendCameraRequest(self, request):
self._sendCommandByteRequest(14, [request])
class Rover20(Rover):
def __init__(self):
Rover.__init__(self)
# Set up treads
self.leftTread = _RoverTread(self, 4)
self.rightTread = _RoverTread(self, 1)
def close(self):
''' Closes off commuincation with Rover.
'''
Rover.close(self)
# Stop moving treads
self.setTreads(0, 0)
def getBatteryPercentage(self):
''' Returns percentage of battery remaining.
'''
self._sendCommandByteRequest(251)
reply = self._receiveCommandReply(32)
return 15 * ord(reply[23])
def setTreads(self, left, right):
''' Sets the speed of the left and right treads (wheels). + = forward;
- = backward; 0 = stop. Values should be in [-1..+1].
'''
currTime = time.time()
self.leftTread.update(left)
self.rightTread.update(right)
def turnLightsOn(self):
''' Turns the headlights and taillights on.
'''
self._setLights(8)
def turnLightsOff(self):
''' Turns the headlights and taillights off.
'''
self._setLights(9)
def _setLights(self, onoff):
self._sendDeviceControlRequest(onoff, 0)
def processVideo(self, jpegbytes, timestamp_10msec):
''' Proccesses bytes from a JPEG image streamed from Rover.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def processAudio(self, pcmsamples, timestamp_10msec):
''' Proccesses a block of 320 PCM audio samples streamed from Rover.
Audio is sampled at 8192 Hz and quantized to +/- 2^15.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def _spinWheels(self, wheeldir, speed):
# 1: Right, forward
# 2: Right, backward
# 4: Left, forward
# 5: Left, backward
self._sendDeviceControlRequest(wheeldir, speed)
class Revolution(Rover):
def __init__(self):
Rover.__init__(self)
self.steerdir_prev = 0
self.command_prev = 0
self.goslow_prev = 0
self.using_turret = False
# Set up vertical camera controller
self.cameraHorizontal = _RoverCamera(self, 5)
def drive(self, wheeldir, steerdir, goslow):
goslow = 1 if goslow else 0
command = 0
if wheeldir == +1 and steerdir == 0:
command = 1
if wheeldir == -1 and steerdir == 0:
command = 2
if wheeldir == 0 and steerdir == +1:
command = 4
if wheeldir == 0 and steerdir == -1:
command = 5
if wheeldir == +1 and steerdir == -1:
command = 6
if wheeldir == +1 and steerdir == +1:
command = 7
if wheeldir == -1 and steerdir == -1:
command = 8
if wheeldir == -1 and steerdir == +1:
command = 9
if steerdir == 0 and self.steerdir_prev != 0:
command = 3
if command != self.command_prev or goslow != self.goslow_prev:
self._sendDeviceControlRequest(command, goslow)
self.steerdir_prev = steerdir
self.command_prev = command
self.goslow_prev = goslow
def processVideo(self, imgbytes, timestamp_msec):
''' Proccesses bytes from an image streamed from Rover.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def processAudio(self, audiobytes, timestamp_msec):
''' Proccesses a block of 1024 PCM audio samples streamed from Rover.
Audio is sampled at 8192 Hz and quantized to +/- 2^15.
Default method is a no-op; subclass and override to do something
interesting.
'''
pass
def useTurretCamera(self):
''' Switches to turret camera.
'''
self._sendUseCameraRequest(1)
def useDrivingCamera(self):
''' Switches to driving camera.
'''
self._sendUseCameraRequest(2)
def moveCameraHorizontal(self, where):
''' Moves the camera up or down, or stops moving it. A nonzero value for the
where parameter causes the camera to move up (+) or down (-). A
zero value stops the camera from moving.
'''
self.cameraHorizontal.move(where)
def _sendUseCameraRequest(self, camera):
self._sendCommandByteRequest(19, [6, camera])
# "Private" classes ===========================================================
# A special Blowfish variant with P-arrays set to zero instead of digits of Pi
class _RoverBlowfish(Blowfish):
def __init__(self, key):
ORIG_P = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
self._keygen(key, ORIG_P)
# A thread for reading streaming media from the Rover
class _MediaThread(threading.Thread):
def __init__(self, rover):
threading.Thread.__init__(self)
self.rover = rover
self.BUFSIZE = 1024
def run(self):
# Accumulates media bytes
mediabytes = ''
# Starts True; set to False by Rover.close()
while self.rover.is_active:
# Grab bytes from rover, halting on failure
try:
buf = self.rover.mediasock.recv(self.BUFSIZE)
except:
break
# Do we have a media frame start?
k = buf.find('MO_V')
# Yes
if k >= 0:
# Already have media bytes?
if len(mediabytes) > 0:
# Yes: add to media bytes up through start of new
mediabytes += buf[0:k]
# Both video and audio messages are time-stamped in 10msec units
timestamp = bytes_to_uint(mediabytes, 23)
# Video bytes: call processing routine
if ord(mediabytes[4]) == 1:
self.rover.processVideo(mediabytes[36:], timestamp)
# Audio bytes: call processing routine
else:
audsize = bytes_to_uint(mediabytes, 36)
sampend = 40 + audsize
offset = bytes_to_short(mediabytes, sampend)
index = ord(mediabytes[sampend+2])
pcmsamples = decodeADPCMToPCM(mediabytes[40:sampend], offset, index)
self.rover.processAudio(pcmsamples, timestamp)
# Start over with new bytes
mediabytes = buf[k:]
# No media bytes yet: start with new bytes
else:
mediabytes = buf[k:]
# No: accumulate media bytes
else:
mediabytes += buf
class _RoverTread(object):
def __init__(self, rover, index):
self.rover = rover
self.index = index
self.isMoving = False
self.startTime = 0
def update(self, value):
if value == 0:
if self.isMoving:
self.rover._spinWheels(self.index, 0)
self.isMoving = False
else:
if value > 0:
wheel = self.index
else:
wheel = self.index + 1
currTime = time.time()
if (currTime - self.startTime) > self.rover.TREAD_DELAY_SEC:
self.startTime = currTime
self.rover._spinWheels(wheel, int(round(abs(value)*10)))
self.isMoving = True
class _RoverCamera(object):
def __init__(self, rover, stopcmd):
self.rover = rover
self.stopcmd = stopcmd
self.isMoving = False
def move(self, where):
if where == 0:
if self.isMoving:
self.rover._sendCameraRequest(self.stopcmd)
self.isMoving = False
elif not self.isMoving:
if where == 1:
self.rover._sendCameraRequest(self.stopcmd-1)
else:
self.rover._sendCameraRequest(self.stopcmd+1)
self.isMoving = True
I know almost nothing about python by the way.
I'm using windows 10 64 bit
At
https://github.com/simondlevy/RoverPylot
it says:
Tips for Windows
Rob Crawley has put a lot of work into getting RoverPylot to work
smoothly on Windows 10. Here are his changes:
Original: # Create a named temporary file for video stream tmpfile =
tempfile.NamedTemporaryFile()
Changed to: tmpfile = tempfile.NamedTemporaryFile(mode='w+b',
bufsize=0 , suffix='.avi', prefix='RoverRev',
dir='\Python27\RoverRev_WinPylot', delete=False) Original: # Wait a
few seconds, then being playing the tmp video file cmd = 'ffplay
-window_title Rover_Revolution -framerate %d %s' % (FRAMERATE, tmpfile.name)
Changed to: cmd = '/Python27/ffmpeg/bin/ffplay.exe -x 640 -y 480
-window_title Rover_Revolution -framerate %d %s' % (FRAMERATE, tmpfile.name) Your files paths may be different than those listed
below, so make your changes accordingly
Which means that the author uses Python 2.7. From your error reports I gather you use Python 3.5, which treats bytes differently. Install and use 2.7 instead.
I am trying to filter an objectlistview based on a text value in a certain column of my data. I can't figure out how to construct the filter properly. I have been refering to:
http://objectlistview.sourceforge.net/python/features.html
http://objectlistview.sourceforge.net/python/majorClasses.html
I am able to get Filter.Head(n) to work sucessfully but not ableto get Filter.TextSearch(objectListView, columns=(), text="") to work because I don't understand what the parameter types are suppost to be.
I have written the below code:
def OnFilterMeter(self,event):
list = self.exception_panel.col_list ## The lenght of my column list
col = list[len(list)-1] ## I want to search the last column
meter_flt = Filter.TextSearch(self.exception_panel,columns = (col), text = "10") ## Create filter to find string 10 in last column
self.exception_panel.SetFilter(meter_flt)
self.exception_panel.populate()
I can't understand why this doesn't work. The program doesn't filter the list when it tries to populate the list view again. At the very least it should show all blanks because it cannot find any items that are equal to "10". Please help. Thank you
Below is my code :
class Display_Manager(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, -1, title)
self.exception_panel = Exception_Display(self,0)
# self.exception_panel2 = Exception_Display(self,1)
## Setup FileMenu Bar Setup
filemenu= wx.Menu() ## Create Menu Bar
filemenu.Append(ID_LOG,"Login","Login as user with password.") ## Clicking shoudl load a single dailyi report which user selects
filemenu.Append(ID_LOAD,"Load Report","Load Daliy Exception Report") ## Clicking shoudl load a single dailyi report which user selects
filemenu.Append(ID_LOADS,"Load All","Load All Daliy Exception Reports") ## Clicking should load all daily reports in a directory which user selects
filemenu.Append(ID_REFRESH,"Refresh DB","Refresh Database. Overwrites any un saved data.") ## Clicking should refreseh the database and overwrite any unsaved changes
filemenu.Append(ID_SAVE,"Save DB","Saves and commits any changes to database.") ## Clicking will save and commit any changes or new data to the database
filemenu.Append(ID_EXIT,"E&xit"," Terminate the program") ## exit the program
## Setup Edit Menu Bar
editmenu = wx.Menu()
editmenu.Append(ID_ADD,"Add","Add Exception")
editmenu.Append(ID_DELETE,"Delete","Delete Exception")
editmenu.Append(ID_UNDO,"Stepback DB","Go back to a previous version of the database")
editmenu.Append(ID_REDO,"Stepfoward DB","Go foward to a previous version of the database")
## Setup Report Menu
reportmenu = wx.Menu()
reportmenu.Append(ID_REPORT,"Exception Report","Generate an Excel Report of selected exceptions.")
reportmenu.Append(ID_REPORT2,"Meter Report","Generate an Excel Report of selected exceptions.")
reportmenu.Append(ID_REPORT3,"Transformer Report","Generate an Excel Report of selected exceptions.")
## Setup Bucket Menu
bucketmenu = wx.Menu()
bucketmenu.Append(ID_METERPROB,"Meter Problem","Place the meter in the meter problem bucket.")
bucketmenu.Append(ID_LOWVOLT,"Investigate Low Voltage","Place the meter in the investigate bucket.")
bucketmenu.Append(ID_TURNS,"Turns Ratio","Place the meter in the turns ratio bucket.")
## Setup Configure Menu Menu
configmenu = wx.Menu()
configmenu.Append(ID_FILTER,"Set Filters","Filter by district and company.")
configmenu.Append(ID_SAVEFIL,"Save Filters","Save Filters for Later use.")
configmenu.Append(ID_LOADFIL,"Load Filters","Load Filters for Later use.")
## Add file menu bar
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File")
menuBar.Append(editmenu, "&Edit")
menuBar.Append(reportmenu, "&Reports")
menuBar.Append(configmenu, "&Config")
menuBar.Append(bucketmenu, "&Bucket")
self.SetMenuBar(menuBar)
## Create Toolbar
tb = self.CreateToolBar( wx.TB_HORIZONTAL | wx.NO_BORDER |
wx.TB_FLAT | wx.TB_TEXT)
tb.AddSimpleTool(10, wx.Bitmap('images/database.png'), 'Save Database')
tb.AddSimpleTool(20, wx.Bitmap('images/excel.png'), 'Get Quick Excel Report')
tb.AddSimpleTool(70, wx.Bitmap('images/analyze.png'), 'Analyze Selected Exceptions')
tb.AddSimpleTool(71, wx.Bitmap('images/refresh.png'), 'Refresh Selected Relationships')
tb.AddSeparator()
tb.AddSimpleTool(30, wx.Bitmap('images/today.png'), 'Filter only the latest data.')
tb.AddSimpleTool(40, wx.Bitmap('images/all_time.png'), 'Filter All Data from all time')
tb.AddSimpleTool(41, wx.Bitmap('images/date_range.png'), 'Select a date range to view data over')
tb.AddSeparator()
tb.AddSimpleTool(50, wx.Bitmap('images/AMI_Meter.png'), 'Bucket as meter problem')
tb.AddSimpleTool(60, wx.Bitmap('images/violation.png'), 'Bucket to District')
tb.AddSimpleTool(61, wx.Bitmap('images/turns.png'), 'Bucket Turns Ratio')
tb.AddSimpleTool(62, wx.Bitmap('images/plan.png'), 'Bucket for further review for planning engineer')
tb.AddSeparator()
tb.AddSimpleTool(63, wx.Bitmap('images/cyme.png'), 'Load CYME model for specific meter')
tb.AddSimpleTool(64, wx.Bitmap('images/relate_dot.png'), 'Cluster & Relate Meter Exceptions')
tb.AddSeparator()
tb.AddSimpleTool(65, wx.Bitmap('images/bucket_m.png'), 'Filter Meter Bucket')
tb.AddSimpleTool(66, wx.Bitmap('images/bucket_v.png'), 'Filter Violation Bucket')
tb.AddSimpleTool(67, wx.Bitmap('images/bucket_t.png'), 'Filter Turns Ratio Bucket')
tb.AddSimpleTool(68, wx.Bitmap('images/bucket_p.png'), 'Filter Planning Bucket')
tb.SetToolBitmapSize((84,84))
tb.Realize()
self.Bind(wx.EVT_TOOL,self.OnRefresh,id =71)
self.Bind(wx.EVT_TOOL,self.OnAnalyze,id =70)
self.Bind(wx.EVT_TOOL,self.OnSave,id =10)
self.Bind(wx.EVT_TOOL,self.OnBucketMeter,id =50)
self.Bind(wx.EVT_TOOL,self.OnVioMeter,id =60)
self.Bind(wx.EVT_TOOL,self.OnTurnsMeter,id =61)
self.Bind(wx.EVT_TOOL,self.OnPlanMeter,id =62)
self.Bind(wx.EVT_TOOL,self.OnFilterMeter,id =65)
# self.Bind(wx.EVT_TOOL,self.OnFilterMeter,id =66)
# self.Bind(wx.EVT_TOOL,self.OnFilterMeter,id =67)
# self.Bind(wx.EVT_TOOL,self.OnFilterMeter,id =68)
## Create Sizers
# self.main_sizer = wx.BoxSizer(wx.VERTICAL)
# self.top_sizer = wx.BoxSizer(wx.HORIZONTAL)
# self.bottom_sizer = wx.BoxSizer(wx.HORIZONTAL)
# self.main_sizer.Add(self.top_sizer,0,wx.EXPAND)
# self.main_sizer.Add(self.bottom_sizer,0,wx.EXPAND)
## Show the frame
# self.SetSizer(self.main_sizer)
self.Center()
self.Show(True)
def OnSave(self,event):
session.commit()
print "ON Save"
def OnRefresh(self,event):
self.exception_panel.populate()
self.ColorBuckets()
print "OnRelate"
def OnAnalyze(self,event):
objectList = self.exception_panel.GetSelectedObjects() ## Get list of selected objects to relate in the database
for object in objectList:
print object
object.calculate()
# print self.GetValueAt(self.GetObjectAt(event.rowIndex),event.subItemIndex)
# self.temp_value = event.editor.GetValue()
self.exception_panel.populate()
print "OnAnalze"
def OnFilterDate1(self,event):
print "on Filter date"
def OnFilterDate2(self,event):
print "on Filter date"
def OnFilterDate3(self,event):
print "on Filter date"
def OnFilterMeter(self,event):
list = self.exception_panel.col_list
col = list[len(list)-1]
# meter_flt = Filter.Head(10)
meter_flt = Filter.TextSearch(self.exception_panel,columns = (col), text = "10")
self.exception_panel.SetFilter(meter_flt)
self.exception_panel.populate()
# self.exception_panel.Refresh()
# self.exception_panel.populate()
# self.exception_panel.SetObjects(qrty_meters_excpt)
# self.exception_panel.populate()
print "On Filter Meter"
def OnBucketMeter(self,event):
objectList = self.exception_panel.GetSelectedObjects()
for object in objectList:
print object
object.known_flags = 20 ## Meter Mismatch Flag Known ***ffa500
self.exception_panel.populate()
self.ColorBuckets()
def OnVioMeter(self,event):
objectList = self.exception_panel.GetSelectedObjects()
for object in objectList:
object.known_flags = 10 ## Meter Mismatch Flag Known ***ffa500
self.exception_panel.populate()
self.ColorBuckets()
def OnTurnsMeter(self,event):
objectList = self.exception_panel.GetSelectedObjects()
for object in objectList:
object.known_flags = 30 ## Meter Mismatch Flag Known ***ffa500
self.exception_panel.populate()
self.ColorBuckets()
def OnPlanMeter(self,event):
objectList = self.exception_panel.GetSelectedObjects()
for object in objectList:
object.known_flags = 40 ## Meter Mismatch Flag Known ***ffa500
self.exception_panel.populate()
self.ColorBuckets()
def ColorBuckets(self): ## Color All Buckets according to knowflags
## Query the session for only items that have know_flags greate than 0
qrty_color_buckets = session.query(Exception).filter(Exception.known_flags != "").all()
print qrty_color_buckets
for exception in qrty_color_buckets:
print exception.known_flags == 10
flag = int(exception.known_flags) ## alias the flag
if flag == 20: ## Meter Mismatch
self.exception_panel.SetItemBackgroundColour(self.exception_panel.GetIndexOf(exception),'#ffa500') ## Oranage
elif flag == 10: ## Violation
self.exception_panel.SetItemBackgroundColour(self.exception_panel.GetIndexOf(exception),'#ff0000') ## Red
elif flag == 30: ## Turns Ratio
self.exception_panel.SetItemBackgroundColour(self.exception_panel.GetIndexOf(exception),'#0066CC') ## Blue
elif flag == 40: ## Plan referal
self.exception_panel.SetItemBackgroundColour(self.exception_panel.GetIndexOf(exception),'#FFFF00') ## Yellow
Please see the function OnFilterMeter.
The following works for me, it does a search on the second column and it shows just one matching entry.
# -*- coding: utf-8 -*-
import datetime
import wx
import wx.lib.sized_controls as SC
import ObjectListView as OLV
class MyData:
def __init__(self, year, month, day, level, sets, reps):
self.date = datetime.date(year, month, day)
self.level = level
self.sets = sets
self.reps = reps
def GetDate(self):
return self.date
def GetLevel(self):
return self.level
def GetSets(self):
return self.sets
def GetRepetitions(self):
return self.reps
class MyListCtrl(OLV.GroupListView):
def __init__(self, parent):
super(MyListCtrl, self).__init__(parent, wx.ID_ANY, style=wx.LC_REPORT)
self.SetColumns(self._ColumnDefinitions())
meter_flt = OLV.Filter.TextSearch(self, columns=self.columns[2:3],
text="7")
self.SetFilter(meter_flt)
self.SetObjects(self._DataObjects())
def _DataObjects(self):
return [MyData(2010,10,8, 1, 2, 3),
MyData(2005,10,10, 7, 2, 3),
MyData(2010,10,3, 2, 2, 3),
MyData(2012,10,10, 1, 2, 3),
MyData(2014,10,10, 1, 2, 3)
]
def _ColumnDefinitions(self):
return [OLV.ColumnDefn('Date', valueGetter='GetDate', groupKeyGetter='GetDate'),
OLV.ColumnDefn('Level', valueGetter='GetLevel', width=150),
OLV.ColumnDefn('Sets', valueGetter='GetSets', width=100, groupKeyGetter='GetSets'),
OLV.ColumnDefn('Reps', valueGetter='GetRepetitions', width=200)]
class MyFrame(SC.SizedFrame):
def __init__(self):
super(MyFrame, self).__init__(None)
pane = self.GetContentsPane()
olv = MyListCtrl(pane)
olv.SetSizerProps(expand=True, proportion=1)
if __name__ == '__main__':
import wx.lib.mixins.inspection as WIT
app = WIT.InspectableApp()
win = MyFrame()
win.Show()
app.MainLoop()
Ok, let's get straight to the point. I got 2 questions
1. Why self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "fore:#000000" + FontSet) not working?
2. Why the custom lexer is not applied?
This is the source code
import wx, re, keyword
from wx import stc
class BaseLexer(object):
"""Defines simple interface for custom lexer objects"""
def __init__(self):
super(BaseLexer, self).__init__()
def StyleText(self, event):
raise NotImplementedError
class STC_LEX_VOTONUSA(BaseLexer):
# Define some style IDs
STC_VOTONUSA_DEFAULT = wx.NewId()
STC_VOTONUSA_VALUE = wx.NewId()
STC_VOTONUSA_OBJECT = wx.NewId()
STC_VOTONUSA_TYPE = wx.NewId()
STC_VOTONUSA_OPERATION = wx.NewId()
STC_VOTONUSA_COMMENT =wx.NewId()
STC_VOTONUSA_QUALIFIER = wx.NewId()
def __init__(self):
super(STC_LEX_VOTONUSA, self).__init__()
# Attributes
self.Comment = re.compile("""
//
""", re.X)
self.Types = re.compile("""
\\b
(void|integer|shortint|(short)?word|float|boolean|char|record|program|module)
\\b
""", re.I|re.X)
self.Operation = re.compile("""
(read|write)(line)?|if|main|case|while|use|return|exit|in_case|repeat_until
(\+|-|\*|/|%|\*\*|:|!|<|>)?=?|
(\{|\}|\(|\)|\[|\])
""", re.I|re.X)
self.Value = re.compile("""
[(`\d*)+\'\w*\']*|\'.*\'|[\+-]*\d*\.?\d*
""", re.I|re.X)
self.Qualifier = re.compile("""
interface|implementation
""", re.I|re.X)
self.Object = re.compile("""
s
""", re.I|re.X)
def GetLastWord(self, Line, CaretPos):
"""
Get the last word from a line
"""
LastWord = re.search(
"""
\s*
(
".*"| # String data type
\w*| # Any letter/number
(\+|-|\*|/|%|\*\*|:|!|<|>)?=?| # Assignment, Comparison & Mathematical
(\{|\}|\(|\)|\[|\]) # Brackets
)
\s*\Z
""",
Line[:CaretPos], re.VERBOSE)
return LastWord
def StyleText(self, event):
"""Handle the EVT_STC_STYLENEEDED event"""
Obj = event.GetEventObject()
# Get Last Correctly Styled
LastStyledPos = Obj.GetEndStyled()
# Get Styling Range
Line = Obj.LineFromPosition(LastStyledPos)
StartPos = Obj.PositionFromLine(Line)
EndPos = event.GetPosition()
# Walk the Range and Style Them
while StartPos < EndPos:
Obj.StartStyling(StartPos, 0x1f)
LastWord = self.GetLastWord(Line, CaretPos)
if self.Comment.search(LastWord):
# Set Comment Keyword style
Style = self.STC_VOTONUSA_COMMENT
elif self.Type.search(LastWord):
# Set Type Keyword style
Style = self.STC_VOTONUSA_TYPE
elif self.Operation.search(LastWord):
# Set Operation Keyword style
Style = self.STC_VOTONUSA_OPERATION
elif self.Value.search(LastWord):
# Set Value Keyword style
Style = self.STC_VOTONUSA_VALUE
elif self.Qualifier.search(LastWord):
# Set Qualifier Keyqord style
Style = self.STC_VOTONUSA_QUALIFIER
elif self.Object.search(LastWord):
# Set Object Keyword style
Style = self.STC_VOTONUSA_OBJECT
# Set the styling byte information for length of LastWord from
# current styling position (StartPos) with the given style.
Obj.SetStyling(len(LastWord), Style)
StartPos += len(LastWord)
class CustomSTC(stc.StyledTextCtrl):
def __init__(self, parent):
super(CustomSTC, self).__init__(parent)
# Attributes
self.custlex = None
Font = wx.Font(12, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)
Face = Font.GetFaceName()
Size = Font.GetPointSize()
# Setup
kwlist = u" ".join(keyword.kwlist)
self.SetKeyWords(0, kwlist)
self.StyleClearAll()
self.SetLexer(wx.NewId(), STC_LEX_VOTONUSA)
self.EnableLineNumbers()
FontSet = "face:%s, size:%d" % (Face, Size)
self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, FontSet)
# Set Default to Black
self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "fore:#000000" + FontSet)
# Set Comment to Pink
self.StyleSetSpec(STC_LEX_VOTONUSA.STC_VOTONUSA_COMMENT, "fore:#ff007f" + FontSet)
# Set Value to Green
self.StyleSetSpec(STC_LEX_VOTONUSA.STC_VOTONUSA_VALUE, "fore:#00ff00" + FontSet)
# Set Object to Brown
self.StyleSetSpec(STC_LEX_VOTONUSA.STC_VOTONUSA_OBJECT, "fore:#a52a2a" + FontSet)
# Set Type to Red
self.StyleSetSpec(STC_LEX_VOTONUSA.STC_VOTONUSA_TYPE, "fore:#ff0000" + FontSet)
# Set Operation to Blue
self.StyleSetSpec(STC_LEX_VOTONUSA.STC_VOTONUSA_OPERATION, "fore:#0000ff" + FontSet)
# Set Qualifier to Orange
self.StyleSetSpec(STC_LEX_VOTONUSA.STC_VOTONUSA_QUALIFIER, "fore:#cc3232" + FontSet)
# Event Handlers
self.Bind(stc.EVT_STC_STYLENEEDED, self.OnStyle)
def EnableLineNumbers(self, enable=True):
"""Enable/Disable line number margin"""
if enable:
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
self.SetMarginMask(1, 0)
self.SetMarginWidth(1, 25)
else:
self.SetMarginWidth(1, 0)
def OnStyle(self, event):
# Delegate to custom lexer object if one exists
if self.custlex:
self.custlex.StyleText(event)
else:
event.Skip()
def SetLexer(self, lexerid, lexer=None):
"""
Overrides StyledTextCtrl.SetLexer
Adds optional param to pass in custom container
lexer object.
"""
self.custlex = lexer
super(CustomSTC, self).SetLexer(lexerid)
class NUSAIPT(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, None, wx.ID_ANY, 'VOTO NUSA IPT')
self.TextArea = CustomSTC(self)
self.Show()
app = wx.App()
frame = NUSAIPT()
app.MainLoop()
If I change
self.SetLexer(wx.NewId(), STC_LEX_VOTONUSA)
into
self.SetLexer(stc.STC_LEX_CPP)
and
self.StyleSetSpec(STC_LEX_VOTONUSA.STC_VOTONUSA_COMMENT, "fore:#ff007f" + FontSet)
into
self.StyleSetSpec(stc.STC_C_COMMENT, "fore:#ff007f" + FontSet)
the comment highlighting worked. so the mistake should be in self.SetLexer(wx.NewId(), STC_LEX_VOTONUSA) or STC_LEX_VOTONUSA.STC_VOTONUSA_COMMENT
Thanks in advance. Hope to see some answer soon.
Just stuck with same problem yesterday, here are my results. Hope it's not too late :)
First, i set lexer to this one, and internal lexer as you do:
self.SetLexer(stc.STC_LEX_CONTAINER)
self.custlex = SCT_LEX_ERLANG_IDNOISE(self)
Bind to event and OnStyle method are same.
And also i changed id of styles from wx.newId() to just numbers starting from 1.
Without it i didn't see any styling at all. Also stc.STC_STYLE_DEFAULT started to work too.
Full listing:
class SCT_LEX_ERLANG_IDNOISE(BaseLexer):
STC_ERLANG_IDNOISE_DEFAULT = 1
STC_ERLANG_IDNOISE_VARIABLE = 2
STC_ERLANG_IDNOISE_ATOM = 3
STC_ERLANG_IDNOISE_MODULE = 4
STC_ERLANG_IDNOISE_KEYWORD = 5
STC_ERLANG_IDNOISE_COMMENT = 6
STC_ERLANG_IDNOISE_MACROS = 7
STC_ERLANG_IDNOISE_NUMBER = 8
def __init__(self, control):
super(SCT_LEX_ERLANG_IDNOISE, self).__init__(control)
self.typeFormatDict = {}
self.typeFormatDict["other"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_DEFAULT
self.typeFormatDict["variable"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_VARIABLE
self.typeFormatDict["atom"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_ATOM
self.typeFormatDict["module"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_MODULE
self.typeFormatDict["keyword"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_KEYWORD
self.typeFormatDict["comment"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_COMMENT
self.typeFormatDict["macros"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_MACROS
self.typeFormatDict["number"] = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_NUMBER
def StyleText(self, event):
start = self.control.GetEndStyled()
end = event.GetPosition()
line = self.control.LineFromPosition(start)
start = self.control.PositionFromLine(line)
text = self.control.GetTextRange(start, end)
self.control.StartStyling(start, 0x1f)
lastEnd = 0
for type, start, end, value in getHighlightRules(text):
style = SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_DEFAULT
if start > lastEnd:
self.control.SetStyling(start - lastEnd, style)
if type in self.typeFormatDict:
style = self.typeFormatDict[type]
self.control.SetStyling(len(value), style)
lastEnd = end
class CustomSTC(stc.StyledTextCtrl):
def __init__(self, parent):
super(CustomSTC, self).__init__(parent)
self.custlex = SCT_LEX_ERLANG_IDNOISE(self)
#self.SetKeyWords(0, kwlist)
self.SetLexer(stc.STC_LEX_CONTAINER)
self.EnableLineNumbers()
self.StyleSetSpec(stc.STC_STYLE_DEFAULT, ColorSchema.formats["other"])
self.StyleClearAll()
self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, ColorSchema.lineFont)
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_DEFAULT, ColorSchema.formats["other"])
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_VARIABLE, ColorSchema.formats["variable"])
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_ATOM, ColorSchema.formats["atom"])
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_MODULE, ColorSchema.formats["module"])
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_KEYWORD, ColorSchema.formats["keyword"])
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_COMMENT, ColorSchema.formats["comment"])
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_MACROS, ColorSchema.formats["macros"])
self.StyleSetSpec(SCT_LEX_ERLANG_IDNOISE.STC_ERLANG_IDNOISE_NUMBER, ColorSchema.formats["number"])
# Event Handlers
self.Bind(stc.EVT_STC_STYLENEEDED, self.OnStyle)
def EnableLineNumbers(self, enable=True):
"""Enable/Disable line number margin"""
if enable:
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
self.SetMarginMask(1, 0)
self.SetMarginWidth(1, 35)
else:
self.SetMarginWidth(1, 0)
def OnStyle(self, event):
if self.custlex:
self.custlex.StyleText(event)
else:
event.Skip()