也许你的苦思冥想,大神们早已有答案。打开CSDN手机App,看到这么一段话,突然有很多感触,相信很多小伙伴都有同样的想法。很多时候,我们都是在干着重复造轮子的事儿,有时是我们当时认知有限,有时是我们太执着。
还记得当时项目需要根据输入内容实时生成几种常用的一维条形码,当时也没怎么多想,找来一本常用条码编码规则的书,照着书上介绍的各种条码的编码规则,一步一步通过算法实现了,依稀还记得当初每次实现一个条码后激动的心情。完成后还得到了老板的表扬,当时心里别提有多舒畅。
再到后来,项目需要根据输入内容生成二维码(QR码),还是老规矩,找来二维码的编码规则,看了好久,发现二维码的编码规则相对一位条码来说,复杂了太多,当时心里有点没底。心想看看网上有没有类似的生成二维码的算法,在网上搜索了一下,阅读了别人写的一些关于QRcode的文章,最后发现一个qrencode-3.4.4的标准库。下载后查看了库的一些用法,结合项目的实际需求,花了大概半天的时间就生成了符合项目需求的二维码,能够调用标准库里提供的API来调整二维码的属性。当时心里还在感慨提供这个库的人真NB,这个库太好用了!省去了很多二维码的开发时间。
再后来,项目需要根据输入内容生成Datamatrix码,不同以往,我这次连DM码的编码规则都没看,直接在网上搜索相关Datamatrix码的相关信息,果然,我又发现一个libdmtx-0.7.4的标准库,还支持中文编码。没过多久我又把DM码给鼓捣出来了。
空闲时,我又在网上搜索了相关条码以及二维码生成的相关信息,最后发现了一个功能更加强大的Zint条码库。Zint 条码库支持目前市场上主流的条码类型,包括 QR码、DM码、code-128码、EAN13码等等。最让我惊喜的是,有大神基于Qt对zint条码库进行了一次简单的封装,生成条码的同时对条码内容的绘制进行了合理的布局,能够自适应条码的缩放,这个功能对我来说太有意义了。分享一下,希望对大家有帮助。
具体实现方式也很简单,在官网上下载最新的ZINT条码库,可以直接编译成动态链接库,当然也可以把源码嵌入到工程文件直接编译使用,我使用后者进行测试。
#ifndef BARCODEITEM_H
#define BARCODEITEM_H
#include
#include
class BarcodeItem : public QGraphicsItem
{
public:
explicit BarcodeItem(QGraphicsItem *parent = Q_NULLPTR);
~BarcodeItem();
QRectF boundingRect() const;
void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
public:
mutable Zint::QZint barcode;
Zint::QZint::AspectRatioMode ar;
QRectF rect() const;
void setRect(const QRectF &rect);
inline void setRect(qreal x, qreal y, qreal w, qreal h);
struct BarcodeItemProp{
int m_symbol;
QString m_text;
QString m_primaryMessage;
int m_height;
int m_borderWidth;
int m_width;
int m_securityLevel;
int m_pdf417CodeWords;
int m_input_mode;
QColor m_fgColor;
QColor m_bgColor;
QString m_lastError;
int m_error;
int m_whitespace;
zint_symbol * m_zintSymbol;
float m_scale;
int m_option_3;
bool m_hidetext;
float m_dot_size;
} barcodeItemPara;
void drawBarcodeItem(BarcodeItemProp barcodeItemPara);
private:
QRectF m_rect;
mutable QRectF m_boundingRect;
};
inline void BarcodeItem::setRect(qreal x, qreal y, qreal w, qreal h)
{
setRect(QRectF(x, y, w, h));
}
#endif
#include
#include "barcodeitem.h"
BarcodeItem::BarcodeItem(QGraphicsItem *parent)
: QGraphicsItem(parent)
{
setRect(QRectF(0,0,200,200));
barcodeItemPara.m_symbol = BARCODE_CODE128;
barcodeItemPara.m_hidetext = false;
barcodeItemPara.m_text = "6922162891569";
barcodeItemPara.m_height = 38;
barcodeItemPara.m_scale = 8.0;
barcodeItemPara.m_dot_size = 4.0 / 5.0;
barcodeItemPara.m_pdf417CodeWords = 928;
barcodeItemPara.m_securityLevel = -1;
barcodeItemPara.m_input_mode = UNICODE_MODE;
barcodeItemPara.m_option_3 = 0;
barcodeItemPara.m_width = 0;
barcodeItemPara.m_borderWidth = 1;
}
BarcodeItem::~BarcodeItem()
{
}
QRectF BarcodeItem::boundingRect() const
{
//return QRectF(0, 0, w, h);
if(m_boundingRect.width() == 0){
m_boundingRect = QRectF(0,0,800,300);
}
return m_boundingRect;
}
void BarcodeItem::paint(QPainter * painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
{
barcode.render(*painter,boundingRect(),ar);
}
QRectF BarcodeItem::rect() const
{
return m_rect;
}
void BarcodeItem::setRect(const QRectF &rect)
{
if(m_rect == rect)
return;
prepareGeometryChange();
m_rect = rect;
m_boundingRect = m_rect;
update();
}
void BarcodeItem::drawBarcodeItem(BarcodeItem::BarcodeItemProp barcodeItemPara)
{
barcode.setHeight(barcodeItemPara.m_height);
barcode.setText(barcodeItemPara.m_text);
barcode.setScale(barcodeItemPara.m_scale);
barcode.setInputMode(barcodeItemPara.m_input_mode);
barcode.setWidth(barcodeItemPara.m_width);
barcode.setOption3(barcodeItemPara.m_option_3);
barcode.setHideText(barcodeItemPara.m_hidetext);
barcode.setDotSize(barcodeItemPara.m_dot_size);
barcode.setPdf417CodeWords(barcodeItemPara.m_pdf417CodeWords);
barcode.setSymbol(barcodeItemPara.m_symbol);
barcode.setSecurityLevel(barcodeItemPara.m_securityLevel);
barcode.setBorderWidth(barcodeItemPara.m_borderWidth);
barcode.setBorderType(Zint::QZint::NO_BORDER);
this->setRect(QRectF(0,0,barcode.width()*barcodeItemPara.m_scale,barcode.height()*barcodeItemPara.m_scale));
update();
}
添加一个继承QGraphicsItem的类用来绘制条码及二维码,主要的是实现方法封装在qzint类中的render()函数体中,这里就不贴代码了。具体的调用方法很简单,设置条码内容,条码类别,以及对应条码相关属性后,调用drawBarcodeItem()更新条码信息,调用update()执行paint()完成对barcodeItem的重绘,更新条码显示。
BarcodeItem *barcode = new BarcodeItem;
QGraphicsScene *scene = new QGraphicsScene;
QGraphicsView *view = new QGraphicsView;
barcode->drawBarcodeItem(barcode->barcodeItemPara);
scene->addItem(barcode);
view->setScene(scene);
QVBoxLayout *vLayout = new QVBoxLayout;
QLineEdit *input = new QLineEdit;
QComboBox *box = new QComboBox;
QStringList barcodeList;
barcodeList << "Barcode_128"
<< "Barcode_39"
<< "EAN13"
<< "QRcode"
<< "Datamatrix"
<< "Pdf147";
input->setText(QString("6922162891569"));
box->addItems(barcodeList);
input->setFixedHeight(50);
box->setFixedHeight(50);
vLayout->addWidget(view);
vLayout->addWidget(input);
vLayout->addWidget(box);
this->setLayout(vLayout);
connect(input,&QLineEdit::textChanged,this,[=](const QString inputStr){
barcode->barcodeItemPara.m_text = inputStr;
barcode->drawBarcodeItem(barcode->barcodeItemPara);
view->update();
});
connect(box,&QComboBox::currentTextChanged,this,[=](const QString comboStr){
if(comboStr == QString("Barcode_128")){
barcode->barcodeItemPara.m_symbol = BARCODE_CODE128;
}
else if(comboStr == QString("Barcode_39")){
barcode->barcodeItemPara.m_symbol = BARCODE_CODE39;
}
else if(comboStr == QString("EAN13")){
barcode->barcodeItemPara.m_symbol = BARCODE_EANX;
}
else if(comboStr == QString("QRcode")){
barcode->barcodeItemPara.m_symbol = BARCODE_QRCODE;
}
else if(comboStr == QString("Datamatrix")){
barcode->barcodeItemPara.m_symbol = BARCODE_DATAMATRIX;
}
else if(comboStr == QString("Pdf147")){
barcode->barcodeItemPara.m_symbol = BARCODE_PDF417;
}
barcode->drawBarcodeItem(barcode->barcodeItemPara);
view->update();
});
这里测试了code_128,code_39,EAN13,qrcode,datamatrix,pdf417,生成6中条码如下:
看到这里相信大家对ZINT条码库的强大已经有目共睹了,有相关需求的可以下载一份ZINT条码库研究一下,毕竟重复造轮子这种事儿还是少干为妙。
ps:其实任何事情都要用辨证的角度去看,虽然我当初煞费苦心的研究条码的编码规则,通过效率并不高的算法实现了一些常用条码的生成,但至少我懂了条码的编码规则,当客户需要连续变化的条码时,我可以很自信的告诉他选择code_128条码,当客户输入条码内容和实际生成的条码扫出来不一致时,我能很确定的告诉客户你输入的条码内容不标准,条码校验码错了,或许这些就是我最大的收获吧。
测试程序下载地址:https://download.csdn.net/download/p154613730/10833507