[Solved] QTableView reflected in every tab PyQt



  • Hello! I am using PyQt4/python2.7
    I have tabbed windows which contains QTableView. So when I open a new tab I get QTableView in it. When I click on a button to populate the view, it works correctly, however it reflects the result in every other QTableView tab.
    I make sure I made a new instance of the view/Model.
    The only way it works correctly, is that I open few tabs but I have to focus on each, like open it. Then it will work on the one i just selected and won't reflect result, however if after that I make a new tab, that new tab reflects current result.
    I checked, but seems the new Qtableview in the new tabs doesn't contain data, even though they reflect it. So I am guessing the problem is with QtableView?
    Thanks!



  • Hi there. Can you give us a look at the code (or an example showing the issue)? I use the model/view framework quite extensively and I've not seen this before so I'm wondering if it might be implementation specific.

    In the meantime, just speculating, but if focusing on the table clears the issue then it may be a painting issue.



  • I don't know but I have too many files. I am gonna place a link to download the src. Don't know if it's against the ToS or not.
    src: https://docs.google.com/file/d/0B85x0CvqiVuTzRHek9BNkxhUlk/edit?usp=sharing
    More details:
    Platform: windows x64
    you might need Impacket/pcapy modules
    can be found here -> http://breakingcode.wordpress.com/2012/07/16/quickpost-updated-impacketpcapy-installers-for-python-2-5-2-6-2-7/
    Thanks!

    UPDATE: To induce the problem, just create new tab, then click on sniff, then create another tab, you will see the new tab has the same result as the other tab. I tried it with tablewidget, worked fine. So is something wrong with my implementation?
    UPDATE2: start with proposal.py


  • Moderators

    Are all the views connected to the same model? If that is the case, then changing something in one view will change all the others as well.



  • Nope, I create a new model in each tab.
    Through my code, New tab -> creates new frame.InnerTab -> which creates Sniffer6.Sniffy() ->which I initiate a new model in it.
    and that happens with every tab.
    Thanks!



  • Hi there, sorry for the delay in replying, I've only just had to time to look through your code.

    The problem you are having is nothing to do with views, its actually to do with the default arguments you are passing to the initialiser of your table model (snifferModel.tableModel). You have the following:

    @
    ...
    def init(self, result=[], headers=[]):
    super(tableModel, self).init()
    self.result=result
    self.headers.headers
    ...
    @

    The thing you need to understand about python is that default arguments to functions/methods are mutable and are only evaluated once at definition not each time the function/method is called. This means that every time this initialiser is called each instance of the model class gets the same instance of the default list and, as you never call this method with anything but the default argument for result, every instance of your model is referring to the same list. You can find a really good explanation of this behaviour "here":http://effbot.org/zone/default-values.htm.

    In the short term, the solution to your problem is a simple rewrite of your initialiser as follows and your problem is solved:

    @
    def init(self, result=None, headers=None):
    super(tableModel, self).init()
    self.result=result or []
    self.headers=headers or []
    @

    This will set your instance variable to the value of the function argument or create a new list if it is None.

    Hope this helps ;o)



  • Oh wow, I never knew they were mutable. Didn't even occur to me, your solution does work great! Thank you!!
    Also, while just another quick question ( I am just taking advantage of you here, hope u don't mind)
    I get this error:
    QObject::startTimer: QTimer can only be used with threads started with QThread
    From what I was able to get, it's okay, cause the garbage collector just closes them in a messy order when I close the application?



  • [quote author="DisappointedIdealist" date="1368189432"]
    QObject::startTimer: QTimer can only be used with threads started with QThread
    [/quote]

    Do you get this error when you exit your application or while its running? If it happens on exit then yes, it is to do with garbage collecting. It usually occurs because an item (widget, model, view etc.) has not been given a parent and is therefore owned by python/PyQt rather than Qt itself. Whilst its probably not the end of the world if this happens it would be better practice to track down the source and prevent it especially as giving widgets a parent is generally a good idea anyhow.



  • At exiting of the application. It happened when I used the model/view from this example(so probably from my Model since I used parts of it in my code). Even when running this example I get the error after closing all windows.

    src: http://www.yasinuludag.com/PyQt/Tutorial03/Tutorial03_TableModel.py

    OR(same)

    @from PyQt4 import QtGui, QtCore, uic
    import sys

    class PaletteTableModel(QtCore.QAbstractTableModel):

    def __init__(self, colors = [[]], headers = [], parent = None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self.__colors = colors
        self.__headers = headers
    
    
    
    def rowCount(self, parent):
        return len(self.__colors)
    
    
    def columnCount(self, parent):
        return len(self.__colors[0])
    
    
    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    
    
    def data(self, index, role):
        
        
        if role == QtCore.Qt.EditRole:
            row = index.row()
            column = index.column()
            return self.__colors[row][column].name()
        
        
        if role == QtCore.Qt.ToolTipRole:
            row = index.row()
            column = index.column()
            return "Hex code: " + self.__colors[row][column].name()
        
    
        if role == QtCore.Qt.DecorationRole:
            
            row = index.row()
            column = index.column()
            value = self.__colors[row][column]
            
            pixmap = QtGui.QPixmap(26, 26)
            pixmap.fill(value)
            
            icon = QtGui.QIcon(pixmap)
            
            return icon
    
              
        if role == QtCore.Qt.DisplayRole:
            
            row = index.row()
            column = index.column()
            value = self.__colors[row][column]
            
            return value.name()
    
    
    def setData(self, index, value, role = QtCore.Qt.EditRole):
        if role == QtCore.Qt.EditRole:
            
            row = index.row()
            column = index.column()
            
            color = QtGui.QColor(value)
            
            if color.isValid():
                self.__colors[row][column] = color
                self.dataChanged.emit(index, index)
                return True
        return False
    
    
    
    
    def headerData(self, section, orientation, role):
        
        if role == QtCore.Qt.DisplayRole:
            
            if orientation == QtCore.Qt.Horizontal:
                
                if section < len(self.__headers):
                    return self.__headers[section]
                else:
                    return "not implemented"
            else:
                return QtCore.QString("Color %1").arg(section)
    
    
    
    #=====================================================#
    #INSERTING & REMOVING
    #=====================================================#
    def insertRows(self, position, rows, parent = QtCore.QModelIndex()):
        self.beginInsertRows(parent, position, position + rows - 1)
        
        for i in range(rows):
            
            defaultValues = [QtGui.QColor("#000000") for i in range(self.columnCount(None))]
            self.__colors.insert(position, defaultValues)
        
        self.endInsertRows()
        
        return True
    
    
    def insertColumns(self, position, columns, parent = QtCore.QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        
        rowCount = len(self.__colors)
        
        for i in range(columns):
            for j in range(rowCount):
                self.__colors[j].insert(position, QtGui.QColor("#000000"))
        
        self.endInsertColumns()
        
        return True
    

    if name == 'main':

    app = QtGui.QApplication(sys.argv)
    app.setStyle("plastique")
    
    
    #ALL OF OUR VIEWS
    listView = QtGui.QListView()
    listView.show()
    
    comboBox = QtGui.QComboBox()
    comboBox.show()
    
    tableView = QtGui.QTableView()
    tableView.show()
    
    
    
    red   = QtGui.QColor(255,0,0)
    green = QtGui.QColor(0,255,0)
    blue  = QtGui.QColor(0,0,255)
    
    
    
    rowCount = 4
    columnCount = 6
    
    headers = ["Pallete0", "Colors", "Brushes", "Omg", "Technical", "Artist"]
    tableData0 = [ [ QtGui.QColor("#FFFF00") for i in range(columnCount)] for j in range(rowCount)]
    
    model = PaletteTableModel(tableData0, headers)
    model.insertColumns(0, 5)
    
    listView.setModel(model)
    comboBox.setModel(model)
    tableView.setModel(model)
    
    
    sys.exit(app.exec_())
    

    @



  • Yep, its the problem I described. If you reimplement the last part of the example as follows, where the views and model are given a parent (in this case a containing QWidget), the application exits quietly:

    @
    ...
    if name == 'main':

    class Widget(QtGui.QWidget):
        def __init__(self, parent=None, **kwargs):
            QtGui.QWidget.__init__(self, parent, **kwargs)
            l=QtGui.QVBoxLayout(self)
    
            #ALL OF OUR VIEWS
            listView = QtGui.QListView(self)
            l.addWidget(listView)
    
            comboBox = QtGui.QComboBox(self)
            l.addWidget(comboBox)
    
            tableView = QtGui.QTableView(self)
            l.addWidget(tableView)        
            
            red   = QtGui.QColor(255,0,0)
            green = QtGui.QColor(0,255,0)
            blue  = QtGui.QColor(0,0,255)
    
            rowCount = 4
            columnCount = 6
    
            headers = ["Pallete0", "Colors", "Brushes", "Omg", "Technical", "Artist"]
            tableData0 = [ [ QtGui.QColor("#FFFF00") for i in range(columnCount)] for j in range(rowCount)]
           
            model = PaletteTableModel(tableData0, headers, self)
            model.insertColumns(0, 5)
            
            listView.setModel(model)
            comboBox.setModel(model)
            tableView.setModel(model)
    
    app = QtGui.QApplication(sys.argv)
    w=Widget()
    w.show()
    w.raise_()
    sys.exit(app.exec_())
    

    @



  • Ah okay, thank you!



  • Hey, I am sorry to bother you, but I tried to give everyone a parent, and I think they do?
    (from my src code)
    @def init(self, parent=None , **kwargs):
    QWidget.init(self, parent, **kwargs)
    layout = QVBoxLayout(self)
    self.lv = snifferView.view()
    layout.addWidget(self.lv)
    self.setLayout(layout)

        headers = ['No','Source','Destination','Protocol']
        
        self.model = snifferModel.tableModel(headers=headers)
        self.lv.tableView.setModel(self.model)
        self.resultList = []
        self.hexDump = ''
        self.count = 0
        self.lv.tableView.selectionModel().selectionChanged.connect(self.rowSelected)
     @

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.