dialogs/findfiles/findfiles.pro
用于在指定文件夹中查找文件的对话框。
Find Files 应用程序允许用户在指定目录中搜索文件,匹配给定的文件名或通配符,并包含指定的字符串(如果已填写)。 搜索结果显示在包含文件名称及其大小的表格中。 该应用程序还显示找到的文件数。
Find Files 示例说明了几个类的使用:
Qt类 | 功能 |
---|---|
QProgressDialog | 提供有关搜索操作进度的反馈 |
QFileDialog | 浏览文件列表 |
QTextStream | 使用流操作符读取文件 |
QTableWidget | 浏览表格中的搜索结果 |
QDesktopServices | 在合适的应用程序中打开结果列表中的文件 |
窗口类定义
Window类继承了QWidget,并且是主要的应用程序小部件。它显示搜索选项并显示搜索结果。
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QDir>
class QComboBox;
class QLabel;
class QPushButton;
class QTableWidget;
class QTableWidgetItem;
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = nullptr);
~Window();
private slots:
void browse();
void find();
void animateFindClick();
void openFileOfItem(int row, int column);
void contextMenu(const QPoint &pos);
private:
QStringList findFiles(const QStringList &files, const QString &text);
void showFiles(const QStringList &paths);
QComboBox *createComboBox(const QString &text = QString());
void createFilesTable();
QComboBox *fileComboBox;
QComboBox *textComboBox;
QComboBox *directoryComboBox;
QLabel *filesFoundLabel;
QPushButton *findButton;
QTableWidget *filesTable;
QDir currentDir;
};
#endif
该应用程序有两个重要的私有槽函数:
The browse() slot
当用户想要浏览要搜索的目录时调用The find() slot
当用户使用 Find 按钮启动搜索时调用
此外,还声明了四个私有函数:
findFiles()
搜索匹配搜索参数的文件showFiles()
显示搜索结果createComboBox()
构造小部件createFilesTable()
构造小部件
窗口类实现
构造函数
在构造函数中,我们首先创建应用程序的小部件。
Window::Window(QWidget *parent)
: QWidget(parent)
{
setWindowTitle(tr("Find Files"));
// 创建浏览按钮与搜寻按钮
QPushButton *browseButton = new QPushButton(tr("&Browse..."), this);
connect(browseButton, &QAbstractButton::clicked, this, &Window::browse);
findButton = new QPushButton(tr("&Find"), this);
connect(findButton, &QAbstractButton::clicked, this, &Window::find);
// 创建三个下拉框:文件下拉框、文本下拉框、目录下拉框
fileComboBox = createComboBox(tr("*"));
connect(fileComboBox->lineEdit(), &QLineEdit::returnPressed,
this, &Window::animateFindClick);
textComboBox = createComboBox();
connect(textComboBox->lineEdit(), &QLineEdit::returnPressed,
this, &Window::animateFindClick);
directoryComboBox = createComboBox(QDir::toNativeSeparators(QDir::currentPath()));
connect(directoryComboBox->lineEdit(), &QLineEdit::returnPressed,
this, &Window::animateFindClick);
filesFoundLabel = new QLabel;
createFilesTable();
// 添加垂直布局
QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(new QLabel(tr("Named:")), 0, 0);
mainLayout->addWidget(fileComboBox, 0, 1, 1, 2);
mainLayout->addWidget(new QLabel(tr("Containing text:")), 1, 0);
mainLayout->addWidget(textComboBox, 1, 1, 1, 2);
mainLayout->addWidget(new QLabel(tr("In directory:")), 2, 0);
mainLayout->addWidget(directoryComboBox, 2, 1);
mainLayout->addWidget(browseButton, 2, 2);
mainLayout->addWidget(filesTable, 3, 0, 1, 3);
mainLayout->addWidget(filesFoundLabel, 4, 0, 1, 2);
mainLayout->addWidget(findButton, 4, 2);
connect(new QShortcut(QKeySequence::Quit, this), &QShortcut::activated, qApp, &QApplication::quit);
}
我们创建小部件来构建 UI,并使用 QGridLayout
将它们添加到主布局中。 addWidget
函数原型及参数见下。
void QGridLayout::addWidget(QWidget *widget, int row, int column, Qt::Alignment alignment = ...)
将给定的小部件添加到行、列的单元格网格中。 默认情况下,左上角的位置是 (0, 0)。对齐方式由对齐方式指定。 默认对齐方式为 0,这意味着小部件填充整个单元格。
void QGridLayout::addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment = ...)
此版本将给定的小部件添加到单元格网格中,跨越多行/列。 单元格将从 fromRow 开始,fromColumn 跨越 rowSpan 行和 columnSpan 列。 小部件将具有给定的对齐方式。如果 rowSpan 和/或 columnSpan 为 -1,则小部件将分别延伸到底部和/或右侧边缘。
然而,我们首先将 Find
和 Quit
按钮和一个可拉伸的空间放在一个单独的 QHBoxLayout
中,以使这些按钮出现在 Window
小部件的右下角。或者,我们可以使用 Qt Designer
来构建 UI
文件,并使用 uic
来生成此代码。
我们没有创建带有 Quit
菜单项的 QMenuBar
; 但我们仍然希望有一个退出的键盘快捷键。 由于我们使用 QKeySequence::Quit
构建了一个 QShortcut
,并将其连接到 QApplication::quit()
,因此在大多数平台上,可以按 Control-Q
退出(或该平台上配置的任何标准退出键)。(在 macOS 上,这是多余的,因为每个应用程序都会自动获得一个 Quit 菜单项;但它有助于使应用程序可移植。)
void Window::animateFindClick()
{
findButton->animateClick();
}
槽函数browse()
void Window::browse()
{
QString directory =
QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Find Files"), QDir::currentPath()));
if (!directory.isEmpty()) {
if (directoryComboBox->findText(directory) == -1)
directoryComboBox->addItem(directory);
directoryComboBox->setCurrentIndex(directoryComboBox->findText(directory));
}
}
browse()
槽函数使用 QFileDialog
类向用户呈现一个文件对话框。QFileDialog
使用户能够遍历文件系统以选择一个或多个文件或目录。创建 QFileDialog
最简单的方法是使用方便的静态函数。

这里我们使用静态 QFileDialog::getExistingDirectory()
函数,它返回用户选择的现有目录。 然后我们使用 QComboBox::addItem()
函数在目录组合框中显示目录并更新当前索引。
QComboBox::addItem()
使用给定文本(如果列表中不存在)并包含指定的用户数据将项目添加到组合框中。 该项目被附加到现有项目的列表中。
槽函数find()
void Window::find()
{
filesTable->setRowCount(0);
QString fileName = fileComboBox->currentText();
QString text = textComboBox->currentText();
QString path = QDir::cleanPath(directoryComboBox->currentText());
currentDir = QDir(path);
updateComboBox(fileComboBox);
updateComboBox(textComboBox);
updateComboBox(directoryComboBox);
QStringList filter;
if (!fileName.isEmpty())
filter << fileName;
QDirIterator it(path, filter, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
QStringList files;
while (it.hasNext())
files << it.next();
if (!text.isEmpty())
files = findFiles(files, text);
files.sort();
showFiles(files);
}
每当用户通过按下 Find
按钮请求新搜索时,都会调用 find()
槽函数。首先,我们通过将表格小部件的行数设置为零来消除任何先前的搜索结果。 然后我们从相应的组合框中检索指定的文件名、文本和目录路径。
static void updateComboBox(QComboBox *comboBox)
{
if (comboBox->findText(comboBox->currentText()) == -1)
comboBox->addItem(comboBox->currentText());
}
我们使用目录的路径来创建一个QDir
; QDir
类提供对目录结构及其内容的访问。我们使用 QDirIterator
遍历与指定文件名匹配的文件并构建路径的 QStringList
。然后我们搜索列表中的所有文件,使用私有 findFiles()
函数,删除不包含指定文本的文件。 我们对它们进行排序(因为 QDirIterator
没有)。最后,我们使用私有的 showFiles()
函数显示结果。如果用户没有指定任何文本,则没有理由搜索文件,因此我们立即排序并显示结果。
私有函数findFiles()
QStringList Window::findFiles(const QStringList &files, const QString &text)
{
QProgressDialog progressDialog(this);
progressDialog.setCancelButtonText(tr("&Cancel"));
progressDialog.setRange(0, files.size());
progressDialog.setWindowTitle(tr("Find Files"));
QMimeDatabase mimeDatabase;
QStringList foundFiles;
for (int i = 0; i < files.size(); ++i) {
progressDialog.setValue(i);
progressDialog.setLabelText(tr("Searching file number %1 of %n...", nullptr, files.size()).arg(i));
QCoreApplication::processEvents();
if (progressDialog.wasCanceled())
break;
const QString fileName = files.at(i);
const QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileName);
if (mimeType.isValid() && !mimeType.inherits(QStringLiteral("text/plain"))) {
qWarning() << "Not searching binary file " << QDir::toNativeSeparators(fileName);
continue;
}
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
QString line;
QTextStream in(&file);
while (!in.atEnd()) {
if (progressDialog.wasCanceled())
break;
line = in.readLine();
if (line.contains(text, Qt::CaseInsensitive)) {
foundFiles << files[i];
break;
}
}
}
}
return foundFiles;
}
在私有 findFiles()
函数中,我们搜索文件列表,查找包含指定文本的文件。 这可能是一个非常缓慢的操作,具体取决于文件的数量及其大小。 如果应用程序必须搜索大量文件,或者某些文件的大小很大,QProgressDialog
会显示一个进度对话框。 QProgressDialog
还可以允许用户在花费太多时间时中止操作。
我们遍历文件,一次一个,并且为每个文件更新 QProgressDialog
值。 该属性保存当前取得的进展量。 我们还更新了进度对话框的标签。然后我们使用 QApplication
对象调用 QCoreApplication::processEvents()
函数。 通过这种方式,我们将显示的进度与搜索文件的过程交错显示,因此应用程序似乎不会被冻结。
QApplication
类管理 GUI 应用程序的控制流和主要设置。 它包含主事件循环,来自窗口系统和其他来源的所有事件都在其中处理和分派。 QApplication
继承 QCoreApplication
。 QCoreApplication::processEvents()
函数根据指定的 QEventLoop::ProcessEventFlags
处理所有挂起的事件,直到没有更多的事件需要处理。 默认标志是 QEventLoop::AllEvents
。
更新 QProgressDialog
后,我们以只读模式打开文件,并使用 QTextStream
一次读取一行。QTextStream
类为读写文本提供了一个方便的接口。 使用 QTextStream
的流式操作符,您可以方便地读写单词、行和数字。
对于我们阅读的每一行,我们检查 QProgressDialog
是否已被取消。 如果有,我们中止操作,否则我们检查该行是否包含指定的文本。 当我们在其中一个文件中找到文本时,我们将文件名添加到包含指定文本的已找到文件列表中,然后开始搜索新文件。最后,我们返回找到的文件列表。
私有函数showFiles()
void Window::showFiles(const QStringList &paths)
{
for (const QString &filePath : paths) {
const QString toolTip = QDir::toNativeSeparators(filePath);
const QString relativePath = QDir::toNativeSeparators(currentDir.relativeFilePath(filePath));
const qint64 size = QFileInfo(filePath).size();
QTableWidgetItem *fileNameItem = new QTableWidgetItem(relativePath);
fileNameItem->setData(absoluteFileNameRole, QVariant(filePath));
fileNameItem->setToolTip(toolTip);
fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable);
QTableWidgetItem *sizeItem = new QTableWidgetItem(QLocale().formattedDataSize(size));
sizeItem->setData(absoluteFileNameRole, QVariant(filePath));
sizeItem->setToolTip(toolTip);
sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable);
int row = filesTable->rowCount();
filesTable->insertRow(row);
filesTable->setItem(row, 0, fileNameItem);
filesTable->setItem(row, 1, sizeItem);
}
filesFoundLabel->setText(tr("%n file(s) found (Double click on a file to open it)", nullptr, paths.size()));
filesFoundLabel->setWordWrap(true);
}
findFiles()
和 showFiles()
函数都是从 find()
槽函数调用的。 在 showFiles()
函数中,我们遍历提供的文件名列表,将每个相对文件名添加到表格小部件的第一列,并使用 QFileInfo
检索第二列的文件大小。 我们使用 QLocale::formattedDataSize()
以人类可读的形式格式化文件大小。 为了以后使用,我们使用定义为 Qt::UserRole + 1
的角色 absoluteFileNameRole
将绝对路径设置为 QTableWidget
上的数据。
enum {
absoluteFileNameRole = Qt::UserRole + 1 };
这允许使用便捷函数检索项目的名称:
static inline QString fileNameOfItem(const QTableWidgetItem *item)
{
return item->data(absoluteFileNameRole).toString();
}
我们还会更新找到的文件总数。
私有 createComboBox()
函数
QComboBox *Window::createComboBox(const QString &text)
{
QComboBox *comboBox = new QComboBox;
comboBox->setEditable(true);
comboBox->addItem(text);
comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
return comboBox;
}
私有 createComboBox()
函数也从构造函数中调用。 我们使用给定的文本创建一个 QComboBox
,并使其可编辑。当用户在可编辑的组合框中输入新字符串时,小部件可能插入也可能不插入,它可以将其插入多个位置,具体取决QComboBox::InsertPolicy
。 默认策略是 QComboBox::InsertAtBottom
。
然后我们将提供的文本添加到组合框,并指定小部件的大小策略,然后返回指向组合框的指针。
私有 createFilesTable()
函数
void Window::createFilesTable()
{
filesTable = new QTableWidget(0, 2);
filesTable->setSelectionBehavior(QAbstractItemView::SelectRows);
QStringList labels;
labels << tr("Filename") << tr("Size");
filesTable->setHorizontalHeaderLabels(labels);
filesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
filesTable->verticalHeader()->hide();
filesTable->setShowGrid(false);
filesTable->setContextMenuPolicy(Qt::CustomContextMenu);
connect(filesTable, &QTableWidget::customContextMenuRequested,
this, &Window::contextMenu);
connect(filesTable, &QTableWidget::cellActivated,
this, &Window::openFileOfItem);
}
从构造函数调用私有 createFilesTable()
函数。 在这个函数中,我们创建了将显示搜索结果的 QTableWidget
。 我们设置了它的水平标题和它们的调整大小模式。
QTableWidget
继承了 QTableView
,它提供了表格视图的默认模型/视图实现。 QTableView::horizontalHeader()
函数将表格视图的水平标题作为 QHeaderView
返回。 QHeaderView
类为项目视图提供了标题行或标题列,QHeaderView::setResizeMode()
函数设置了如何调整标题中的节大小的约束。
最后,我们使用 QWidget::hide()
函数隐藏 QTableWidget
的垂直标题,并使用 QTableView::setShowGrid()
函数删除为表格绘制的默认网格。
槽函数openFileOfItem()
void Window::openFileOfItem(int row, int /* column */)
{
const QTableWidgetItem *item = filesTable->item(row, 0);
openFile(fileNameOfItem(item));
}
当用户双击表格中的单元格时,将调用 openFileOfItem()
槽。 QDesktopServices::openUrl()
知道如何打开给定文件名的文件。
槽函数 contextMenu()
void Window::contextMenu(const QPoint &pos)
{
const QTableWidgetItem *item = filesTable->itemAt(pos);
if (!item)
return;
QMenu menu;
#ifndef QT_NO_CLIPBOARD
QAction *copyAction = menu.addAction("Copy Name");
#endif
QAction *openAction = menu.addAction("Open");
QAction *action = menu.exec(filesTable->mapToGlobal(pos));
if (!action)
return;
const QString fileName = fileNameOfItem(item);
if (action == openAction)
openFile(fileName);
#ifndef QT_NO_CLIPBOARD
else if (action == copyAction)
QGuiApplication::clipboard()->setText(QDir::toNativeSeparators(fileName));
#endif
}
我们将表视图的上下文菜单策略设置为 Qt::CustomContextMenu
并将槽函数 contextMenu()
连接到其信号 customContextMenuRequested()
。 我们从 QTableWidgetItem
的数据中检索绝对文件名,并使用提供复制文件名和打开文件的操作填充上下文菜单。
完整程序
main.cpp
#include "window.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QDir>
class QComboBox;
class QLabel;
class QPushButton;
class QTableWidget;
class QTableWidgetItem;
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = nullptr);
~Window();
private slots:
void browse();
void find();
void animateFindClick();
void openFileOfItem(int row, int column);
void contextMenu(const QPoint &pos);
private:
QStringList findFiles(const QStringList &files, const QString &text);
void showFiles(const QStringList &paths);
QComboBox *createComboBox(const QString &text = QString());
void createFilesTable();
QComboBox *fileComboBox;
QComboBox *textComboBox;
QComboBox *directoryComboBox;
QLabel *filesFoundLabel;
QPushButton *findButton;
QTableWidget *filesTable;
QDir currentDir;
};
#endif
window.cpp
#include <QtWidgets>
#include "window.h"
enum {
absoluteFileNameRole = Qt::UserRole + 1 };
static inline QString fileNameOfItem(const QTableWidgetItem *item)
{
return item->data(absoluteFileNameRole).toString();
}
static inline void openFile(const QString &fileName)
{
QDesktopServices::openUrl(QUrl::fromLocalFile(fileName));
}
Window::Window(QWidget *parent)
: QWidget(parent)
{
setWindowTitle(tr("Find Files"));
// 创建浏览按钮与搜寻按钮
QPushButton *browseButton = new QPushButton(tr("&Browse..."), this);
connect(browseButton, &QAbstractButton::clicked, this, &Window::browse);
findButton = new QPushButton(tr("&Find"), this);
connect(findButton, &QAbstractButton::clicked, this, &Window::find);
// 创建三个下拉框:文件下拉框、文本下拉框、目录下拉框
fileComboBox = createComboBox(tr("*"));
connect(fileComboBox->lineEdit(), &QLineEdit::returnPressed,
this, &Window::animateFindClick);
textComboBox = createComboBox();
connect(textComboBox->lineEdit(), &QLineEdit::returnPressed,
this, &Window::animateFindClick);
directoryComboBox = createComboBox(QDir::toNativeSeparators(QDir::currentPath()));
connect(directoryComboBox->lineEdit(), &QLineEdit::returnPressed,
this, &Window::animateFindClick);
filesFoundLabel = new QLabel;
createFilesTable();
// 添加垂直布局
QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(new QLabel(tr("Named:")), 0, 0);
mainLayout->addWidget(fileComboBox, 0, 1, 1, 2);
mainLayout->addWidget(new QLabel(tr("Containing text:")), 1, 0);
mainLayout->addWidget(textComboBox, 1, 1, 1, 2);
mainLayout->addWidget(new QLabel(tr("In directory:")), 2, 0);
mainLayout->addWidget(directoryComboBox, 2, 1);
mainLayout->addWidget(browseButton, 2, 2);
mainLayout->addWidget(filesTable, 3, 0, 1, 3);
mainLayout->addWidget(filesFoundLabel, 4, 0, 1, 2);
mainLayout->addWidget(findButton, 4, 2);
connect(new QShortcut(QKeySequence::Quit, this), &QShortcut::activated, qApp, &QApplication::quit);
}
Window::~Window()
{
}
void Window::browse()
{
QString directory =
QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Find Files"), QDir::currentPath()));
if (!directory.isEmpty()) {
if (directoryComboBox->findText(directory) == -1)
directoryComboBox->addItem(directory);
directoryComboBox->setCurrentIndex(directoryComboBox->findText(directory));
}
}
static void updateComboBox(QComboBox *comboBox)
{
if (comboBox->findText(comboBox->currentText()) == -1)
comboBox->addItem(comboBox->currentText());
}
void Window::find()
{
filesTable->setRowCount(0);
QString fileName = fileComboBox->currentText();
QString text = textComboBox->currentText();
QString path = QDir::cleanPath(directoryComboBox->currentText());
currentDir = QDir(path);
updateComboBox(fileComboBox);
updateComboBox(textComboBox);
updateComboBox(directoryComboBox);
QStringList filter;
if (!fileName.isEmpty())
filter << fileName;
QDirIterator it(path, filter, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
QStringList files;
while (it.hasNext())
files << it.next();
if (!text.isEmpty())
files = findFiles(files, text);
files.sort();
showFiles(files);
}
void Window::animateFindClick()
{
findButton->animateClick();
}
QStringList Window::findFiles(const QStringList &files, const QString &text)
{
QProgressDialog progressDialog(this);
progressDialog.setCancelButtonText(tr("&Cancel"));
progressDialog.setRange(0, files.size());
progressDialog.setWindowTitle(tr("Find Files"));
QMimeDatabase mimeDatabase;
QStringList foundFiles;
for (int i = 0; i < files.size(); ++i) {
progressDialog.setValue(i);
progressDialog.setLabelText(tr("Searching file number %1 of %n...", nullptr, files.size()).arg(i));
QCoreApplication::processEvents();
if (progressDialog.wasCanceled())
break;
const QString fileName = files.at(i);
const QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileName);
if (mimeType.isValid() && !mimeType.inherits(QStringLiteral("text/plain"))) {
qWarning() << "Not searching binary file " << QDir::toNativeSeparators(fileName);
continue;
}
QFile file(fileName);
if (file.open(QIODevice::ReadOnly)) {
QString line;
QTextStream in(&file);
while (!in.atEnd()) {
if (progressDialog.wasCanceled())
break;
line = in.readLine();
if (line.contains(text, Qt::CaseInsensitive)) {
foundFiles << files[i];
break;
}
}
}
}
return foundFiles;
}
void Window::showFiles(const QStringList &paths)
{
for (const QString &filePath : paths) {
const QString toolTip = QDir::toNativeSeparators(filePath);
const QString relativePath = QDir::toNativeSeparators(currentDir.relativeFilePath(filePath));
const qint64 size = QFileInfo(filePath).size();
QTableWidgetItem *fileNameItem = new QTableWidgetItem(relativePath);
fileNameItem->setData(absoluteFileNameRole, QVariant(filePath));
fileNameItem->setToolTip(toolTip);
fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable);
QTableWidgetItem *sizeItem = new QTableWidgetItem(QLocale().formattedDataSize(size));
sizeItem->setData(absoluteFileNameRole, QVariant(filePath));
sizeItem->setToolTip(toolTip);
sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable);
int row = filesTable->rowCount();
filesTable->insertRow(row);
filesTable->setItem(row, 0, fileNameItem);
filesTable->setItem(row, 1, sizeItem);
}
filesFoundLabel->setText(tr("%n file(s) found (Double click on a file to open it)", nullptr, paths.size()));
filesFoundLabel->setWordWrap(true);
}
QComboBox *Window::createComboBox(const QString &text)
{
QComboBox *comboBox = new QComboBox;
comboBox->setEditable(true);
comboBox->addItem(text);
comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
return comboBox;
}
void Window::createFilesTable()
{
filesTable = new QTableWidget(0, 2);
filesTable->setSelectionBehavior(QAbstractItemView::SelectRows);
QStringList labels;
labels << tr("Filename") << tr("Size");
filesTable->setHorizontalHeaderLabels(labels);
filesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
filesTable->verticalHeader()->hide();
filesTable->setShowGrid(false);
filesTable->setContextMenuPolicy(Qt::CustomContextMenu);
connect(filesTable, &QTableWidget::customContextMenuRequested,
this, &Window::contextMenu);
connect(filesTable, &QTableWidget::cellActivated,
this, &Window::openFileOfItem);
}
void Window::openFileOfItem(int row, int /* column */)
{
const QTableWidgetItem *item = filesTable->item(row, 0);
openFile(fileNameOfItem(item));
}
void Window::contextMenu(const QPoint &pos)
{
const QTableWidgetItem *item = filesTable->itemAt(pos);
if (!item)
return;
QMenu menu;
#ifndef QT_NO_CLIPBOARD
QAction *copyAction = menu.addAction("Copy Name");
#endif
QAction *openAction = menu.addAction("Open");
QAction *action = menu.exec(filesTable->mapToGlobal(pos));
if (!action)
return;
const QString fileName = fileNameOfItem(item);
if (action == openAction)
openFile(fileName);
#ifndef QT_NO_CLIPBOARD
else if (action == copyAction)
QGuiApplication::clipboard()->setText(QDir::toNativeSeparators(fileName));
#endif
}
界面展示