66import json
77from typing import Dict , Any
88
9- from PySide6 .QtWidgets import QWidget , QVBoxLayout , QGridLayout
9+ from PySide6 .QtWidgets import QWidget , QVBoxLayout
1010from PySide6 .QtGui import QFont
1111from PySide6 .QtCore import (
1212 Signal ,
1717 QThreadPool ,
1818 QObject ,
1919)
20- from qfluentwidgets import SubtitleLabel , BodyLabel , CardWidget
20+ from qfluentwidgets import SubtitleLabel , BodyLabel , CardWidget , FlowLayout
2121from loguru import logger
2222
2323from app .tools .variable import (
@@ -301,10 +301,11 @@ def init_ui(self):
301301 self .count_label .setFont (QFont ("" , 12 ))
302302 self .main_layout .addWidget (self .count_label )
303303
304- # 创建网格布局
305- self .grid_layout = QGridLayout ()
306- self .grid_layout .setSpacing (STUDENT_CARD_SPACING )
307- self .main_layout .addLayout (self .grid_layout )
304+ # 创建流式布局
305+ self .flow_layout = FlowLayout ()
306+ self .flow_layout .setVerticalSpacing (STUDENT_CARD_SPACING )
307+ self .flow_layout .setHorizontalSpacing (STUDENT_CARD_SPACING )
308+ self .main_layout .addLayout (self .flow_layout )
308309
309310 # 初始化卡片列表
310311 self .cards = []
@@ -421,7 +422,7 @@ def update_ui(self):
421422
422423 # 清空现有卡片并准备异步渲染
423424 self .cards = []
424- self ._clear_grid_layout ()
425+ self ._clear_flow_layout ()
425426
426427 # 将待渲染学生放入队列,启动增量渲染
427428 self ._pending_students = list (self .students ) if self .students else []
@@ -431,7 +432,7 @@ def update_ui(self):
431432
432433 def update_layout (self ):
433434 """更新布局"""
434- if not self .grid_layout or not self .cards :
435+ if not self .flow_layout or not self .cards :
435436 return
436437
437438 # 检查是否需要更新布局
@@ -464,27 +465,17 @@ def update_layout(self):
464465 self .setUpdatesEnabled (False )
465466
466467 # 清空现有布局
467- self ._clear_grid_layout ()
468+ self ._clear_flow_layout ()
468469
469- # 计算列数
470- window_width = max (self .width (), self .sizeHint ().width ())
471- columns = self ._calculate_columns (window_width )
472-
473- # 添加卡片到网格布局
474- for i , card in enumerate (self .cards ):
475- row = i // columns
476- col = i % columns
477- self .grid_layout .addWidget (card , row , col )
470+ # 添加卡片到流式布局
471+ for card in self .cards :
472+ self .flow_layout .addWidget (card )
478473 # 仅在控件当前不可见时显示,避免重复触发绘制
479474 if not card .isVisible ():
480475 card .show ()
481476
482- # 设置列的伸缩因子,使卡片均匀分布
483- for col in range (columns ):
484- self .grid_layout .setColumnStretch (col , 1 )
485-
486477 logger .debug (
487- f"布局更新完成: 宽度={ window_width } , 列数= { columns } , 卡片数={ len (self .cards )} "
478+ f"布局更新完成: 宽度={ current_width } , 卡片数={ len (self .cards )} "
488479 )
489480 finally :
490481 # 清除布局更新标志
@@ -515,26 +506,17 @@ def update_layout(self):
515506 "Error calling update() after layout update (ignored): {}" , e
516507 )
517508
518- def _calculate_columns (self , width : int ) -> int :
519- """根据窗口宽度和卡片尺寸动态计算列数"""
509+ def _clear_flow_layout (self ):
510+ """清空流式布局"""
511+ # 使用FlowLayout的removeAllWidgets方法清空布局
512+ self .flow_layout .removeAllWidgets ()
513+ # 清空已记录的已添加卡片集合
520514 try :
521- if width <= 0 :
522- return 1
523-
524- # 计算可用宽度(减去左右边距)
525- available_width = width - 40 # 左右各20px边距
526-
527- # 所有卡片使用相同的尺寸
528- card_actual_width = STUDENT_CARD_FIXED_WIDTH + STUDENT_CARD_SPACING
529- max_cols = max (1 , available_width // card_actual_width )
530-
531- # 至少显示1列,且不超过一个合理上限
532- return max (1 , min (int (max_cols ), 6 ))
515+ self ._cards_set .clear ()
533516 except Exception as e :
534517 from loguru import logger
535518
536- logger .exception ("Error calculating columns (fallback to 1): {}" , e )
537- return 1
519+ logger .exception ("Error clearing cards set (ignored): {}" , e )
538520
539521 def _start_incremental_render (self ):
540522 """使用 QThreadPool 启动后台任务,按批准备数据并通过信号通知主线程创建控件"""
@@ -724,69 +706,33 @@ def _on_batch_ready(self, reporter, batch: list):
724706 self .cards .append (card )
725707 self ._cards_set .add (key )
726708
727- # 将新卡片添加到布局(只放置尚未加入布局的卡片)
709+ # 将新卡片添加到布局
728710 try :
729- columns = self ._calculate_columns (
730- max (self .width (), self .sizeHint ().width ())
731- )
732-
733- for i , card in enumerate (list (self .cards )):
734- # 如果卡片已经在布局中则跳过
711+ for card in list (self .cards ):
712+ # 确保卡片不在另一个父控件下
735713 try :
736- if self . grid_layout . indexOf ( card ) != - 1 :
737- continue
714+ if card . parent () is not None and card . parent () is not self :
715+ card . setParent ( None )
738716 except Exception as e :
739717 from loguru import logger
740-
741- logger .exception (
742- "Error checking grid_layout.indexOf (ignored): {}" , e
743- )
744-
745- row = i // columns
746- col = i % columns
747-
748- # 如果目标格位已有其它控件,先移除避免重叠
718+ logger .exception ("Error resetting card parent (ignored): {}" , e )
719+
720+ # 如果卡片已经在布局中则跳过
749721 try :
750- existing_item = self .grid_layout .itemAtPosition (row , col )
751- if existing_item is not None :
752- existing_widget = existing_item .widget ()
753- if existing_widget is not None and existing_widget is not card :
754- try :
755- self .grid_layout .removeWidget (existing_widget )
756- except Exception as e :
757- from loguru import logger
758-
759- logger .exception (
760- "Error removing existing widget from grid (ignored): {}" ,
761- e ,
762- )
763- try :
764- existing_widget .hide ()
765- except Exception as e :
766- from loguru import logger
767-
768- logger .exception (
769- "Error hiding existing widget (ignored): {}" , e
770- )
722+ if self .flow_layout .indexOf (card ) != - 1 :
723+ continue
771724 except Exception as e :
772725 from loguru import logger
773-
774- logger .exception (
775- "Error handling existing widget in grid (ignored): {}" , e
776- )
777-
726+ logger .exception ("Error checking flow_layout.indexOf (ignored): {}" , e )
727+
778728 try :
779- self .grid_layout .addWidget (card , row , col )
729+ self .flow_layout .addWidget (card )
780730 if not card .isVisible ():
781731 card .show ()
782732 except Exception :
783- logger .exception ("向网格添加卡片失败" )
784-
785- for col in range (columns ):
786- self .grid_layout .setColumnStretch (col , 1 )
733+ logger .exception ("向流式布局添加卡片失败" )
787734 except Exception as e :
788735 from loguru import logger
789-
790736 logger .exception ("增量渲染时布局更新失败: {}" , e )
791737
792738 def _on_render_finished (self , reporter ):
0 commit comments