草庐IT

Qt案例:实现显示图片

摩天仑 2023-07-17 原文

效果图:

17.1 组件使用

17.1.1 QDockWidget

含义:停靠区窗口,和状态栏、标题栏是一个等级

属性:

  • allowedAreas:设置允许停靠区域,或者使用代码setAllowedAreas(Qt::DockWidgetAreas areas)
  • features:设置停靠的属性。setFeatures(DockWidgetFeatures features)

17.1.2 QTreeWidget

含义:目录树

属性:

  • Columns页用于设计目录树的列,目录树可以有多个列。在设计器里可以添加、删除、移动列,设置列的文字、字体、前景色、背景色、文字对齐方式、图标等。

  • Items页面用于设计目录树的节点,可对每个节点设置属性,如文字、字体、图标等,特别是fags属性,可以设置节点是否可选、是否可编辑、是否有CheckBox等,还可以设置节点的CheckState。

17.2 Action

17.3 定义基本变量

private:
    // 创建节点时用作type参数,自定义类型必须大于1000
    enum treeItemType{
        itTopItem = 1001,
        itGroupItem,
        itImageItem
    };
    enum treeColNum{
        colItem=0,
        colItemType=1
    };

    QLabel *LabFileName;// 显示状态栏文件名称
    QPixmap curPixmap; // 当前图片
    float pixRatio; // 当前图片比例


    // 初始化目录树
    void initTree();

    void addFolderItem(QTreeWidgetItem *parItem,QString dirName); // 添加目录

    QString getFinalFolderName(const QString &fullPathName); // 提取目录名称

    void addImageItem(QTreeWidgetItem *parItem,QString aFilename); // 添加图片

    void displayImage(QTreeWidgetItem *item); // 显示一个图片节点的图片

    void changeItemCaption(QTreeWidgetItem *item); // 遍历改变节点标题

17.4 目录树初始化

添加顶层节点

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 状态栏显示文件名
    LabFileName = new QLabel("");
    ui->statusBar->addWidget(LabFileName);
    // 设置中心窗体
    this->setCentralWidget(ui->scrollArea);
    // 初始化目录树
    initTree();
}

void MainWindow::initTree()
{
    QString dataStr = "";
    ui->treeWidget->clear(); // 清空目录树
    QIcon icon;
    icon.addFile(":/icons/icons/15.ico");

    QTreeWidgetItem *item = new QTreeWidgetItem(MainWindow::itTopItem); //?
    item->setIcon(MainWindow::colItem,icon); // 第一列图标
    item->setText(MainWindow::colItem,"图片文件"); // 第一列文字
    item->setText(MainWindow::colItemType,"type=itTopItem"); // 第二列文字
    item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsAutoTristate | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
    item->setCheckState(colItem,Qt::Checked); // 第一列勾选
    item->setData(MainWindow::colItem,Qt::UserRole,QVariant(dataStr)); //?
    ui->treeWidget->addTopLevelItem(item);// 添加顶层节点

}
  • QTreeWidget的每个节点都是一个QTree WidgetItem对象,添加一个节点前需先创建它,并做好相关设置。
  • setData()函数为节点的某一列设置一个角色数据,setData()函数原型为:void() TreeWidgetItem::setData(int column,int role,const QVariant &value)

item->setData(MainWindow:colItem,Qt::UserRole,QVariant (datastr));

它为节点的第1列,角色Qt:UserRole,设置了一个字符串数据dataStr.Qt:UserRole是枚举类型Qt:ItemDataRole中一个预定义的值。

17.5 添加目录节点

定义3个函数

// 获取文件名称
QString MainWindow::getFinalFolderName(const QString &fullPathName)
{
    return fullPathName.right(fullPathName.length()-fullPathName.lastIndexOf("/")-1);
}
// 添加节点函数
void MainWindow::addFolderItem(QTreeWidgetItem *parItem, QString dirName)
{
    QIcon icon(":/icons/icons/open3.bmp");
    QString NodeText = getFinalFolderName(dirName);

    QTreeWidgetItem *item = new QTreeWidgetItem(MainWindow::itGroupItem); // 传入目录的节点类型type值1001
    item->setIcon(colItem,icon);
    item->setText(colItem,NodeText);
    item->setText(colItemType,"type:itGroupItem");
    item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsAutoTristate | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
    item->setCheckState(colItem,Qt::Checked);
    item->setData(colItem,Qt::UserRole,QVariant(dirName));
    parItem->addChild(item); // 在父节点添加子节点
}
// action关联函数
void MainWindow::on_actAddFolder_triggered()
{
    QString fullname = QFileDialog::getExistingDirectory();
    if(!fullname.isEmpty()){
        QTreeWidgetItem *parItem = ui->treeWidget->currentItem();
        if(parItem){
            addFolderItem(parItem,fullname);
        }else {
            // 创建弹窗
            QMessageBox::critical(this, tr("危险弹窗"),  tr("请选择目标节点"),QMessageBox::Save | QMessageBox::Discard,  QMessageBox::Discard);
        }
    }
    else {
         return;
    }

}

17.6 添加图片节点

QFileDialog::getOpenFileNames函数可以实现添加多个文件

实现:

  1. 创建临时变量parItem和item;
  2. parItem用于最终的添加目标,item存放当前节点;
  3. 如果当前节点是文件节点或者顶层节点,则目标节点是当前节点;
  4. 如果当前节点是图片节点,则目标节点是图片节点的父节点(图片节点为末尾节点,后面不能添加子节点);
  5. 使用for循环分别获取文件的名称,并添加到目标节点下;
void MainWindow::addImageItem(QTreeWidgetItem *parItem, QString aFilename)
{
    QIcon icon(":/icons/icons/31.ico");
    QString NodeText = getFinalFolderName(aFilename);
    QTreeWidgetItem *item;
    item = new QTreeWidgetItem(MainWindow::itImageItem);
    item->setIcon(colItem,icon);
    item->setText(colItem,NodeText);
    item->setText(colItemType,"type=itImageItem");
    item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsAutoTristate | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
    item->setData(colItem,Qt::UserRole,QVariant(aFilename));
    parItem->addChild(item); // 在父节点添加子节点
}
void MainWindow::on_actAddFiles_triggered()
{
    QStringList files = QFileDialog::getOpenFileNames(this,"选择一个或者多个文件","","Images(*.jpg)");
    if(files.isEmpty())
        return;

    QTreeWidgetItem *parItem,*item;
    item = ui->treeWidget->currentItem();
    if(item){
        if(item->type()==itImageItem) // 当前节点是图片节点
            parItem = item->parent();
        else {
            parItem=item;
        }
        for (int i = 0;i<files.size();++i) {
            QString aFilename = files.at(i);
            addImageItem(parItem,aFilename);
        }
    }else {
            QMessageBox::critical(this, tr("危险弹窗"),  tr("请选择目标节点"),QMessageBox::Save | QMessageBox::Discard,  QMessageBox::Discard);
        }
}

17.7 当前节点发生变化响应

QTreeWidget会发出currentItemChanged信号

实现:

  1. 获取当前节点的类型;
  2. 判断当前选中的节点属于哪个类型;
  3. 根据类型设置添加、删除等按钮的状态;
  4. 如果为图片节点,调用图片显示函数;

代码实现:

void MainWindow::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    Q_UNUSED(previous);
    if(current==NULL)
        return;
    int var = current->type();
    switch (var) {
        case itTopItem:
            ui->actAddFolder->setEnabled(true);
            ui->actAddFiles->setEnabled(true);
            ui->actDeleteItem->setEnabled(false);
            break;
        case itGroupItem:
            ui->actAddFolder->setEnabled(true);
            ui->actAddFiles->setEnabled(true);
            ui->actDeleteItem->setEnabled(true);
            break;
        case itImageItem: // 当前选中为图片,不能添加子节点,显示图片
            ui->actAddFolder->setEnabled(false);
            ui->actAddFiles->setEnabled(true);
            ui->actDeleteItem->setEnabled(true);
            ui->actZoomFitH->setEnabled(true);
            ui->actZoomFitW->setEnabled(true);
            ui->actZoomIn->setEnabled(true);
            ui->actZoomOut->setEnabled(true);
            ui->actZoomRealSize->setEnabled(true);
            displayImage(current);
            break;
        }
}

17.8 删除节点

删除节点使用QTreeWidgetItem对象上的removeChild函数

实现:

  1. 获取当前节点;
  2. 获取当前节点的父节点;
  3. 从父节点中删除子节点;

代码实现:

void MainWindow::on_actDeleteItem_triggered()
{
    QTreeWidgetItem *item = ui->treeWidget->currentItem();
    QTreeWidgetItem *parItem = item->parent();
    parItem->removeChild(item);
    delete item; // 删除子节点的内存空间。removveChild只能从父节点中删除子节点,但不能移除子节点的内存空间。
}

17.9 遍历节点

使用递归调用

int topLevelItemCount():返回顶层节点个数。
QTree WidgetItemtopLevelItem(int index):返回序号为index的顶层节点。

int topLevelItemCount():返回顶层节点个数。
QTree WidgetItem*topLevelItem(int index):返回序号为index的顶层节点。

实现:

  1. 获取全部的顶层节点,遍历更改;
  2. 更改每个节点后,获取全部子节点并更改;

代码实现:

void MainWindow::on_actScanItems_triggered()
{
    int cnt = ui->treeWidget->topLevelItemCount();
    for(int i = 0;i<cnt;++i){
        QTreeWidgetItem *item = ui->treeWidget->topLevelItem(i); // 顶层节点
        changeItemCaption(item); // 调用【更改节点标题】函数
    }
}
void MainWindow::changeItemCaption(QTreeWidgetItem *item)
{
    // 节点标题前加*
    QString str = "*" + item->text(colItem);
    item->setText(colItem,str);

    if(item->childCount()>0){
        for (int i = 0;i<item->childCount();i++) {
            changeItemCaption(item->child(i));
        }
    }
}

17.10 显示节点的图片

curPixmap是在MainWindow中定义的一个QPixmap类型的变量,用于操作图片。QPixmap:load(QString&cfileName)直接将一个图片文件载入。

实现:

  1. 获取存入的文件名称并在状态栏显示名称;
  2. 调用QPixmap下的load函数载入图片;
  3. 自适应高度显示图片;

这里还显示不了,还未写自适应高度显示action;

void MainWindow::displayImage(QTreeWidgetItem *item)
{
    QString filename = item->data(colItem,Qt::UserRole).toString(); // 获取文件名,之前用setData存的数据
    LabFileName->setText(filename); // 状态栏显示图片名称
    curPixmap.load(filename); // 当前图片
    on_actZoomFitH_triggered(); // 自适应高度显示
}

17.11 图片显示与缩放

QPixmap存储图片数据,可以缩放图片,有以下几个函数。

  • QPixmap scaledToHeight(int height):返回一个缩放后的图片的副本,图片缩放到一个高度height.
  • QPixmap scaledTo Width(int width):返回一个缩放后的图片的副本,图片缩放到一个宽度width.
  • QPixmap scaled(int width,.int height):返回一个缩放后的图片的副本,图片缩放到宽度width和高度height,缺省为不保持比例。

变量curPixmap保存了图片的原始副本,要缩放只需调用curPixmap的相应函数,返回缩放后的图片副本。在界面上的一个标签LabPicture上显示图片,使用了QLabel的setPixmap(const QPixmap&)函数。

void MainWindow::on_actZoomFitH_triggered()
{
    // 自适应高度显示
    int H = ui->scrollArea->height(); // 获取当前滑动块的高度
    int realH = curPixmap.height(); // 获取当前图片的高度
    pixRatio = float(H)/realH; // 当前图片显示的比例(必须是浮点数)
    QPixmap pix = curPixmap.scaledToHeight(H-30); // 图片缩放指定高度
    ui->label->setPixmap(pix); // label标签显示图片
}

void MainWindow::on_actZoomFitW_triggered()
{
    // 自适应宽度显示
    int W = ui->scrollArea->width(); // 获取当前滑动块的高度
    int realW = curPixmap.width(); // 获取当前图片的高度
    pixRatio = float(W)/realW; // 当前图片显示的比例(必须是浮点数)
    QPixmap pix = curPixmap.scaledToWidth(W-30); // 图片缩放指定高度
    ui->label->setPixmap(pix); // label标签显示图片
}

void MainWindow::on_actZoomIn_triggered()
{
    // 放大显示
    pixRatio = pixRatio*1.2;
    int w = pixRatio*curPixmap.width();
    int h = pixRatio*curPixmap.height();
    QPixmap pix = curPixmap.scaled(w,h);
    ui->label->setPixmap(pix);
}

void MainWindow::on_actZoomOut_triggered()
{
    // 缩小显示
    pixRatio = pixRatio*0.8;
    int w = pixRatio*curPixmap.width();
    int h = pixRatio*curPixmap.height();
    QPixmap pix = curPixmap.scaled(w,h);
    ui->label->setPixmap(pix);
}

void MainWindow::on_actZoomRealSize_triggered()
{
    // 实际大小
    pixRatio = 1;
    ui->label->setPixmap(curPixmap);
}

17.12 dockWidget

只写action按钮的动作,手动拖动dockWidget时按钮的状态不会改变,需要使用dockWidget上的信号;

隐藏发射信号visibilityChanged(bool)
浮动、停靠信号topLevelChanged(bool)

void MainWindow::on_actDockVisible_toggled(bool arg1)
{
    ui->dockWidget->setVisible(arg1);
}

void MainWindow::on_actDockFloat_toggled(bool arg1)
{
    ui->dockWidget->setFloating(arg1);
}

void MainWindow::on_dockWidget_topLevelChanged(bool topLevel)
{
    ui->actDockFloat->setChecked(topLevel);
}

void MainWindow::on_dockWidget_visibilityChanged(bool visible)
{
    ui->actDockVisible->setChecked(visible);
}

有关Qt案例:实现显示图片的更多相关文章

  1. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  4. ruby-on-rails - link_to 不显示任何 rails - 2

    我试图在索引页中创建一个超链接,但它没有显示,也没有给出任何错误。这是我的index.html.erb代码。ListingarticlesTitleTextssss我检查了我的路线,我认为它们也没有问题。PrefixVerbURIPatternController#Actionwelcome_indexGET/welcome/index(.:format)welcome#indexarticlesGET/articles(.:format)articles#indexPOST/articles(.:format)articles#createnew_articleGET/article

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  7. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

    目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

  8. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

随机推荐