Jacob Davis schrieb: > I found SM2DGraphView, but I guess that I am too much of a newbie with > interface builder and pyobjc to figure out how to get SM2DGraphView to > work. Are there any good tutorials (or better yet, examples) of how to > get SM2DGraphView to work? > > I don't know pyobjc well at all.
There isn't much to it. Unfortunately, there aren't many good tutorials, but at least a few examples in the pyobjc repository. below is my code for implementing the SM2DGraphDataSource category. It is of course interspersed with my application-logic, but should give you a start. Additionally, you need to load the SM2DGraphView-framework. The code to do so is also below. Diez # # BCGraphViewController.py # BruceControl # # Created by Diez Roggisch on 22.02.08. # Copyright (c) 2008 __MyCompanyName__. All rights reserved. # from Foundation import * from AppKit import * import sys from PyObjCTools import NibClassBuilder import objc MODES = "displaySpeed", "displayPosition" kSM2DGraph_Axis_Y = 0 kSM2DGraph_Axis_X = 1 kSM2DGraph_Axis_Y_Right = 2 kSM2DGraph_Axis_Y_Left = kSM2DGraph_Axis_Y class BCGraphViewController(NibClassBuilder.AutoBaseClass): _displayPosition = False _displaySpeed = False def displayPosition(self): return self._displayPosition def setDisplayPosition_(self, v): self._displayPosition= v self.reloadData() def displaySpeed(self): return self._displaySpeed def setDisplaySpeed_(self, v): self._displaySpeed= v self.reloadData() def awakeFromNib(self): self._displayed_mis = [] self._ts_min = 0.0 self._ts_max = 0.0 self.graphView.setDataSource_(self) def setMotorInfos_(self, motor_infos): self._motor_infos = motor_infos # apparently, it's enough to just # subscribe once motor_infos[0].subscribeDisplayChanged(self) def setConnector_(self, connector): self._connector = connector connector.subscribeStateListener(self) def stateArrived_(self, n): state = n.object() ts = float(state.timestamp) / 1000000000.0 # nano to seconds if self._ts_min == 0: self._ts_min = ts self._ts_max = ts def reloadData(self): if self.numberOfLinesInTwoDGraphView_(None): self.graphView.reloadData() self.graphView.reloadAttributes() def displayChanged_(self, n): motor_info = n.object() motor_id = motor_info.motor_id if motor_info.display() and motor_info not in self._displayed_mis: self._displayed_mis.append(motor_info) else: try: self._displayed_mis.remove(motor_info) except ValueError: pass self.reloadData() @property def active_modes(self): return [mode for mode in MODES if getattr(self, mode)()] @property def activated_views(self): return len(self.active_modes) @objc.signature('I@:@') def numberOfLinesInTwoDGraphView_(self, view): res = len(self._displayed_mis) * self.activated_views return res @objc.signature('@@:@I') def twoDGraphView_dataForLineIndex_(self, view, lineIndex): av = self.activated_views # first, compute the mi to be used offset = lineIndex // av mi = self._motor_infos[offset] mode = self.active_modes[lineIndex % av] return mi[mode] @objc.signature('d@:@Ii') def twoDGraphView_maximumValueForLineIndex_forAxis_(self, view, lineIndex, axis): if not self.numberOfLinesInTwoDGraphView_(view): return .0 av = self.activated_views mode = self.active_modes[lineIndex % av] if axis == kSM2DGraph_Axis_Y: maxs = [mi.max[mode] for mi in self._displayed_mis] return max(maxs) elif axis == kSM2DGraph_Axis_X: return float(self._ts_max) return .0 @objc.signature('d@:@Ii') def twoDGraphView_minimumValueForLineIndex_forAxis_(self, view, lineIndex, axis): if not self.numberOfLinesInTwoDGraphView_(view): return .0 av = self.activated_views mode = self.active_modes[lineIndex % av] if axis == kSM2DGraph_Axis_Y: mins = [mi.min[mode] for mi in self._displayed_mis] return min(mins) elif axis == kSM2DGraph_Axis_X: return float(self._ts_min) return .0 @objc.signature('@@:@I') def twoDGraphView_attributesForLineIndex_(self, view, lineIndex): try: if not self.numberOfLinesInTwoDGraphView_(None): return None av = self.activated_views # first, compute the mi to be used offset = lineIndex // av mi = self._motor_infos[offset] res = {NSForegroundColorAttributeName : mi.color} except: print sys.exc_info()[1] return None return res def crop_(self, sender): self._ts_min = self._ts_max for mi in self._motor_infos: mi._set_min_max_defaults() import objc, AppKit, Foundation, os import logging, sys from ctypes.util import find_library logger = logging.getLogger('bundles') frameworks = set(("SM2DGraphView",)) loaded = set() loading_exceptions = [] for framework in frameworks: logger.debug('Trying to load framework <%s>', framework) bundle_path = find_library(framework) bundle_path = bundle_path[:bundle_path.index('framework')] + "framework" logger.debug('from path <%s>', bundle_path) try: objc.loadBundle(framework, globals(), bundle_path=bundle_path) loaded.add(framework) continue except: loading_exceptions.append(sys.exc_info()[1]) pass if loaded != frameworks and loading_exceptions: logger.error("Got exceptions loading frameworks") for e in loading_exceptions: logger.error(e) raise loading_exceptions[0] del objc, AppKit, Foundation, os, bundle_path -- http://mail.python.org/mailman/listinfo/python-list