首先来看下效果:
点击这些最近的文件能马上打开,比如点击SS.stp:
关键代码:
新建一个类,类名为RecentFiles,继承QObject,具体的.h文件(RecentFiles.h)如下,读者可以自行理解:
#ifndef RECENTFILES_H
#define RECENTFILES_H
#include <QObject>
#include <QStringList>
#include <QMainWindow>
#include <QSettings>
class QMenu;
class QAction;
#define recentFileCount "OCCADrecentFiles/numOfRecentFiles"
#define recentFileListId "OCCADrecentFiles/fileList"
/**
* @brief The RecentFiles class manages a list of recently accessed files.
*
* It handles user-settable number of most recently accessed files, provides
* a sub-menu that allows the user to select recently used files for opening.
*/
class RecentFiles : public QObject
{
Q_OBJECT
public:
explicit RecentFiles(QMainWindow *parent=NULL); /* Parent mainwindow, just for proper heirarchy, not actually used outside QObject constr */
~RecentFiles();
/// Inserts the sub-menu into another Menu
/// param menu The parent menu where the sub-menu should be inserted
/// param text Text of menu item after which Recent menu is inserted
void attachToMenuAfterItem(QMenu *menu, QString text, const char *slotName);
QStringList getRecentFiles() const; ///< application calls this to get list of recent files
void setMostRecentFile(const QString fileName); ///< called when each new file is opened
QString strippedName(const QString &fullFileName); ///< returns filename from full path
void setMenuEnabled(bool tf);
/// returns how many recent files are being remenbered. see setNumOfRecentFiles()
int numberOfRecentFilesToSave();
static const int MaxRecentFiles = 6; ///< Max number of names we keep.
public slots:
/// The application can set the number of recent files retained/reported here
void setNumOfRecentFiles(int n);
signals:
void openFile(QString fileName); ///< emitted when user selects item from "Open Recent" sub-menu
void newMaxFilesShown(int); ///< tells observers that the number of recent files being remembered has changed.
private slots:
void openRecentFile(); ///< menu items signal this when user selects item from "Open Recent" sub-menu
private:
void purgeMissingFilesFromList(QStringList &recentFileList);
void updateRecentFiles(QSettings &settings); ///< call this with each new filename
QMenu *m_recentMenu;
QAction *m_recentMenuTriggeredAction;
QAction *m_recentFileActions[MaxRecentFiles]; ///< QActions created in file menu for storing recent files
};
#endif // RECENTFILES_H
对应的.cpp文件如下:
#include "RecentFiles.h"
#include <QAction>
#include <QApplication>
#include <QDir>
#include <QFileInfo>
#include <QFile>
#include <QMenu>
#include <QString>
#include <QStringList>
#include <QSettings>
#include <QRegExp>
QString sanitizedFileName(const QString &name)
{
QString clean = name;
return clean.replace(QRegExp("[^A-Za-z0-9]"), QString("_"));
}
RecentFiles::RecentFiles(QMainWindow *parent)
: QObject(parent)
, m_recentMenu(new QMenu(parent))
, m_recentMenuTriggeredAction(NULL)
{
// create the sub-menu
m_recentMenu->setTitle("Open Recent...");
m_recentMenu->setObjectName("RecentMenu");
// create an action for all possible entries in the sub-menu
for (int i = 0; i < MaxRecentFiles; i++) {
m_recentFileActions[i] = new QAction(m_recentMenu);
m_recentFileActions[i]->setText("---");
m_recentFileActions[i]->setVisible(false);
connect(m_recentFileActions[i], SIGNAL(triggered()),
this, SLOT(openRecentFile()));
m_recentMenu->addAction(m_recentFileActions[i]);
}
// Set some defaults
QSettings settings;
if (!settings.value(recentFileCount).isValid())
settings.setValue(recentFileCount, QVariant(4));
// If there are no recent files, initialize an empty list
if (!settings.allKeys().contains(recentFileListId)) {
settings.setValue(recentFileListId, QVariant(QStringList()));
}
updateRecentFiles(settings);
}
RecentFiles::~RecentFiles()
{
// delete m_recentMenu; // might be bad because parent menu will delete.
m_recentMenu = (QMenu *)NULL;
}
//在menu菜单项下插图一个text名称的菜单项,并且这个菜单关联slotname响应
void RecentFiles::attachToMenuAfterItem(QMenu *menu, /* menu that "Recent" sub-menu should be inserted into */
QString text, /* Action in menu after which Recent menu should be inserted */
const char * slotName)
{
QList<QAction *> actionList = menu->actions();
int indexOfItemToFollow = 0;
for (; indexOfItemToFollow < actionList.size(); indexOfItemToFollow++) {
QAction *act = actionList.at(indexOfItemToFollow);
if (!act->text().compare(text)) {
break;
}
}
int indexOfItemToPreceed = indexOfItemToFollow + 1;
if (indexOfItemToPreceed >= actionList.size()) {
// append to end of menu
m_recentMenuTriggeredAction = menu->addMenu(m_recentMenu);
m_recentMenuTriggeredAction->setObjectName("recentMenuAction");
}
else {
// insert into menu
QAction *before = actionList.at(indexOfItemToPreceed);
m_recentMenuTriggeredAction = menu->insertMenu(before, m_recentMenu);
m_recentMenuTriggeredAction->setObjectName("recentMenuAction");
menu->insertSeparator(before);
}
connect(this, SIGNAL(openFile(QString)), parent(), slotName);
}
void RecentFiles::openRecentFile()
{
QAction *action = qobject_cast<QAction *>(sender());
if (action)
emit openFile(action->data().toString());
}
void RecentFiles::purgeMissingFilesFromList(QStringList &recentFileList)
{
for (QMutableStringListIterator i(recentFileList); i.hasNext();) {
QString fileName = i.next(); // stash filename and advance iterator
if (!QFile::exists(fileName)) {
i.remove(); // removes item last jumped by i.next()
}
}
}
QString RecentFiles::strippedName(const QString &fullFileName)
{
return QFileInfo(fullFileName).fileName();
}
void RecentFiles::setMenuEnabled(bool tf)
{
m_recentMenuTriggeredAction->setEnabled(tf);
}
int RecentFiles::numberOfRecentFilesToSave()
{
QSettings settings;
return settings.value(recentFileCount).toInt();
}
void RecentFiles::setMostRecentFile(const QString fileName)
{
if (fileName.isEmpty())
return;
QSettings settings;
QStringList recentFileList = settings.value(recentFileListId).toStringList();
recentFileList.removeAll(fileName);
recentFileList.prepend(fileName);
settings.setValue(recentFileListId, QVariant(recentFileList));
updateRecentFiles(settings);
qApp->setProperty("currentDirectory",
QVariant(
QFileInfo(fileName)
.absoluteDir()
.absolutePath()
));
}
void RecentFiles::setNumOfRecentFiles(int n)
{
QSettings settings;
settings.setValue(recentFileCount, QVariant(n));
updateRecentFiles(settings);
// So a preference panel can be updated to show new value...
emit newMaxFilesShown(n);
}
QStringList RecentFiles::getRecentFiles() const
{
QSettings settings;
QStringList recentFileList = settings.value(recentFileListId).toStringList();
return recentFileList;
}
void RecentFiles::updateRecentFiles(QSettings &settings)
{
int numOfRecentFiles = settings.value(recentFileCount, QVariant(4)).toInt();
QStringList MyRecentFileList = settings.value(recentFileListId).toStringList();
purgeMissingFilesFromList(MyRecentFileList);
settings.setValue(recentFileListId, QVariant(MyRecentFileList));
// If there are no recent files, then the menu item (that would show the list)
// should not be visible.
if (m_recentMenuTriggeredAction) {
if (numOfRecentFiles == 0) {
m_recentMenuTriggeredAction->setVisible(false);
}
else {
m_recentMenuTriggeredAction->setVisible(true);
}
}
for (int j = 0; j < MaxRecentFiles; ++j) {
if (j < MyRecentFileList.count() && j < numOfRecentFiles) {
QString text = strippedName(MyRecentFileList[j]);
m_recentFileActions[j]->setText(text);
m_recentFileActions[j]->setData(MyRecentFileList[j]);
m_recentFileActions[j]->setObjectName(sanitizedFileName(text));
m_recentFileActions[j]->setVisible(true);
}
else {
m_recentFileActions[j]->setVisible(false);
}
}
for (int j = numOfRecentFiles; j < MyRecentFileList.count(); j++)
m_recentFileActions[j]->setVisible(false);
getRecentFiles();
}
关于怎么使用的问题,就我的程序上来说,需要在Mainwindow上进行操作,因此我需要在Mainwindow上增加如下代码:
构造函数中:
m_recentFiles(this);
m_recentFiles.attachToMenuAfterItem(ui.menu_F, "Export...", SLOT(openFile(QString)));//在Export菜单项下插入
m_recentFiles.setNumOfRecentFiles(8);//最多显示最近的8个文件
在打开文件函数中添加如下代码:
QSettings settings;
QFileInfo fi(filename);
settings.setValue("currentDirectory", fi.absolutePath());
m_recentFiles.setMostRecentFile(filename);
如果需要点击这些最近的文件后打开,需要实现openFile(QString filename)函数,这个可以根据自己的情况就行了,我的实现是:
//最近文档打开接口
void OCCAD::openFile(QString filename)
{
QFormDoc *Temp = FindMdiChild(filename);
//判断文件是否已经打开
if (!Temp)
{//文件还没打开
QFormDoc *formDoc = FindEmptyFile();
if (formDoc)
{//还有空的文档,直接写入空文档
setActiveSubWindow(formDoc);
formDoc->loadFromFile(filename);
formDoc->setcurrFileName(filename);
formDoc->showMaximized(); //默认全屏显示
formDoc->Fill_View_style();
formDoc->show();
//
CurrOperation = "OPEN";
CreateModelNode();
CreateNodeWithModelType(filename, formDoc);
//
QSettings settings;
QFileInfo fi(filename);
settings.setValue("currentDirectory", fi.absolutePath());
m_recentFiles.setMostRecentFile(filename);
}
else
{
//没有空窗口,新建一个并显示到这个新窗口中
formDoc = new QFormDoc(this);
ui.mdiArea->addSubWindow(formDoc);
setActiveSubWindow(formDoc);
formDoc->loadFromFile(filename);
formDoc->showMaximized(); //默认全屏显示
formDoc->Fill_View_style();
formDoc->show();
//
CurrOperation = "OPEN";
CreateModelNode();
CreateNodeWithModelType(filename, formDoc);
//
QSettings settings;
QFileInfo fi(filename);
settings.setValue("currentDirectory", fi.absolutePath());
m_recentFiles.setMostRecentFile(filename);
}
}
else
{//文件已经打开,置顶这个窗口
Temp->activateWindow();
Temp->showMaximized(); //默认全屏显示
}
}
QT4下我测试的时候好像没问题,但是在QT5下工作不正常,后面看了下官网的资料:
因此,我在主函数中加入了这三句代码,之后能工作正常:
QCoreApplication::setOrganizationName("OCSOFT");
QCoreApplication::setOrganizationDomain("OCSOFT.COM");
QCoreApplication::setApplicationName("OCCAD V1.0");
后记: 到此,在QT窗口菜单中实现最近打开的文件功能已经完成。如果有什么写错的地方,请联系我修改 QQ:1623451686。