在保留文件扩展名的同时编辑 QTreeWidgetItem

Editing QTreeWidgetItem while retaining file extension

我有一个包含文件名的 QListWidget。右键单击一个项目会弹出一个包含 Rename... 项目的菜单。单击 Rename... 允许用户编辑文件名。到目前为止一切顺利。

但是在 Qt Creator Projects window 中,右键单击(比如)foo.cpp 并选择 Rename... 会向用户显示一个字段,其中 foo 被选中,而 .cpp 未被选中。所以默认操作是重命名 foo 部分而不更改 .cpp 扩展名。

这正是我所需要的,但我没有看到使用 Qt 的 public API 来实现它的方法。我需要做什么?我想是自定义代表;但这肯定是一个常见的要求,所以我想知道是否有人有一些我可以使用的现成的 C++ 代码?

一个可能的解决方案是创建一个 QObject 来拦截编辑器的显示事件,然后更改选择:

#include <QtWidgets>

class Helper: public QObject{
public:
    Helper(QLineEdit *le): QObject(le), m_le(le){
        m_le->installEventFilter(this);
    }
    bool eventFilter(QObject *watched, QEvent *event){
        if(watched == m_le && event->type() == QEvent::Show){
            QString filename = m_le->text();
            QFileInfo fi(filename);
            QString base = fi.baseName();
            m_le->setSelection(0, base.length());
        }
        return QObject::eventFilter(watched, event);
    }
private:
    QLineEdit* m_le;
};

class StyledItemDelegate: public QStyledItemDelegate{
public:
    using QStyledItemDelegate::QStyledItemDelegate;
    QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex &index) const{
        QWidget *editor = QStyledItemDelegate::createEditor(parent, option, index);
        if(QLineEdit *le = qobject_cast<QLineEdit *>(editor)){
            new Helper(le);
        }
        return editor;
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTreeWidget w;
    w.setItemDelegate(new StyledItemDelegate);
    for(const QString & filename: {"foo.txt", "foo.tar.gz", "foo.cpp"}){
        auto item = new QTreeWidgetItem({filename});
        item->setFlags(item->flags() | Qt::ItemIsEditable);
        w.addTopLevelItem(item);
    }
    w.show();
    return a.exec();
}