add 1 class to another class array - python

I have 2 classes:
1 which contains the data and another that contain an array
how can I create a function that add that class (like a list)
class Event(object):
def __init__(self):
self.msg_idx=0 ## the message from the panel
self.evt_id=0 ## the event id given by the server
self.Panel_Number=0 ## the panel number
self.line=""
def updateData(self,msg,event,panel,line):
self.msg_idx =msg
self.evt_id = event
self.Panel_Number = panel
self.line =line
class Events(object):
def __init__(self):
self.event =[]
def addEvent(self, Server_Event):
????????

Literally just append:
class Event(object):
def __init__(self):
self.msg_idx=0 ## the message from the panel
self.evt_id=0 ## the event id given by the server
self.Panel_Number=0 ## the panel number
self.line=""
def updateData(self,msg,event,panel,line):
self.msg_idx =msg
self.evt_id = event
self.Panel_Number = panel
self.line =line
class Events(object):
def __init__(self):
self.event =[]
def addEvent(self, Server_Event):
self.event.append(Server_Event)
something = Event()
somethings = Events()
somethings.addEvent(something)
I would question why you need such a class right now, when you could just use a list called events. But I have done something similar before and I know it makes it easier to add metadata on top.
However if you're just using it for the above without any extra analysis, it would be more efficient to just use a list.

Related

Elegant way in Python to map string content to method calls

Given this example code where we have a series of log processors, I can't help feeling there ought to be a more pythonic/efficient way of deciding which log processor to use to process some data:
class Component1ErrorLogProcessor:
def process(logToProcess):
# Do something with the logs
pass
class Component2ErrorLogProcessor:
def process(logToProcess):
# Do something with the logs
pass
class LogProcessor:
def __init__(self):
self.component1 = Component1ErrorLogProcessor()
self.component2 = Component2ErrorLogProcessor()
def process_line(self, line, component):
if component == "Component1Log-" or component == "[Component1]":
self.component1.process_errors(line)
elif component == "Component2Log-" or component == "[Component2]":
self.component2.process_errors(line)
I'd personally use the idea of registry, so you map each class to component names.
There are a bunch of different ways to go about this, here's a quick example by using a base class:
class ComponentLogProcessor(object):
_Mapping = {}
#classmethod
def register(cls, *component_names):
for name in component_names:
cls._Mapping[name] = cls
#classmethod
def cls_from_component(cls, component):
return cls._Mapping[component]
class Component1ErrorLogProcessor(ComponentLogProcessor):
def process(logToProcess):
# Do something with the logs
pass
Component1ErrorLogProcessor.register('Component1Log-', '[Component1]')
class Component2ErrorLogProcessor(ComponentLogProcessor):
def process(logToProcess):
# Do something with the logs
pass
Component2ErrorLogProcessor.register('Component2Log-', '[Component2]')
class LogProcessor:
def process_line(self, line, component):
ComponentLogProcessor.cls_from_component(component).process_errors(line)

How to register event handlers in the (reverse?) observer pattern?

I am trying to create a piece of user interface consisting of a grid of draggable pads that can be dropped on each other.
When a pad is dropped on another one, they should swap places.
I want objects of Pad and Pads classes to be oblivious of each other as much as possible so I thought of applying the observer pattern with those two classes, inheriting from the Observer and Observable class respectively.
I came up with this boilerplate code:
class Observable:
def __init__(self):
self.observers = []
def subscribe(self, observer):
self.observers.append(observer)
def unsubscribe(self, observer):
self.observers.remove(observer)
def notify(self, data):
for observer in self.observers:
observer.receive(data)
class Observer:
def receive(self, data):
print('{} received {}'.format(self.id, data))
class Pads(Observable):
def __init__(self, n_pads):
super().__init__()
self.pads = []
for i in range(1, n_pads + 1):
pad = Pad(i)
self.pads.append(pad)
self.subscribe(pad)
def swap(self, src_pad, target_pad):
a = self.pads.index(src_pad)
b = self.pads.index(target_pad)
self.pads[a], self.pads[b] = self.pads[b], self.pads[a]
print('Swapped pad {} with pad {}'.format(src_pad.id, target_pad.id))
class Pad(Observer):
def __init__(self, id):
self.id = id
def drop_on(self, target_pad):
print('Dropped pad {} on pad {}'.format(self.id, target_pad.id))
# how to call 'swap' of 'Pads'class automatically here?
pads = Pads(16)
some_pad = pads.pads[8]
another_pad = pads.pads[11]
some_pad.drop_on(another_pad)
# I do not want to call this manually. Instead, I want it to happen
# automatically after "some_pad.drop_on(another_pad)"
pads.swap(some_pad, another_pad)
however, I don't know how to move on from there.
I guess what I need to do is to implement the notify method of Observable class in such a way that the swap method of Pads class is automatically called whenever drop_on method of Pad is called.
Can someone guide me how to achieve this?

Set SingleSelection in QListView

I am writing an application in PySide2 and I have developed a class inheriting from Qdialog to display a list with checkboxes:
The code of the class:
class ListDialog(QDialog):
def __init__(self, items, all_checked = False, parent=None):
super(ListDialog, self).__init__(parent=parent)
self.setWindowTitle(title)
form = QFormLayout(self)
self.listView = QListView(self)
self.listView.setSelectionMode(QTableView.NoSelection)
form.addRow(self.listView)
self.model = QStandardItemModel(self.listView)
for item in items:
# create an item with a caption
standardItem = QStandardItem(item)
standardItem.setCheckable(True)
standardItem.setEditable(False)
if all_checked:
standardItem.setCheckState(Qt.Checked)
self.model.appendRow(standardItem)
self.listView.setModel(self.model)
The result (plus some extra code):
As it is, you can check multiple checkboxes, but I need to make it a single selection.
Note the line:
self.listView.setSelectionMode(QTableView.NoSelection)
At first, I thought setSelectionMode was responsible for this behaviour but this controls only the highlighting on the items of the list and not its checkboxes. Therefore I set it to NoSelection for not highlighting the text part, the checkboxes are working!
Is there an easy way to set the selection mode to single? Or should I overload the signal that controls the box checking to unselect all the boxes and then select the one I clicked?
An easy way to do that it to use a proxy model which will handle the single selection and the signal QStandardItemModel::itemChanged to know when user clicks on an item.
For example:
class SingleCheckProxyModel(QIdentityProxyModel):
def __init__(self, model, parent=None):
super().__init__(parent)
model.itemChanged.connect(self.checkSingleCheck)
self.setSourceModel(model)
self.currentItemChecked = None
def checkSingleCheck(self, item):
if self.currentItemChecked:
self.currentItemChecked.setCheckState(Qt.Unchecked)
if item.checkState(): # Allows the user to uncheck then check the same item
self.currentItemChecked = item
else:
self.currentItemChecked = None
class ListDialog(QDialog):
def __init__(self, items, all_checked = False, parent=None):
super(ListDialog, self).__init__(parent=parent)
self.setWindowTitle("kjnve")
form = QFormLayout(self)
self.listView = QListView(self)
self.listView.setSelectionMode(QTableView.NoSelection)
form.addRow(self.listView)
self.model = QStandardItemModel(self.listView)
for item in items:
# create an item with a caption
standardItem = QStandardItem(item)
standardItem.setCheckable(True)
standardItem.setEditable(False)
if all_checked:
standardItem.setCheckState(Qt.Checked)
self.model.appendRow(standardItem)
self.listView.setModel(SingleCheckProxyModel(self.model)) # Use proxy
The checkSingleCheck method will be called when the user clicks on an item. But, if you want to be able to edit the items, you have to adapt this function.

(PyQt) Uncheck pushbutton from outside button's class?

A QPushButton is set 'asCheckable'. Whence toggled, a class bool is changed.
This altered bool allows a method in a different class to proceed, and upon completion of this outside method I need to return the button to its initial state, 'setChecked(False)'.
While I am able to return the class housed bool to its default state at the end of this external method, I am unable to externally access a method which un-clicks the button.
I assume its due to the arguments in the classes init, but these are necessary - and I'm wondering if there is another means to achieve the described workflow.
Related code snips below:
(command in question is distinguished at bottom of 'Class 2')
Class 1:
class shapeCSVeditor(QtGui.QDialog, QtGui.QWidget):
valueShare = []
rowOverride = False# <<=== equivalent to 'override' in 'Class 2'
def __init__(self, iface, fileName, editorType, parent=None):
super(shapeCSVeditor, self).__init__(parent)
self.iface = iface
self.editorType = editorType
self.fileName = filename
self.pushButtonSetBase = QtGui.QPushButton(self)
self.pushButtonSetBase.setText("Set Base Shape")
self.pushButtonSetBase.setCheckable(True)
self.pushButtonSetBase.toggled.connect(self.on_pushButtonSetBase_toggled)
self.layoutHorizontal.addWidget(self.pushButtonSetBase)
#some other things here...
#QtCore.pyqtSlot()
def on_pushButtonSetBase_toggled(self):
shapeCSVeditor.rowOverride = True
pass
def on_BaseRow_Changed(self):
self.pushButtonSetBase.setChecked(False)
return
Class 2:
class CSVModel(QtCore.QAbstractTableModel):
# Establish inital settings and branch processes
def __init__(self, iface, fileName, editorType, parent=None):
super(CSVModel,self).__init__()
self.propertiesFile = r'some file'
self.areaStressFile = r'some other file'
self.iface = iface
self.rows = []
self.editorType = editorType
self.loadCSV()
self.iface.mapCanvas().selectionChanged.connect(self.addRow)
# add rows to the TableView based on object selection(s) in Qgis.mapCanvas
def addRow(self):
override = shapeCSVeditor.rowOverride
selectedFeatures = selectedLayer.selectedFeatures()
if override:
for feature in selectedFeatures:
self.rows.pop(0)
feat_Attributes = []
feat_Attributes.extend([self.iface.activeLayer().name()+'_'+str(feature.id())])
feat_Attributes.extend(['',]*(len(self.header)-1))
self.beginResetModel()
self.rows.insert(0,feat_Attributes)
shapeCSVeditor.rowOverride = False
self.endResetModel()
shapeCSVeditor.on_BaseRow_Changed# <<<=== wrong-diddily!
break
PS - if parentheticals are added to the 'shapeCSVeditor()' 3 arguments are requisite as referenced in the Button class, and if parentheticals are added to 'on_BaseRow_Changed', the return is;
TypeError: unbound method on_BaseRow_Changed() must be called with
shapeCSVeditor instance as first argument (got nothing instead)
What you are doing is strange.
In python, the first argument of a class method is always the object itself.
So, in your:
def on_BaseRow_Changed(self):
self.pushButtonSetBase.setChecked(False)
# return => This return is useless
if you don't provide an object then you can't access the pushbutton.
You didn't gave us all the code but I think you should provide your addRow with the shapeCSVeditor object that you want to update:
def addRow(self, shapeCSVObj):
override = shapeCSVObj.rowOverride
if override:
for feature in selectedFeatures:
self.rows.pop(0)
feat_Attributes = []
feat_Attributes.extend([self.iface.activeLayer().name()+'_'+str(feature.id())])
feat_Attributes.extend(['',]*(len(self.header)-1))
self.beginResetModel()
self.rows.insert(0,feat_Attributes)
shapeCSVObj.rowOverride = False
self.endResetModel()
shapeCSVObj.on_BaseRow_Changed()
break
Somewhere you must have a shapeCSVeditor that is created. You should provide it to you outside class.
Hope this helps.
class shapeCSVeditor(QtGui.QDialog, QtGui.QWidget):
valueShare = []
rowOverride = False
def __init__(self, iface, fileName, editorType, parent=None):
super(shapeCSVeditor, self).__init__(parent)
self.iface = iface
self.editorType = editorType
self.fileName = fileName
self.tableView = QtGui.QTableView(self)
self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
self.tableData = CSVModel(self,iface,fileName,editorType)
^^==not implementing 'self' (shapeCSVeditor object) was the problem!
self.tableView.setModel(self.tableData)
...
self.pushButtonSetBase = QtGui.QPushButton(self)
self.pushButtonSetBase.setText("Set Base Shape")
self.pushButtonSetBase.setCheckable(True)
self.pushButtonSetBase.clicked.connect(self.on_pushButtonSetBase_toggled)
...
#QtCore.pyqtSlot()
def on_pushButtonSetBase_toggled(self):
self.rowOverride = True
#QtCore.pyqtSlot()
def on_BaseRow_Changed(self):
self.rowOverride = False
self.pushButtonSetBase.setChecked(False)
///////////////////////////////////////////////////////////////////////////////////////
class CSVModel(QtCore.QAbstractTableModel):
def __init__(self, shapeCSVeditor, iface, fileName, editorType):
super(CSVModel,self).__init__()
self.propertiesFile = r'foo'
self.areaStressFile = r'bar'
self.tableView = shapeCSVeditor <<== proper passing of shapeCSVeditor object! (?)
self.iface = iface
self.rows = []
self.editorType = editorType
self.loadCSV()
self.iface.mapCanvas().selectionChanged.connect(self.addRow)
...
def addRow(self):
selectedFeatures = selectedLayer.selectedFeatures()
if self.tableView.rowOverride:
for feature in selectedFeatures:
self.rows.pop(0)
feat_Attributes = []
feat_Attributes.extend([self.iface.activeLayer().name()+'_'+str(feature.id())])
feat_Attributes.extend(['',]*(len(self.header)-1))
self.beginResetModel()
self.rows.insert(0,feat_Attributes)
self.endResetModel()
self.tableView.rowOverride = False
self.tableView.on_BaseRow_Changed()
Radical. Works for the current needs.
Now the question is if its proper to python 'standards'.
Quite new to writing, so its possible more needs fixed.
High thanks to Plouff for the clues.

libavg custom event handler

I'm trying to find a way to use libavg's event handlers from an embedded serial output. My understanding is that I need to create my own Publisher that I will call when I process serial commands. All I need is a way to create 10 different triggers given different serial inputs. An analogy of what I am trying to do would be to use libavg's keyboard handling to process different keyboard inputs.
I want the custom publisher to take the 10 serial outputs and pass a event.serialid parameter to various subscribers similarly to what event.keystring does.
Here is some nonfunctional code that I have that I think has the basics of what needs to be done.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from libavg import avg, statemachine, player
class Test():
PRESSED = avg.Publisher.genMessageID()
RELEASED = avg.Publisher.genMessageID()
def __init__(self, parent=None, **kwargs):
self.registerInstance(self, parent)
self.publish(self.PRESSED)
self.publish(self.RELEASED)
def isActive(self):
self.notifySubscribers(Test.PRESSED, [])
def isInactive(self):
self.notifySubscribers(Test.RELEASED, [])
def onKeyDown(event):
global node
if event.serialid == '1':
#serialid isn't implemented anywhere but this is what ideally I would like to have happen
node.color = "FF8000"
def onKeyUp(event):
global node
node.color = "FFFFFF"
player = avg.Player.get()
canvas = player.createMainCanvas(size=(640,480))
rootNode = player.getRootNode()
node = avg.WordsNode(pos=(10,10), font="arial", text="Hello World", parent=rootNode)
vbutton=Test()
node.subscribe(vbutton.PRESSED, onKeyDown)
node.subscribe(vbutton.RELEASED, onKeyUp)
player.play()
examples of custom publishers from here:
class _ButtonBase(avg.DivNode):
PRESSED = avg.Publisher.genMessageID()
RELEASED = avg.Publisher.genMessageID()
def __init__(self, parent=None, **kwargs):
super(_ButtonBase, self).__init__(**kwargs)
self.registerInstance(self, parent)
self.publish(self.PRESSED)
self.publish(self.RELEASED)
def _setActiveArea(self, upNode, activeAreaNode, fatFingerEnlarge):
self.__activeAreaNode = activeAreaNode
if fatFingerEnlarge:
if self.__activeAreaNode != None:
raise(RuntimeError(
"Button: Can't specify both fatFingerEnlarge and activeAreaNode"))
size = upNode.size
minSize = 20*player.getPixelsPerMM()
size = avg.Point2D(max(minSize, size.x), max(minSize, size.y))
self.__activeAreaNode = avg.RectNode(size=size, opacity=0, parent=self)
else:
if self.__activeAreaNode == None:
self.__activeAreaNode = self
else:
self.appendChild(self.__activeAreaNode)
self._tapRecognizer = gesture.TapRecognizer(self.__activeAreaNode,
possibleHandler=self._onDown,
detectedHandler=self._onTap,
failHandler=self._onTapFail)
You can pass arbitrary parameters through the publish-subscribe interface. The parameter(s) are passed as a list:
self.notifySubscribers(Test.PRESSED, [serialID])
And in the handler:
def onKeyDown(serialID):
global node
if serialid == '1':
node.color = "FF8000"

Categories