#include "ImageGridWidget.h" #include "ImageTileWidget.h" #include #include #include #include #include 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(); } }