订餐程序中qt的使用(qt基础用法)

记录了一下项目制作过程中 Qt基本API的使用,以及一些基本概念源码可至GitHub查看

Qt基础知识

1. Qt中的窗口类

1.1 基础窗口类

image-20240503151301988

常用的窗口类是图中下面三个,在创建Qt窗口时,需要让自己的窗口类继承上述三个窗口类中的一个

1.2 窗口的显示方式

模态(modal)窗口:窗口弹出后,没关闭之前,不可以对同一应用程序的其他窗口进行操作;非模态(modeless)窗口:窗口弹出后,没关闭之前,可以对同一应用程序的其他窗口进行操作

1.3 模态窗口的实现方法

窗口的show()函数显示的类型是非模态的,有几种方法可以将窗口设为模态,如下

1.3.1 QDialog对话框

方法一:exec()

1
2
3
4
QDialog dlg(this);
dlg.exec();

//exec是execute(执行)的缩写,当调用exec()函数时,并不会立即返回,只用当对话框关闭才会返回,因此,只有关闭对话框才会执行后续的代码

方法二:setModal()

1
2
3
4
QDialog dlg(this);
dlg.setModal(true); //相当于dlg.setWindowModality(Qt::ApplicationModal);
dlg.show();

方法三:setWindowModality()

1
2
3
QDialog dlg(this);
dlg.setWindowModality(Qt::ApplicationModal);
dlg.show();

==setWindowModality()==的参数设置要阻塞的窗口类型:

枚举值 说明
Qt::NonModal 0 非模态,不阻塞任何窗口
Qt::WindowModal 1 半模态,窗口极模态,阻塞它的父窗口、所有的祖先窗口以及他们的子窗口
Qt::ApplicationModal 2 模态,应用程序级模态,阻塞应用程序所有的窗口

2. 常用类

2.1字符串类型

C ----> char*

C++ ------> std::string

Qt -------> QByteArray,QString

相关函数,查阅qt中的帮助文档,在命令行中输入assistant

2.2 QVariant类

类似于C++中的模板

可以对不同的数据类型进行包装,从而使用相同的函数对不同类型的数据进行处理

2.2.1 对Qt中的标准类型进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HelloQt::HelloQt(QWidget *parent): QMainWindow(parent)
{
ui.setupUi(this);
int value = dataPlus(10,20);
QString str = dataPlus("hello","world").toString();
}

//dataPlus()函数在HelloQt类中已经被声明
QVariant HelloQt::dataPlus(QVariant a,QVariant b)
{
QVariant ret;
if(a.type() == QVariant::int && b.type() == QVariant::int) //或者使用QMetaType::Int
ret = QVariant(a.toInt() + b.toInt());
else if(a.type() == QVariant::String && b.type() == QVariant::String)
ret.setValue(a.toString() + b.toString());
return ret;
}

2.2.2 自定义类型

若自定义了一个类型,则需要使用Qt中的宏进行声明

Q_DECLARE_METATYPE(Type)

第一步:定义类型,并注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//自定义类型
class Animal
{
public:
Animal(){} //必须要有默认构造函数
//拷贝构造函数也必须有,不过没有深、浅拷贝时,用默认的即可
Animal(QString name):_name(name){}
void show()
{
qDebug()<<"Animal show name is :"<< _name <<endl;
}
private:
QString _name;
};
//自定义类型注册
Q_DECLARE_METATYPE(Animal);

第二步: 使用fromvalue()存储对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
//QVariant vt(Animal("snake")); //不可以通过构造函数存自定义类型
QVariant vt;
//有以下两种方法可以,存自定义类型
vt = QVariant::fromValue(Animal("dog")); //①
vt.setValue(Animal("cat")); //②
//如果能转换到Animal类型,就转换
if(vt.canConvert<Animal>())
{
Animal animal = vt.value<Animal>();
animal.show();
}
return 0;
}

2.3 QPoint

QPoint类封装了我们常用用到的坐标点 (x, y), 常用的 API如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void QPoint::setX(int x);
void QPoint::setY(int y);

int QPoint::x() const;
int &QPoint::rx();

int QPoint::y() const;
int &QPoint::ry();

//如果x和y坐标都为0则返回true,否则返回false
bool isNull() const

//返回x()和y()的绝对值之和,传统上称为从原点到该点的向量的“曼哈顿长度”。
//(p1-p2).manhattanLength();
int manhattanLength() const

//返回一个交换了x和y坐标的点: QPoint{1, 2}.transposed() // {2, 1}
QPoint transposed() const

// 直接通过坐标对象进行算术运算: 加减乘除
QPoint &QPoint::operator*=(float factor);
QPoint &QPoint::operator*=(double factor);
QPoint &QPoint::operator*=(int factor);
QPoint &QPoint::operator+=(const QPoint &point);
QPoint &QPoint::operator-=(const QPoint &point);
QPoint &QPoint::operator/=(qreal divisor);

2.4 QLine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 设置直线的起点坐标
void QLine::setP1(const QPoint &p1);
// 设置直线的终点坐标
void QLine::setP2(const QPoint &p2);

void QLine::setPoints(const QPoint &p1, const QPoint &p2);
void QLine::setLine(int x1, int y1, int x2, int y2);


QPoint QLine::p1() const; // 返回直线的起始点坐标
QPoint QLine::p2() const; // 返回直线的终点坐标
QPoint QLine::center() const; // 返回值直线的中心点坐标, (p1() + p2()) / 2

int QLine::x1() const; // 返回值直线起点的 x 坐标
int QLine::y1() const; // 返回值直线起点的 y 坐标
int QLine::x2() const; // 返回值直线终点的 x 坐标
int QLine::y2() const; // 返回值直线终点的 y 坐标

int QLine::dx() const //返回直线向量的水平分量
int QLine::dy() const //返回直线向量的垂直分量

// 用给定的坐标点平移这条直线
void QLine::translate(const QPoint &offset);
void QLine::translate(int dx, int dy);
// 用给定的坐标点平移这条直线, 返回平移之后的坐标点(不会改变这条线的坐标)
QLine QLine::translated(const QPoint &offset) const;
QLine QLine::translated(int dx, int dy) const;

// 直线对象进行比较
bool operator!=(const QLine &line) const;
bool operator==(const QLine &line) const;

2.5 QSize

在QT中QSize类用来形容长度和宽度, 常用的API如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void setWidth(int width)
void setHeight(int height);

int width() const; // 得到宽度
int &rwidth(); // 得到宽度的引用
int height() const; // 得到高度
int &rheight(); // 得到高度的引用

void transpose(); // 交换高度和宽度的值
QSize transposed() const; // 交换高度和宽度的值, 返回交换之后的尺寸信息

//返回一个大小,宽为当前大小与other的最小值,高为当前大小与other的最小值
QSize boundedTo(const QSize& oterSize)
//返回一个大小,宽为当前大小与other的最大值,高为当前大小与other的最大值
QSize expandedTo(const QSize &otherSize) const

/*
根据指定的模式,按给定的宽度和高度缩放矩形:
如果mode为Qt::IgnoreAspectRatio,则大小设置为(width, height)。
如果mode为Qt::KeepAspectRatio,当前大小将在内部缩放到一个尽可能大的矩形(宽度,高度),保持高宽比。
如果mode是Qt::KeepAspectRatioByExpanding,当前大小被缩放到一个矩形,尽可能小的外部(宽度,高度),保持长宽比。
*/
void scale(int width, int height, Qt::AspectRatioMode mode)
void scale(const QSize &size, Qt::AspectRatioMode mode)
QSize scaled(int width, int height, Qt::AspectRatioMode mode) const
QSize scaled(const QSize &s, Qt::AspectRatioMode mode) const


// 进行算法运算: 加减乘除
QSize &operator*=(qreal factor);
QSize &operator+=(const QSize &size);
QSize &operator-=(const QSize &size);
QSize &operator/=(qreal divisor);

3. 信号和槽

3.1 信号(signal)

  • 信号本质是事件,如按钮点击,窗口刷新等

  • 信号以函数形式呈现

Qt中信号的发出者可能是某个实例化的类对象,对象内部可以进行相关事件的检测

3.2 槽(slot)

  • 槽函数是一类特殊的功能函数,在编码过程中也可以作为类的普通成员函数来使用

  • 对发出来的信号进行处理

槽函数的所有者也是某个类的实例对象

3.3 connect函数

connect函数属于QObject类

需要通过这个函数建立signal和slot二者之间的联系

1
2
3
4
5
6
7
8
9
10
QMetaObject::Connection QObject::connect(const QObject *sender,const char *signal, 
const QObject *receiver, [static] const char *method, Qt::ConnectionType type = Qt::AutoConnection)

------------------------------------------------------------------------
sender: 发送信号的对象。
signal: 发送的信号的名称,说明发出了什么信号,以字符串形式表示。
receiver: 接收信号的对象。
method: 接收对象中用于响应信号的槽函数的名称,以字符串形式表示。
type: 连接类型,决定了信号和槽的连接方式。默认为 Qt::AutoConnection。

例如,如果你有一个按钮(QPushButton),并且想要在按钮被点击时执行某些操作,你可以将按钮的 clicked() 信号连接到一个槽函数:

1
2
3
4
5
6
7
#include<QPushButton>
QPushButton *button = new QPushButton("Click me");
MyObject *myObject = new MyObject;

// 连接按钮的clicked信号到myObject的slotMethod槽函数
QObject::connect(button, SIGNAL(clicked()), myObject, SLOT(slotMethod()));
//当按钮被点击时,MyObject 的 slotMethod 方法将被调用。

3.4 自定义信号和槽

为了使自定义信号和槽正常工作,确保你的类继承自 QObject 并且在类的定义中添加Q_OBJECT 宏。同时,确保项目的 .pro 文件中添加了 QT += core,以确保 Qt 核心模块被正确链接

  • 自定义信号,通常信号只有声明没有实现

1
2
3
4
5
6
7
class MyClass : public QObject
{
Q_OBJECT
signals:
void mySignal(int value);
};

  • 自定义槽:

自定义槽是普通的成员函数,可以在信号发射时被调用。

1
2
3
4
5
6
7
8
class MyClass : public QObject
{
Q_OBJECT
public slots: //新版本中不可以省略不写
void mySlot(int value) {
qDebug() << "Received value:" << value;
}
};
  • 触发自定义信号

需在类中的某个函数中使用 emit 关键字,可加可不加,加了更规范

1
2
3
4
5
6
7
8
void MyClass::someFunction() {
// 触发信号
emit mySignal(42);
}

//使用
MyClass obj;
obj.someFunction(); // 这将触发 mySignal,导致 mySlot 被调用。

3.5 补充

  • 信号可以连接多个槽函数

  • 信号可以连接信号

  • 信号函数和槽函数的参数有一些要求:

    1. 参数类型必须兼容:信号函数和槽函数的参数类型必须兼容,最好是相同的类型或可以自动转换的类型。如果参数类型不兼容,连接将无法建立,并且编译器将会报错。
    2. 参数数量必须匹配:信号函数和槽函数的参数数量必须匹配。如果信号函数有参数而槽函数没有,或者槽函数有参数而信号函数没有,连接仍然是有效的。但是,如果参数数量不匹配,连接将无法建立。
    3. 参数的顺序和类型必须一致:参数的顺序和类型在信号函数和槽函数之间必须一致。如果顺序或类型不匹配,连接将无法建立。

4. QLineEdit

4.1 获取和设置文本内容:

  • QString text() const:返回当前文本框中的文本内容。

  • setText(const QString &text):设置文本框的文本内容。

1
2
3
4
5
QLineEdit *lineEdit = new QLineEdit();
lineEdit->setText("Hello, World!");

// 获取当前文本内容
QString currentText = lineEdit->text();

4.2 密码模式

setEchoMode(QLineEdit::EchoMode mode):设置文本框的显示模式。常用的模式有:

  • QLineEdit::Normal:默认模式,显示输入的文本。

  • QLineEdit::Password:以密码形式显示文本,用圆点或星号代替实际字符。

  • QLineEdit::PasswordEchoOnEdit:在编辑时以密码形式显示文本,但在失去焦点后显示圆点。

1
2
QLineEdit *lineEdit = new QLineEdit();
lineEdit->setEchoMode(QLineEdit::Password);

4.3 设置最大长度

使用setMaxLentgh方法可以限制用户输入的最大字符数

1
2
QLineEdit* lineEdit = new QLineEdit(this);
lineEdit- >setMaxLength(10);//限制输入的最大长度为10个字符

5. QLable

5.1 设置字体的颜色 大小等

可以使用setStyleSheet()函数

1
2
3
4
5
6
7
8
//对某个组件局部使用
ui->display->setStyleSheet("color: red;" "text-align: right;" " font-size: 10px;");
//对某个窗口下的某种组件设置
MainWindow->setStyleSheet("QLineEdit{ background-color: lime}");
//全局使用
/*使用qApp的setStyleSheet函数可以为应用程序全局设置样式。例如下面为应用程序的QLineEdit组件设置样式
*/
qApp->setStyleSheet("QLineEdit{ background-color: gray }");

6. 使用类设置字体属性 颜色

  • QFont类的构造函数QFont(const QString &family, int pointSize, int weight = -1, bool italic = false)

family:字符串,表示字体的家族名称,例如"Arial","Times New Roman"等。

pointSize:整数,代表字体的大小,以磅(point)为单位。

weight:整数,指定字体的粗细,通常是100到1000的范围内的数值;-1表示使用默认值。

italic:布尔值,表示字体是否是斜体;false表示非斜体,true表示斜体。

1
2
3
4
5
6
7
//设置字体属性
QFont font("Arial", 16);
font.setBold(true);
ui->lineEdit->setFont(font);
//设置对齐位置
ui->lineEdit->setAlignment(Qt::AlignRight);

  • QPalette 类用于管理窗口部件的外观,包括背景色、前景色和文本格式等

1
2
3
4
5
6
7
//设置颜色
QPalette palette;
palette.setColor(QPalette::Text, Qt::red);
ui->lineEdit->setPalette(palette);
//setColor() 方法第一个参数是要设置的颜色属性,第二个参数是要应用的颜色值。

//在设置控件背景色填充时,一定要先调用setAutoFillBackground(true)函数,来运行自动填充背景

7. QProgressBar

可与QSlider QScrollBar QDial配合使用

format属性

%p:完成的百分比 %v:当前值 %m:总步骤数

默认值为%p%

1
2
3
4
5
6
connect(ui->slider,&QSlider::valueChanged,this,&Widget::do_valueChanged);

void Widget::do_valueChanged(int value);
{
ui->progressBar->setValue(value);
}

8. 日期时间数据

QTime QDate QDateTime QCalendarWidget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void Widgey::on_btnGetTime_clicked()
{
QDateTime curDateTime = QDateTime::currentDateTime();
ui->timeEdit->setTime(curDateTime.time());
ui->editTime->setText(curDateTime.toString("hh:mm:ss"))

ui->timeEdit->setDate(curDateTime.date());
ui->editTime->setText(curDateTime.toString("yy-MM-dd"));

ui->timeEdit->setDateTime(curDateTime);
}

void Widget::on_calendarWidget_selectionChanged()
{
//获取日历控件上选择的日期
QString str = ui->calendarWidget->selectedDate().toString("yyyy年M月d日");
}

9. 计时器 QTimer

timer 超时后会发出timeout()信号,所以在创建好定时器对象后给其建立信号与槽

1
2
3
4
5
6
7
8
9
#inlcude <QTimer>

QTimer *timer = new QTimer;
timer->setSingleShot(false);//设置是否只使用一次
timer->setInterval(2000);//设置时间间隔,以毫秒为单位

timer->start();//启动
timer->stop();//停止
connect(timer, SIGNAL(timeout()), this, SLOT(onTimeout()));

10. QTabWidget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 创建一个 QTabWidget 实例,用于包含多个选项卡
QTabWidget *tabWidget = new QTabWidget;

// 设置选项卡的形状为三角形
tabWidget->setTabShape(QTabWidget::Triangular);

// 设置选项卡可移动
tabWidget->setMovable(true);

// 设置选项卡的位置为左侧
tabWidget->setTabPosition(QTabWidget::West);

// 创建三个子窗口部件(QWidget),用作每个选项卡的内容
QWidget *pageWidget_0 = new QWidget;
QWidget *pageWidget_1 = new QWidget;
QWidget *pageWidget_2 = new QWidget;

// 将每个子窗口部件添加到选项卡中,同时设置相应的标签
tabWidget->addTab(pageWidget_0, "第一页");
tabWidget->addTab(pageWidget_1, "第二页");
tabWidget->addTab(pageWidget_2, "第三页");

11. QTableView QStandardItemModel QItemSelectionModel

QStandardItemModel是Qt提供的用于存储和操作标准项数据模型的类。它继承自QAbstractItemModel,并提供了一种方便的方式来组织和展示数据。通过添加、删除、修改或移动标准项,可以对数据进行操作。

QItemSelectionModel则是用于管理项选择状态的类。它是一个与视图交互的模型,负责跟踪用户选择的项以及通知相关视图进行相应更新。QItemSelectionModel可以监听并响应用户选择项变化事件,同时也可以通过编程方式改变选择状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <QFileDialog>
#include <QFile>
#include <QStandardItemModel>
#include <QItemSelectionModel>

class MainWindow:public QMainWindow
{
Q_OBJECT
private:
QStandardItemModel* m_model; // 数据模型
QItemSelectionModel* m_selection; // 选择模型
QLabel* labCurFile; // 当前文件标签
QLabel* labCellPos; // 当前单元格位置标签
public:
.........
private slots:
void do_currentChanged(const QModelIndex &current,const QModelIndex &previous);

};

MainWindow::MainWindow(QWidget* parent):QMainWindow(parent),ui(new Ui::MainWindow)
{
labCurFile = new QLabel("当前文件",this);
labCurFile->setMinimumWidth(200);
ui->statusBar->addWidget(labCurFile); // 将当前文件标签添加到状态栏

m_model = new QStandardItemModel(2,6,this); // 创建数据模型,2行6列
m_selection = new QItemSelectionModel(m_model,this); // 创建选择模型

ui->tableView->setModel(m_model); // 设置表格视图的模型
ui->tableView->setSelectionModel(m_selection); // 设置表格视图的选择模型
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection); // 设置选择模式
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems); // 设置选择行为

connect(m_selection,&QItemSelection::currentChanged,this,&MainWindow::do_currentChanged);
}

void MainWinidow::do_currentChanged(const QModelIndex &current,const QModelIndex &previous)
{
if(current.isValid())
{
labCellPos->setText(QString::asprintf("当前单元格:%d行,%d列",current.row(),current.column()));
QStandardItem *aItem = m_model->itemFromIndex(current); // 获取当前单元格的项
ui->actFontBold->setChecked(aItem->font().bold()); // 检查当前单元格的文本是否为粗体,如果当前单元格的文本为粗体,动作将被选中,否则动作将取消选中
}
}


void MainWindow::on_actOpen_triggered()
{
// 获取当前应用程序的路径
QString curPath = QCoreApplication::applicationDirPath();
// 打开文件对话框以获取要打开的文件路径
QString aFilePath = QFileDialog::getOpenFileName(this, "打开一个文件", curPath, "数据文件(*.txt);;所有文件(*.*)");
// 如果文件名为空,则退出函数
if (aFileName.isEmpty()) return;

// 打开文件
QFile aFile(aFileName);
if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text)) return; // 如果文件无法打开,则退出函数

// 读取文件内容并显示在界面上
QStringList aFileContent;
QTextStream aStream(&aFile);
while (!aStream.atEnd())
{
QString str = aStream.readLine();
ui->plainTextEdit->appendPlainText(str); // 在文本框中添加一行内容
aFileContent.append(str); // 将读取的每一行内容添加到QStringList中
}
// 关闭文件
aFile.close();

// 更新界面显示,显示当前打开的文件名
labCurFile->setText("当前文件:" + aFileName);
// 启用一个动作(假设这里是一个菜单项或按钮),允许用户追加内容
ui->actAppend->setEnabled(true);

iniModelData(aFileContent); // 初始化模型数据
}

void MainWindow::iniModelData(QStringList& aFileContent)
{
int rowCnt = aFileContent.size(); // 获取文件内容的行数
m_model->setRowCount(rowCnt - 1); // 设置表格模型的行数(减去标题行)

QString header = aFileContent.at(0); // 获取标题行
QStringList headerList = header.split(QRegularExpression(R"(\s+)"), Qt::SkipEmptyParts); // 根据空白字符拆分标题行
m_model->setHorizontalHeaderLabels(headerList); // 设置表头标签

QStandardItem* aItem; // 用于创建每个单元格的项
int j;
for(int i = 1; i < rowCnt; i++) // 从第二行开始遍历文件内容
{
QString aLineText = aFileContent.at(i); // 获取当前行的文本
QStringList tmpList = aLineText.split(QRegularExpression(R"(\s+)"), Qt::SkipEmptyParts); // 根据空白字符拆分当前行

for(j = 0; j < 6; j++) // 遍历当前行的每一列(假设每行有6列)
{
aItem = new QStandardItem(tmpList.at(j)); // 创建一个新的项,内容为当前列的值
m_model->setItem(i - 1, j, aItem); // 在指定位置设置项
}

// 处理最后一列
aItem = new QStandardItem(tmpList.at(j)); // 创建最后一列的项
aItem->setCheckable(true); // 设置项为可选中的
aItem->setBackground(QBrush(Qt::yellow)); // 设置项的背景颜色为黄色
if(tmpList.at(j) == "0") // 如果值为0,则设置为未选中状态
{
aItem->setCheckState(Qt::Unchecked);
}
else // 否则设置为选中状态
{
aItem->setCheckState(Qt::Checked);
}
m_model->setItem(i - 1, j, aItem); // 在指定位置设置项
}
}


12. QTableWidget

QTableWidget继承自QTableView,QTableWidget是QTableView的子类,主要的区别是QTableView可以使用自定义的数据模型来显示内容(也就是先要通过setModel来绑定数据源),而QTableWidget则只能使用标准的数据模型,并且其单元格数据是QTableWidgetItem的对象来实现的

12.1 初始化表格数据
界面上的“初始化表格数据”按钮根据表格的行数,生成数据填充表格,并为每个单元格生成 QTableWidgetItem 对象,设置相应属性。下面是 btnlniData 的 clicked() 信号的槽函数代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void ManagerInterface::readMenuInfo()
{
QFile file("menuInfo.dat");
file.open(QIODevice::ReadOnly);
if (!file.isOpen())
{
qDebug() << "文件打开失败1";
}
else
{
QString name;
QString type;
double price;
double discount;
QString imagePath;
QDataStream in(&file);
while (!in.atEnd())
{
in >> name >> type >> price >> discount>> imagePath;
ui->menuTable->insertRow(ui->menuTable->rowCount());
creatTableRows(ui->menuTable->rowCount()-1, name, type, price, discount,imagePath);//注意要将获得的行数减一
qDebug() << name << type << price << discount << imagePath;
}
}
file.close();
}
---------------------------------------------------------------------------
QTableWidget::clearContents() 函数清除表格数据区的所有内容,但是不清除表头。

QTableWidget::rowCount() 函数返回表格数据区的行数。

for 循环里为每一行生成需要显示的数据,然后调用自定义函数 creatTableRows(),为表格一行的各个单元格生成 QTableWidgetItem 对象。

creatTableRows() 是在窗体类里自定义的函数,其实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void ManagerInterface::creatTableRows(int rowNo,  QString menuName, QString type, double price, double discount,QString imagePath)
{
QTableWidgetItem* item;

item = new QTableWidgetItem(menuName);
item->setTextAlignment(Qt::AlignCenter);
ui->menuTable->setItem(rowNo, 0, item);

item = new QTableWidgetItem(type);
item->setTextAlignment(Qt::AlignCenter);
ui->menuTable->setItem(rowNo, 1, item);

item = new QTableWidgetItem(QString::number(price, 'f', 2));
item->setTextAlignment(Qt::AlignCenter);
ui->menuTable->setItem(rowNo, 2, item);

item = new QTableWidgetItem(QString::number(discount, 'f', 2));
item->setTextAlignment(Qt::AlignCenter);
ui->menuTable->setItem(rowNo, 3, item);

item = new QTableWidgetItem(imagePath);
item->setTextAlignment(Qt::AlignCenter);
ui->menuTable->setItem(rowNo, 4, item);

//将第四列隐藏
ui->menuTable->setColumnHidden(4, true);

}

12.2 获得当前单元格数据
当鼠标在表格上单击单元格时,被选中的单元格是当前单元格。通过QTableWidget 的 currentColumn() 和 currentRow() 可以获得当前单元格的列编号和行编号。

当前单元格发生切换时,会发射==currentCellChanged() 信号和 currentItemChanged()==信号,两个信号都可以利用,只是传递的参数不同。

对 currentCellChanged() 信号编写槽函数,用于获取当前单元格的数据,以及当前行的学生的学号信息,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void MainWindow::on_tableInfo_currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn)
{//当前选择单元格发生变化时的响应
Q_UNUSED(previousRow);
Q_UNUSED(previousColumn);
QTableWidgetItem* item=ui->tableInfo->item(currentRow,currentColumn); //获取单元格的 Item
if (item==NULL)
return;
labCellIndex->setText(QString::asprintf("当前单元格坐标:%d 行,%d 列",currentRow,currentColumn));
int cellType=item->type();//获取单元格的类型
labCellType->setText(QString::asprintf("当前单元格类型:%d",cellType));
item=ui->tableInfo->item(currentRow,MainWindow::colName); //取当前行第1列的单元格的 item
int ID=item->data(Qt::UserRole).toInt();//用data()函数提取自定义数据,也就是创建单元格时存储的学生 ID
labStudID->setText(QString::asprintf("学生ID:%d",ID));//学生ID
}

12.3 插入、添加、删除行
QTableWidget 处理行操作的函数如下:

insertRow(int row):在行号为row的行前面插入一行,如果row等于或大于总行数,则在表格最后添加一行。insertRow()函数只是插入一个空行,不会为单元格创建QTableWidgetItem对象,需要手工为单元格创建。
removeRow(int row):删除行号为 row 的行。

下面是界面上“插入行” “添加行”“删除当前行”按钮的响应代码。在插入行之后,会调用 createItemsARow() 函数,为新创建的空行的各单元格构造 QTableWidgetItem 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void MainWindow::on_btnInsertRow_clicked()
{ //插入一行
//int curRow;
int curRow=ui->tableInfo->currentRow();//当前行号
ui->tableInfo->insertRow(curRow); //插入一行,但不会自动为单元格创建item
createItemsARow(curRow, "新学生", "男",
QDate::fromString("1990-1-1","yyyy-M-d"),"苗族",true,60 ); //为某一行创建items
}
void MainWindow::on_btnAppendRow_clicked()
{ //添加一行
//int curRow;
int curRow=ui->tableInfo->rowCount();//总行号
ui->tableInfo->insertRow(curRow);//在表格尾部添加一行
createItemsARow(curRow, "新生", "女",
QDate::fromString("2000-1-1","yyyy-M-d"),"满族",false,50 ); //为某一行创建items
}
void MainWindow::on_btnDelCurRow_clicked()
{//删除当前行及其items
//int curRow;
int curRow=ui->tableInfo->currentRow();//当前行号
ui->tableInfo->removeRow(curRow); //删除当前行及其items
}

12.4 自动调整行高和列宽
QTableWidget 有几个函数自动调整表格的行高和列宽,分别如下:

1
2
3
4
5
6
resizeColumnsToContents():自动调整所有列的宽度,以适应其内容。
resizeColumnToContents(int column):自动调整列号为 co/www 的列的宽度。
resizeRowsToContents():自动调整所有行的高度,以适应其内容。
resizeRowToContents(int row):自动调整行号为 raw 的行的高度。

这几个函数实际上是 QTableWidget 的父类 QTableView 的函数。

12.4 其他属性控制
设置表格内容是否可编辑:QTableWidget 的 EditTriggers 属性表示是否可编辑,以及进入编辑状态的方式。界面上的"表格可编辑"复选框的槽函数代码为:

1
2
3
4
5
6
7
8
void MainWindow::on_chkBoxTabEditable_clicked(bool checked)
{ //设置编辑模式
if (checked)
//双击或获取焦点后单击,进入编辑状态
ui->tableInfo->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::SelectedClicked);
else
ui->tableInfo->setEditTriggers(QAbstractItemView::NoEditTriggers); //不允许编辑
}

设置行表头、列表头是否显示:horizontalHeader()获取行表头,verticalHeader()获取列表头,然后可设置其可见性。

1
2
3
4
5
6
7
8
9
10
void MainWindow::on_chkBoxHeaderH_clicked(bool checked)
{
//是否显示水平表头
ui->tableInfo->horizontalHeader()->setVisible(checked);
}
void MainWindow::on_chkBoxHeaderV_clicked(bool checked)
{
//是否显示垂直表头
ui->tableInfo->verticalHeader()->setVisible(checked);
}

间隔行底色:setAltematingRowColors() 函数可以设置表格的行是否用交替底色显示,若为交替底色,则间隔的一行会用灰色作为底色。具体底色的设置需要用 styleSheet。

1
2
3
4
void MainWindow::on_chkBoxRowColor_clicked(bool checked)
{
ui->tableInfo->setAlternatingRowColors(checked);
}

选择模式:setSelectionBehavior() 函数可以设置选择方式为单元格选择,还是行选择:

1
2
3
4
5
6
7
8
void MainWindow::on_rBtnSelectItem_clicked()
{//选择行为:单元格选择
ui->tableInfo->setSelectionBehavior(QAbstractItemView::Selectltems);
}
void MainWindow::on_rBtnSelectRow_clicked()
{//选择行为:行选择
ui->tableInfo->setSelectionBehavior(QAbstractItemView::SelectRows);
}

12.6 遍历表格读取数据
“读取表格内容到文本”按钮演示了将表格数据区的内容全部读出的方法,它将每个单元格的文字读出,同一行的单元格的文字用空格分隔开,作为文本的一行,然后将这行文字作为文本编辑器的一行内容,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void ManagerInterface::saveMenuInfo()
{
QFile file("menuInfo.dat");
file.open(QIODevice::WriteOnly);
if (!file.isOpen())
{
qDebug() << "文件打开失败2";
}
else
{
QDataStream out(&file);
for (int i = 0; i < ui->menuTable->rowCount(); i++)
{
QTableWidgetItem* item = ui->menuTable->item(i, 0);
QString menuName = item->text();
item = ui->menuTable->item(i, 1);
QString type = item->text();
item = ui->menuTable->item(i, 2);
double price = item->text().toDouble();
item = ui->menuTable->item(i, 3);
double discount = item->text().toDouble();

item = ui->menuTable->item(i, 4);
QString imagePath = item->text();

out << menuName << type << price << discount<<imagePath;

}
file.close();
}
}

12.7 在一个qtablewidgetitem中设置复选框

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
QTableWidgetItem* item;
for (int i = 0; i < ui->menuTable->rowCount(); i++)
{
item = ui->menuTable->item(i,0);
item->setCheckState(Qt::Unchecked);
}


//单一控制 利用QTableWidget::cellchanged()函数判断单元格内容的变化

//批量删除被选择的行
void ManagerInterface::on_deleteBut_clicked()
{
for (int i = 0; i < ui->menuTable->rowCount(); i++)
{
if(ui->menuTable->item(i,0)->checkState() == Qt::Checked)
ui->menuTable->removeRow(i);
}
}