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 QAbstractTableModelint 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 dataQt::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 rowsbool 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 headerQVariant 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;
}