用Qt搭建图书管理系统(七)

 

第七章 借书与还书(二)

 

https://gitee.com/mayonaka/LibraryManageSystem

百度云:https://pan.baidu.com/s/1G95yPyGG080b6yXcjc8B0g

提取码:4q8b

 

上一章我们建了一个基类用来作为还书界面与借书界面的基类,这一章,我们就来具体实现还书界面和借书界面。

 

首先我们来思考一下借书和还书的流程,,借书的时候打开借书界面,选择要借的书,然后点确定按钮;还书的时候,打开还书界面,选择要换的书,然后点确定。两个操作在实现方面也很类似,借书操作要把借的书记录下来,最后保存到数据库中,还书操作要把还的书记录下来,最后从数据库中把还的书删掉。

 

下面开始编写借书界面:

1.    新建一个C++类,类名为BorrowBook。

2.    让BorrowBook类public继承Form类,在BorrowBook.cpp 文件中添加#include”ui_form.h”,并把Form类的ui属性改为protected,否则在BorrowBook类中访问不了ui变量。

3.    类的属性:

a)    userBook:储存用户已借阅的书,在完成借书操作后,会把借阅的书添加到userBook中去。

b)    borrowBook:用来储存借书操作中借阅的书,方便之后回写到数据库中去。如果没有这个变量,在回写操作中就要遍历userBook链表以确定哪本书是借的。

c)     book:用来储存了所有书的信息。

4.    类的方法:

a)    ShowAllBooks:显示所有的书,让用户来借。

 

b)    BorrowBookSlot:用户在点击确定按钮后,进入此函数,记录借的书。

注意要在类的声明中加Q_OBJECT宏,否则无法在父类和子类间进行信号与槽的连接。

#include "form.h"
#include "book.h"
#include "userbook.h"

class BorrowBook : public Form
{
    Q_OBJECT
public:
    // node储存的是用户已借阅的书
    // node2用来储存当前操作借的书
    // node3储存所有书的信息
    BorrowBook(UserBook* node, UserBook* node2, Book* node3);

    // 显示所有的书
    void ShowAllBooks();

public slots:
    // 当用户在借书界面点击确定按钮时,调用此函数
    void BorrowBookSlot();

protected:
    Book* book = NULL;
    UserBook* userBook = NULL;
    UserBook* borrowBook = NULL;
};

 

具体的实现:

1.    在构造函数中,先设置一下Tree Widget有几列,并为每一列设置一下标题。然后把确认按钮与BorrowBookSlot槽连接起来。

2.    ShowAllBooks:遍历book链表,把所有的书的信息显示在Tree Widget中,每一行都要添加一个复选框,让用户来选择借阅的书。

 

3.    BorrowBookSlot:遍历Tree Widget的每一行,检查复选框有没有被选中,如果被选中了,就添加到borrowBook中.

#include <QDate>
#include <QDebug>
#include <QMessageBox>
#include "borrowbook.h"
#include "ui_form.h"

BorrowBook::BorrowBook(UserBook* node, UserBook* node2, Book* node3)
{
    this->setWindowTitle(QString::fromLocal8Bit("借书"));
    // 为Tree Widget设置有多少列,并设置每一列的名称
    // 设置Tree Widget共四列
    ui->treeWidget->setColumnCount(4);
    QStringList header;
    header << QString::fromLocal8Bit("书籍编号")
           << QString::fromLocal8Bit("书籍名称")
           << QString::fromLocal8Bit("书籍作者")
           << QString::fromLocal8Bit("书籍类型");
    // 设置Tree Widget每一列的标题
    ui->treeWidget->setHeaderLabels(header);

    this->userBook = node;
    this->borrowBook = node2;
    this->book = node3;

    // 把确定按钮与借书操作连接起来
    QObject::connect(ui->confirmPushButton, SIGNAL(clicked()),
                     this, SLOT(BorrowBookSlot()));
}

void BorrowBook::BorrowBookSlot()
{
    // 遍历Tree Widget的每一行
    // topLevelItemCount函数用于获得Tree Widget有多少行
    for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++)
    {
        QTreeWidgetItem* item = ui->treeWidget->topLevelItem(i);
        // 判断改行的复选框是否被选中
        // 如果选中,就添加到userBook,borrowBook中
        if (item->checkState(0) == Qt::Checked)
        {
            UserBookType* node = new UserBookType();
            node->SetId(this->userBook->userId);
            node->SetBookId(item->text(0).toInt());
            QDate date;
            date = date.currentDate();
            qDebug() << date.year() << " " << date.month() << " " << endl;
            node->SetYear(date.year());
            node->SetMonth(date.month());
            node->SetDay(date.day());
            this->borrowBook->AddNode(node);

            // 把复选框置回到未选中的状态
            item->setCheckState(0, Qt::Unchecked);
        }
    }
    this->close();
}


void BorrowBook::ShowAllBooks()
{
    if (this->book == NULL)
    {
        return;
    }

    // 获得头节点
    BookType* node = (BookType*)this->book->GetNode(-1);
    // 获得第一个节点
    node = (BookType*)node->GetNext();
    // 遍历整个链表,把所有book的信息显示到Tree Widget上
    while (node != NULL)
    {
        QTreeWidgetItem* item = new QTreeWidgetItem();
        item->setText(0, QString::number(node->GetId()));
        item->setText(1, node->GetName());
        item->setText(2, node->GetAuthor());
        item->setText(3, node->GetCategory());
        // 设置item的标志
        // ItemIsEnabled设置item可用
        // ItemIsSelectable设置item可选
        // ItemIsUserCheckable设置item有复选框
        item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable
                       | Qt::ItemIsUserCheckable);
        // 设置item的初始状态
        // 第一个参数表示要设置哪一列
        // 第二个参数设置初始状态,我们设置为未选中
        item->setCheckState(0, Qt::Unchecked);
        // 把item添加到Tree Widget中
        ui->treeWidget->insertTopLevelItem(0, item);

        node = (BookType*)node->GetNext();
    }
}

 

虽然借书的界面和基本逻辑都建立完了,但还是有两个问题:

1.    当用户点击确定按钮后,虽然会调用BorrowBookSLot函数,把借的书存到borrowBook链表里,但并没有存到数据库中。

 

2.    在用户点击确认按钮后,借书界面关闭,回到user界面,但user界面所显示的书并没有发生变化。

要解决两个问题也很简单:

 

1.    Qt提供了一个函数closeEvent,这个函数可以拦截关闭事件,让我们可以自己处理关闭时间,首先在头文件borrowbook.h里添加一下函数的声明。然后在closeEvent函数里实现保存的操作.

注意:这里有一个地方比较容易犯错,我们实现的链表在添加节点的函数(AddNode函数)中使用的参数是指针,当添加节点的时候,添加的节点不要同时添加到两个链表中,具体的分析过程我在另一篇博客中介绍了。点击打开链接

// borrowbook.h
    // 拦截关闭事件
    void closeEvent(QCloseEvent* e);

 

 

// 关闭事件处理程序
void BorrowBook::closeEvent(QCloseEvent *)
{
    // 弹出对话框,询问是否保存
    QMessageBox::StandardButton msg = QMessageBox::information(this,
              tr("Prompt"),
              tr("Save You Book?"),
              QMessageBox::Save,
              QMessageBox::Cancel);

    switch (msg)
    {
    case QMessageBox::Save:
    {
        // 把借的书添加到userBook链表中
        UserBookType* node = (UserBookType*)this->borrowBook->GetNode(-1);
        node = (UserBookType*)node->GetNext();
        while (node != NULL)
        {
            UserBookType* node2 = new UserBookType();
            node2->SetId(node->GetId());
            node2->SetBookId(node->GetBookId());
            node2->SetYear(node->GetYear());
            node2->SetMonth(node->GetMonth());
            node2->SetDay(node->GetDay());
            this->userBook->AddNode(node2);
            node = (UserBookType*)node->GetNext();
        }

        // 把borrowBook链表中的信息添加到数据库中
        this->borrowBook->Save();
    } break;
    case QMessageBox::Cancel:
    {
        this->borrowBook->Clear();
    } break;
    default:
        break;
    }
}

在函数中我们使用了Clear函数,这是新给LinerList新添加的函数。

void LinerList::Clear()
{
    NodeType* preNode = this->list->GetNext();
    NodeType* nextNode = this->list->GetNext();

    while (nextNode != NULL)
    {
        preNode = nextNode;
        nextNode = nextNode->GetNext();

        delete preNode;
    }

    this->length = 0;
    this->list->SetNext(NULL);
}

 

2.    为了实现在用户借书之后刷新user界面,需要给user界面一个信号,当user界面接到这个信号时,就刷新界面。这里有两种方法:第一种方法是让借书界面关闭后自动销毁,这样就会产生一个destroyed的信号,user界面接到这个信号就刷新。第二个方法就是自己定义一个信号,不过这里并没有这个必要。

 

// userinterface.cpp
// 打开借书界面
void UserInterface::BorrowBookSlot()
{
    BorrowBook* w = new BorrowBook(this->userBook, this->borrowBook, this->book);
    // 设置当close时销毁,发出destoryed信号
    w->setAttribute(Qt::WA_DeleteOnClose);
    // 当收到借书界面的destroyed信号时,调用ShowAllUserBooks函数
    QWidget::connect(w, SIGNAL(destroyed()), this, SLOT(ShowAllUserBooks()));
    w->show();
    w->ShowAllBooks();
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值