Как вставить формулу в tableWidget сходство с Excel и вернуть значение формулы в лист? - PullRequest
0 голосов
/ 04 июля 2019

в моем приложении я хочу создать лист как Excel, мы вводим формулу и параметры, и у нас есть результаты;Я видел метод SpreadSheet (QTableWidget)

таблица отображается, но при первом щелчке в ячейке программа возвращает ошибку

SpreadSheet (QTableWidgetItem)

SpreadSheetDelegate (QitemDelegate (QitemDelegate))

from PyQt5 import QtCore, QtGui,QtWidgets,QtPrintSupport
from PyQt5.QtWidgets import QMainWindow,QApplication,QTableWidget,QTableWidgetItem,QInputDialog,QHBoxLayout,QItemDelegate,QLineEdit
from PyQt5.QtCore import QDir,Qt,QPointF,pyqtProperty, pyqtSignal, pyqtSlot,QDateTime#3 dernier test
from PyQt5.QtGui import QIcon,QTextDocument,QTextCursor,QPainter,QFont,QPalette,QColor,QPen,QBrush,QPixmap
import string,re

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.label = QtWidgets.QLabel(self.centralwidget)
        self.label.setObjectName("label")
        self.horizontalLayout.addWidget(self.label)
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setObjectName("lineEdit")
        self.horizontalLayout.addWidget(self.lineEdit)
        self.verticalLayout.addLayout(self.horizontalLayout)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label.setText(_translate("MainWindow", "FX"))



class fusionassurf(QMainWindow):
    def __init__(self):
        super(fusionassurf,self).__init__()
        self.ui=Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.tableWidget=Spreadsheet(self)
        self.ui.verticalLayout.addWidget(self.ui.tableWidget)
        self.ui.tableWidget.cellClicked.connect(self.onClickItem)
        self.ui.tableWidget.cellActivated.connect(self.onClickItem)
    def onClickItem(self):
            # return value of formule in QLineEdit
        pass


class Spreadsheet(QTableWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        _translate = QtCore.QCoreApplication.translate     
        self.setRowCount(20)
        self.setColumnCount(26)
        self.cells = {}
        self.setObjectName("tableWidget")
        header=[x for x in string.ascii_uppercase]
        self.setHorizontalHeaderLabels(header)
        self.setItemDelegate(SpreadSheetDelegate(self))
        self.setSelectionMode(self.ContiguousSelection)
        # test
        self.autocalcul=True
        #self.setItemPrototype(SpreadSheetItem('', self))
        for i in range(0, self.rowCount()):
            for j in range(0, self.columnCount()):
                cell = SpreadSheetItem("")
                self.setItem(i, j, cell)



class SpreadSheetDelegate(QItemDelegate):
    def __init__(self, parent=None):
        super(SpreadSheetDelegate, self).__init__(parent)

    def createEditor(self, parent, styleOption, index):
        editor = QLineEdit(parent)
        editor.editingFinished.connect(self.commitAndCloseEditor)
        return editor

    def commitAndCloseEditor(self):
        editor = self.sender()
        self.commitData.emit(editor)
        self.closeEditor.emit(editor, QItemDelegate.NoHint)

    def setEditorData(self, editor, index):
        editor.setText(index.model().data(index, Qt.EditRole))

    def setModelData(self, editor, model, index):
        model.setData(index, editor.text())
#ENCODAGE ET DECODAGE DES CELLULES REFERENCEES
cellre = re.compile(r'\b[A-Z][0-9]\b')


def cellname(i, j):
    return f'{chr(ord("A")+j)}{i+1}'        
def decode_pos(pos):
    try:
        row = int(pos[1:]) - 1
        col = ord(pos[0]) - ord('A')
    except ValueError:
        row = -1
        col = -1

    return row, col


def encode_pos(row, col):
    return chr(col + ord('A')) + str(row + 1)


class SpreadSheetItem(QTableWidgetItem):
    def __init__(self, text=None):
        if text is not None:
            super(SpreadSheetItem, self).__init__(text)
        else:
            super(SpreadSheetItem, self).__init__()

        self.isResolving = False

    def clone(self):
        item = super(SpreadSheetItem, self).clone()
        item.isResolving = self.isResolving

        return item

    def formula(self):
        return super(SpreadSheetItem, self).data(Qt.DisplayRole)

    def data(self, role):
        if role in (Qt.EditRole, Qt.StatusTipRole):
            return self.formula()
        if role == Qt.DisplayRole:
            return self.display()
        t = str(self.display())
        try:
            number = int(t)
        except ValueError:
            number = None
        if role == Qt.TextColorRole:
            if number is None:
                return QColor(Qt.black)
            elif number < 0:
                return QColor(Qt.red)
            return QColor(Qt.blue)

        if role == Qt.TextAlignmentRole:
            if t and (t[0].isdigit() or t[0] == '-'):
                return Qt.AlignRight | Qt.AlignVCenter
        return super(SpreadSheetItem, self).data(role)

    def setData(self, role, value):
        super(SpreadSheetItem, self).setData(role, value)
        if self.tableWidget():
            self.tableWidget().viewport().update()

    def display(self):
        # avoid circular dependencies
        if self.isResolving:
            return None
        self.isResolving = True
        result = self.computeFormula(self.formula(), self.tableWidget())
        self.isResolving = False
        return result

    def computeFormula(self, formula, widget):
        formula=formula.strip().replace(' ', '')
        if formula =="" or formula is None:
            return ""
        elif formula[0]=='=':
            self.formula=formula.upper()
        else:
            return formula



        # check if the string is actually a formula or not
        slist = formula.split(' ')
        if not slist or not widget:
            # it is a normal string
            return formula
        op = slist[0].lower()
        firstRow = -1
        firstCol = -1
        secondRow = -1
        secondCol = -1
        if len(slist) > 1:
            firstRow, firstCol = decode_pos(slist[1])
        if len(slist) > 2:
            secondRow, secondCol = decode_pos(slist[2])
        start = widget.item(firstRow, firstCol)
        end = widget.item(secondRow, secondCol)
        firstVal = 0
        try:
            firstVal = start and int(start.text()) or 0
        except ValueError:
            pass
        secondVal = 0
        try:
            secondVal = end and int(end.text()) or 0
        except ValueError:
            pass
        result = None
        if op == "sum":
            sum_ = 0
            for r in range(firstRow, secondRow + 1):
                for c in range(firstCol, secondCol + 1):
                    tableItem = widget.item(r, c)
                    if tableItem and tableItem != self:
                        try:
                            sum_ += int(tableItem.text())
                        except ValueError:
                            pass
            result = sum_
        elif op == "+":
            result = (firstVal + secondVal)
        elif op == "-":
            result = (firstVal - secondVal)
        elif op == "*":
            result = (firstVal * secondVal)
        elif op == "/":
            if secondVal == 0:
                result = "nan"
            else:
                result = (firstVal / secondVal)
        elif op == "=":
            if start:
                result = start.text()
        else:
            result = formula
        return result


if __name__ == "__main__":

    import sys

    app = QtWidgets.QApplication(sys.argv)
    locale=QtCore.QLocale.system().name()
    window =fusionassurf()
    window.show() 
    sys.exit(app.exec_())

Я ожидаю результат значения формулы в ячейке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...