T-573 修复封面画廊候选图宽度

This commit is contained in:
chengma
2026-07-09 15:51:48 +08:00
parent 065ad349de
commit c3c79b63d4
3 changed files with 109 additions and 12 deletions
+45 -10
View File
@@ -2,7 +2,7 @@
from __future__ import annotations
from PySide6.QtCore import QEvent
from PySide6.QtCore import QEvent, QSize
from ..models import GenerateTaskTableModel
from ..widgets import *
@@ -188,13 +188,14 @@ class CoverGalleryDialog(QDialog):
self.status_label.setWordWrap(True)
layout.addWidget(self.status_label)
scroll = QScrollArea()
scroll.setObjectName("coverGalleryScrollArea")
scroll.setWidgetResizable(False)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
content = QWidget()
self.candidate_layout = QHBoxLayout(content)
self.candidate_scroll = QScrollArea()
self.candidate_scroll.setObjectName("coverGalleryScrollArea")
self.candidate_scroll.setWidgetResizable(False)
self.candidate_scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.candidate_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.candidate_content = QWidget()
self.candidate_content.setObjectName("coverGalleryCandidateContent")
self.candidate_layout = QHBoxLayout(self.candidate_content)
self.candidate_layout.setContentsMargins(0, 0, 0, 0)
self.candidate_layout.setSpacing(12)
if self.candidates:
@@ -207,8 +208,9 @@ class CoverGalleryDialog(QDialog):
empty_label.setMinimumSize(320, self.THUMBNAIL_SIZE)
empty_label.setAlignment(Qt.AlignCenter)
self.candidate_layout.addWidget(empty_label)
scroll.setWidget(content)
layout.addWidget(scroll, 1)
self._sync_candidate_content_size()
self.candidate_scroll.setWidget(self.candidate_content)
layout.addWidget(self.candidate_scroll, 1)
return panel
def _candidate_item(self, candidate_path, index):
@@ -252,6 +254,38 @@ class CoverGalleryDialog(QDialog):
layout.addStretch(1)
return item
def _sync_candidate_content_size(self):
layout = getattr(self, "candidate_layout", None)
content = getattr(self, "candidate_content", None)
if layout is None or content is None:
return
layout.activate()
margins = layout.contentsMargins()
spacing = max(0, layout.spacing())
hint = layout.sizeHint()
if self.candidates:
candidate_count = len(self.candidates)
min_width = (
margins.left()
+ margins.right()
+ candidate_count * (self.THUMBNAIL_SIZE + 16)
+ max(0, candidate_count - 1) * spacing
)
else:
min_width = margins.left() + margins.right() + 320
min_height = max(
self.THUMBNAIL_SIZE,
hint.height(),
content.minimumHeight(),
)
size = QSize(max(min_width, hint.width()), min_height)
content.setMinimumSize(size)
content.resize(size)
content.updateGeometry()
scroll = getattr(self, "candidate_scroll", None)
if scroll is not None:
scroll.updateGeometry()
def _sync_initial_selection(self):
for candidate_path, radio in self.candidate_buttons.items():
if _same_file(candidate_path, self.current_path):
@@ -560,6 +594,7 @@ class CoverGalleryDialog(QDialog):
empty_label.setMinimumSize(320, self.THUMBNAIL_SIZE)
empty_label.setAlignment(Qt.AlignCenter)
self.candidate_layout.addWidget(empty_label)
self._sync_candidate_content_size()
self._install_navigation_event_filters()
def _on_regenerate_progress(self, payload):
+10 -2
View File
@@ -3,7 +3,7 @@ id: T-573
title: ②封面画廊候选图横向滚动内容宽度修复
phase: 7
deps: [T-567, T-569]
status: TODO
status: DONE
created: 2026-07-09
---
@@ -65,4 +65,12 @@ T-568/T-569 后封面画廊支持切换任务和重新生成,候选图列表
## 执行记录
(做完在这里写:改了什么文件、跑了什么验证命令及结果、关键决策。)
- 2026-07-09:已完成。
- `app/gui/tabs/generate.py`:`CoverGalleryDialog` 保存 `candidate_scroll` / `candidate_content` 引用,新增 `_sync_candidate_content_size()`;候选图初始化和 `_rebuild_candidate_items()` 后按候选数量、item 宽度、spacing 与 layout sizeHint 同步 content 最小尺寸和实际尺寸,保留横向滚动行为。
- `tests/test_gui.py`:新增多候选图内容宽度测试,以及从少候选任务切换到多候选任务后的宽度重新同步测试。
- 验证通过:
- `py -3.10 -m unittest tests.test_gui`
- `python -m ruff check app tests main.py`
- `py -3.10 -m compileall app main.py`
- `py -3.10 -m unittest discover -s tests`
- `git diff --check`
+54
View File
@@ -2277,6 +2277,60 @@ class GuiTests(TempDirMixin, unittest.TestCase):
self.assert_removed(temp_dir)
def test_cover_gallery_candidate_content_width_fits_multiple_candidates(self):
with self.make_temp_dir() as temp_dir:
cfg, account, tasks, canonicals, _archives = self._cover_gallery_task_set(temp_dir, count=1)
prefix = os.path.splitext(canonicals[0])[0]
self.write_test_image(f"{prefix}_20260709101100.jpg")
self.write_test_image(f"{prefix}_20260709101200.jpg")
dialog = CoverGalleryDialog(tasks[0], cfg["image_dir"], cfg["db_path"], account=account)
self.addCleanup(dialog.close)
self.assertGreaterEqual(len(dialog.candidates), 4)
expected_width = (
len(dialog.candidates) * (dialog.THUMBNAIL_SIZE + 16)
+ (len(dialog.candidates) - 1) * dialog.candidate_layout.spacing()
)
self.assertIs(dialog.candidate_scroll.widget(), dialog.candidate_content)
self.assertGreaterEqual(dialog.candidate_content.minimumWidth(), expected_width)
self.assertGreaterEqual(dialog.candidate_content.width(), expected_width)
self.assert_removed(temp_dir)
def test_cover_gallery_switch_task_resyncs_candidate_content_width(self):
with self.make_temp_dir() as temp_dir:
cfg, account, tasks, canonicals, archives = self._cover_gallery_task_set(temp_dir, count=2)
os.remove(archives[0])
prefix = os.path.splitext(canonicals[1])[0]
self.write_test_image(f"{prefix}_20260709101100.jpg")
self.write_test_image(f"{prefix}_20260709101200.jpg")
dialog = CoverGalleryDialog(
tasks[0],
cfg["image_dir"],
cfg["db_path"],
account=account,
visible_tasks=tasks,
task_index=0,
account_by_alias={"alias-a": account},
)
self.addCleanup(dialog.close)
initial_width = dialog.candidate_content.minimumWidth()
self.assertTrue(dialog.switch_task(1))
expected_width = (
len(dialog.candidates) * (dialog.THUMBNAIL_SIZE + 16)
+ (len(dialog.candidates) - 1) * dialog.candidate_layout.spacing()
)
self.assertEqual(tasks[1].id, dialog.task.id)
self.assertGreater(len(dialog.candidates), 2)
self.assertGreater(dialog.candidate_content.minimumWidth(), initial_width)
self.assertGreaterEqual(dialog.candidate_content.minimumWidth(), expected_width)
self.assertGreaterEqual(dialog.candidate_content.width(), expected_width)
self.assert_removed(temp_dir)
def test_cover_gallery_save_switches_current_cover(self):
with self.make_temp_dir() as temp_dir:
cfg = self.make_config(temp_dir)