Charts Factory 鼠标悬停显示数值信息实现详解

Charts Factory 鼠标悬停显示数值信息实现详解

charts_factory.py中,鼠标悬停显示数值信息的功能通过 PySide6 的信号槽机制和工具提示系统实现。以下是详细的实现原理和流程:

1. 核心实现机制

1.1 信号连接机制

在创建每种图表类型时,都会将图表系列的hovered信号连接到对应的处理函数:

# 折线图信号连接(line_chart.py:102)series.hovered.connect(self.on_line_hovered)# 柱状图信号连接(bar_chart.py:208) - 使用lambda传递额外参数bar_set.hovered.connect(lambdastatus,index,bs=bar_set:self.on_bar_hovered(status,index,bs))

1.2 事件处理函数

每种图表类型都有对应的悬停处理函数,这些函数负责:

  • 接收悬停事件参数
  • 解析数据信息
  • 生成格式化的工具提示
  • 控制工具提示的显示/隐藏

2. 具体实现流程

2.1 通用流程

  1. 信号触发:鼠标悬停在图表数据点上时,触发hovered信号
  2. 事件处理:对应的处理函数接收信号参数(不同图表类型参数不同)
  3. 数据解析:从参数中提取需要显示的数据(如坐标、数值、标签等)
  4. HTML生成:创建包含样式和数据的HTML工具提示内容
  5. 显示提示:使用QToolTip.showText()显示工具提示

2.2 不同图表类型的实现差异

折线图/曲线图/面积图
defon_line_hovered(self,point,state):ifstateandisinstance(point,QPointF):tooltip_html=f""" <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;"> <div style="font-weight: bold; margin-bottom: 4px;">数据点</div> <div>X: <span style="color: #3498db;">{point.x():.1f}</span></div> <div>Y: <span style="color: #2ecc71;">{point.y():.1f}</span></div> </div> """QToolTip.showText(QCursor.pos(),tooltip_html,w=None,msecShowTime=3000)else:QToolTip.hideText()
  • 参数point(数据点坐标,QPointF类型)、state(悬停状态,布尔值)
  • 特点:直接显示X/Y坐标值,使用不同颜色区分X/Y值
柱状图
defon_bar_hovered(self,*args):iflen(args)==3:# Pattern: (status, index, barset) - from lambda connectionstatus,index,barset=argsifstatusandbarsetisnotNoneandindex>=0:tooltip_html=f""" <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;"> <div style="font-weight: bold; margin-bottom: 4px;">{barset.label()}</div> <div>数值: <span style="color: #f39c12;">{barset.at(index)}</span></div> </div> """QToolTip.showText(QCursor.pos(),tooltip_html,w=None,msecShowTime=3000)else:QToolTip.hideText()
  • 参数status(悬停状态)、index(数据索引)、barset(柱状图数据集)
  • 特点:使用lambda函数传递额外的barset参数,显示数据集标签和具体数值
饼图
defon_pie_hovered(self,slice,state):ifstateandsliceisnotNone:tooltip_html=f""" <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;"> <div style="font-weight: bold; margin-bottom: 4px;">{slice.label()}</div> <div>数值: <span style="color: #9b59b6;">{slice.value():.1f}</span></div> <div>百分比: <span style="color: #1abc9c;">{slice.percentage()*100:.1f}%</span></div> </div> """QToolTip.showText(QCursor.pos(),tooltip_html,w=None,msecShowTime=3000)slice.setExploded(True)# 饼图切片突出显示else:QToolTip.hideText()ifsliceisnotNone:slice.setExploded(False)
  • 参数slice(饼图切片对象)、state(悬停状态)
  • 特点:显示切片标签、数值和百分比,并实现切片突出显示效果

3. 技术特点

3.1 HTML样式的工具提示

  • 使用HTML和内联CSS创建美观的工具提示
  • 支持字体、颜色、布局等样式自定义
  • 不同类型的数据使用不同颜色区分,提高可读性

3.2 自适应不同图表类型

  • 针对不同图表类型的hovered信号参数差异,设计了不同的处理逻辑
  • 柱状图使用lambda函数解决参数传递问题
  • 饼图实现了额外的视觉反馈(切片突出)

3.3 性能优化

  • 仅在悬停状态有效时才生成和显示工具提示
  • 设置工具提示显示时间为3000毫秒,避免长时间占用屏幕
  • 鼠标离开时立即隐藏工具提示

4. 实现优势

  1. 代码复用:相似图表类型的悬停处理函数可以复用(如曲线图和面积图复用折线图的处理函数)
  2. 扩展性强:新增图表类型时,只需添加对应的悬停处理函数即可
  3. 用户体验好:美观的工具提示提供了清晰的数据信息,提升了交互体验
  4. 灵活性高:支持自定义工具提示的样式和内容

通过这种实现方式,Charts Factory 提供了一致且美观的鼠标悬停数据显示功能,增强了图表的交互性和可读性。

```python #!/usr/bin/env python3 """ Charts Factory Module Provides a factory for creating beautiful charts with consistent styling """ import sys import random from PySide6.QtWidgets import QWidget, QVBoxLayout, QToolTip from PySide6.QtCore import Qt, QPointF from PySide6.QtGui import QColor, QPen, QBrush, QFont, QLinearGradient, QPainter, QCursor from PySide6 import QtCharts class ChartsFactory: """ Factory class for creating consistent, beautifully styled charts """ # Default theme colors - Tech style THEME_COLORS = { "background": "#0A0E27", # Dark blue-black background "primary": "#00C8FF", # Bright cyan - main color "secondary": "#6B5B95", # Deep purple "accent1": "#2E8B57", # Dark green "accent2": "#50C878", # Medium green "accent3": "#1E3A8A", # Deep blue "grid": "#1E3A8A", # Dark blue grid lines "text": "#E0E0E0" # Light gray text for readability } # Default color palette for multiple series (e.g., bar charts) - Tech style COLOR_PALETTE = [ "#00C8FF", # Bright cyan - main color "#1E90FF", # Deep blue "#4169E1", # Royal blue "#6A5ACD", # Slate blue "#4B0082", # Indigo "#32CD32", # Lime green (accent) "#20B2AA", # Light sea green "#4682B4", # Steel blue "#708090", # Slate gray "#87CEFA" # Light sky blue ] def __init__(self): """Initialize the charts factory""" pass def create_chart_view(self, chart_type, data, title, **kwargs): """ Create a chart view based on the given type Args: chart_type (str): Type of chart ("line", "spline", "area", "bar", "pie", "scatter", "boxplot") data: Chart data title (str): Chart title **kwargs: Additional parameters Returns: QtCharts.QChartView: Configured chart view """ chart_type_map = { "line": self.create_line_chart, "spline": self.create_spline_chart, "area": self.create_area_chart, "bar": self.create_bar_chart, "horizontal_bar": self.create_horizontal_bar_chart, "pie": self.create_pie_chart, "scatter": self.create_scatter_chart, "boxplot": self.create_boxplot_chart } if chart_type not in chart_type_map: raise ValueError(f"Unsupported chart type: {chart_type}") return chart_type_map[chart_type](data, title, **kwargs) def create_line_chart(self, data, title, **kwargs): """Create a line chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create series series = QtCharts.QLineSeries() series.setName(kwargs.get("series_name", "Data")) # Set series style pen_color = QColor(kwargs.get("color", self.THEME_COLORS["primary"])) pen_width = kwargs.get("line_width", 2) series.setPen(QPen(pen_color, pen_width)) # Add data for x, y in data: series.append(x, y) # Add series to chart chart.addSeries(series) # Connect hovered signal series.hovered.connect(self.on_line_hovered) # Create and configure axes self._setup_axes(chart, series, **kwargs) # Create chart view return self._create_chart_view(chart) def create_spline_chart(self, data, title, **kwargs): """Create a spline chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create series series = QtCharts.QSplineSeries() series.setName(kwargs.get("series_name", "Data")) # Set series style pen_color = QColor(kwargs.get("color", self.THEME_COLORS["secondary"])) pen_width = kwargs.get("line_width", 2) series.setPen(QPen(pen_color, pen_width)) # Add data for x, y in data: series.append(x, y) # Add series to chart chart.addSeries(series) # Connect hovered signal series.hovered.connect(self.on_spline_hovered) # Create and configure axes self._setup_axes(chart, series, **kwargs) # Create chart view return self._create_chart_view(chart) def create_area_chart(self, data, title, **kwargs): """Create an area chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create line series for area boundaries line_series = QtCharts.QLineSeries() line_series.setName(kwargs.get("series_name", "Data")) # Add data for x, y in data: line_series.append(x, y) # Create area series with the line series and a base line area_series = QtCharts.QAreaSeries(line_series) # Set area style pen_color = QColor(kwargs.get("color", self.THEME_COLORS["primary"])) area_series.setPen(QPen(pen_color, 2)) # Create gradient fill gradient = QLinearGradient() gradient.setStart(0, 0) gradient.setFinalStop(0, 1) gradient.setColorAt(0, QColor(pen_color.red(), pen_color.green(), pen_color.blue(), 100)) gradient.setColorAt(1, QColor(pen_color.red(), pen_color.green(), pen_color.blue(), 0)) area_series.setBrush(gradient) # Add series to chart chart.addSeries(area_series) # Connect hovered signal area_series.hovered.connect(self.on_area_hovered) # Create and configure axes self._setup_axes(chart, area_series, **kwargs) # Create chart view return self._create_chart_view(chart) def create_bar_chart(self, data, title, **kwargs): """Create a vertical bar chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create bar series series = QtCharts.QBarSeries() # Create bar sets for i, (set_name, values) in enumerate(data.items()): bar_set = QtCharts.QBarSet(set_name) bar_set.append(values) # Set bar set style with different colors if "color" in kwargs: # User specified a single color for all bars pen_color = QColor(kwargs["color"]) else: # Use color from palette based on index pen_color = QColor(self.COLOR_PALETTE[i % len(self.COLOR_PALETTE)]) bar_set.setPen(QPen(pen_color)) bar_set.setBrush(QColor(pen_color)) # Connect hovered signal for this bar set using lambda to pass bar_set reference bar_set.hovered.connect(lambda status, index, bs=bar_set: self.on_bar_hovered(status, index, bs)) series.append(bar_set) # Add series to chart chart.addSeries(series) # Remove incorrect signal connection pass # Create and configure axes self._setup_axes(chart, series, **kwargs) # Create chart view return self._create_chart_view(chart) def create_horizontal_bar_chart(self, data, title, **kwargs): """Create a horizontal bar chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create bar series series = QtCharts.QHorizontalBarSeries() # Create bar sets for i, (set_name, values) in enumerate(data.items()): bar_set = QtCharts.QBarSet(set_name) bar_set.append(values) # Set bar set style with different colors if "color" in kwargs: # User specified a single color for all bars pen_color = QColor(kwargs["color"]) else: # Use color from palette based on index pen_color = QColor(self.COLOR_PALETTE[i % len(self.COLOR_PALETTE)]) bar_set.setPen(QPen(pen_color)) bar_set.setBrush(QColor(pen_color)) # Connect hovered signal for this bar set using lambda to pass bar_set reference bar_set.hovered.connect(lambda status, index, bs=bar_set: self.on_bar_hovered(status, index, bs)) series.append(bar_set) # Add series to chart chart.addSeries(series) # Create and configure axes (swapped for horizontal bar chart) kwargs["horizontal"] = True self._setup_axes(chart, series, **kwargs) # Create chart view return self._create_chart_view(chart) def create_pie_chart(self, data, title, **kwargs): """Create a pie chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create pie series series = QtCharts.QPieSeries() # Add data slices using the tech-style color palette for i, (label, value) in enumerate(data.items()): slice = series.append(label, value) slice_color = QColor(self.COLOR_PALETTE[i % len(self.COLOR_PALETTE)]) slice.setBrush(slice_color) slice.setPen(QPen(QColor(self.THEME_COLORS["background"]), 2)) slice.setLabelBrush(QColor(self.THEME_COLORS["text"])) # Make first slice exploded if requested if kwargs.get("explode_first", True) and i == 0: slice.setExploded(True) slice.setLabelVisible(True) # Connect hovered signal for the pie series series.hovered.connect(self.on_pie_hovered) # Add series to chart chart.addSeries(series) # Create chart view return self._create_chart_view(chart) def create_scatter_chart(self, data, title, **kwargs): """Create a scatter chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create scatter series series = QtCharts.QScatterSeries() series.setName(kwargs.get("series_name", "Data")) # Set scatter style pen_color = QColor(kwargs.get("color", self.THEME_COLORS["primary"])) series.setColor(pen_color) series.setMarkerSize(kwargs.get("marker_size", 8)) # Add data for x, y in data: series.append(x, y) # Add series to chart chart.addSeries(series) # Connect hovered signal series.hovered.connect(self.on_scatter_hovered) # Create and configure axes self._setup_axes(chart, series, **kwargs) # Create chart view return self._create_chart_view(chart) def create_boxplot_chart(self, data, title, **kwargs): """Create a box plot chart""" # Create chart chart = QtCharts.QChart() self._setup_chart(chart, title) # Create box plot series series = QtCharts.QBoxPlotSeries() series.setName(kwargs.get("series_name", "Data")) # Set box plot style pen_color = QColor(kwargs.get("color", self.THEME_COLORS["primary"])) series.setPen(QPen(pen_color, 1)) series.setBrush(QColor(pen_color.red(), pen_color.green(), pen_color.blue(), 100)) # Connect hovered signal for the box plot series series.hovered.connect(self.on_boxplot_hovered) # Add data for label, box_data in data.items(): # box_data should be [min, lower_quartile, median, upper_quartile, max] # Correct order: min, lower_quartile, median, upper_quartile, max box = QtCharts.QBoxSet(box_data[0], box_data[1], box_data[2], box_data[3], box_data[4], label) series.append(box) # Add series to chart chart.addSeries(series) # Create and configure axes self._setup_axes(chart, series, **kwargs) # Create chart view return self._create_chart_view(chart) def _setup_chart(self, chart, title): """Setup common chart properties""" # Set chart background chart.setBackgroundBrush(QColor(self.THEME_COLORS["background"])) # Set chart title chart.setTitle(title) chart.setTitleBrush(QColor(self.THEME_COLORS["text"])) # Set animation options chart.setAnimationOptions(QtCharts.QChart.SeriesAnimations) return chart def _setup_axes(self, chart, series, **kwargs): """Setup common axis properties""" horizontal_bar = kwargs.get("horizontal", False) # Create X and Y axes based on chart type if isinstance(series, (QtCharts.QBarSeries, QtCharts.QHorizontalBarSeries)): # Bar charts typically use category axes for one dimension if horizontal_bar: axis_x = QtCharts.QValueAxis() axis_y = QtCharts.QCategoryAxis() else: axis_x = QtCharts.QCategoryAxis() axis_y = QtCharts.QValueAxis() else: # Most charts use value axes axis_x = QtCharts.QValueAxis() axis_y = QtCharts.QValueAxis() # Configure X axis axis_x.setTitleText(kwargs.get("x_axis_title", "X Axis")) axis_x.setLabelFormat(kwargs.get("x_label_format", "%.0f")) axis_x.setTickCount(kwargs.get("x_tick_count", 11)) if "x_min" in kwargs and "x_max" in kwargs: axis_x.setRange(kwargs["x_min"], kwargs["x_max"]) # Configure Y axis axis_y.setTitleText(kwargs.get("y_axis_title", "Y Axis")) axis_y.setLabelFormat(kwargs.get("y_label_format", "%.0f")) axis_y.setTickCount(kwargs.get("y_tick_count", 11)) if "y_min" in kwargs and "y_max" in kwargs: axis_y.setRange(kwargs["y_min"], kwargs["y_max"]) # Apply styles to both axes for axis in [axis_x, axis_y]: # Set axis colors axis.setLabelsColor(QColor(self.THEME_COLORS["text"])) axis.setTitleBrush(QColor(self.THEME_COLORS["text"])) # Set grid line style grid_pen = QPen(QColor(self.THEME_COLORS["grid"]), 0.5) axis.setGridLinePen(grid_pen) # Set axis line style axis_pen = QPen(QColor(self.THEME_COLORS["text"]), 1.0) axis.setLinePen(axis_pen) # Add axes to chart if horizontal_bar: chart.addAxis(axis_x, Qt.AlignBottom) chart.addAxis(axis_y, Qt.AlignLeft) else: chart.addAxis(axis_x, Qt.AlignBottom) chart.addAxis(axis_y, Qt.AlignLeft) # Attach series to axes series.attachAxis(axis_x) series.attachAxis(axis_y) return axis_x, axis_y def _create_chart_view(self, chart): """Create a chart view with common settings""" chart_view = QtCharts.QChartView(chart) chart_view.setRenderHint(QPainter.Antialiasing) return chart_view def on_line_hovered(self, point, state): """折线图数据点悬停处理""" if state and isinstance(point, QPointF): tooltip_html = f""" <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;"> <div style="font-weight: bold; margin-bottom: 4px;">数据点</div> <div>X: <span style="color: #3498db;">{point.x():.1f}</span></div> <div>Y: <span style="color: #2ecc71;">{point.y():.1f}</span></div> </div> """ QToolTip.showText( QCursor.pos(), tooltip_html, w=None, msecShowTime=3000 ) else: QToolTip.hideText() def on_spline_hovered(self, point, state): """曲线图表数据点悬停处理""" self.on_line_hovered(point, state) def on_area_hovered(self, point, state): """面积图表数据点悬停处理""" self.on_line_hovered(point, state) def on_bar_hovered(self, *args): """柱状图悬停处理""" # Handle different parameter patterns if len(args) == 3: # Pattern: (status, index, barset) - from lambda connection status, index, barset = args if status and barset is not None and index >= 0: tooltip_html = f""" <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;"> <div style="font-weight: bold; margin-bottom: 4px;">{barset.label()}</div> <div>数值: <span style="color: #f39c12;">{barset.at(index)}</span></div> </div> """ QToolTip.showText( QCursor.pos(), tooltip_html, w=None, msecShowTime=3000 ) else: QToolTip.hideText() else: # Fallback if we don't recognize the pattern QToolTip.hideText() def on_pie_hovered(self, slice, state): """饼图悬停处理""" if state and slice is not None: tooltip_html = f""" <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;"> <div style="font-weight: bold; margin-bottom: 4px;">{slice.label()}</div> <div>数值: <span style="color: #9b59b6;">{slice.value():.1f}</span></div> <div>百分比: <span style="color: #1abc9c;">{slice.percentage()*100:.1f}%</span></div> </div> """ QToolTip.showText( QCursor.pos(), tooltip_html, w=None, msecShowTime=3000 ) slice.setExploded(True) else: QToolTip.hideText() if slice is not None: slice.setExploded(False) def on_scatter_hovered(self, point, state): """散点图悬停处理""" if state and isinstance(point, QPointF): tooltip_html = f""" <div style="font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;"> <div style="font-weight: bold; margin-bottom: 4px;">数据点</div> <div>X: <span style="color: #3498db;">{point.x():.1f}</span></div> <div>Y: <span style="color: #e74c3c;">{point.y():.1f}</span></div> </div> """ QToolTip.showText( QCursor.pos(), tooltip_html, w=None, msecShowTime=3000 ) else: QToolTip.hideText() def on_boxplot_hovered(self, state, index, barset): """箱线图悬停处理""" if state and barset is not None and index >= 0: QToolTip.showText( QCursor.pos(), f"组: {barset.label()}", w=None, msecShowTime=3000 ) else: QToolTip.hideText() def create_chart_tab(self, chart_view, tab_name): """Create a tab with the chart view""" tab = QWidget() layout = QVBoxLayout(tab) layout.addWidget(chart_view) return tab # Example usage def main(): """Example demonstrating the charts factory""" from PySide6.QtWidgets import QApplication, QMainWindow, QTabWidget, QVBoxLayout, QWidget app = QApplication(sys.argv) # 设置QToolTip样式 app.setStyleSheet(""" QToolTip { background-color: #2c3e50; color: #ecf0f1; border: 1px solid #34495e; border-radius: 4px; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-size: 12px; padding: 8px; opacity: 0.9; } """) # Create main window window = QMainWindow() window.setWindowTitle("Charts Factory Demo") window.setGeometry(100, 100, 1000, 700) # Create central widget and layout central_widget = QWidget() main_layout = QVBoxLayout(central_widget) window.setCentralWidget(central_widget) # Create tab widget tab_widget = QTabWidget() main_layout.addWidget(tab_widget) # Create charts factory factory = ChartsFactory() # Create sample data line_data = [(x, random.randint(0, 100)) for x in range(20)] bar_data = {"Product A": [15, 20, 35, 25, 40], "Product B": [20, 25, 30, 35, 45]} pie_data = {"Company A": 35, "Company B": 25, "Company C": 20, "Company D": 15, "Others": 5} scatter_data = [(random.uniform(0, 100), random.uniform(0, 100)) for _ in range(50)] boxplot_data = { "Set 1": [10, 20, 30, 40, 50], "Set 2": [15, 25, 35, 45, 55], "Set 3": [5, 15, 25, 35, 45] } try: # Create charts one by one with proper error handling print("Creating charts...") # 创建简化的数据以减少资源消耗 simplified_line_data = line_data[:10] # 减少数据点数量 simplified_scatter_data = scatter_data[:20] # 减少散点数量 # 所有支持的图表类型 - 按照资源消耗从低到高排序 all_chart_types = [ ("line", simplified_line_data, "Line Chart"), ("bar", bar_data, "Bar Chart"), ("pie", pie_data, "Pie Chart"), ("scatter", simplified_scatter_data, "Scatter Chart") ] # 扩展图表类型列表,展示所有可用类型(根据系统资源自动调整) extended_chart_types = [ ("spline", simplified_line_data, "Spline Chart"), ("area", simplified_line_data, "Area Chart"), ("horizontal_bar", bar_data, "Horizontal Bar Chart"), ("boxplot", boxplot_data, "Box Plot Chart") ] # 创建图表类型示例 charts_created = 0 max_charts = 4 # 限制同时显示的图表数量以避免资源耗尽 print("=== 基本图表类型示例 ===") for chart_type, data, title in all_chart_types: if charts_created >= max_charts: break print(f"Creating {chart_type} chart...") try: chart_view = factory.create_chart_view(chart_type, data, title) tab = factory.create_chart_tab(chart_view, title) tab_widget.addTab(tab, title) charts_created += 1 print(f"✓ {title} created successfully") except Exception as e: print(f"✗ Error creating {title}: {e}") import traceback traceback.print_exc() # 如果还有资源,创建更多图表类型 print(f"\n=== 扩展图表类型示例 (已创建 {charts_created}/{max_charts} 个) ===") for chart_type, data, title in extended_chart_types: if charts_created >= max_charts: print(f"已达到最大图表数量 ({max_charts}),跳过 {title}") continue print(f"Creating {chart_type} chart...") try: chart_view = factory.create_chart_view(chart_type, data, title) tab = factory.create_chart_tab(chart_view, title) tab_widget.addTab(tab, title) charts_created += 1 print(f"✓ {title} created successfully") except Exception as e: print(f"✗ Error creating {title}: {e}") import traceback traceback.print_exc() print(f"\n共创建了 {charts_created} 个图表类型示例") # 在文档中列出所有可用的图表类型 print("\n=== 所有支持的图表类型 ===") all_supported_types = [ "line (折线图)", "spline (曲线图表)", "area (面积图表)", "bar (条形图)", "horizontal_bar (水平条形图)", "pie (饼图)", "scatter (散点图)", "boxplot (箱线图)" ] for i, chart_type in enumerate(all_supported_types, 1): print(f"{i}. {chart_type}") # Show window window.show() print("Application started successfully!") return app.exec() except Exception as e: print(f"Error: {e}") import traceback traceback.print_exc() return 1 if __name__ == "__main__": main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1178533.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手机共享位置的技术原理解析

在社交软件、出行平台和家庭守护类应用中&#xff0c;手机共享位置几乎已经成为默认能力。表面上看&#xff0c;它只是把手机当前的经纬度展示给另一个人&#xff0c;但在工程上&#xff0c;这其实是一个融合定位、系统调度、网络通信与隐私控制的综合问题。 位置是如何被计算…

2026年行业内有实力的升降机公司排名,登车桥/装卸平台/自行走升降平台/防爆升降机/防爆升降机,升降机供应厂家怎么选择 - 品牌推荐师

近年来,随着工业自动化、物流仓储及建筑领域对高效作业设备的需求激增,升降机行业迎来技术升级与市场分化的双重挑战。一方面,智能化、模块化、高安全性的产品成为主流趋势;另一方面,客户对全生命周期服务能力的要…

Windows文件传输命令大汇总

Windows文件传输命令大汇总 在Windows系统间或从网络服务器传输文件时&#xff0c;你是否遇到过BITS服务报错“不支持必要的HTTP协议”&#xff1f;本文将为你系统梳理Windows下各种文件传输命令&#xff0c;从标准工具到非常规技巧&#xff0c;帮你成为文件传输高手。 一、核心…

甘肃万通汽修技工学校排名及优势解读 - 工业品牌热点

2026年技能型社会建设持续推进,优质技工教育已成为青年实现职业理想、企业填补人才缺口的核心支撑。无论是契合产业需求的专业设置、理实一体化的实战教学,还是技能+学历双提升的培养路径,靠谱院校的专业能力直接决…

【课程设计/毕业设计】基于微信小程序的乐器宣传平台基于springboot+微信小程序的乐器宣传平台【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

进制转化入门 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

数据库备份的 10 分钟里,接了个 SQL 优化单:甲方给了执行计划,改 3 行代码,结款比备份还快

数据库备份的 10 分钟里,接了个 SQL 优化单:甲方给了执行计划,改 3 行代码,结款比备份还快周三下午四点半,我点击了数据库备份按钮——后台提示预计耗时12分钟,盯着进度条一点点蠕动的间隙,顺手点开了【程序员接…

基于深度学习的大地电磁反演方法研究

✅ 博主简介&#xff1a;擅长数据搜集与处理、建模仿真、程序设计、仿真代码、论文写作与指导&#xff0c;毕业论文、期刊论文经验交流。✅成品或者定制&#xff0c;扫描文章底部微信二维码。(1) GoogLeNetINV神经网络架构设计与大地电磁反演模型构建大地电磁测深法是一种利用天…

EtherCAT 主站3 - 指南

EtherCAT 主站3 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &quo…

承重型变形缝源头厂家哪家好?苏州昱安值得选择吗 - 工业品牌热点

问题1:建筑项目选承重型变形缝时,为什么口碑比低价更重要? 很多项目方在采购承重型变形缝时,容易陷入低价陷阱——认为变形缝只是金属条,只要能填充缝隙就行。但实际案例中,低价产品往往在关键性能上偷工减料:比…

ASPUPLOAD组件实现文件上传完整代码示例与应用详解

ASPUPLOAD组件是ASP环境下实现文件上传的常用工具&#xff0c;能够简化服务器端对用户上传文件的处理流程。本文详细介绍了ASPUPLOAD组件的安装、引用方法&#xff0c;并通过HTML表单与后端ASP代码结合&#xff0c;演示了如何获取文件信息、验证文件类型与大小、安全保存文件等…

基于sabl-cascade-rcnn_r101_fpn_1x_coco的葡萄成熟度检测项目_1

1. 基于sabl-cascade-rcnn_r101_fpn_1x_coco的葡萄成熟度检测项目 1.1. 项目概述 &#x1f347;&#x1f347;&#x1f347;大家好呀&#xff01;今天要和大家分享一个超级实用的葡萄成熟度检测项目&#xff01;这个项目基于sabl-cascade-rcnn_r101_fpn_1x_coco模型&#xff…

【2026最新】Maven配置阿里云镜像

我用的是maven3.9版本,JDK是21版本。 打开maven目录下的conf/settings文件,将下面阿里镜像代码复制到<mirrors>下: <mirrors><mirror><id>aliyunmaven</id><name>阿里云公共仓库</name><url>https://maven.aliyun.com/re…

2025年行业内品牌形象升级广告大型公司口碑排行,广告4A公司帕特广告引领行业标杆 - 品牌推荐师

随着消费市场对品牌价值认知的深化,品牌形象升级已成为企业突破增长瓶颈的核心战略。据行业数据显示,2024年美妆、快消领域品牌视觉迭代需求同比增长37%,其中78%的企业选择与专业广告公司合作完成系统性升级。然而,…

Servlet生命周期全解析 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2026年深圳技术好的ISO认证代理怎么选择,CE认证/3A信用等级认证/ISO45001,ISO认证代办哪家强 - 品牌推荐师

行业洞察:ISO认证代理市场如何破局? 随着全球质量管理体系标准的持续升级,企业对ISO认证的需求从“合规性”转向“战略价值”,市场对认证代理机构的专业能力、服务深度及行业适配性提出更高要求。然而,当前市场存…

承重型变形缝厂家哪家好,河南口碑较好的厂家有哪些 - 工业品牌热点

随着商业综合体、车库、户外广场等大荷载场景的建筑项目增多,承重型变形缝的市场需求日益增长,但许多客户在选择供应商时却面临产品质量参差不齐、定制能力不足、服务响应滞后等痛点。本文整理了关于承重型变形缝供应…

软件工程Agent在工程依赖版本升级探索

软件工程Agent在工程依赖版本升级探索背景与动机 现代软件项目广泛依赖开源库以避免重复开发,但库版本更新常引入破坏性变更,导致代码兼容性问题。手动适配这些更新需消耗大量开发者时间,且大型代码库中开发者易忽…

经典78M05 LDO经典应用电路

经典的线性稳压电源电路&#xff0c;核心作用是将 12V 直流输入&#xff08;VCC_12V&#xff09;转换为稳定的 5V 直流输出&#xff08;VCC_5V&#xff09;&#xff0c;下面我们分模块拆&#x1f539; 核心稳压模块&#xff1a;U1&#xff08;7805&#xff09;功能&#xff1a;…

机箱界的西装暴徒,能打的硬核小钢炮:机械大师C34 Pro装机实测

机箱界的西装暴徒&#xff0c;能打的硬核小钢炮&#xff1a;机械大师C34 Pro装机实测哈喽小伙伴们好&#xff0c;我是Stark-C~话说我分享了那么多的主机电脑机箱&#xff0c;什么海景房、静音侠、模块化、小钢炮……但真正能让我在开箱那一刻就露出“哎哟&#xff0c;这东西有点…