Reputation: 135
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
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
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