Qt Demo: addressbook
(1)创建项目:选择不创建界面,即UI,此时会自动生成的文件如图所示:
QApplication:
MainWindow 继承自 QMainWindow,根据需要设计的界面样式。
(2)确定MainWindow 的成员变量
首先,从此张界面图推断出 MainWindow 的组成:
- 一个QTabWidget;
- 两个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;
}