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

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.

Related

Concatenate Two QFileSystemModels

In this post, my goal is to concatenate two QFileSystemModels to one and display them together. (Lots of updates has been made)
Context :
In my C drive , I created the folder MyFolder (https://drive.google.com/drive/folders/1M-b2o9CiohXOgvjoZrAnl0iRVQBD1sXY?usp=sharing) , in which there are some folders and some files, for the sake of producing the minimal reproducible example . Their structure is :
The following Python code using PyQt5 library (modified from How to display parent directory in tree view?) runs after importing necessary libraries:
#The purpose of the proxy model is to display the directory.
#This proxy model is copied here from the reference without modification.
class ProxyModel(QSortFilterProxyModel):
def __init__(self, parent=None):
super().__init__(parent)
self._root_path = ""
def filterAcceptsRow(self, source_row, source_parent):
source_model = self.sourceModel()
if self._root_path and isinstance(source_model, QFileSystemModel):
root_index = source_model.index(self._root_path).parent()
if root_index == source_parent:
index = source_model.index(source_row, 0, source_parent)
return index.data(QFileSystemModel.FilePathRole) == self._root_path
return True
#property
def root_path(self):
return self._root_path
#root_path.setter
def root_path(self, p):
self._root_path = p
self.invalidateFilter()
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.create_treeview()
self.setCentralWidget(self.treeView_1) #The line I will be talking about.
def create_treeview(self):
self.treeView_1 = QTreeView()
self.dirModel_1 = QFileSystemModel()
self.dirModel_1.setRootPath(QDir.rootPath())
path_1 = 'C:/MyFolder/SubFolder1' # Changing the path is sufficient to change the displayed directory
root_index_1 = self.dirModel_1.index(path_1).parent()
self.proxy_1 = ProxyModel(self.dirModel_1)
self.proxy_1.setSourceModel(self.dirModel_1)
self.proxy_1.root_path = path_1
self.treeView_1.setModel(self.proxy_1)
proxy_root_index_1 = self.proxy_1.mapFromSource(root_index_1)
self.treeView_1.setRootIndex(proxy_root_index_1)
self.treeView_2 = QTreeView()
self.dirModel_2 = QFileSystemModel()
self.dirModel_2.setRootPath(QDir.rootPath())
path_2 = 'C:/MyFolder'
root_index_2 = self.dirModel_2.index(path_2).parent()
self.proxy_2 = ProxyModel(self.dirModel_2)
self.proxy_2.setSourceModel(self.dirModel_2)
self.proxy_2.root_path = path_2
self.treeView_2.setModel(self.proxy_2)
proxy_root_index_2 = self.proxy_2.mapFromSource(root_index_2)
self.treeView_2.setRootIndex(proxy_root_index_2)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The line self.setCentralWidget(self.treeView_1) gives:
Changing self.setCentralWidget(self.treeView_1) to self.setCentralWidget(self.treeView_2) gives:
Objective:
My goal is to concatenate the two trees together. That is, when click run, the user should be able to see:
The order which they show up does not matter. All I care is that MyFolder and SubFolder1 show up as if they are completely independent items (even though in reality one is a subfolder of the other). I should remark that everything is static. That is, we are not trying to detect any changes on folders or files. The only time we ever need to peak at the existing folders and files will be when we click on run.
Update:
After several days of studying and trying, a major progress has been made. I thank musicamante for the hint of using QTreeWidget. The idea is, as said in comments, traverse through models and gradually move everything into one new QTreeWidget. To avoid freeze, my solution is to ask the QFileSystemModel to fetchMore whenever the user wants to see more (i.e. when the user wants to extend QTreeWidget).
The following code runs and almost solves my problem:
import os
from PyQt5.QtCore import*
from PyQt5.QtWidgets import*
from PyQt5 import QtTest
class To_Display_Folder(QSortFilterProxyModel):
def __init__(self, disables=False, parent=None):
super().__init__(parent)
#self.setFilterRegularExpression(r'^(.*\.dcm|[^.]+)$')
self._disables = bool(disables)
self._root_path = ""
def filterAcceptsRow(self, source_row, source_parent):
source_model = self.sourceModel()
#case 1 folder
if self._root_path and isinstance(source_model, QFileSystemModel):
root_index = source_model.index(self._root_path).parent()
if root_index == source_parent:
index = source_model.index(source_row, 0, source_parent)
return index.data(QFileSystemModel.FilePathRole) == self._root_path
return True
'''
#case 2 file
file_index = self.sourceModel().index(source_row, 0, source_parent)
if not self._disables:
return self.matchIndex(file_index)
return file_index.isValid()
'''
#property
def root_path(self):
return self._root_path
#root_path.setter
def root_path(self, p):
self._root_path = p
self.invalidateFilter()
def matchIndex(self, index):
return (self.sourceModel().isDir(index) or
super().filterAcceptsRow(index.row(), index.parent()))
def flags(self, index):
flags = super().flags(index)
if (self._disables and
not self.matchIndex(self.mapToSource(index))):
flags &= ~Qt.ItemIsEnabled
return flags
class Widget_Item_from_Proxy(QTreeWidgetItem):
def __init__(self, index_in_dirModel, parent = None):
super().__init__(parent)
self.setText(0, index_in_dirModel.data(QFileSystemModel.FileNameRole))
self.setText(1, index_in_dirModel.data(QFileSystemModel.FilePathRole))
if os.path.isfile(index_in_dirModel.data(QFileSystemModel.FilePathRole)):
self.setIcon(0,QApplication.style().standardIcon(QStyle.SP_FileIcon))
else:
self.setIcon(0,QApplication.style().standardIcon(QStyle.SP_DirIcon))
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
global treeWidget
treeWidget = QTreeWidget()
self.treeWidget = treeWidget
self.treeWidget.itemExpanded.connect(self.upon_expansion)
self.treeWidget.itemClicked.connect(self.tree_click)
#The following directories will be displayed on the tree.
self.add_path_to_tree_widget('C:/MyFolder')
self.add_path_to_tree_widget('C:/Users/r2d2w/OneDrive/Desktop')
self.add_path_to_tree_widget('C:/')
self.setCentralWidget(self.treeWidget)
def add_path_to_tree_widget(self,path):
dirModel = QFileSystemModel()
dirModel.setRootPath(QDir.rootPath())
dirModel.directoryLoaded.connect(lambda: self.once_loaded(path, dirModel))
def once_loaded(self, path, dirModel):
if dirModel.canFetchMore(dirModel.index(path)):
dirModel.fetchMore(dirModel.index(path))
return
root_index = dirModel.index(path).parent()
proxy = To_Display_Folder(disables = False, parent = dirModel)
proxy.setSourceModel(dirModel)
proxy.root_path = path
proxy_root_index = proxy.mapFromSource(root_index)
origin_in_proxy = proxy.index(0,0,parent = proxy_root_index)
root_item = Widget_Item_from_Proxy(
proxy.mapToSource(origin_in_proxy))
self.treeWidget.addTopLevelItem(root_item)
for row in range(0, proxy.rowCount(origin_in_proxy)):
proxy_index = proxy.index(row,0,parent = origin_in_proxy)
child = Widget_Item_from_Proxy(
proxy.mapToSource(proxy_index),
parent = self.treeWidget.topLevelItem(self.treeWidget.topLevelItemCount()-1))
dirModel.directoryLoaded.disconnect()
#pyqtSlot(QTreeWidgetItem)
def upon_expansion(self, treeitem):
for i in range(0, treeitem.childCount()):
if os.path.isdir(treeitem.child(i).text(1)):
self.add_child_path_to_tree_widget(treeitem.child(i))
def add_child_path_to_tree_widget(self,subfolder_item):
subfolder_path = subfolder_item.text(1)
dirModel = QFileSystemModel()
dirModel.setRootPath(QDir.rootPath())
dirModel.directoryLoaded.connect(lambda: self.child_once_loaded(subfolder_item, subfolder_path,dirModel))
def child_once_loaded(self, subfolder_item, subfolder_path, dirModel):
if dirModel.canFetchMore(dirModel.index(subfolder_path)):
dirModel.fetchMore(dirModel.index(subfolder_path))
return
root_index = dirModel.index(subfolder_path).parent()
proxy = To_Display_Folder(disables = False, parent = dirModel)
proxy.setSourceModel(dirModel)
proxy.root_path = subfolder_path
proxy_root_index = proxy.mapFromSource(root_index)
origin_in_proxy = proxy.index(0,0,parent = proxy_root_index)
root_item = Widget_Item_from_Proxy(
proxy.mapToSource(origin_in_proxy))
folder_item = subfolder_item.parent()
itemIndex = folder_item.indexOfChild(subfolder_item)
folder_item.removeChild(subfolder_item)
folder_item.insertChild(itemIndex, root_item)
for row in range(0, proxy.rowCount(origin_in_proxy)):
proxy_index = proxy.index(row,0,parent = origin_in_proxy)
child = Widget_Item_from_Proxy(
proxy.mapToSource(proxy_index),
parent = root_item)
dirModel.directoryLoaded.disconnect()
#pyqtSlot(QTreeWidgetItem)
def tree_click(self, item):
print(item.text(0))
print(item.text(1))
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Since the bounty period is still not over, I will use the time to post two new questions:
Sometimes, especially when the line self.add_path_to_tree_widget('C:/') is present, the code does not give all directories when we click run. This problem is easily fixed by closing the window and clicking on run again. This problem occurs because the QFileSystemModel does not yet have enough time to traverse through the designated folder. If it has just a little bit more time, it will be able to. I wonder if there is a way to fix this programatically.
The function add_path_to_tree_widget is similar to add_child_path_to_tree_widget. The function once_loaded is similar to child_once_loaded. I wonder if there is a way to write these functions more succinctly.
While not impossible, it's quite difficult to create a unique and dynamic model that is able to access different QFileSystemModel structures.
An easier and simpler implementation, which would be more practical for static purposes, is to use a QTreeWidget and create items recursively.
class MultiBrowser(QTreeWidget):
def __init__(self, *pathList):
super().__init__()
self.iconProvider = QFileIconProvider()
self.setHeaderLabels(['Name'])
for path in pathList:
item = self.createFSItem(QFileInfo(path), self.invisibleRootItem())
self.expand(self.indexFromItem(item))
def createFSItem(self, info, parent):
item = QTreeWidgetItem(parent, [info.fileName()])
item.setIcon(0, self.iconProvider.icon(info))
if info.isDir():
infoList = QDir(info.absoluteFilePath()).entryInfoList(
filters=QDir.AllEntries | QDir.NoDotAndDotDot,
sort=QDir.DirsFirst
)
for childInfo in infoList:
self.createFSItem(childInfo, item)
return item
# ...
multiBrowser = MultiBrowser('path1', 'path2')
For obvious reasons, the depth of each path and their contents will freeze the UI from interaction until the whole structure has been crawled.
If you need a more dynamic approach, consider using the QFileSystemModel as a source for path crawling, along with its directoryLoaded signal, which will obviously require a more complex implementation.

Subclass not initialising parent class in Python 2.x

I'm having some problems initialising the parent class inside one subclass in Python 2. What I'm trying to do is override parent class attributes with properties in the child class.
Somehow, when I don't use the method _update_rect(self) in the child class setters (e.g. _set_grab(self, ps_value) and _set_grab(self, ps_value)), everything works as expected. But as soon as I use it the initialization of the parent class fails (the print '+++ END GfxObject initialisation' is not reached) and I get AttributeError: 'GfxRect' object has no attribute '_s_grab'.
As I said at the beginning, the code looks correct to me and the problematic method _update_rect only uses real attributes of itself so I have no idea where the error comes. I could avoid using inheritance in the child class as a workaround but I really want to understand what the problem is.
Regards and thanks in advance.
# Extra code to simplify test code
#=================================
class pygame:
class Rect:
def __init__(self, x, y, w, h):
self.x = x
self.y = y
self.w = w
self.h = h
# Classes
#========
class GfxObject(object):
"""
Generic Graphical Object which is the parent class of all the sub-classes below.
"""
def __init__(self):
self.i_x = 0
self.i_y = 0
self.s_grab = 'nw'
class GfxRect(GfxObject):
"""
Class to draw a rectangle.
"""
def __init__(self):
print '--- START GfxObject initialisation'
super(GfxRect, self).__init__()
print '+++ END GfxObject initialisation'
self._i_x = 0
self._s_grab = 'nw'
self._o_rect = None
print self
self._update_rect()
def __str__(self):
return unicode(self).encode('utf8')
def __unicode__(self):
u_out = u'<GfxRect>\n'
u_out += u' .i_x: %s\n' % self.i_x
u_out += u' ._i_x: %s\n' % self._i_x
u_out += u' .s_grab: %s\n' % self.s_grab
u_out += u' ._s_grab: %s\n' % self._s_grab
return u_out
def _get_grab(self):
return self._s_grab
def _get_x(self):
return self._i_x
def _set_grab(self, ps_value):
self._s_grab = ps_value
#self._update_rect()
self._b_redraw = True
def _set_x(self, i_value):
self._i_x = i_value
self._update_rect()
self._b_redraw = True
def _update_rect(self):
"""
Method to update the pygame rectangle object.
:return:
"""
# [1/?] Calculating the deltas for (x,y) based on the grab position
#------------------------------------------------------------------
if self._s_grab == 'nw':
i_dx = 0
elif self._s_grab == 'n':
i_dx = -800 / 2
else:
raise ValueError('Invalid grab value "%s"' % self._s_grab)
# [2/?] Applying the deltas
#--------------------------
i_x = self._i_x + i_dx
self._o_rect = pygame.Rect(i_x, 0, 800, 600)
i_x = property(fget=_get_x, fset=_set_x)
s_grab = property(fget=_get_grab, fset=_set_grab)
# Main code
#==========
if __name__ == '__main__':
o_progbar = GfxRect()
UPDATE: Moving the initialisation of the parent class in the child class after the internal properties seems to fix the problem which it's even more weird for me.
Before (doesn't work)
def __init__(self):
print '--- START GfxObject initialisation'
super(GfxRect, self).__init__()
print '+++ END GfxObject initialisation'
self._i_x = 0
self._s_grab = 'nw'
self._o_rect = None
self._update_rect()
After (works)
def __init__(self):
self._i_x = 0
self._s_grab = 'nw'
self._o_rect = None
print '--- START GfxObject initialisation'
super(GfxRect, self).__init__()
print '+++ END GfxObject initialisation'
self._update_rect()
...but something wrong seems to be happening under the hood. If I add print 'child class "_update_rect" called' to the _update_rect method, I get this output when running the script:
--- START GfxObject initialisation
child class "_update_rect" called <-- ERROR!?
child class "_update_rect" called <-- ERROR!?
+++ END GfxObject initialisation
child class "_update_rect" called <-- this is correct
...
Which means the parent class is calling the child methods when being initialised!?
UPDATE 2: It seems this is the workflow when initialising the child class.
[1] Child.__init__()
[2] Parent.__init__()
[3] self.i_x = 0
[4] Child._set_x(0)
[5] Child._update_rect()
[6] Child._s_grab = 'foo'
The problem appears in step [6] because ._s_grab attribute hasn't been created yet since the initialisation of the Child class is still initialising the Parent class. To me, it's counter-intuitive (and I would say that it's even a bug) the step [3]-[4] when setting the attribute .i_x of the Parent class triggers the property of the Child class.
By moving the initialisation of the parent class at the end of the child class or adding the missing attribute as a Parent class global (not to the instances), the problem disappear.
Your issue is that you're trying to initialise non-existing class properties/variables (you're calling self.i_x, but you've initialised self._i_x, for example) with a method call.
Changing GfxObject to:
class GfxObject(object):
"""
Generic Graphical Object which is the parent class of all the sub-classes below.
"""
def __init__(self):
self._i_x = 0
self._i_y = 0
self._s_grab = 'nw'
Executed script on my machine. Result output:
$ python2 issue.py
--- START GfxObject initialisation
+++ END GfxObject initialisation
<GfxRect>
.i_x: 0
._i_x: 0
.s_grab: nw
._s_grab: nw
EDIT
Funny thing, once I moved i_x and s_grab from GfxObject()'s init, your code worked as a charm. Basically I only changed that class to this:
class GfxObject(object):
"""
Generic Graphical Object which is the parent class of all the sub-classes below.
"""
i_x = None
s_grab = None
def __init__(self):
# self.i_x = None
# self.s_grab = None
#self.s_grab = 'nw'
pass
So, it seems that you're expperiencing same issue I had with Python3 and #property decorator - if I didn't set an object to None or some other value before defining it as a property, it threw no attribute/not defined errors first time I'd try to use that getter/setter.

In transitions,how to define a callback function by function reference instead of function name string

In transitions, callbacks are defined like this:
State(name='solid', on_exit=['say_goodbye'])
machine.add_transition('melt', 'solid', 'liquid', before='set_environment')
I want to use a callback function defined in another class
class MyClass(object):
def func(self):
print('nothing')
class NarcolepticSuperhero(object):
# Define some states. Most of the time, narcoleptic superheroes are just like
# everyone else. Except for...
states = [State('asleep'), 'hanging out', 'hungry', 'sweaty', 'saving the world']
def __init__(self, name):
# No anonymous superheroes on my watch! Every narcoleptic superhero gets
# a name. Any name at all. SleepyMan. SlumberGirl. You get the idea.
self.name = name
self.mc = MyClass()
# Initialize the state machine
self.machine = Machine(model=self, states=NarcolepticSuperhero.states, initial='asleep')
self.machine.add_transition(trigger='wake_up', source='asleep', dest='hanging out', prepare=self.mc.func)
m = NarcolepticSuperhero('Superman')
m.wake_up()
and got a TypeError: getattr(): attribute name must be string
My full code is something like this. I have several Mission and each mission have different method to do. You know one hero can not use the same action to beat different monsters.
And a hero can not always beat monsters. So based on prepare we will choose retreat or beat_the_next.
class Mission(object):
def __init__(self, name):
super().__init__()
self.result = 0
self._state = State(name=name, on_exit=self.on_exit, on_enter=self.on_enter)
self.state = name
def fire(self):
print('checking state {}'.format(self.name))
self.result = random.random()
def on_enter(self):
print('enter state {}'.format(self.name))
def on_exit(self):
print('checking state {}'.format(self.name))
def condition1(self):
return self.result > 0.6
def condition2(self):
return self.result > 0.3
def condition3(self):
return self.result > 0.1
class Robot(object):
def __init__(self):
super().__init__()
self.a = Mission('a')
self.b = Mission('b')
self.c = Mission('c')
self.states = [i._state for i in [self.a, self.b, self.c]]
self.machine = Machine(model=self, states=self.states, initial=self.a.state, auto_transitions=False)
self.machine.add_transition( trigger='go_out', source=self.a.state, dest=self.b.state , prepare = self.a.fire, conditions = [self.a.condition2], after = 'beat_next')
self.machine.add_transition( trigger='go_back', source=self.a.state, dest=self.c.state , after = 'sleep')
self.machine.add_transition( trigger='beat_next', source=self.b.state, dest=self.c.state , after = 'sleep')
self.machine.add_transition( trigger='sleep', source=self.c.state, dest=self.a.state )
def show_graph(self):
self.graph.draw('state.png', prog='dot')
display(Image('state.png'))
The machine model is self so I can not change it to mc.
One possible way is to bind your machine not to a NarcolepticSuperhero instance, but to an interface.
class StateMachineInterface(object):
superhero = None
def __init__(self, superhero):
self.superhero = superhero
def start(self):
"""Initiate State Machine with all states and transitions"""
machine = Machine(
self,
states=STATES,
initial=INITIAL_STATE,
)
machine.add_transition(trigger='wake_up', source='asleep', dest='hanging out', prepare='wakeup_prepare_callback')
return machine
def wakeup_prepare_callback(self):
return self.superhero.func()
# Usage:
m = NarcolepticSuperhero('Superman')
machine = StateMachineInterface(m)
machine.start()
machine.wake_up()
This principle is suggested in documentation

PyQt - Set model of a proxymodel in QThread

In my project i noticed that the main dialog freezes when it is setting the model of some ProxyModel, so i decided to create a new thread for this task to provide the responsiveness of the window, but right now it keeps popping an error that say:
TypeError: QTableView.setModel(QAbstractItemModel): argument 1 has unexpected type 'tuple'
and i don't know why...
Here's my code:
This is the QThread for updating the proxyModel with the arguments i provide
class ThreadedProxyModel(QThread):
def __init__(self, contacts, contactsProxyModel, groups, groupsProxyModel,
chatSession, chatSessionProxyModel, msgs, msgsProxyModel):
QThread.__init__(self)
self.contacts = contacts
self.contactsProxyModel = contactsProxyModel
self.groups = groups
self.groupsProxyModel = groupsProxyModel
self.chatSession = chatSession
self.chatSessionProxyModel = chatSessionProxyModel
self.msgs = msgs
self.msgsProxyModel = msgsProxyModel
def run(self):
self.contactsProxyModel.setSourceModel(recordsTableModel(self.contacts))
self.contactsProxyModel.setFilterKeyColumn(-1)
self.contactsProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.groupsProxyModel.setSourceModel(recordsTableModel(self.groups))
self.groupsProxyModel.setFilterKeyColumn(-1)
self.groupsProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.chatSessionProxyModel.setSourceModel(recordsTableModel(self.chatSession))
self.chatSessionProxyModel.setFilterKeyColumn(-1)
self.chatSessionProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.msgsProxyModel.setSourceModel(recordsTableModel(self.msgs))
self.msgsProxyModel.setFilterKeyColumn(-1)
self.msgsProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
def getContactsProxyModel(self):
return self.contactsProxyModel,
def getGroupsProxyModel(self):
return self.groupsProxyModel
def getChatSessionProxyModel(self):
return self.chatSessionProxyModel
def getMsgsProxyModel(self):
return self.msgsProxyModel
And this is the method calling the setProxyModel thread in the dialog class. Notice that all the data (contacts, groups, chatsession...) is fine:
def setProxyModel(self):
progress = QProgressDialog("Initializing UI ...", "Abort", 0, 0, self)
progress.setWindowTitle("WhatsApp Browser ...")
progress.setWindowModality(Qt.WindowModal)
progress.setMinimumDuration(0)
progress.setCancelButton(None)
progress.show()
queryTh = ThreadedProxyModel(self.contacts, self.contactsProxyModel, self.groups, self.groupsProxyModel,
self.chatSession, self.chatSessionProxyModel, self.msgs, self.msgsProxyModel,)
queryTh.start()
while queryTh.isRunning():
QApplication.processEvents()
self.contactsProxyModel = queryTh.getContactsProxyModel()
self.groupsProxyModel = queryTh.getGroupsProxyModel()
self.chatSessionProxyModel = queryTh.getChatSessionProxyModel()
self.msgsProxyModel = queryTh.getMsgsProxyModel()
progress.close()
And this is in the init method in my dialog, i create the proxymodels and call the method for updating them in the Thread and then i set them up in various QTableView:
self.contactsProxyModel = QSortFilterProxyModel(self)
self.groupsProxyModel = QSortFilterProxyModel(self)
self.groupMembersProxyModel = QSortFilterProxyModel(self)
self.chatSessionProxyModel = QSortFilterProxyModel(self)
self.chatMsgsProxyModel = QSortFilterProxyModel(self)
self.msgsProxyModel = QSortFilterProxyModel(self)
self.setProxyModel()
self.contactsTableView.setModel(self.contactsProxyModel)
self.contactsTableView.resizeColumnsToContents()
self.groupsTableView.setModel(self.groupsProxyModel)
self.groupsTableView.resizeColumnsToContents()
self.chatSessionTableView.setModel(self.chatSessionProxyModel)
self.chatSessionTableView.resizeColumnsToContents()
self.chatSessionTableView.clicked.connect(self.setChatMsgsProxyModel)
self.chatMsgsTableView.resizeColumnsToContents()
self.groupsTableView.clicked.connect(self.setGroupMembersProxyModel)
self.groupMembersTableView.resizeColumnsToContents()
self.msgsTableView.setModel(self.msgsProxyModel)
self.msgsTableView.resizeColumnsToContents()
Thank you for any advice, i'm pretty stuck...
Not sure, but it seems that
def getContactsProxyModel(self):
return self.contactsProxyModel,
return a tuple, try to delete the comma

Python class wont add to objectStore

for some reason when I try to add an object to a dictionary in a class, where the dictionary belongs to another class and objects are added/removed by class functions it always seems to fail adding.
Heres the datahandler :
class datastore():
def __init__(self, dict=None):
self.objectStore = {}
self.stringStore = {}
if dict is not None:
self.objectStore = dict
def __addobj__(self,obj,name):
print("adddedval")
self.objectStore[name] = obj
def __getobject__(self,name):
_data = self.objectStore.get(name)
return _data
def __ripobj__(self,name,append):
if isinstance(append, object):
self.objectStore[name] = append
def __returnstore__(self):
return self.objectStore
def __lst__(self):
return self.objectStore.items()
and heres the trigger code to try to add the item :
if self.cmd=="addtkinstance-dev":
print("Adding a tk.Tk() instance to dataStore")
#$$ below broken $$#
_get = datastore.__dict__["__returnstore__"](self.dat)
_get["test-obj"] = tk.Tk()
datastore.__init__(self.dat, dict=_get)
#--------------------------------------------#
tool(tk.Tk(), "test-obj", datastore())
and also heres the init for the class that trys to add the object
class cmdproc(tk.Tk, datastore):
def __init__(self,lst,variable_mem,restable):
self.pinst = stutils(lst,restable,variable_mem)
self.vinst = varutils(variable_mem,lst,restable)
self.tki = tkhandler()
self.dat = datastore(dict=None)
datastore.__init__(self, dict=datastore.__returnstore__(self.dat))
tk.Tk.__init__(self)
self.lst = lst
self.vdat = variable_mem
self.restable = restable
please help this is seriously baffling me
(note that tkhandler dosn't have to do with anything)

Categories