You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart文件间传递Future<List<int>>返回值用于PDF生成

问题:将Stateful Widget中的图表图片数据传递到其他文件生成PDF

我是Flutter新手,希望将Stateful Widget中readImageData()函数(返回Future<List<int>>,对应图表转换后的ByteData)的返回值传递到另一个Dart文件,用于生成包含图片和DataGrid的PDF。请提供实现代码。

以下是我已编写的代码:

import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';

// 假设DataCathodic是已定义的数据类
class DataCathodic {
  final DateTime timestamp;
  final double voltage;
  final double voltageLoc2;
  final double voltageLoc3;
  final double voltageLoc4;
  final double voltageLoc5;

  DataCathodic({
    required this.timestamp,
    required this.voltage,
    required this.voltageLoc2,
    required this.voltageLoc3,
    required this.voltageLoc4,
    required this.voltageLoc5,
  });
}

class CathodicColumn extends StatefulWidget {
  const CathodicColumn({Key? key}) : super(key: key);

  @override
  State<CathodicColumn> createState() => _CathodicColumnState();
}

class _CathodicColumnState extends State<CathodicColumn> {
  // Key State for Column Chart
  late GlobalKey<SfCartesianChartState> keyChart =
      GlobalKey<SfCartesianChartState>();
  List<DataCathodic>? chartData;

  // Initiate State
  @override
  void initState() {
    loadCathodicData();
    keyChart = GlobalKey<SfCartesianChartState>();
    super.initState();
  }

  // 模拟加载数据
  void loadCathodicData() {
    chartData = [
      DataCathodic(
        timestamp: DateTime.now(),
        voltage: 1.2,
        voltageLoc2: 1.3,
        voltageLoc3: 1.1,
        voltageLoc4: 1.4,
        voltageLoc5: 1.0,
      ),
      // 可添加更多测试数据
    ];
  }

  // Dispose Data
  @override
  void dispose() {
    chartData!.clear();
    super.dispose();
  }

  // Overrides
  @override
  Widget build(BuildContext context) {
    return _buildCathodicColumnChart();
  }

  Column _buildCathodicColumnChart() {
    const defaultPadding = 16.0;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        SfCartesianChart(
          key: keyChart,
          plotAreaBorderWidth: 1.0,
          title: const ChartTitle(text: 'Cathodic Voltages to Time Column Charts'),
          tooltipBehavior: TooltipBehavior(enable: true),
          legend: const Legend(
            position: LegendPosition.bottom,
            isResponsive: true,
            isVisible: true,
          ),
          primaryXAxis: const DateTimeAxis(
            edgeLabelPlacement: EdgeLabelPlacement.shift,
            title: AxisTitle(text: 'Time (hourly)'),
            intervalType: DateTimeIntervalType.hours,
            majorGridLines: MajorGridLines(width: 0),
            isVisible: true,
          ),
          primaryYAxis: const NumericAxis(
            edgeLabelPlacement: EdgeLabelPlacement.shift,
            axisLine: AxisLine(width: 0),
            labelFormat: '{value} DCV',
            majorTickLines: MajorTickLines(size: 0),
          ),
          series: _getCathodicColumnSeries(),
        ),
        const SizedBox(height: defaultPadding * 1.2),
        ElevatedButton(
          onPressed: saveFileAsPdf,
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.red,
            maximumSize: const Size(200.0, 50.0),
          ),
          child: const Row(
            children: [
              Text("Export to PDF"),
              Spacer(),
              Icon(Icons.picture_as_pdf_outlined),
            ],
          ),
        ),
      ],
    );
  }

  List<ColumnSeries<DataCathodic, DateTime>> _getCathodicColumnSeries() {
    return <ColumnSeries<DataCathodic, DateTime>>[
      ColumnSeries(
        name: 'TR Area DWP Voltages',
        dataSource: chartData!,
        xValueMapper: (DataCathodic cathodic, _) => cathodic.timestamp,
        yValueMapper: (DataCathodic cathodic, _) => cathodic.voltage,
      ),
      ColumnSeries(
        name: 'Mile Area 22',
        dataSource: chartData!,
        xValueMapper: (DataCathodic cathodic, _) => cathodic.timestamp,
        yValueMapper: (DataCathodic cathodic, _) => cathodic.voltageLoc2,
      ),
      ColumnSeries(
        name: 'Mile Area 34',
        dataSource: chartData!,
        xValueMapper: (DataCathodic cathodic, _) => cathodic.timestamp,
        yValueMapper: (DataCathodic cathodic, _) => cathodic.voltageLoc3,
      ),
      ColumnSeries(
        name: 'Mile Area 50',
        dataSource: chartData!,
        xValueMapper: (DataCathodic cathodic, _) => cathodic.timestamp,
        yValueMapper: (DataCathodic cathodic, _) => cathodic.voltageLoc4,
      ),
      ColumnSeries(
        name: 'Mile Area 68',
        dataSource: chartData!,
        xValueMapper: (DataCathodic cathodic, _) => cathodic.timestamp,
        yValueMapper: (DataCathodic cathodic, _) => cathodic.voltageLoc5,
      ),
    ];
  }

  Future<List<int>> readImageData() async {
    // Convert Charts to Images
    final ui.Image data = await keyChart.currentState!.toImage(pixelRatio: 3.0);

    // Creates Image from Chart with format PNG
    final ByteData? bytesImage =
        await data.toByteData(format: ui.ImageByteFormat.png);

    // Return the Image
    return bytesImage!.buffer.asUint8List(
      bytesImage.offsetInBytes,
      bytesImage.lengthInBytes,
    );
  }

  // 待实现的PDF保存方法
  Future<void> saveFileAsPdf() async {
    // 后续补充实现
  }
}

实现方案

1. 添加依赖

在pubspec.yaml中添加PDF生成相关依赖:

dependencies:
  pdf: ^3.10.0
  printing: ^5.12.0
  syncfusion_flutter_charts: ^25.1.39 # 保持你已使用的版本

2. 创建PDF生成工具文件

新建pdf_generator.dart,封装生成PDF的逻辑,接收图表图片数据和表格数据:

import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import '../models/data_cathodic.dart'; // 导入你的DataCathodic类

class PdfGenerator {
  static Future<void> generatePdf(List<int> chartImageBytes, List<DataCathodic> tableData) async {
    final pdf = pw.Document();

    // 添加图表图片和DataGrid表格
    pdf.addPage(
      pw.Page(
        build: (context) {
          return pw.Column(
            crossAxisAlignment: pw.CrossAxisAlignment.start,
            children: [
              pw.Text('Cathodic Voltages Report', style: pw.TextStyle(fontSize: 24, fontWeight: pw.FontWeight.bold)),
              pw.SizedBox(height: 20),
              pw.Image(pw.MemoryImage(chartImageBytes), width: PdfPageFormat.a4.width - 40),
              pw.SizedBox(height: 20),
              // 生成DataGrid表格
              pw.Table.fromTextArray(
                headers: ['时间', 'TR Area DWP', 'Mile Area 22', 'Mile Area 34', 'Mile Area 50', 'Mile Area 68'],
                data: tableData.map((item) => [
                  item.timestamp.toString(),
                  item.voltage.toStringAsFixed(2),
                  item.voltageLoc2.toStringAsFixed(2),
                  item.voltageLoc3.toStringAsFixed(2),
                  item.voltageLoc4.toStringAsFixed(2),
                  item.voltageLoc5.toStringAsFixed(2),
                ]).toList(),
                border: pw.TableBorder.all(),
                headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold),
                cellAlignment: pw.Alignment.centerLeft,
              ),
            ],
          );
        },
      ),
    );

    // 保存或打印PDF
    await Printing.layoutPdf(onLayout: (format) async => pdf.save());
  }
}

3. 在原Widget中调用PDF生成函数

修改_CathodicColumnState中的saveFileAsPdf方法,获取图表图片数据后调用工具类:

import 'pdf_generator.dart'; // 导入PDF生成工具

// ... 其他代码保持不变

Future<void> saveFileAsPdf() async {
  try {
    // 获取图表图片数据
    final chartImageBytes = await readImageData();
    // 调用PDF生成函数
    await PdfGenerator.generatePdf(chartImageBytes, chartData!);
  } catch (e) {
    // 处理错误,显示提示
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('生成PDF失败: $e')),
    );
  }
}

内容的提问来源于stack exchange,提问作者Agil Calfarera

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:45:35