How do I implement the ability to edit a QTableWid

2019-08-02 14:46发布

问题:

I have a QTableWidget that is displayed in the user interface that I can add and remove rows and columns using buttons. The problem is, when I add a row or column, I can change the data in the actual cells, but I cannot name the row or column. The name is simply a static number.

Is there a way to allow the user of my program to perhaps double-click on a row/column header and edit the name in-line or something similar?

Thanks.

回答1:

As far as I know there is no built-in way to do this. However this can be implemented manually. The main idea of the following code is to detect double clicks on header items, place QLineEdit over them and save edited text once it loses focus. The example is based on Qt generated Designer Form Class with a table named ui->tableWidget which can be either QTableWidget or QTableView.

class MainWindow : public QMainWindow {
  Q_OBJECT
public:
  explicit MainWindow(QWidget *parent = 0);
  ~MainWindow();
private:
  Ui::MainWindow *ui;
  QLineEdit* header_editor;
  int editor_index;
  bool eventFilter(QObject*, QEvent*);
};

Source:

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  header_editor = 0;
  ui->setupUi(this);
  ui->tableWidget->horizontalHeader()->viewport()->installEventFilter(this);
  ui->tableWidget->verticalHeader()->viewport()->installEventFilter(this);
}

MainWindow::~MainWindow() {
  delete ui;
}

bool MainWindow::eventFilter(QObject* object, QEvent* event) {
  if ((object == ui->tableWidget->horizontalHeader()->viewport() ||
       object == ui->tableWidget->verticalHeader()->viewport()) &&
      event->type() == QEvent::MouseButtonDblClick) {
    if (header_editor) { //delete previous editor just in case
      header_editor->deleteLater();
      header_editor = 0;
    }
    QMouseEvent* e = static_cast<QMouseEvent*>(event);
    QHeaderView* header = static_cast<QHeaderView*>(object->parent());
    int mouse_pos = header->orientation() == Qt::Horizontal ? e->x() : e->y();
    int logical_index = header->logicalIndex(header->visualIndexAt(mouse_pos));
    if (logical_index >= 0) { // if mouse is over an item
      QRect rect; // line edit rect in header's viewport's coordinates
      if (header->orientation() == Qt::Horizontal) {
        rect.setLeft(header->sectionPosition(logical_index));
        rect.setWidth(header->sectionSize(logical_index));
        rect.setTop(0);
        rect.setHeight(header->height());
      } else {
        rect.setTop(header->sectionPosition(logical_index));
        rect.setHeight(header->sectionSize(logical_index));
        rect.setLeft(0);
        rect.setWidth(header->width());
      }
      rect.adjust(1, 1, -1, -1);
      header_editor = new QLineEdit(header->viewport());
      header_editor->move(rect.topLeft());
      header_editor->resize(rect.size());
      header_editor->setFrame(false);
      //get current item text
      QString text = header->model()->
          headerData(logical_index, header->orientation()).toString();
      header_editor->setText(text);
      header_editor->setFocus();
      editor_index = logical_index; //save for future use
      header_editor->installEventFilter(this); //catch focus out event
      //if user presses Enter it should close editor
      connect(header_editor, SIGNAL(returnPressed()), 
              ui->tableWidget, SLOT(setFocus()));
      header_editor->show();
    }
    return true; // filter out event
  } else if (object == header_editor && event->type() == QEvent::FocusOut) {
    QHeaderView* header = static_cast<QHeaderView*>(
        header_editor->parentWidget()->parentWidget());
    //save item text
    header->model()->setHeaderData(editor_index, header->orientation(), 
                                   header_editor->text());
    header_editor->deleteLater(); //safely delete editor
    header_editor = 0;
  }
  return false;
}

Downsides of this method are that it's hacky, things go bad when headers are resized or table is scrolled. It's just an example that can be improved.

I have a feeling there has to be a simpler way. But Qt headers ignore Qt::ItemIsEditable flag and can't use delegates.