第4篇 vs2019+QT调用SDK连接海康相机显示图片

作者:txwtech笛克电科日期:2025/10/5

vs2019+QT调用SDK连接海康相机显示图片

连接,采图,获取与设置参数,曝光,增益,帧率

新建项目-文件结构:

debug x64

调用类:

TTcamera.cpp

1#include "TTcamera.h"
2#include <QDebug>
3TTcamera::TTcamera()
4{
5    m_hDevHandle = NULL;
6    m_pBufForSaveImage = nullptr;
7    m_nBufSizeForSaveImage = 0;
8    m_pBufForDriver = nullptr;
9    m_nBufSizeForDriver = 0;
10    memset(&m_stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
11    m_Device = NULL;
12
13}
14
15TTcamera::~TTcamera()
16{
17    if (m_pBufForDriver != nullptr) {
18        free(m_pBufForDriver);
19        m_pBufForDriver = nullptr;
20    }
21    if (m_pBufForSaveImage != nullptr) {
22        free(m_pBufForSaveImage);
23        m_pBufForSaveImage = nullptr;
24    }
25
26    if (m_hDevHandle) {
27        MV_CC_DestroyHandle(m_hDevHandle);
28        m_hDevHandle = NULL;
29    }
30}
31
32int TTcamera::InitSDK()
33{
34    return MV_CC_Initialize();
35}
36// ch:反初始化SDK | en:Finalize SDK
37int TTcamera::FinalizeSDK()
38{
39    return MV_CC_Finalize();
40}
41
42//查询设备列表
43int TTcamera::EnumDevices(MV_CC_DEVICE_INFO_LIST* pstDevList)
44{
45    int temp = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, pstDevList);
46    if (MV_OK != temp)
47    {
48        return -1;
49    }
50    return 0;
51}
52
53//连接相机
54//id:自定义相机名称
55int TTcamera::connectCamera(string id)
56{
57    int temp = EnumDevices(&m_stDevList);
58    if (temp != 0) {
59        qDebug() << "枚举设备失败,错误码:" << temp;
60        return -1;
61    }
62
63    if (m_stDevList.nDeviceNum == 0) {
64        qDebug() << "未找到任何相机";
65        return 2;
66    }
67
68    m_Device = NULL;
69    for (unsigned int i = 0; i < m_stDevList.nDeviceNum; i++)
70    {
71        MV_CC_DEVICE_INFO* pDeviceInfo = m_stDevList.pDeviceInfo[i];
72        if (NULL == pDeviceInfo)
73        {
74            continue;
75        }
76
77        if (id == (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chUserDefinedName ||
78            id == (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber)
79        {
80            m_Device = m_stDevList.pDeviceInfo[i];
81            break;
82        }
83    }
84
85    if (m_Device == NULL) {
86        qDebug() << "未找到指定名称的相机";
87        return 3;
88    }
89
90    temp = MV_CC_CreateHandle(&m_hDevHandle, m_Device);
91    if (temp != MV_OK) {
92        qDebug() << "创建句柄失败,错误码:" << temp;
93        return -1;
94    }
95
96    temp = MV_CC_OpenDevice(m_hDevHandle);
97    if (temp != MV_OK) {
98        qDebug() << "打开设备失败,错误码:" << temp;
99        MV_CC_DestroyHandle(m_hDevHandle);
100        m_hDevHandle = NULL;
101        return -1;
102    }
103
104    // 设置触发模式为关闭(连续采集模式)
105    int triggerResult = setTriggerMode(0);
106    if (triggerResult != 0) {
107        qDebug() << "设置触发模式失败";
108        MV_CC_CloseDevice(m_hDevHandle);
109        MV_CC_DestroyHandle(m_hDevHandle);
110        m_hDevHandle = NULL;
111        return -1;
112    }
113
114    return 0;
115}
116//设置相机是否开启触发模式
117int TTcamera::setTriggerMode(unsigned int TriggerModeNum)
118{
119    int nRet = MV_CC_SetTriggerMode(m_hDevHandle, TriggerModeNum);
120    if (MV_OK != nRet)
121    {
122        return -1;
123    }
124
125}
126//启动相机采集
127int TTcamera::startCamera()
128{
129    if (m_hDevHandle == NULL) {
130        qDebug() << "相机句柄为空,无法启动采集";
131        return -1;
132    }
133
134    int temp = MV_CC_StartGrabbing(m_hDevHandle);
135    if (temp != 0)
136    {
137        qDebug() << "抓图失败,错误码:" << temp;
138        return -1;
139    }
140    else
141    {
142        qDebug() << "抓图成功";
143        return 0;
144    }
145}
146//发送软触发
147int TTcamera::softTrigger()
148{
149    int enumValue = MV_CC_SetEnumValue(m_hDevHandle, "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE);
150    if (enumValue != 0) {
151        qDebug() << "设置软触发失败";
152        return -1;
153    }
154    else {
155        qDebug() << "设置软触发";
156    }
157    int comdValue = MV_CC_SetCommandValue(m_hDevHandle, "TriggerSoftware");
158    if (comdValue != 0)
159    {
160        qDebug() << "软触发失败";
161        return -1;
162    }
163    else
164    {
165        qDebug() << "软触发一次";
166        return 0;
167    }
168}
169//读取相机中的图像
170int TTcamera::ReadBuffer(Mat& image)
171{
172    if (m_hDevHandle == NULL) {
173        qDebug() << "相机句柄为空,无法读取图像";
174        return -1;
175    }
176
177    // 释放之前分配的内存
178    if (m_pBufForDriver != nullptr) {
179        free(m_pBufForDriver);
180        m_pBufForDriver = nullptr;
181    }
182    if (m_pBufForSaveImage != nullptr) {
183        free(m_pBufForSaveImage);
184        m_pBufForSaveImage = nullptr;
185    }
186
187    unsigned int nBufSize = 0;
188    MVCC_INTVALUE stIntvalue;
189    memset(&stIntvalue, 0, sizeof(MVCC_INTVALUE));
190
191    int tempValue = MV_CC_GetIntValue(m_hDevHandle, "PayloadSize", &stIntvalue);
192    if (tempValue != 0)
193    {
194        qDebug() << "GetIntValue失败,错误码:" << tempValue;
195        return -1;
196    }
197
198    nBufSize = stIntvalue.nCurValue;
199    m_pBufForDriver = (unsigned char*)malloc(nBufSize);
200    if (m_pBufForDriver == nullptr) {
201        qDebug() << "内存分配失败";
202        return -1;
203    }
204
205    MV_FRAME_OUT_INFO_EX stImageInfo;
206    memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
207
208    int timeout = MV_CC_GetOneFrameTimeout(m_hDevHandle, m_pBufForDriver, nBufSize, &stImageInfo, 1000);
209    if (timeout != 0)
210    {
211        qDebug() << "GetOneFrameTimeout失败,错误码:" << timeout;
212        free(m_pBufForDriver);
213        m_pBufForDriver = nullptr;
214        return -1;
215    }
216
217    m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
218    m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage);
219    if (m_pBufForSaveImage == nullptr) {
220        qDebug() << "内存分配失败";
221        free(m_pBufForDriver);
222        m_pBufForDriver = nullptr;
223        return -1;
224    }
225
226    bool isMono;
227    switch (stImageInfo.enPixelType)
228    {
229    case PixelType_Gvsp_Mono8:
230    case PixelType_Gvsp_Mono10:
231    case PixelType_Gvsp_Mono10_Packed:
232    case PixelType_Gvsp_Mono12:
233    case PixelType_Gvsp_Mono12_Packed:
234        isMono = true;
235        break;
236    default:
237        isMono = false;
238        break;
239    }
240
241    if (isMono)
242    {
243        image = Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC1, m_pBufForDriver);
244    }
245    else
246    {
247        MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 };
248        stConvertParam.nWidth = stImageInfo.nWidth;
249        stConvertParam.nHeight = stImageInfo.nHeight;
250        stConvertParam.pSrcData = m_pBufForDriver;
251        stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;
252        stConvertParam.enSrcPixelType = stImageInfo.enPixelType;
253        stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed;
254        stConvertParam.pDstBuffer = m_pBufForSaveImage;
255        stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage;
256
257        int convertResult = MV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam);
258        if (convertResult != MV_OK) {
259            qDebug() << "像素格式转换失败,错误码:" << convertResult;
260            free(m_pBufForDriver);
261            free(m_pBufForSaveImage);
262            m_pBufForDriver = nullptr;
263            m_pBufForSaveImage = nullptr;
264            return -1;
265        }
266
267        image = Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3, m_pBufForSaveImage);
268    }
269
270    return 0;
271}
272//设置心跳时间
273int TTcamera::setHeartBeatTime(unsigned int time)
274{
275    //心跳时间最小为500ms
276    if (time < 500)
277        time = 500;
278    int temp = MV_CC_SetIntValue(m_hDevHandle, "GevHeartbeatTimeout", time);
279    if (temp != 0)
280    {
281        return -1;
282    }
283    else
284    {
285        return 0;
286    }
287}
288//设置曝光时间
289int TTcamera::setExposureTime(float ExposureTimeNum)
290{
291    int temp = MV_CC_SetFloatValue(m_hDevHandle, "ExposureTime", ExposureTimeNum);
292    if (temp != 0)
293        return -1;
294    return 0;
295}
296// ch:获取和设置Enum型参数,如 PixelFormat
297// en:Get Enum type parameters, such as PixelFormat
298int TTcamera::GetEnumValue(  char* strKey,  MVCC_ENUMVALUE* pEnumValue)
299{
300    return MV_CC_GetEnumValue(m_hDevHandle, strKey, pEnumValue);
301}
302int TTcamera::GetSDKVersion()
303{
304    return MV_CC_GetSDKVersion();
305}
306// ch:获取和设置Float型参数,如 ExposureTime和Gain
307// en:Get Float type parameters, such as ExposureTime and Gain
308int TTcamera::GetFloatValue(char* strKey,  MVCC_FLOATVALUE* pFloatValue)
309{
310    return MV_CC_GetFloatValue(m_hDevHandle, strKey, pFloatValue);
311}
312int TTcamera::SetEnumValue( char* strKey, unsigned int nValue)
313{
314    return MV_CC_SetEnumValue(m_hDevHandle, strKey, nValue);
315}
316int TTcamera::SetFloatValue( char* strKey, float fValue)
317{
318    return MV_CC_SetFloatValue(m_hDevHandle, strKey, fValue);
319}
320int TTcamera::SetBoolValue( char* strKey,  bool bValue)
321{
322    return MV_CC_SetBoolValue(m_hDevHandle, strKey, bValue);
323}
324//关闭相机
325int TTcamera::closeCamera()
326{
327    int nRet = MV_OK;
328    if (NULL == m_hDevHandle)
329    {
330        qDebug() << "没有句柄,不用关闭";
331        return -1;
332    }
333    MV_CC_CloseDevice(m_hDevHandle);
334    nRet = MV_CC_DestroyHandle(m_hDevHandle);
335    m_hDevHandle = NULL;
336    return nRet;
337}

TTcamera.h

1
2#ifndef TTcamera_H
3#define TTcamera_H
4#include "MvCameraControl.h"
5#pragma execution_character_set("utf-8")   //设置当前文件为UTF-8编码
6#pragma warning( disable : 4819 )    //解决SDK中包含中文问题;忽略C4819错误
7#include <stdio.h>
8#include <iostream>
9#include "opencv2/core/core.hpp"
10#include "opencv2/opencv.hpp"
11#include "opencv2/highgui/highgui.hpp"
12#include <string>
13#include <QDebug>
14#include <QDateTime> // 用于生成时间戳文件名
15
16using namespace std;
17using namespace cv;
18class TTcamera
19{
20public:
21    TTcamera();
22    ~TTcamera();
23    static int InitSDK();
24    static int FinalizeSDK();
25    //声明相关变量及函数等
26    //枚举相机设备列表
27    static int EnumDevices(MV_CC_DEVICE_INFO_LIST* pstDevList);
28    static int GetSDKVersion();
29   
30    // ch:连接相机
31    int connectCamera(string id);
32
33    //设置相机触发模式
34    int setTriggerMode(unsigned int TriggerModeNum);
35
36    //开启相机采集
37    int startCamera();
38
39    //发送软触发
40    int softTrigger();
41
42    //读取buffer
43    int ReadBuffer(Mat& image);
44
45    //设置心跳时间
46    int setHeartBeatTime(unsigned int time);
47
48    //设置曝光时间
49    int setExposureTime(float ExposureTimeNum);
50    //关闭相机
51    int closeCamera();
52    int TTcamera::GetFloatValue(char* strKey, MVCC_FLOATVALUE* pFloatValue);
53    int TTcamera::GetEnumValue(char* strKey, MVCC_ENUMVALUE* pEnumValue);
54    int TTcamera::SetEnumValue(char* strKey, unsigned int nValue);
55    int TTcamera::SetFloatValue( char* strKey, float fValue);
56    int TTcamera::SetBoolValue(char* strKey, bool bValue);
57private:
58    void* m_hDevHandle;
59public:
60    unsigned char* m_pBufForSaveImage; // 用于保存图像的缓存
61    unsigned int m_nBufSizeForSaveImage;
62    unsigned char* m_pBufForDriver; // 用于从驱动获取图像的缓存
63    unsigned int m_nBufSizeForDriver;
64    MV_CC_DEVICE_INFO_LIST m_stDevList; // ch:设备信息列表结构体变量,用来存储设备列表
65    MV_CC_DEVICE_INFO* m_Device = NULL; //设备对象
66};
67#endif // TTcamera_H

QtWidgetsApplication1.h

1#pragma once
2
3#include <QtWidgets/QMainWindow>
4#include "ui_QtWidgetsApplication1.h"
5#include "TTcamera.h"
6#include <QCloseEvent>
7#include <Qtimer>
8
9class QtWidgetsApplication1 : public QMainWindow
10{
11    Q_OBJECT
12
13public:
14    QtWidgetsApplication1(QWidget *parent = nullptr);
15    ~QtWidgetsApplication1();
16   
17
18    TTcamera* m_pcMycamera;
19    MV_CC_DEVICE_INFO_LIST m_stDevList;//设备列表
20    string cameraName; //相机名称
21    Mat imageMat; //使用OpenCV接受采集图像
22    QImage cvMat2QImage(const cv::Mat& mat);
23    QImage image;
24 
25
26private:
27    Ui::QtWidgetsApplication1Class ui;
28    QTimer* m_timer; // 用于定时获取图像
29    bool m_bIsGrabbing; // 标记是否正在连续采集
30    void closeEvent(QCloseEvent* e);
31    int GetExposureTime();
32    // 定时器超时槽函数
33    int GetTriggerMode();
34    int GetGain();
35    int                     m_nTriggerMode;                       // ch:触发模式 | en:Trigger Mode
36    bool                    m_bSoftWareTriggerCheck;
37private slots:
38    void on_pushButton_link_clicked();
39
40    void on_pushButton_close_clicked();
41
42    void on_pushButton_caiji_clicked();
43    void on_pushButton_realtime_clicked(); // 实时显示按钮
44    int GetFrameRate();
45    void updateFrame();
46   
47
48    void GetPara();
49    int GetTriggerSource();
50    int SetExposureTime();
51    int SetGain();
52     
53    int SetFrameRate();
54    void SetPara();
55    void ShowMsg(QString msg);
56    void CloseWindow();
57
58private:
59  //  Ui::MainWindow* ui;
60
61
62};
63

QtWidgetsApplication1.cpp

1#include "QtWidgetsApplication1.h"
2#include "qmessagebox.h"
3 
4
5QtWidgetsApplication1::QtWidgetsApplication1(QWidget *parent)
6    : QMainWindow(parent)
7{
8    ui.setupUi(this);
9    TTcamera::InitSDK();
10    int i_version = TTcamera::GetSDKVersion();
11    connect(ui.pushButton_start, &QPushButton::clicked, this, [=] {
12        QMessageBox::information(this,"title","btn test");
13        
14        });
15    connect(ui.pushButton_realtime, &QPushButton::clicked, this, [=] {
16       // on_pushButton_realtime_clicked();
17
18        });
19    connect(ui.on_pushButton_caiji, &QPushButton::clicked, this, [=] {
20        
21        on_pushButton_caiji_clicked();
22        });
23    connect(ui.on_pushButton_close, &QPushButton::clicked, this, [=] {
24        on_pushButton_close_clicked();
25
26        });
27    connect(ui.on_pushButton_link, &QPushButton::clicked, this, [=] {
28        on_pushButton_link_clicked();
29
30        });
31    connect(ui.pushButton_exit, &QPushButton::clicked, this, &QtWidgetsApplication1::CloseWindow);
32    
33    connect(ui.pushButton_get_para, &QPushButton::clicked, this, &QtWidgetsApplication1::GetPara);
34    connect(ui.pushButton_set_para, &QPushButton::clicked, this, &QtWidgetsApplication1::SetPara);
35
36   // ui->setupUi(this);
37    // 初始化定时器和状态变量
38    m_timer = new QTimer(this);
39    m_bIsGrabbing = false;
40    connect(m_timer, SIGNAL(timeout()), this, SLOT(updateFrame()));
41
42    m_pcMycamera = new TTcamera;
43    int neRt = m_pcMycamera->EnumDevices(&m_stDevList);
44    qDebug() << neRt;
45    qDebug() << m_stDevList.pDeviceInfo[0]->nTLayerType;
46    //获取相机的IP地址
47    if (1 == m_stDevList.pDeviceInfo[0]->nTLayerType) {
48        int nIp1, nIp2, nIp3, nIp4;
49        nIp1 = ((m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
50        nIp2 = ((m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
51        nIp3 = ((m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
52        nIp4 = (m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);
53        QString nIp = QString("%1.%2.%3.%4").arg(nIp1).arg(nIp2).arg(nIp3).arg(nIp4);
54        qDebug() << nIp;
55    }
56   
57
58}
59
60QtWidgetsApplication1::~QtWidgetsApplication1()   
61{}
62
63//连接相机
64void QtWidgetsApplication1::on_pushButton_link_clicked()
65{
66    cameraName = (char*)m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.chUserDefinedName;
67    //cameraName = (char*)m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.chSerialNumber;
68    qDebug() << "尝试连接相机:" << QString::fromStdString(cameraName);
69
70    int linkCamera = m_pcMycamera->connectCamera(cameraName);
71    qDebug() << "连接结果:" << linkCamera;
72
73    if (linkCamera == 0) {
74        qDebug() << "连接相机成功";
75
76        // 开启抓图
77        int satrtCamera = m_pcMycamera->startCamera();
78        if (satrtCamera != 0) {
79            qDebug() << "启动相机采集失败";
80            
81        }
82        else {
83            qDebug() << "正在启动相机采集信息";
84            QMessageBox::information(this, "title", "已连接相机");
85        }
86    }
87    else {
88        qDebug() << "连接相机失败,错误码:" << linkCamera;
89
90        // 尝试使用序列号连接
91        QString serialNumber = QString::fromLocal8Bit((char*)m_stDevList.pDeviceInfo[0]->SpecialInfo.stGigEInfo.chSerialNumber);
92        qDebug() << "尝试使用序列号连接:" << serialNumber;
93
94        int linkBySerial = m_pcMycamera->connectCamera(serialNumber.toStdString());
95        qDebug() << "使用序列号连接结果:" << linkBySerial;
96    }
97}
98//添加实时显示按钮的槽函数
99void QtWidgetsApplication1::on_pushButton_realtime_clicked()
100{
101    if (!m_bIsGrabbing) {
102        // 开始实时显示
103        if (m_pcMycamera->setTriggerMode(0) == 0) { // 设置为连续采集模式
104            m_timer->start(33); // 约30帧/秒
105            m_bIsGrabbing = true;
106            ui.pushButton_realtime->setText("停止实时显示");
107        }
108    }
109    else {
110        // 停止实时显示
111        m_timer->stop();
112        m_bIsGrabbing = false;
113        ui.pushButton_realtime->setText("开始实时显示");
114    }
115}
116// ch:获取帧率 | en:Get Frame Rate
117int QtWidgetsApplication1::GetFrameRate()
118{
119    MVCC_FLOATVALUE stFloatValue = { 0 };
120    char temp_info[] = "ResultingFrameRate";
121    int nRet = m_pcMycamera->GetFloatValue(temp_info, &stFloatValue);
122    if (MV_OK != nRet)
123    {
124        return nRet;
125    }
126   // m_dFrameRateEdit = stFloatValue.fCurValue;
127    ui.lineEdit_frame_rate->setText(QString::number(stFloatValue.fCurValue));
128
129    return MV_OK;
130}
131
132// 定时器超时槽函数,用于更新画面
133void QtWidgetsApplication1::updateFrame()
134{
135    // 读取相机中的图像
136    int readInt = m_pcMycamera->ReadBuffer(imageMat);
137    if (readInt != 0) {
138        qDebug() << "读取图像失败";
139        return;
140    }
141
142    // 转换并显示图像
143    image = cvMat2QImage(imageMat);
144    ui.label_image->setPixmap(QPixmap::fromImage(image).scaled(
145        ui.label_image->width(),
146        ui.label_image->height(),
147        Qt::KeepAspectRatio));
148}
149// ch:获取曝光时间 | en:Get Exposure Time
150int QtWidgetsApplication1::GetExposureTime()
151{
152    MVCC_FLOATVALUE stFloatValue = { 0 };
153    char temp_info[] = "ExposureTime";
154    int nRet = m_pcMycamera->GetFloatValue(temp_info, &stFloatValue);
155    if (MV_OK != nRet)
156    {
157        return nRet;
158    }
159
160   ui.lineEdit_expose->setText(QString::number(stFloatValue.fCurValue));
161
162    return MV_OK;
163}
164int QtWidgetsApplication1::GetTriggerMode()
165{
166    MVCC_ENUMVALUE stEnumValue = { 0 };
167    char temp_info[] = "TriggerMode";
168    int nRet = m_pcMycamera->GetEnumValue(temp_info, &stEnumValue);
169    if (MV_OK != nRet)
170    {
171        return nRet;
172    }
173
174    m_nTriggerMode = stEnumValue.nCurValue;
175    if (MV_TRIGGER_MODE_ON == m_nTriggerMode)
176    {
177        //OnBnClickedTriggerModeRadio();
178    }
179    else
180    {
181        m_nTriggerMode = MV_TRIGGER_MODE_OFF;
182        //OnBnClickedContinusModeRadio();
183    }
184
185    return MV_OK;
186}
187// ch:获取增益 | en:Get Gain
188int QtWidgetsApplication1::GetGain()
189{
190    MVCC_FLOATVALUE stFloatValue = { 0 };
191    char temp_info[] = "Gain";
192    int nRet = m_pcMycamera->GetFloatValue(temp_info, &stFloatValue);
193    if (MV_OK != nRet)
194    {
195        return nRet;
196    }
197    ui.lineEdit_gain->setText(QString::number(stFloatValue.fCurValue));
198
199    return MV_OK;
200}
201void QtWidgetsApplication1::GetPara()
202{
203    int nRet = GetTriggerMode();
204    if (nRet != MV_OK)
205    {
206       // ShowErrorMsg(TEXT("Get Trigger Mode Fail"), nRet);
207        ShowMsg("Get Trigger Mode Fail");
208    }
209
210    nRet = GetExposureTime();
211    if (nRet != MV_OK)
212    {
213       // ShowErrorMsg(TEXT("Get Exposure Time Fail"), nRet);
214        ShowMsg("Get Exposure Time Fail");
215    }
216
217    nRet = GetGain();
218    if (nRet != MV_OK)
219    {
220       // ShowErrorMsg(TEXT("Get Gain Fail"), nRet);
221        ShowMsg("Get Gain Fail");
222    }
223
224    nRet = GetFrameRate();
225    if (nRet != MV_OK)
226    {
227       // ShowErrorMsg(TEXT("Get Frame Rate Fail"), nRet);
228        ShowMsg("Get Frame Rate Fail");
229    }
230
231    nRet = GetTriggerSource();
232    if (nRet != MV_OK)
233    {
234       // ShowErrorMsg(TEXT("Get Trigger Source Fail"), nRet);
235        ShowMsg("Get Trigger Source Fail");
236    }
237
238   
239}
240// ch:获取触发源 | en:Get Trigger Source
241int QtWidgetsApplication1::GetTriggerSource()
242{
243    MVCC_ENUMVALUE stEnumValue = { 0 };
244    char temp_info[] = "TriggerSource";
245    int nRet = m_pcMycamera->GetEnumValue(temp_info, &stEnumValue);
246    if (MV_OK != nRet)
247    {
248        return nRet;
249    }
250
251    if ((unsigned int)MV_TRIGGER_SOURCE_SOFTWARE == stEnumValue.nCurValue)
252    {
253        m_bSoftWareTriggerCheck = true;
254    }
255    else
256    {
257        m_bSoftWareTriggerCheck = false;
258    }
259
260    return MV_OK;
261}
262// ch:设置曝光时间 | en:Set Exposure Time
263int QtWidgetsApplication1::SetExposureTime()
264{
265    char temp_info[] = "ExposureAuto";
266    m_pcMycamera->SetEnumValue(temp_info, MV_EXPOSURE_AUTO_MODE_OFF);
267
268    char temp_info2[] = "ExposureTime";
269    return m_pcMycamera->SetFloatValue(temp_info2, ui.lineEdit_expose->text().toFloat());
270}
271// ch:设置增益 | en:Set Gain
272int QtWidgetsApplication1::SetGain()
273{
274    // ch:设置增益前先把自动增益关闭,失败无需返回
275    //en:Set Gain after Auto Gain is turned off, this failure does not need to return
276    char temp_info[] = "GainAuto";
277    m_pcMycamera->SetEnumValue(temp_info, 0);
278    char temp_info2[] = "Gain";
279    return m_pcMycamera->SetFloatValue(temp_info2, ui.lineEdit_gain->text().toFloat());
280}
281
282
283// ch:设置帧率 | en:Set Frame Rate
284int QtWidgetsApplication1::SetFrameRate()
285{
286    char temp_info[] = "AcquisitionFrameRateEnable";
287    int nRet = m_pcMycamera->SetBoolValue(temp_info, true);
288    if (MV_OK != nRet)
289    {
290        return nRet;
291    }
292    char temp_info2[] = "AcquisitionFrameRate";
293    return m_pcMycamera->SetFloatValue(temp_info2, ui.lineEdit_frame_rate->text().toFloat());
294}
295void QtWidgetsApplication1::SetPara()
296{
297    bool bIsSetSucceed = true;
298    int nRet = SetExposureTime();
299    if (nRet != MV_OK)
300    {
301        bIsSetSucceed = false;
302       // ShowErrorMsg(TEXT("Set Exposure Time Fail"), nRet);
303        ShowMsg("Set Exposure Time Fail");
304    }
305    nRet = SetGain();
306    if (nRet != MV_OK)
307    {
308        bIsSetSucceed = false;
309        //ShowErrorMsg(TEXT("Set Gain Fail"), nRet);
310
311        ShowMsg("Set Gain Fail");
312    }
313    nRet = SetFrameRate();
314    if (nRet != MV_OK)
315    {
316        bIsSetSucceed = false;
317        //ShowErrorMsg(TEXT("Set Frame Rate Fail"), nRet);
318        ShowMsg("Set Frame Rate Fail");
319    }
320
321    if (true == bIsSetSucceed)
322    {
323
324       // ShowErrorMsg(TEXT("Set Parameter Succeed"), nRet);
325        ShowMsg("Set Parameter Succeed");
326
327    }
328}
329void QtWidgetsApplication1::ShowMsg(QString msg)
330{
331    QMessageBox::information(this,"title",msg);
332}
333void QtWidgetsApplication1::CloseWindow()
334{
335    if (QMessageBox::question(this, tr("Tips"), tr("退出程序吗?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
336    {
337        on_pushButton_close_clicked();
338        QApplication::exit();
339    }
340    
341}
342
343// 修改单张采集函数,确保在单张采集时使用触发模式
344void QtWidgetsApplication1::on_pushButton_caiji_clicked()
345{
346    // 如果正在实时显示,先停止
347    if (m_bIsGrabbing) {
348        m_timer->stop();
349        m_bIsGrabbing = false;
350        ui.pushButton_realtime->setText("开始实时显示");
351    }
352
353    // 设置为触发模式
354    m_pcMycamera->setTriggerMode(1);
355
356    // 发送软触发
357    int softTrigger = m_pcMycamera->softTrigger();
358    if (softTrigger != 0) {
359        qDebug() << "软触发失败";
360    }
361    else {
362        qDebug() << "成功触发一次";
363    }
364
365    // 读取相机中的图像
366    int readInt = m_pcMycamera->ReadBuffer(imageMat);
367    if (readInt != 0) {
368        qDebug() << "读取图像失败";
369    }
370    image = cvMat2QImage(imageMat);
371    ui.label_image->setPixmap(QPixmap::fromImage(image).scaled(
372        ui.label_image->width(),
373        ui.label_image->height(),
374        Qt::KeepAspectRatio));
375}
376void QtWidgetsApplication1::closeEvent(QCloseEvent* ee)
377{
378    if (QMessageBox::question(this, tr("Tips"), tr("关闭程序吗?"), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes)
379    {
380      //  setWindowState(Qt::WindowMinimized);
381       // emit SigToMainLog("已执行最小化");
382        on_pushButton_close_clicked();
383        
384        ee->accept();
385        
386    }
387    else
388    {
389        ee->ignore();
390        // return;
391       // 
392    }
393}
394//关闭设备
395void QtWidgetsApplication1::on_pushButton_close_clicked()
396{
397    //关闭设备,释放资源
398    int close = m_pcMycamera->closeCamera();
399    if (close != 0) {
400        qDebug() << "相机关闭失败";
401        QMessageBox::information(this,"title","相机关闭失败");
402    }
403    else
404    {
405        QMessageBox::information(this, "title", "相机已经关闭");
406    }
407    TTcamera::FinalizeSDK();
408   
409}
410
411//Mat转QImage函数
412QImage QtWidgetsApplication1::cvMat2QImage(const cv::Mat& mat)
413{
414    // 8-bits unsigned, NO. OF CHANNELS = 1
415    if (mat.type() == CV_8UC1)
416    {
417        QImage qimage(mat.cols, mat.rows, QImage::Format_Indexed8);
418        // Set the color table (used to translate colour indexes to qRgb values)
419        qimage.setColorCount(256);
420        for (int i = 0; i < 256; i++)
421        {
422            qimage.setColor(i, qRgb(i, i, i));
423        }
424        // Copy input Mat
425        uchar* pSrc = mat.data;
426        for (int row = 0; row < mat.rows; row++)
427        {
428            uchar* pDest = qimage.scanLine(row);
429            memcpy(pDest, pSrc, mat.cols);
430            pSrc += mat.step;
431        }
432        return qimage;
433    }
434    // 8-bits unsigned, NO. OF CHANNELS = 3
435    else if (mat.type() == CV_8UC3)
436    {
437        // Copy input Mat
438        const uchar* pSrc = (const uchar*)mat.data;
439        // Create QImage with same dimensions as input Mat
440        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
441        return image.rgbSwapped();
442    }
443    else if (mat.type() == CV_8UC4)
444    {
445        // Copy input Mat
446        const uchar* pSrc = (const uchar*)mat.data;
447        // Create QImage with same dimensions as input Mat
448        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
449        return image.copy();
450    }
451    else
452    {
453        return QImage();
454    }
455}
456
457

QtWidgetsApplication1.ui

1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>QtWidgetsApplication1Class</class>
4 <widget class="QMainWindow" name="QtWidgetsApplication1Class">
5  <property name="geometry">
6   <rect>
7    <x>0</x>
8    <y>0</y>
9    <width>837</width>
10    <height>644</height>
11   </rect>
12  </property>
13  <property name="windowTitle">
14   <string>QtWidgetsApplication1</string>
15  </property>
16  <widget class="QWidget" name="centralWidget">
17   <layout class="QVBoxLayout" name="verticalLayout">
18    <item>
19     <layout class="QHBoxLayout" name="horizontalLayout">
20      <item>
21       <widget class="QGroupBox" name="groupBox">
22        <property name="minimumSize">
23         <size>
24          <width>500</width>
25          <height>500</height>
26         </size>
27        </property>
28        <property name="maximumSize">
29         <size>
30          <width>16777215</width>
31          <height>500</height>
32         </size>
33        </property>
34        <property name="title">
35         <string>显示画面</string>
36        </property>
37        <layout class="QGridLayout" name="gridLayout">
38         <item row="0" column="0">
39          <widget class="QLabel" name="label_image">
40           <property name="styleSheet">
41            <string notr="true">background-color: rgb(0, 0, 0);</string>
42           </property>
43           <property name="frameShadow">
44            <enum>QFrame::Sunken</enum>
45           </property>
46           <property name="text">
47            <string/>
48           </property>
49          </widget>
50         </item>
51        </layout>
52       </widget>
53      </item>
54      <item>
55       <widget class="QGroupBox" name="groupBox_2">
56        <property name="minimumSize">
57         <size>
58          <width>0</width>
59          <height>500</height>
60         </size>
61        </property>
62        <property name="maximumSize">
63         <size>
64          <width>16777215</width>
65          <height>500</height>
66         </size>
67        </property>
68        <property name="title">
69         <string>参数</string>
70        </property>
71        <widget class="QLabel" name="label">
72         <property name="geometry">
73          <rect>
74           <x>20</x>
75           <y>60</y>
76           <width>54</width>
77           <height>12</height>
78          </rect>
79         </property>
80         <property name="text">
81          <string>曝光</string>
82         </property>
83        </widget>
84        <widget class="QLabel" name="label_2">
85         <property name="geometry">
86          <rect>
87           <x>20</x>
88           <y>100</y>
89           <width>54</width>
90           <height>12</height>
91          </rect>
92         </property>
93         <property name="text">
94          <string>增益</string>
95         </property>
96        </widget>
97        <widget class="QLabel" name="label_3">
98         <property name="geometry">
99          <rect>
100           <x>20</x>
101           <y>140</y>
102           <width>54</width>
103           <height>12</height>
104          </rect>
105         </property>
106         <property name="text">
107          <string>帧率</string>
108         </property>
109        </widget>
110        <widget class="QPushButton" name="pushButton_get_para">
111         <property name="geometry">
112          <rect>
113           <x>20</x>
114           <y>180</y>
115           <width>75</width>
116           <height>23</height>
117          </rect>
118         </property>
119         <property name="text">
120          <string>获取</string>
121         </property>
122        </widget>
123        <widget class="QPushButton" name="pushButton_set_para">
124         <property name="geometry">
125          <rect>
126           <x>110</x>
127           <y>180</y>
128           <width>75</width>
129           <height>23</height>
130          </rect>
131         </property>
132         <property name="text">
133          <string>设置</string>
134         </property>
135        </widget>
136        <widget class="QLineEdit" name="lineEdit_expose">
137         <property name="geometry">
138          <rect>
139           <x>80</x>
140           <y>50</y>
141           <width>113</width>
142           <height>20</height>
143          </rect>
144         </property>
145        </widget>
146        <widget class="QLineEdit" name="lineEdit_gain">
147         <property name="geometry">
148          <rect>
149           <x>80</x>
150           <y>90</y>
151           <width>113</width>
152           <height>20</height>
153          </rect>
154         </property>
155        </widget>
156        <widget class="QLineEdit" name="lineEdit_frame_rate">
157         <property name="geometry">
158          <rect>
159           <x>80</x>
160           <y>130</y>
161           <width>113</width>
162           <height>20</height>
163          </rect>
164         </property>
165        </widget>
166       </widget>
167      </item>
168     </layout>
169    </item>
170    <item>
171     <layout class="QGridLayout" name="gridLayout_2">
172      <item row="0" column="0">
173       <widget class="QPushButton" name="on_pushButton_link">
174        <property name="styleSheet">
175         <string notr="true">background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
176stop:0 rgba(204, 250, 227, 255), /*第1个颜色值*/
177stop:0.25 rgba(126, 242, 185, 255), /*第2个颜色值*/
178stop:0.5 rgba(76, 237, 157, 255), /*第3个颜色值*/
179stop:0.65 rgba(91, 239, 166, 255), /*第4个颜色值*/
180stop:1 rgba(184, 248, 217, 255));/*第5个颜色值*/
181border: 2px solid rgb(78,238,158);/*边框颜色值*/
182 border-radius: 10px;
183font: 16pt &quot;Arial&quot;;
184 </string>
185        </property>
186        <property name="text">
187         <string>开始连接</string>
188        </property>
189       </widget>
190      </item>
191      <item row="0" column="1">
192       <widget class="QPushButton" name="pushButton_realtime">
193        <property name="styleSheet">
194         <string notr="true">background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
195stop:0 rgba(199, 238, 249, 255), 
196stop:0.25 rgba(132, 217, 243, 255), 
197stop:0.5 rgba(80, 200, 238, 255), 
198stop:0.65 rgba(87, 203, 239, 255), 
199stop:1 rgba(186, 233, 249, 255));
200 border: 2px solid rgb(106,208,240);
201 border-radius: 10px;
202font: 16pt &quot;Arial&quot;;
203 </string>
204        </property>
205        <property name="text">
206         <string>实时显示</string>
207        </property>
208       </widget>
209      </item>
210      <item row="0" column="2">
211       <widget class="QPushButton" name="on_pushButton_caiji">
212        <property name="styleSheet">
213         <string notr="true">background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
214stop:0 rgba(250, 204, 246, 255), /*第1个颜色值*/
215stop:0.25 rgba(243, 144, 236, 255), /*第2个颜色值*/
216stop:0.5 rgba(238, 81, 223, 255), /*第3个颜色值*/
217stop:0.65 rgba(239, 92, 225, 255), /*第4个颜色值*/
218stop:1 rgba(249, 186, 243, 255));/*第5个颜色值*/
219border: 2px solid rgb(240,102,255);/*边框颜色值*/
220 border-radius: 10px;
221font: 16pt &quot;Arial&quot;;
222</string>
223        </property>
224        <property name="text">
225         <string>图像采集</string>
226        </property>
227       </widget>
228      </item>
229      <item row="0" column="3">
230       <widget class="QPushButton" name="on_pushButton_close">
231        <property name="styleSheet">
232         <string notr="true">background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
233stop:0 rgba(249, 202, 201, 255), /*第1个颜色值*/
234stop:0.25 rgba(242, 126, 126, 255), /*第2个颜色值*/
235stop:0.5 rgba(237, 78, 78, 255), /*第3个颜色值*/
236stop:0.65 rgba(238, 89, 89, 255), /*第4个颜色值*/
237stop:1 rgba(247, 175, 175, 255));/*第5个颜色值*/
238border: 2px solid rgb(237,80,78);/*边框颜色值*/
239 border-radius: 10px;
240 font: 16pt &quot;Arial&quot;;</string>
241        </property>
242        <property name="text">
243         <string>关闭连接</string>
244        </property>
245       </widget>
246      </item>
247      <item row="0" column="4">
248       <widget class="QPushButton" name="pushButton_exit">
249        <property name="styleSheet">
250         <string notr="true">background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
251stop:0 rgba(247, 250, 204, 255), 
252stop:0.25 rgba(236, 243, 133, 255), 
253stop:0.5 rgba(226, 237, 76, 255), 
254stop:0.65 rgba(229, 239, 91, 255), 
255stop:1 rgba(229, 233, 160, 255));
256 border: 2px solid rgb(225,238,78);
257 border-radius: 10px;
258font: 16pt &quot;Arial&quot;;
259</string>
260        </property>
261        <property name="text">
262         <string>退出</string>
263        </property>
264       </widget>
265      </item>
266      <item row="1" column="0">
267       <widget class="QPushButton" name="pushButton_start">
268        <property name="styleSheet">
269         <string notr="true">.QPushButton {
270        background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
271stop:0 rgba(233, 233, 233, 255), 
272stop:0.35 rgba(220, 220, 220, 255), 
273stop:0.5 rgba(213, 213, 213, 255), 
274stop:0.65 rgba(230, 230, 230, 255), 
275stop:1 rgba(242, 242, 242, 255));
276 border: 1px solid rgb(128,126,126);
277 border-radius: 5px;
278font: 16pt &quot;Arial&quot;;
279}
280.QPushButton:hover{
281        background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
282stop:0 rgba(250, 250, 250, 255), 
283stop:0.5 rgba(255, 255, 255, 255), 
284stop:1 rgba(250, 250, 250, 255));
285 border: 1px solid rgb(63,140,161);
286 border-radius: 5px;
287}
288 
289.QPushButton:pressed{
290        background:qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, 
291stop:0 rgba(255, 255, 255, 255), 
292stop:0.5 rgba(235, 247, 253, 255), 
293stop:1 rgba(213, 237, 250, 255));
294 border: 1px solid rgb(3,110,183);
295 border-radius: 5px;
296
297}
298
299 </string>
300        </property>
301        <property name="text">
302         <string>显示消息</string>
303        </property>
304       </widget>
305      </item>
306     </layout>
307    </item>
308   </layout>
309  </widget>
310  <widget class="QMenuBar" name="menuBar">
311   <property name="geometry">
312    <rect>
313     <x>0</x>
314     <y>0</y>
315     <width>837</width>
316     <height>23</height>
317    </rect>
318   </property>
319  </widget>
320  <widget class="QToolBar" name="mainToolBar">
321   <attribute name="toolBarArea">
322    <enum>TopToolBarArea</enum>
323   </attribute>
324   <attribute name="toolBarBreak">
325    <bool>false</bool>
326   </attribute>
327  </widget>
328  <widget class="QStatusBar" name="statusBar"/>
329 </widget>
330 <layoutdefault spacing="6" margin="11"/>
331 <resources>
332  <include location="QtWidgetsApplication1.qrc"/>
333 </resources>
334 <connections/>
335</ui>
336

海康官网下载最新SDK,如:MVS_STD_4.3.2_240529.zip

安装后:项目属性,包含目录:

C:\Program Files (x86)\MVS\Development\Includes

库目录添加:

链接器-》输入:


第4篇 vs2019+QT调用SDK连接海康相机显示图片》 是转载文章,点击查看原文


相关推荐


AI 自动化测试:接口测试全流程自动化的实现方法
Jinkxs2025/10/4

在 AI 技术飞速渗透各行各业的当下,我们早已告别 “谈 AI 色变” 的观望阶段,迈入 “用 AI 提效” 的实战时代 💡。无论是代码编写时的智能辅助 💻、数据处理中的自动化流程 📊,还是行业场景里的精准解决方案 ,AI 正以润物细无声的方式,重构着我们的工作逻辑与行业生态 🌱。曾几何时,我们需要花费数小时查阅文档 📚、反复调试代码 ⚙️,或是在海量数据中手动筛选关键信息 ,而如今,一个智能工具 🧰、一次模型调用 ⚡,就能将这些繁琐工作的效率提升数倍 📈。正是在这样的变革中,AI


基于PyTorch的CIFAR10加载与TensorBoard可视化实践
StarPrayers.2025/10/3

视频学习来源:https://www.bilibili.com/video/BV1hE411t7RN?t=1.1&p=15 import torchvision from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter from test_03 import writer # 添加 添加 download=True 参数来下载数据集 test_data = torchv


什么是 ONNX Runtime?
Cosolar2025/10/2

在人工智能技术飞速发展的今天,模型训练与部署之间的“鸿沟”始终是行业痛点——训练好的模型往往因框架差异、硬件限制等问题难以高效落地。而ONNX Runtime的出现,为这一难题提供了强有力的解决方案。作为微软开源的跨平台推理引擎,ONNX Runtime凭借其跨框架兼容性、全硬件加速能力和极致的性能优化,已成为AI模型部署领域的关键基础设施。本文将深入解析ONNX Runtime的核心价值、技术原理与应用场景,带你领略它如何为AI落地“加速”。 1、什么是ONNX Runtime? ONNX R


关于win11的Microsoft To Pdf打印机修改端口后无法再刷新显示于设备界面的问题
随风万里无云2025/10/2

请记住,有时候死钻牛角尖,反倒是不值得; 从24号到30号,再到今天国庆节第一天才记录,这就是过程,每个过程都结束的时候, 所以,请别焦虑,或许换个思路,就能柳暗花明又一村 (如果你只是需要解决的方法,直接看2.2往后) 1.问题起因: 我需要修改端口实现打印不弹出选择的保存界面,直接存在固定的位置 2.修改完成端口本地端口为固定路径 测试打印没问题,然后离谱的就出现了! 设备界面中再也找不到这个打印机了,但是你打印的时候依旧可以正常打印 我在网上找了很多帖子想要


分布式秒杀系统设计方案
nlog3n10/2/2025

核心组件说明1. 接入层CDN: 静态资源缓存,减少服务器压力Nginx: 负载均衡,请求分发,限流API Gateway: 统一入口,认证,限流,熔断2. 应用层秒杀服务: 核心业务逻辑处理用户服务: 用户认证和信息管理商品服务: 商品信息管理订单服务: 订单处理和管理支付服务: 支付处理3. 中间件层Redis集群: 缓存热点数据,分布式锁RocketMQ: 异步消息处理,削峰填谷Elasticsearch: 日志分析和搜索4. 数据层MySQL主从集群:


2025 年 AI+BI 趋势下,Wyn 商业智能软件如何重构企业决策效率?
葡萄城技术团队9/30/2025

2025年AI+BI趋势下,Wyn商业智能软件通过&quot;嵌入式架构+AI原生能力&quot;重构企业决策效率。Gartner预测,60%的企业将依赖自然语言交互完成数据分析。Wyn具备三大核心优势:1)零门槛AI对话分析,业务人员可自然语言提问获取分析结果;2)国产化与灵活部署,适配统信UOS等国产系统;3)嵌入式全域集成,可融入MES、OA等业务系统。典型案例显示,Wyn帮助制造企业减少40%设备停机时间,医药企业提升70%决策响应速度。选型考量聚焦可信性、易用性、集成性和国产化。


【征文计划】基于Rokid CXR-M SDK 打造AI 实时会议助手:从连接到自定义界面的完整实践
_摘星_2025/10/6

【征文计划】基于Rokid CXR-M SDK 打造AI 实时会议助手:从连接到自定义界面的完整实践 > **摘要**:本文基于 Rokid CXR-M SDK,详细阐述如何构建一个面向商务会议场景的“AI 实时会议助手”应用。通过手机端与 Rokid 智能眼镜的协同,实现语音转写、要点提炼、提词引导、多语翻译与会后纪要自动生成。文章涵盖从环境配置、蓝牙/Wi-Fi 连接、设备控制、AI 场景交互到自定义 UI 渲染的完整开发流程,并提供关键代码示例与最佳实践建议。 > > ![](https:


CICD工具选型指南,Jenkins vs Arbess哪一款更好用?
高效研发之旅2025/10/8

Jenkins是一款常用的CICD工具,Arbess作为一款新兴的国产开源免费的CICD工具,两款工具各有特点。本文将从安装配置、功能特性、用户体验等几个方面对两款软件进行详细对比。 1、安装配置 项目 Jenkins Arbess 安装难度需要预装Java环境,需要手动配置端口和后台服务。一键安装,私有部署不同环境均支持傻瓜式一键安装。配置难度需要配置国内镜像源,安装核心插件零配置,安装后即刻可用,无需额外配置。支持操作系统支持Windows、ma


深入解析 Vue 3 源码:computed 的底层实现原理
excel2025/10/9

在 Vue 3 的响应式系统中,computed 是一个非常重要的功能,它用于创建基于依赖自动更新的计算属性。本文将通过分析源码,理解 computed 的底层实现逻辑,帮助你从源码层面掌握它的原理。 一、computed 的基本使用 在使用层面上,computed 有两种常见用法: 1. 只读计算属性 const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value)


先用js快速开发,后续引入ts是否是一个好的实践?
你的人类朋友2025/10/11

前言 我在业余时间做一些小项目时,每次进行技术选型,都会有一个疑问: 应该直接使用 TypeScript 开发,还是先用 JavaScript 快速启动,后续再引入 TypeScript? 今天干脆来整理一下思路,方便后续复用这些想法 正文 一、快速开发的优势 先用 JavaScript 进行快速开发确实有其明显优势: 开发速度更快 无需类型定义和接口声明 跳过类型检查的编译步骤 ⭐ 【重要】特别适合【原型开发】和【概念验证】,个人认为这个是最重要的 学习成本低 更容易上手 ⭐ 【重要】减

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0