PDA

View Full Version : Select columns from a QTableWidget



toglez
4th October 2007, 17:31
Hi to all !!!

I'm new here and a newbie at the same time, so please don't be harsh...

I use Python with PyQt4 to develop a program reading a file with numbers and displaying them in a QTableWidget. So far so good.

What I have not accomplished yet, is to select certain columns from the QTableWidget and display them in another table. I would also like to store the selected tables' indexes in a global list.

My main.py file, the one that materializes the GUI and uses the derivative file from pyuic4 looks something like this:



from PyQt4 import QtGui, QtCore
from tstMain import Ui_tstMain

import sys, string
from os.path import isfile
from os import chdir

import variousFuncs


## Create a dictionary of updateable variables. These will be updated by the various
## functions of Class startGui
updVars = {"InitialFile": [], "SelectedColumns": []}

class startGui(QtGui.QMainWindow):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_tstMain()
self.ui.setupUi(self)

## create our slots here
QtCore.QObject.connect(self.ui.btn_SetWorkingDir, QtCore.SIGNAL("clicked()"), self.setWorkingDir)
QtCore.QObject.connect(self.ui.btn_OpenFile, QtCore.SIGNAL("clicked()"), self.openFile)
QtCore.QObject.connect(self.ui.btn_ListShow, QtCore.SIGNAL("clicked()"), self.showList)

def setWorkingDir(self):
wd = QtGui.QFileDialog(self)
currentDir = QtCore.QString(wd.getExistingDirectory())
self.ui.lnEdt_WorkingDir.setText(currentDir)
chdir(currentDir)

def openFile(self):
fd = QtGui.QFileDialog(self)
self.file = fd.getOpenFileName()

if isfile(self.file):
fileToOpen = open(self.file)
initialFile = [line.split() for line in fileToOpen.readlines()]
variousFuncs.dbl_str2num(initialFile)

updVars["InitialFile"] = initialFile
variousFuncs.tablePainter(initialFile, self.ui.tbl_OpenFile)

updVars["SelectedColumns"] = self.ui.tbl_OpenFile.selectedItems()

def showList(self):
tempSelected = updVars["SelectedColumns"]
variousFuncs.tablePainter(tempSelected, self.ui.tbl_ListShow)


while the variousFuncs file which contains various functions, looks something like this:



#!/usr/bin/python

import string, random, math
from PyQt4 import QtGui, QtCore

##
def dbl_str2num(lst):
""" This function transforms the items of the list "lst" from strings to numbers.
The list must be a nested list. """
for i in range(len(lst)):
for j in range(len(lst[0])):
lst[i][j] = eval(lst[i][j])

def tablePainter(someTwoDimLst, someTbl):
""" This function creates a QTableWidgetItem out of a 2-dimension nested list which contains numbers,
and then uses it to "paint" the someTbl object, which is a QTableWidget """
someTbl.setColumnCount(len(someTwoDimLst[0]))
someTbl.setRowCount(len(someTwoDimLst))

for i in range(len(someTwoDimLst)):
for j in range(len(someTwoDimLst[0])):
itemListShow = QtGui.QTableWidgetItem(QtCore.QString.number(someT woDimLst[i][j]), QtGui.QTableWidgetItem.Type)
someTbl.setItem(i, j, itemListShow)


currently, when I select certain columns from the tbl_OpenFile QTableWidget and try to display them in the tbl_ListShow one, the whole thing ends up with the error:


Traceback (most recent call last):
File "D:\Tutorial\main.py", line 52, in showList
itemListShow = QtGui.QTableWidgetItem(QtCore.QString.number(tempS elected[0][0]))
IndexError: list index out of range


which IMHO means that the line



updVars["SelectedColumns"] = self.ui.tbl_OpenFile.selectedItems()

returned nothing in the list (???)

Any help would be much appreciated.
Thank you all in advance,

Thomas

jacek
4th October 2007, 18:10
currently, when I select certain columns from the tbl_OpenFile QTableWidget and try to display them in the tbl_ListShow one, the whole thing ends up with the error
Do these "certain columns" happen to be empty?

toglez
4th October 2007, 19:16
OK - now I forgot to also post the derivative file of the pyuic4. After I had designed the layout with QT Designer, I created the following tstMain.py file via pyuic4:



# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'tstMain.ui'
#
# Created: Sun Sep 30 21:39:12 2007
# by: PyQt4 UI code generator 4.3
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

class Ui_tstMain(object):
def setupUi(self, tstMain):
tstMain.setObjectName("tstMain")
tstMain.setEnabled(True)
tstMain.resize(QtCore.QSize(QtCore.QRect(0,0,951,3 94).size()).expandedTo(tstMain.minimumSizeHint()))

sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Preferred,QtGu i.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(tstMain.sizePolicy(). hasHeightForWidth())
tstMain.setSizePolicy(sizePolicy)
tstMain.setLayoutDirection(QtCore.Qt.LeftToRight)

self.centralwidget = QtGui.QWidget(tstMain)
self.centralwidget.setObjectName("centralwidget")

self.tbl_OpenFile = QtGui.QTableWidget(self.centralwidget)
self.tbl_OpenFile.setGeometry(QtCore.QRect(110,80, 811,121))

sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,QtGu i.QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.tbl_OpenFile.siz ePolicy().hasHeightForWidth())
self.tbl_OpenFile.setSizePolicy(sizePolicy)
self.tbl_OpenFile.setMaximumSize(QtCore.QSize(1677 7215,16777215))
self.tbl_OpenFile.setLineWidth(1)
self.tbl_OpenFile.setObjectName("tbl_OpenFile")

self.btn_OpenFile = QtGui.QPushButton(self.centralwidget)
self.btn_OpenFile.setGeometry(QtCore.QRect(20,80,8 1,23))
self.btn_OpenFile.setObjectName("btn_OpenFile")

self.tbl_ListShow = QtGui.QTableWidget(self.centralwidget)
self.tbl_ListShow.setGeometry(QtCore.QRect(20,260, 901,81))
self.tbl_ListShow.setObjectName("tbl_ListShow")

self.btn_SetWorkingDir = QtGui.QPushButton(self.centralwidget)
self.btn_SetWorkingDir.setGeometry(QtCore.QRect(20 ,50,82,23))
self.btn_SetWorkingDir.setObjectName("btn_SetWorkingDir")

self.lnEdt_WorkingDir = QtGui.QLineEdit(self.centralwidget)
self.lnEdt_WorkingDir.setEnabled(True)
self.lnEdt_WorkingDir.setGeometry(QtCore.QRect(110 ,50,811,20))
self.lnEdt_WorkingDir.setAutoFillBackground(False)
self.lnEdt_WorkingDir.setReadOnly(True)
self.lnEdt_WorkingDir.setObjectName("lnEdt_WorkingDir")

self.btn_ListShow = QtGui.QPushButton(self.centralwidget)
self.btn_ListShow.setGeometry(QtCore.QRect(730,230 ,191,23))
self.btn_ListShow.setObjectName("btn_ListShow")
tstMain.setCentralWidget(self.centralwidget)

self.menubar = QtGui.QMenuBar(tstMain)
self.menubar.setGeometry(QtCore.QRect(0,0,951,21))
self.menubar.setObjectName("menubar")
tstMain.setMenuBar(self.menubar)

self.statusbar = QtGui.QStatusBar(tstMain)
self.statusbar.setObjectName("statusbar")
tstMain.setStatusBar(self.statusbar)

self.retranslateUi(tstMain)
QtCore.QMetaObject.connectSlotsByName(tstMain)

def retranslateUi(self, tstMain):
tstMain.setWindowTitle(QtGui.QApplication.translat e("tstMain", "My Test Application", None, QtGui.QApplication.UnicodeUTF8))
self.tbl_OpenFile.setRowCount(0)
self.tbl_OpenFile.clear()
self.tbl_OpenFile.setColumnCount(0)
self.tbl_OpenFile.setRowCount(0)
self.btn_OpenFile.setText(QtGui.QApplication.trans late("tstMain", "Open File", None, QtGui.QApplication.UnicodeUTF8))
self.tbl_ListShow.clear()
self.tbl_ListShow.setColumnCount(0)
self.tbl_ListShow.setRowCount(0)
self.btn_SetWorkingDir.setText(QtGui.QApplication. translate("tstMain", "Set Working Dir", None, QtGui.QApplication.UnicodeUTF8))
self.lnEdt_WorkingDir.setText(QtGui.QApplication.t ranslate("tstMain", "Working Directory NOT yet set !", None, QtGui.QApplication.UnicodeUTF8))
self.btn_ListShow.setText(QtGui.QApplication.trans late("tstMain", "Show List", None, QtGui.QApplication.UnicodeUTF8))


OK - Once I run the main.py file I am presented with the option to load a file in the first QTableWidget and I do so. In this way, the first QTableWidget named tbl_OpenFile is full of numbers imported from the opened file.
I then try to select whole columns here and there clicking with the mouse on the headers of the table. And so it does - the columns are selected...

...but when I click on the button btn_ListShow responsible to transfer my selection to the last QTable Widget named tbl_ListShow, I get the aforementioned error.

Thanx again,
Thomas

jacek
4th October 2007, 23:55
I am presented with the option to load a file in the first QTableWidget and I do so. [...] I then try to select whole columns here and there clicking with the mouse on the headers of the table. [...] but when I click on the button btn_ListShow responsible to transfer my selection to the last QTable Widget named tbl_ListShow, I get the aforementioned error.
You retrieve the selected items in openFile(). Isn't that before you have a chance to select anything?

P.S. Unfortunately I can't test your code, because PyQt4 package I have is for some reason incompatible with Qt4 installed on my system. I've tried to build PyQt4 from source, but GCC didn't survive this (probably because of OOM error).

toglez
5th October 2007, 16:15
The line responsible to collect the selected lines is line 44 in main.py:



updVars["SelectedColumns"] = self.ui.tbl_OpenFile.selectedItems()


This is of course inside the function openFile(). This line instructs the program to update the global dictionary {updVars} in its element "SelectedColumns" (which is a Python list) with any - if any - selected columns of the table tbl_OpenFile. At least, that was my intention.

The problem is that after some tests* I have conducted, it is proved that the global dictionary is not updated and the element list "SelectedColumns" is empty, that's why the program ends with this error.

So, either the columns are not actually selected with a simple mouse click, or the code is not written that way.

Thomas.

*test: after instructing the program to return the length of the global list "SelectedItems", it returns 0, no matter what column selection has been done on the table.

jacek
5th October 2007, 16:49
This is of course inside the function openFile(). This line instructs the program to update the global dictionary {updVars} in its element "SelectedColumns" (which is a Python list) with any - if any - selected columns of the table tbl_OpenFile.
As you wrote earlier, you first invoke openFile(), then you select columns and finally you call showList(). The problem is that you check what columns were selected in openFile(), that is before you select them. Move that line to showList() and it should work.

Do you really need that global dictionary?

toglez
5th October 2007, 22:27
et voila!!! It worked !!!

Thank you jacek, I really owe you one!

Problem solved.

The global dictionary is needed so as to put there various updates of the various variables, because the project is a much more complicated program, needing to display various pieces of information from various sources. (At least I think I need it...)

Thank you again.

Thomas

toglez
6th October 2007, 03:27
Now would someone be so very kind as to show me how I am to collect the indexes of the selected columns of the table (e.g. 0, 1, 5, etc)?

Thanx again in advance

Thomas

toglez
7th October 2007, 02:10
Anybody any ideas?

Thomas

jpn
7th October 2007, 08:04
Take a look at QItemSelectionModel (http://www.riverbankcomputing.com/Docs/PyQt4/html/qitemselectionmodel.html) which is accessible via QAbstractItemView.selectionModel (http://www.riverbankcomputing.com/Docs/PyQt4/html/qabstractitemview.html#selectionModel).

toglez
7th October 2007, 16:15
I think I have eventually come up with a solution.

It seems that each selected item has an attribute column() (or row() of course), which returns the item's column (or row) as an integer. So, if I would like to test the existence of selected columns it would now be rather easy to isolate them:



def showList(self):
tempSelected = self.ui.tbl_OpenFile.selectedItems()

tempLst = []

for i in tempSelected:
if i.row() == 0: tempLst.append(i.column())

tempLst.sort()

s = ""

for i in xrange(len(tempLst)):
s += str(tempLst[i]) + " "

self.ui.txtEd_ListShow.setText(QtCore.QString(s))



The above function gathers the selected items' list in a locally defined list named tempSelected. Then, for each member of this list the function adds the corresponding column to a string, which then displays in a text edit window by the name txtEd_ListShow.

Thomas