前言

  本项目的出现理由只是笔者的一个念头,于是利用专业Qt和Opencv相关的知识开发一个辅助工具,本文章仅用于Qt和Opencv结合的学习。

 

Demo演示效果

  
  
  
  

运行包下载地址(供测试学习)

  CSDN粉丝0积分下载地址:https://download.csdn.net/download/qq21497936/85372782
  QQ群下载地址:1047134658(点击“文件”搜索“findTheDifference”,群内与博文同步更新)

运行包+源码包下载地址(供测试学习)

  CSDN下载地址:https://download.csdn.net/download/qq21497936/85372767
  (注意:源码本博客后面都有,若是想一步到位,下载这个,源码编译版本为Qt5.9.x mingw32 + openCV3.4.10)

 

功能列表

  • 应用程序可将某Q游戏界面套入内部区域,游戏方便操作;
  • 抓图区域调整,可通过右上角区域,调整区域1和区域2的位置;
  • 位置微调功能,点击按钮可像对应方向微调一个像素;
  • 识别不同,调用opencv算法,识别不同处在游戏图上绘制显示区域;
  • 游戏界面区域操作焦点为游戏界面;
  • 可清空已经绘制的区域;
 

Qt技术点

 

OpenCV技术点

 

项目模块化部署

  项目的环境为Qt5.9.3 mingw32版本,使用QtCreator开发,配合mingw32版本的Opencv3.4.10,下图左侧为项目结构,右侧为实际文件夹部署结构。
  

 

Qt代码:DrawWdget

  该类的主要作用:

  • 覆盖在游戏窗口上
  • 全部透明窗口用以当作游戏界面上的画布
  • 对鼠标消息穿透(无法点击中)
  • 识别出后绘制标记处不同的区域

Ui界面

  为自动生成默认的,没有任何改动。
  
  一共绘制两类图形,一类是框出抓取图的界面,一类是识别出后的区域,定义两个缓存变量,用以绘制对应的区域矩形。

DrawWidegt.h

#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H #include <QWidget> namespace Ui {
class DrawWidget;
} class DrawWidget : public QWidget
{
Q_OBJECT public:
explicit DrawWidget(QWidget *parent = 0);
~DrawWidget(); public:
void setRect(int x, int y, int width, int height);
void setRect2(int x, int y, int width, int height);
void clearListRect();
void setListRect(QList<QRect> listRect); protected:
void initControl(); protected:
void paintEvent(QPaintEvent *event); protected:
void drawSelectRect(QPainter *painter);
void drawListRect(QPainter *painter); private:
Ui::DrawWidget *ui; private:
QColor _colorRect;
QRect _rect;
QRect _rect2; QList<QRect> _listRect; }; #endif // DRAWWIDGET_H

DrawWidget.cpp

#include "DrawWidget.h"
#include "ui_DrawWidget.h"
#include <QPainter>
#include <windows.h> #include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") DrawWidget::DrawWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::DrawWidget),
_colorRect(Qt::red)
{
ui->setupUi(this); setWindowFlag(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_TransparentForMouseEvents); initControl();
} DrawWidget::~DrawWidget()
{
delete ui;
} void DrawWidget::setRect(int x, int y, int width, int height)
{
_rect.setRect(x, y, width, height);
} void DrawWidget::setRect2(int x, int y, int width, int height)
{
_rect2.setRect(x, y, width, height);
LOG << _rect << _rect2;
} void DrawWidget::clearListRect()
{
_listRect.clear();
update();
} void DrawWidget::setListRect(QList<QRect> listRect)
{
_listRect = listRect;
update();
} void DrawWidget::initControl()
{
// 置顶
::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
} void DrawWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this); drawSelectRect(&painter);
drawListRect(&painter);
} void DrawWidget::drawSelectRect(QPainter *painter)
{
painter->save(); painter->setPen(QPen(_colorRect, 4));
painter->drawRect(_rect);
painter->drawRect(_rect2); painter->restore();
} void DrawWidget::drawListRect(QPainter *painter)
{
painter->save(); painter->setPen(QPen(Qt::white, 2));
for(int index = 0; index < _listRect.size(); index++)
{
painter->drawRect(_rect.x() + _listRect.at(index).x(),
_rect.y() + _listRect.at(index).y(),
_listRect.at(index).width(),
_listRect.at(index).height()); }
painter->setPen(QPen(Qt::blue, 2));
for(int index = 0; index < _listRect.size(); index++)
{
painter->drawRect(_rect2.x() + _listRect.at(index).x(),
_rect2.y() + _listRect.at(index).y(),
_listRect.at(index).width(),
_listRect.at(index).height());
}
painter->restore();
}
 

Qt代码:FindDifferenceWidget

  该类的主要作用:

  • 作为主窗口提供一个套入找茬游戏界面的区域;
  • 提供可以动态选取抓取区域的控件;
  • 提供微调控件,微调应用窗口,并且让DrawWidget窗口与透明区域位置同步改变;
  • 提供识别触发按钮,将识别结果反馈到DrawWidget;
  • 清空按钮,将识别的结果进行清空,也就是删除识别结果的矩形;

Ui界面

  

FindDifferenceWidget.h

#ifndef FINDDIFFERENCEWIDGET_H
#define FINDDIFFERENCEWIDGET_H #include <QWidget>
#include <QPainter>
#include <QRect>
#include <QRegion>
#include <QList>
#include "FindDifferenceManager.h"
#include "DrawWidget.h"
#include <QElapsedTimer> namespace Ui {
class FindDifferenceWidget;
} class FindDifferenceWidget : public QWidget
{
Q_OBJECT public:
explicit FindDifferenceWidget(QWidget *parent = 0);
~FindDifferenceWidget(); protected:
void initControl();
void updateGameRect(); protected slots:
void slot_initControl(); protected:
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
void moveEvent(QMoveEvent *event);
void closeEvent(QCloseEvent *event); protected slots:
void slot_valueChanged(int value); protected slots:
void slot_findResult(bool result, QList<QRect> listRect = QList<QRect>()); private slots:
void on_pushButton_do_clicked();
void on_pushButton_up_clicked();
void on_pushButton_left_clicked();
void on_pushButton_right_clicked();
void on_pushButton_down_clicked();
void on_pushButton_clear_clicked(); private:
Ui::FindDifferenceWidget *ui; private:
FindDifferenceManager *_pFindDifferenceManager;
QRect _rectGame;
QRect _rectApplication;
int _captionHeigh;
int _margin; DrawWidget *_pDrawWidget;
}; #endif // FINDDIFFERENCEWIDGET_H

FindDifferenceWidget.cpp

#include "FindDifferenceWidget.h"
#include "ui_FindDifferenceWidget.h" #include <windows.h>
#include <QApplication>
#include <QDesktopWidget>
#include <QScreen>
#include <QTimer> #include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") FindDifferenceWidget::FindDifferenceWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::FindDifferenceWidget),
_pFindDifferenceManager(0),
_pDrawWidget(0)
{
ui->setupUi(this); QString version = "v1.0.0";
setWindowTitle(QString("大家来找茬(仅供学习Qt+OpenCV实战项目) Demo %1(作者:长沙红胖子 QQ:21497936 WX:15173255813 blog:hpzwl.blog.csdn.net").arg(version)); resize(1230, 785); initControl(); QTimer::singleShot(0, this, SLOT(slot_initControl()));
} FindDifferenceWidget::~FindDifferenceWidget()
{
delete ui;
} void FindDifferenceWidget::initControl()
{
// 置顶
::SetWindowPos(HWND(this->winId()), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); // 识别类
_pFindDifferenceManager = new FindDifferenceManager();
connect(_pFindDifferenceManager, SIGNAL(signal_findResult(bool,QList<QRect>)),
this, SLOT(slot_findResult(bool,QList<QRect>))); // 初始化
_captionHeigh = 26;
_margin = 3;
updateGameRect(); _pDrawWidget = new DrawWidget();
_pDrawWidget->show(); connect(ui->spinBox_image1X, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int)));
connect(ui->spinBox_image1Y, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int)));
connect(ui->spinBox_image1Width, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int)));
connect(ui->spinBox_image1Height, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int))); connect(ui->spinBox_image2X, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int)));
connect(ui->spinBox_image2Y, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int)));
connect(ui->spinBox_image2Width, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int)));
connect(ui->spinBox_image2Height, SIGNAL(valueChanged(int)),
this, SLOT(slot_valueChanged(int))); _pDrawWidget->setRect(ui->spinBox_image1X->value(),
ui->spinBox_image1Y->value(),
ui->spinBox_image1Width->value(),
ui->spinBox_image1Height->value()); _pDrawWidget->setRect2(ui->spinBox_image2X->value(),
ui->spinBox_image2Y->value(),
ui->spinBox_image2Width->value(),
ui->spinBox_image2Height->value()); } void FindDifferenceWidget::updateGameRect()
{
_rectApplication = QRect(-_margin,
-_captionHeigh,
rect().width() + _margin*2,
rect().height() + _captionHeigh + _margin);
_rectGame = QRect(_margin, rect().height() - _margin - 780, 1032, 780);
} void FindDifferenceWidget::slot_initControl()
{
_pDrawWidget->setGeometry(ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(),
ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(),
ui->frame_mask->width(),
ui->frame_mask->height()); } void FindDifferenceWidget::paintEvent(QPaintEvent *event)
{
#if 1
QRegion r1(_rectApplication);
QRegion r2(_rectGame);
QRegion r3 = r1 - r2;
setMask(r3);
#endif
QWidget::paintEvent(event);
} void FindDifferenceWidget::resizeEvent(QResizeEvent *event)
{
// 初始化
updateGameRect(); if(_pDrawWidget)
{
_pDrawWidget->setGeometry(ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(),
ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(),
ui->frame_mask->width(),
ui->frame_mask->height());
}
} void FindDifferenceWidget::moveEvent(QMoveEvent *event)
{
if(_pDrawWidget)
{
_pDrawWidget->setGeometry(ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(),
ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(),
ui->frame_mask->width(),
ui->frame_mask->height());
}
LOG << geometry();
} void FindDifferenceWidget::closeEvent(QCloseEvent *event)
{
_pDrawWidget->hide();
_pDrawWidget->deleteLater();
} void FindDifferenceWidget::slot_valueChanged(int value)
{
_pDrawWidget->setRect(ui->spinBox_image1X->value(),
ui->spinBox_image1Y->value(),
ui->spinBox_image1Width->value(),
ui->spinBox_image1Height->value()); _pDrawWidget->setRect2(ui->spinBox_image2X->value(),
ui->spinBox_image2Y->value(),
ui->spinBox_image2Width->value(),
ui->spinBox_image2Height->value());
_pDrawWidget->update(); QSpinBox *pSpinBox = dynamic_cast<QSpinBox *>(sender());
if(pSpinBox == ui->spinBox_image1Width)
{
ui->spinBox_image2Width->setValue(value);
}else if(pSpinBox == ui->spinBox_image2Width)
{
ui->spinBox_image1Width->setValue(value);
}else if(pSpinBox == ui->spinBox_image1Height)
{
ui->spinBox_image2Height->setValue(value);
}else if(pSpinBox == ui->spinBox_image2Height)
{
ui->spinBox_image1Height->setValue(value);
}
} void FindDifferenceWidget::slot_findResult(bool result, QList<QRect> listRect)
{
if(result)
{
LOG << listRect;
_pDrawWidget->setListRect(listRect);
}
} void FindDifferenceWidget::on_pushButton_do_clicked()
{
_pDrawWidget->clearListRect(); QElapsedTimer elapsedTimer;
elapsedTimer.start();
while(elapsedTimer.elapsed() < 500)
{
qApp->processEvents();
} QScreen * pScreen = QApplication::primaryScreen();
QImage gameImage = pScreen->grabWindow(QApplication::desktop()->winId(),
ui->frame_mask->mapToGlobal(QPoint(0, 0)).x(),
ui->frame_mask->mapToGlobal(QPoint(0, 0)).y(),
ui->frame_mask->width(),
ui->frame_mask->height()).toImage();
QImage image1 = gameImage.copy(ui->spinBox_image1X->value(),
ui->spinBox_image1Y->value(),
ui->spinBox_image1Width->value(),
ui->spinBox_image1Height->value());
QImage image2 = gameImage.copy(ui->spinBox_image2X->value(),
ui->spinBox_image2Y->value(),
ui->spinBox_image2Width->value(),
ui->spinBox_image2Height->value());
_pFindDifferenceManager->slot_findDiffrence(image1, image2);
} void FindDifferenceWidget::on_pushButton_up_clicked()
{
setGeometry(geometry().x(), geometry().y() - 1, geometry().width(), geometry().height());
} void FindDifferenceWidget::on_pushButton_left_clicked()
{
setGeometry(geometry().x() - 1, geometry().y(), geometry().width(), geometry().height());
} void FindDifferenceWidget::on_pushButton_right_clicked()
{
setGeometry(geometry().x() + 1, geometry().y(), geometry().width(), geometry().height());
} void FindDifferenceWidget::on_pushButton_down_clicked()
{
setGeometry(geometry().x(), geometry().y() + 1, geometry().width(), geometry().height());
} void FindDifferenceWidget::on_pushButton_clear_clicked()
{
_pDrawWidget->setListRect(QList<QRect>());
}
 

OpenCV代码:FindDifferenceManager

  识别不同处代码类功能:

  • 引入OpenCV头文件和库文件
  • 提供接口输入2个同样大小的矩形、阈值和能识别的最小矩形。
  • 核心算法:先灰度图->阈值化->寻找边界->识别最小矩形
      (最开始算法进行了滤波,闭运算,因为实际有可能存在两幅图截屏就有色差导致灰度图色差小,实际有可能原图色差较小导致灰度色差较小,实际有可能不同的点较少导致滤波去掉了这些点,以上三种经过测试都是存在的)。

FindDifferenceManager.h

#ifndef FINDDIFFERENCEMANAGER_H
#define FINDDIFFERENCEMANAGER_H #include <QObject>
#include <QImage> // opencv
#include "opencv/highgui.h"
#include "opencv/cxcore.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/opencv.hpp"
#include "opencv2/xphoto.hpp"
#include "opencv2/dnn/dnn.hpp"
// opencv_contrib
#include <opencv2/xphoto.hpp>
#include <opencv2/ximgproc.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp> class FindDifferenceManager : public QObject
{
Q_OBJECT
public:
explicit FindDifferenceManager(QObject *parent = 0); private:
bool getRunning() const; signals:
void signal_findResult(bool result, QList<QRect> listRect = QList<QRect>()); public slots:
void slot_start();
void slot_stop(); public slots:
void slot_findDiffrence(QImage image, QImage image2, int thresh = 20, QRect minRect = QRect(0, 0, 4, 4)); protected:
cv::Mat image2Mat(QImage image); private:
bool _running;
}; #endif // FINDDIFFERENCEMANAGER_H

FindDifferenceManager.cpp

#include "FindDifferenceManager.h"
#include <QTimer> #include <QDebug>
#include <QDateTime>
//#define LOG qDebug()<<__FILE__<<__LINE__
//#define LOG qDebug()<<__FILE__<<__LINE__<<__FUNCTION__
//#define LOG qDebug()<<__FILE__<<__LINE__<<QThread()::currentThread()
//#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd")
#define LOG qDebug()<<__FILE__<<__LINE__<<QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") FindDifferenceManager::FindDifferenceManager(QObject *parent)
: QObject(parent),
_running(false)
{
qRegisterMetaType<QList<QRect>>("QList<QRect> ");
} bool FindDifferenceManager::getRunning() const
{
return _running;
} void FindDifferenceManager::slot_start()
{
if(_running)
{
LOG << "Failed to" << __FUNCTION__ << ", it's already running.";
return;
}
_running = true;
} void FindDifferenceManager::slot_stop()
{
if(!_running)
{
LOG << "Failed to" << __FUNCTION__ << ", it's not running.";
return;
}
_running = false;
} void FindDifferenceManager::slot_findDiffrence(QImage image, QImage image2, int thresh, QRect minRect)
{
QList<QRect> listRect; // 将QImage转换为cv::Mat
cv::Mat srcMat = image2Mat(image);
cv::Mat srcMat2 = image2Mat(image2); if ((srcMat.rows != srcMat2.rows) || (srcMat.cols != srcMat2.cols))
{
emit signal_findResult(false);
} cv::Mat srcMatGray;
cv::Mat srcMat2Gray; // 转灰度图
cv::cvtColor(srcMat, srcMatGray, cv::COLOR_BGR2GRAY);
cv::cvtColor(srcMat2, srcMat2Gray, cv::COLOR_BGR2GRAY); // cv::imshow("1", srcMatGray);
// cv::imshow("2", srcMat2Gray); cv::Mat diffMatGray;
// 图1减去图2:查看差异(灰度,可能差距不大,0-255, 0 1 2 3差距小看不出)
cv::subtract(srcMatGray, srcMat2Gray, diffMatGray, cv::Mat(), CV_16SC1); // 绝对值(有负数,变正数)
// cv::imshow("3", diffMatGray);
cv::Mat diffAbsMatGray = cv::abs(diffMatGray); // 改变位深(归一化试过,但是可能存在0和255,导致漏掉一些)
diffAbsMatGray.convertTo(diffAbsMatGray, CV_8UC1, 1, 0);
// cv::imshow("4", diffAbsMatGray); #if 0
// 整个像素降低5个点的误差(色差)
for(int row = 0; row < diffAbsMatGray.rows; row++)
{
for( int col = 0; col < diffAbsMatGray.cols; col++)
{
if(diffAbsMatGray.at<uchar>(row, col) < 3)
{
diffAbsMatGray.at<uchar>(row, col) = 0;
}else{
diffAbsMatGray.at<uchar>(row, col) = diffAbsMatGray.at<uchar>(row, col) - 5;
}
}
}
#endif cv::Mat threshMat;
//阈值处理
cv::threshold(diffAbsMatGray, threshMat, thresh, 255, cv::THRESH_BINARY);
// cv::imshow("5", threshMat); cv::Mat mdianMat;
#if 0
//中值滤波
cv::medianBlur(threshMat, mdianMat, 3);
cv::imshow("6", mdianMat);
#else
mdianMat = threshMat.clone();
#endif cv::Mat closeMat;
#if 0
// 闭运算: 用拟合小裂缝,消除小型黑洞,并且在平滑较大物体的边界的同时不明显改变其面积。
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3), cv::Point(-1, -1));
cv::morphologyEx(mdianMat, closeMat, cv::MORPH_CLOSE, kernel, cv::Point(-1, -1), 2, cv::BORDER_REPLICATE);
#else
closeMat = mdianMat.clone();
#endif
// cv::imshow("7", closeMat); // 寻找边界
std::vector<std::vector<cv::Point>> contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(closeMat,
contours,
hierarchy,
CV_RETR_EXTERNAL,
CV_CHAIN_APPROX_SIMPLE,
cv::Point(0, 0));
std::vector<std::vector<cv::Point>> contoursPoly(contours.size()); for(int index = 0; index < contours.size(); index++)
{
cv::approxPolyDP(cv::Mat(contours[index]), contoursPoly[index], 5, true);
cv::Rect rect = cv::boundingRect(cv::Mat(contoursPoly[index])); #if 0
// 小于最小矩形则忽略
if(rect.width < minRect.width() || rect.height < minRect.height())
{
continue;
}
#endif
listRect.append(QRect(rect.x, rect.y, rect.width, rect.height));
// cv::rectangle(srcMat, rect, cv::Scalar(0, 255, 0), 2);
// cv::rectangle(srcMat2, rect, cv::Scalar(0, 255, 0), 2);
}
// cv::imshow("8", srcMat2); // cv::waitKey(0); emit signal_findResult(true, listRect);
} cv::Mat FindDifferenceManager::image2Mat(QImage image)
{
cv::Mat mat;
switch(image.format())
{
case QImage::Format_ARGB32:
case QImage::Format_RGB32:
case QImage::Format_ARGB32_Premultiplied:
mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
cv::cvtColor(mat, mat, CV_BGRA2BGR);
break;
case QImage::Format_RGB888:
mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
cv::cvtColor(mat, mat, CV_BGR2RGB);
break;
case QImage::Format_Indexed8:
case QImage::Format_Grayscale8:
mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
break;
default:
qDebug() << __FILE__ << __LINE__ << "error to image2Mat !!! imge.format =" << image.format();
}
return mat;
}
 

项目实战:Qt+OpenCV大家来找茬(Qt抓图,穿透应用,识别左右图区别,框选区别,微调位置)的更多相关文章

  1. 项目实战:Qt+Ffmpeg+OpenCV相机程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  2. 【QT】找茬外挂制作

    找茬外挂制作 找茬游戏大家肯定都很熟悉吧,两张类似的图片,找里面的不同.在下眼神不大好,经常瞪图片半天也找不到区别.于是乎决定做个辅助工具来解放一下自己的双眼. 一.使用工具 Qt:主要是用来做界面的 ...

  3. 【大话QT之十六】使用ctkPluginFramework插件系统构建项目实战

    "使用ctkPluginFramework插件系统构建项目实战",这篇文章是写博客以来最纠结的一篇文章. 倒不是由于技术都多么困难,而是想去描写叙述一个项目架构採用ctkPlugi ...

  4. 项目实战:Qt手机模拟器拉伸旋转框架

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  5. Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)

    Visual Studio 2015开发Qt项目实战经验分享(附项目示例源码)    转 https://blog.csdn.net/lhl1124281072/article/details/800 ...

  6. QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL

    QT5 QSS QML界面美化视频课程系列 QT原理 项目实战 C++1X STL 课程1   C语言程序设计高级实用速成课程 基础+进阶+自学 课程2   C语言程序设计Windows GDI图形绘 ...

  7. Win10下部署VS+Qt+OpenCV+darknet(YOLO)集成环境

    VS+Qt集成环境 下载VS与Qt并安装. VS:官网链接 Qt:下载链接 将Qt的bin目录加入PATH路径 bin目录举例:D:\development\Qt\5.12.0\msvc2017_64 ...

  8. 给缺少Python项目实战经验的人

    我们在学习过程中最容易犯的一个错误就是:看的多动手的少,特别是对于一些项目的开发学习就更少了! 没有一个完整的项目开发过程,是不会对整个开发流程以及理论知识有牢固的认知的,对于怎样将所学的理论知识应用 ...

  9. 【腾讯Bugly干货分享】React Native项目实战总结

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/577e16a7640ad7b4682c64a7 “8小时内拼工作,8小时外拼成长 ...

随机推荐

  1. java集合类框架的基本接口有哪些

    集合类接口指定了一组叫做元素的对象.集合类接口的每一种具体的实现类都可以以他自己的方式对元素进行保存和排序.有的集合允许重复的键,有些不允许. java集合类里面最基本 的接口: Collection ...

  2. 外部晶振的使用原因与内部RC振荡器的使用方法 _

    原因一 早些年,芯片的生产制作工艺也许还不能够将晶振做进芯片内部,但是现在可以了.这个问题主要还是实用性和成本决定的.   原因二 芯片和晶振的材料是不同的,芯片 (集成电路) 的材料是硅,而晶体则是 ...

  3. zx-editor 移动端(HTML5)富文本编辑器,可与原生App混合(hybrid)开发

    ZxEditor 移动端HTML文档(富文本)编辑器,支持图文混排.引用.大标题.无序列表,字体颜色.加粗.斜体. 可用于独立web项目开发,也可以用于与原生App混合(hybrid)开发. 源码地址 ...

  4. Javascript Symbol 隐匿的未来之星

    ES6中基础类型增加到了7种,比上一个版本多了一个Symbol,貌似出现了很长时间,但却因没有使用场景,一直当作一个概念层来理解它,我想,用它的最好的方式,还是要主动的去深入了解它吧,所以我从基础部分 ...

  5. python-排列组合序列

    [题目描述]用户输入整数n(1<=n<=26)和整数m(m<=n),然后输入n个不同的字母,请编写程序输出在这n个字母中选择m个字母的所有排列序列和组合序列. [练习要求]请给出源代 ...

  6. JS 实现权限列表移动

    JS 实现列表移动 学习内容: 需求 总结: 学习内容: 需求 用 JS 实现列表移动 实现代码 <html> <head> <meta http-equiv=" ...

  7. 小白文-Git-版本控制

    推荐阅读 Git学习-图文并茂还有游戏玩! Git版本控制 注意:开始学习之前,确保自己的网络可以畅通的连接Github:https://github.com,这个是一个国外网站,连起来特别卡,至于用 ...

  8. 【Azure API 管理】解决API Management添加AAD Group时遇见的 Failed to query Azure Active Directory graph due to error 错误

    问题描述 为APIM添加AAD Group时候,等待很长很长的时间,结果添加失败.错误消息为: Write Groups ValidationError :Failed to query Azure ...

  9. Postman+newman+jenkins+git实战

    一.接口分类,流程,用例设计 接口分类: 外部接口:被测系统与外部其他系统之间的接口. 承保系统(被测系统),核算系统. 内部接口:被测系统内部各个子模块之间的接口. 承保系统(A模块,B模块) 测试 ...

  10. ArcGIS使用技巧(七)——批量导出

    新手,若有错误还请指正! 在ArcGIS中如何将栅格数据批量导出?用到"复制栅格这个工具",这里我用的例子是:将ArcGIS默认输出的DEM文件夹批量导出为tif格式.(如果是文件 ...