一、功能描述
需要完成带吸附效果的线段就需要完成一下功能点。
-
线段绘制。
-
当鼠标接近绘制好的线段时线段变粗。
-
当线段在线段两段时,按下鼠标选择定点移动。
-
当选择线段中间时,线段平移。
二、代码分析
实现以上功能,需要完成关键的三个鼠标响应事件。
// 鼠标按下事件
void mousePressEvent(QMouseEvent *event);
// 鼠标释放事件
void mouseReleaseEvent(QMouseEvent *event);
// 鼠标要移动事件
void mouseMoveEvent(QMouseEvent *event);
关键的绘图事件
// 界面的绘制在这里
void paintEvent(QPaintEvent *event);
关键数据结构
enum SelStatus {
outLine, // 在线段外
onStartPoint, // 在起始点
onEndPoint, // 在结束点
onLine // 在线段上
struct LineSegment {
QPointF startPoint; // 线段起点
QPointF endPoint; // 点段终点
LineSegment(QPointF a, QPointF b)
startPoint = a;
endPoint = b;
LineSegment() {}
struct LineInfo {
bool bDraw; //是否绘制
SelStatus selStatus; // 线段的选中状态
LineSegment* seg; // 保存线段的起始和终点坐标
LineInfo()
selStatus = outLine;
seg = new LineSegment;
~LineInfo() { delete seg; }
在mainwindow中定义变量m_listLineInfos,保存所有的已经绘制的线段数据。
QList<LineInfo> m_listLineInfos
LineInfo * m_currectSelectedLine 保存当前被选中的线段的指针。
-
记录按下的点以及线段绘制的起始点。
-
如果线段被选中,记录选中的线段的起始点和结束点
void QDrawingPaperView::mousePressEvent(QMouseEvent *event)
switch (event->button()) {
case Qt::LeftButton:
m_bLBtnDown = true; // 记录左键鼠标按下
m_currectSelectedLine = nullptr;
m_currectSelectedLine = getSeleledLine();
if (nullptr == m_currectSelectedLine) { // 未选中
m_startPoint = event->pos();
m_endPoint = m_startPoint;
// 记录绘画起始点
m_tempLine = new LineInfo;
m_tempLine->seg->startPoint.setX(event->x());
m_tempLine->seg->startPoint.setY(event->y());
} else {
m_tmpPoint = event->pos();
// 记录被选中的开始点和结束点,当鼠标移动时需要通过他们来计算移动的偏移量。
m_startPoint = m_currectSelectedLine->seg->startPoint;
m_endPoint = m_currectSelectedLine->seg->endPoint;
break;
default:
break;
-
记录按下的点以及线段绘制的结束点。
-
如果线段被选中不做处理。
void QDrawingPaperView::mouseReleaseEvent(QMouseEvent *event)
switch (event->button()) {
case Qt::LeftButton:
m_bLBtnDown = false; // 记录左键鼠标按下
if (nullptr == m_currectSelectedLine) {
// 记录绘画结束点
m_tempLine->seg->endPoint.setX(event->pos().x());
m_tempLine->seg->endPoint.setY(event->pos().y());
m_tempLine->bDraw = true;
// 将线段信息保存在列表中,开始位置不能与起始位置重复.
if (m_tempLine->seg->startPoint != m_tempLine->seg->endPoint)
m_listLineInfos.push_back(m_tempLine);
} else {
m_currectSelectedLine = nullptr;
break;
default:
break;
update();
关键的算法都在这里。
-
需要判断是否选中线段
-
需要判断选择线段的位置
-
如果选中需要判断是否已经按下。
-
如果按下更具选中的状态修改线段坐标点
void QDrawingPaperView::mouseMoveEvent(QMouseEvent *event)
QPointF movePt = event->pos();
if (!m_bLBtnDown) {
selSeg(movePt);
m_currectSelectedLine = getSeleledLine();
if (nullptr == m_currectSelectedLine) {
if (m_bLBtnDown) {
m_endPoint = movePt;
} else {
if (m_bLBtnDown) {
if (m_currectSelectedLine->selStatus == onLine) {
qInfo() << (movePt);
qInfo() << "m_tmpPoint" << m_tmpPoint;
qInfo() << "偏移:" << movePt - m_tmpPoint;
qInfo() << m_currectSelectedLine->seg->startPoint + movePt -
m_tmpPoint;
m_currectSelectedLine->seg->startPoint =
m_startPoint + movePt - m_tmpPoint;
m_currectSelectedLine->seg->endPoint =
m_endPoint + movePt - m_tmpPoint;
qInfo() << "endPoint" << (m_currectSelectedLine->seg->endPoint);
} else if (m_currectSelectedLine->selStatus == onStartPoint) {
m_currectSelectedLine->seg->startPoint =
m_startPoint + movePt - m_tmpPoint;
} else if (m_currectSelectedLine->selStatus == onEndPoint) {
m_currectSelectedLine->seg->endPoint =
m_endPoint + movePt - m_tmpPoint;
update();
线段绘制的入门基础可以查看文章
QT线段画板实战_啊渊的专栏-CSDN博客
void QDrawingPaperView::paintEvent(QPaintEvent *event)
QPainter p(this);
// 设置画笔的样式
// 绘制临时图像
if (m_bLBtnDown == true && nullptr == m_currectSelectedLine) {
p.setPen(QPen(Qt::red, 1));
p.drawLine(m_startPoint, m_endPoint);
// 绘制最终的数据列表
foreach (auto item, m_listLineInfos) {
if (true == item->bDraw) {
// 如果线段选中状态不是outLine那么必然在线段上,要么在开始点,要么在结束点,要么在线段上
if (item->selStatus != outLine) {
p.setPen(QPen(Qt::red, 2));
if (item->selStatus == onStartPoint) {
p.setPen(QPen(Qt::red, 2));
p.drawEllipse(item->seg->startPoint, 3, 3);
} else if (item->selStatus == onEndPoint) {
p.setPen(QPen(Qt::red, 2));
p.drawEllipse(item->seg->endPoint, 3, 3);
} else {
// 未选中状态使用细线绘制。
p.setPen(QPen(Qt::red, 1));
p.drawLine(item->seg->startPoint, item->seg->endPoint);
计算垂点,详细分析可以查看文章
求点到线段的最短距离(QT)_啊渊的专栏-CSDN博客
QPointF QDrawingPaperView::getPointToLineVerticalpoint(QPointF pt,
LineSegment seg)
QPointF np;
double x_se = seg.startPoint.x() - seg.endPoint.x();
double y_se = seg.startPoint.y() - seg.endPoint.y();
double x_se_2 = x_se * x_se;
double y_se_2 = y_se * y_se;
double x = (x_se_2 * pt.x() + (pt.y() - seg.startPoint.y()) * y_se * x_se +
seg.startPoint.x() * y_se_2) /
(x_se_2 + y_se_2);
double y = pt.y() + x_se * (pt.x() - x) / y_se;
np.setX(x);
np.setY(y);
return np;
git传送门
代码编译指令
mkdir build
qmake ..
CustomLine3 · master · 啊渊 / QT博客案例 · GIT CODE
一、功能描述需要完成带吸附效果的线段就需要完成一下功能点。线段绘制。 当鼠标接近绘制好的线段时线段变粗。 当线段在线段两段时,按下鼠标选择定点移动。 当选择线段中间时,线段平移。二、代码分析实现以上功能,需要完成关键的三个鼠标响应事件。// 鼠标按下事件void mousePressEvent(QMouseEvent *event);// 鼠标释放事件void mouseReleaseEvent(QMouseEvent *event);// 鼠标要移动事件void m..
某日,闲来无事,无聊的翻看着电脑中的APP图标,忽然萌生一个想法:用Axure原型制作一个连连看类型的游戏原型,于是说做就做,打开AxureRP7,开始搞。一天,两天。。。(由于只有业余时间搞)。。。五天,原型终于搞定。期间经过了不同实现方法的尝试、逻辑的梳理、原型的测试等等等。。。。开始界面:点击PLAY按钮即可进入游戏游戏界面:点击翻开图片,图片等待将近1s的时间后自动恢复,如果依次翻开的两个图片如果相同,这两个图片则自动消失,显示OVER字样结束界面:点击REPLAY可以重新开始游戏补充一些废话,做事情要有始有终,所以原型设计也是这样,要有头有尾。这个过程真的不是那么顺利,从开始只是有一
这次主要和大家分享一下常用的一个功能,截图工具的实现。我仿照常用的QQ截图工具用Qt5做了一个功能上的实能。功能目前实现了常用的一些,有几个功能还未实现,以后有机会实现吧(应该没机会了)。
已经实现的功能:
实现单屏幕上的矩形选择截图。
可拖动、缩放、重绘矩形选框。
支持线条、矩形框、椭圆、箭头、字体的绘制。
颜色、大小可供选择。
支持撤销、保存操作。
鼠标放大镜功能。
未实现的功能:
截图边框吸附功能
马赛克功能(做了一半)
还有未测试出的数不清的bug
学习DSP需要一些前置知识,如信号与系统、傅里叶变换、滤波等。如果对这些概念不熟悉,需要先进行相关学习。
首先,需要了解DSP的基本概念和原理,可以通过阅读相关书籍或教材来学习。其中,推荐书籍有《数字信号处理》、《实时数字信号处理》等。
其次,需要熟练使用Matlab或C语言等编程语言,在实践中不断操练。可以通过搭建实验环境,如使用FPGA开发板或软件仿真平台等,来进行具体实践项目。
在学习过程中还要注重理论与实践结合,可以将学习知识应用于项目中,如音频信号处理、数字滤波器设计等,这样可以更深入地理解DSP的应用。
最后,可以通过查阅一些DSP相关文章和论文来拓宽知识面,关注业界最新技术和发展趋势。
总之,DSP学习需要坚持不懈,理论与实践相结合,多读书、多实践,才能逐步掌握。
### 回答2:
关于如何学习并掌握数字信号处理 (DSP) 的知识,我建议从以下几个方面入手:
1. 基础数学知识:DSP 依赖于一些基本的数学知识,如线性代数、概率论、微积分等。因此,拥有坚实的数学基础是非常重要的。如果你已经有了这些基础,那么可以直接开始学习 DSP。
2. 学习 DSP 理论:DSP 可以从理论与实践两个方面来进行学习。首先,你可以阅读相关的书籍和教材,如“数字信号处理”(Alan V. Oppenheim)、"数字信号处理导论" (John G. Proakis) 等,通过了解 DSP 的理论知识,进一步深入 DSP 的概念和算法。
3. 学习 DSP 实践:除了理论部分的学习,你还应该了解 DSP 的实践应用。这可以通过实验或者模拟得到实现。在这一方面,你可以从学习一些常用的 DSP 硬件平台开始,如 Texas Instruments 的 C2000 和 C6000 DSP 系列,或者者一些常见的软件平台,如 Matlab 和 Simulink。
4. 不断练习与实践:这是最重要的步骤,只有通过不断的练习和实践才能真正掌握 DSP 的技能。你可以通过做一些设计项目来实践,如滤波器的设计、语音信号处理、图像处理等。此外,也可以参加一些 DSP 相关的竞赛和实习项目来提升自己的实践经验。
总之,DSP 是一个需要持续不断学习和实践的领域。通过这些学习和实践的方式,我们可以不断地提高自己的 DSP 技能,从而更好地应用于我们的实际工作中。
### 回答3:
学习 DSP(数字信号处理)是一项有挑战性的任务,但掌握了这个领域的基础知识,你就可以应用它来解决各种实际问题。以下是一些手把手教你学 DSP 的建议和步骤:
1. 找到一本优质的学习资料,如《数字信号处理与MATLAB》或《数字信号处理》。这些书籍不仅会教你基本概念和原理,还提供了实际案例和代码示例。
2. 熟悉 DSP 的数学基础,包括傅里叶变换、Z 变换、LaPlace 变换等。同时,了解采样定理和滤波器设计的基础知识也很重要。
3. 安装 MATLAB 软件并学会使用它进行数字信号处理。有很多关于 Matlab 的学习资料可以帮助你学会基本的编程和信号处理技能。
4. 尝试使用不同类型的滤波器,如 FIR(有限脉冲响应)和 IIR(无限脉冲响应)滤波器。掌握滤波器的设计和实现技巧对于 DSP 任务至关重要。
5. 学习数字滤波的原理和应用。数字滤波器可以用于去除噪声和干扰,在信号恢复和增强等方面也具有广泛的应用。
总之,学习 DSP 需要坚定的决心和充分的时间投入。通过系统学习、实践和探究,你将能够深入理解 DSP 的原理和应用,掌握数字信号处理的核心技能。