Set data om multiple selected items in TableView

93 views
Skip to first unread message

johan Borgström

unread,
Jan 8, 2015, 9:17:05 AM1/8/15
to python_in...@googlegroups.com
Hi all!

(PySide QTableView / QStandardItemModel question)

The behaviour that I want is that the data set on the last selected item in the table view will also be set on the previous selected items.
So my idea is to listen for the dataChanged signal and loop through the selected rows and set the data.

I realise that this will cause a loop, since I will trigger the dataChanged signal. What is the best way to approach this?
Subclass the QStandardItemModel and and implement the setData method to only emit the dataChanged when the user interacts with the item directly?

Thankful for any suggestions and tips!




Justin Israel

unread,
Jan 8, 2015, 8:51:15 PM1/8/15
to python_in...@googlegroups.com
Hi,

Depending on how you are using the view and expecting it to function, the view usually needs to see the dataChanged signal to know that it should refresh the display of items. You could however use the blockSignals(True) method on your model, then perform the data updates, and then call blockSignals(False). After this, you would probably have to refresh the view to ensure it is displaying correctly. 

 Justin


--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/f7c91608-f455-46eb-9240-ea90c0eb76ae%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

johan Borgström

unread,
Jan 9, 2015, 2:49:32 AM1/9/15
to python_in...@googlegroups.com
Thanks Justin!

This is what I did
  • Get the data from the QModelIndex that was edited
  • Block signals on the model
  • Loop through and set the data on the selected rows
  • "Unblock" signals
  • It seems like the tableview updates fine, but if I want to force an update do I call reset() on the model to do so?
I want the Tableview to only accept floats. I guess one way to get this behaviour is to use a float when I set the data of the QStandardItem?
By default I get two decimals on the tableview spinbox editor. How can I access and set the min, max etc of the spinbox? My initial idea was to use  self.tableview.itemDelegate() to get a reference to the spinbox, but I am quite new to this, what is the best way to go?

Best Regards,
Johan


from PySide import QtCore, QtGui
from shiboken import wrapInstance
import maya.OpenMayaUI as omui


def maya_main_window():
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(long(main_window_ptr), QtGui.QWidget)
    
    
# the main ui class  
class TableviewTest(QtGui.QWidget):
 
    def __init__(self, parent=None):
 
        super(TableviewTest, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Tool)
        
        self.resize(300, 350)
        self.setWindowTitle("Tableview")
                
        self.vertical_layout = QtGui.QVBoxLayout()
        self.setLayout(self.vertical_layout)
        
        # tableview  
        self.tableview = QtGui.QTableView()
        self.tableview.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
        self.vertical_layout.addWidget(self.tableview)
        
        # model      
        self.model = QtGui.QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Corner radius'])
        self.tableview.setModel(self.model)
        self.model.dataChanged.connect(self.model_changed)
        
        for row in range(5):
            
            item = QtGui.QStandardItem()
            item.setData(1.0, QtCore.Qt.EditRole)
            self.model.setItem(row, 0, item);
            
            # access the spinbox to set min, max ?
            #delegate = self.tableview.itemDelegate()
            
    
    def model_changed(self, top_left, bottom_right):
        
        print('model changed')
        
        val = self.model.data(top_left)
        selection_model = self.tableview.selectionModel()
        
        # returns QModelIndex
        selected_rows = selection_model.selectedRows()
        
        self.model.blockSignals(True)
        
        for row in selected_rows:
            self.model.setData(row, val)

        self.model.blockSignals(False)
        
        #self.model.reset()  


try:
    win.close()
    
except NameError as e:
    print(e)
    
win = TableviewTest(parent=maya_main_window())
win.move(100, 210)
win.show()




On Friday, January 9, 2015 at 2:51:15 AM UTC+1, Justin Israel wrote:
Hi,

Depending on how you are using the view and expecting it to function, the view usually needs to see the dataChanged signal to know that it should refresh the display of items. You could however use the blockSignals(True) method on your model, then perform the data updates, and then call blockSignals(False). After this, you would probably have to refresh the view to ensure it is displaying correctly. 

 Justin


On Fri Jan 09 2015 at 03:17:06 johan Borgström <jo...@petfactory.se> wrote:
Hi all!

(PySide QTableView / QStandardItemModel question)

The behaviour that I want is that the data set on the last selected item in the table view will also be set on the previous selected items.
So my idea is to listen for the dataChanged signal and loop through the selected rows and set the data.

I realise that this will cause a loop, since I will trigger the dataChanged signal. What is the best way to approach this?
Subclass the QStandardItemModel and and implement the setData method to only emit the dataChanged when the user interacts with the item directly?

Thankful for any suggestions and tips!




--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

damon shelton

unread,
Jan 9, 2015, 2:55:33 AM1/9/15
to python_in...@googlegroups.com

I believe self.tableView.viewport().update()
Will do the trick if you need to force to view to refresh

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/a7c8666b-de52-400c-bbd7-9edc34490b19%40googlegroups.com.

johan Borgström

unread,
Jan 9, 2015, 2:46:43 PM1/9/15
to python_in...@googlegroups.com
@damonshelton Thanks for the tip, tough it seems like I do not need to call the update since it updates without.

For completion, what I did to allow for more decimals was to create a custom QItemDelegate and override the createEditor method. Feedback appreciated!

from PySide import QtCore, QtGui
from shiboken import wrapInstance
import maya.OpenMayaUI as omui


def maya_main_window():
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(long(main_window_ptr), QtGui.QWidget)
    

class MyDelegate(QtGui.QItemDelegate):
    
    def __init__(self, parent=None):
        super(MyDelegate, self).__init__(parent)
        
    def createEditor(self, parent, option, index):
        spinbox = QtGui.QDoubleSpinBox(parent)
        spinbox.setRange(.05,999)
        spinbox.setDecimals(3)
        spinbox.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
        return spinbox
    
               
# the main ui class  
class TableviewTest(QtGui.QWidget):
 
    def __init__(self, parent=None):
 
        super(TableviewTest, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Tool)
        
        self.resize(300, 350)
        self.setWindowTitle("Tableview")
                
        self.vertical_layout = QtGui.QVBoxLayout()
        self.setLayout(self.vertical_layout)
        
        # tableview  
        self.tableview = QtGui.QTableView()
        self.tableview.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
        self.vertical_layout.addWidget(self.tableview)
        
        self.tableview.setItemDelegate(MyDelegate(self.tableview))
        
        # model      
        self.model = QtGui.QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['Corner radius'])
        self.tableview.setModel(self.model)
        self.model.dataChanged.connect(self.model_changed)
        
        for row in range(5):
            
            item = QtGui.QStandardItem()
            item.setData(1.0, QtCore.Qt.EditRole)
            self.model.setItem(row, 0, item);            
    
    def model_changed(self, top_left, bottom_right):
        
        print('model changed')
        
        val = self.model.data(top_left)
        selection_model = self.tableview.selectionModel()
        
        # returns QModelIndex
        selected_rows = selection_model.selectedRows()
        
        self.model.blockSignals(True)
        
        for row in selected_rows:
            self.model.setData(row, val)

        self.model.blockSignals(False)
        
        #self.tableview.viewport().update() 


try:
    win.close()
    
except NameError as e:
    print(e)
    
win = TableviewTest(parent=maya_main_window())
win.move(100, 210)
win.show()

Thanks Justin!

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsubscribe@googlegroups.com.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages