204 lines
7.3 KiB
C++
204 lines
7.3 KiB
C++
#include "ImageGridWidget.h"
|
|
#include "ImageTileWidget.h"
|
|
#include <QGridLayout>
|
|
#include <QtMath>
|
|
#include <QTimer>
|
|
#include <QResizeEvent>
|
|
|
|
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);
|
|
}
|
|
|
|
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::initImages(int count) {
|
|
m_paths.clear();
|
|
m_selectedIndex = -1; // 默认无选中,所有格子等大
|
|
m_expandedIndex = -1; // 默认无展开
|
|
|
|
// 清空现有布局
|
|
QLayoutItem* child;
|
|
while ((child = m_layout->takeAt(0)) != nullptr) {
|
|
if (child->widget()) child->widget()->deleteLater();
|
|
delete child;
|
|
}
|
|
m_tiles.clear();
|
|
|
|
// 初始化指定数量的格子
|
|
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::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;
|
|
|
|
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() {
|
|
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();
|
|
}
|
|
}
|