`

Swing开发之JProgressBar篇

阅读更多
JProgressBar是一个简单的组件,它一般是一种颜色部分或完全填充的矩形。缺省情况下,进度条配备了一个凹陷的边框,并水平放置。
  进度条还可以选择显示一个字符串,这个字符串在进度条矩形的中央位置上显示。这个字符串缺省时为耗时任务已完成的百分比。这个字符串可用JProgressBar.setString方法定制。
当你在安装一个新软件时,系统会告知你目前软件安装的进度如何?才不会让你觉得程序好像死了,同样的,若你设计的程序所
需要的运行超过2秒以上,你应该显示程序正在运行中的图标,或直接显示程序运行的进度,这样就能让用户清楚知道程序到底是死
了还是继续运行,在swing中,JProgressBar组件提供了类似这样的功能,它可以簋简单地输出进度的变化情况,让你想要提供进度
信息时,不再需要自行绘制绘图组件,只需要使用JProgressBar再加上几行程序设置就可以了。以下是JProgressBar的范例,在此
范例中,我们使用Timer组件当作控制进度杆移动的速度,当用户按下"start"按钮,则进度杆线就会开始向右移动,并显示出目前
的进度信息。每当JProgressBar的值改变一次(利用setValue()方法),就会触发一次ChangeEvent事件,如果你要处理这个事件,
你必须实作ChangeListener界面所定义的stateChanged()方法,在此我们是将JPogressBar的移动信息放在label上。

构造函数
JProgressBar()
          创建一个显示边框但不带进度字符串的水平进度条。
JProgressBar(BoundedRangeModel newModel)
          创建使用指定的保存进度条数据模型的水平进度条。
JProgressBar(int orient)
          创建具有指定方向(JProgressBar.VERTICAL 或 JProgressBar.HORIZONTAL)的进度条。
JProgressBar(int min, int max)
          创建具有指定最小值和最大值的水平进度条。
JProgressBar(int orient, int min, int max)
          创建使用指定方向、最小值和最大值的进度条。

常用方法
addChangeListener(ChangeListener l)
          将指定的 ChangeListener 添加到进度条。
getMaximum()
          返回进度条的最大值,该值存储在进度条的 BoundedRangeModel 中。
getMinimum()
          返回进度条的最小值,该值存储在进度条的 BoundedRangeModel 中。
getModel()
          返回此进度条使用的数据模型。
getString()
          返回进度字符串的当前值。
getValue()
          返回进度条的当前值,该值存储在进度条的 BoundedRangeModel 中。
setBorderPainted(boolean b)
          设置 borderPainted 属性,如果进度条应该绘制其边框,则此属性为 true。
setMaximum(int n)
          将进度条的最大值(存储在进度条的数据模型中)设置为 n。
setMinimum(int n)
          将进度条的最小值(存储在进度条的数据模型中)设置为 n。
setModel(BoundedRangeModel newModel)
          设置 JProgressBar 使用的数据模型。
setString(String s)
          设置进度字符串的值。
setValue(int n)
          将进度条的当前值(存储在进度条的数据模型中)设置为 n。
setUI(ProgressBarUI ui)
          设置呈现此组件的外观对象。

例 1:向JProgressBar设置值
Java代码
import java.awt.BorderLayout;  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
 
import javax.swing.JButton;  
import javax.swing.JFrame;  
import javax.swing.JProgressBar;  
 
public class JProgressBarSetValue extends JFrame {  
  JProgressBar bar = new JProgressBar();  
  JButton step = new JButton("Step");  
 
  public JProgressBarSetValue() {  
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    step.addActionListener(new ActionListener() {  
      public void actionPerformed(ActionEvent e) {  
        int value = bar.getValue() + 7;  
        if (value > bar.getMaximum()) {  
          value = bar.getMaximum();  
        }  
        bar.setValue(value);  
      }  
    });  
 
    getContentPane().add(bar, BorderLayout.NORTH);  
    getContentPane().add(step, BorderLayout.EAST);  
    pack();  
    setVisible(true);  
  }  
 
  public static void main(String arg[]) {  
    new JProgressBarSetValue();  
  }  


import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;

public class JProgressBarSetValue extends JFrame {
  JProgressBar bar = new JProgressBar();
  JButton step = new JButton("Step");

  public JProgressBarSetValue() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    step.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        int value = bar.getValue() + 7;
        if (value > bar.getMaximum()) {
          value = bar.getMaximum();
        }
        bar.setValue(value);
      }
    });

    getContentPane().add(bar, BorderLayout.NORTH);
    getContentPane().add(step, BorderLayout.EAST);
    pack();
    setVisible(true);
  }

  public static void main(String arg[]) {
    new JProgressBarSetValue();
  }
}

例 2:用线程控制JProgressBar进度
Java代码
import java.awt.BorderLayout;  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
 
import javax.swing.JButton;  
import javax.swing.JFrame;  
import javax.swing.JProgressBar;  
 
public class ProgressBarStep {  
  static class BarThread extends Thread {  
    private static int DELAY = 500;  
 
    JProgressBar progressBar;  
 
    public BarThread(JProgressBar bar) {  
      progressBar = bar;  
    }  
 
    public void run() {  
      int minimum = progressBar.getMinimum();  
      int maximum = progressBar.getMaximum();  
      for (int i = minimum; i < maximum; i++) {  
        try {  
          int value = progressBar.getValue();  
          progressBar.setValue(value + 1);  
 
          Thread.sleep(DELAY);  
        } catch (InterruptedException ignoredException) {  
        }  
      }  
    }  
  }  
 
  public static void main(String args[]) {  
    JFrame frame = new JFrame("Stepping Progress");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    final JProgressBar aJProgressBar = new JProgressBar(0, 50);  
    aJProgressBar.setStringPainted(true);  
  aJProgressBar.setBackground(Color.orange);  
  aJProgressBar.setForeground(Color.red);  
 
    final JButton aJButton = new JButton("Start");  
 
    ActionListener actionListener = new ActionListener() {  
      public void actionPerformed(ActionEvent e) {  
        aJButton.setEnabled(false);  
        Thread stepper = new BarThread(aJProgressBar);  
        stepper.start();  
      }  
    };  
    aJButton.addActionListener(actionListener);  
    frame.add(aJProgressBar, BorderLayout.NORTH);  
    frame.add(aJButton, BorderLayout.SOUTH);  
    frame.setSize(300, 200);  
    frame.setVisible(true);  
  }  


import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JProgressBar;

public class ProgressBarStep {
  static class BarThread extends Thread {
    private static int DELAY = 500;

    JProgressBar progressBar;

    public BarThread(JProgressBar bar) {
      progressBar = bar;
    }

    public void run() {
      int minimum = progressBar.getMinimum();
      int maximum = progressBar.getMaximum();
      for (int i = minimum; i < maximum; i++) {
        try {
          int value = progressBar.getValue();
          progressBar.setValue(value + 1);

          Thread.sleep(DELAY);
        } catch (InterruptedException ignoredException) {
        }
      }
    }
  }

  public static void main(String args[]) {
    JFrame frame = new JFrame("Stepping Progress");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    final JProgressBar aJProgressBar = new JProgressBar(0, 50);
    aJProgressBar.setStringPainted(true);
  aJProgressBar.setBackground(Color.orange);
  aJProgressBar.setForeground(Color.red);

    final JButton aJButton = new JButton("Start");

    ActionListener actionListener = new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        aJButton.setEnabled(false);
        Thread stepper = new BarThread(aJProgressBar);
        stepper.start();
      }
    };
    aJButton.addActionListener(actionListener);
    frame.add(aJProgressBar, BorderLayout.NORTH);
    frame.add(aJButton, BorderLayout.SOUTH);
    frame.setSize(300, 200);
    frame.setVisible(true);
  }
}

例 3:获取JProgressBar值改变状况
Java代码
import java.awt.BorderLayout;  
import java.awt.Insets;  
import java.awt.Toolkit;  
import java.awt.event.ActionEvent;  
import java.awt.event.ActionListener;  
import java.beans.PropertyChangeEvent;  
import java.beans.PropertyChangeListener;  
import java.util.Random;  
 
import javax.swing.BorderFactory;  
import javax.swing.JButton;  
import javax.swing.JComponent;  
import javax.swing.JFrame;  
import javax.swing.JPanel;  
import javax.swing.JProgressBar;  
import javax.swing.JScrollPane;  
import javax.swing.JTextArea;  
import javax.swing.SwingWorker;  
 
public class ProgressBarDemo2 extends JPanel implements ActionListener,  
    PropertyChangeListener {  
 
  private JProgressBar progressBar;  
  private JButton startButton;  
  private JTextArea taskOutput;  
  private Task task;  
 
  class Task extends SwingWorker<Void, Void> {  
    /* 
     * Main task. Executed in background thread. 
     */ 
    @Override 
    public Void doInBackground() {  
      Random random = new Random();  
      int progress = 0;  
      // Initialize progress property.  
      setProgress(0);  
      // Sleep for at least one second to simulate "startup".  
      try {  
        Thread.sleep(1000 + random.nextInt(2000));  
      } catch (InterruptedException ignore) {  
      }  
      while (progress < 100) {  
        // Sleep for up to one second.  
        try {  
          Thread.sleep(random.nextInt(1000));  
        } catch (InterruptedException ignore) {  
        }  
        // Make random progress.  
        progress += random.nextInt(10);  
        setProgress(Math.min(progress, 100));  
      }  
      return null;  
    }  
 
    /* 
     * Executed in event dispatch thread 
     */ 
    public void done() {  
      Toolkit.getDefaultToolkit().beep();  
      startButton.setEnabled(true);  
      taskOutput.append("Done!\n");  
    }  
  }  
 
  public ProgressBarDemo2() {  
    super(new BorderLayout());  
 
    // Create the demo's UI.  
    startButton = new JButton("Start");  
    startButton.setActionCommand("start");  
    startButton.addActionListener(this);  
 
    progressBar = new JProgressBar(0, 100);  
    progressBar.setValue(0);  
 
    // Call setStringPainted now so that the progress bar height  
    // stays the same whether or not the string is shown.  
    progressBar.setStringPainted(true);  
 
    taskOutput = new JTextArea(5, 20);  
    taskOutput.setMargin(new Insets(5, 5, 5, 5));  
    taskOutput.setEditable(false);  
 
    JPanel panel = new JPanel();  
    panel.add(startButton);  
    panel.add(progressBar);  
 
    add(panel, BorderLayout.PAGE_START);  
    add(new JScrollPane(taskOutput), BorderLayout.CENTER);  
    setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));  
  }  
 
  /** 
   * Invoked when the user presses the start button. 
   */ 
  public void actionPerformed(ActionEvent evt) {  
    progressBar.setIndeterminate(true);  
    startButton.setEnabled(false);  
    // Instances of javax.swing.SwingWorker are not reusuable, so  
    // we create new instances as needed.  
    task = new Task();  
    task.addPropertyChangeListener(this);  
    task.execute();  
  }  
 
  /** 
   * Invoked when task's progress property changes. 
   */ 
  public void propertyChange(PropertyChangeEvent evt) {  
    if ("progress" == evt.getPropertyName()) {  
      int progress = (Integer) evt.getNewValue();  
      progressBar.setIndeterminate(false);  
      progressBar.setValue(progress);  
      taskOutput.append(String.format("Completed %d%% of task.\n", progress));  
    }  
  }  
 
  /** 
   * Create the GUI and show it. As with all GUI code, this must run on the 
   * event-dispatching thread. 
   */ 
  private static void createAndShowGUI() {  
    // Create and set up the window.  
    JFrame frame = new JFrame("ProgressBarDemo2");  
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
 
    // Create and set up the content pane.  
    JComponent newContentPane = new ProgressBarDemo2();  
    newContentPane.setOpaque(true); // content panes must be opaque  
    frame.setContentPane(newContentPane);  
 
    // Display the window.  
    frame.pack();  
    frame.setVisible(true);  
  }  
 
  public static void main(String[] args) {  
    // Schedule a job for the event-dispatching thread:  
    // creating and showing this application's GUI.  
    javax.swing.SwingUtilities.invokeLater(new Runnable() {  
      public void run() {  
        createAndShowGUI();  
      }  
    });  
  }  



分享到:
评论

相关推荐

    Python项目-实例-02 代码雨.zip

    Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。

    Matlab实现SO-CNN-SVM蛇群算法优化卷积神经网络-支持向量机的多输入单输出回归预测(含完整的程序,GUI设计和代码详解)

    内容概要:本文介绍了使用 Matlab 实现 SO-CNN-SVM 框架进行多输入单输出回归预测的全过程。该框架利用蛇群优化算法(SO)优化卷积神经网络(CNN)和 支持向量机(SVM),实现高效的特征提取和回归预测。文章详细描述了数据预处理、模型构建、SO算法优化、模型训练、可视化和 GUI 设计的步骤,并提供了完整的代码示例。 适合人群:具备一定机器学习和深度学习基础,熟悉 Matlab 编程的研究人员和开发人员。 使用场景及目标:① 工业制造中的设备故障预测和质量控制;② 金融分析中的市场价格预测和风险管理;③ 环境监测中的气候变化和空气质量预测。该框架的目标是提高预测精度,优化模型参数,缩短训练时间,增强模型泛化能力。 阅读建议:本文不仅详细介绍了理论背景和技术细节,还提供了实际操作的代码和 GUI 设计思路,建议读者在阅读过程中结合实际数据和代码进行实验,以更好地理解和掌握相关技术。

    Java系统源码+社区养老服务系统

    Java系统源码+社区养老服务系统 内容概要: 本资源包含了完整的Java前后端源码及说明文档,适用于想要快速搭建并部署Java Web应用程序的开发者、学习者。 技术栈: 后端:Java生态系统,包含Spring Boot、Shiro、MyBatis等,数据库使用Mysql 前端:Vue、Bootstrap、Jquery等 适用场景示例: 1、毕业生希望快速启动一个新的Java Web应用程序。 2、团队寻找一个稳定的模板来加速产品开发周期。 3、教育机构或个人学习者用于教学目的或自学练习。 4、创业公司需要一个可以立即投入使用的MVP(最小可行产品)。

    Java系统源码+健身房管理系统

    Java系统源码+健身房管理系统 内容概要: 本资源包含了完整的Java前后端源码及说明文档,适用于想要快速搭建并部署Java Web应用程序的开发者、学习者。 技术栈: 后端:Java生态系统,包含Spring Boot、Shiro、MyBatis等,数据库使用Mysql 前端:Vue、Bootstrap、Jquery等 适用场景示例: 1、毕业生希望快速启动一个新的Java Web应用程序。 2、团队寻找一个稳定的模板来加速产品开发周期。 3、教育机构或个人学习者用于教学目的或自学练习。 4、创业公司需要一个可以立即投入使用的MVP(最小可行产品)。

    阵列信号处理-MUSIC算法-均匀线阵-幅相误差-信噪比变化

    阵列信号处理中,均匀线阵条件下,分析不同信噪比条件下,幅相误差对于测向角度偏差的影响

    Python项目-游戏源码-07 坦克大战.zip

    Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。

    Python项目-实例-04 简易时钟.zip

    Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。

    瓶罐检测26-CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rar

    瓶罐检测26-CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rarDetectResiduos-V1 2024-02-24 3:32 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括6821张图像。 工具以创建格式注释。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为640x640(拉伸) 应用以下扩展来创建每个源图像的3个版本: *水平翻转的50%概率 *垂直翻转的50%概率 * -15和+15度之间的随机旋转 * 0到1.5像素之间的随机高斯模糊

    名片管理系统.pdf

    名片管理系统.pdf

    瓶子检测3-YOLOv9数据集合集.rar

    瓶子检测3-YOLOv9数据集合集.rarMY_DATASET11-V1 2022-12-28 1:46 AM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括1001张图像。 塑料 - 玻璃金属纸纸以yolov9格式注释。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整到224x224(拉伸) 没有应用图像增强技术。

    水瓶瓶罐检测58-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rar

    水瓶瓶罐检测58-YOLO(v5至v9)、COCO、CreateML、Darknet、Paligemma、TFRecord、VOC数据集合集.rarQaldyq Suryptau-V2 2024-02-26 8:05 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括2328张图像。 以可可格式注释了金属 - 柔性 - plastmassa-qaldyq。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为416x416(拉伸) 应用以下扩展来创建每个源图像的3个版本: *随机裁剪图像的0%至10% * -15和+15度之间的随机旋转 *随机的BRIGTHNESS调整-10%至+10% * -7%至 +7%之间的随机暴露调整

    Python项目-自动办公-05 在Excel表格中将上下行相同内容的单元格自动合并.zip

    Python课程设计,含有代码注释,新手也可看懂。毕业设计、期末大作业、课程设计、高分必看,下载下来,简单部署,就可以使用。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。

    基于ssm的精品酒销售管理系统+jsp源代码(完整前后端+mysql+说明文档+LW).zip

    使用精品酒销售管理系统的用户分管理员和用户两个角色的权限子模块。 管理员所能使用的功能主要有:主页、个人中心、用户管理、商品分类管理、商品信息管理、系统管理、订单管理等。 用户可以实现主页、个人中心、我的收藏管理、订单管理等。 前台首页可以实现商品信息、新闻资讯、我的、跳转到后台、购物车等。 项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7

    1_io_thread_1734442494401.wmv

    1_io_thread_1734442494401.wmv

    一个基于Java Web的在线问卷调查系统源码实例

    java 一个基于Java Web的在线问卷调查系统源码实例 一个基于Java Web的在线问卷调查系统源码实例

    基于ssm的在线项目众筹平台源代码(完整前后端+mysql+说明文档+LW).zip

    网站前台注重的功能实现包括会员注册、系统公告、项目查看、在线留言、关注收藏项目、众筹项目申请,网站后台注重的功能实现包括系统用户管理、用户注册审核、项目类别管理、项目信息管理、投资申请查看、投资申请审核、申请结果反馈。 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7

    毕业设计的概要介绍与分析

    以下是一个关于毕业设计的资源描述和项目源码的简要概述: 资源描述 该毕业设计项目为一个基于Spring Boot的在线学习系统。该项目使用了丰富的资源来确保项目的顺利完成。首先,通过数字图书馆和在线数据库(如谷歌学术)获取了大量的相关文献和最新研究成果,为项目的理论基础提供了坚实的支撑。其次,参考了一些电子书籍和国内外教程资源,学习了相关的开发技巧和最佳实践。此外,项目还利用了Spring Boot、MyBatis等开源框架,以及MySQL数据库,这些资源大大提高了开发效率和系统的稳定性。 在开发过程中,还参与了线上和线下的技术培训和研讨会,与其他开发者交流经验,解决了一些技术难题。这些活动不仅提供了宝贵的学习机会,还帮助更好地理解了项目的需求和实现方式。 项目源码概述 该项目源码主要包括以下几个部分: 后端代码:基于Spring Boot框架,实现了用户管理、课程管理、在线学习、模拟考试等功能。 前端代码:使用HTML、CSS和JavaScript(可能使用Vue.js或React.js)等技术,构建了友好的用户界面,使用户能够方便地浏览课程、进行在线学习和考试。 数据库脚本

    xshell与xftp插件

    如果在运维环境中,尤其是乙方,甲方客户为了安全一般不允许上传破解/绿色版等运维软件,这时候如果有官网下载的运维工具且是免费的,那不就可以正常使用了。 8款软件,显示版本到6,以后可不可以不清楚,现在我用绿色版用不上这个。 包含:xfile、xftp、xlpd、xmanager、xmanager 3d、xmanager powersuite、xshell、xshell plus

    广东省深圳市公司申请助理级职称的主要步骤

    广东省深圳市公司申请助理级职称的主要步骤

    杂货产品检测43-YOLO(v5至v9)、CreateML、Paligemma、TFRecord、VOC数据集合集.rar

    杂货产品检测43-YOLO(v5至v9)、CreateML、Paligemma、TFRecord、VOC数据集合集.rarIPCV分配-V6 2024-01-21 6:10 PM ============================= *与您的团队在计算机视觉项目上合作 *收集和组织图像 *了解和搜索非结构化图像数据 *注释,创建数据集 *导出,训练和部署计算机视觉模型 *使用主动学习随着时间的推移改善数据集 对于最先进的计算机视觉培训笔记本,您可以与此数据集一起使用 该数据集包括7012张图像。 家庭废物以createMl格式注释。 将以下预处理应用于每个图像: *像素数据的自动取向(带有Exif-Arientation剥离) *调整大小为640x640(拉伸) 没有应用图像增强技术。

Global site tag (gtag.js) - Google Analytics