1. qt 里面的网络调用都是异步的,同步 http 请求的例子如下:
bool WebUtil::HttpPost(const QUrl& url, const QByteArray& post_data, QByteArray* resp) {
QNetworkRequest req;
req.setUrl(QUrl(url));
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkAccessManager m;
bool ret = false;
QNetworkReply* reply = nullptr;
do {
reply = m.post(req, post_data);
QEventLoop loop;
QTimer timer;
timer.setSingleShot(true);
QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
QObject::connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()));
timer.start(3*1000);
qDebug() << "enter main_loop";
loop.exec();
qDebug() << "exit main_loop";
if (!timer.isActive()) {
QObject::disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
*resp = "time-out";
break;
}
timer.stop();
if (reply->error() == QNetworkReply::NoError) {
if (resp != nullptr) {
*resp = reply->readAll();
}
ret = true;
} else {
qDebug() << "error to http post: " << reply->errorString();
if (resp != nullptr) {
*resp = reply->errorString().toLatin1();
}
}
} while (false);
if (reply != nullptr) {
delete reply;
}
return ret;
}
在loop.exec() 的时候,可能切换到别的线程去了
2. QT 里面好多函数不能跨线程直接通讯,可以使用 PostEvent 来达到这个目的,代码如下:
// 定义一个事件
const QEvent::Type WS_SEND = static_cast<QEvent::Type>(QEvent::User + 100);
class WsSendEvent : public QEvent {
public:
WsSendEvent(const QByteArray& data) : QEvent(WS_SEND) {
data_ = data;
}
const QByteArray& GetData() {
return data_;
}
private:
QByteArray data_;
};
在目的对象里面,继承 QObject, 重写:
bool event(QEvent* event) {
if (event->type() == WS_SEND) {
WsSendEvent* me = static_cast<WsSendEvent*>(event);
ws_->sendMessage(me->GetData());
return true;
}
return QObject::event(event);
}
在另外一线程里发消息,通知该线程处理:
QCoreApplication::postEvent(this, new WsSendEvent(qba));
3. 关于 DeleteLater
如果不是做 GUI 相关的,尽量不要使用,直接 delete 好了。
4. ESC/POS 图片打印, 网上看了好多资料,下面给出一个实际可用的【图片之间不会出现空白行】
bool Printer::PrintImage1(const QImage& img) {
bool pr = false;
do {
QByteArray cmd;
QTcpSocket socket;
socket.connectToHost(host_, port_);
qDebug() << "connect print: " << host_ << ":" << port_;
bool conn_ret = socket.waitForConnected(20*1000);
if (conn_ret == false) {
break;
}
// just print image !!
int w = img.width();
int h = img.height();
int line_height = 24;
int wl = w % 256;
int wh = w / 256;
// 复位
cmd.clear();
cmd.append(0x1b);
cmd.append(0x40);
SendData(&socket, cmd);
qDebug() << "img_h: " << h << ", img_w: " << w;
// print 24 height every time !!
bool send_data_succ = true;
int32_t seg_cnt = (h + line_height - 1)/line_height;
for (int li = 0; li < seg_cnt; ++li) {
char raw_data[w*3] = {0};
int batch_height = (h - li*line_height);
if(batch_height > line_height) {
batch_height = line_height;
}
cmd.clear();
cmd.append((char)0x1B);
cmd.append((char)0x2A);
cmd.append((char)0x21);
cmd.append((char)wl);
cmd.append((char)wh);
// sub line!!
for (int hp = 0; hp < batch_height; hp++) {
for (int wp = 0; wp < w; ++wp) {
int image_y = li*line_height + hp;
int image_x = wp;
int print_value = (qBlue(img.pixel(image_x, image_y)) < 0xff) ? 1 : 0;
int data_index = wp*3 + (hp/8);
int bit_index = (7 - hp%8);
raw_data[data_index] |= (print_value << bit_index);
}
}
for (int i = 0; i < 3*w; ++i) {
cmd.append(raw_data[i]);
}
if (!SendData(&socket, cmd)) {
send_data_succ = false;
break;
}
// 进纸并进纸 24 个点
cmd.clear();
cmd.append(0x1b);
cmd.append(0x4a);
cmd.append(24);
if (!SendData(&socket, cmd)) {
send_data_succ = false;
break;
}
}
// 打印并进纸 4 行
cmd.append(0x1b);
cmd.append(0x64);
cmd.append(4);
SendAndClear(&socket, &cmd);
// 走纸张并切纸, 方式为 1
cmd.clear();
cmd.append((char)0x1D);
cmd.append((char)0x56);
cmd.append((char)0x01);
if (!SendData(&socket, cmd)) {
qDebug() << "cut paper error !!";
break;
}
pr = true;
socket.close();
} while (false);
return pr;
}
5. 非 gui 使用 gui 的东西,怎么办呢?
int image_w = 576;
int image_h = (24+4)*op.dish_info_size() + 48;
QImage img(image_w, image_h, QImage::Format_Grayscale8);
img.fill(Qt::GlobalColor::white);
QPainter painter(&img);
//painter.setRenderHint(QPainter::TextAntialiasing, true);
QFont font("宋体");
font.setBold(true);
int top = 0;
int line_height;
QRect r;
// title;
top += 0;
line_height = 48;
font.setPixelSize(line_height);
painter.setFont(font);
r = QRect(0, top, image_w, line_height);
top += line_height + 4;
painter.drawText(r, Qt::AlignVCenter|Qt::AlignHCenter, QString::fromStdString(op.table()));
line_height = 24;
font.setPixelSize(line_height);
painter.setFont(font);
int need_height;
int x_offset;
int part_w;
for (int i = 0; i < op.dish_info_size(); ++i) {
const server::OrderPrepare_DishInfo & di = op.dish_info(i);
// every field !!
x_offset = 0;
need_height = line_height;
part_w = image_w/2;
r = QRect(x_offset, top, part_w, need_height);
painter.drawText(r, Qt::AlignLeft|Qt::AlignTop, QString::fromStdString(di.dish_name()));
x_offset += part_w;
part_w = image_w/4;
need_height = line_height;
r = QRect(x_offset, top, part_w, need_height);
painter.drawText(r, Qt::AlignRight|Qt::AlignTop, QString::fromStdString(di.dish_count()));
x_offset += part_w;
part_w = image_w/4;
need_height = line_height;
r = QRect(x_offset, top, part_w, need_height);
painter.drawText(r, Qt::AlignRight|Qt::AlignTop, QString::fromStdString(di.dish_comment()));
top += need_height + 4;
}
std::string nm = std::to_string(QDateTime::currentDateTime().toTime_t()).append(".png");
img.save(QString::fromStdString(nm));
PrintImage1(img);
return true;
这样 img 是可以直接用的, 需要使用 QAppication