QT: 操作主从视图及XML
按钮绑定信号、槽
控件属性
运行效果:
connectdlg.h
#ifndef CONNECTDLG_H #define CONNECTDLG_H #include <QDialog> #include <QMessageBox> class QSqlError; namespace Ui { class ConnDlg; } class ConnDlg : public QDialog { Q_OBJECT public: // explicit ConnDlg(QWidget *parent = nullptr); // ~ConnDlg(); explicit ConnDlg(QWidget *parent = 0); ~ConnDlg(); QString driverName() const; QString databaseName() const; QString userName() const; QString password() const; QString hostName() const; int port() const; QSqlError addConnection(const QString &driver, const QString &dbName, const QString &host, const QString &user, const QString &passwd, int port = -1); private: Ui::ConnDlg *ui; // Ui::QSqlConnectionDialogUi *ui; private slots: void createDB(); void addSqliteConnection(); void on_okButton_clicked(); void on_cancelButton_clicked(){ reject(); } void driverChanged(const QString &); }; #endif // CONNECTDLG_H
connectdlg.cpp
#include "connectdlg.h" #include "ui_connectdlg.h" #include <QtSql/QSqlDatabase> #include <QtSql/QSql> #include <QtSql/QtSql> ConnDlg::ConnDlg(QWidget *parent) : QDialog(parent) ,ui(new Ui::ConnDlg) { ui->setupUi(this); QStringList drivers = QSqlDatabase::drivers(); // 查找数据库驱动 ui->comboDriver->addItems(drivers); connect(ui->comboDriver,SIGNAL(currentIndexChanged(const QString &)),this, SLOT(driverChanged(const QString &))); ui->status_label->setText(tr("准备连接数据库!")); } QString ConnDlg::driverName() const { return ui->comboDriver->currentText(); } QString ConnDlg::databaseName() const { return ui->editDatabase->text(); } QString ConnDlg::userName() const { return ui->editUsername->text(); } QString ConnDlg::password() const { return ui->editPassword->text(); } QString ConnDlg::hostName() const { return ui->editHostname->text(); } int ConnDlg::port() const { return ui->portSpinBox->value(); } QSqlError ConnDlg::addConnection(const QString &driver, const QString &dbName, const QString &host, const QString &user, const QString &passwd, int port) { QSqlError err; QSqlDatabase db = QSqlDatabase::addDatabase(driver); db.setDatabaseName(dbName); db.setHostName(host); db.setPort(port); if(!db.open(user,passwd)) { err = db.lastError(); } return err; } void ConnDlg::createDB() { //创建数据库 QSqlQuery query ; query.exec("create table factory (id int primary key, manufactory varchar(40)," "address varchar(40) )"); query.exec(QObject::tr("insert into factory values(1,'一汽大众','长春')")); query.exec(QObject::tr("insert into factory values(2,'二汽神龙','武汉')")); query.exec(QObject::tr("insert into factory values(3,'上海大众','上海')")); query.exec("create table cars (carid int primary key, name varchar(50)," "factoryid int, year int, foreign key(factoryid) references factory" " )"); query.exec("insert into cars values(1,'奥迪A6',1,2005)"); query.exec("insert into cars values(2,'捷达',1,1993)"); query.exec("insert into cars values(3,'宝来',1,2000)"); query.exec("insert into cars values(4,'毕加索',2,1999)"); query.exec("insert into cars values(5,'富康',2,2004)"); query.exec("insert into cars values(6,'标致',2,2001)"); query.exec("insert into cars values(7,'桑塔纳',3,1995)"); query.exec("insert into cars values(8,'帕萨特',3,2000)"); } void ConnDlg::addSqliteConnection() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("databasefile.db"); if(!db.open()) { ui->status_label->setText(db.lastError().text()); return; } ui->status_label->setText(tr("创建SQLite数据库成功!")); } void ConnDlg::on_okButton_clicked() { // if(ui->comboDriver->currentText().isEmpty()){ ui->status_label->setText(tr("请选择一个数据库驱动!")); ui->comboDriver->setFocus(); } else if(ui->comboDriver->currentText() == "QSQLITE") { addSqliteConnection(); createDB();//创建数据库表,如已存在则无须执行 accept(); } else { QSqlError err = addConnection(driverName(),databaseName(),hostName(),userName(), password(),port()); if(err.type() != QSqlError::NoError) ui->status_label->setText(err.text()); else{ ui->status_label->setText("连接数据库成功!"); accept(); } } } void ConnDlg::driverChanged(const QString &text) { // if(text == "QSQLITE") { ui->editDatabase->setEnabled(false); ui->editUsername->setEnabled(false); ui->editPassword->setEnabled(false); ui->editHostname->setEnabled(false); ui->portSpinBox->setEnabled(false); } else { ui->editDatabase->setEnabled(true); ui->editUsername->setEnabled(true); ui->editPassword->setEnabled(true); ui->editHostname->setEnabled(true); ui->portSpinBox->setEnabled(true); } } ConnDlg::~ConnDlg() { delete ui; }
connectdlg.ui 详细代码:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>ConnDlg</class> <widget class="QDialog" name="ConnDlg"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>450</width> <height>397</height> </rect> </property> <property name="windowTitle"> <string>数据库连接</string> </property> <widget class="QGroupBox" name="connGroupBox"> <property name="geometry"> <rect> <x>10</x> <y>10</y> <width>431</width> <height>261</height> </rect> </property> <property name="title"> <string>数据库连接设置</string> </property> <widget class="QComboBox" name="comboDriver"> <property name="geometry"> <rect> <x>170</x> <y>30</y> <width>221</width> <height>22</height> </rect> </property> </widget> <widget class="QLineEdit" name="editDatabase"> <property name="geometry"> <rect> <x>170</x> <y>70</y> <width>181</width> <height>21</height> </rect> </property> <property name="text"> <string>databasefile.db</string> </property> </widget> <widget class="QLineEdit" name="editUsername"> <property name="geometry"> <rect> <x>170</x> <y>100</y> <width>181</width> <height>21</height> </rect> </property> <property name="text"> <string>admin</string> </property> </widget> <widget class="QLineEdit" name="editPassword"> <property name="geometry"> <rect> <x>170</x> <y>130</y> <width>181</width> <height>21</height> </rect> </property> <property name="text"> <string>123456</string> </property> <property name="echoMode"> <enum>QLineEdit::Password</enum> </property> <property name="placeholderText"> <string/> </property> </widget> <widget class="QLineEdit" name="editHostname"> <property name="geometry"> <rect> <x>170</x> <y>160</y> <width>181</width> <height>21</height> </rect> </property> <property name="text"> <string>localhost</string> </property> </widget> <widget class="QSpinBox" name="portSpinBox"> <property name="geometry"> <rect> <x>170</x> <y>190</y> <width>181</width> <height>22</height> </rect> </property> <property name="maximum"> <number>65535</number> </property> </widget> <widget class="QLabel" name="textLabel2"> <property name="geometry"> <rect> <x>20</x> <y>30</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>驱动:</string> </property> </widget> <widget class="QLabel" name="textLabel3"> <property name="geometry"> <rect> <x>20</x> <y>70</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>数据库名:</string> </property> </widget> <widget class="QLabel" name="textLabel4"> <property name="geometry"> <rect> <x>20</x> <y>100</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>用户名:</string> </property> </widget> <widget class="QLabel" name="textLabel4_2"> <property name="geometry"> <rect> <x>20</x> <y>130</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>密码:</string> </property> </widget> <widget class="QLabel" name="textLabel5"> <property name="geometry"> <rect> <x>20</x> <y>170</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>主机名:</string> </property> </widget> <widget class="QLabel" name="textLabel5_2"> <property name="geometry"> <rect> <x>20</x> <y>200</y> <width>72</width> <height>15</height> </rect> </property> <property name="text"> <string>端口:</string> </property> </widget> </widget> <widget class="QLabel" name="status_label"> <property name="geometry"> <rect> <x>30</x> <y>290</y> <width>391</width> <height>16</height> </rect> </property> <property name="text"> <string>状态:</string> </property> </widget> <widget class="QWidget" name="horizontalLayoutWidget"> <property name="geometry"> <rect> <x>20</x> <y>330</y> <width>401</width> <height>41</height> </rect> </property> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="okButton"> <property name="text"> <string>连接</string> </property> </widget> </item> <item> <widget class="QPushButton" name="cancelButton"> <property name="text"> <string>取消</string> </property> </widget> </item> </layout> </widget> </widget> <resources/> <connections> <connection> <sender>cancelButton</sender> <signal>clicked()</signal> <receiver>ConnDlg</receiver> <slot>reject()</slot> <hints> <hint type="sourcelabel"> <x>373</x> <y>349</y> </hint> <hint type="destinationlabel"> <x>224</x> <y>198</y> </hint> </hints> </connection> <connection> <sender>okButton</sender> <signal>clicked()</signal> <receiver>ConnDlg</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel"> <x>274</x> <y>349</y> </hint> <hint type="destinationlabel"> <x>224</x> <y>198</y> </hint> </hints> </connection> </connections> </ui>
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>1057</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <widget class="QGroupBox" name="createFactoryGroupBox"> <property name="geometry"> <rect> <x>20</x> <y>20</y> <width>561</width> <height>201</height> </rect> </property> <property name="title"> <string>汽车制造商</string> </property> </widget> <widget class="QGroupBox" name="createCarGroupBox"> <property name="geometry"> <rect> <x>20</x> <y>230</y> <width>561</width> <height>231</height> </rect> </property> <property name="title"> <string>汽车</string> </property> </widget> <widget class="QGroupBox" name="createDetailsGroupBox"> <property name="geometry"> <rect> <x>600</x> <y>20</y> <width>441</width> <height>441</height> </rect> </property> <property name="title"> <string>详细信息</string> </property> </widget> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>1057</width> <height>26</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QGridLayout> #include <QAbstractItemView> #include <QHeaderView> #include <QAction> #include <QMenu> #include <QMenuBar> #include <QDialog> MainWindow::MainWindow(const QString &factoryTable, const QString &carTable, QFile *carDetails, QWidget *parent) : QMainWindow(parent) // , ui(new Ui::MainWindow) { // ui->setupUi(this); file = carDetails; readCarData(); carModel = new QSqlRelationalTableModel(this); carModel->setTable(carTable); carModel->setRelation(2,QSqlRelation(factoryTable,"id","manufactory")); carModel->select(); factoryModel = new QSqlTableModel(this); factoryModel->setTable(factoryTable); factoryModel->select(); QGroupBox *factory = createFactoryGroupBox(); QGroupBox *cars = createCarGroupBox(); QGroupBox *details = createDetailsGroupBox(); // 布局 QGridLayout *layout = new QGridLayout; layout->addWidget(factory,0,0); layout->addWidget(cars,1,0); layout->addWidget(details,0,1,2,1); layout->setColumnStretch(1,1); layout->setColumnMinimumWidth(0,500); QWidget *widget = new QWidget; widget->setLayout(layout); setCentralWidget(widget); createMenuBar(); resize(850,400); setWindowTitle(tr("主从视图")); } MainWindow::~MainWindow() { // delete ui; } void MainWindow::addCar() { // /* Dialog *dialog = new QDialog(carModel, factoryModel,carData, file, this); int accepted = dialog->exec(); if(accepted ==1 ){ int lastRow = carModel->rowCount()-1; carView->selectRow(lastRow); carView->scrollToBottom(); showCarDetails(carModel->index(lastRow,0)); } */ } void MainWindow::changeFactory(QModelIndex index) { QSqlRecord record = factoryModel->record(index.row()); QString factoryId = record.value("id").toString(); carModel->setFilter("id = '"+ factoryId + "'"); showFactoryProfile(index); } void MainWindow::delCar() { QModelIndexList selection = carView->selectionModel()->selectedRows(0); if(!selection.empty()){ QModelIndex idIndex = selection.at(0); int id = idIndex.data().toInt(); QString name = idIndex.sibling(idIndex.row(),1).data().toString(); QString factory = idIndex.sibling(idIndex.row(),2).data().toString(); QMessageBox::StandardButton button; button =QMessageBox::question(this, tr("删除汽车记录"),QString(tr("确认删除由'%1'生产的'%2'吗?").arg(factory).arg(name)),QMessageBox::Yes|QMessageBox::No); if(button == QMessageBox::Yes){ removeCarFromFile(id); removeCarFromDatabase(idIndex); decreaseCarCount(indexOfFactory(factory)); } else{ QMessageBox::information(this,tr("删除汽车记录"),tr("请选择要删除的记录")); } } } void MainWindow::showCarDetails(QModelIndex index) { QSqlRecord record = carModel->record(index.row()); QString factory = record.value("manufactory").toString(); QString name = record.value("name").toString(); QString year = record.value("year").toString(); QString carId = record.value("carid").toString(); showFactoryProfile(indexOfFactory(factory)); titleLabel->setText(tr("品牌:%1 (%2)").arg(name).arg(year)); titleLabel->show(); QDomNodeList cars = carData.elementsByTagName("car"); for (int i = 0; i<cars.count(); i++) { QDomNode car = cars.item(i); if(car.toElement().attribute("id")==carId){ getAttribList(car.toElement()); break; } } if( (!attribList->count()) == 0){ attribList->show(); } } void MainWindow::showFactoryProfile(QModelIndex index) { QSqlRecord record = factoryModel->record(index.row()); QString name = record.value("manufactory").toString(); int count = carModel->rowCount(); profileLabel->setText(tr("汽车制造商:%1\n产品数量:%2").arg(name).arg(count)); profileLabel->show(); titleLabel->hide(); attribList->hide(); } QGroupBox *MainWindow::createFactoryGroupBox() { factoryView = new QTableView; factoryView->setEditTriggers(QAbstractItemView::NoEditTriggers); factoryView->setSortingEnabled(true); factoryView->setSelectionBehavior(QAbstractItemView::SelectRows); factoryView->setSelectionMode(QAbstractItemView::SingleSelection); factoryView->setShowGrid(false); factoryView->setAlternatingRowColors(true); factoryView->setModel(factoryModel); connect(factoryView, SIGNAL(clicked(QModelIndex)), this, SLOT(changeFactory(QModelIndex))); QGroupBox *box = new QGroupBox(tr("汽车制造商")); QGridLayout *layout = new QGridLayout; layout->addWidget(factoryView,0,0); box->setLayout(layout); return box; } QGroupBox *MainWindow::createCarGroupBox() { // QGroupBox *box = new QGroupBox(tr("汽车")); carView = new QTableView; carView->setEditTriggers(QAbstractItemView::NoEditTriggers); carView->setSortingEnabled(true); carView->setSelectionBehavior(QAbstractItemView::SelectRows); carView->setSelectionMode(QAbstractItemView::SingleSelection); carView->setShowGrid(false); carView->verticalHeader()->hide(); carView->setAlternatingRowColors(true); carView->setModel(carModel); connect(carView, SIGNAL(clicked(QModelIndex)), this, SLOT(showCarDetails(QModelIndex))); connect(carView, SIGNAL(activated(QModelIndex)), this, SLOT(showCarDetails(QModelIndex))); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(carView,0,0); box->setLayout(layout); return box; } QGroupBox *MainWindow::createDetailsGroupBox() { // QGroupBox *box = new QGroupBox(tr("详细信息")); profileLabel = new QLabel; profileLabel->setWordWrap(true); profileLabel->setAlignment(Qt::AlignBottom); titleLabel = new QLabel; titleLabel->setWordWrap(true); titleLabel->setAlignment(Qt::AlignBottom); attribList = new QListWidget; QGridLayout *layout = new QGridLayout; layout->addWidget(profileLabel,0,0,1,2); layout->addWidget(titleLabel,1,0,1,2); layout->addWidget(attribList,2,0,1,2); layout->setRowStretch(2,1); box->setLayout(layout); return box; } void MainWindow::createMenuBar() { // 菜单函数 QAction *addAction = new QAction(tr("添加"),this); QAction *deleteAction = new QAction(tr("删除"),this); QAction *quitAction = new QAction(tr("退出"),this); addAction->setShortcut(tr("Ctrl+A")); deleteAction->setShortcut(tr("Ctrl+D")); quitAction->setShortcut(tr("Ctrl+Q")); QMenu *fileMenu = menuBar()->addMenu(tr("操作菜单")); fileMenu->addAction(addAction); fileMenu->addAction(deleteAction); fileMenu->addSeparator(); fileMenu->addAction(quitAction); connect(addAction, SIGNAL(triggered(bool)), this, SLOT(addCar())); connect(deleteAction, SIGNAL(triggered(bool)), this, SLOT(delCar())); connect(quitAction, SIGNAL(triggered(bool)), this, SLOT(close())); } void MainWindow::decreaseCarCount(QModelIndex index) { int row = index.row(); int count = carModel->rowCount(); if(count == 0) { factoryModel->removeRow(row); } } void MainWindow::getAttribList(QDomNode car) { attribList->clear(); QDomNodeList attribs = car.childNodes(); QDomNode node; QString attribNumber; for(int j = 0; j<attribs.count(); j++){ node = attribs.item(j); attribNumber = node.toElement().attribute("number"); QListWidgetItem *item = new QListWidgetItem(attribList); QString showText(attribNumber + ": " + node.toElement().text()); item->setText(tr("%1").arg(showText)); } } QModelIndex MainWindow::indexOfFactory(const QString &factory) { for(int i =0 ;i < factoryModel->rowCount(); i++){ QSqlRecord record = factoryModel->record(i); if(record.value("manufactory")== factory) return factoryModel->index(i,1); } return QModelIndex(); } void MainWindow::readCarData() { if(!file->open(QIODevice::ReadOnly)) return; if(!carData.setContent(file)) { file->close(); return; } file->close(); } void MainWindow::removeCarFromDatabase(QModelIndex index) { carModel->removeRow(index.row()); } void MainWindow::removeCarFromFile(int id) { QDomNodeList cars = carData.elementsByTagName("car"); for(int i = 0; i<cars.count(); i++){ QDomNode node = cars.item(i); if(node.toElement().attribute("id").toInt()==id){ carData.elementsByTagName("archive").item(0).removeChild(node); break; } } }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGroupBox> #include <QTableView> #include <QListWidget> #include <QLabel> #include <QFile> #include <QSqlRelationalTableModel> #include <QSqlTableModel> #include <QDomNode> #include <QDomDocument> #include <QtSql/QSqlRecord> #include <QMessageBox> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(const QString &factoryTable, const QString &carTable, QFile *carDetails, QWidget *parent = nullptr); ~MainWindow(); private: QGroupBox *createCarGroupBox(); QGroupBox *createFactoryGroupBox(); QGroupBox *createDetailsGroupBox(); void createMenuBar(); QTableView *carView; QTableView *factoryView; QListWidget *attribList; /* 声明相关的信息标签 **/ QLabel *profileLabel; QLabel *titleLabel; // void decreaseCarCount(QModelIndex index); // 减少汽车数量 void getAttribList(QDomNode car); QModelIndex indexOfFactory(const QString &factory); void readCarData(); void removeCarFromDatabase(QModelIndex index); void removeCarFromFile(int id); QDomDocument carData; QFile *file; QSqlRelationalTableModel *carModel; QSqlTableModel *factoryModel; Ui::MainWindow *ui; private slots: void addCar(); void changeFactory(QModelIndex index); void delCar(); void showCarDetails(QModelIndex index); void showFactoryProfile(QModelIndex index); }; #endif // MAINWINDOW_H
attribs.xml
<?xml version="1.0" encoding="utf-8"?> <archive> <car id="1"> <attrib number="01">排量:2393ml</attrib> <attrib number="02">价格:43.26万元</attrib> <attrib number="03">排放:欧4</attrib> <attrib number="04">油耗:7.01(90km/h)</attrib> <attrib number="05">功率:130/6000</attrib> </car> <car id="2"> <attrib number="01">排量:1600ml</attrib> <attrib number="02">价格:8.98万元</attrib> <attrib number="03">排放:欧3</attrib> <attrib number="04">油耗:6.11(90km/h)</attrib> <attrib number="05">功率:68/5800</attrib> </car> <car id="3"> <attrib number="01">排量:1600ml</attrib> <attrib number="02">价格:11.25万元</attrib> <attrib number="03">排放:欧3带OBD</attrib> <attrib number="04">油耗:6.01(90km/h)</attrib> <attrib number="05">功率:74/6000</attrib> </car> <car id="4"> <attrib number="01">排量:1997ml</attrib> <attrib number="02">价格:15.38万元</attrib> <attrib number="03">排放:欧3带OBD</attrib> <attrib number="04">油耗:7.01(90km/h)</attrib> <attrib number="05">功率:130/6000</attrib> </car> <car id="5"> <attrib number="01">排量:1600ml</attrib> <attrib number="02">价格:6.58万元</attrib> <attrib number="03">排放:欧3</attrib> <attrib number="04">油耗:6.51(90km/h)</attrib> <attrib number="05">功率:65/5600</attrib> </car> <car id="6"> <attrib number="01">排量:1997ml</attrib> <attrib number="02">价格:16.08万元</attrib> <attrib number="03">排放:欧4</attrib> <attrib number="04">油耗:7.01(90km/h)</attrib> <attrib number="05">功率:108/6000</attrib> </car> <car id="7"> <attrib number="01">排量:1781ml</attrib> <attrib number="02">价格:7.98万元</attrib> <attrib number="03">排放:欧3</attrib> <attrib number="04">油耗:7.21(90km/h)</attrib> <attrib number="05">功率:70/5200</attrib> </car> <car id="8"> <attrib number="01">排量:1984ml</attrib> <attrib number="02">价格:19.58万元</attrib> <attrib number="03">排放:欧4</attrib> <attrib number="04">油耗:7.11(90km/h)</attrib> <attrib number="05">功率:85/5400</attrib> </car> </archive>
优质生活从拆开始