0%

QT_(九)-光标

要求

要求:**一个弹窗界面有多个弹窗以及按钮,现在主界面有上下左右按钮,同时还有鼠标点击

针对上下左右按钮,需要知道当前在哪个位置,往哪个方向移动,所以需要将页面中的控件统一起来

解决方案:设计一个结构,保存所有相关控件的指针,然后等待后续的上下左右

一、设置结构

布局中有QLineEdit、QComboBox、QPushButton等,可以设置成二维矩阵,另外设置一个当前光标位置focusedWidget用来追踪状态

1
2
3
4
QVector<QVector<QWidget*>> grid;	// 用于存储控件指针的二维数组
QWidget* focusedWidget; // 默认光标控件
int currentRow = 0;
int currentColumn = 0;

二、初始化结构,添加控件

将所有相关的控件都添加到QVector的二维结构之中,以便后续从此进行查找

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
void SettingsDialog::initGrid()
{
grid.resize(9); // 9*3的二维矩阵
for (int i = 0; i < 9; ++i)
{
grid[i].resize(3); // 每行 3 列,默认初始化为 QWidget* 的 nullptr
}

setWidget(0, 0, ui->m_edtDriverId);
setWidget(1, 0, ui->m_edtAssistDriverId);
setWidget(2, 0, ui->m_edtSectionId);
setWidget(3, 0, ui->m_edtStationId);
setWidget(4, 0, ui->m_comboxTrainType);
setWidget(5, 0, ui->m_edtTrainNum);
setWidget(6, 0, ui->m_comboxPassengerOrFreight);
setWidget(7, 0, ui->m_comboxMainOrAssist);
setWidget(8, 0, ui->m_btnConfirm);

setWidget(0, 1, ui->m_edtTotalWeight);
setWidget(1, 1, ui->m_edtCarriageCount);
setWidget(2, 1, ui->m_edtTotalLength);
setWidget(3, 1, ui->m_edtSpeedLimit);
setWidget(4, 1, nullptr);
setWidget(5, 1, nullptr);
setWidget(6, 1, nullptr);
setWidget(7, 1, nullptr);
setWidget(8, 1, nullptr);

setWidget(0, 2, ui->m_edtLoadWeight);
setWidget(1, 2, ui->m_edtPassengerCar);
setWidget(2, 2, ui->m_edtLoadCar);
setWidget(3, 2, ui->m_edtEmptyCar);
setWidget(4, 2, ui->m_edtNonOperatingCar);
setWidget(5, 2, ui->m_edtSubstitutePassengerCar);
setWidget(6, 2, ui->m_edtGuardCar);
setWidget(7, 2, nullptr);
setWidget(8, 2, ui->m_btnCancel);
}

void SettingsDialog::setWidget(int row, int col, QWidget* widget)
{
if (row >= 0 && row < grid.size() && col >= 0 && col < grid[row].size())
{
grid[row][col] = widget;
}
}

三、建立信号槽

建立信号槽,创建上下左右的实现函数

在主界面LKJ中实现connect

1
2
3
4
connect(this, &LKJ::signalSettingsDialogUp, settingsDialog, &SettingsDialog::moveFocusUp);
connect(this, &LKJ::signalSettingsDialogDown, settingsDialog, &SettingsDialog::moveFocusDown);
connect(this, &LKJ::signalSettingsDialogLeft, settingsDialog, &SettingsDialog::moveFocusLeft);
connect(this, &LKJ::signalSettingsDialogRight, settingsDialog, &SettingsDialog::moveFocusRight);

四、实现光标切换

以向下为例,判断当前控件指针focusedWidget如何变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void SettingsDialog::moveFocusDown()
{
qDebug() << QStringLiteral("当前拥有焦点的控件:") << focusedWidget;
focusedWidget->setStyleSheet("background-color: white;");

do
{
currentRow++;
currentRow %= 9;
} while (grid[currentRow][currentColumn] == nullptr);
focusedWidget = grid[currentRow][currentColumn];

qDebug() << QStringLiteral("当前向下拥有焦点的控件:") << focusedWidget;
focusedWidget->setStyleSheet("background-color: blue;");
}

1.5、

这里发现一个问题,我设置的grid结构的光标指针与我鼠标点击的光标指针不同步,如何解决,

最后设想,在点击控件的时候,可以发出信号然后修改focusedWidget

可是,QLineEdit没有clicked,它的focusInEvent是一个虚拟函数,在获取焦点的时候,会调用此函数;所以在自定义控件CustomLineEdit中重写此函,发出customClicked()信号

注意:自定义控件文件需要是单独的.h或.cpp文件,不要把它加在其他文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once

#include <QLineEdit>

class CustomLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit CustomLineEdit(QWidget* parent = nullptr);

signals:
void customClicked();

protected:
void focusInEvent(QFocusEvent* event) override;
};
1
2
3
4
5
6
7
8
9
10
11
#include "CustomLineEdit.h"
#include <QFocusEvent>

CustomLineEdit::CustomLineEdit(QWidget* parent)
: QLineEdit(parent) {}

void CustomLineEdit::focusInEvent(QFocusEvent* event)
{
QLineEdit::focusInEvent(event);
emit customClicked();
}

1.6、

完成自定义控件customLineEdit的编写之后,需要对QLineEdit进行提升,将其变为CustomLineEdit类型

然后建立connect连接

1
2
// 连接 customClicked 信号
connect(ui->m_edtDriverId, &CustomLineEdit::customClicked, this, [this]() { onEditBoxClicked(ui->m_edtDriverId); });

1.7、

然后根据当前是什么控件,查找到对应的位置,更改光标

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
void SettingsDialog::onEditBoxClicked(CustomLineEdit* edit)
{
// 检查传入的编辑框是否有效
if (!edit)
{
return;
}

// 更新当前焦点的位置
//updateCurrentFocus(edit);
for (int row = 0; row < grid.size(); ++row)
{
for (int column = 0; column < grid[row].size(); ++column)
{
if (grid[row][column] == edit)
{
// 更新当前行列信息
currentRow = row;
currentColumn = column;
focusedWidget->setStyleSheet("background-color: white;"
"border-left: 2px solid black; "
"border-top: 2px solid black; "
"border-right: 2px solid white; "
"border-bottom: 2px solid white; ");
focusedWidget = grid[currentRow][currentColumn];
focusedWidget->setStyleSheet("background-color: blue;"
"border-left: 2px solid black; "
"border-top: 2px solid black; "
"border-right: 2px solid white; "
"border-bottom: 2px solid white; ");
return;
}
}
}
}

1.8、

同理,针对QComboBox,自定义控件,重写focusInEvent函数,发送信号,对Ui中的控件进行升级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma once

#include <QComboBox>
#include <QFocusEvent>

class CustomComboBox : public QComboBox
{
Q_OBJECT
public:
explicit CustomComboBox(QWidget* parent = nullptr) : QComboBox(parent) {}

signals:
void customClicked();

protected:
void focusInEvent(QFocusEvent* event) override
{
QComboBox::focusInEvent(event);
emit customClicked(); // 发出自定义点击信号
}
};


-------------本文结束感谢您的阅读-------------