2016-12-03 6 views
1

У меня есть QTableView, как показано ниже. Я бы хотел нажать кнопку «Тест» и вставить «a» в курсор - например, в середине «11» в (строка, столбец) = (2,2). То есть пользователь дважды щелкает ячейку (2,2) и помещает курсор в середину «11» и нажимает «Тест». Желаемый результат: «1a1».PyQt: Как вставить текст в курсор в QTableView

screen capture

Является ли это выполнимо? Если да, то как? Огромное спасибо.

# coding: utf-8 

import sys 
from PyQt4 import QtGui, QtCore 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 

MY_ARRAY = [['00', '01', '02'], 
      ['10', '11', '12'], 
      ['20', '21', '22']] 


class MyWindow(QTableView): 
    def __init__(self, *args): 
     super(MyWindow, self).__init__() 

     self.tablemodel = MyTableModel(MY_ARRAY) 

     self.tableview = QTableView() 

     self.tableview.setModel(self.tablemodel) 

     self.tableview.setItemDelegate(MyDelegate(self)) 

     self.layout = QVBoxLayout(self) 
     self.layout.addWidget(self.tableview) 

     self.button1 = QPushButton("Test") 

     self.button1.released.connect(self.test) 

     self.layout.addWidget(self.button1) 
     self.setLayout(self.layout) 

    def test(self): 

     # MY_ARRAY.append([30,31,32]) 

     index = self.tableview.currentIndex() 
     item = self.tablemodel.data(index, Qt.DisplayRole) 

     print("item %s " % item) 

     item_edit = self.tableview.edit(index) 

     qDebug("qDebug: item_edit %s " % item_edit) 

     MY_ARRAY.insert(index.row(), ['30', '31', '32']) 

     self.tablemodel.layoutChanged.emit() 

     qDebug(" {} " .format(MY_ARRAY)) 

     qcursor = QCursor.pos() 
     qDebug(" {} ".format(qcursor)) 

     qcursor1 = self.mapFromGlobal(qcursor) 
     qDebug(" {} ".format(qcursor1)) 

     # qDebug(" self.tableview.indexAt(qcursor) {} ".format(self.tableview(qcursor))) 
     # qDebug(" self.tableview.indexAt(qcursor1) {} ".format(self.tableview(qcursor1))) 

     # print(' index.row(): ', index.row()) 

     qDebug(
      " tableview.rowViewportPosition %s " % 
      self.tableview.rowViewportPosition(index.row())) 
     qDebug(
      " tableview.columnViewportPosition %s " % 
      self.tableview.columnViewportPosition(index.column())) 

     # qDebug(" tableview.viewport() %s " % self.tableview.viewport(qcursor)) 

     item = self.tableview.setCurrentIndex(index) 
     qDebug(" tableview.item() %s " % self.tableview) 


class MyTableModel(QAbstractTableModel): 
    def __init__(self, datain, parent=None, *args): 
     super(MyTableModel, self).__init__(parent, *args) 

     self.arraydata = datain 

    def rowCount(self, parent): 
     return len(self.arraydata) 

    def columnCount(self, parent): 
     return len(self.arraydata[0]) 

    def data(self, index, role): 
     if not index.isValid(): 
      return None 

     elif not (role == Qt.DisplayRole or role == Qt.EditRole): 
      return None 
     return (self.arraydata[index.row()][index.column()]) 

    def setData(self, index, value, role=Qt.EditRole): 
     self.arraydata[index.row()][index.column()] = value 
     return True 

    def flags(self, index): 
     return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable 


class MyDelegate(QStyledItemDelegate): 

    def __init__(self, parent=None): 
     super(MyDelegate, self).__init__(parent) 

    def createEditor(self, parent, option, index): 
     editor = QLineEdit(parent) 
     self.connect(editor, SIGNAL("returnPressed()"), 
        self.commitAndCloseEditor) 
     return editor 

    def commitAndCloseEditor(self): 
     editor = self.sender() 
     if isinstance(editor, (QTextEdit, QLineEdit)): 
      self.emit(SIGNAL("commitData(QWidget*)"), editor) 
      self.emit(SIGNAL("closeEditor(QWidget*)"), editor) 

    def setEditorData(self, editor, index): 
     text = index.model().data(index, Qt.DisplayRole) 

     editor.setText(text) 

    def setModelData(self, editor, model, index): 
     model.setData(index, editor.text()) 

def main(): 
    app = QApplication(sys.argv) 
    w = MyWindow() 
    w.show() 
    sys.exit(app.exec_()) 

if __name__ == "__main__": 
    main() 
+0

Добро пожаловать в переполнение стека! Похоже, вы просите о помощи на дому. Хотя у нас нет проблем с самим собой, обратите внимание на эти [dos and don'ts] (http://meta.stackoverflow.com/questions/334822/how-do-i-ask-and-answer-homework-questions/338845 # 338845), и соответственно отредактируйте свой вопрос. –

+0

@JoeC. Это действительно не похоже на вопрос о домашнем задании. – ekhumoro

+0

Ну, это не домашнее задание. Это проблема из моего любительского проекта о выравнивании двойного языка. Алогорифм автоматически выравнивает два текста. Очень часто происходит несоосность, и требуется ручное выравнивание. Я относительно новичок в PyQt. Я потратил несколько дней на чтение книг и googling, но не мог найти решения. Поэтому я бы очень признателен, если кто-нибудь может дать указатель или два. – mike

ответ

1

Ячейки таблицы не имеют указателя и не редактируются непосредственно. Элементы редактирования предоставляются делегатом item. По умолчанию виджет редактора для текстовых данных является QLineEdit, но другие типы данных могут использовать различные виджеты редактора, такие как QSpinBox для числовых данных, или QComboBox для булевых данных. Определенный виджет может управляться установкой custom item-delegate.

Большая проблема с использованием чего-то типа кнопки для вставки текста в виджет редактирования заключается в том, что редактор будет автоматически закрыт (и уничтожен) сразу после нажатия кнопки. Поэтому будет гораздо проще использовать контекстное меню, чтобы добавить пользовательские действия:

class MyWindow(QTableView): 
    def __init__(self, *args): 
     ... 
     self.delegate = MyDelegate(self) 
     self.delegate.contextMenuRequested.connect(self.showContextMenu) 
     self.tableview.setItemDelegate(self.delegate) 

    def showContextMenu(self, editor, pos): 
     pos = editor.mapToGlobal(pos) 
     menu = editor.createStandardContextMenu() 
     menu.addSeparator() 
     action = menu.addAction('Insert Text') 
     if menu.exec_(pos) is action: 
      editor.insert(' foo ') 

class MyDelegate(QStyledItemDelegate): 
    contextMenuRequested = pyqtSignal(object, QPoint) 

    def createEditor(self, parent, option, index): 
     editor = QLineEdit(parent) 
     editor.setContextMenuPolicy(Qt.CustomContextMenu) 
     editor.customContextMenuRequested.connect(
      lambda pos: self.contextMenuRequested.emit(editor, pos)) 
     return editor 
+0

Большое спасибо. То, что «1a1» является просто примером. MyEelegate (QStyledItemDelegate) createEditor() создает редактор QLineEdit, я просто не знаю, как его использовать. Мой пример использования выглядит так: каждая ячейка содержит строку (абзац английского текста или текста на других языках). Пользователь визуально проверяет содержимое ячейки и решает на месте вставить дополнительный текст, затем он помещает курсор в это место и нажимает кнопку. Тем временем я нашел indexWidget для QTableView, но не слишком уверен, можно ли его использовать. – mike

+0

@mike. Использование отдельной кнопки для вставки текста будет довольно сложно реализовать. Контекстное меню будет намного проще. См. Мой обновленный ответ. – ekhumoro

+0

Еще раз спасибо. Я попробую использовать ваше предложение. Отличная помощь, я ценю это. – mike

1

После много борьбы и использования QDebug я, наконец, удалось найти решение. Я уверен, что он может быть дополнительно улучшен. Но я не знаю много о PyQt. Идея заключается в том, чтобы кэшировать позицию курсора в MyDelegate (QStyledItemDelegate) до закрытия редактора. Надеюсь, это может быть полезно для тех, кто сталкивается с той же проблемой.

class MyDelegate(QStyledItemDelegate): 
    ... 
    def createEditor(self, parent, option, index): 
     self.cursorpos = -1 # unset flag 
     editor = QLineEdit(parent) 
     self.connect(editor, SIGNAL("editingFinished()"), 
         self.commitAndCloseEditor) 
     return editor 

    def commitAndCloseEditor(self): 
     editor = self.sender() 
     self.cursorpos = editor.cursorPosition() 
     if isinstance(editor, (QTextEdit, QLineEdit)): 
      self.emit(SIGNAL("commitData(QWidget*)"), editor) 
      self.emit(SIGNAL("closeEditor(QWidget*)"), editor) 

Все это приводится ниже.

# coding: utf-8 

import sys 
from PyQt4 import QtGui, QtCore 
from PyQt4.QtCore import * 
from PyQt4.QtGui import * 

MY_ARRAY = [['00', '01', '02'], 
      ['10', '11', '12'], 
      ['20', '21', '22']] 


class MyWindow(QTableView): 
    def __init__(self, *args): 
     super(MyWindow, self).__init__() 

     self.tablemodel = MyTableModel(MY_ARRAY) 

     self.tableview = QTableView() 

     self.tableview.setModel(self.tablemodel) 

     # self.tableview.setItemDelegate(MyDelegate(self)) 

     self.delegate = MyDelegate(self) 
     self.tableview.setItemDelegate(self.delegate) 

     self.layout = QVBoxLayout(self) 
     self.layout.addWidget(self.tableview) 

     self.button1 = QPushButton("Test") 

     self.button1.released.connect(self.test) 

     self.layout.addWidget(self.button1) 
     self.setLayout(self.layout) 

    def test(self): 

     index = self.tableview.currentIndex() 
     item = self.tablemodel.data(index, Qt.DisplayRole) 

     qDebug("item %s " % item) 

     qDebug(" <test><MyDelegateMyDelegate> self.delegate.cursorpos: %s " % self.delegate.cursorpos) 

     cursorpos = self.delegate.cursorpos 
     qDebug(" <test> cursor pos %s " % cursorpos) 
     if cursorpos > -1: 
      index.model().setData(index, item[:cursorpos] + ' foo ' + item[cursorpos:]) 
      self.tablemodel.layoutChanged.emit() 
      self.delegate.cursorpos = -1 


class MyTableModel(QAbstractTableModel): 
    def __init__(self, datain, parent=None, *args): 
     super(MyTableModel, self).__init__(parent, *args) 

     self.arraydata = datain 

    def rowCount(self, parent): 
     return len(self.arraydata) 

    def columnCount(self, parent): 
     return len(self.arraydata[0]) 

    def data(self, index, role): 
     if not index.isValid(): 
      return None 

     elif not (role == Qt.DisplayRole or role == Qt.EditRole): 
      return None 
     return (self.arraydata[index.row()][index.column()]) 

    def setData(self, index, value, role=Qt.EditRole): 
     self.arraydata[index.row()][index.column()] = value 
     return True 

    def flags(self, index): 
     return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable 


class MyDelegate(QStyledItemDelegate): 

    def __init__(self, parent=None): 
     super(MyDelegate, self).__init__(parent) 
     self.cursorpos = -1 # unset flag 

    def createEditor(self, parent, option, index): 
     self.cursorpos = -1 # unset flag 
     editor = QLineEdit(parent) 
     self.connect(editor, SIGNAL("editingFinished()"), 
         self.commitAndCloseEditor) 
     return editor 

    def commitAndCloseEditor(self): 
     editor = self.sender() 
     self.cursorpos = editor.cursorPosition() 
     if isinstance(editor, (QTextEdit, QLineEdit)): 
      self.emit(SIGNAL("commitData(QWidget*)"), editor) 
      self.emit(SIGNAL("closeEditor(QWidget*)"), editor) 

    def setEditorData(self, editor, index): 
     text = index.model().data(index, Qt.DisplayRole) 

     editor.setText(text) 


    def setModelData(self, editor, model, index): 
     model.setData(index, editor.text()) 

def main(): 
    app = QApplication(sys.argv) 
    w = MyWindow() 
    w.show() 
    sys.exit(app.exec_()) 

if __name__ == "__main__": 
    main() 
Смежные вопросы