QPrintDialog弹出慢的问题

开发环境

复制代码
            操作系统: openkylin2
            qt版本  : 5.15.10

排查过程

首先看下问题的现象,

问题现象

复现问题的demo很简单,只能是从跟踪qt代码方面入手

cpp 复制代码
            void MainWindow::on_pushButton_clicked()
            {
                QPrinter printer;
                QPrintDialog dialog(&printer,this);
                dialog.exec();
            }

现在需要找一个代码的起点去跟踪,想了半天没有思绪,于是设置环境变量export QT_DEBUG_PLUGINS=1看看有没有提示,结果发现程序会在这一行阻塞一段时间

cpp 复制代码
     load library  "xxx/plugins/printsupport/libcupsprintersupport.so"

怀疑可能与加载libcupsprintersupport.so库有关,可以从QLibrary加载插件库的代码开始查,经过gdb+打日志双重定位下,找到了耗时的代码范围

cpp 复制代码
            //这个函数在运行过程中被调用了多次
            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

bash 复制代码
 (1) cups 是一个开放源代码的打印系统,为Unix类操作系统(如Linux)提供了标准的打印架构。
 
 (2) libcupsprintersupport.so库为qt开发者提供更便捷的api, 
     libcupsprintersupport.so库内部调用的还是cups库api

我单独写了一个调用cups api的demo,进一步验证是cupsGetDests耗时

cpp 复制代码
            #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组件弹出慢

相关推荐
cs8219848313 小时前
QT 解决msvc fatal error C1060: 编译器的堆空间不足
开发语言·qt
m0_555762906 小时前
手势、鼠标滑动实现界面切换
c++·qt
bbqz0078 小时前
Qml Console
c++·qt·qml
cykaw259020 小时前
QT 文件选择对话框 QFileDialog
开发语言·qt
freshman_y1 天前
Qt实现车载多媒体项目,包含天气、音乐、视频、地图、五子棋功能模块,免费下载源文件!
开发语言·qt
www_pp_1 天前
# 创建一个功能完备的计算器应用:使用PyQt5和Python
开发语言·python·qt
神仙别闹1 天前
基于QT(C++)实现(图形界面)校园导览系统
数据库·c++·qt
feiyangqingyun1 天前
Qt/C++开发监控GB28181系统/警情订阅/目录订阅/报警事件上报/通道上下线
c++·qt·gb28181
繁星蓝雨1 天前
Qt中数据结构使用自定义类————附带详细示例
数据结构·c++·qt·qmap·qset
cykaw25901 天前
QT QList容器及行高亮
开发语言·qt