QPrintDialog弹出慢的问题
开发环境
操作系统: openkylin2 qt版本 : 5.15.10
排查过程
首先看下问题的现象,
问题现象
复现问题的demo很简单,只能是从跟踪qt代码方面入手
void MainWindow::on_pushButton_clicked()
{
QPrinter printer;
QPrintDialog dialog(&printer,this);
dialog.exec();
}
现在需要找一个代码的起点去跟踪,想了半天没有思绪,于是设置环境变量export QT_DEBUG_PLUGINS=1看看有没有提示,结果发现程序会在这一行阻塞一段时间
load library "xxx/plugins/printsupport/libcupsprintersupport.so"
怀疑可能与加载libcupsprintersupport.so库有关,可以从QLibrary加载插件库的代码开始查,经过gdb+打日志双重定位下,找到了耗时的代码范围
//这个函数在运行过程中被调用了多次
QPrinterInfo QPrinterPrivate::findValidPrinter(const QPrinterInfo &printer)
{
// Try find a valid printer to use, either the one given, the default or the first available
QPrinterInfo printerToUse = printer;
if (printerToUse.isNull()) {
printerToUse = QPrinterInfo::defaultPrinter(); //调用耗时1秒
if (printerToUse.isNull()) {
QStringList availablePrinterNames = QPrinterInfo::availablePrinterNames(); //调用耗时1秒
if (!availablePrinterNames.isEmpty())
printerToUse = QPrinterInfo::printerInfo(availablePrinterNames.at(0));
}
}
return printerToUse;
}
//这个构造函数被调用了一次
QUnixPrintWidgetPrivate::QUnixPrintWidgetPrivate(QUnixPrintWidget *p, QPrinter *prn)
: parent(p), propertiesDialog(nullptr), printer(prn),
#if QT_CONFIG(cups)
m_duplexPpdOption(nullptr),
#endif
optionsPane(nullptr), filePrintersAdded(false)
{
q = nullptr;
if (parent)
q = qobject_cast (parent->parent());
widget.setupUi(parent);
int currentPrinterIndex = 0;
QPlatformPrinterSupport *ps = QPlatformPrinterSupportPlugin::get();
if (ps) {
const QStringList printers = ps->availablePrintDeviceIds(); //调用耗时1秒
const QString defaultPrinter = ps->defaultPrintDeviceId(); //调用耗时1秒
widget.printers->addItems(printers);
const QString selectedPrinter = prn && !prn->printerName().isEmpty() ? prn->printerName() : defaultPrinter;
const int idx = printers.indexOf(selectedPrinter);
if (idx >= 0)
currentPrinterIndex = idx;
}
widget.properties->setEnabled(true);
#if QT_CONFIG(filesystemmodel) && QT_CONFIG(completer)
QFileSystemModel *fsm = new QFileSystemModel(widget.filename);
fsm->setRootPath(QDir::homePath());
widget.filename->setCompleter(new QCompleter(fsm, widget.filename));
#endif
_q_printerChanged(currentPrinterIndex);
QObject::connect(widget.printers, SIGNAL(currentIndexChanged(int)),
parent, SLOT(_q_printerChanged(int)));
QObject::connect(widget.fileBrowser, SIGNAL(clicked()), parent, SLOT(_q_btnBrowseClicked()));
QObject::connect(widget.properties, SIGNAL(clicked()), parent, SLOT(_q_btnPropertiesClicked()));
// disable features that QPrinter does not yet support.
widget.preview->setVisible(false);
}
//上面调用耗时的函数就是下面这两个
QStringList QCupsPrinterSupport::availablePrintDeviceIds() const
{
QStringList list;
cups_dest_t *dests;
int count = cupsGetDests(&dests); //调用耗时1秒
list.reserve(count);
for (int i = 0; i < count; ++i) {
QString printerId = QString::fromLocal8Bit(dests[i].name);
if (dests[i].instance)
printerId += QLatin1Char('/') + QString::fromLocal8Bit(dests[i].instance);
list.append(printerId);
}
cupsFreeDests(count, dests);
return list;
}
QString QCupsPrinterSupport::staticDefaultPrintDeviceId()
{
QString printerId;
cups_dest_t *dests;
int count = cupsGetDests(&dests); //调用耗时1秒
for (int i = 0; i < count; ++i) {
if (dests[i].is_default) {
printerId = QString::fromLocal8Bit(dests[i].name);
if (dests[i].instance) {
printerId += QLatin1Char('/') + QString::fromLocal8Bit(dests[i].instance);
break;
}
}
}
cupsFreeDests(count, dests);
return printerId;
}
cupsGetDests是cups库的api
(1) cups 是一个开放源代码的打印系统,为Unix类操作系统(如Linux)提供了标准的打印架构。
(2) libcupsprintersupport.so库为qt开发者提供更便捷的api,
libcupsprintersupport.so库内部调用的还是cups库api
我单独写了一个调用cups api的demo,进一步验证是cupsGetDests耗时
#include < cups/cups.h >
#include < iostream >
#include < ctime >
#include < sys/time.h >
//编译命令 g++ test.cpp -lcups
/*
开始 cupsGetDests
Timestamp (milliseconds): 1742524701156
Timestamp (milliseconds): 1742524702187
结束 cupsGetDests
开始 cupsFreeDests
Timestamp (milliseconds): 1742524702187
Timestamp (milliseconds): 1742524702187
结束 cupsFreeDests
*/
void getime(){
struct timeval tv;
gettimeofday(&tv, nullptr);
long timestamp = tv.tv_sec * 1000 + tv.tv_usec / 1000;
std::cout << "Timestamp (milliseconds): " << timestamp << std::endl;
}
int main() {
// 获取打印机列表
cups_dest_t* dests = nullptr;
std::cout << "开始 cupsGetDests" << std::endl;
getime();
int num_dests = cupsGetDests(&dests); //此处耗时大约1秒
getime();
std::cout << "结束 cupsGetDests" << std::endl;
/*
if (num_dests == 0) {
std::cerr << "No printers found!" << std::endl;
return 1;
}
*/
// 遍历打印机列表
for (int i = 0; i < num_dests; i++) {
cups_dest_t& dest = dests[i];
// 打印打印机名称
std::cout << "Printer Name: " << dest.name << std::endl;
// 打印打印机是否默认
if (dest.is_default) {
std::cout << " (Default Printer)" << std::endl;
}
// 打印打印机选项
for (int j = 0; j < dest.num_options; j++) {
std::cout << " Option: " << dest.options[j].name
<< " = " << dest.options[j].value << std::endl;
}
std::cout << std::endl;
}
// 释放打印机列表
std::cout << "开始 cupsFreeDests" << std::endl;
getime();
cupsFreeDests(num_dests, dests);
getime();
std::cout << "结束 cupsFreeDests" << std::endl;
return 0;
}
排查结论
qt程序运行过程中使用cups库的api,调用api耗时,导致qt组件弹出慢