欢迎小伙伴的点评✨✨,相互学习、互关必回、全天在线🍳🍳🍳
博主🧑🧑 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神👩🚀
本章首先介绍几种主要位置函数及其之间的区别,以及各种与位置相关函数的使用场合;然后,通过一个简单绘图工具实例,介绍利用 QPainter 和 QPainterPath 两种方法绘制各种基础图形。
设计界面,区分各种形状及画笔颜色、画笔线宽、画笔风格、画笔顶帽、画笔连接点、填充模式、铺展效果、画刷颜色、画刷风格设置等。
图一
#ifndef PAINTAREA_H
#define PAINTAREA_H
#include
#include
#include
class PaintArea : public QWidget
{
Q_OBJECT
public:
enum Shape{Line,Rectangle,RoundRect,Ellipse,Polygon,Polyline,Points,Arc,Path,Text, Pixmap};
explicit PaintArea(QWidget *parent = nullptr);
void setShape(Shape);
void setPen (QPen) ;
void setBrush(QBrush);
void setFillRule (Qt::FillRule) ;
void paintEvent(QPaintEvent *);
signals:
public slots:
private:
Shape shape;
QPen pen;
QBrush brush;
Qt::FillRule fillRule;
};
#endif // PAINTAREA_H
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
#include "paintarea.h"
#include
#include
#include
#include
#include
#include
#include
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private:
PaintArea *paintArea;
QLabel *shapeLabel;
QComboBox *shapeComboBox;
QLabel *penWidthLabel;
QSpinBox *penWidthSpinBox;
QLabel *penColorLabel;
QFrame *penColorFrame;
QPushButton *penColorBtn;
QLabel *penStyleLabel;
QComboBox *penStyleComboBox;
QLabel *penCapLabel;
QComboBox *penCapComboBox;
QLabel *penJoinLabel;
QComboBox *penJoinComboBox;
QLabel *fillRuleLabel;
QComboBox *fillRuleComboBox;
QLabel *spreadLabel;
QComboBox *spreadComboBox;
QGradient::Spread spread;
QLabel *brushStyleLabel;
QComboBox *brushStyleComboBox;
QLabel *brushColorLabel;
QFrame *brushColorFrame;
QPushButton *brushColorBtn;
QGridLayout *rightLayout;
private slots:
void ShowShape(int);
void ShowPenWidth(int);
void ShowPenColor();
void ShowPenStyle(int);
void ShowPenCap(int);
void ShowPenJoin(int);
void ShowSpreadStyle();
void ShowFillRule();
void ShowBrushColor();
void ShowBrush(int);
};
#endif // WIDGET_H
#include "widget.h"
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFont f("ZYSong18030",12);
a.setFont(f);
Widget w;
w.show();
return a.exec();
}
#include "paintarea.h"
#include
PaintArea::PaintArea(QWidget *parent) : QWidget(parent)
{
setPalette (QPalette (Qt:: white));
setAutoFillBackground(true); //完成对窗体背景色的设置,与下面的代码效果一致:
setMinimumSize(400,400);
}
void PaintArea::setShape(Shape s)
{
shape= s; //setShape() 函数可以设置形状
update();
}
void PaintArea::setPen(QPen p)
{ //setPen() 函数可以设置画笔
pen= p;
update();
}
void PaintArea::setBrush(QBrush b)
{
brush= b; //setBrush() 函数可以设置画刷
update();
}
void PaintArea::setFillRule(Qt::FillRule rule)
{
fillRule =rule; //setFillRule() 函数可以设置填充模式
update(); //重画绘制区窗体
}
void PaintArea::paintEvent(QPaintEvent *)
{
QPainter p(this); //新建一个 QPainter 对象
p.setPen(pen); //设置 QPainter 对象的画笔
p.setBrush(brush); //设置 QPainter 对象的画刷
QRect rect(50,100,300,200); // (a)
static const QPoint points [4]= //(b)
{
QPoint(150,100),
QPoint(300,150),
QPoint(350,250),
QPoint(100,300)
};
int startAngle =30*16; //(c)
int spanAngle =120*16;
QPainterPath path; //新建一个 QPainterPath 对象为画路径做准备
path.addRect(150,150,100,100);
path.moveTo(100,100);
path.cubicTo(300,100,200,200,300,300);
path.cubicTo(100,300,200,200,100,100);
path.setFillRule (fillRule);
switch (shape)
{ //(d)
case Line: //直线
p.drawLine(rect.topLeft(),rect.bottomRight()) ;break;
case Rectangle: //长方形
p.drawRect(rect);break;
case RoundRect: //圆角方形
p.drawRoundRect(rect);break;
case Ellipse: //椭圆形
p.drawEllipse(rect); break;
case Polygon: //多边形
p.drawPolygon(points,4); break;
case Polyline: //多边线
p.drawPolyline(points,4);break;
case Points: //点
p.drawPoints(points,4);break;
case Arc: //弧
p.drawArc(rect,startAngle,spanAngle);break;
case Path: //路径
p.drawPath(path);break;
case Text: //文字
p.drawText(rect,Qt::AlignCenter,tr("Hello Qt!"));break;
case Pixmap: //图片
p.drawPixmap(150,150,QPixmap("butterfly.png")); break;
default: break;
}
}
其中,
(a)QRect rect(50,100,300,200):设定一个方形区域,为画长方形、圆角方形、椭圆等做准备。
(b)static const QPoint points [4]= {…}:创建一个QPoint 的数组,包含四个点,为画多边形、多边线及点做准备。
(c)int startAngle =30*16:其中,参数 startAngle 表示起始角,为弧形的起始点与圆心之间连线与水平方向的夹角;参数 spanAngle 表示的是跨度角,为弧形起点、终点分别与圆心连线之间的夹角。
(d) switch (shape){…}:使用 一个 switchO语句,对所要画的形状做判断,调用 QPainter 的各
个 draw()函数完成图形的绘制 。
#include "widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
paintArea =new PaintArea;
shapeLabel =new QLabel(tr(" 形状:")); //形状选择下拉列表框
shapeComboBox =new QComboBox;
shapeComboBox->addItem (tr("Line"),PaintArea:: Line); //(a)
shapeComboBox->addItem(tr("Rectangle"),PaintArea::Rectangle);
shapeComboBox->addItem(tr("RoundedRect"),PaintArea::RoundRect);
shapeComboBox->addItem(tr("Ellipse"),PaintArea::Ellipse);
shapeComboBox->addItem(tr("Polygon"),PaintArea::Polygon);
shapeComboBox->addItem(tr("Polyline"),PaintArea::Polyline);
shapeComboBox->addItem(tr("Points"),PaintArea::Points);
shapeComboBox->addItem (tr ("Arc"), PaintArea::Arc);
shapeComboBox->addItem(tr("Path"),PaintArea::Path);
shapeComboBox->addItem(tr("Text"),PaintArea::Text);
shapeComboBox->addItem(tr("Pixmap"),PaintArea::Pixmap);
connect(shapeComboBox,SIGNAL(activated(int)),this,SLOT(ShowShape(int)));
penColorLabel =new QLabel(tr(" 画笔颜色:")); //画笔颜色选择控件
penColorFrame =new QFrame;
penColorFrame->setFrameStyle(QFrame::Panel|QFrame::Sunken);
penColorFrame->setAutoFillBackground(true);
penColorFrame->setPalette(QPalette(Qt::blue));
penColorBtn =new QPushButton(tr(" 更改"));
connect(penColorBtn,SIGNAL(clicked()),this,SLOT(ShowPenColor()));
penWidthLabel =new QLabel(tr(" 画笔线宽:")); //画笔线宽选择控件
penWidthSpinBox =new QSpinBox;
penWidthSpinBox->setRange(0,20);
connect(penWidthSpinBox,SIGNAL(valueChanged(int)),this,SLOT (ShowPenWidth(int)));
penStyleLabel =new QLabel(tr(" 画笔风格:")); //画笔风格选择下拉表框
penStyleComboBox =new QComboBox;
penStyleComboBox->addItem(tr("SolidLine"),static_cast<int>(Qt::SolidLine)); //(b)
penStyleComboBox->addItem(tr("DashLine"),static_cast<int>(Qt::DashLine));
penStyleComboBox->addItem(tr("DotLine"),static_cast<int>(Qt::DotLine));
penStyleComboBox->addItem(tr("DashDotLine"),static_cast<int>(Qt::DashDotLine));
penStyleComboBox->addItem(tr("DashDotDotLine"),static_cast<int>(Qt::DashDotDotLine));
penStyleComboBox->addItem(tr("CustomDashLine"),static_cast<int>(Qt::CustomDashLine));
connect(penStyleComboBox,SIGNAL(activated(int)),this,SLOT (ShowPenStyle(int)));
penCapLabel =new QLabel(tr(" 画笔顶帽:")); //画笔顶帽风格选择下拉列表框
penCapComboBox =new QComboBox;
penCapComboBox->addItem(tr("SquareCap"),Qt::SquareCap); //(c)
penCapComboBox->addItem(tr("FlatCap"),Qt::FlatCap);
penCapComboBox->addItem(tr("RoundCap"),Qt::RoundCap);
connect(penCapComboBox,SIGNAL(activated(int)),this,SLOT (ShowPenCap (int)));
penJoinLabel =new QLabel(tr(" 画笔连接点: ")); //画笔连接点风格选择下拉框
penJoinComboBox =new QComboBox;
penJoinComboBox->addItem(tr("BevelJoin"),Qt::BevelJoin); //(d)
penJoinComboBox->addItem(tr("MiterJoin"),Qt::MiterJoin);
penJoinComboBox->addItem(tr("RoundJoin"),Qt::RoundJoin);
connect(penJoinComboBox,SIGNAL(activated(int)),this,SLOT (ShowPenJoin (int)));
fillRuleLabel =new QLabel( tr ("填充模式:")); //填充模式选择下拉列表框
fillRuleComboBox =new QComboBox;
fillRuleComboBox->addItem(tr("Odd Even"),Qt::OddEvenFill); //(e)
fillRuleComboBox->addItem(tr("Winding"),Qt::WindingFill);
connect(fillRuleComboBox,SIGNAL(activated(int)),this,SLOT (ShowFillRule()));
spreadLabel =new QLabel(tr(" 铺展效果:")); //铺展效果选择下拉列表框
spreadComboBox =new QComboBox;
spreadComboBox->addItem(tr("PadSpread"),QGradient::PadSpread); //(f)
spreadComboBox->addItem(tr("RepeatSpread"),QGradient::RepeatSpread);
spreadComboBox->addItem(tr("ReflectSpread"),QGradient:: ReflectSpread);
connect(spreadComboBox,SIGNAL(activated(int)),this,SLOT(ShowSpreadStyle()));
brushColorLabel =new QLabel(tr(" 画刷颜色:")); //画刷颜色选择控件
brushColorFrame =new QFrame;
brushColorFrame->setFrameStyle(QFrame:: Panel|QFrame:: Sunken) ;
brushColorFrame->setAutoFillBackground(true);
brushColorFrame->setPalette(QPalette(Qt::green));
brushColorBtn =new QPushButton(tr(" 更改")) ;
connect (brushColorBtn, SIGNAL (clicked()), this, SLOT (ShowBrushColor ()));
brushStyleLabel =new QLabel(tr(" 画刷风格:")); //画刷风格选择下拉列表框
brushStyleComboBox =new QComboBox;
brushStyleComboBox->addItem(tr("SolidPattern"),static_cast<int>(Qt::SolidPattern)); //(g)
brushStyleComboBox->addItem(tr("DenselPattern"),static_cast<int>(Qt::Dense1Pattern));
brushStyleComboBox->addItem(tr("Dense2Pattern"),static_cast<int>(Qt::Dense2Pattern));
brushStyleComboBox->addItem(tr("Dense3Pattern"),static_cast<int>(Qt::Dense3Pattern));
brushStyleComboBox->addItem(tr("Dense4Pattern"),static_cast<int>(Qt::Dense4Pattern));
brushStyleComboBox->addItem(tr("Dense5Pattern"),static_cast<int>(Qt::Dense5Pattern));
brushStyleComboBox->addItem(tr("Dense6Pattern"),static_cast<int>(Qt::Dense6Pattern));
brushStyleComboBox->addItem(tr("Dense7Pattern"),static_cast<int>(Qt::Dense7Pattern));
brushStyleComboBox->addItem(tr("HorPattern"),static_cast<int>(Qt::HorPattern));
brushStyleComboBox->addItem(tr("VerPattern"),static_cast<int>(Qt::VerPattern));
brushStyleComboBox->addItem(tr("CrossPattern"),static_cast<int>(Qt::CrossPattern));
brushStyleComboBox->addItem(tr("BDiagPattern"),static_cast<int>(Qt::BDiagPattern));
brushStyleComboBox->addItem(tr("FDiagPattern"),static_cast<int>(Qt::FDiagPattern));
brushStyleComboBox->addItem(tr("DiagCrossPattern"),static_cast<int>(Qt:: DiagCrossPattern));
brushStyleComboBox->addItem(tr("LinearGradientPattern"),static_cast<int>(Qt::LinearGradientPattern));
brushStyleComboBox->addItem(tr("ConicalGradientPattern"),static_cast<int>(Qt::ConicalGradientPattern));
brushStyleComboBox->addItem(tr("RadialGradientPattern"),static_cast<int>(Qt::RadialGradientPattern));
brushStyleComboBox->addItem(tr("TexturePattern"),static_cast<int>(Qt::TexturePattern));
connect(brushStyleComboBox,SIGNAL(activated(int)),this,SLOT(ShowBrush(int)));
rightLayout =new QGridLayout; //控制面包布局
rightLayout->addWidget(shapeLabel,0,0);
rightLayout->addWidget(shapeComboBox,0,1);
rightLayout->addWidget(penColorLabel,1,0);
rightLayout->addWidget(penColorFrame,1,1);
rightLayout->addWidget(penColorBtn,1,2);
rightLayout->addWidget(penWidthLabel,2,0);
rightLayout->addWidget(penWidthSpinBox,2,1);
rightLayout->addWidget(penStyleLabel,3,0);
rightLayout->addWidget(penStyleComboBox,3,1);
rightLayout->addWidget(penCapLabel,4,0);
rightLayout->addWidget(penCapComboBox,4,1);
rightLayout->addWidget(penJoinLabel,5,0);
rightLayout->addWidget(penJoinComboBox,5,1);
rightLayout->addWidget(fillRuleLabel,6,0);
rightLayout->addWidget(fillRuleComboBox,6,1);
rightLayout->addWidget(spreadLabel,7,0);
rightLayout->addWidget(spreadComboBox,7,1);
rightLayout->addWidget(brushColorLabel,8,0);
rightLayout->addWidget(brushColorFrame,8,1);
rightLayout->addWidget(brushColorBtn,8, 2);
rightLayout->addWidget(brushStyleLabel,9,0);
rightLayout->addWidget(brushStyleComboBox,9,1);
QHBoxLayout *mainLayout =new QHBoxLayout(this); //整体的布局
mainLayout->addWidget(paintArea);
mainLayout->addLayout(rightLayout);
mainLayout->setStretchFactor(paintArea,1);
mainLayout->setStretchFactor(rightLayout,0);
ShowShape(shapeComboBox->currentIndex()); //显示默认的图形
}
Widget::~Widget()
{
}
void Widget::ShowShape(int value)
{
PaintArea::Shape shape= PaintArea::Shape(shapeComboBox->itemData(value, Qt:: UserRole) . toInt());
paintArea->setShape(shape);
}
void Widget::ShowPenColor()
{
QColor color= QColorDialog::getColor(static_cast<int>(Qt::blue));
penColorFrame->setPalette(QPalette(color));
int value = penWidthSpinBox->value();
Qt::PenStyle style= Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(),Qt::UserRole).toInt());
Qt::PenCapStyle cap= Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(),Qt::UserRole).toInt());
Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt());
paintArea->setPen(QPen(color,value,style,cap,join));
}
void Widget::ShowPenWidth(int value)
{
QColor color= penColorFrame->palette() .color(QPalette::Window);
Qt::PenStyle style= Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(),Qt::UserRole).toInt());
Qt::PenCapStyle cap= Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(),Qt::UserRole) .toInt());
Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt());
paintArea->setPen(QPen(color,value,style,cap,join));
}
void Widget::ShowPenStyle(int styleValue)
{
QColor color = penColorFrame->palette().color(QPalette::Window) ;
int value= penWidthSpinBox->value();
Qt::PenStyle style= Qt::PenStyle(penStyleComboBox->itemData(styleValue, Qt:: UserRole).toInt ());
Qt::PenCapStyle cap= Qt::PenCapStyle(penCapComboBox->itemData(penCapComboBox->currentIndex(),Qt::UserRole).toInt());
Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt()) ;
paintArea->setPen(QPen(color,value,style,cap,join));
}
void Widget::ShowPenCap(int capValue)
{
QColor color= penColorFrame->palette() .color(QPalette::Window);
int value = penWidthSpinBox->value ();
Qt::PenStyle style= Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex() ,Qt::UserRole).toInt());
Qt::PenCapStyle cap= Qt::PenCapStyle(penCapComboBox->itemData(capValue, Qt::UserRole).toInt());
Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(penJoinComboBox->currentIndex(),Qt::UserRole).toInt());
paintArea->setPen(QPen(color,value,style,cap,join));
}
void Widget::ShowPenJoin(int joinValue)
{
QColor color = penColorFrame->palette().color(QPalette::Window);
int value = penWidthSpinBox->value ();
Qt::PenStyle style= Qt::PenStyle(penStyleComboBox->itemData(penStyleComboBox->currentIndex(),Qt::UserRole).toInt());
Qt::PenCapStyle cap= Qt::PenCapStyle(penCapComboBox->itemData(
penCapComboBox->currentIndex(),Qt:: UserRole).toInt());
Qt::PenJoinStyle join=Qt::PenJoinStyle(penJoinComboBox->itemData(joinValue,Qt::UserRole).toInt());
paintArea->setPen(QPen(color,value,style,cap,join));
}
void Widget::ShowFillRule()
{
Qt::FillRule rule=Qt::FillRule(fillRuleComboBox->itemData(fillRuleComboBox->currentIndex (),Qt::UserRole).toInt());
paintArea->setFillRule(rule);
}
void Widget::ShowSpreadStyle()
{
spread=QGradient::Spread(spreadComboBox->itemData(spreadComboBox->currentIndex () ,Qt::UserRole).toInt ());
}
void Widget::ShowBrushColor()
{
QColor color= QColorDialog::getColor(static_cast<int>(Qt:: blue));
brushColorFrame->setPalette(QPalette(color));
ShowBrush(brushStyleComboBox->currentIndex());
}
void Widget::ShowBrush(int value)
{
//获得画刷的颜色
QColor color= brushColorFrame->palette() .color(QPalette::Window);
Qt::BrushStyle style= Qt::BrushStyle(brushStyleComboBox->itemData(value, Qt:: UserRole).toInt()); // 获得所选的画刷风格,若选择的是渐变或者纹理图案,则需要进行一定的处理。
if (style == Qt::LinearGradientPattern) //主窗口的 style 变量值为 Qt::LinearGradientPattern 时,表明选择的是线形渐变。
{
QLinearGradient linearGradient(0,0,400,400);
linearGradient.setColorAt(0.0,Qt::white);
linearGradient.setColorAt(0.2,color);
linearGradient. setColorAt (1.0, Qt::black) ;
linearGradient.setSpread(spread);
paintArea->setBrush(linearGradient);
}else if(style == Qt::RadialGradientPattern) //主窗口的 style 变量值为 Qt: :RadialGradientPattern 时,表明选择的是圆形渐变。
{
QRadialGradient radialGradient(200,200,150,150,100);
radialGradient.setColorAt(0.0,Qt::white);
radialGradient.setColorAt(0.2,color) ;
radialGradient.setColorAt(1.0,Qt::black);
radialGradient.setSpread(spread);
paintArea->setBrush(radialGradient);
}else if (style == Qt::ConicalGradientPattern) //主窗口的 style 变量值为 Qt::ConicalGradientPattern 时,表明选择的是锥形渐变
{
QConicalGradient conicalGradient(200,200,30);
conicalGradient.setColorAt(0.0,Qt::white);
conicalGradient.setColorAt(0.2,color);
conicalGradient.setColorAt(1.0,Qt::black);
paintArea->setBrush(conicalGradient);
}else if(style == Qt::TexturePattern)
{
paintArea->setBrush(QBrush(QPixmap("butterfly.png")));
}else
{
paintArea->setBrush(QBrush(color,style));
}
}
其中,
(a)shapeComboBox->addItem (tr(“Line”),PaintArea::Line):QComboBox 的 addltem()函数
可以仅插入文本,也可同时插入与文本相对应的具体数据,通常为枚举型数据,便千后面操作
时确定选择的是哪个数据。
(b) penStyleComboBox->addItem(tr(“SolidLine”),static_cast(Qt::SolidLine)):选用不同的参数,对应画笔的不同风格。
(c)penCapComboBox->addItem(tr(“SquareCap”),Qt::SquareCap):选用不同的参数,对应画笔顶帽的不同风格。其中, Qt:: SquareCap 表示在线条的顶点处是方形的,且线条绘制的区域包括了端点,并且再往外延伸半个线宽的长度; Qt: :FlatCap 表示在线条的顶点处是方形的,但线条绘制区域不包括端点在内; Qt: :RoundCap 表示在线条的顶点处是圆形的,且线条绘制区域包含了端点。
(d)penJoinComboBox->addItem(tr(“BevelJoin”),Qt::BevelJoin):其中, Qt: :BevelJoin 风格连接点是指两条线的中心线顶点相汇,相连处依然保留线条各自的方形顶端; Qt: :MiterJoin 风格连接点是指两条线的中心线顶点相汇,相连处线条延长到线的外侧汇集至点,形成一个尖顶的连接; Qt::RoundJoin 风格连接点是指两条线的中心线顶点相汇,相连处以圆弧形连接。
(e)fillRuleComboBox->addItem(tr(“Odd Even”),Qt::OddEvenFill):Qt 为 QPainterPath 类提供
了两种填充规则,分别是 Qt: :OddEvenFill 和 Qt::WindingFill。其中, Qt: :OddEvenFill 填充规则判断的依据是从图形中某一点画一条水平线到图形外。若这条水平线与图形边线的交点数目为奇数,则说明此点位千图形的内部;若交点数目为偶数,则此点位于图形的外部而 Qt::WindingFill 填充规则的判断依据则是从图形中某一点画一条水平线到图形外,每个交点外边线的方向可能向上,也可能向下,将这些交点数累加,方向相反的相互抵消,若最后结果不为 0 则说明此点在图形内,若最后结果为 0 则说明在图形外。
(f)spreadComboBox->addItem(tr(“PadSpread”),QGradient::PadSpread):铺展效果有三
种,分别为 QGradient: :PadSpread 、 QGradient: :RepeatSpread 和 QGradient:: ReflectSpread。其中,PadSpread 是默认的铺展效果,也是最常见的铺展效果,没有被渐变覆盖的区域填充单一的起始
颜色或终止颜色; RepeatSpread 效果与 ReflectSpread 效果只对线性渐变和圆形渐变起作用
(g)brushStyleComboBox->addItem(tr(“SolidPattern”),static_cast(Qt::SolidPattern)):选用不同的参数,对应画刷的不同风格ShowShapeO槽函数,根据当前下拉列表框中选择的选项,调用 PaintArea 类的 setShapeQ 函数设置 PaintArea 对象的形状参数。
图像与图片的基础图形的绘制会在应用程序开发中经常用到的