QStyledItemDelegate 部分选择默认 QLineEdit 编辑器的文本

Posted

技术标签:

【中文标题】QStyledItemDelegate 部分选择默认 QLineEdit 编辑器的文本【英文标题】:QStyledItemDelegate partially select text of default QLineEdit editor 【发布时间】:2016-09-23 18:38:01 【问题描述】:

我有一个QStyledItemDelegate 的子类,目前它没有重新实现任何功能(为简单起见)。

使用默认的QStyledItemDelegate 实现,当用户开始编辑QTableView 中的文本时,代理会使用模型中的文本绘制QLineEdit,并选择所有文本(突出显示所有文本以进行编辑)。

文本代表文件名,例如“document.pdf”。允许用户编辑整个文本,但是,我只想首先突出显示基本名称部分(“文档”)而不是后缀(“pdf”)。我怎样才能做到这一点? (我不需要这样做的逻辑,我需要知道如何让QStyledItemDelegate 突出显示部分文本)

我试过了:

setEditorData() 中使用QLineEdit::setSelection() 突出显示某些文本。这没有任何效果。

paint() 中尝试根据其他受访者对类似问题的建议进行绘画,但未成功。我对QPainter 的经验很少。这是一个例子:Adjusting the selection behaviour of QStandardItem with QStyledItemDelegate

请提供帮助,并在此先感谢您。非常感谢您选择文本的前 3 个字符的代码 sn-p。

【问题讨论】:

当角色为Qt::EditRole 时,您可以让模型返回不带扩展名的文件名。但这样一来,用户将无法更改扩展名。 如果您希望扩展是可编辑的,您不需要绘制选择,您需要在行编辑上真正设置选择以排除扩展。您提到的第二种方法对您不起作用。 覆盖setEditorData 并设置您想要的选择应该可以正常工作。但是在Qt source code 中,您可以在setEditorData 之后看到对le->selectAll(); 的调用。不幸的是,这意味着您在setEditorData 中所做的任何选择都会在该呼叫中发生变化。这就是为什么您的第一种方法行不通的原因。 @Mike 关于如何选择文本的一部分有什么建议吗? 【参考方案1】:

正如我对问题的 cmets 所述,子类化 QStyledItemDelegate 并尝试在 setEditorData 中设置任何默认选择的问题如下:

void setEditorData(QWidget* editor, const QModelIndex &index)const
    QStyledItemDelegate::setEditorData(editor, index);
    if(index.column() == 0) //the column with file names in it
        //try to cast the default editor to QLineEdit
        QLineEdit* le= qobject_cast<QLineEdit*>(editor);
        if(le)
            //set default selection in the line edit
            int lastDotIndex= le->text().lastIndexOf("."); 
            le->setSelection(0,lastDotIndex);
        
    

在视图调用我们的setEditorDatahere之后(在Qt代码中),当编辑器小部件是QLineEdit时,它会尝试调用selectAll()here。这意味着我们在setEditorData 中提供的任何选择都会在之后更改。

我能想到的唯一解决方案是以排队的方式提供我们的选择。因此,我们的选择是在执行回到事件循环时设置的。这是工作示例:

#include <QApplication>
#include <QtWidgets>

class FileNameDelegate : public QStyledItemDelegate
public:
    explicit FileNameDelegate(QObject* parent= nullptr)
        :QStyledItemDelegate(parent)
    ~FileNameDelegate()

    void setEditorData(QWidget* editor, const QModelIndex &index)const
        QStyledItemDelegate::setEditorData(editor, index);
        //the column with file names in it
        if(index.column() == 0)
            //try to cast the default editor to QLineEdit
            QLineEdit* le= qobject_cast<QLineEdit*>(editor);
            if(le)
                QObject src;
                //the lambda function is executed using a queued connection
                connect(&src, &QObject::destroyed, le, [le]()
                    //set default selection in the line edit
                    int lastDotIndex= le->text().lastIndexOf(".");
                    le->setSelection(0,lastDotIndex);
                , Qt::QueuedConnection);
            
        
    
;

//Demo program

int main(int argc, char** argv)
    QApplication a(argc, argv);

    QStandardItemModel model;
    QList<QStandardItem*> row;
    QStandardItem item("document.pdf");
    row.append(&item);
    model.appendRow(row);
    FileNameDelegate delegate;
    QTableView tableView;
    tableView.setModel(&model);
    tableView.setItemDelegate(&delegate);
    tableView.show();

    return a.exec();

这听起来像是一个 hack,但我决定写这个,直到有人有更好的方法来解决这个问题。

【讨论】:

非常感谢迈克。这可以完美地与您的代码进行非常小的修改以删除行 if(index.column() == 0) 因为我正在编辑列> 0。它看起来确实是一种解决方法,您认为值得提交吗向 Qt 报告错误以提供更好的 API 来访问小部件,以便用户可以完全控制它?非常感谢:) @CSLover ,不客气。这就是我所说的意思,如果你有文件名,你需要将它更改为列:) @CSLover ,我不太确定错误报告。但就个人而言,我认为这真的不值得提交错误报告。他们似乎为QLineEdits 调用了le-&gt;selectAll(),因此覆盖setEditorData 的用户没有义务调用selectAll() 以默认选择其行编辑中的文本。省略该调用可能会导致许多已编写的代码显示QLineEdit,默认情况下没有选择。 很公平。再次感谢,非常感谢。 这可以通过覆盖 QLineEdit 的方法来完成吗?我希望默认情况下不选择文本,但我正在努力制作与您的连接调用等效的 python。

以上是关于QStyledItemDelegate 部分选择默认 QLineEdit 编辑器的文本的主要内容,如果未能解决你的问题,请参考以下文章

QStyledItemDelegate 在 QTableView 中显示 QComboBox

如何在 QStyledItemDelegate 中绘制整行的背景?

在 QStyledItemDelegate 中显示 QComboBox 文本而不是索引值

Qt表格中的自定义编辑组件---------------自定义代理QStyledItemDelegate

QStyledItemDelegate - updateEditorGeometry 如何工作?

没有为 QTableView 行调用 QStyledItemDelegate 的 sizeHint 方法