qtableview和qlistview使用的一些经验(2)

418 阅读2分钟

示例

demo.gif

功能

功能是参照本地资源管理器

  • 按键盘字母,自动选中文件名开头对应的字母
  • 列表视图和图标视图按住ctrl滚轮切换
  • 排序
  • 重命名
  • shift多选
  • ctrl单选反选

功能具体实现

重命名(列表视图)

因为列表视图是横向单行,所以用了QLineEdit控件
创建控件和填充数据均是在delegate中完成

// 显示控件
openPersistentEditor(QModelIndex)
// 隐藏控件
closePersistentEditor(QModelIndex)
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	if (index.column() == 1) {
		const auto container = new QWidget(parent);
		const auto lineEdit = new RenameLineEdit(container);
		return container;
	}
	return QStyledItemDelegate::createEditor(parent, option, index);
}

void setEditorData(QWidget* editor, const QModelIndex& index) const
{
	if (!editor) {
                return;
	}
	QList<RenameLineEdit*> list = editor->findChildren<RenameLineEdit*>();
	if (list.isEmpty()) {
		return;
	}
        // 因为qlineedit控件创建的时候只有一个,所以固定取第一个
	const auto lineEdit = list[0];
	if (!lineEdit) {
		return;
	}
        // 获取数据
	const auto data = index.data(Qt::UserRole).value<QString>();
	lineEdit->setFocus();
	lineEdit->SetText(data);
        // 选中文件名前缀部分,文件格式不选中
	int selectionIndex = data.length() - 1;
	const auto suffix = QFileInfo(data).suffix();
	if (!suffix.isEmpty()) {
		selectionIndex = data.length() - suffix.length() - 1;
	}
	lineEdit->setSelection(0, selectionIndex);
}

重命名(图标视图)

因为图标视图的重命名框需要显示多行,内容比较多,所以使用了QTextEdit

// 显示控件
openPersistentEditor(QModelIndex)
// 隐藏控件
closePersistentEditor(QModelIndex)
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	const auto container = new QWidget(parent);
	const auto textEdit = new RenameTextEdit(container);
	textEdit->setAlignment(Qt::AlignCenter);
	return container;
}

void setEditorData(QWidget* editor, const QModelIndex& index) const
{
	if (!editor) {
		return;
	}
	const auto textEdit = editor->findChildren<RenameTextEdit*>()[0];
	if (!textEdit) {
		return;
	}
	const auto data = index.data(Qt::UserRole).value<QString>();
	textEdit->setFocus();
	textEdit->SetText(data);
	int selectionIndex = data.length() - 1;
	const QString suffix = QFileInfo(data).suffix();
	if (!suffix.isEmpty()) {
		selectionIndex = data.length() - suffix.length() - 1;
	}
        // QTextEdit是使用游标的方式来操作选中的,这个和QLineEdit完全不一样
	auto cursor = textEdit->textCursor();
	cursor.setPosition(0, QTextCursor::MoveAnchor);
	cursor.setPosition(selectionIndex, QTextCursor::KeepAnchor);
	textEdit->setTextCursor(cursor);
}

单选,多选,取消选中

// 单选(通过多选的逻辑实现的单选)
void selectRow(int row)
{
	if (row == -1) {
		return;
	}
	QItemSelectionModel* model = selectionModel();
	if (!model || !model_) {
		return;
	}
	QItemSelection selection;
	selection.merge({ model_->index(row, 0) , model_->index(row, 7) }, QItemSelectionModel::Select);
	model->select(selection, QItemSelectionModel::Select);
}

// 多选
void selectMulRows(int startRow, int endRow)
{
	const auto model = selectionModel();
	if (!model || !model_) {
		return;
	}
	QItemSelection selection;
	int begin = startRow;
	int end = endRow;
	if (startRow > endRow) {
		begin = endRow;
		end = startRow;
	}
	QList<int> selectRows;
	for(int i = begin; i < end + 1; i++) {
		selection.merge({ model_->index(i, 0) , model_->index(i, 7) }, QItemSelectionModel::Select);
		selectRows << i;
	}
	model->select(selection, QItemSelectionModel::Select);
}

// 取消选中
void unSelectRow(int row)
{
	if (row == -1) {
		return;
	}
	const auto model = selectionModel();
	if (!model || !model_) {
		return;
	}
	model->select({ model_->index(row, 0) , model_->index(row, 7) }, QItemSelectionModel::Deselect);
}

图标视图文字绘制

图标视图绘制图标下方文件名,文件名过长的时候,需要进行换行,这里有个注意点

// 需要使用TextWrapAnywhere
painter->drawText(rect, Qt::AlignHCenter | Qt::TextWrapAnywhere, name);
// 不能使用TextWordWrap,因为这个是遇到换行符才会进行换行
painter->drawText(rect, Qt::AlignHCenter | Qt::TextWordWrap, name);

图标视图显示缩略图

// 加载本地图片
QImage image;
image.load("xxxx");
// 读取svg格式的图片
QIcon icon;
icon.addFile("xxxx");
// 实际情况下,并不是所有的png都能通过QImage读取成功,具体原因不知道,QImage和QImageReader都会直接返回错误,这个时候,使用gdiplus来读取文件
IStream* stream;
SHCreateStreamOnFileEx(path.toStdWString().c_str(), STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &stream);
if (stream) {
	const auto bitmap(Gdiplus::Bitmap::FromStream(stream));
	stream->Release();
	HICON icon;
	bitmap->GetHICON(&icon);
	const auto pixmap = QtWin::fromHICON(icon);
	if (pixmap.isNull()) {
		return false;
	}
	return true;
}