Qt 学习(一) addressbook

Qt Demo: addressbook
(1)创建项目:选择不创建界面,即UI,此时会自动生成的文件如图所示:
在这里插入图片描述
QApplication:
MainWindow 继承自 QMainWindow,根据需要设计的界面样式。

(2)确定MainWindow 的成员变量
在这里插入图片描述
首先,从此张界面图推断出 MainWindow 的组成:

  1. 一个QTabWidget;
  2. 两个QMenu: Files Tools;点击之后弹出的选项为:QAction;QAction 绑定槽函数
    MainWindow 包含的成员对象:
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow();
private slots:
    void updateActions(const QItemSelection &selection);
    void openFile();
    void saveFile();
private:
    void createMenus();

    AddressWidget *addressWidget;
    QMenu *fileMenu;
    QMenu *toolMenu;
    QAction *openAct;
    QAction *saveAct;
    QAction *exitAct;
    QAction *addAct;
    QAction *editAct;
    QAction *removeAct;
};

(3)在MainWindow中设置 centralwidget 以及 title, 并添加menu 以及 action,再绑定槽函数

setCentralWidget
setWindowTitle
fileMenu = menuBar()->addMenu(tr("&File"));
openAct = new QAction(tr("&Open"),this);
fileMenu->addAction(openAct);
connect(openAct,&QAction::triggered,this,&MainWindow::open_file);

为两个menu 添加了三个可点击的控件,对应的槽函数需要根据代码架构来设计。

// Open file
QString file_name = QFileDialog().getOpenFileName(this);
// Save file
QString file_name = QFileDialog().getSaveFileName(this);

(4)QTabWidget
添加tab: QtableView、 QWidget

QTableView* tableview = new QtableView();
// QTableView 设置一系列属性
// int addTab(QWidget* widget, const QString&);
addTab(tableview, str); 

model-view
QAbstractListModel QAbstractTableModel
索引:QModelIndex
role: ItemDataRole
实现自己的model类:

class tableModel : public QAbstractTableModel
{
public:
    tableModel(QObject* parent = nullptr);

// virtual function
//  must override this 3 funciton when use QAbstractTableModel
    int rowCount(const QModelIndex &parent) const override;
    int columnCount(const QModelIndex &parent) const override;
    QVariant data(const QModelIndex &index, int role) const override;

//  must override this 2 funciton when edit data
    Qt::ItemFlags flags(const QModelIndex &index) const override;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;

//  must override this 2 funciton when change rows
    bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
    bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;

//  must override this 1 funciton when use table header
    QVariant headerData(int section, Qt::Orientation orientation, int role) const override;

    const QVector<Contact> &getContacts() const;

private:
    QVector<Contact> _contacts;
};

(5) 槽函数:添加,修改,删除
每一个{name, address} 都是通过一个 QDialog 添加;
此界面包含的控件:QLineEdit;QTextEdit;QLabel;QPushButton
layout:QGridLayout;QHBoxLayout;QVBoxLayout
在这里插入图片描述

addDialog::addDialog(QWidget* parent)
{
    _name = new QLineEdit();
    _address = new QTextEdit();
    auto nameLabel = new QLabel("Name");
    auto addressLabel = new QLabel("Address");

    auto layout = new QGridLayout();
    layout->setColumnStretch(1,2);

    layout->addWidget(nameLabel,0,0);
    layout->addWidget(_name,0,1);
    layout->addWidget(addressLabel,1,0,Qt::AlignLeft|Qt::AlignTop);
    layout->addWidget(_address,1,1,Qt::AlignLeft);

    auto okBtn = new QPushButton("OK");
    auto cancelBtn = new QPushButton("Cancel");

    auto btnLayout = new QHBoxLayout;
    btnLayout->addWidget(okBtn);
    btnLayout->addWidget(cancelBtn);
    layout->addLayout(btnLayout,2,1,Qt::AlignRight);

    auto mainLayout = new QVBoxLayout;
    mainLayout->addLayout(layout);
    setLayout(mainLayout);
    setWindowTitle("Add a Contact");

    connect(okBtn,&QAbstractButton::clicked,this,&QDialog::accept);
    connect(cancelBtn, &QAbstractButton::clicked, this, &QDialog::reject);
}

添加:

void addressWidget::show_add_entry_dialog()
{
    qDebug()<<"show_add_entry_dialog"<<endl;
    addDialog add_dialog;
    if(add_dialog.exec())
    {
        qDebug()<<"add_dialog.exec()"<<endl;
        add_entry(add_dialog.name(),add_dialog.address());
    }
}
void addressWidget::add_entry(const QString& name, const QString& address)
{
    qDebug()<<"add_entry"<<"name:"<<name<<"address:"<<address<<endl;
    if(!_table_model->getContacts().contains({name,address}))
    {
        _table_model->insertRows(0,1,QModelIndex());
        QModelIndex index = _table_model->index(0,0,QModelIndex());
        _table_model->setData(index,name,Qt::EditRole);

        index = _table_model->index(0,1,QModelIndex());
        _table_model->setData(index,address);
        removeTab(indexOf(_new_address_tab));
    }
    else
    {
        qDebug()<<"duplicate name"<<endl;
    }
}

修改

void AddressWidget::editEntry()
{
    QTableView *temp = static_cast<QTableView*>(currentWidget());
    QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model());
    QItemSelectionModel *selectionModel = temp->selectionModel();

    const QModelIndexList indexes = selectionModel->selectedRows();
    QString name;
    QString address;
    int row = -1;

    for (const QModelIndex &index : indexes) {
        row = proxy->mapToSource(index).row();
        QModelIndex nameIndex = table->index(row, 0, QModelIndex());
        QVariant varName = table->data(nameIndex, Qt::DisplayRole);
        name = varName.toString();

        QModelIndex addressIndex = table->index(row, 1, QModelIndex());
        QVariant varAddr = table->data(addressIndex, Qt::DisplayRole);
        address = varAddr.toString();
    }
    AddDialog aDialog;
    aDialog.setWindowTitle(tr("Edit a Contact"));
    aDialog.editAddress(name, address);

    if (aDialog.exec()) {
        const QString newAddress = aDialog.address();
        if (newAddress != address) {
            const QModelIndex index = table->index(row, 1, QModelIndex());
            table->setData(index, newAddress, Qt::EditRole);
        }
    }
}

删除

void AddressWidget::removeEntry()
{
    QTableView *temp = static_cast<QTableView*>(currentWidget());
    QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model());
    QItemSelectionModel *selectionModel = temp->selectionModel();

    const QModelIndexList indexes = selectionModel->selectedRows();

    for (QModelIndex index : indexes) {
        int row = proxy->mapToSource(index).row();
        table->removeRows(row, 1, QModelIndex());
    }

    if (table->rowCount(QModelIndex()) == 0)
        insertTab(0, newAddressTab, tr("Address Book"));
}

(6)存储数据

void AddressWidget::writeToFile(const QString &fileName)
{
    QFile file(fileName);

    if (!file.open(QIODevice::WriteOnly)) {
        QMessageBox::information(this, tr("Unable to open file"), file.errorString());
        return;
    }

    QDataStream out(&file);
    out << table->getContacts();
}

读取数据:

void AddressWidget::readFromFile(const QString &fileName)
{
    QFile file(fileName);

    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::information(this, tr("Unable to open file"),
            file.errorString());
        return;
    }

    QVector<Contact> contacts;
    QDataStream in(&file);
    in >> contacts;
    if (contacts.isEmpty()) {
        QMessageBox::information(this, tr("No contacts in file"),
                                 tr("The file you are attempting to open contains no contacts."));
    } else {
        for (const auto &contact: qAsConst(contacts))
            addEntry(contact.name, contact.address);
    }
}

Contacts 需要重载流运算符

inline QDataStream &operator<<(QDataStream &stream, const Contact &contact)
{
    return stream << contact.name << contact.address;
}

inline QDataStream &operator>>(QDataStream &stream, Contact &contact)
{
    return stream >> contact.name >> contact.address;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/745771.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何运用Midjourney探究新中式美学?

新中式美学最近真是越来越火了&#xff0c;把传统中式元素和现代设计结合起来&#xff0c;不仅看着舒服&#xff0c;还特别有文化韵味。 1. 研究和准备 首先&#xff0c;得先弄清楚什么是新中式美学。说白了&#xff0c;就是把传统中式元素和现代设计结合起来。你可以看看相关…

RabbitMQ实践——超时消息的处理方法

大纲 准备工作整个队列的消息都有相同的时效性抛弃超时消息新建带x-message-ttl的队列新建绑定关系实验 超时消息路由到死信队列新建带死信和ttl的队列新建绑定关系实验 消息指定自己的超时时间新建带死信的队列绑定实验 消息自带TTL和队列TTL的关系消息TTL < 队列指定TTL消…

使用 Ubuntu x86_64 平台交叉编译适用于 Linux aarch64(arm64) 平台的 QT5(包含OpenGL/WebEngine支持) 库

使用 Ubuntu AMD64 平台交叉编译适用于 Linux ARM64 平台的 QT5(包含 OpenGL/WebEngine 支持) 库 目录 使用 Ubuntu AMD64 平台交叉编译适用于 Linux ARM64 平台的 QT5(包含 OpenGL/WebEngine 支持) 库写在前面前期准备编译全流程1. 环境搭建2. 复制源码包并解压&#xff0c;创…

django 和 pyecharts实现可视化大屏(完整代码)

1.配置settings文件 &#xff08;1&#xff09;注意&#xff1a;需要先创建app(djnago-admin startapp app名称) &#xff08;2&#xff09;配置模板文件 DIRS: [os.path.join(BASE_DIR, templates)], &#xff08;3&#xff09;配置静态文件(这里我由于存放清洗好的需要进行可…

数据结构与算法笔记:高级篇 - 位图:如何实现网页爬虫中的URL去重功能?

概述 网页爬虫是搜索引擎中的非常重要的系统&#xff0c;复杂爬取几十亿、上百亿额度网页。爬虫的工作原理是&#xff0c;通过解析已经爬取网页中的网页链接&#xff0c;然后再爬取这些链接对应地网页。而同一个网页链接有可能被包含在多个页面中&#xff0c;这就会导致爬虫在…

测试开发是什么?为什么现在那么多公司都要招聘测试开发?

测试开发是一种软件开发过程中的一种角色&#xff0c;旨在提高软件质量并确保软件功能完善和稳定。测试开发人员负责编写和执行自动化测试脚本&#xff0c;创建测试工具和框架&#xff0c;以及与开发人员紧密合作&#xff0c;提供实时反馈和改进。 为什么现在那么多公司都要招…

RISC-V异常处理流程概述

RISC-V异常处理流程概述 一、RISC-V异常处理流程和异常委托1.1 异常处理流程1.2 异常委托二、RISC-V异常处理中软件相关内容2.1 异常处理准备工作2.2 异常处理函数2.3 Opensbi系统调用的注册三、参考资料一、RISC-V异常处理流程和异常委托 1.1 异常处理流程 发生异常时,首先…

聚乙烯醇(PVA)涂布型薄膜是高阻隔性包装材料 我国市场增长快速

聚乙烯醇&#xff08;PVA&#xff09;涂布型薄膜是高阻隔性包装材料 我国市场增长快速 聚乙烯醇&#xff08;PVA&#xff09;涂布型薄膜&#xff0c;是以其他塑料薄膜&#xff08;主要是双向拉伸薄膜&#xff09;为基材&#xff0c;以聚乙烯醇为涂料&#xff0c;经表面涂布后制…

如何从0构建一款类jest工具

Jest工作原理 Jest 是一个流行的 JavaScript 测试框架&#xff0c;特别适用于 React 项目&#xff0c;但它也可以用来测试任何 JavaScript 代码。Jest 能够执行用 JavaScript 编写的测试文件的原因在于其设计和内部工作原理。下面是 Jest 的工作原理及其内部机制的详细解释&…

C语言的学习发展路线(都是干货)

哈喽&#xff0c;大家好呀~我又回来了&#xff0c;前期比较忙&#xff0c;没有时间来更文&#xff0c;现在给大家推荐了一个C语言的学习路线&#xff0c;供大家一起学习啦&#xff01; 1. 环境搭建与工具篇 选择编译器&#xff1a;常用的编译器有gcc、Clang、Visual Studio等。…

第一个Java程序--HalloWorld(记事本版)

一、开发步骤 1.编写 将 Java 代码编写到扩展名为 .java 的源文件中 class HelloChina{public static void main(String[] args){System.out.println("HelloWorld!");} } 2.编译 winr进入DOS操作系统&#xff0c;进入当前目录。&#xff08;操作命令见《JAVA概述…

红酒哲学:品味流转时光,探寻生活之深邃奥秘

在繁华的都市中&#xff0c;我们时常被各种声音和色彩所包围&#xff0c;追求着速度与激情。然而&#xff0c;在这喧嚣之中&#xff0c;总有那么一刻&#xff0c;我们渴望静下心来&#xff0c;品味一份不同的宁静与深度。这时&#xff0c;一杯雷盛红酒便成了我们与内心对话的桥…

Ubuntu磁盘分区和挂载 虚拟机扩容 逻辑卷的创建和扩容保姆及教程

目录 1、VMware虚拟机Ubuntu20.04系统磁盘扩容 2、Linux的磁盘分区和挂载 3、创建逻辑卷和逻辑卷的扩容 1、VMware虚拟机Ubuntu20.04系统磁盘扩容 通过下图可以看出我们的根磁盘一共有20G的大小&#xff0c;现在我们把它扩容为30G 注&#xff1a;如果你的虚拟机有快照是无…

鸿萌数据迁移业务案例:为医药客户成功迁移重要科研数据

天津鸿萌科贸发展有限公司对 Windows 及 Linux 系统下的各类型备份及数据迁移业务积累了丰富的业务经验&#xff0c;可提供针对性的解决方案。 医药科研数据迁移成功案例 2024年6月初&#xff0c;天津某医药厂家埃尔法 workstation2020 服务器硬盘老化&#xff0c;为保证服务…

小白上手AIGC-基于PAI-DSW部署Stable Diffusion文生图Lora模型

小白上手AIGC-基于PAI-DSW部署Stable Diffusion文生图Lora模型 前言资源准备开启体验服务创建工作空间 部署服务创建DSW实例安装Diffusers启动WebUI 写在最后 前言 在上一篇博文小白上手AIGC-基于FC部署stable-diffusion 中&#xff0c;说到基于函数计算应用模板部署AIGC文生图…

这么精彩的排序算法,你确定不来看一下?

目录 1.交换函数&#xff1a; 2.三数取中&#xff1a; 一.插入排序&#xff1a; 二.希尔排序&#xff1a; 三.选择排序&#xff1a; 四.快速排序&#xff1a; 1.霍尔法&#xff08;递归版&#xff09;&#xff1a; 2.挖坑法&#xff08;递归版&#xff09;&#xff1a; 3.双指针…

智领全栈,模力全开|2024中国智算中心全栈技术大会,锐捷网络引爆智算网络新风潮

6月25日至27日&#xff0c;2024中国智算中心全栈技术大会暨展览会、第5届中国数据中心绿色能源大会暨第10届中国(上海)国际数据中心产业展览会在上海新国际博览中心隆重开幕。此次大会由CDCC和益企研究院主办&#xff0c;以“AI赋能&#xff0c;重构未来”为主题&#xff0c;吸…

重温react-06

开始 函数组件必然成为未来发展的趋势(个人见解),总之努力的去学习,才能赚更多的钱.加油呀! 函数组件的格式 import React from reactexport default function LearnFunction01() {return (<div>LearnFunction01</div>) }以上是函数式组件的组基本的方式 快捷生…

如何提高工业交换机的电源功耗?

工业交换机的电源功耗是指在工作状态下所消耗的能量。随着工业自动化技术的发展&#xff0c;工业交换机在生产和制造领域中扮演着至关重要的角色。它们通过连接各种设备和系统&#xff0c;实现信息的传输和处理&#xff0c;提高生产效率和质量。然而&#xff0c;工业交换机的大…

springAI孵化(二)

目录 一、spring AI 目的 二、spring AI 来源 三、sprig AI 是什么&#xff1f; 四、spring AI中的 概念 4.1、模型&#xff08;Models&#xff09; 4.2、提示&#xff08;Prompts&#xff09; 4.3、提示模板&#xff08;Prompt Templates&#xff09; 4.4、令 牌&…