当前位置: 首页 > article >正文

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组件弹出慢


http://www.kler.cn/a/595214.html

相关文章:

  • 计算机技术系列博客——目录页(持续更新)
  • git 设置保存密码 git保存密码
  • 大屏技术汇集【目录】
  • 在Springboot中集成unihttp后应用无法启动的解决办法
  • HTML 中如何设置页面的语言,这对 SEO 和无障碍访问有什么影响?
  • MySQL 中,查看执行频次、慢查询日志、SHOW PROFILE和 EXPLAIN性能分析和优化
  • 如何自定义知行之桥Webhook端口返回的Response消息
  • C#使用SnsPictureBox.dll绘制点,线段、圆、折线、多边形、测量尺等多种图形。
  • 【大模型LLM第十三篇】Agent入门之CoT,self-ask,Plan-and-execute,ReAct串讲
  • 【pytest框架源码分析五】pytest插件的注册流程
  • AtCoder - arc086_d Shift and Decrement分析与实现
  • 深度剖析淘宝拍立淘按图搜索商品API技术规范
  • Hinton提出的知识蒸馏(Knowledge Distillation,简称KD):原理解释和代码实现
  • Babel 从入门到精通(二):Plugin插件和Preset预设配置详解
  • Java多线程与高并发专题——Callable 和 Runnable 的不同?
  • windows单节点验证victoriametrics结合AlertManger实现告警推送webhook
  • 分布式容器技术是什么
  • MySQL:表的增删查改
  • nginx 反向代理 ubuntu
  • 噪声的类型