2016-12-03 96 views
1

我有一個QTableView如下。我想按測試按鈕並在光標處插入一個「a」 - 例如在(行,列)=(2,2)處的「11」中間。也就是說,用戶雙擊單元格(2,2)並將光標放在「11」的中間,然後按下Test。預期結果:「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

歡迎來到Stack Overflow!看起來你正在尋求作業幫助。雖然我們本身沒有任何問題,但請觀察這些[應做和不應該](http://meta.stackoverflow.com/questions/334822/how-do-i-ask-and-answer-homework-questions/338845#338845),並相應地編輯您的問題。 –

+0

@JoeC。這看起來不像一個家庭作業問題。 – ekhumoro

+0

嗯,這不是功課。這是我的業餘項目關於雙語對齊的一個問題。一個算法會自動對齊兩個文本。通常會出現不對中,需要手動對齊。我對PyQt比較陌生。我花了幾天的時間閱讀書籍和谷歌搜索,但無法找到任何解決方案。所以我非常感謝任何人都可以給一兩個指針。 – mike

回答

1

表格單元格沒有光標,不能直接編輯。編輯功能由物品代表提供。默認情況下,文本數據的編輯器小部件爲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」只是一個例子。 MyDelegate(QStyledItemDelegate)的createEditor()創建了一個QLineEdit編輯器,我只是不知道如何使用它。我的用例如下所示:每個單元格包含一個字符串(一段英文文本或其他語言的文本)。用戶通過視覺檢查單元格的內容並決定插入一些額外文本的位置,然後將光標放在該位置並按下按鈕。同時,我發現了QTableView的indexWidget,但我不太確定它是否可以使用。 – 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() 
相關問題