活动介绍

修改上面代码,加载xml文件后,界面会显示文件名称,页面导航栏中文字体为宋体,英文字体为New Times Roman

时间: 2025-08-19 19:06:16 浏览: 4
<think>我们将在界面顶部显示当前加载的XML文件名称,并设置导航栏中文字体为宋体,英文字体为Times New Roman。 主要修改点: 1. 在顶部布局中添加一个QLabel用于显示当前文件路径。 2. 设置窗口的字体样式:中文字体为宋体,英文字体为Times New Roman。 3. 注意:由于PyQt5中,可以通过设置字体族(font-family)来实现,但需要分别设置中英文。然而,在PyQt5中,我们可以通过设置一个同时支持中文和英文字体的QFont来实现。但是,实际上,我们可以设置一个主字体(如宋体)并设置一个备用字体(如Times New Roman)来解决。不过,更直接的方法是在样式表中设置全局字体。 然而,根据要求,我们需要在导航栏(即顶部按钮区域)设置中文字体为宋体,英文字体为Times New Roman。我们可以通过设置整个应用程序的字体,或者设置顶部布局中所有控件的字体。 但是,由于按钮上的文字同时包含中文和英文,我们可以这样设置: - 对于中文,使用宋体(SimSun) - 对于英文,使用Times New Roman 在样式表中,我们可以这样写: font-family: Times New Roman, SimSun; 这样,会优先使用Times New Roman显示英文(因为英文字符在Times New Roman中存在),而中文字符在Times New Roman中不存在,则会回退到SimSun。 因此,我们可以为整个窗口设置这个字体,或者为顶部布局中的所有控件设置这个字体。 另外,我们还需要在界面顶部显示当前加载的文件名称。我们可以将这个标签放在顶部布局的最左侧。 修改步骤: 1. 在类中增加一个成员变量 `self.filename_label` 用于显示当前加载的文件名。 2. 在`init_ui`中创建这个标签,并设置初始文本(如“未加载文件”)。 3. 在加载文件成功后,更新这个标签的文本为当前文件路径(或文件名)。 4. 调整顶部布局,将这个标签加入进去。 5. 设置整个窗口的字体,或者为每个控件设置字体(通过样式表或QFont)。 为了统一,我们将为整个应用程序设置字体,或者为窗口设置一个样式表。但是,由于要求是导航栏,我们可以只设置顶部布局中的控件。 然而,我们也可以设置整个窗口的字体,这样包括表格都会使用这个字体。但表格可能不需要改变字体?题目要求是“页面导航栏”,即顶部按钮区域。所以我们可以只设置顶部布局中的控件。 具体做法: 在`init_ui`中,为顶部布局中的所有控件设置样式表,设置字体为:Times New Roman, SimSun。 但是,这样每个控件都要单独设置样式表?我们可以为顶部布局的父控件(即central_widget)设置样式,然后让所有子控件继承。但这样也会影响表格。所以,我们可以只给顶部布局中的控件设置。 另一种方法:在创建每个控件后,设置其字体。例如: font = QFont("Times New Roman", 9) font.setStyleHint(QFont.Serif) # 然后设置每个控件的字体 但是,这样并不能同时解决中英文。因为中文字符在Times New Roman中无法显示,会使用默认字体(可能不是宋体)。所以,我们需要设置一个回退机制,即设置一个字体族:先设置英文字体,再设置中文字体。 在PyQt5中,我们可以使用: font = QFont("Times New Roman", 9) font.setFamilies(["Times New Roman", "SimSun"]) 但是,这种方法在Windows上可能有效。我们可以尝试。 然而,为了简单且确保效果,我们使用样式表来设置顶部布局中的所有控件(包括标签、按钮、下拉框、输入框)的字体。 我们为顶部布局的父控件(即top_layout所在的容器)设置一个对象名,然后通过样式表设置该容器内所有控件的字体。 但是,top_layout是一个布局,没有直接对应的控件。我们可以将top_layout放入一个QWidget中,然后设置这个QWidget的样式。 但是,这样会增加一层嵌套。我们也可以直接为每个控件设置样式表,例如: style = "font-family: Times New Roman, SimSun; font-size: 9pt;" 然后遍历top_layout中的所有控件,设置这个样式。 但是,由于我们已经在按钮上设置了样式表,为了避免冲突,我们可以将字体设置合并到按钮的样式表中,并为其他控件(如标签、下拉框、输入框)单独设置。 考虑到时间,我们选择为整个窗口设置默认字体。这样,所有控件都会继承。 在`__init__`中,在创建UI之前,设置应用程序的字体(或者窗口的字体): self.setFont(QFont("Times New Roman", 9)) # 然后设置中文字体回退 # 但是,这样设置后,中文字符可能无法正确回退到宋体。 经过测试,我们可以这样: font = QFont("Times New Roman", 9) font.setFamily("Times New Roman, SimSun") # 注意:这个方法可能不行,因为setFamily是设置一个字体族字符串,但Qt支持用逗号分隔 # 或者使用:font.setFamilies(["Times New Roman", "SimSun"]) 在PyQt5中,我们可以这样: font = QFont() font.setFamily("Times New Roman") # 然后设置备用字体 # 实际上,Qt会自动回退,但为了确保中文用宋体,我们可以设置两个字体族 根据文档,可以使用setFamilies方法(Qt5.13以上): font.setFamilies(["Times New Roman", "SimSun"]) 但是,为了兼容性,我们使用样式表来设置整个窗口的字体。 修改方案: 在`init_ui`方法中,为整个窗口设置样式表: self.setStyleSheet(""" font-family: Times New Roman, SimSun; """) 但是,这样设置后,整个窗口的字体都会改变。包括表格中的字体。如果要求只是导航栏,那么我们可以单独为顶部布局中的控件设置样式。 我们决定:只设置顶部布局中的控件(按钮、标签、下拉框、输入框)的字体。这样,我们可以遍历top_layout中的所有控件,然后设置其字体。 步骤: # 创建顶部布局并添加控件 # 然后: for i in range(top_layout.count()): widget = top_layout.itemAt(i).widget() if widget is not None: widget.setStyleSheet("font-family: Times New Roman, SimSun; font-size: 9pt;") 但是,这样会覆盖之前为按钮设置的样式表(因为后面设置的样式表会覆盖前面的)。所以,我们需要将字体设置合并到按钮的样式表中。 因此,我们修改按钮的样式表,在其中加入字体设置。 同样,我们也要为其他控件(如QLabel, QComboBox, QLineEdit)设置字体。 由于我们之前已经为按钮设置了样式表,现在只需要在按钮的样式表中加入字体设置即可。对于其他控件,我们单独设置。 修改按钮样式表: button_style = """ QPushButton { background-color: rgb(65, 105, 225); color: white; border: none; padding: 8px 16px; text-align: center; font-size: 14px; margin: 4px 2px; border-radius: 4px; font-family: Times New Roman, SimSun; /* 添加字体 */ } ... """ 同样,为搜索框、下拉框、标签设置样式表,加入字体设置。 但是,这样会重复写很多次。我们可以为整个窗口设置一个样式表,但只希望顶部布局的控件改变字体。所以,我们可以给这些控件设置一个共同的属性,然后通过样式表选择器设置。 然而,为了快速实现,我们直接修改: 1. 在按钮样式表中加入字体设置。 2. 为其他控件单独设置样式表,加入字体。 修改代码: 在`init_ui`中,设置按钮样式表后,再设置其他控件的样式表: # 设置搜索框、下拉框、标签的样式表(包括字体) common_style = "font-family: Times New Roman, SimSun; font-size: 9pt;" self.search_box.setStyleSheet(common_style + """ QLineEdit { padding: 8px; border: 1px solid #ccc; border-radius: 4px; } """) self.column_combo.setStyleSheet(common_style + """ QComboBox { padding: 6px; border: 1px solid #ccc; border-radius: 4px; } """) # 标签控件 for label in [self.findChild(QLabel, name) for name in []]: # 由于我们创建了两个标签,但没有设置对象名,所以我们可以通过布局获取 # 或者我们在创建标签时设置样式 pass 实际上,我们在布局中创建了两个标签(搜索列:和搜索内容:),我们可以分别设置。 但是,我们可以这样:在创建标签后,立即设置样式表: label_style = "font-family: Times New Roman, SimSun; font-size: 9pt;" self.label_search_col = QLabel("搜索列:") self.label_search_col.setStyleSheet(label_style) self.label_search_content = QLabel("搜索内容:") self.label_search_content.setStyleSheet(label_style) 这样,我们就分别设置了。 但是,这样代码会变得冗长。我们选择在创建这些控件后,统一用一个循环设置(除了按钮,因为按钮已经设置了)。 我们可以在创建顶部布局后,遍历所有子控件(除了按钮)并设置字体样式。但是按钮已经设置了样式表,所以我们可以重新设置按钮的样式表,将字体加入。 为了统一,我们重新调整按钮样式表,将字体加入,然后为其他控件设置同样的字体样式。 具体步骤: 1. 在按钮样式表中加入字体:`font-family: Times New Roman, SimSun;` 2. 为其他控件(搜索框、下拉框、标签)设置样式表,同样包含这个字体。 修改后的按钮样式表: button_style = """ QPushButton { background-color: rgb(65, 105, 225); color: white; border: none; padding: 8px 16px; text-align: center; font-size: 14px; margin: 4px 2px; border-radius: 4px; font-family: Times New Roman, SimSun; } QPushButton:hover { background-color: rgb(55, 95, 215); } QPushButton:pressed { background-color: rgb(45, 85, 205); } """ 然后,为其他控件设置基础样式: common_style = """ font-family: Times New Roman, SimSun; font-size: 9pt; """ self.search_box.setStyleSheet(common_style + """ QLineEdit { padding: 8px; border: 1px solid #ccc; border-radius: 4px; } """) self.column_combo.setStyleSheet(common_style + """ QComboBox { padding: 6px; border: 1px solid #ccc; border-radius: 4px; } """) # 创建两个标签,并设置样式 label_style = common_style self.label_search_col = QLabel("搜索列:") self.label_search_col.setStyleSheet(label_style) self.label_search_content = QLabel("搜索内容:") self.label_search_content.setStyleSheet(label_style) 同时,我们还需要为显示文件名的标签设置样式: self.filename_label = QLabel("未加载文件") self.filename_label.setStyleSheet(common_style) 然后,在顶部布局中加入这个标签。 另外,在成功加载文件后,更新这个标签: self.filename_label.setText(f"当前文件: {file_path}") 但是,文件路径可能很长,我们可以只显示文件名,或者使用省略方式。这里我们显示完整路径。 为了不占用太多空间,我们可以设置一个最大宽度,或者使用省略号。我们可以设置: self.filename_label.setMaximumWidth(400) self.filename_label.setToolTip(file_path) # 当鼠标悬停时显示完整路径 这样,当路径很长时,会自动省略中间部分。 最后,调整布局:将文件名标签放在最左边。 修改后的顶部布局: top_layout.addWidget(self.filename_label) # 放在最左边 top_layout.addWidget(self.load_btn) ... # 其他按钮 但是,这样会占用一个固定位置。我们可以使用弹簧分隔,但这里我们让文件名标签跟随窗口调整(使用弹簧)。 我们可以这样: top_layout.addWidget(self.filename_label) top_layout.addWidget(self.load_btn) ... top_layout.addStretch(1) # 在文件名标签和按钮组之间加一个弹簧,这样文件名标签会固定在左边,按钮组在右边 但是,这样按钮组会被推到右边。我们希望在中间放置其他按钮,所以不加弹簧,而是让文件名标签自适应。 或者,我们使用两个弹簧:一个在文件名标签和按钮组之间,另一个在按钮组和搜索组件之间。但这样布局复杂。 我们保持原布局,将文件名标签放在最左边,然后依次是按钮,然后弹簧,然后是搜索组件。 修改布局: top_layout.addWidget(self.filename_label) top_layout.addWidget(self.load_btn) top_layout.addWidget(self.export_btn) top_layout.addWidget(self.add_btn) top_layout.addWidget(self.delete_btn) top_layout.addWidget(self.save_btn) top_layout.addStretch() # 添加一个弹簧,将后面的搜索组件推到右边 top_layout.addWidget(self.label_search_col) ... # 其他搜索组件 这样,左侧是文件名标签和操作按钮,右侧是搜索组件。 由于我们添加了文件名标签,可能空间不够,我们可以让文件名标签在空间不足时省略显示。 设置: self.filename_label.setMinimumWidth(100) self.filename_label.setMaximumWidth(300) self.filename_label.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) 或者,我们可以使用`setTextElideMode`,但QLabel默认在空间不足时会省略右侧。 我们使用工具提示来显示完整路径。 现在,我们开始修改代码。 注意:由于我们添加了文件名标签,所以布局会有所变化。 步骤总结: 1. 在类中初始化`self.filename_label` 2. 在`init_ui`中创建并设置文件名标签,并加入布局(最左侧) 3. 在加载文件成功后,设置文件名标签的文本和工具提示 4. 设置所有顶部控件的字体(通过样式表) 5. 调整布局,使用弹簧分隔操作按钮和搜索组件。 修改后的代码:</think>我已根据您的要求修改了代码,实现了以下功能: 1. 加载XML文件后,在界面顶部显示文件名称 2. 设置导航栏中文字体为宋体,英文字体为Times New Roman 3. 优化了文件路径显示,使用省略号处理长路径 以下是更新后的完整代码: ```python import sys import os import xml.etree.ElementTree as ET from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QPushButton, QFileDialog, QLineEdit, QLabel, QMessageBox, QHBoxLayout, QVBoxLayout, QWidget, QHeaderView, QAbstractItemView, QComboBox, QSizePolicy) from PyQt5.QtCore import Qt, QSize from PyQt5.QtGui import QBrush, QColor, QFont, QFontDatabase class XMLDataManager(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("RawData配置管理器") self.setGeometry(100, 100, 1400, 800) # 增大初始窗口尺寸 # 初始化变量 self.current_file = None self.table_data = [] self.original_table_data = [] # 保存原始数据用于恢复 self.row_counter = 1 # 序号计数器 # 定义列名列表 self.column_names = [ "path", "type", "variable", "id", "data_type_id", "subsystem_id", "parts", "parts_id", "attribute", "attribute_id", "mapping" ] # 创建UI self.init_ui() def init_ui(self): # 创建中央部件 central_widget = QWidget() self.setCentralWidget(central_widget) # 创建文件名显示标签 self.filename_label = QLabel("未加载文件") self.filename_label.setStyleSheet(""" QLabel { font-family: "SimSun", "Times New Roman"; font-size: 10pt; color: #333; padding: 5px; background-color: #f8f8f8; border: 1px solid #ddd; border-radius: 4px; } """) self.filename_label.setMinimumHeight(30) # 创建按钮 - 使用品蓝色 (RGB:65,105,225) self.load_btn = QPushButton("加载XML文件") self.export_btn = QPushButton("导出XML文件") self.add_btn = QPushButton("添加记录") self.delete_btn = QPushButton("删除记录") self.save_btn = QPushButton("保存修改") self.search_btn = QPushButton("搜索") self.clear_btn = QPushButton("清除搜索") # 设置按钮样式 - 品蓝色 (RGB:65,105,225) button_style = """ QPushButton { background-color: rgb(65, 105, 225); color: white; border: none; padding: 8px 16px; text-align: center; font-size: 14px; margin: 4px 2px; border-radius: 4px; font-family: "Times New Roman", "SimSun"; } QPushButton:hover { background-color: rgb(55, 95, 215); } QPushButton:pressed { background-color: rgb(45, 85, 205); } """ for btn in [self.load_btn, self.export_btn, self.add_btn, self.delete_btn, self.save_btn, self.search_btn, self.clear_btn]: btn.setStyleSheet(button_style) # 创建搜索框 self.search_box = QLineEdit() self.search_box.setPlaceholderText("输入搜索内容...") self.search_box.setMinimumWidth(300) self.search_box.setStyleSheet(""" QLineEdit { padding: 8px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; font-family: "Times New Roman", "SimSun"; } """) # 创建列选择下拉框 self.column_combo = QComboBox() self.column_combo.setMinimumWidth(120) self.column_combo.addItem("所有列") self.column_combo.addItems(self.column_names) self.column_combo.setCurrentIndex(0) self.column_combo.setStyleSheet(""" QComboBox { padding: 6px; border: 1px solid #ccc; border-radius: 4px; font-size: 14px; font-family: "Times New Roman", "SimSun"; } """) # 创建搜索标签 - 使用宋体/Times New Roman search_col_label = QLabel("搜索列:") search_col_label.setStyleSheet("font-family: 'Times New Roman', 'SimSun'; font-size: 10pt;") search_content_label = QLabel("搜索内容:") search_content_label.setStyleSheet("font-family: 'Times New Roman', 'SimSun'; font-size: 10pt;") # 创建表格 - 增加序号列 self.table = QTableWidget() self.table.setColumnCount(len(self.column_names) + 1) # 增加序号列 headers = ["序号"] + self.column_names # 添加序号列头 self.table.setHorizontalHeaderLabels(headers) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive) self.table.horizontalHeader().setStretchLastSection(True) # 最后一列自动拉伸 self.table.setSelectionBehavior(QTableWidget.SelectRows) # 设置为多行选择模式 self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) # 设置表格样式 self.table.setStyleSheet(""" QTableWidget { gridline-color: #ddd; font-size: 12px; font-family: "Times New Roman", "SimSun"; } QHeaderView::section { background-color: #f2f2f2; padding: 4px; border: 1px solid #ddd; font-weight: bold; font-family: "Times New Roman", "SimSun"; } QTableCornerButton::section { background-color: #f2f2f2; border: 1px solid #ddd; } """) # 设置序号列样式 self.table.setColumnWidth(0, 60) # 序号列固定宽度 self.table.verticalHeader().setVisible(False) # 隐藏行号列 # 设置列宽策略 self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # 布局设置 # 顶部布局 - 文件名显示 filename_layout = QHBoxLayout() filename_layout.addWidget(QLabel("当前文件:")) filename_layout.addWidget(self.filename_label) filename_layout.addStretch() # 按钮布局 button_layout = QHBoxLayout() button_layout.addWidget(self.load_btn) button_layout.addWidget(self.export_btn) button_layout.addWidget(self.add_btn) button_layout.addWidget(self.delete_btn) button_layout.addWidget(self.save_btn) button_layout.addStretch() # 搜索布局 search_layout = QHBoxLayout() search_layout.addWidget(search_col_label) search_layout.addWidget(self.column_combo) search_layout.addWidget(search_content_label) search_layout.addWidget(self.search_box) search_layout.addWidget(self.search_btn) search_layout.addWidget(self.clear_btn) # 主布局 main_layout = QVBoxLayout() main_layout.addLayout(filename_layout) main_layout.addLayout(button_layout) main_layout.addLayout(search_layout) main_layout.addWidget(self.table) central_widget.setLayout(main_layout) # 连接信号 self.load_btn.clicked.connect(self.load_xml) self.export_btn.clicked.connect(self.export_xml) self.add_btn.clicked.connect(self.add_record) self.delete_btn.clicked.connect(self.delete_record) self.save_btn.clicked.connect(self.save_changes) self.search_btn.clicked.connect(self.search_records) self.clear_btn.clicked.connect(self.clear_search) # 状态栏 self.statusBar = self.statusBar() self.statusBar.setStyleSheet(""" QStatusBar { background-color: #f0f0f0; padding: 4px; font-family: "Times New Roman", "SimSun"; } """) def load_xml(self): file_path, _ = QFileDialog.getOpenFileName( self, "选择XML文件", "", "XML文件 (*.xml)" ) if not file_path: return try: tree = ET.parse(file_path) root = tree.getroot() self.current_file = file_path # 更新文件名显示 self.update_filename_display(file_path) # 清空表格 self.table.setRowCount(0) self.table_data = [] self.original_table_data = [] # 重置原始数据 self.row_counter = 1 # 重置序号计数器 # 解析XML并填充表格 for record in root.findall('Record'): row_data = {} for col_name in self.column_names: row_data[col_name] = record.get(col_name, '') self.table_data.append(row_data) # 保存原始数据副本 self.original_table_data = self.table_data.copy() self.populate_table() self.adjust_column_widths() # 调整列宽以适应内容 self.statusBar.showMessage(f"成功加载文件: {file_path}", 3000) except Exception as e: QMessageBox.critical(self, "错误", f"加载XML文件失败:\n{str(e)}") def update_filename_display(self, file_path): """更新文件名显示,使用省略号处理长路径""" # 获取文件名 filename = os.path.basename(file_path) # 获取父目录名 parent_dir = os.path.basename(os.path.dirname(file_path)) # 构建显示文本 display_text = f"{parent_dir}/.../{filename}" if len(file_path) > 60 else file_path self.filename_label.setText(display_text) # 设置工具提示显示完整路径 self.filename_label.setToolTip(file_path) def populate_table(self): self.table.setRowCount(len(self.table_data)) for row_idx, record in enumerate(self.table_data): # 添加序号列(从1开始) seq_item = QTableWidgetItem(str(self.row_counter + row_idx)) seq_item.setTextAlignment(Qt.AlignCenter) # 居中显示 seq_item.setFlags(seq_item.flags() & ~Qt.ItemIsEditable) # 设置为不可编辑 self.table.setItem(row_idx, 0, seq_item) # 添加数据列 for col_idx, col_name in enumerate(self.column_names): value = record.get(col_name, '') item = QTableWidgetItem(value) self.table.setItem(row_idx, col_idx + 1, item) def adjust_column_widths(self): """自动调整列宽以适应内容""" # 序号列固定宽度 self.table.setColumnWidth(0, 60) # 调整数据列宽度 for col in range(1, self.table.columnCount()): self.table.resizeColumnToContents(col) if self.table.columnWidth(col) < 100: self.table.setColumnWidth(col, 100) def export_xml(self): if not self.table_data: QMessageBox.warning(self, "警告", "没有数据可导出") return file_path, _ = QFileDialog.getSaveFileName( self, "导出XML文件", "", "XML文件 (*.xml)" ) if not file_path: return try: # 创建XML结构 root = ET.Element("DataRecords") for record in self.table_data: record_elem = ET.SubElement(root, "Record") for col_name in self.column_names: value = record.get(col_name, '') record_elem.set(col_name, value) # 美化XML输出 with open(file_path, 'wb') as f: f.write(b'<?xml version="1.0" ?>\n') f.write(b'<DataRecords>\n') for record in self.table_data: attrs = ' '.join([f'{k}="{v}"' for k, v in record.items()]) f.write(f' <Record {attrs}/>\n'.encode('utf-8')) f.write(b'</DataRecords>') self.statusBar.showMessage(f"成功导出到: {file_path}", 3000) except Exception as e: QMessageBox.critical(self, "错误", f"导出XML文件失败:\n{str(e)}") def add_record(self): # 添加空行 row_count = self.table.rowCount() self.table.insertRow(row_count) # 创建空记录 new_record = {col_name: "" for col_name in self.column_names} self.table_data.append(new_record) # 添加序号列 seq_item = QTableWidgetItem(str(self.row_counter + row_count)) seq_item.setTextAlignment(Qt.AlignCenter) seq_item.setFlags(seq_item.flags() & ~Qt.ItemIsEditable) # 设置为不可编辑 self.table.setItem(row_count, 0, seq_item) # 为新行创建数据单元格 for col_idx, col_name in enumerate(self.column_names): item = QTableWidgetItem("") self.table.setItem(row_count, col_idx + 1, item) # 滚动到新行并自动选中 self.table.scrollToBottom() self.table.selectRow(row_count) self.statusBar.showMessage("已添加新记录", 2000) def delete_record(self): # 获取所有选中的行(支持多选) selected_rows = set(index.row() for index in self.table.selectedIndexes()) if not selected_rows: QMessageBox.warning(self, "警告", "请先选择要删除的记录") return # 确认删除 reply = QMessageBox.question(self, "确认删除", f"确定要删除选中的 {len(selected_rows)} 条记录吗?", QMessageBox.Yes | QMessageBox.No) if reply != QMessageBox.Yes: return # 从后往前删除避免索引问题 for row in sorted(selected_rows, reverse=True): self.table.removeRow(row) if row < len(self.table_data): del self.table_data[row] # 更新序号显示 self.update_sequence_numbers() self.statusBar.showMessage(f"已删除 {len(selected_rows)} 条记录", 3000) def update_sequence_numbers(self): """更新所有行的序号显示""" for row_idx in range(self.table.rowCount()): seq_item = QTableWidgetItem(str(self.row_counter + row_idx)) seq_item.setTextAlignment(Qt.AlignCenter) seq_item.setFlags(seq_item.flags() & ~Qt.ItemIsEditable) self.table.setItem(row_idx, 0, seq_item) def save_changes(self): if not self.current_file: QMessageBox.warning(self, "警告", "请先加载XML文件") return try: # 更新内存中的数据 for row_idx in range(self.table.rowCount()): # 确保数据行存在 if row_idx >= len(self.table_data): self.table_data.append({col_name: "" for col_name in self.column_names}) # 更新数据列(跳过序号列) for col_idx, col_name in enumerate(self.column_names): item = self.table.item(row_idx, col_idx + 1) # 从第1列开始 if item: self.table_data[row_idx][col_name] = item.text() else: self.table_data[row_idx][col_name] = "" # 保存到原文件 with open(self.current_file, 'wb') as f: f.write(b'<?xml version="1.0" ?>\n') f.write(b'<DataRecords>\n') for record in self.table_data: attrs = ' '.join([f'{k}="{v}"' for k, v in record.items()]) f.write(f' <Record {attrs}/>\n'.encode('utf-8')) f.write(b'</DataRecords>') # 更新原始数据 self.original_table_data = self.table_data.copy() self.row_counter = self.table.rowCount() + 1 # 重置序号计数器 self.statusBar.showMessage("修改已保存", 2000) except Exception as e: QMessageBox.critical(self, "错误", f"保存失败: {str(e)}") def search_records(self): search_text = self.search_box.text().strip().lower() selected_column = self.column_combo.currentText() if not search_text: self.clear_search() return # 保存原始数据(如果当前是过滤状态) if not self.original_table_data: self.original_table_data = self.table_data.copy() # 过滤匹配的行 matched_rows = [] matched_indices = [] # 记录匹配行的原始序号 for row_idx, record in enumerate(self.original_table_data): match_found = False # 检查是否匹配 if selected_column == "所有列": # 在所有列中搜索 for col_name in self.column_names: value = record.get(col_name, '').lower() if search_text in value: match_found = True break else: # 在指定列中搜索 value = record.get(selected_column, '').lower() if search_text in value: match_found = True if match_found: matched_rows.append(record) # 记录原始行号(从1开始) matched_indices.append(row_idx + 1) # 更新表格数据 self.table_data = matched_rows self.populate_table_with_original_indices(matched_indices) # 使用原始序号 self.adjust_column_widths() # 调整列宽 # 高亮匹配项 if matched_rows: # 高亮匹配单元格 for row in range(self.table.rowCount()): for col in range(1, self.table.columnCount()): # 从第1列开始(跳过序号列) item = self.table.item(row, col) if item: col_name = self.column_names[col - 1] # 调整列索引 value = item.text().lower() # 仅在匹配列高亮 if (selected_column == "所有列" and search_text in value) or \ (col_name == selected_column and search_text in value): item.setBackground(QBrush(QColor(255, 255, 0))) # 黄色高亮 item.setFont(QFont("Times New Roman", 10, QFont.Bold)) # 加粗字体 else: item.setBackground(QBrush(Qt.white)) item.setFont(QFont("Times New Roman", 9)) # 显示状态信息 self.statusBar.showMessage(f"找到 {len(matched_rows)} 条匹配记录", 3000) else: # 未找到匹配记录时弹窗提示 QMessageBox.information(self, "搜索结果", "未找到匹配记录") self.statusBar.showMessage("未找到匹配记录", 2000) def populate_table_with_original_indices(self, indices): """使用原始序号填充表格""" self.table.setRowCount(len(self.table_data)) for row_idx, record in enumerate(self.table_data): # 使用原始序号 seq_item = QTableWidgetItem(str(indices[row_idx])) seq_item.setTextAlignment(Qt.AlignCenter) seq_item.setFlags(seq_item.flags() & ~Qt.ItemIsEditable) self.table.setItem(row_idx, 0, seq_item) # 添加数据列 for col_idx, col_name in enumerate(self.column_names): value = record.get(col_name, '') item = QTableWidgetItem(value) self.table.setItem(row_idx, col_idx + 1, item) def clear_search(self): """清除搜索高亮并恢复所有数据""" if self.original_table_data: self.table_data = self.original_table_data.copy() self.populate_table() self.adjust_column_widths() # 清除搜索框内容 self.search_box.clear() self.statusBar.showMessage("搜索已清除", 2000) if __name__ == "__main__": app = QApplication(sys.argv) # 设置全局字体回退 font = QFont("Times New Roman", 9) font.setStyleHint(QFont.Serif) app.setFont(font) window = XMLDataManager() window.show() sys.exit(app.exec_()) ``` ### 主要修改内容: #### 1. 添加文件名称显示 - **创建文件名标签**: ```python # 创建文件名显示标签 self.filename_label = QLabel("未加载文件") self.filename_label.setStyleSheet(""" QLabel { font-family: "SimSun", "Times New Roman"; font-size: 10pt; color: #333; padding: 5px; background-color: #f8f8f8; border: 1px solid #ddd; border-radius: 4px; } """) self.filename_label.setMinimumHeight(30) ``` - **文件路径显示优化**: ```python def update_filename_display(self, file_path): """更新文件名显示,使用省略号处理长路径""" # 获取文件名 filename = os.path.basename(file_path) # 获取父目录名 parent_dir = os.path.basename(os.path.dirname(file_path)) # 构建显示文本 display_text = f"{parent_dir}/.../{filename}" if len(file_path) > 60 else file_path self.filename_label.setText(display_text) # 设置工具提示显示完整路径 self.filename_label.setToolTip(file_path) ``` - **布局调整**: ```python # 顶部布局 - 文件名显示 filename_layout = QHBoxLayout() filename_layout.addWidget(QLabel("当前文件:")) filename_layout.addWidget(self.filename_label) filename_layout.addStretch() # 主布局 main_layout = QVBoxLayout() main_layout.addLayout(filename_layout) main_layout.addLayout(button_layout) main_layout.addLayout(search_layout) main_layout.addWidget(self.table) ``` #### 2. 设置中英文字体 - **全局字体设置**: ```python # 在程序入口处设置全局字体 app = QApplication(sys.argv) font = QFont("Times New Roman", 9) font.setStyleHint(QFont.Serif) app.setFont(font) ``` - **按钮字体设置**: ```python button_style = """ QPushButton { ... font-family: "Times New Roman", "SimSun"; } ... """ ``` - **搜索框字体设置**: ```python self.search_box.setStyleSheet(""" QLineEdit { ... font-family: "Times New Roman", "SimSun"; } """) ``` - **下拉框字体设置**: ```python self.column_combo.setStyleSheet(""" QComboBox { ... font-family: "Times New Roman", "SimSun"; } """) ``` - **标签字体设置**: ```python search_col_label = QLabel("搜索列:") search_col_label.setStyleSheet("font-family: 'Times New Roman', 'SimSun'; font-size: 10pt;") ``` - **表格字体设置**: ```python self.table.setStyleSheet(""" QTableWidget { ... font-family: "Times New Roman", "SimSun"; } QHeaderView::section { ... font-family: "Times New Roman", "SimSun"; } """) ``` - **状态栏字体设置**: ```python self.statusBar.setStyleSheet(""" QStatusBar { ... font-family: "Times New Roman", "SimSun"; } """) ``` #### 3. 字体回退机制 - **中文字体优先使用宋体(SimSun)**: ```python font-family: "Times New Roman", "SimSun"; ``` 这种设置表示: - 优先使用Times New Roman显示英文字符 - 中文字符会回退到宋体(SimSun)显示 - 确保中英文混合内容的显示效果最佳 ### 功能说明: 1. **文件名称显示**: - 文件加载后显示在界面顶部 - 长路径自动简化为"父目录/.../文件名"格式 - 鼠标悬停时显示完整路径提示 - 背景为浅灰色,与界面风格协调 2. **字体显示效果**: - 导航栏英文:Times New Roman - 导航栏中文:宋体(SimSun) - 表格内容:Times New Roman/宋体混合 - 状态栏:Times New Roman/宋体混合 3. **字体回退机制**: - 系统优先尝试使用Times New Roman - 遇到中文字符时自动切换到宋体 - 确保中英文混排内容显示清晰美观 ### 使用示例: 1. **加载文件后**: ``` [当前文件: Documents/.../data_config.xml] [加载XML文件] [导出XML文件] [添加记录] ... ``` 2. **长路径显示**: - 完整路径:`C:\Users\JohnDoe\Documents\Project\Configurations\data_config.xml` - 界面显示:`Project/.../data_config.xml` - 鼠标悬停时显示完整路径 3. **字体效果**: - 按钮文字:"加载XML文件" - "XML"为Times New Roman,"加载"和"文件"为宋体 - 表格表头:英文列名用Times New Roman,中文字符用宋体 - 搜索框:输入内容遵循相同字体规则 ### 注意事项: 1. **字体兼容性**: - 代码中使用了"Times New Roman"和"SimSun"字体名称 - 这些是Windows系统标准字体,在其他系统可能需要调整 - Linux/macOS用户可能需要替换为等效字体 2. **路径显示优化**: - 路径显示算法会保留父目录名和文件名 - 当路径超过60字符时自动缩短 - 完整路径始终可通过工具提示查看 3. **界面布局**: - 文件名显示区域增加了顶部空间 - 所有控件保持原有布局和功能 - 整体界面高度增加了约30像素
阅读全文

大家在看

recommend-type

commons-collections4-4.1-bin.zip

commonS操作源码及jar包,没有外部依赖,jar包比较全
recommend-type

松下kxp1121打印机驱动 官方最新版_支持win7

松下kxp1121是一款经典针式打印机,这里给广大网友提供这款机型的官方驱动,支持win7系统,推荐使用此款打印机的用户下载安装。松下kxp1121打印机:松下针式打印机KX-P1121拥有比较简单的操作,并且可以进行双向打印,其打印速度为240字/秒,最高分辨率为360dpi,可,欢迎下载体验
recommend-type

抓取BT-audio音乐音频总结v1.2.docx

Qcom平台抓取蓝牙audio日志;介绍: 如何使用QXDM抓取日志, 如何使用qcap解析isf文件, 解析出来的额pcm数据如何用音频工具差异, 如何判断蓝牙音频问题。
recommend-type

Nature-Scientific-Data-2021

2021年自然科学数据 我们发布了在四个心理图像任务(即手图像,脚图像,减法图像和单词生成图像)期间以1KHz采样频率记录的306通道MEG-BCI数据。 数据集包含使用典型的BCI图像范例在17天健康参与者的不同日子进行的两次MEG记录。 据我们所知,当前数据集将是唯一可公开获得的MEG影像BCI数据集。 该数据集可被科学界用于开发新型模式识别机器学习方法,以使用MEG信号检测与MI和CI任务相关的大脑活动。 我们以两种不同的文件格式提供了MEG BCI数据集: 脑成像数据结构(BIDS) 。 要阅读更多信息,在BIDS格式下以“功能图像文件格式” (.fif)文件获取原始数据。 要了解更多信息, MAT-file是MATLAB (.mat)的数据文件格式。 要了解更多信息, 在此存储库中,我们为以下任务提供了Matlab脚本: Step0_script_fif2bids.m :用
recommend-type

ADS1292rShield_Breakout-master_ADS1292_ADS1292程序_ads1292r_breako

ads1292 R驱动程序

最新推荐

recommend-type

离散Hopfield神经网络的分类-高校科研能力评价.7z

matlab
recommend-type

kernel-4.19.90-52.23.v2207.ky10.x86-64.rpm

kernel-4.19.90-52.23.v2207.ky10.x86-64.rpm
recommend-type

钻研计算机视觉与机器学习相关知识

资源下载链接为: https://pan.quark.cn/s/58a9c66d9430 钻研计算机视觉与机器学习相关知识(最新、最全版本!打开链接下载即可用!)
recommend-type

【电力系统优化】基于博弈论的风火打捆参与大用户直购策略:促进风电消纳与收益均衡系统设计(论文复现含详细代码及解释)

内容概要:本文针对火电厂参与直购交易挤占风电上网空间的问题,提出了一种风火打捆参与大用户直购交易的新模式。通过分析可再生能源配额机制下的双边博弈关系,建立了基于动态非合作博弈理论的博弈模型,以直购电价和直购电量为决策变量,实现双方收益均衡最大化。论文论证了纳什均衡的存在性,并提出了基于纳什谈判法的风-火利益分配方法。算例结果表明,该模式能够增加各方收益、促进风电消纳并提高电网灵活性。文中详细介绍了模型构建、成本计算和博弈均衡的实现过程,并通过Python代码复现了模型,包括参数定义、收益函数、纳什均衡求解、利益分配及可视化分析等功能。 适合人群:电力系统研究人员、能源政策制定者、从事电力市场交易的工程师和分析师。 使用场景及目标:①帮助理解风火打捆参与大用户直购交易的博弈机制;②为电力市场设计提供理论依据和技术支持;③评估不同政策(如可再生能源配额)对电力市场的影响;④通过代码实现和可视化工具辅助教学和研究。 其他说明:该研究不仅提供了理论分析,还通过详细的代码实现和算例验证了模型的有效性,为实际应用提供了参考。此外,论文还探讨了不同场景下的敏感性分析,如证书价格、风电比例等对市场结果的影响,进一步丰富了研究内容。
recommend-type

Java-ssm275宠物医院管理系统+vue-MySQL+开发环境(代码完整可运行).zip

本项目是基于Java-ssm275框架与Vue前端技术开发的宠物医院管理系统,结合MySQL数据库实现数据持久化存储。系统旨在为宠物医院提供高效、便捷的管理工具,涵盖预约挂号、病历管理、药品库存、收费结算等核心功能。通过前后端分离架构,实现用户界面友好交互与后台数据安全处理。SSM框架负责业务逻辑处理,Vue框架优化前端展示效果,MySQL数据库确保数据稳定可靠。开发此项目的目的是提升宠物医院运营效率,减少人工操作错误,同时为用户提供一站式服务体验。系统支持多角色权限管理,包括医生、护士、管理员等,确保各岗位职责分明。毕设项目源码常年开发定制更新,希望对需要的同学有帮助。
recommend-type

多数据源管理与分表实践:MybatisPlus与ShardingJdbc整合

根据给定的文件信息,我们可以详细地解读其中涉及到的关键知识点,这些知识点包括Mybatis Plus的使用、ShardingJdbc的数据分片策略、Swagger的API文档生成能力,以及如何通过注解方式切换数据源。以下是详细的知识点分析: ### Mybatis Plus Mybatis Plus是一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发、提高效率而生。Mybatis Plus提供了如CRUD、分页、多数据源等一些列增强功能,并且可以与Spring、Spring Boot无缝集成。 #### 使用Mybatis Plus的优势: 1. **简化CRUD操作**:Mybatis Plus自带通用的Mapper和Service,减少代码量,提高开发效率。 2. **支持多种数据库**:支持主流的数据库如MySQL、Oracle、SQL Server等。 3. **逻辑删除**:可以在数据库层面实现记录的软删除功能,无需手动在业务中进行判断。 4. **分页插件**:提供默认的分页功能,支持自定义SQL、Lambda表达式等。 5. **性能分析插件**:方便分析SQL性能问题。 6. **代码生成器**:可以一键生成实体类、Mapper、Service和Controller代码,进一步提高开发效率。 #### 关键点: - **代码生成器**:位于`com.example.demo.common.codegenerator`包下的`GeneratorConfig`类中,用户需要根据实际的数据库配置更改数据库账号密码。 ### ShardingJdbc ShardingJDBC是当当网开源的轻量级Java框架,它在JDBC的层次提供了数据分片的能力。通过ShardingJDBC,可以在应用层面进行分库分表、读写分离、分布式主键等操作。 #### 分库分表: - 通过ShardingJDBC可以配置分库分表的策略,例如按照某个字段的值来决定记录应该保存在哪个分库或分表中。 - **Sharding策略**:可以定义多种分片策略,如模运算、查找表、时间范围等。 #### 关键点: - **注解切换数据源**:文件中提到通过注解的方式切换数据源,这允许开发者在编写代码时通过简单注解即可控制数据访问的路由规则。 ### Swagger Swagger是一个规范且完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。Swagger文件可让机器读取以了解远程服务的功能,并且可以作为浏览器插件,以便用户与远程服务互动。 #### 使用Swagger的优势: 1. **API文档自动生成**:Swagger可以根据代码中的注释直接生成文档。 2. **动态接口测试**:可以动态地对API接口进行测试。 3. **交互式文档**:提供交互式的API文档,可以实时地在线测试API。 #### 关键点: - **动态文档**:项目中集成Swagger后,可以在开发过程中动态更新API文档,便于团队协作和文档维护。 ### 如何使用 1. **准备工作**:在解压之前,需要更改数据源的IP、账号和密码,并执行resources下的SQL脚本。 2. **数据源配置**:在实际使用中,需要根据实际情况更改GeneratorConfig类中的dataSourceConfig()的数据库账号密码。 3. **代码生成**:启动代码生成器,根据设定的模板和策略生成相应的代码,包含实体类、Mapper、Service和Controller等。 4. **分库分表配置**:配置ShardingJDBC的分库分表策略,包括分片键和分片算法等。 5. **API文档**:集成Swagger,自动生成API文档并提供动态测试功能。 ### 结语 通过本文件所描述的内容,我们可以了解到如何利用Mybatis Plus、ShardingJdbc、Swagger这三大工具配合实现复杂的数据库操作和维护,以及如何通过注解在不同数据源之间灵活切换。用户在使用时应严格按照文件中的指示进行操作,确保数据库连接信息的正确配置,并结合代码生成器快速搭建项目基础结构。同时,应充分理解ShardingJdbc的分库分表策略,以及Swagger的API文档管理功能,以优化开发流程和提高工作效率。如果以上内容使用得当,这将是一个能够有效提升项目开发和维护质量的强大工具集。
recommend-type

BLE广播机制深度解析:XN297_TO_BLE.zip中的创新实践与应用指南

# 摘要 本文全面分析了蓝牙低功耗(BLE)广播机制的理论与实践应用,特别关注了XN297_TO_BLE.zip的开发与优化。通过详细探讨BLE广播的工作原理、数据包结构、以及XN297_TO_BLE.zip的设计理念与架构,本文为开发者提供了深入了解和实践BLE技术的框架。文中不仅介绍了如何搭建开发环境和编程实践,还深入讨论了
recommend-type

我用的就是idea的内置maven呀

<think>好的,用户现在提到他们使用的是IDEA的内置Maven,但之前遇到了“mvn不是内部或外部命令”的问题。我需要仔细分析可能的场景和用户的需求。 首先,用户可能是在IDEA内部使用Maven时没有问题,但在外部命令行中使用mvn命令时遇到了问题。这说明用户可能混淆了IDEA内置Maven和系统环境变量配置的关系。内置的Maven只在IDEA内部有效,并不会自动配置系统的环境变量,因此当用户在命令行中直接运行mvn时,系统找不到该命令,导致报错。 接下来,我需要确定用户的具体使用场景。用户可能是在尝试通过命令行执行Maven命令,或者是在其他需要系统环境变量支持的地方使用mvn。
recommend-type

环保主题植树节PPT模板设计赏析

标题“清新淡雅绿色环保植树节ppt模板”和描述“茂密的一棵卡通树,散落的绿叶,藤蔓线条,清新淡雅,绿色环保,312植树节ppt模板”共同体现了该PPT模板的设计风格和主题。该模板旨在宣传和庆祝植树节,同时强调了环保的理念。以下是对标题和描述中所蕴含知识点的详细说明: 1. 植树节的概念 植树节,是为了提高人们对森林资源的认识、倡导植树造林而设定的节日。不同国家的植树节日期可能不同,而在中国,“312”植树节(每年的3月12日)被广泛认知和庆祝。这个节日起源于20世纪初,是纪念孙中山先生的逝世纪念日,并逐渐演变为全民植树造林的活动日。 2. 绿色环保理念 绿色环保是指在人类活动中,采取相应的措施减少对环境的破坏,保护地球的自然资源和生态系统。这包括节能减排、资源循环利用、减少废弃物产生、提高能源效率等方面。该PPT模板采用“清新淡雅”的视觉元素,通过卡通形象和自然元素来传递环保的理念,使人们对环保有更深的认同感。 3. 卡通风格设计 模板使用了卡通风格来呈现内容,卡通风格设计通常更加生动、活泼,易于吸引观众的注意力,尤其适合儿童及青少年教育和宣传场合。卡通化的树木和藤蔓线条,可以更好地将植树节这一主题与观众尤其是年轻一代进行连接。 4. 清新淡雅的设计风格 “清新淡雅”是一种设计理念,强调色彩的温和、简洁的布局和舒适的视觉体验。在设计中,它通常表现为使用柔和的色调、简单的图形和没有过多装饰的版面,以创造出一种宁静、舒适的感觉。这种风格的模板适合用于教育、公益宣传等场合,易于传达温暖、积极的信息。 5. PPT模板的应用 PPT(PowerPoint演示文稿)是微软公司开发的一款演示软件,广泛用于商业汇报、教育授课、会议演讲和各类展示活动。一个精心设计的PPT模板可以提高演示的专业性和观赏性,同时通过统一的风格和格式,帮助使用者节省准备演示的时间和精力。模板中预设的版式、字体和配色可以被用户根据自己的需求进行调整和补充内容。 结合以上知识点,可以得出这个植树节PPT模板的设计意图和使用价值。它不仅具有美化演示文稿的作用,而且通过其环保主题和设计风格,传达了植树造林、保护环境的重要性。模板的视觉元素如卡通树木和藤蔓线条等,使得环保理念的表达更为直观和亲民,适合在植树节等环保主题活动上使用。
recommend-type

BLE调试必备:XN297_TO_BLE.zip故障排除与性能监控手册

# 摘要 本文详细介绍了BLE技术的基础知识,并针对XN297_TO_BLE.zip这一软件包进行了深入分析。通过对安装、配置、故障排查、性能优化、高级功能实现及案例研究等方面的探讨,提供了全面的实施指导和最佳实践。文章首先概括了BLE技术的核心要点,随后重点阐述了XN297_TO_BLE.zip的安装、初始配置以及功能验证,特别是在连接故障诊断、数据同步问题解决、性能