255 lines
8.7 KiB
C++
255 lines
8.7 KiB
C++
#include "ImageGridWidget.h"
|
||
#include "ImageTileWidget.h"
|
||
#include <QGridLayout>
|
||
#include <QtMath>
|
||
#include <QTimer>
|
||
#include <QResizeEvent>
|
||
#include <QLabel>
|
||
|
||
ImageGridWidget::ImageGridWidget(QWidget* parent)
|
||
: QWidget(parent) {
|
||
m_layout = new QGridLayout(this);
|
||
m_layout->setContentsMargins(0, 0, 0, 0);
|
||
m_layout->setHorizontalSpacing(0);
|
||
m_layout->setVerticalSpacing(0);
|
||
setLayout(m_layout);
|
||
|
||
// 设置控件大小策略为可扩展
|
||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||
|
||
// 添加一个默认标签,当没有图像时显示
|
||
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);
|
||
}
|
||
|
||
// 通过别名设置图像
|
||
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; // 默认无展开
|
||
m_aliasMap.clear(); // 清空别名映射
|
||
|
||
// 清空现有布局
|
||
QLayoutItem* child;
|
||
while ((child = m_layout->takeAt(0)) != nullptr) {
|
||
if (child->widget()) {
|
||
child->widget()->deleteLater();
|
||
}
|
||
delete child;
|
||
}
|
||
m_tiles.clear();
|
||
|
||
// 如果count为0,显示提示信息
|
||
if (count <= 0) {
|
||
m_layout->addWidget(m_noImageLabel, 0, 0, Qt::AlignCenter);
|
||
m_noImageLabel->show();
|
||
return;
|
||
}
|
||
|
||
m_noImageLabel->hide();
|
||
|
||
// 初始化指定数量的格子
|
||
m_columns = qMax(1, qMin(2, count));
|
||
m_rows = (count + m_columns - 1) / m_columns;
|
||
|
||
for (int i = 0; i < count; ++i) {
|
||
ImageTileWidget* tile = new ImageTileWidget(this);
|
||
int r = i / m_columns;
|
||
int c = i % m_columns;
|
||
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::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 columns
|
||
int n = m_paths.size();
|
||
m_columns = qMax(1, qMin(2, n));
|
||
m_rows = (n + m_columns - 1) / m_columns;
|
||
|
||
// 如果没有路径,显示提示信息
|
||
if (n <= 0) {
|
||
m_layout->addWidget(m_noImageLabel, 0, 0, Qt::AlignCenter);
|
||
m_noImageLabel->show();
|
||
return;
|
||
}
|
||
|
||
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 r = i / m_columns;
|
||
int c = i % m_columns;
|
||
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() {
|
||
// 如果没有瓦片,直接返回
|
||
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);
|
||
|
||
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 r = i / m_columns;
|
||
int c = i % m_columns;
|
||
m_layout->addWidget(t, r, c, Qt::AlignCenter);
|
||
|
||
// 所有格子都使用正常尺寸,不因选中而放大
|
||
t->setFixedSize(m_sizeNormal);
|
||
|
||
// 所有格子都设置为可扩展,以便随窗口大小变化
|
||
t->setMinimumSize(100, 100);
|
||
t->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
||
t->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||
}
|
||
}
|
||
|
||
// 显示所有格子,让它们都能随窗口放大
|
||
for (int i = 0; i < m_tiles.size(); ++i) {
|
||
m_tiles[i]->show();
|
||
}
|
||
} |