欢迎光临
我们一直在努力

QT笔记(一)QAxObject操作指南以及如何进行word、excel的编辑

前言
QAxObject主要于COM(Component Object Model)对象进行交互,简单来说就是对COM对象的封装。

QAxObject的主要函数

  • querySubObject()函数
    querySubObject获取COM对象中的子对象,并返回相应的QAxObject对象。使用此方法时,需要指定子对象的名称或者索引。例如:
  • #用于获取Documents对象,就是word的文档集合
    QAxObject *document = m_wordObject->querySubObject("Documents");

  • dynamicCall()函数
    dynamicCall动态调用对象的方法,可以在运行时动态调用对象的方法。这意味着可以根据具体的运行时条件选择不同的方法进行调用,而不需要在编译时确定调用哪个方法。
    该方法的参数是任意类型(基本类型、自定义类型等),并且支持传递多个参数,返回值也是任意类型。例如:
  • #添加文档,新建以模板类型的文档,传入参数为自定义模板路径
    document->dynamicCall("Add(QString)", m_templateFilePath);
    #新建一个空文档
    document->dynamicCall("Add()");

  • setProperty()函数
    setProperty设置对象属性,传入参数为属性的名称和属性的值。例如:
  • #设置是否显示窗口
    m_wordObject->setProperty("Visible", m_visable);

  • property函数
    property获取对象的属性值,传入参数为属性的名称,返回值为改属性的值。例如:
  • #获得页面左边距
    pageSetup->property("LeftMargin")

    访问word的对象模型(相关参数可以Microsoft Office的官方文档或者COM API文档)

    访问对象接口函数前首先要对接口进行初始化(一个进程对COM对象接口只需要初始化一次)

    //为当前线程初始化windows com的运行环境并指定当前线程的并发模型
    //COINIT_APARTMENTTHREADED , COINIT_MULTITHREADED
    HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);

    程序退出之前要终止服务函数也就是需要反初始化释放COM资源

    CoUninitialize();

  • 打开word
  • bool custom_wordEngine::open()
    {
    //先关闭再打开
    close();
    //为当前线程初始化windows com的运行环境并指定当前线程的并发模型
    //COINIT_APARTMENTTHREADED , COINIT_MULTITHREADED
    HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    if (SUCCEEDED(hr)){
    m_comInitialized = true;
    }
    QStringList progIds = {
    "word.Application",
    "kwps.Application",
    "wps.Application",
    };
    //创建一个com对象
    m_wordObject = new QAxObject();
    bool flag = false;
    for(const QString& progId : progIds){
    flag = m_wordObject->setControl( progId );
    if(flag){
    break;
    }else{
    std::string id = progId.toStdString();
    saError("Unable to start document:%s",id.c_str());
    }
    }
    if(!flag){
    if(m_wordObject != nullptr){
    delete m_wordObject;
    }
    return false;
    }
    //是否显示窗体
    m_wordObject->setProperty("Visible", m_visable);
    //获得所有工作文档
    QAxObject *document = m_wordObject->querySubObject("Documents");
    if(!document){
    saError("Unable to get working document");
    QAxObject *lastError = m_wordObject->querySubObject("GetLastError()");
    if(lastError){
    QString error = lastError->dynamicCall("Description()").toString();
    saError( "COM Error: %s",error.toStdString().c_str());
    delete lastError;
    }
    return false;
    }
    //是否以文件template.dot为模版新建一个文档
    if(m_templates){
    if(m_templateFilePath.isEmpty())
    return false;
    //判断文件是否文件不存在
    QFileInfo fileInfo(m_templateFilePath);
    if(!fileInfo.exists())
    return false;
    document->dynamicCall("Add(QString)", m_templateFilePath);
    }else{
    //新建一个新文档
    document->dynamicCall("Add()");
    }
    //获取当前激活的文档
    m_wordDocument = m_wordObject->querySubObject("ActiveDocument");
    //获得选定对象
    m_selection = m_wordObject->querySubObject("Selection");
    m_opened = true;
    return m_opened;
    }

    2.保存

    //word的保存是没有返回值的,因此需要自己判断文件是否保存成功,可以判断文件是否发生修改或者大小发生变化
    bool custom_wordEngine::saveAs(const QString &strWordFilePath)
    {
    //如果文件已存在,记录原始信息用于对比
    QFileInfo oldInfo(strWordFilePath);
    bool fileExisted = oldInfo.exists();
    QDateTime oldModified = oldInfo.lastModified();
    qint64 oldSize = oldInfo.size();

    QVariant result = m_wordDocument->dynamicCall("SaveAs(const QString&)",
    QDir::toNativeSeparators(strWordFilePath));

    QFileInfo newInfo(strWordFilePath);
    if(!newInfo.exists()){
    return false;
    }
    if(fileExisted){
    //检测旧文件是否覆盖修改
    if(newInfo.lastModified() == oldModified && newInfo.size() == oldSize){
    return false;
    }
    }else{
    //新文件大小
    if(newInfo.size() <= 0){
    return false;
    }
    }
    return true;
    }

  • 关闭并退出
  • bool custom_wordEngine::close()
    {
    //如果文档打开中
    if(m_opened){
    //关闭文档窗口
    if(m_wordDocument)
    m_wordDocument->dynamicCall("Close (bool)", true);
    //退出word
    if(m_wordObject)
    m_wordObject->dynamicCall("Quit()");
    //释放对象
    if(m_wordObject){
    delete m_wordObject;
    m_wordObject = nullptr;
    }
    m_opened = false;
    //反初始化
    if(m_comInitialized){
    CoUninitialize();
    m_comInitialized = false;
    }
    }
    return m_opened;
    }

  • 设置字体样式与内容
  • void custom_wordEngine::setText(const QString &text)
    {
    m_selection->dynamicCall("TypeText(QString&)", text);
    }

    void custom_wordEngine::setFont(QString strFamily, int nSize, bool bBold, bool bItalic, bool bUnderLine)
    {
    m_selection->querySubObject("Font")->setProperty("Name", strFamily);
    m_selection->querySubObject("Font")->setProperty("Size", nSize);
    m_selection->querySubObject("Font")->setProperty("Bold", bBold);
    m_selection->querySubObject("Font")->setProperty("Italic", bItalic);
    if(bUnderLine){
    m_selection->querySubObject("Font")->setProperty("Underline",2);
    }else{
    m_selection->querySubObject("Font")->setProperty("Underline",0);
    }
    }

  • 插入表格
  • int custom_wordEngine::insertTable(int row, int column)
    {
    m_selection->querySubObject("ParagraphFormat")->dynamicCall("Alignment", "wdAlignParagraphCenter");
    //m_selection->dynamicCall("TypeText(QString&)", "Table Test");//设置标题

    QAxObject *range = m_selection->querySubObject("Range");
    QAxObject *tables = m_wordDocument->querySubObject("Tables");
    QAxObject *table = tables->querySubObject("Add(QVariant,int,int)",range->asVariant(),row,column);

    //设置边框样式
    for(int i=1;i<=6;i++){
    QString str = QString("Borders(-%1)").arg(i);
    QAxObject *borders = table->querySubObject(str.toLatin1().data());
    borders->dynamicCall("SetLineStyle(int)",1);
    }

    //获取当前文档中所有表格的数量(新插入的表格是最后一个)
    QAxObject *allTables = m_wordDocument->querySubObject("Tables");
    int tableIndex = allTables->property("Count").toInt();
    return tableIndex;
    }

  • 设置单元格文本
  • void custom_wordEngine::setCellString(int tableIndex, int row, int column, const QString &text)
    {
    QAxObject* tables = m_wordDocument->querySubObject( "Tables" );
    QAxObject* table = tables->querySubObject("Item(int)", tableIndex);
    if(table){
    table->querySubObject("Cell(int, int)", row, column)->querySubObject("Range")->dynamicCall("SetText(QString)", text);
    table->querySubObject("Cell(int, int)", row, column);
    }
    }

  • 合并单元格
  • void custom_wordEngine::mergeCell(int tableIndex, int nStartRow, int nStartCol, int nEndRow, int nEndCol, bool bVerticalCenter)
    {
    QAxObject* tables = m_wordDocument->querySubObject("Tables");
    QAxObject* table = tables->querySubObject("Item(int)",tableIndex);
    QAxObject* StartCell =table->querySubObject("Cell(int, int)",nStartRow,nStartCol);
    QAxObject* EndCell = table->querySubObject("Cell(int, int)",nEndRow,nEndCol);

    //合并单元格
    //StartCell->querySubObject("Merge(QAxObject *)",EndCell->asVariant());
    StartCell->dynamicCall("Merge(IDispatch*)", EndCell->asVariant());

    //设置对齐方式 -上下对齐
    if(bVerticalCenter){
    StartCell->dynamicCall("VerticalAlignment", "wdCellAlignVerticalCenter");
    }else{
    m_selection->querySubObject("ParagraphFormat")->dynamicCall("Alignment", "wdAlignParagraphJustify");
    StartCell->dynamicCall("VerticalAlignment", "wdCellAlignVerticalTop");
    }
    }

  • 插入图片
  • //往单元格中插入图片
    void custom_wordEngine::insertCellPic(int tableIndex, int row, int column, const QString &picPath)
    {
    QAxObject* pTables = m_wordDocument->querySubObject( "Tables" );
    QAxObject* table = pTables->querySubObject("Item(int)", tableIndex);
    QAxObject* range = table->querySubObject("Cell(int, int)", row, column)->querySubObject("Range");
    range->querySubObject("InlineShapes")->dynamicCall("AddPicture(const QString&)",picPath);
    }
    //插入图片
    void custom_wordEngine::insertPicture(QString picturePath)
    {
    // 插入图片
    QAxObject* inlineShapes = m_selection->querySubObject("InlineShapes");
    QAxObject* shape = inlineShapes->querySubObject("AddPicture(const QString&)", picturePath);
    // 设置段落居中
    QAxObject* paragraphFormat = m_selection->querySubObject("ParagraphFormat");
    paragraphFormat->setProperty("Alignment", 1 /*wdAlignParagraphCenter*/);
    }

  • 使用案例
  • std::unique_ptr<custom_wordEngine> pWord(new custom_wordEngine(this));
    pWord->setVisable(false);
    pWord->setEnableTemplates(false);
    if(!pWord->open()){
    saError("Unable to open document");
    emit signals_save_failed();
    return;
    }
    QFileInfo fileInfo(m_saveWordFilePath);
    QString strWordName = fileInfo.baseName();

    QList<QList<QString>>datas;
    ///设置页边距
    pWord->setPageMargin(45,72,45,72);
    pWord->setFont("SimSun",15,true,false,false);
    pWord->setAlign(custom_wordEngine::AlignmentType::AlignmentTypeCenter);
    pWord->setText(strWordName);

    QStringList listHeader;
    listHeader.append(tr("深度(m)"));
    listHeader.append(tr("俯仰角(°)"));
    listHeader.append(tr("翻滚角(°)"));
    listHeader.append(tr("方位角(°)"));
    int tableRows = m_fileData.testPointData.size() + 1;
    //插入标题表格
    int tableIndex = pWord->insertTable(tableRows,7);
    pWord->setTableAlign(1,custom_wordEngine::AlignmentTypeCenter);
    for(int j = 0;j < listHeader.size();j++){
    pWord->setTableFont(tableIndex,1,j + 1,"SimSun",10,true,false,false);
    pWord->setCellString(tableIndex,1,j + 1,listHeader.at(i));
    }
    QString text = "";
    for(int j = 0;j < m_fileData.testPointData.size();j++){
    SH::POINTDATA pointData = m_fileData.testPointData.at(j);
    text = QString("%1").arg(pointData.Deep,0,'f',shAppConfig->deepDecimalPlacesIndex());
    pWord->setTableFont(tableIndex,j+2,1,"SimSun",10,false,false,false);
    pWord->setCellString(tableIndex,j+2,1,text);
    text = QString("%1").arg(pointData.Pitch,0,'f',shAppConfig->angleDecimalPlacesIndex());
    pWord->setTableFont(tableIndex,j+2,2,"SimSun",10,false,false,false);
    pWord->setCellString(tableIndex,j+2,2,text);
    text = QString("%1").arg(pointData.Roll,0,'f',shAppConfig->angleDecimalPlacesIndex());
    pWord->setTableFont(tableIndex,j+2,3,"SimSun",10,false,false,false);
    pWord->setCellString(tableIndex,j+2,3,text);
    text = QString("%1").arg(pointData.Yaw,0,'f',shAppConfig->angleDecimalPlacesIndex());
    pWord->setTableFont(tableIndex,j+2,4,"SimSun",10,false,false,false);
    pWord->setCellString(tableIndex,j+2,4,text);
    }
    //移动到结尾
    pWord->moveEnd();
    //换页
    pWord->skipPage();
    //保存
    pWord->saveAs(m_saveWordFilePath);

    访问excel的对象模型

  • 打开excel
  • bool custom_excelEngine::open()
    {
    //先关闭再打开
    close();
    //为当前线程初始化windows com的运行环境并指定当前线程的并发模型
    //COINIT_APARTMENTTHREADED , COINIT_MULTITHREADED
    HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    if (SUCCEEDED(hr)){
    m_comInitialized = true;
    }
    QStringList progIds = {
    "Excel.Application",
    "ket.Application",
    "et.Application",
    };
    //创建一个com对象
    m_excelObject = new QAxObject();
    bool flag = false;
    for(const QString& progId : progIds){
    flag = m_excelObject->setControl( progId );
    if(flag){
    break;
    }else{
    std::string id = progId.toStdString();
    saError("Unable to start document:%s",id.c_str());
    }
    }
    if(!flag){
    if(m_excelObject != nullptr){
    delete m_excelObject;
    }
    return false;
    }
    //是否显示窗体
    m_excelObject->setProperty("Visible", m_visable);
    //不显示任何警告信息。如果为true那么在关闭是会出现类似“文件已修改,是否保存”的提示
    m_excelObject->setProperty("DisplayAlerts", false);

    //获取工作簿集合
    QAxObject* workbooks = m_excelObject->querySubObject("WorkBooks");
    if(!workbooks){
    saError("Unable to get working excel");
    QAxObject *lastError = m_excelObject->querySubObject("GetLastError()");
    if(lastError){
    QString error = lastError->dynamicCall("Description()").toString();
    saError( "COM Error: %s",error.toStdString().c_str());
    delete lastError;
    }
    return false;
    }
    //新建一个工作簿
    workbooks->dynamicCall("Add()");
    //获取当前工作簿
    m_workbook = m_excelObject->querySubObject("ActiveWorkBook");
    //获取工作表集合
    QAxObject *worksheets = m_workbook->querySubObject("Sheets");
    //获取工作表集合的工作表1,即sheet1
    m_worksheet = worksheets->querySubObject("Item(int)", 1);

    m_opened = true;

    return m_opened;
    }

  • 保存
  • /bool custom_excelEngine::saveAs(const QString &strExcelFilePath)
    {
    //注意一定要用QDir::toNativeSeparators将路径中的"/"转换为"\\",不然一定保存不了。
    QVariant result = m_workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(strExcelFilePath));
    return result.toBool();
    }

  • 关闭并退出
  • bool custom_excelEngine::close()
    {
    //如果文档打开中
    if(m_opened){
    //关闭文档窗口
    if(m_workbook)
    m_workbook->dynamicCall("Close (bool)", true);
    //退出word
    if(m_excelObject)
    m_excelObject->dynamicCall("Quit()");
    //释放对象
    if(m_excelObject){
    delete m_excelObject;
    m_excelObject = nullptr;
    }

    m_opened = false;

    //反初始化
    if(m_comInitialized){
    CoUninitialize();
    m_comInitialized = false;
    }
    }
    return m_opened;
    }

  • 设置数据
  • //往某行某列写入数据
    void custom_excelEngine::setCellString(int row, int column, const QString &value)
    {
    QAxObject *range = m_worksheet->querySubObject("Cells(int,int)", row, column);
    range->dynamicCall("SetValue(const QString&)", value);
    }
    //往指定范围写入数据
    void custom_excelEngine::setCellString(const QString &cell, const QVariant &value)
    {
    QAxObject *range = m_worksheet->querySubObject("Range(const QString&)", cell);
    range->setProperty("NumberFormatLocal","@"); //设置所有单元格为文本属性
    range->setProperty("Value2", value);
    }

  • 使用案例
  • std::unique_ptr<custom_excelEngine> pExcel(new custom_excelEngine(this));
    pExcel->setVisable(false);
    if(!pExcel->open()){
    saError("Unable to open excel");
    emit signals_save_failed();
    return;
    }
    //表格标题
    QList<QVariant> excelTitles;
    excelTitles.append(tr("序号"));
    excelTitles.append(tr("俯仰角(°)"));
    excelTitles.append(tr("翻滚角(°)"));
    excelTitles.append(tr("方位角(°)"));
    excelTitles.append(tr("测试深度(m)"));

    //以二维数组的形式存储预写入数据
    QList<QList<QVariant>> testingDatas;

    //添加标题
    testingDatas.append(excelTitles);

    for (int i = 0;i < m_fileInfoList.size();i++){
    SH::FileINFO fileInfo = m_fileInfoList.at(i);
    QString filePath = QString("%1/%2").arg(fileInfo.folderPath).arg(fileInfo.fileName);
    FileOperate fileOperate;
    if(!fileOperate.readFile(filePath,m_fileData)){
    continue;
    }
    for(int j = 0;j<m_fileData.testPointData.size();j++){

    //实测数据表格
    QList<QVariant> testingCols;
    testingCols.append(QString("%1").arg(j));
    testingCols.append(QString("%1").arg(m_fileData.testPointData.at(j).Pitch,0,'f',2));
    testingCols.append(QString("%1").arg(m_fileData.testPointData.at(j).Roll,0,'f',2));
    testingCols.append(QString("%1").arg(m_fileData.testPointData.at(j).Yaw)),0,'f',2));
    testingCols.append(QString("%1").arg(m_fileData.testPointData.at(j).Deep,0,'f',2));
    testingDatas.append(testingCols);
    }
    }
    //单个写入数据
    pExcel->mergeCells(1,1,1,11);
    pExcel->setCellString(1,1,tr("数据表格"));
    //二维数组转一维转变量
    QList<QVariant> vars;
    for(auto v:testingCols){
    vars.append(QVariant(v));
    }
    QVariant var = QVariant(vars);
    //获得指定范围
    QString cell;
    cell.append(QChar('A'));
    cell.append(QString::number(2));
    cell.append(QString(":"));
    cell.append(QChar::fromLatin1(excelTitles.size() 1 + 'A'));
    cell.append(QString::number(designDatas.size() + 1));
    //往指定范围类批量写入数据
    pExcel->setCellString(cell,var);
    //保存
    pExcel->saveAs(m_saveExcelFilePath);

    注意:往Excel表格中写入数据时,如果逐一单元格的写入会异常的缓慢,这是由于每次写入都要跨进程通信调用excel进程。所以推荐将数据包装成变量QVariant,一次性写入,避免频繁跨进程调用。

    赞(0)
    未经允许不得转载:171主机测评 » QT笔记(一)QAxObject操作指南以及如何进行word、excel的编辑
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址