实现层级目录窗口

This commit is contained in:
Voge1imkafig 2025-08-05 17:51:11 +08:00
parent c28642bdec
commit efc37d4270
8 changed files with 401 additions and 429 deletions

View File

@ -0,0 +1,15 @@
{
"检查人员": "213",
"厂家人员": "213",
"业主人员": "213",
"数据处理人员": "213",
"报告编制人员": "123",
"机组型号": "123",
"机组厂家": "213",
"施工日期": "开始-结束",
"": "123",
"外部检查": true,
"内部检查": true,
"防雷检查": true,
"json路径": "/home/dtyx/桌面/yhh/ReportGenerator/config/单次检查配置信息"
}

View File

@ -1,14 +0,0 @@
{
"项目名称": "123",
"风场名": "123",
"风场地址": "213",
"甲方公司": "123",
"甲方负责人": "123",
"甲方负责人电话": "123",
"乙方公司": "武汉迪特聚能科技有限公司",
"乙方负责人": "123",
"乙方负责人电话": "123",
"项目规格": "213",
"项目工期": "123",
"json路径": "/home/dtyx/桌面/yhh/ReportGenerator/config/项目基本信息"
}

Binary file not shown.

View File

@ -1,9 +1,13 @@
from PySide6.QtWidgets import (QGroupBox, QVBoxLayout, QHBoxLayout, QCheckBox,
QPushButton, QDialog, QLineEdit, QFontComboBox,
QFileDialog, QMessageBox, QLabel, QWidget,
QTextBrowser, QApplication, QCompleter, QFrame)
from PySide6.QtCore import QDateTime,QTimer,QDateTime,Signal,QSettings, QSortFilterProxyModel
from PySide6.QtGui import QPixmap, QDragEnterEvent, QDropEvent, Qt, QIcon
QTextBrowser, QApplication, QCompleter, QFrame,
QListWidgetItem, QListWidget, QAbstractItemView,
QStackedWidget, QStackedLayout)
from PySide6.QtCore import (QDateTime,QTimer,QDateTime,Signal,QSettings,
QSortFilterProxyModel, QSize)
from PySide6.QtGui import (QPixmap, QDragEnterEvent, QDropEvent, Qt, QIcon,
QFontMetrics)
import json, sys, os
from info_core.defines import *
@ -138,6 +142,10 @@ class ConfigComboBoxGroup(QGroupBox):
QMessageBox.information(self, '信息', '删除操作已取消。')
else:
QMessageBox.warning(self, '警告', '没有选中任何项目。')
def get_current_config_file(self):
"""获取当前选中的配置文件"""
return os.path.join(self.config_dir, self.combo_box.currentText() + ".json")
class AddProjectDialog(QDialog):
def __init__(self, dir, parent=None, path=None, combobox=None):
@ -298,8 +306,9 @@ class AddPersonnelDialog(QDialog):
{"key": "报告编制人员", "label": "报告编制人员:", "default": ""},
{"key": "机组型号", "label": "机组型号:", "default": ""},
{"key": "机组厂家", "label": "机组厂家:", "default": ""},
{"key": "叶片型号", "label": "叶片型号", "default": ""},
{"key": "叶片厂家", "label": "叶片厂家:", "default": ""},
{"key": "施工日期", "label": "施工日期", "default": "开始-结束"},
{"key": "", "label": "", "default": ""},
#{"key": "", "label": "", "default": ""},
# 可以轻松添加更多人员字段
]
@ -377,7 +386,25 @@ class AddPersonnelDialog(QDialog):
self.save_button = QPushButton("保存")
self.save_button.clicked.connect(self.on_save_button_clicked)
# 创建复选框布局
checkbox_group = QGroupBox("检查类型")
checkbox_layout = QHBoxLayout()
# 添加复选框
self.checkboxes = {}
for field in self.checkbox_fields:
checkbox = QCheckBox(field["label"])
if self.path and field["key"] in self.data:
checkbox.setChecked(bool(self.data[field["key"]]))
else:
checkbox.setChecked(field["default"])
self.checkboxes[field["key"]] = checkbox
checkbox_layout.addWidget(checkbox)
checkbox_group.setLayout(checkbox_layout)
# 添加到主布局
main_layout.addWidget(checkbox_group)
main_layout.addWidget(form_widget)
main_layout.addWidget(self.save_button)
@ -390,6 +417,10 @@ class AddPersonnelDialog(QDialog):
field["key"]: self.fields[field["key"]].text()
for field in self.form_fields
}
# 添加复选框数据
for key, checkbox in self.checkboxes.items():
personnel_info[key] = checkbox.isChecked()
personnel_info["json路径"] = self.dir
# 验证保存目录
@ -420,11 +451,7 @@ class AddPersonnelDialog(QDialog):
QMessageBox.critical(self, "错误", f"保存文件失败: {str(e)}")
return
# 更新QComboBox
if self.combobox is None:
self.parent().ui.personnel.addItem(os.path.basename(file_path))
else:
self.combobox.load_config_files(os.path.basename(self.dir))
self.parent().load_config_files()
# 提示用户保存成功
QMessageBox.information(self, "信息", f"人员信息已成功保存到 {file_path}")
@ -700,386 +727,300 @@ class SmartDropdown(QWidget):
except ValueError:
self.messagebrowser.append(f"删除失败: 选项 {current_text} 不存在")
class FolderImportWidget(QGroupBox):
"""支持双路径独立导入的组件"""
main_folder_selected = Signal(str) # 仅总图片路径变化时发射
selected_folder_selected = Signal(str) # 选中路径变化时发射
get_baogao_choose_info = Signal(str) # 获取报告选择
class FolderDropWidget(QWidget):
selection_changed = Signal(list)
def __init__(self, title: str = "图片文件夹导入", parent=None):
super().__init__(title, parent)
self.main_folder = None
self.selected_folder = None
self.setup_ui()
self.apply_styles()
def setup_ui(self):
"""设置UI布局"""
self.setMinimumSize(GROUP_BOX_MIN_WIDTH, GROUP_BOX_MIN_HEIGHT)
main_layout = QVBoxLayout()
main_layout.setSpacing(GROUP_BOX_SPACING)
main_layout.setContentsMargins(*GROUP_BOX_MARGINS)
# ================= 总图片路径区域 =================
self.main_group = DropGroupBox("总图片路径(自动解析数量,生成略缩图)")
main_group_layout = QVBoxLayout()
# 拖拽区域
self.main_drag_label = QLabel("拖拽文件夹到此处或点击按钮选择")
self.main_drag_label.setProperty("class", "waiting-label")
# 路径显示
self.main_path_label = QLabel("未选择")
self.main_path_label.setProperty("class", "info-display")
# 选择按钮
self.main_select_btn = QPushButton("选择总图片文件夹")
self.main_select_btn.setProperty("class", "normal-button")
main_group_layout.addWidget(self.main_drag_label)
main_group_layout.addWidget(self.main_path_label)
main_group_layout.addWidget(self.main_select_btn, 0, Qt.AlignmentFlag.AlignHCenter)
self.main_group.setLayout(main_group_layout)
self.main_group.setAcceptDrops(True)
# ================= 选中图片路径区域 =================
self.selected_group = DropGroupBox("选中图片路径(获取典型部位图片,自动读取图片名做描述)")
selected_group_layout = QVBoxLayout()
# 拖拽区域
self.selected_drag_label = QLabel("拖拽文件夹到此处或点击按钮选择")
self.selected_drag_label.setProperty("class", "waiting-label")
# 路径显示
self.selected_path_label = QLabel("未选择")
self.selected_path_label.setProperty("class", "info-display")
# 选择按钮
self.selected_select_btn = QPushButton("选择图片文件夹")
self.selected_select_btn.setProperty("class", "normal-button")
self.modify_layout = QHBoxLayout()
self.modify_picture_quexian_btn = QPushButton("修改图片缺陷信息")
self.modify_picture_quexian_btn.setProperty("class", "normal-button")
self.modify_picture_quexian_btn.setEnabled(False)
self.modify_picture_quexian_btn.clicked.connect(self.on_modify_picture_quexian_btn_clicked)
self.modify_picture_huizong_btn = QPushButton("修改图片汇总信息")
self.modify_picture_huizong_btn.setProperty("class", "normal-button")
self.modify_picture_huizong_btn.setEnabled(False)
self.modify_picture_huizong_btn.clicked.connect(self.on_modify_picture_huizong_btn_clicked)
self.modify_group = QGroupBox("修改图片信息")
self.modify_layout.addWidget(self.modify_picture_quexian_btn, 0, Qt.AlignmentFlag.AlignHCenter)
self.modify_layout.addWidget(self.modify_picture_huizong_btn, 0, Qt.AlignmentFlag.AlignHCenter)
self.modify_layout.addStretch(1)
self.modify_group.setLayout(self.modify_layout)
selected_group_layout.addWidget(self.selected_drag_label)
selected_group_layout.addWidget(self.selected_path_label)
selected_group_layout.addWidget(self.selected_select_btn, 0, Qt.AlignmentFlag.AlignHCenter)
selected_group_layout.addWidget(self.modify_group)
self.selected_group.setLayout(selected_group_layout)
self.selected_group.setAcceptDrops(True)
# ================= 添加到主布局 =================
main_layout.addWidget(self.main_group)
main_layout.addWidget(self.selected_group)
self.setLayout(main_layout)
# 连接信号
self.main_select_btn.clicked.connect(lambda: self.select_folder("main"))
self.selected_select_btn.clicked.connect(lambda: self.select_folder("selected"))
self.search_file_list = []
def apply_styles(self):
"""应用样式"""
self.setStyleSheet(f"""
{GROUP_BOX_STYLE}
/* 内部GroupBox样式 */
QGroupBox QGroupBox {{
font-size: {TITLE_FONT_SIZE - 1}pt;
border: 1px solid #ced4da;
margin-top: 16px;
}}
QLabel[class="waiting-label"] {{
{WAITING_LABEL_STYLE}
font-size: {CONTENT_FONT_SIZE}pt;
}}
QLabel[class="info-display"] {{
{INFO_DISPLAY_STYLE}
min-height: 60px;
}}
QPushButton[class="normal-button"] {{
{BUTTON_STYLE}
min-width: 160px;
}}
""")
def select_folder(self, folder_type: str):
"""选择文件夹"""
dialog_title = "选择总图片文件夹" if folder_type == "main" else "选择图片文件夹"
folder = QFileDialog.getExistingDirectory(
self,
dialog_title,
os.path.expanduser("~"),
QFileDialog.Option.ShowDirsOnly | QFileDialog.Option.DontResolveSymlinks
)
if folder:
self.set_folder_path(folder, folder_type)
def set_folder_path(self, folder_path: str, folder_type: str):
"""设置文件夹路径并更新UI"""
if folder_type == "main":
self.main_folder = folder_path
self.main_path_label.setText(folder_path)
self.main_drag_label.hide()
self.main_folder_selected.emit(folder_path) # 触发解析
else:
self.selected_folder = folder_path
self.selected_path_label.setText(folder_path)
self.selected_drag_label.hide()
self.modify_picture_quexian_btn.setEnabled(True)
self.modify_picture_huizong_btn.setEnabled(True)
self.selected_folder_selected.emit(folder_path)
def dragEnterEvent(self, event: QDragEnterEvent):
"""总区域的拖拽事件(转发到对应子区域)"""
source = event.source()
if isinstance(source, QGroupBox):
# 如果是来自子区域的拖拽,交给子区域处理
return
# 否则检查是否是有效的文件夹拖拽
if event.mimeData().hasUrls():
urls = event.mimeData().urls()
if len(urls) == 1 and urls[0].isLocalFile():
file_info = urls[0].toLocalFile()
if os.path.isdir(file_info):
event.acceptProposedAction()
def dropEvent(self, event: QDropEvent):
"""总区域的放下事件(自动分配到第一个区域)"""
urls = event.mimeData().urls()
if urls and urls[0].isLocalFile():
folder_path = urls[0].toLocalFile()
if os.path.isdir(folder_path):
self.set_folder_path(folder_path, "main")
def get_paths(self) -> tuple:
"""获取两个路径(总路径,选中路径)"""
return self.main_folder, self.selected_folder
def get_baogao_choose(self):
self.get_baogao_choose_info.emit()
def update_baogao_choose_info(self, info: list[str]):
self.search_file_list = info
def on_modify_picture_quexian_btn_clicked(self):
"""修改图片缺陷类型"""
# self.get_baogao_choose()
# if self.search_file_list:
# Y1_num, Y1 =
def on_modify_picture_huizong_btn_clicked(self):
"""修改图片汇总信息"""
self.get_baogao_choose()
# 子区域GroupBox需要单独处理拖拽事件
class DropGroupBox(QGroupBox):
"""支持拖拽的子区域GroupBox"""
def __init__(self, parent=None):
super().__init__(parent)
self.setAcceptDrops(True)
def dragEnterEvent(self, event: QDragEnterEvent):
if event.mimeData().hasUrls():
urls = event.mimeData().urls()
if len(urls) == 1 and urls[0].isLocalFile():
file_info = urls[0].toLocalFile()
if os.path.isdir(file_info):
event.acceptProposedAction()
return
event.ignore()
def dropEvent(self, event: QDropEvent):
urls = event.mimeData().urls()
if urls and urls[0].isLocalFile():
folder_path = urls[0].toLocalFile()
if os.path.isdir(folder_path):
# 通过parent()调用主组件的方法
parent = self.parent()
while parent and not isinstance(parent, FolderImportWidget):
parent = parent.parent()
if parent:
folder_type = "main" if self == parent.main_group else "selected"
parent.set_folder_path(folder_path, folder_type)
class ImageAnalysisWidget(QGroupBox):
"""完全使用宏定义样式的图片解析组件"""
generate_path_selected = Signal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.setTitle("图片解析")
self.image_folder_path = None
self.generate_path = None
self.setup_ui()
self.current_dir = None
self.selected_folders = set()
self.init_ui()
self.apply_styles()
def setup_ui(self):
"""设置UI布局"""
self.setMinimumSize(GROUP_BOX_MIN_WIDTH, GROUP_BOX_MIN_HEIGHT)
def init_ui(self):
main_layout = QVBoxLayout()
main_layout.setSpacing(GROUP_BOX_SPACING)
main_layout.setContentsMargins(*GROUP_BOX_MARGINS)
main_layout.setSpacing(15)
main_layout.setContentsMargins(15, 15, 15, 15)
# 顶部按钮区域
btn_layout = QHBoxLayout()
self.reset_btn = QPushButton("重新选择项目文件夹")
self.reset_btn.clicked.connect(self.reset_selection)
self.reset_btn.setFixedSize(120, 40)
self.reset_btn.setVisible(False)
# 初始状态 - 等待导入
self.waiting_label = QLabel("请先导入图片文件夹以开始解析")
self.waiting_label.setProperty("class", "waiting-label")
self.clear_btn = QPushButton("清空选中机组列表")
self.clear_btn.clicked.connect(self.clear_selected)
self.clear_btn.setFixedSize(120, 40)
self.clear_btn.setVisible(False)
# 解析结果区域
self.result_frame = QFrame()
result_layout = QVBoxLayout()
result_layout.setSpacing(15)
btn_layout.addWidget(self.reset_btn)
btn_layout.addWidget(self.clear_btn)
btn_layout.addStretch()
main_layout.addLayout(btn_layout)
# 主内容区域 - 使用堆叠布局管理不同状态
self.stacked_layout = QStackedLayout()
# 图片文件夹信息
folder_info_layout = QHBoxLayout()
folder_label = QLabel("图片文件夹:")
folder_label.setProperty("class", "info-label")
self.folder_path_label = QLabel("未选择")
self.folder_path_label.setProperty("class", "info-display")
folder_info_layout.addWidget(folder_label)
folder_info_layout.addWidget(self.folder_path_label)
# 状态1: 未选择文件夹时的提示
self.prompt_container = QWidget()
prompt_layout = QVBoxLayout()
self.prompt_label = QLabel("拖放文件夹到此处或点击选择文件夹")
self.prompt_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.prompt_label.mousePressEvent = self.select_folder
prompt_layout.addWidget(self.prompt_label)
self.prompt_container.setLayout(prompt_layout)
self.stacked_layout.addWidget(self.prompt_container)
# 状态2: 显示第一层文件夹 (项目选择)
self.level1_container = QWidget()
level1_main_layout = QVBoxLayout()
# 图片数量信息
count_info_layout = QHBoxLayout()
count_label = QLabel("图片数量:")
count_label.setProperty("class", "info-label")
self.image_count_label = QLabel("-")
self.image_count_label.setProperty("class", "info-display")
count_info_layout.addWidget(count_label)
count_info_layout.addWidget(self.image_count_label)
# 添加状态标签
self.level1_title = QLabel("项目选择")
self.level1_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
level1_main_layout.addWidget(self.level1_title)
# 分隔线
separator = QFrame()
separator.setFrameShape(QFrame.Shape.HLine)
separator.setProperty("class", "separator")
self.level1_list = QListWidget()
self.level1_list.setIconSize(QSize(48, 48))
self.level1_list.setViewMode(QListWidget.ViewMode.IconMode)
self.level1_list.setResizeMode(QListWidget.ResizeMode.Adjust)
self.level1_list.setMovement(QListWidget.Movement.Static)
self.level1_list.setSpacing(10)
self.level1_list.itemDoubleClicked.connect(self.show_level2_folders)
level1_main_layout.addWidget(self.level1_list)
# 生成路径区域
path_info_layout = QHBoxLayout()
path_label = QLabel("生成路径:")
path_label.setProperty("class", "info-label")
self.generate_path_label = QLabel("未选择")
self.generate_path_label.setProperty("class", "info-display")
path_info_layout.addWidget(path_label)
path_info_layout.addWidget(self.generate_path_label)
self.level1_container.setLayout(level1_main_layout)
self.stacked_layout.addWidget(self.level1_container)
# 状态3: 显示第二层文件夹 (机组选择)
self.level2_container = QWidget()
level2_main_layout = QVBoxLayout()
# 选择按钮
self.select_path_button = QPushButton("选择生成路径")
self.select_path_button.setProperty("class", "normal-button")
self.select_path_button.clicked.connect(self.select_generate_path)
self.select_path_button.setEnabled(False)
# 添加状态标签
self.level2_title = QLabel("机组选择")
self.level2_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
level2_main_layout.addWidget(self.level2_title)
# 生成报告选项
check_box_layout = QHBoxLayout()
self.check_is_waibu = QCheckBox("外部")
self.check_is_neibu = QCheckBox("内部")
self.check_is_fanglei = QCheckBox("防雷")
self.check_is_neibu.setStyleSheet(CHECKBOX_STYLE)
self.check_is_waibu.setStyleSheet(CHECKBOX_STYLE)
self.check_is_fanglei.setStyleSheet(CHECKBOX_STYLE)
check_box_layout.addWidget(self.check_is_waibu)
check_box_layout.addWidget(self.check_is_neibu)
check_box_layout.addWidget(self.check_is_fanglei)
self.level2_list = QListWidget()
self.level2_list.setIconSize(QSize(48, 48))
self.level2_list.setViewMode(QListWidget.ViewMode.IconMode)
self.level2_list.setResizeMode(QListWidget.ResizeMode.Adjust)
self.level2_list.setMovement(QListWidget.Movement.Static)
self.level2_list.setSpacing(10)
level2_main_layout.addWidget(self.level2_list)
# 添加到结果布局
result_layout.addLayout(folder_info_layout)
result_layout.addLayout(count_info_layout)
result_layout.addWidget(separator)
result_layout.addLayout(path_info_layout)
result_layout.addWidget(self.select_path_button, 0, Qt.AlignmentFlag.AlignHCenter)
result_layout.addLayout(check_box_layout)
result_layout.addStretch()
# 添加返回按钮
self.back_btn = QPushButton("返回项目选择")
self.back_btn.clicked.connect(lambda: self.stacked_layout.setCurrentIndex(1))
level2_main_layout.addWidget(self.back_btn)
self.result_frame.setLayout(result_layout)
self.result_frame.hide()
# 添加到主布局
main_layout.addWidget(self.waiting_label)
main_layout.addWidget(self.result_frame)
self.level2_container.setLayout(level2_main_layout)
self.stacked_layout.addWidget(self.level2_container)
# 将堆叠布局添加到主布局
stack_container = QWidget()
stack_container.setLayout(self.stacked_layout)
main_layout.addWidget(stack_container)
# 已选目录列表 (始终显示在底部)
self.selected_group = QGroupBox("已选机组")
self.selected_group.setVisible(False)
selected_layout = QVBoxLayout()
self.selected_list = QListWidget()
self.selected_list.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection)
selected_layout.addWidget(self.selected_list)
self.selected_group.setLayout(selected_layout)
main_layout.addWidget(self.selected_group)
self.setLayout(main_layout)
def apply_styles(self):
"""完全使用宏定义应用样式"""
self.setStyleSheet(GROUP_BOX_STYLE)
self.prompt_label.setStyleSheet(f"""
{PATH_DISPLAY_STYLE}
border: 2px dashed {SECONDARY_COLOR};
min-height: 150px;
""")
# 通过QSS类选择器应用样式
self.setStyleSheet(f"""
{self.styleSheet()}
/* 等待提示 */
QLabel[class="waiting-label"] {{
{WAITING_LABEL_STYLE}
}}
/* 信息标签 */
QLabel[class="info-label"] {{
{INFO_LABEL_STYLE}
}}
/* 信息显示 */
QLabel[class="info-display"] {{
{INFO_DISPLAY_STYLE}
}}
/* 分隔线 */
QFrame[class="separator"] {{
{SEPARATOR_STYLE}
}}
/* 普通按钮 */
QPushButton[class="normal-button"] {{
{BUTTON_STYLE}
self.level1_list.setStyleSheet(f"""
QListWidget {{
background-color: #f8f9fa;
min-height: 150px;
}}
""")
self.level2_list.setStyleSheet(f"""
QListWidget {{
background-color: #f8f9fa;
min-height: 150px;
}}
""")
self.level1_title.setStyleSheet(f"""
{LABEL_STYLE}
font-size: {TITLE_FONT_SIZE}pt;
font-weight: bold;
padding: 10px;
""")
self.level2_title.setStyleSheet(f"""
{LABEL_STYLE}
font-size: {TITLE_FONT_SIZE}pt;
font-weight: bold;
padding: 10px;
""")
self.selected_group.setStyleSheet(GROUP_BOX_STYLE)
self.reset_btn.setStyleSheet(BUTTON_STYLE)
self.clear_btn.setStyleSheet(BUTTON_STYLE)
self.back_btn.setStyleSheet(BUTTON_STYLE)
def select_folder(self, event=None):
folder = QFileDialog.getExistingDirectory(self, "选择文件夹")
if folder:
self.load_folder(folder)
def reset_selection(self):
self.current_dir = None
self.selected_folders.clear()
self.level1_list.clear()
self.level2_list.clear()
self.selected_list.clear()
self.stacked_layout.setCurrentIndex(0) # 显示提示
self.reset_btn.setVisible(False)
self.clear_btn.setVisible(False)
self.selected_group.setVisible(False)
self.selection_changed.emit([])
def clear_selected(self):
self.selected_folders.clear()
self.selected_list.clear()
self.update_checkbox_states()
self.selection_changed.emit([])
def load_folder(self, path):
self.current_dir = path
self.load_level1_folders(path)
self.stacked_layout.setCurrentIndex(1) # 显示第一层
self.reset_btn.setVisible(True)
self.clear_btn.setVisible(True)
self.selected_group.setVisible(True)
def dragEnterEvent(self, event: QDragEnterEvent):
if event.mimeData().hasUrls():
event.acceptProposedAction()
def dropEvent(self, event: QDropEvent):
for url in event.mimeData().urls():
path = url.toLocalFile()
if os.path.isdir(path):
self.load_folder(path)
break
def load_level1_folders(self, root_path):
self.level1_list.clear()
self.level2_list.clear()
for item in os.listdir(root_path):
item_path = os.path.join(root_path, item)
if os.path.isdir(item_path):
item_widget = QListWidgetItem(QIcon.fromTheme("folder"), item)
item_widget.setData(Qt.ItemDataRole.UserRole, item_path)
item_widget.setSizeHint(QSize(80, 80))
item_widget.setTextAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignBottom)
self.level1_list.addItem(item_widget)
def show_level2_folders(self, item):
self.level2_list.clear()
folder_path = item.data(Qt.ItemDataRole.UserRole)
for sub_item in os.listdir(folder_path):
sub_item_path = os.path.join(folder_path, sub_item)
if os.path.isdir(sub_item_path):
list_item = QListWidgetItem()
list_item.setSizeHint(QSize(100, 80))
list_item.setData(Qt.ItemDataRole.UserRole, sub_item_path)
widget = QWidget()
layout = QVBoxLayout()
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
icon_label = QLabel()
icon_label.setPixmap(QIcon.fromTheme("folder").pixmap(48, 48))
icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(icon_label)
name_check_layout = QHBoxLayout()
checkbox = QCheckBox(sub_item)
checkbox.setStyleSheet(f"""
{PRIMARY_CHECKBOX_STYLE}
QCheckBox::indicator:checked {{
background-color: {PRIMARY_COLOR};
border: 1px solid {PRIMARY_COLOR};
}}
""")
checkbox.stateChanged.connect(lambda state, path=sub_item_path: self.toggle_folder_selection(path, state))
checkbox.setChecked(sub_item_path in self.selected_folders)
name_check_layout.addWidget(checkbox)
layout.addLayout(name_check_layout)
widget.setLayout(layout)
list_item.setSizeHint(widget.sizeHint())
self.level2_list.addItem(list_item)
self.level2_list.setItemWidget(list_item, widget)
self.stacked_layout.setCurrentIndex(2) # 显示第二层
def toggle_folder_selection(self, folder_path, state):
if state == Qt.CheckState.Checked.value:
self.selected_folders.add(folder_path)
item = QListWidgetItem(folder_path)
self.selected_list.addItem(item)
else:
self.selected_folders.discard(folder_path)
items = self.selected_list.findItems(folder_path, Qt.MatchFlag.MatchExactly)
for item in items:
self.selected_list.takeItem(self.selected_list.row(item))
self.selection_changed.emit(self.get_selected_folders())
def update_checkbox_states(self):
for i in range(self.level2_list.count()):
item = self.level2_list.item(i)
widget = self.level2_list.itemWidget(item)
if widget:
checkbox = widget.findChild(QCheckBox)
if checkbox:
path = item.data(Qt.ItemDataRole.UserRole)
checkbox.setChecked(path in self.selected_folders)
def get_selected_folders(self):
return list(self.selected_folders)
def set_image_folder(self, folder_path: str):
"""设置图片文件夹路径并开始解析"""
self.image_folder_path = folder_path
self.folder_path_label.setText(folder_path)
self.start_analysis()
def start_analysis(self):
"""开始解析"""
self.total_picture_count = 0
for root, dirs, files in os.walk(self.image_folder_path):
for file in files:
# 检查文件扩展名是否为图片格式
if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff')):
self.total_picture_count += 1
self.waiting_label.hide()
self.image_count_label.setText(str(self.total_picture_count)) # 模拟解析结果
self.select_path_button.setEnabled(True)
self.result_frame.show()
def select_generate_path(self):
"""选择生成路径"""
path = QFileDialog.getExistingDirectory(
self,
"选择生成路径",
os.path.expanduser("~") or self.image_folder_path,
QFileDialog.Option.ShowDirsOnly | QFileDialog.Option.DontResolveSymlinks
)
if path:
self.set_generate_path(path)
def set_generate_path(self, path: str):
"""设置并显示生成路径"""
self.generate_path = path
self.generate_path_label.setText(path)
self.generate_path_selected.emit(path)
class DraggableLine(QFrame):
def __init__(self, parent=None):
super().__init__(parent)
self.setFrameShape(QFrame.HLine)
self.setFrameShadow(QFrame.Sunken)
self.setLineWidth(2)
self.setFixedHeight(10)
self.dragging = False
self.setCursor(Qt.SizeVerCursor)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.dragging = True
self.start_pos = event.globalPos()
def mouseMoveEvent(self, event):
if self.dragging:
delta = event.globalPos() - self.start_pos
self.start_pos = event.globalPos()
# 通知父窗口调整布局
self.parent().adjust_row_height(delta.y())
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.dragging = False

View File

@ -18,8 +18,8 @@ TEXT_COLOR = "#2c3e50"
LIGHT_TEXT_COLOR = "#ecf0f1"
# 按钮样式
BUTTON_WIDTH = 100
BUTTON_HEIGHT = 34
BUTTON_WIDTH = 200
BUTTON_HEIGHT = 20
BUTTON_RADIUS = 4
BUTTON_FONT_WEIGHT = QFont.Weight.Medium
@ -64,7 +64,7 @@ PRIMARY_BUTTON_STYLE = f"""
"""
# 下拉框样式
COMBO_BOX_HEIGHT = 34
COMBO_BOX_HEIGHT = 10
COMBO_BOX_STYLE = f"""
QComboBox {{
font-family: "{FONT_FAMILY}";
@ -81,10 +81,10 @@ COMBO_BOX_STYLE = f"""
"""
# 组框样式
GROUP_BOX_MIN_WIDTH = 380
GROUP_BOX_MIN_HEIGHT = 200
GROUP_BOX_SPACING = 15
GROUP_BOX_MARGINS = (15, 15, 15, 15)
GROUP_BOX_MIN_WIDTH = 300
GROUP_BOX_MIN_HEIGHT = 120
GROUP_BOX_SPACING = 5
GROUP_BOX_MARGINS = (5, 5, 5, 5)
GROUP_BOX_STYLE = f"""
QGroupBox {{
font-family: "{FONT_FAMILY}";
@ -127,8 +127,8 @@ PATH_DISPLAY_STYLE = f"""
# 主窗口样式
WINDOW_MIN_WIDTH = 1000
WINDOW_MIN_HEIGHT = 720
MAIN_LAYOUT_SPACING = 20
MAIN_LAYOUT_MARGINS = (25, 25, 25, 25)
MAIN_LAYOUT_SPACING = 10
MAIN_LAYOUT_MARGINS = (5, 5, 5, 5)
# 信息标签样式 (左侧固定标签)
INFO_LABEL_STYLE = f"""
@ -167,7 +167,7 @@ WAITING_LABEL_STYLE = f"""
"""
CHECKBOX_SIZE = 16 # 复选框大小
CHECKBOX_MARGIN = 4 # 边距
CHECKBOX_MARGIN = 1 # 边距
# 基础CheckBox样式
CHECKBOX_STYLE = f"""
@ -193,6 +193,15 @@ PRIMARY_CHECKBOX_STYLE = f"""
}}
QCheckBox::indicator:checked {{
background-color: {PRIMARY_COLOR};
image: url(:/icons/check_white.svg);
}}
"""
SPLITTER_STYLE = """
QSplitter::handle {
background: #a0a0a0; /* 分割线颜色 */
height: 4px; /* 水平分割线高度垂直分割线用 width */
}
QSplitter::handle:hover {
background: #808080; /* 鼠标悬停时颜色 */
}
"""

89
main.py
View File

@ -1,10 +1,11 @@
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QGridLayout,
QPushButton, QSizePolicy)
QPushButton, QSizePolicy, QSplitter, QToolBar)
from PySide6.QtGui import QFontDatabase
from PySide6.QtCore import Signal
from PySide6.QtCore import Signal, Qt
import os
from info_core.defines import *
from info_core.MyQtClass import ConfigComboBoxGroup, FolderImportWidget, ImageAnalysisWidget
from info_core.MyQtClass import ConfigComboBoxGroup, FolderDropWidget, DraggableLine
class ReportGeneratorUI(QMainWindow):
@ -46,46 +47,66 @@ class ReportGeneratorUI(QMainWindow):
# 第一行:项目信息和人员配置
self.project_group = ConfigComboBoxGroup("项目基本信息")
self.staff_group = ConfigComboBoxGroup("单次检查配置信息", is_project=False)
self.main_layout.addWidget(self.project_group, 0, 0)
self.main_layout.addWidget(self.staff_group, 0, 1)
# 第二行:导入图片路径、填写机组信息
self.picture_group = FolderImportWidget("导入图片路径")
self.main_layout.addWidget(self.picture_group, 1, 0)
self.image_analysis = ImageAnalysisWidget("填写机组信息")
self.main_layout.addWidget(self.image_analysis, 1, 1)
# 连接信号
self.picture_group.main_folder_selected.connect(self.image_analysis.set_image_folder)
self.image_analysis.generate_path_selected.connect(self.on_generate_path_selected)
# 获取请求信号,调用获取函数,发送更新信号
self.picture_group.get_baogao_choose_info.connect(self.get_baogao_choose_info)
self.send_baogao_choose_info.connect(self.picture_group.update_baogao_choose_info)
self.picture_group = FolderDropWidget()
# self.image_analysis =
# self.main_layout.addWidget(self.image_analysis, 1, 1)
# 第三行:生成报告按钮(跨两列)
self.create_generate_button()
self.generate_btn.setEnabled(False)
self.main_layout.addWidget(self.generate_btn, 2, 0, 1, 2)
# 设置列和行的拉伸比例
self.main_layout.setColumnStretch(0, 1) # 第一列拉伸比例
self.main_layout.setColumnStretch(1, 1) # 第二列拉伸比例
self.main_layout.setRowStretch(0, 1) # 第一行拉伸比例为1
self.main_layout.setRowStretch(1, 4) # 第二行拉伸比例为4
self.main_layout.setRowStretch(2, 0) # 第三行不拉伸(固定高度)
# 创建一个垂直分割器
self.splitter = QSplitter(Qt.Vertical)
self.splitter.setStyleSheet(SPLITTER_STYLE)
# 创建顶部和底部容器
top_container = QWidget()
top_container.setLayout(QGridLayout())
top_container.layout().addWidget(self.project_group, 0, 0)
top_container.layout().addWidget(self.staff_group, 0, 1)
middle_container = QWidget()
middle_container.setLayout(QGridLayout())
middle_container.layout().addWidget(self.picture_group, 0, 0)
# 添加部件到分割器
self.splitter.addWidget(top_container)
self.splitter.addWidget(middle_container)
# 设置主布局
self.main_layout.addWidget(self.splitter, 0, 0, 2, 2) # 占据前两行两列
self.main_layout.addWidget(self.generate_btn, 2, 0, 1, 2)
# 设置分割器初始比例
self.splitter.setStretchFactor(0, 1)
self.splitter.setStretchFactor(1, 4)
self.toolbar = QToolBar()
self.addToolBar(self.toolbar)
self.toolbar.setMovable(False)
self.toolbar.setFloatable(False)
new_action = self.toolbar.addAction("重置布局比例")
self.toolbar.addSeparator()
new_action.triggered.connect(self.reset_splitter)
def reset_splitter(self):
"""重置分割器的比例"""
total_size = sum(self.splitter.sizes()) # 获取当前总大小
self.splitter.setSizes([
int(total_size * 0.2), # 第一部分占 20%(比例 1:4
int(total_size * 0.8) # 第二部分占 80%
])
def on_generate_path_selected(self, path):
self.generate_btn.setEnabled(True)
def get_baogao_choose_info(self):
search_file_list = []
if self.image_analysis.check_is_waibu:
search_file_list.append("外汇总")
if self.image_analysis.check_is_neibu:
search_file_list.append("内汇总")
if self.image_analysis.check_is_fanglei:
search_file_list.append("防汇总")
self.send_baogao_choose_info.emit(search_file_list)
# search_file_list = []
# if self.image_analysis.check_is_waibu:
# search_file_list.append("外汇总")
# if self.image_analysis.check_is_neibu:
# search_file_list.append("内汇总")
# if self.image_analysis.check_is_fanglei:
# search_file_list.append("防汇总")
# self.send_baogao_choose_info.emit(search_file_list)
def create_button(self, text):
"""创建统一风格的按钮"""