1、访问控件的子控件:
(1)访问控件中的控件:
想要访问控件的控件时,使用下面的两种方法:
QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
QList QObject::findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
Qt::FindChildOptions options
可选可不选,其可选属性有:
Qt::FindDirectChildrenOnly //值0x0,在object的直接孩子中查找
Qt::FindChildrenRecursively //值0x1,在object的所有孩子中查找,包括其孩子的孩子
(2)使用时:
findchild
:
//只有一个
QLabel *label1= icon1->findChild<QLabel*>("h1",Qt::FindDirectChildrenOnly);
当未找到名为h1
的子控件时,会返回控件本身。如果找到,就会返回这个控件。
qDebug()<<icon1->findChild<QLabel*>("h1",Qt::FindDirectChildrenOnly);
findchildren
:
QList<QLabel*> qLabels = icon1->findChildren<QLabel*>();
qDebug()<<qLabels;
qDebug()<<qLabels[1];
如果找到,就会返回控件的数组。如果未找到,就会返回一个空的数组。
(3)在之前的自建控件中使用:
之前写的自建的控件,想要访问其中元素也可以这样来,之前的链接:https://blog.csdn.net/qq_36780295/article/details/113860352
但是试了一下,发现直接查找子元素能找到,但添加子控件的objectname
就找不到了,无语,不过也不影响。
当该类型的子控件只有一个时,就用findchild
来访问。当该类型的子控件有两个以上的时候,就用findchildren
放到容器中,然后通过数组来访问。
查找的代码:
QWidget *icon1 = icon();
icon1->setParent(ui->label_1);
//只有 1 个label时
QLabel *lab1= icon1->findChild<QLabel*>();
//有 2 个及以上的pushbutton时
QList<QPushButton*> btns = icon1->findChildren<QPushButton*>();
获取到了对象就能对其修改了,如果想要在其他的函数中使用,除了extern
或golabal
,建议还是把实例化和子控件寻址写在头文件中。
数组中的控件顺序是按在内存中的地址来的。new
出来的也是从前往后申请内存空间的,所以与自建控件中定义的顺序一致。
控制子元素时:
lab1->setStyleSheet("background-color:red;");
btns[1]->setStyleSheet("background-color:red;"); //第二个按钮子控件
运行结果:
2、qss让控件上下左右偏移:
直接方向加像素就可以了:
setStyleSheet("top:2px;left:2px;bottom:2px;right:2px;");
3、重绘combobox的样式:
combox
右边的小三角可以通过drop-down
元素来访问,下拉动作则可以通过on
来访问。下面给个例子:
ui->oddNumber->setStyleSheet("QComboBox#oddNumber{background-color:white;border-radius:3px;border:0px solid rgb(220,220,220);}"
"QComboBox#oddNumber::drop-down{width:15px;height:15px;border-image:url(:/new/prefix1/source/drop_down.png);top:2px;right:1px;}"
"QComboBox#oddNumber::drop-down:on{border-image:url(:/new/prefix1/source/drop_up.png);}");
上面图示就是运行结果,下拉时:
4、添加opencv:
(1)下载opencv:
可以去官网下新版本的,旧版本已经无法下载了。
opencv
官网:https://opencv.org/opencv
下载:https://sourceforge.net/projects/opencvlibrary/files/
之前保存过2.4.11
版本的:
链接:https://pan.baidu.com/s/1vetQc6TMlgfYahy_djfQ6A
提取码:nm6g
一定要看好自己的qt
版本来下载,如果与qt
版本不匹配,就会出现缺少dll
文件缺失,导致debug
模式无法运行。确认版本的两种方法:
-
通过左下角搜索
Qt
,比如我查找到的是Qt MSVC2015
,就是vs2015版本的qt,那我就要下载有vc14
版本的opencv
。
-
还有一种方法就是打开文件夹到
C:\Windows\SysWOW64
,翻到一堆msvcp
的dll
和msvcr
的dll
文件的地方,看一下有没有d
结尾的dll
文件,如:msvcp140d.dll
。观察发现只有msvcp140.dll
是有对应的带d
的dll
,其他的100
、110
、120
等都是单独的不带d
的。不带d
的是release
模式会用到的,带d
的是debug
模式会用到的。所以下载opencv
只要下载包含vc14
的就行了。如果安装和配置错了opencv
版本,qt
就找不到debug
模式下的dll
,debug
模式就会出错。
不要想着装其他版本的opencv
,然后自己去下debug
模式的msvcp
和msvcr
了,我试过了。下完了放到系统文件夹,还要添加到注册表,各种添加失败浪费时间,最后debug
模式还是会由于版本不匹配,找不到自己添加的dll
而报错。
opencv
下载完提取文件到D盘
即可,提取到其他目录,那下面的配置要改一下路径。
(2)配置opencv:
下面以配置opencv-3.4.6
,msvc2015
为例。
环境变量:
我的电脑->属性->高级系统设置->环境变量
在用户变量的PATH
中添加:
地址根据自己提取的opencv
路径来,x64
中会有多个vc
文件夹,配置自己用的那个版本。请不要随便改qt
的环境变量,不然可能会导致qtcreater
不能用,惨痛的教训。
配置qt:
- 在
.pro
中添加:
# opencv 3.4.6
INCLUDEPATH += D:\opencv\build\include \
D:\opencv\build\include\opencv \
D:\opencv\build\include\opencv2
# 把vc14目录下的所有lib包添加过来,以 d 结尾的是debug模式用的,没有d结尾的是release模式用的
CONFIG(debug,debug|release) {
LIBS += -LD:\opencv\build\x64\vc14\lib \
-lopencv_world346d
} else {
LIBS += -LD:\opencv\build\x64\vc14\lib \
-lopencv_world346
}
同样添加自己使用的vc
版本。每次修改环境变量
或者.pro
文件后,运行前都先点击构建->重新构建项目
,然后再运行。
- 在头文件中添加:
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
不一定添加到mainwindow.h
中,放到自己建的class
的头文件中也可,记得在mainwindow.h
中include
这个类。如果添加的头文件下面一堆红线,提示找不到opencv.hpp
等,那肯定是.pro
文件中的路径写错了,仔细检查检查。还有一种是重新构建时提示无法打开某个刚刚添加的包,多半也是.pro
中路径写错了
(3)测试代码:
测试是否可以正常使用时可以修改main.cpp
中的代码:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
//QApplication a(argc, argv);
//MainWindow w;
//w.showFullScreen();
//w.show();
//return a.exec();
//图片路径自己添加
Mat img = imread("C:/Users/Administrator/Pictures/qtback/1.jpg");
imshow("image",img);
waitKey(0);
return 0;
}
运行结果:
不出意外的话,会有一个窗口显示图片:
(4)程序异常结束:
坑我已经踩过了,上面是已经修改好的了,跟着上面的步骤来配置基本不会出错。
测试时:
-
如果
构建
时提示某某包不存在,那多半就是.pro
中的某个包的包名写错了。 -
如果配置完以后编译构建,没问题,但是一旦运行就会提示
程序异常结束
,连个错误原因也没有,一般就是链接库丢失。要看具体是哪个丢失,去到项目文件夹中,找到生成的debug
文件夹,在里面找到.exe
文件,双击运行,一般就会提示找不到什么什么.dll
,在针对着修复。一般可能就是directx
缺失,vc++
组件缺失,和dll
缺失等。directx
可以用directx
修复工具,dll
和vc++
大多可以在杀毒软件,如腾讯管家的电脑诊所中查找到修复。 -
如果构建没问题,
debug
和release
都出现程序异常退出,但是打开项目文件夹,发现exe
是能正常运行的,其实表示已经配置好了,重启电脑即可。
其他可能的问题或解决方法:
- 包的路径写错了,如检查这一段:
LIBS += -LD:\opencv\build\x64\vc14\lib \
,其中-L
和路径中间不要有空格。 - 检查环境变量有没有配错。再看看是不是以前装过
opencv
,然后有多个版本的opencv
的环境变量。 - 左下角搜索
Qt
,打开搜索出来的MSVC
,执行set
命令,会输出环境变量
,再在cmd
中执行set
,看看两个环境变量是不是一样的,可能有些特殊符号会把环境变量截断,(之前在某篇博客看到的方法,虽然我看了一下没有出错,还是在这里写一下吧,原出处由于重启找不到了,浏览器历史中也找不到,就不放链接了)。 release
可以,debug
就程序异常结束,多半是opencv
和qt
的msvc
版本不匹配,如msvc2015
就要配置vc14
版本的opencv
。
5、Qt中使用海康相机:
(1)下载海康的sdk
软件,我放在网盘里了:
链接:https://pan.baidu.com/s/1VgNfMAMQueJMvaAH88OSgQ
提取码:bv1b
MVS
是必须装的,记住安装目录。软件包中的另一个sdk
不清楚,最好也装一下。
装完后,将MVS
安装目录下的MVS\Development
目录下的Include
文件夹复制到Qt
项目中,再将Libraries
文件夹下win64
中的MvCameraControl.lib
压缩包放到之前拷贝的Include
中。
(2)添加海康sdk到项目:
在 .pro
中添加代码:
# HKcamera
# $$PWD 表示当前项目地址
LIBS += -L$$PWD/Includes/ -lMvCameraControl
INCLUDEPATH += $$PWD/Includes
DEPENDPATH += $$PWD/Includes
海康相机的函数接口,通过打开mvs
软件,帮助->Development
,会打开development
的文件夹,然后打开Samples->C++Builder->XE5->BasicDemo
,在MyCamera
中保存了一些接口函数。
把函数接口写到Qt
中去,在项目中创建一个Class
,名字设为HKcamera
。
在HKcamera.h
中添加代码:
#ifndef HKCAMERA_H
#define HKCAMERA_H
//opencv
//#include <QDebug>
//#include <opencv2/opencv.hpp>
//#include <opencv2/core/core.hpp>
//#include <opencv2/highgui/highgui.hpp>
//using namespace cv;
#include "MvCameraControl.h"
#include "MvErrorDefine.h"
#include "CameraParams.h"
#include <string>
#define MY_OK 0
#define MY_FAIL -1
class HKcamera
{
public:
HKcamera();
~HKcamera();
static int EnumDevices(MV_CC_DEVICE_INFO_LIST* pstDevList);
// 打开设备
int Open(MV_CC_DEVICE_INFO* pstDeviceInfo);
// 关闭设备
int Close();
// 开启抓图
int StartGrabbing();
// 停止抓图
int StopGrabbing();
// 主动获取一帧图像数据
int GetOneFrameTimeout(unsigned char* pData, unsigned int* pnDataLen, unsigned int nDataSize, MV_FRAME_OUT_INFO_EX* pFrameInfo, int nMsec);
// 设置显示窗口句柄
int Display(void* hWnd);
// 保存图片
int SaveImage(MV_SAVE_IMAGE_PARAM_EX* pstParam);
// 注册图像数据回调
int RegisterImageCallBack(void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser),void* pUser);
// 注册消息异常回调
int RegisterExceptionCallBack(void(__stdcall* cbException)(unsigned int nMsgType, void* pUser),void* pUser);
// 设置和获取Int型参数,如 Width和Height,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int GetIntValue(IN const char* strKey, OUT unsigned int *pnValue);
int SetIntValue(IN const char* strKey, IN unsigned int nValue);
// 设置和获取Float型参数,如 ExposureTime和Gain,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int GetFloatValue(IN const char* strKey, OUT float *pfValue);
int SetFloatValue(IN const char* strKey, IN float fValue);
// 设置和获取Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int GetEnumValue(IN const char* strKey, OUT unsigned int *pnValue);
int SetEnumValue(IN const char* strKey, IN unsigned int nValue);
// 设置和获取Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int GetBoolValue(IN const char* strKey, OUT bool *pbValue);
int SetBoolValue(IN const char* strKey, IN bool bValue);
// 设置和获取String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件UserSetSave
int GetStringValue(IN const char* strKey, IN OUT char* strValue, IN unsigned int nSize);
int SetStringValue(IN const char* strKey, IN const char * strValue);
// 执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int CommandExecute(IN const char* strKey);
private:
void* m_hDevHandle;
};
#endif // HKCAMERA_H
在HKcamera.cpp
中添加下面代码:
#include "hkcamera.h"
HKcamera::HKcamera()
{
m_hDevHandle = NULL;
}
HKcamera::~HKcamera()
{
if (m_hDevHandle)
{
MV_CC_DestroyHandle(m_hDevHandle);
m_hDevHandle = NULL;
}
}
//枚举设备
int HKcamera::EnumDevices(MV_CC_DEVICE_INFO_LIST* pstDevList)
{
int nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, pstDevList);
if (MV_OK != nRet)
{
return MY_FAIL;
}
return MY_OK;
}
//打开设备
int HKcamera::Open(MV_CC_DEVICE_INFO* pstDeviceInfo)
{
if (NULL == pstDeviceInfo)
{
return MY_FAIL;
}
int nRet = MV_CC_CreateHandle(&m_hDevHandle, pstDeviceInfo);
if (MV_OK != nRet)
{
return MY_FAIL;
}
nRet = MV_CC_OpenDevice(m_hDevHandle);
if (MV_OK != nRet)
{
MV_CC_DestroyHandle(&m_hDevHandle);
return MY_FAIL;
}
return MY_OK;
}
//关闭设备
int HKcamera::Close()
{
if (NULL == m_hDevHandle)
{
return MY_FAIL;
}
MV_CC_CloseDevice(m_hDevHandle);
return MV_CC_DestroyHandle(m_hDevHandle);
}
//开启抓图
int HKcamera::StartGrabbing()
{
if (NULL == m_hDevHandle)
{
return MY_FAIL;
}
return MV_CC_StartGrabbing(m_hDevHandle);
}
//停止抓图
int HKcamera::StopGrabbing()
{
if (NULL == m_hDevHandle)
{
return MY_FAIL;
}
return MV_CC_StopGrabbing(m_hDevHandle);
}
//主动获取一帧图像数据
int HKcamera::GetOneFrameTimeout(unsigned char* pData
, unsigned int* pnDataLen
, unsigned int nDataSize
, MV_FRAME_OUT_INFO_EX* pFrameInfo
, int nMsec)
{
if (NULL == m_hDevHandle || NULL == pData || NULL == pnDataLen || NULL == pFrameInfo)
{
return MY_FAIL;
}
*pnDataLen = 0;
int nRet = MV_CC_GetOneFrameTimeout(m_hDevHandle, pData, nDataSize, pFrameInfo, nMsec);
if (MV_OK != nRet)
{
return MY_FAIL;
}
*pnDataLen = pFrameInfo->nFrameLen;
return MY_OK;
}
//显示
int HKcamera::Display(void* hWnd)
{
if (NULL == m_hDevHandle)
{
return MY_FAIL;
}
return MV_CC_Display(m_hDevHandle, hWnd);
}
//保存图片
int HKcamera::SaveImage(MV_SAVE_IMAGE_PARAM_EX* pstParam)
{
if (NULL == pstParam)
{
return MY_FAIL;
}
return MV_CC_SaveImageEx(pstParam);
}
//注册图像数据回调
int HKcamera::RegisterImageCallBack(void(__stdcall* cbOutput)(unsigned char * pData
,MV_FRAME_OUT_INFO_EX* pFrameInfo
,void* pUser)
,void* pUser)
{
if (NULL == m_hDevHandle)
{
return MY_FAIL;
}
return MV_CC_RegisterImageCallBackEx(m_hDevHandle, cbOutput, pUser);
}
//注册消息异常回调
int HKcamera::RegisterExceptionCallBack(void(__stdcall* cbException)(unsigned int nMsgType
,void* pUser)
,void* pUser)
{
if (NULL == m_hDevHandle)
{
return MY_FAIL;
}
return MV_CC_RegisterExceptionCallBack(m_hDevHandle, cbException, pUser);
}
//获取和设置Int型参数,如 Width和Height,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int HKcamera::GetIntValue(IN const char* strKey, OUT unsigned int *pnValue)
{
if (NULL == m_hDevHandle || NULL == strKey || NULL == pnValue)
{
return MY_FAIL;
}
MVCC_INTVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_INTVALUE));
int nRet = MV_CC_GetIntValue(m_hDevHandle, strKey, &stParam);
if (MV_OK != nRet)
{
return MY_FAIL;
}
*pnValue = stParam.nCurValue;
return MY_OK;
}
int HKcamera::SetIntValue(IN const char* strKey, IN unsigned int nValue)
{
if (NULL == m_hDevHandle || NULL == strKey)
{
return MY_FAIL;
}
return MV_CC_SetIntValue(m_hDevHandle, strKey, nValue);
}
//获取和设置Float型参数,如 ExposureTime和Gain,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int HKcamera::GetFloatValue(IN const char* strKey, OUT float *pfValue)
{
if (NULL == m_hDevHandle || NULL == strKey || NULL == pfValue)
{
return MY_FAIL;
}
MVCC_FLOATVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_FLOATVALUE));
int nRet = MV_CC_GetFloatValue(m_hDevHandle, strKey, &stParam);
if (MV_OK != nRet)
{
return MY_FAIL;
}
*pfValue = stParam.fCurValue;
return MY_OK;
}
int HKcamera::SetFloatValue(IN const char* strKey, IN float fValue)
{
if (NULL == m_hDevHandle || NULL == strKey)
{
return MY_FAIL;
}
return MV_CC_SetFloatValue(m_hDevHandle, strKey, fValue);
}
//获取和设置Enum型参数,如 PixelFormat,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int HKcamera::GetEnumValue(IN const char* strKey, OUT unsigned int *pnValue)
{
if (NULL == m_hDevHandle || NULL == strKey || NULL == pnValue)
{
return MY_FAIL;
}
MVCC_ENUMVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_ENUMVALUE));
int nRet = MV_CC_GetEnumValue(m_hDevHandle, strKey, &stParam);
if (MV_OK != nRet)
{
return MY_FAIL;
}
*pnValue = stParam.nCurValue;
return MY_OK;
}
int HKcamera::SetEnumValue(IN const char* strKey, IN unsigned int nValue)
{
if (NULL == m_hDevHandle || NULL == strKey)
{
return MY_FAIL;
}
return MV_CC_SetEnumValue(m_hDevHandle, strKey, nValue);
}
//获取和设置Bool型参数,如 ReverseX,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int HKcamera::GetBoolValue(IN const char* strKey, OUT bool *pbValue)
{
if (NULL == m_hDevHandle || NULL == strKey || NULL == pbValue)
{
return MY_FAIL;
}
int nRet = MV_CC_GetBoolValue(m_hDevHandle, strKey, pbValue);
if (MV_OK != nRet)
{
return MY_FAIL;
}
return MY_OK;
}
int HKcamera::SetBoolValue(IN const char* strKey, IN bool bValue)
{
if (NULL == m_hDevHandle || NULL == strKey)
{
return MY_FAIL;
}
return MV_CC_SetBoolValue(m_hDevHandle, strKey, bValue);
}
//获取和设置String型参数,如 DeviceUserID,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件UserSetSave
int HKcamera::GetStringValue(IN const char* strKey
, IN OUT char* strValue
, IN unsigned int nSize)
{
if (NULL == m_hDevHandle || NULL == strKey || NULL == strValue)
{
return MY_FAIL;
}
MVCC_STRINGVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_STRINGVALUE));
int nRet = MV_CC_GetStringValue(m_hDevHandle, strKey, &stParam);
if (MV_OK != nRet)
{
return MY_FAIL;
}
strcpy_s(strValue, nSize, stParam.chCurValue);
return MY_OK;
}
int HKcamera::SetStringValue(IN const char* strKey, IN const char* strValue)
{
if (NULL == m_hDevHandle || NULL == strKey)
{
return MY_FAIL;
}
return MV_CC_SetStringValue(m_hDevHandle, strKey, strValue);
}
//执行一次Command型命令,如 UserSetSave,详细内容参考SDK安装目录下的 MvCameraNode.xlsx 文件
int HKcamera::CommandExecute(IN const char* strKey)
{
if (NULL == m_hDevHandle || NULL == strKey)
{
return MY_FAIL;
}
return MV_CC_SetCommandValue(m_hDevHandle, strKey);
}
使用时,在mainwindow.h
中引入hkcamera
类,创建海康相机的对象就能使用了。
同目录下的BasicDemo
是演示的实例,上面这些函数接口的使用可以参考这里。
为了在C++
中使用海康相机,需要使用代码执行以下操作:
1、回调函数。
这个函数每一次回调,就会执行一次,在回调函数中 使用 MV_FRAME_OUT_INFO_EX 接收相机图像信息。
2、EnumDevices() OpenDevice() 枚举和打开设备。
3、MV_CC_RegisterImageCallBackEx() 注册回调函数
4、SetTriggerMode() 设置触发模式
触发模式即指定怎样触发拍一张或多张照,包括软触发和硬触发,软触发可以是一个commond,硬触发则可以是一个电信号
除此之外,还可以通过SetTriggerMode(MV_TRIGGER_MODE_OFF);来关闭触发模式,这样开始采集流后就会一直触发,而非指定次数,或发送信号的触发
5、数据包延迟,像素通道,Gamma等属性。
6、MV_CC_StartGrabbing() 获取流,如果以上一些操作都设置好了,打开获取流以后,相机就会进入画面捕捉了