282 lines
10 KiB
C++
Raw Normal View History

#include "ImageGridWidget.h"
#include "ImageTileWidget.h"
#include <QGridLayout>
#include <QtMath>
#include <QTimer>
#include <QResizeEvent>
2025-08-31 21:08:28 +08:00
#include <QLabel>
ImageGridWidget::ImageGridWidget(QWidget* parent)
: QWidget(parent) {
m_layout = new QGridLayout(this);
m_layout->setContentsMargins(0, 0, 0, 0);
m_layout->setHorizontalSpacing(4); // 左右保留间距
m_layout->setVerticalSpacing(0); // 上下无间距
setLayout(m_layout);
// 设置控件大小策略为可扩展
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
2025-08-31 21:08:28 +08:00
// 添加一个默认标签,当没有图像时显示
m_noImageLabel = new QLabel("暂无图像数据", this);
m_noImageLabel->setAlignment(Qt::AlignCenter);
m_noImageLabel->setStyleSheet("color: gray; font-size: 18px;");
m_noImageLabel->hide();
}
void ImageGridWidget::setImages(int index, const QImage& image) {
if (index < 0 || index >= m_tiles.size()) return;
// 直接调用ImageTileWidget的setImage方法
m_tiles[index]->setImage(image);
}
2025-08-31 21:08:28 +08:00
// 通过别名设置图像
void ImageGridWidget::setImages(const QString& alias, const QImage& image) {
if (m_aliasMap.contains(alias)) {
int index = m_aliasMap[alias];
setImages(index, image);
}
}
void ImageGridWidget::initImages(int count) {
m_paths.clear();
m_selectedIndex = -1; // 默认无选中,所有格子等大
m_expandedIndex = -1; // 默认无展开
2025-08-31 21:08:28 +08:00
m_aliasMap.clear(); // 清空别名映射
// 清空现有布局
QLayoutItem* child;
while ((child = m_layout->takeAt(0)) != nullptr) {
2025-08-31 21:08:28 +08:00
if (child->widget()) {
child->widget()->deleteLater();
}
delete child;
}
m_tiles.clear();
2025-08-31 21:08:28 +08:00
// 如果count为0显示提示信息
if (count <= 0) {
m_layout->addWidget(m_noImageLabel, 0, 0, Qt::AlignCenter);
m_noImageLabel->show();
return;
}
m_noImageLabel->hide();
// 初始化指定数量的格子改为竖向布局最多2行
m_rows = qMax(1, qMin(2, count));
m_columns = (count + m_rows - 1) / m_rows;
for (int i = 0; i < count; ++i) {
ImageTileWidget* tile = new ImageTileWidget(this);
// 列优先布局:先填满一列再填下一列
int c = i / m_rows;
int r = i % m_rows;
// 奇数排(行号为偶数)图片靠下显示,偶数排(行号为奇数)图片靠上显示
Qt::Alignment imageAlign = (r % 2 == 0) ? Qt::AlignBottom : Qt::AlignTop;
tile->setImageAlignment(imageAlign);
// 设置固定尺寸
tile->setFixedSize(m_sizeNormal);
tile->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
// 控件在网格中居中显示
m_layout->addWidget(tile, r, c, Qt::AlignCenter);
m_tiles.append(tile);
connect(tile, &ImageTileWidget::clicked, this, [this, i]() {
if (m_expandedIndex == i) {
// 如果点击的是已展开的格子,不触发选中,只触发点击事件
emit tileClicked(i);
} else if (m_expandedIndex == -1) {
// 如果没有展开的格子,设置选中并展开
setExpandedIndex(i);
emit tileClicked(i);
}
});
connect(tile, &ImageTileWidget::shrinkRequested, this, [this, i]() {
if (m_expandedIndex == i) {
setExpandedIndex(-1);
}
});
}
updateTileSizes();
}
2025-08-31 21:08:28 +08:00
// 设置别名
void ImageGridWidget::setTileAlias(int index, const QString& alias) {
if (index < 0 || index >= m_tiles.size()) return;
// 设置tile的别名
m_tiles[index]->setAlias(alias);
// 更新别名到索引的映射
m_aliasMap[alias] = index;
}
void ImageGridWidget::setSelectedIndex(int index) {
if (index < -1 || index >= m_tiles.size()) return;
m_selectedIndex = index;
updateTileSizes();
}
void ImageGridWidget::setExpandedIndex(int index) {
if (index < -1 || index >= m_tiles.size()) return;
m_expandedIndex = index;
updateTileSizes();
}
void ImageGridWidget::rebuildGrid() {
// Clear existing
QLayoutItem* child;
while ((child = m_layout->takeAt(0)) != nullptr) {
if (child->widget()) child->widget()->deleteLater();
delete child;
}
m_tiles.clear();
// Determine grid size: up to 2 rows (vertical layout)
int n = m_paths.size();
m_rows = qMax(1, qMin(2, n));
m_columns = (n + m_rows - 1) / m_rows;
2025-08-31 21:08:28 +08:00
// 如果没有路径,显示提示信息
if (n <= 0) {
m_layout->addWidget(m_noImageLabel, 0, 0, Qt::AlignCenter);
m_noImageLabel->show();
return;
}
2025-08-31 21:08:28 +08:00
m_noImageLabel->hide();
for (int i = 0; i < n; ++i) {
ImageTileWidget* tile = new ImageTileWidget(this);
tile->setImagePath(m_paths.at(i));
tile->setSelected(i == m_selectedIndex);
tile->setExpanded(i == m_expandedIndex);
// 列优先布局:先填满一列再填下一列
int c = i / m_rows;
int r = i % m_rows;
// 奇数排(行号为偶数)图片靠下显示,偶数排(行号为奇数)图片靠上显示
Qt::Alignment imageAlign = (r % 2 == 0) ? Qt::AlignBottom : Qt::AlignTop;
tile->setImageAlignment(imageAlign);
// 设置固定尺寸,确保控件大小一致
tile->setFixedSize(m_sizeNormal);
tile->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
// 控件在网格中居中显示
m_layout->addWidget(tile, r, c, Qt::AlignCenter);
m_tiles.append(tile);
connect(tile, &ImageTileWidget::clicked, this, [this, i]() {
if (m_expandedIndex == i) {
// 如果点击的是已展开的格子,不触发选中,只触发点击事件
emit tileClicked(i);
} else if (m_expandedIndex == -1) {
// 如果没有展开的格子,设置选中并展开
setExpandedIndex(i);
emit tileClicked(i);
}
});
connect(tile, &ImageTileWidget::shrinkRequested, this, [this, i]() {
if (m_expandedIndex == i) {
setExpandedIndex(-1);
}
});
}
updateTileSizes();
}
void ImageGridWidget::resizeEvent(QResizeEvent* event) {
QWidget::resizeEvent(event);
// 防止递归调用,只在尺寸真正变化时更新
static QSize lastSize;
if (lastSize != event->size()) {
lastSize = event->size();
updateTileSizes();
}
}
void ImageGridWidget::updateTileSizes() {
2025-08-31 21:08:28 +08:00
// 如果没有瓦片,直接返回
if (m_tiles.isEmpty()) {
return;
}
const bool anyExpanded = (m_expandedIndex >= 0 && m_expandedIndex < m_tiles.size());
const bool anySelected = (m_selectedIndex >= 0 && m_selectedIndex < m_tiles.size());
// 计算可用空间(减去边距和间距)
int availableWidth = width() - m_layout->contentsMargins().left() - m_layout->contentsMargins().right();
int availableHeight = height() - m_layout->contentsMargins().top() - m_layout->contentsMargins().bottom();
// 计算每个格子的基础尺寸(根据窗口大小动态调整)
// 确保减去的间距不会导致负数
int horizontalSpacingTotal = m_layout->horizontalSpacing() * (m_columns - 1);
int verticalSpacingTotal = m_layout->verticalSpacing() * (m_rows - 1);
// 对于竖向布局优先保证高度分配合理因为最多只有2行
int baseTileWidth = qMax(100, (availableWidth - horizontalSpacingTotal) / m_columns);
int baseTileHeight = qMax(100, (availableHeight - verticalSpacingTotal) / m_rows);
// 根据窗口大小动态调整尺寸
m_sizeNormal = QSize(baseTileWidth, baseTileHeight);
m_sizeExpanded = QSize(availableWidth, availableHeight);
for (int i = 0; i < m_tiles.size(); ++i) {
ImageTileWidget* t = m_tiles[i];
bool expanded = anyExpanded && (i == m_expandedIndex);
bool sel = anySelected && (i == m_selectedIndex);
t->setSelected(sel);
t->setExpanded(expanded);
if (expanded) {
// 展开的格子占据整个九宫格空间并支持缩放
t->setMinimumSize(100, 100); // 设置最小尺寸
t->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); // 允许最大尺寸
t->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// 重新布局,让展开的格子占据整个九宫格空间
m_layout->removeWidget(t);
m_layout->addWidget(t, 0, 0, m_rows, m_columns);
t->raise(); // 确保展开的格子在最前面
// 强制更新布局,确保展开的瓦片正确缩放
m_layout->invalidate();
updateGeometry();
} else {
// 恢复正常布局
m_layout->removeWidget(t);
// 列优先布局:先填满一列再填下一列
int c = i / m_rows;
int r = i % m_rows;
// 奇数排(行号为偶数)图片靠下显示,偶数排(行号为奇数)图片靠上显示
Qt::Alignment imageAlign = (r % 2 == 0) ? Qt::AlignBottom : Qt::AlignTop;
t->setImageAlignment(imageAlign);
2025-11-26 22:44:38 +08:00
// 控件在网格中居中显示
m_layout->addWidget(t, r, c, Qt::AlignCenter);
// 设置固定尺寸
t->setFixedSize(m_sizeNormal);
t->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}
}
// 显示所有格子,让它们都能随窗口放大
for (int i = 0; i < m_tiles.size(); ++i) {
m_tiles[i]->show();
}
2025-08-31 21:08:28 +08:00
}