JoV
JoV

Reputation: 135

Python - QTableWidget.selectedRanges() return multiple ranges for on selection

I'm new in python and develop a GUI with a table. It should be possible to connect rows and column via a context menu. And this works. I can selected multiple rows by using ctrl + mouse left click.

But is one or more span is/are in the table and i want to add more, QTableWidget.selectedRanges() returns n*m selectionRanges if if select a nXm selection. For example if i selected 3 rows in a column, there are 3 selectionRanges.

And on the console is written 3 times

QTableView::setSpan: single cell span won't be added 

Python 2.7.5+ is installed.

Thx and bye.

Edited on 17th March 2014

Here is the complete code of my small program.

The program.py

import sys
from PyQt4 import QtGui, QtCore
from tableGui import Ui_Dialog as Dlg


class MarkDownTableGui(QtGui.QDialog,Dlg):
  def __init__(self):
    QtGui.QDialog.__init__(self)
    self.setupUi(self)
    ColumnCount = None
    ColumnRow = None    
    # Context menu connect cell/reset connected/selected cells
    self.menu = QtGui.QMenu()           
    self.menu.addAction("Connect",self.addSpan)
    self.menu.addAction("Reset",self.resetConnected)     

    self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)

    self.customContextMenuRequested.connect(self.showContextMenu)            
    self.connect(self.generateButton,QtCore.SIGNAL("clicked()"),self.onGenerate)

  def onGenerate(self):    
    """
      Generate a m x n table
    """
    self.tableWidget.setRowCount(self.RowCount.value())
    self.tableWidget.setColumnCount(self.ColumnCount.value())

  def addSpan(self):    
    selectedElements = self.tableWidget.selectedRanges()       

    for slrange in selectedElements:      
      self.tableWidget.setSpan(slrange.topRow(),slrange.leftColumn(),slrange.rowCount(),slrange.columnCount())  


  def showContextMenu(self,pos):             
    self.menu.exec_(QtGui.QCursor.pos())    

  def resetConnected(self):
    #TODO
    print "TODO"


app = QtGui.QApplication(sys.argv)
dialog = MarkDownTableGui()
dialog.show()
sys.exit(app.exec_())

this is the tableGui.py, generated by pyuic4

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

# Form implementation generated from reading ui file 'dialog_Table.ui'
#
# Created: Mon Mar 17 08:59:43 2014
#      by: PyQt4 UI code generator 4.10.3
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName(_fromUtf8("Dialog"))
        Dialog.setWindowModality(QtCore.Qt.ApplicationModal)
        Dialog.resize(509, 426)
        Dialog.setModal(True)
        self.buttonBox = QtGui.QDialogButtonBox(Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(140, 370, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName(_fromUtf8("buttonBox"))
        self.ColumnCount = QtGui.QSpinBox(Dialog)
        self.ColumnCount.setGeometry(QtCore.QRect(90, 10, 51, 23))
        self.ColumnCount.setMinimum(1)
        self.ColumnCount.setProperty("value", 5)
        self.ColumnCount.setObjectName(_fromUtf8("ColumnCount"))
        self.labelChapterCount = QtGui.QLabel(Dialog)
        self.labelChapterCount.setGeometry(QtCore.QRect(10, 10, 74, 23))
        self.labelChapterCount.setObjectName(_fromUtf8("labelChapterCount"))
        self.RowCount = QtGui.QSpinBox(Dialog)
        self.RowCount.setGeometry(QtCore.QRect(250, 10, 51, 23))
        self.RowCount.setMinimum(1)
        self.RowCount.setProperty("value", 5)
        self.RowCount.setObjectName(_fromUtf8("RowCount"))
        self.labelChapterCount_2 = QtGui.QLabel(Dialog)
        self.labelChapterCount_2.setGeometry(QtCore.QRect(160, 10, 74, 23))
        self.labelChapterCount_2.setObjectName(_fromUtf8("labelChapterCount_2"))
        self.generateButton = QtGui.QPushButton(Dialog)
        self.generateButton.setGeometry(QtCore.QRect(340, 10, 111, 24))
        self.generateButton.setObjectName(_fromUtf8("generateButton"))
        self.tableWidget = QtGui.QTableWidget(Dialog)
        self.tableWidget.setGeometry(QtCore.QRect(0, 40, 491, 321))
        self.tableWidget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.tableWidget.setRowCount(5)
        self.tableWidget.setColumnCount(5)
        self.tableWidget.setObjectName(_fromUtf8("tableWidget"))

        self.retranslateUi(Dialog)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), Dialog.accept)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(_translate("Dialog", "Table editor", None))
        self.labelChapterCount.setText(_translate("Dialog", "Column", None))
        self.labelChapterCount_2.setText(_translate("Dialog", "Rows", None))
        self.generateButton.setText(_translate("Dialog", "generate Table", None))

The problem

  1. if the programm is running you can select cell by pressing and holding the left mouse button
  2. Left click open the context menu
  3. Select connect, create a column/row span
  4. if i want to add additional spans and start at point 1. again then i got the message

    QTableView::setSpan: single cell span won't be added

The Question is why selectedRanges() returns a list with n selectionRanges instead of only on selectionRange. I've read the documentation of QTableWidget and QTableSelectionRange. But haven't any ideas

Upvotes: 1

Views: 3253

Answers (1)

ekhumoro
ekhumoro

Reputation: 120568

It seems that spanning cells in a table changes how the selection model constructs its selection-ranges. I don't exactly know why that is, but even if this didn't happen, it would not eliminate all the problems.

By default, a table-widget allows multiple selections, so you can end up with a selection that cannot be spanned (as a whole). But even if the multiple selections were next to each other and formed a block that could be spanned, the selection-model will always record these as a list of selection-ranges, rather than merging them all into a single selection.

So to get this to work properly, I think you will have to switch to a different selection-mode before allowing a span to be set. The best option would seem to be this:

    self.tableWidget.setSelectionMode(
        QtGui.QAbstractItemView.ContiguousSelection)

which only allows single, rectangular blocks to be selected. Probably you will need a button to switch between the different selection-modes, and disable the "Connect" menu-item as appropriate.

This still leaves the problem of dealing with the list of selection-ranges after the first span has been set. To fix that, you can do the following:

    def addSpan(self): 
        selection = list(self.tableWidget.selectionModel().selection())
        selection.sort()
        top = selection[0].top()
        left = selection[0].left()
        bottom = selection[-1].bottom()
        right = selection[-1].right()
        self.tableWidget.setSpan(
            top, left, bottom - top + 1, right - left + 1)

I'm not sure whether sorting the selection is actually necessary, but it does guarantee that the selection-ranges are always in the right order.

Upvotes: 1

Related Questions