捣鼓了一下午加一晚上,把这个功能实现了。先说一下主要完成了几个内容:
1、实现右击菜单(重点:如何只在Item项上面弹出右击菜单,而在空白处不弹出菜单)
2、实现重命名功能
3、使用使用委托类实现对重命名检查,后缀名更改时给予警告
最后在编译程序时出现了2个编译错误(检查老半天才把问题纠察出来)。把相关错误写出来,给以后做参考!
1 实现右击菜单
网上有很多资料讲解了右击菜单的实现。但大多数都是基于QListWidget视图,本人实现的浏览器是QtreeView视图,所以相对来说有部分不同。但都是大同小异。
实现右键菜单, 必须重写下面这个函数
void QWidget::contextMenuEvent ( QContextMenuEvent * event ) [virtual protected]这个函数是QWidget的一个虚函数,使用时必须由QWidget的子类重写该函数。
本文中该函数的重新如下:
//实现右击菜单 void fileView::contextMenuEvent(QContextMenuEvent *event) { QMenu* popMenu = new QMenu(this); QModelIndex currIndex=this->tree->indexAt(tree->viewport()->mapFromGlobal(event->globalPos())); int i=currIndex.row(); // qDebug()<<"right:"<<i; if(i!=-1) { QAction *Rename=new QAction(QObject::tr("Rename"),this); popMenu->addAction(Rename); connect(Rename,SIGNAL(triggered(bool)),this,SLOT(slotRename())); } popMenu->exec( QCursor::pos() ); }说明:该函数实现与参考文献1中最大的差别就是关于通过鼠标位置确定来获取当前所对应的项。在QtreeView中没有ItemAt(widget_pos)函数,取而代之的是indexAt(viewport_pos)函数 该函数返回当前的模式索引QModelIndex.括号里的坐标参数也不一样 indexAt参数为视口坐标参数 Qt文档中indexAt()解释:
QModelIndex QAbstractItemView::indexAt(const QPoint & point) const Returns the model index of the item at the viewport coordinates point. In the base class this is a pure virtual function.
最简单的实现就是使用edit() 函数 所有的视图类都有该函数。但是本文在使用时候发现一直提示:editing fail.
经过查看Qt文档发现是由于使用的模型的原因。Qtreeview所对应的模型是:QFileSystemModel 在文档中有这样的描述:
This class provides access to the local filesystem, providing functions for renaming and removing files and directories, and for creating new directories可见该类是支持重命名的,但为何在程序中不能实现呢 又看到有一个属性 readOnly 描述如下:
readOnly : bool This property holds whether the directory model allows writing to the file system. If this property is set to false, the directory model will allow renaming, copying and deleting of files and directories. This property is true by default Access functions: bool isReadOnly() const void setReadOnly(bool enable)
原来默认情况下是只读的!所以可以通过setReadOnly(false)设置为可编辑的
3、委托机制
上一节的重命名只是简单的文本编辑功能,不能够进行编辑结果的检查,这时候使用委托机制,可以很好的完成相应的工作
关于委托参见参考文献2.实现一个委托类 要继承QStyledItemDelegate. 并且重新实现一下四个类:
createEditor():返回一个组件。该组件会被作为用户编辑数据时所使用的编辑器,从模型中接受数据,返回用户修改的数据。
setEditorData():提供上述组件在显示时所需要的默认值。
updateEditorGeometry():确保上述组件作为编辑器时能够完整地显示出来。
setModelData():返回给模型用户修改过的数据。
后缀名检查机制是通过在编辑前和编辑完成之后通过FileInfo类获取文件的后缀名。如果后缀名不相同则说明后缀名发生了更改。给予对应的警告。在setEditorData中获取编辑前后缀名 在setModelData获取修改后的文件后缀名 比与之前后缀名进行比较判断
//从模型中获取编辑数据 void TextBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index)const { QString value=index.model()->data(index,Qt::EditRole).toString(); QLineEdit *TextBox=static_cast<QLineEdit*>(editor); TextBox->setText(value); //获取文件后缀名 QFileInfo tmpInfo(value); startExt=tmpInfo.suffix(); // qDebug()<<startExt; }
//保存数据到模型 void TextBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QLineEdit *TextBox=static_cast<QLineEdit*>(editor); QString value=TextBox->text(); //获取后缀名 QFileInfo tmpInfo(value); QString endExt=tmpInfo.suffix(); //判断后缀名是否改变 并作出警告 if(startExt!=endExt) { QMessageBox::StandardButton res= QMessageBox::warning(NULL, "warning", "后缀名改变可能会导致文件不可用!", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); if(res==QMessageBox::No) return; if(res==QMessageBox::Yes) model->setData(index, value, Qt::EditRole); } //qDebug()<<endExt; }
4 编译过程的错误
错误一: error:LNK2001
见 参考文献3
大部分原因是没有生成MOC文件, 该原因可能是没加Q_OBJECT 后加上之后 要清理项目 重新qmake
错误二:error C2678: 二进制“=”: 没有找到接受“const QString”类型的左操作数的运算符(或没有可接受的转换)
这个问题简直令人头大 查找了半天文献 发现了一篇有用的提示:参考文献4
该文献大概是说 类成员函数为const函数 在函数内部不容许修改任何类成员 。所以我本来是定义一个QString的全局类成员变量 但是在const类函数内自动转换为
const QString; 所以导致我不能给变量赋值 但是还不能更该成员函数的类型(应为这些都是继承父类的虚函数 更改之后就不会响应了)
最后 没办法 本人暂时放弃声明该变量为类成员变量
参考文献:
【1】QListWidget的item上实现右键菜单
【2】视图与委托
【3】LNK2001
【4】const 函数