一、前言

高亮按钮控件,既可以作为类似于交通指示灯使用,也可以作为设备状态指示灯使用,控件内置多套颜色风格,还可以自己设置颜色风格,按钮可以增加文字显示,非常适合需要在状态设备上显示小量的文字展示,按钮还可以开启报警,开启后会红黑闪烁,也可以自定义设置报警的两种颜色,除了默认是圆形外,还可以设置成矩形模式,控件写好了作为独立控件拖动使用,这样的话可以将控件作为一个设备,在地图上拖动,用户只需要开启拖动即可,不需要再自己编码。

二、实现的功能

  • 1:可设置文本,居中显示
  • 2:可设置文本颜色
  • 3:可设置外边框渐变颜色
  • 4:可设置里边框渐变颜色
  • 5:可设置背景色
  • 6:可直接调用内置的设置 绿色/红色/黄色/黑色/蓝色 等公有槽函数
  • 7:可设置是否在容器中可移动,当成一个对象使用
  • 8:可设置是否显示矩形
  • 9:可设置报警颜色+非报警颜色
  • 10:可控制启动报警和停止报警,报警时闪烁

三、效果图

四、头文件代码

#ifndef LIGHTBUTTON_H
#define LIGHTBUTTON_H /**
* 高亮发光按钮控件 作者:feiyangqingyun(QQ:517216493) 2016-10-16
* 1:可设置文本,居中显示
* 2:可设置文本颜色
* 3:可设置外边框渐变颜色
* 4:可设置里边框渐变颜色
* 5:可设置背景色
* 6:可直接调用内置的设置 绿色/红色/黄色/黑色/蓝色 等公有槽函数
* 7:可设置是否在容器中可移动,当成一个对象使用
* 8:可设置是否显示矩形
* 9:可设置报警颜色+非报警颜色
* 10:可控制启动报警和停止报警,报警时闪烁
*/ #include <QWidget> #ifdef quc
#if (QT_VERSION < QT_VERSION_CHECK(5,7,0))
#include <QtDesigner/QDesignerExportWidget>
#else
#include <QtUiPlugin/QDesignerExportWidget>
#endif class QDESIGNER_WIDGET_EXPORT LightButton : public QWidget
#else
class LightButton : public QWidget
#endif {
Q_OBJECT
Q_PROPERTY(QString text READ getText WRITE setText)
Q_PROPERTY(QColor textColor READ getTextColor WRITE setTextColor)
Q_PROPERTY(QColor alarmColor READ getAlarmColor WRITE setAlarmColor)
Q_PROPERTY(QColor normalColor READ getNormalColor WRITE setNormalColor) Q_PROPERTY(QColor borderOutColorStart READ getBorderOutColorStart WRITE setBorderOutColorStart)
Q_PROPERTY(QColor borderOutColorEnd READ getBorderOutColorEnd WRITE setBorderOutColorEnd)
Q_PROPERTY(QColor borderInColorStart READ getBorderInColorStart WRITE setBorderInColorStart)
Q_PROPERTY(QColor borderInColorEnd READ getBorderInColorEnd WRITE setBorderInColorEnd)
Q_PROPERTY(QColor bgColor READ getBgColor WRITE setBgColor) Q_PROPERTY(bool canMove READ getCanMove WRITE setCanMove)
Q_PROPERTY(bool showRect READ getShowRect WRITE setShowRect)
Q_PROPERTY(bool showOverlay READ getShowOverlay WRITE setShowOverlay)
Q_PROPERTY(QColor overlayColor READ getOverlayColor WRITE setOverlayColor) public:
explicit LightButton(QWidget *parent = 0); protected:
bool eventFilter(QObject *watched, QEvent *event);
void paintEvent(QPaintEvent *);
void drawBorderOut(QPainter *painter);
void drawBorderIn(QPainter *painter);
void drawBg(QPainter *painter);
void drawText(QPainter *painter);
void drawOverlay(QPainter *painter); private:
QString text; //文本
QColor textColor; //文字颜色
QColor alarmColor; //报警颜色
QColor normalColor; //正常颜色 QColor borderOutColorStart; //外边框渐变开始颜色
QColor borderOutColorEnd; //外边框渐变结束颜色
QColor borderInColorStart; //里边框渐变开始颜色
QColor borderInColorEnd; //里边框渐变结束颜色
QColor bgColor; //背景颜色 bool showRect; //显示成矩形
bool canMove; //是否能够移动
bool showOverlay; //是否显示遮罩层
QColor overlayColor; //遮罩层颜色 QTimer *timerAlarm; //定时器切换颜色 public:
QString getText() const;
QColor getTextColor() const;
QColor getAlarmColor() const;
QColor getNormalColor() const; QColor getBorderOutColorStart() const;
QColor getBorderOutColorEnd() const;
QColor getBorderInColorStart() const;
QColor getBorderInColorEnd() const;
QColor getBgColor() const; bool getCanMove() const;
bool getShowRect() const;
bool getShowOverlay() const;
QColor getOverlayColor() const; QSize sizeHint() const;
QSize minimumSizeHint() const; public Q_SLOTS:
//设置文本
void setText(const QString &text);
//设置文本颜色
void setTextColor(const QColor &textColor); //设置报警颜色+正常颜色
void setAlarmColor(const QColor &alarmColor);
void setNormalColor(const QColor &normalColor); //设置外边框渐变颜色
void setBorderOutColorStart(const QColor &borderOutColorStart);
void setBorderOutColorEnd(const QColor &borderOutColorEnd); //设置里边框渐变颜色
void setBorderInColorStart(const QColor &borderInColorStart);
void setBorderInColorEnd(const QColor &borderInColorEnd); //设置背景色
void setBgColor(const QColor &bgColor); //设置是否可移动
void setCanMove(bool canMove);
//设置是否显示矩形
void setShowRect(bool showRect);
//设置是否显示遮罩层
void setShowOverlay(bool showOverlay);
//设置遮罩层颜色
void setOverlayColor(const QColor &overlayColor); //设置为绿色
void setGreen();
//设置为红色
void setRed();
//设置为黄色
void setYellow();
//设置为黑色
void setBlack();
//设置为灰色
void setGray();
//设置为蓝色
void setBlue();
//设置为淡蓝色
void setLightBlue();
//设置为淡红色
void setLightRed();
//设置为淡绿色
void setLightGreen(); //设置报警闪烁
void startAlarm();
void stopAlarm();
void alarm();
}; #endif // LIGHTBUTTON_H

五、核心代码

#pragma execution_character_set("utf-8")

#include "lightbutton.h"
#include "qpainter.h"
#include "qevent.h"
#include "qtimer.h"
#include "qdebug.h" LightButton::LightButton(QWidget *parent) : QWidget(parent)
{
text = "";
textColor = QColor(255, 255, 255);
alarmColor = QColor(255, 107, 107);
normalColor = QColor(10, 10, 10); borderOutColorStart = QColor(255, 255, 255);
borderOutColorEnd = QColor(166, 166, 166); borderInColorStart = QColor(166, 166, 166);
borderInColorEnd = QColor(255, 255, 255); bgColor = QColor(100, 184, 255); showRect = false;
showOverlay = true;
overlayColor = QColor(255, 255, 255); canMove = false;
this->installEventFilter(this); timerAlarm = new QTimer(this);
connect(timerAlarm, SIGNAL(timeout()), this, SLOT(alarm()));
timerAlarm->setInterval(500); //setFont(QFont("Arial", 8));
} bool LightButton::eventFilter(QObject *watched, QEvent *event)
{
if (canMove) {
static QPoint lastPnt;
static bool pressed = false;
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); if (mouseEvent->type() == QEvent::MouseButtonPress) {
if (this->rect().contains(mouseEvent->pos()) && (mouseEvent->button() == Qt::LeftButton)) {
lastPnt = mouseEvent->pos();
pressed = true;
}
} else if (mouseEvent->type() == QEvent::MouseMove && pressed) {
int dx = mouseEvent->pos().x() - lastPnt.x();
int dy = mouseEvent->pos().y() - lastPnt.y();
this->move(this->x() + dx, this->y() + dy);
} else if (mouseEvent->type() == QEvent::MouseButtonRelease && pressed) {
pressed = false;
}
} return QWidget::eventFilter(watched, event);
} void LightButton::paintEvent(QPaintEvent *)
{
int width = this->width();
int height = this->height();
int side = qMin(width, height); //绘制准备工作,启用反锯齿,平移坐标轴中心,等比例缩放
QPainter painter(this);
painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); if (showRect) {
//绘制矩形区域
painter.setPen(Qt::NoPen);
painter.setBrush(bgColor);
painter.drawRoundedRect(this->rect(), 5, 5); //绘制文字
if (!text.isEmpty()) {
QFont font;
font.setPixelSize(side - 20);
painter.setFont(font);
painter.setPen(textColor);
painter.drawText(this->rect(), Qt::AlignCenter, text);
}
} else {
painter.translate(width / 2, height / 2);
painter.scale(side / 200.0, side / 200.0); //绘制外边框
drawBorderOut(&painter);
//绘制内边框
drawBorderIn(&painter);
//绘制内部指示颜色
drawBg(&painter);
//绘制居中文字
drawText(&painter);
//绘制遮罩层
drawOverlay(&painter);
}
} void LightButton::drawBorderOut(QPainter *painter)
{
int radius = 99;
painter->save();
painter->setPen(Qt::NoPen);
QLinearGradient borderGradient(0, -radius, 0, radius);
borderGradient.setColorAt(0, borderOutColorStart);
borderGradient.setColorAt(1, borderOutColorEnd);
painter->setBrush(borderGradient);
painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
painter->restore();
} void LightButton::drawBorderIn(QPainter *painter)
{
int radius = 90;
painter->save();
painter->setPen(Qt::NoPen);
QLinearGradient borderGradient(0, -radius, 0, radius);
borderGradient.setColorAt(0, borderInColorStart);
borderGradient.setColorAt(1, borderInColorEnd);
painter->setBrush(borderGradient);
painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
painter->restore();
} void LightButton::drawBg(QPainter *painter)
{
int radius = 80;
painter->save();
painter->setPen(Qt::NoPen);
painter->setBrush(bgColor);
painter->drawEllipse(-radius, -radius, radius * 2, radius * 2);
painter->restore();
} void LightButton::drawText(QPainter *painter)
{
if (text.isEmpty()) {
return;
} int radius = 100;
painter->save(); QFont font;
font.setPixelSize(85);
painter->setFont(font);
painter->setPen(textColor);
QRect rect(-radius, -radius, radius * 2, radius * 2);
painter->drawText(rect, Qt::AlignCenter, text);
painter->restore();
} void LightButton::drawOverlay(QPainter *painter)
{
if (!showOverlay) {
return;
} int radius = 80;
painter->save();
painter->setPen(Qt::NoPen); QPainterPath smallCircle;
QPainterPath bigCircle;
radius -= 1;
smallCircle.addEllipse(-radius, -radius, radius * 2, radius * 2);
radius *= 2;
bigCircle.addEllipse(-radius, -radius + 140, radius * 2, radius * 2); //高光的形状为小圆扣掉大圆的部分
QPainterPath highlight = smallCircle - bigCircle; QLinearGradient linearGradient(0, -radius / 2, 0, 0);
overlayColor.setAlpha(100);
linearGradient.setColorAt(0.0, overlayColor);
overlayColor.setAlpha(30);
linearGradient.setColorAt(1.0, overlayColor);
painter->setBrush(linearGradient);
painter->rotate(-20);
painter->drawPath(highlight); painter->restore();
} QString LightButton::getText() const
{
return this->text;
} QColor LightButton::getTextColor() const
{
return this->textColor;
} QColor LightButton::getAlarmColor() const
{
return this->alarmColor;
} QColor LightButton::getNormalColor() const
{
return this->normalColor;
} QColor LightButton::getBorderOutColorStart() const
{
return this->borderOutColorStart;
} QColor LightButton::getBorderOutColorEnd() const
{
return this->borderOutColorEnd;
} QColor LightButton::getBorderInColorStart() const
{
return this->borderInColorStart;
} QColor LightButton::getBorderInColorEnd() const
{
return this->borderInColorEnd;
} QColor LightButton::getBgColor() const
{
return this->bgColor;
} bool LightButton::getCanMove() const
{
return this->canMove;
} bool LightButton::getShowRect() const
{
return this->showRect;
} bool LightButton::getShowOverlay() const
{
return this->showOverlay;
} QColor LightButton::getOverlayColor() const
{
return this->overlayColor;
} QSize LightButton::sizeHint() const
{
return QSize(100, 100);
} QSize LightButton::minimumSizeHint() const
{
return QSize(10, 10);
} void LightButton::setText(const QString &text)
{
if (this->text != text) {
this->text = text;
update();
}
} void LightButton::setTextColor(const QColor &textColor)
{
if (this->textColor != textColor) {
this->textColor = textColor;
update();
}
} void LightButton::setAlarmColor(const QColor &alarmColor)
{
if (this->alarmColor != alarmColor) {
this->alarmColor = alarmColor;
update();
}
} void LightButton::setNormalColor(const QColor &normalColor)
{
if (this->normalColor != normalColor) {
this->normalColor = normalColor;
update();
}
} void LightButton::setBorderOutColorStart(const QColor &borderOutColorStart)
{
if (this->borderOutColorStart != borderOutColorStart) {
this->borderOutColorStart = borderOutColorStart;
update();
}
} void LightButton::setBorderOutColorEnd(const QColor &borderOutColorEnd)
{
if (this->borderOutColorEnd != borderOutColorEnd) {
this->borderOutColorEnd = borderOutColorEnd;
update();
}
} void LightButton::setBorderInColorStart(const QColor &borderInColorStart)
{
if (this->borderInColorStart != borderInColorStart) {
this->borderInColorStart = borderInColorStart;
update();
}
} void LightButton::setBorderInColorEnd(const QColor &borderInColorEnd)
{
if (this->borderInColorEnd != borderInColorEnd) {
this->borderInColorEnd = borderInColorEnd;
update();
}
} void LightButton::setBgColor(const QColor &bgColor)
{
if (this->bgColor != bgColor) {
this->bgColor = bgColor;
update();
}
} void LightButton::setCanMove(bool canMove)
{
if (this->canMove != canMove) {
this->canMove = canMove;
update();
}
} void LightButton::setShowRect(bool showRect)
{
if (this->showRect != showRect) {
this->showRect = showRect;
update();
}
} void LightButton::setShowOverlay(bool showOverlay)
{
if (this->showOverlay != showOverlay) {
this->showOverlay = showOverlay;
update();
}
} void LightButton::setOverlayColor(const QColor &overlayColor)
{
if (this->overlayColor != overlayColor) {
this->overlayColor = overlayColor;
update();
}
} void LightButton::setGreen()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(0, 166, 0));
} void LightButton::setRed()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(255, 0, 0));
} void LightButton::setYellow()
{
textColor = QColor(25, 50, 7);
setBgColor(QColor(238, 238, 0));
} void LightButton::setBlack()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(10, 10, 10));
} void LightButton::setGray()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(129, 129, 129));
} void LightButton::setBlue()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(0, 0, 166));
} void LightButton::setLightBlue()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(100, 184, 255));
} void LightButton::setLightRed()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(255, 107, 107));
} void LightButton::setLightGreen()
{
textColor = QColor(255, 255, 255);
setBgColor(QColor(24, 189, 155));
} void LightButton::startAlarm()
{
if (!timerAlarm->isActive()) {
timerAlarm->start();
}
} void LightButton::stopAlarm()
{
if (timerAlarm->isActive()) {
timerAlarm->stop();
}
} void LightButton::alarm()
{
static bool isAlarm = false;
if (isAlarm) {
textColor = QColor(255, 255, 255);
bgColor = normalColor;
} else {
textColor = QColor(255, 255, 255);
bgColor = alarmColor;
} this->update();
isAlarm = !isAlarm;
}

六、控件介绍

  1. 超过149个精美控件,涵盖了各种仪表盘、进度条、进度球、指南针、曲线图、标尺、温度计、导航条、导航栏,flatui、高亮按钮、滑动选择器、农历等。远超qwt集成的控件数量。
  2. 每个类都可以独立成一个单独的控件,零耦合,每个控件一个头文件和一个实现文件,不依赖其他文件,方便单个控件以源码形式集成到项目中,较少代码量。qwt的控件类环环相扣,高度耦合,想要使用其中一个控件,必须包含所有的代码。
  3. 全部纯Qt编写,QWidget+QPainter绘制,支持Qt4.6到Qt5.12的任何Qt版本,支持mingw、msvc、gcc等编译器,支持任意操作系统比如windows+linux+mac+嵌入式linux等,不乱码,可直接集成到Qt Creator中,和自带的控件一样使用,大部分效果只要设置几个属性即可,极为方便。
  4. 每个控件都有一个对应的单独的包含该控件源码的DEMO,方便参考使用。同时还提供一个所有控件使用的集成的DEMO。
  5. 每个控件的源代码都有详细中文注释,都按照统一设计规范编写,方便学习自定义控件的编写。
  6. 每个控件默认配色和demo对应的配色都非常精美。
  7. 超过130个可见控件,6个不可见控件。
  8. 部分控件提供多种样式风格选择,多种指示器样式选择。
  9. 所有控件自适应窗体拉伸变化。
  10. 集成自定义控件属性设计器,支持拖曳设计,所见即所得,支持导入导出xml格式。
  11. 自带activex控件demo,所有控件可以直接运行在ie浏览器中。
  12. 集成fontawesome图形字体+阿里巴巴iconfont收藏的几百个图形字体,享受图形字体带来的乐趣。
  13. 所有控件最后生成一个dll动态库文件,可以直接集成到qtcreator中拖曳设计使用。
  14. 目前已经有qml版本,后期会考虑出pyqt版本,如果用户需求量很大的话。

七、SDK下载

  • SDK下载链接:https://pan.baidu.com/s/1A5Gd77kExm8Co5ckT51vvQ 提取码:877p
  • 下载链接中包含了各个版本的动态库文件,所有控件的头文件,使用demo,自定义控件+属性设计器。
  • 自定义控件插件开放动态库dll使用(永久免费),无任何后门和限制,请放心使用。
  • 目前已提供26个版本的dll,其中包括了qt5.12.3 msvc2017 32+64 mingw 32+64 的。
  • 不定期增加控件和完善控件,不定期更新SDK,欢迎各位提出建议,谢谢!
  • widget版本(QQ:517216493)qml版本(QQ:373955953)三峰驼(QQ:278969898)。
  • 涛哥的知乎专栏 Qt进阶之路 https://zhuanlan.zhihu.com/TaoQt
  • 欢迎关注微信公众号【高效程序员】,C++/Python、学习方法、写作技巧、热门技术、职场发展等内容,干货多多,福利多多!

Qt编写自定义控件38-高亮按钮的更多相关文章

  1. Qt编写自定义控件二动画按钮

    现在的web发展越来越快,很多流行的布局样式,都是从web开始的,写惯了Qt widgets 项目,很多时候想改进一下现有的人机交互,尤其是在现有的按钮上加一些动画的效果,例如鼠标移上去变大,移开还原 ...

  2. Qt编写自定义控件9-导航按钮控件

    前言 导航按钮控件,主要用于各种漂亮精美的导航条,我们经常在web中看到导航条都非常精美,都是html+css+js实现的,还自带动画过度效果,Qt提供的qss其实也是无敌的,支持基本上所有的CSS2 ...

  3. Qt编写自定义控件8-动画按钮组控件

    前言 动画按钮组控件可以用来当做各种漂亮的导航条用,既可以设置成顶部底部+左侧右侧,还自带精美的滑动效果,还可以设置悬停滑动等各种颜色,原创作者雨田哥(QQ:3246214072),驰骋Qt控件界多年 ...

  4. Qt编写自定义控件42-开关按钮

    一.前言 从2010年进入互联网+智能手机时代以来,各种各样的APP大行其道,手机上面的APP有很多流行的元素,开关按钮个人非常喜欢,手机QQ.360卫士.金山毒霸等,都有很多开关控制一些操作,在Qt ...

  5. Qt编写自定义控件37-发光按钮(会呼吸的痛)

    一.前言 这个控件是好早以前写的,已经授权过好几个人开源过此控件代码,比如红磨坊小胖,此控件并不是来源于真实需求,而仅仅是突发奇想,类似于星星的闪烁,越到边缘越来越淡,定时器动态改变边缘发光的亮度,产 ...

  6. Qt编写自定义控件27-颜色按钮面板

    一.前言 颜色按钮面板主要用在提供一个颜色按钮面板,用户单击某个按钮,然后拿到对应的颜色值,用户可以预先设定常用的颜色集合,传入到控件中,自动生成面板颜色集合按钮,每当滑过按钮的时候,按钮边缘高亮提示 ...

  7. Qt编写自定义控件11-设备防区按钮控件

    前言 在很多项目应用中,需要根据数据动态生成对象显示在地图上,比如地图标注,同时还需要可拖动对象到指定位置显示,能有多种状态指示,安防领域一般用来表示防区或者设备,可以直接显示防区号,有多种状态颜色指 ...

  8. Qt编写自定义控件30-颜色多态按钮

    一.前言 这个控件一开始打算用样式表来实现,经过初步的探索,后面发现还是不够智能以及不能完全满足需求,比如要在此控件设置多个角标,这个用QSS就很难实现,后面才慢慢研究用QPainter来绘制,我记得 ...

  9. Qt编写自定义控件1-汽车仪表盘

    前言 汽车仪表盘几乎是qt写仪表盘控件中最常见的,一般来说先要求美工做好设计图,然后设计效果图给到程序员,由程序员根据效果来实现,主要靠贴图,这种方法有个好处就是做出来的效果比较逼真,和真实效果图基本 ...

随机推荐

  1. Laravel 队列不执行的原因,job缓存

    laravel关于异步消息队列queue不生效(job缓存)解决办法 php artisan queue:restart 每次修改代码都需要执行上面的命令,执行后成功解决! 然后再次执行 php ar ...

  2. 为什么Java那么火?

    承德SEO:常居编程语言榜首的 Java 已有 20 多年历史,它的实用性.性能和向后兼容性都无可替代,即使是忽略它的“年龄”也依然稳居第一 如今的 Java 几乎占据了C语言曾拥有的地位,而C语言在 ...

  3. js实现发送验证码倒计时效果

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. BZOJ3678 wangxz与OJ (平衡树 无旋treap)

    题面 维护一个序列,支持以下操作: 1.在某个位置插入一段值连续的数. 2.删除在当前序列位置连续的一段数. 3.查询某个位置的数是多少. 题解 显然平衡树,一个点维护一段值连续的数,如果插入或者删除 ...

  5. 2019-2020 ICPC, NERC, Southern and Volga Russian Regional Contest

    目录 Contest Info Solutions A. Berstagram B. The Feast and the Bus C. Trip to Saint Petersburg E. The ...

  6. Good Bye 2018题解

    Good Bye 2018题解 题解 CF1091A [New Year and the Christmas Ornament] 打完cf都忘记写题解了qwq 题意就是:给你一些黄,蓝,红的球,满足蓝 ...

  7. git命令如何删除文件或文件夹

    拉取远程仓到本地 git clone ×× cd ××× 查看分支 git branch -a 切换到想要操作的分支 git checkout 想要操作的分支 在本地仓库删除文件 git rm 我的文 ...

  8. python合并多个txt文件

    python合并多个txt文件 #合并一个文件夹下的多个txt文件 #coding=utf-8 import os #获取目标文件夹的路径 filedir = os.getcwd()+'\\数据' # ...

  9. 【原创】go语言学习(十五)IO操作2

    目录 文件打开和读写 读取压缩文件 bufio原理和cat命令实现 defer详解 文件打开和读写 1. 文件是存储在外部介质上的数据集合. A. 文件分类:文本文件和二进制文件 B. 文件存取方式: ...

  10. gulp4配置多页面项目编译打包

    又开始公司的新项目了... 那当我们拿到公司新项目的时候我们需要做些什么呢? 下面就来分享一下我的工作步骤吧(仅使用于初学者,大神勿见怪- -,有不好的地方希望指出,十分感谢) 1. 整版浏览 这是一 ...