Mix|使用VS2017CMake构建Qt工程 仿照MVS(仅用于学习)

MVS下载链接:https://www.hikrobotics.com/cn/machinevision/service/download/?module=0
CMake工程构建参考:CMake|VS2017+CMake3.8搭建Qt项目

文章目录

  • 效果图
  • 整体结构
  • 实现代码
    • 最外层CMakeLists.txt
    • 代码实现及CMakeLists.txt搭建
      • CMakeLists.txt搭建
      • 主函数
      • MainWindow
      • DeviceListDockWidget
        • Struct.h
      • ImageShowDockWidget
        • OneImageWindow
      • AttributeListDockWidget

效果图

只用Qt实现了显示效果,并没有实现具体功能,仅供学习使用,如有侵权请私信我删除。
在这里插入图片描述

整体结构

在这里插入图片描述

实现代码

最外层CMakeLists.txt

# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required (VERSION 3.8)project ("MVSImitateCMake")# Include sub-projects.
add_subdirectory ("MVSImitateCMake")

代码实现及CMakeLists.txt搭建

CMakeLists.txt搭建

# CMakeList.txt : CMake project for MVSImitateCMake, include source and define
# project specific logic here.
#
cmake_minimum_required (VERSION 3.8)# 设置C++标准 C++17
set(CMAKE_CXX_STANDARD 17)# 自动把ui转化为C++代码
# uic qtcmake.ui > ui_qtcmake.h
set(CMAKE_AUTOUIC ON)# 自动生成元对象的C++代码
set(CMAKE_AUTOMOC ON)# 自动生成资源文件
set(CMAKE_AUTORCC ON)# --- 执行文件输出路径
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)set(INCLUDE_DIR ./include)
set(SRC_DIR ./src)include_directories(${INCLUDE_DIR})
file(GLOB_RECURSE HEADER "${INCLUDE_DIR}/*.h")
file(GLOB_RECURSE SOURCES "${SRC_DIR}/*.cpp")# Add source to this project's executable.
add_executable (MVSImitateCMake MVSImitateCMake.cpp ${HEADER} ${SOURCES})# TODO: Add tests and install targets if needed.
# find_package 查找内部库
# 导入qt的库
# cmake通过qt5提供的查找方案,去查找对应的库
# 这里以查找 Widgets库 为例
find_package(Qt5 COMPONENTS Widgets REQUIRED)# 根据自己电脑的环境,写死的指定Qt5_DIR这个变量
# 目的是寻找 Qt5Config.cmake 这个文件
set(Qt5_DIR C:/Qt/Qt5.14.2/5.14.2/msvc2017_64/lib/cmake/Qt5)# 指定qt依赖的动态库
# Qt5 自带连接头文件
target_link_libraries(${PROJECT_NAME}Qt5::Widgets
)

主函数

头文件

// MVSImitateCMake.h : Include file for standard system include files,
// or project specific include files.#pragma once#include <iostream>
#include <QtWidgets>
#include <QApplication>#include "MainWindow.h"// TODO: Reference additional headers your program requires here.

源文件

// MVSImitateCMake.cpp : Defines the entry point for the application.
//#include "MVSImitateCMake.h"using namespace std;int main(int argc, char *argv[])
{QApplication a(argc, argv);MainWindow main_window;main_window.show();return a.exec();
}

从主函数引用顺序来展示各个类的代码

MainWindow

搭建整体UI架构,创建DeviceListDockWidget类、ImageShowDockWidget类、AttributeListDockWidget类,分别为设备列表、图像显示区域、属性窗口区域。
头文件

#pragma once
#include <qmainwindow.h>
#include <QSplitter>
#include "DeviceList.h"
#include "ImageShow.h"
#include "AttributeList.h"class MainWindow :public QMainWindow
{Q_OBJECT
public:MainWindow();~MainWindow();private:void Init();DeviceListDockWidget* device_list_;ImageShowDockWidget* image_show_;AttributeListDockWidget* attribute_list_;
};

源文件

#include "MainWindow.h"
#include<QMenuBar>
#include<QToolBar>
#include <QLabel>
#include <QStatusBar>
#include <QHBoxLayout>MainWindow::MainWindow()
{Init();
}MainWindow::~MainWindow()
{
}void MainWindow::Init()
{resize(1700, 950);QSplitter* main_widget = new QSplitter(this);this->setCentralWidget(main_widget);//包含菜单栏,只能有一个QMenuBar * bar = menuBar();//将菜单栏放入到窗口中this->setMenuBar(bar);//创建文件菜单QMenu * dockWidgetMenu = bar->addMenu(QStringLiteral("窗口"));//QMenu * editMenu = bar->addMenu(QStringLiteral("编辑"));//添加菜单项QAction * deviceAction = dockWidgetMenu->addAction(QStringLiteral("设备列表"));deviceAction->setCheckable(true);//添加分割线//dockWidgetMenu->addSeparator();QAction * ImageAction = dockWidgetMenu->addAction(QStringLiteral("图像显示"));ImageAction->setCheckable(true);//添加分割线//dockWidgetMenu->addSeparator();QAction * AttributeAction = dockWidgetMenu->addAction(QStringLiteral("属性信息"));AttributeAction->setCheckable(true);//工具栏,可以有多个QToolBar * toolBar = new QToolBar(this);addToolBar(Qt::TopToolBarArea, toolBar);//默认停靠范围//只允许左右侧停靠//toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);//设置浮动toolBar->setFloatable(false);//设置移动(总开关)toolBar->setMovable(false);//工具栏添加菜单项toolBar->addAction(deviceAction);//添加分割线toolBar->addSeparator();toolBar->addAction(ImageAction);toolBar->addSeparator();toolBar->addAction(AttributeAction);//状态栏,只能有一个//QStatusBar * stBar = statusBar();//setStatusBar(stBar);//QLabel * label = new QLabel(QStringLiteral("提示信息"), this);//stBar->addWidget(label);//添加提示信息到左侧//QLabel * label2 = new QLabel(QStringLiteral("右侧提示信息"), this);//stBar->addPermanentWidget(label2);device_list_ = new DeviceListDockWidget;QHBoxLayout* main_layout = new QHBoxLayout;main_layout->addWidget(device_list_,1);image_show_ = new ImageShowDockWidget;main_layout->addWidget(image_show_,5);attribute_list_ = new AttributeListDockWidget;main_layout->addWidget(attribute_list_, 2);main_widget->setLayout(main_layout);// 设备列表显隐connect(deviceAction, &QAction::toggled, device_list_, [=](bool state) {device_list_->setHidden(!state);});connect(device_list_, &QDockWidget::visibilityChanged, deviceAction, &QAction::setChecked);// 图像显示区域显隐connect(ImageAction, &QAction::toggled, image_show_, [=](bool state) {image_show_->setHidden(!state);});connect(image_show_, &QDockWidget::visibilityChanged, ImageAction, &QAction::setChecked);;// 属性列表显隐connect(AttributeAction, &QAction::toggled, attribute_list_, [=](bool state) {attribute_list_->setHidden(!state);});connect(attribute_list_, &QDockWidget::visibilityChanged, AttributeAction, &QAction::setChecked);
}

DeviceListDockWidget

设备列表类继承QDockWidget类
头文件

#pragma once
#include <QApplication>
#include <QClipboard>
#include <QDockWidget>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QVBoxLayout>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QToolBar>
#include <QLabel>
#include <QStatusBar>
#include <QLabel>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QSplitter>
#include <QHeaderView>
#include <Struct.h>class DeviceListDockWidget :public QDockWidget
{Q_OBJECT
public:DeviceListDockWidget();~DeviceListDockWidget();private:void Init();void InitSlot();void InitDeviceInfoTable();void AddGigECameraTreeItem(QString _camera_name);void AddUSBCameraTreeItem(QString _camera_name);void RefreshDeviceInfoTable(QString _camera_name,DeviceInfo _device_info);void RefreshGigEInfo(GigEDeviceInfo _gige_info);void RefreshUSBInfo(USBDeviceInfo _usb_info);DeviceInfo GetDeviceInfo(QString _camera_name);private slots:void SlotClickedDeviceList(QTreeWidgetItem* _item);void SlotShowMenuPos(const QPoint &pos);void SlotMenu(QAction* _action);private://QMap<QString, DeviceInfo> all_device;QVBoxLayout* main_layout;QTreeWidget *device_list;QTreeWidgetItem* GigE_root;QTreeWidgetItem* USB_root;QTableWidget* device_info_table;QMenu* copy_menu;QAction* copy_select;QAction* copy_all;
};

源文件

#include "DeviceList.h"DeviceListDockWidget::DeviceListDockWidget()
{Init();InitSlot();
}DeviceListDockWidget::~DeviceListDockWidget()
{
}void DeviceListDockWidget::Init()
{//QWidget * main_widget = new QWidget;QSplitter * main_widget = new QSplitter(Qt::Vertical, nullptr);main_layout = new QVBoxLayout;main_widget->setLayout(main_layout);device_list = new QTreeWidget();device_list->resize(350, 700);device_list->setHeaderLabel(QStringLiteral("设备列表"));GigE_root = new QTreeWidgetItem(device_list);GigE_root->setText(0, "GigE");device_list->addTopLevelItem(GigE_root);AddGigECameraTreeItem("GigECamera1");AddGigECameraTreeItem("GigECamera2");USB_root = new QTreeWidgetItem(device_list);USB_root->setText(0, "USB");device_list->addTopLevelItem(USB_root);device_list->expandAll();main_layout->addWidget(device_list);AddUSBCameraTreeItem("USBCamera1");AddUSBCameraTreeItem("USBCamera2");InitDeviceInfoTable();this->setWidget(main_widget);}void DeviceListDockWidget::InitSlot()
{// 切换设备信息connect(device_list, &QTreeWidget::itemClicked, this, &DeviceListDockWidget::SlotClickedDeviceList);// 右键设备信息显示菜单复制connect(device_info_table, &QTableWidget::customContextMenuRequested, this, &DeviceListDockWidget::SlotShowMenuPos);// 将内容复制到剪切板connect(copy_menu, &QMenu::triggered, this, &DeviceListDockWidget::SlotMenu);
}void DeviceListDockWidget::InitDeviceInfoTable()
{//QVBoxLayout* table_layout = new QVBoxLayout;device_info_table = new QTableWidget(2, 2);// 设置水平滚动条策略为按需显示device_info_table->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);// 获取水平表头QHeaderView *hHeaderView = device_info_table->horizontalHeader();// 设置列的调整模式为根据内容自动调整大小hHeaderView->setSectionResizeMode(QHeaderView::Stretch);device_info_table->verticalHeader()->setVisible(false);device_info_table->horizontalHeader()->setVisible(false);// 起始行 起始列 合并的行数 合并的列数device_info_table->setSpan(0, 0, 1, 2);device_info_table->setSpan(1, 0, 1, 2);device_info_table->setEditTriggers(QAbstractItemView::NoEditTriggers);QTableWidgetItem *item1 = new QTableWidgetItem(QStringLiteral("设备信息"));item1->setTextAlignment(Qt::AlignCenter);device_info_table->setItem(0, 0, item1);QTableWidgetItem *item2 = new QTableWidgetItem(QStringLiteral("暂无设备信息"));item2->setTextAlignment(Qt::AlignCenter);device_info_table->setItem(1, 0, item2);// 设置列宽device_info_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);device_info_table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Interactive);//device_info_table->setColumnWidth(0, 75);// 设置菜单栏右键复制device_info_table->setContextMenuPolicy(Qt::CustomContextMenu);copy_menu = new QMenu(device_info_table);copy_select = new QAction(copy_menu);copy_select->setText(QStringLiteral("复制"));copy_menu->addAction(copy_select);copy_all = new QAction(copy_menu);copy_all->setText(QStringLiteral("复制全部"));copy_menu->addAction(copy_all);//table_layout->addWidget(device_info_table);main_layout->addWidget(device_info_table);}void DeviceListDockWidget::AddGigECameraTreeItem(QString _camera_name)
{QTreeWidgetItem* GigE_camera = new QTreeWidgetItem(GigE_root);GigE_camera->setText(0, _camera_name);GigE_root->addChild(GigE_camera);
}void DeviceListDockWidget::AddUSBCameraTreeItem(QString _camera_name)
{QTreeWidgetItem* usb_camera = new QTreeWidgetItem(USB_root);usb_camera->setText(0, _camera_name);USB_root->addChild(usb_camera);
}void DeviceListDockWidget::RefreshDeviceInfoTable(QString _camera_name, DeviceInfo _device_info)
{// 删除第一行外所有内容for (int i = device_info_table->rowCount() - 1; i >= 1; --i){device_info_table->removeRow(i);}if (_camera_name == "GigECamera1" || _camera_name == "GigECamera2"){RefreshGigEInfo(_device_info.gige_info);}else if (_camera_name == "USBCamera1" || _camera_name == "USBCamera2"){RefreshUSBInfo(_device_info.usb_info);}else{int rowCount = device_info_table->rowCount();device_info_table->insertRow(rowCount);QTableWidgetItem *item2 = new QTableWidgetItem(QStringLiteral("暂无设备信息"));item2->setTextAlignment(Qt::AlignCenter);device_info_table->setItem(1, 0, item2);device_info_table->setSpan(1, 0, 1, 2);}
}void DeviceListDockWidget::RefreshGigEInfo(GigEDeviceInfo _gige_info)
{int rowCount = device_info_table->rowCount();QStringList gige_info_list;gige_info_list << QStringLiteral("设备名称")<< QStringLiteral("物理地址")<< QStringLiteral("IP地址")<< QStringLiteral("子网掩码")<< QStringLiteral("网关")<< QStringLiteral("厂商")<< QStringLiteral("型号")<< QStringLiteral("序列号")<< QStringLiteral("设备版本")<< QStringLiteral("占用者IP");QStringList gige_info_list2;gige_info_list2 << _gige_info.device_name << _gige_info.physical_address << _gige_info.ip_address<< _gige_info.net_mask << _gige_info.gateway << _gige_info.manufacturer<< _gige_info.device_model << _gige_info.serial_num << _gige_info.device_version<< _gige_info.occupant_ip;for (int i=0;i<gige_info_list.size();++i){device_info_table->insertRow(rowCount + i);device_info_table->setItem(rowCount + i, 0, new QTableWidgetItem(gige_info_list.at(i)));device_info_table->setItem(rowCount + i, 1, new QTableWidgetItem(gige_info_list2.at(i)));}//device_info_table->resizeColumnsToContents();
}void DeviceListDockWidget::RefreshUSBInfo(USBDeviceInfo _usb_info)
{int rowCount = device_info_table->rowCount();QStringList usb_info_list;usb_info_list << QStringLiteral("设备名称") << QStringLiteral("型号") << QStringLiteral("序列号")<< QStringLiteral("GUID") << QStringLiteral("厂商") << QStringLiteral("设备版本");QStringList usb_info_list2;usb_info_list2 << _usb_info.device_name<< _usb_info.device_model<< _usb_info.serial_num<< _usb_info.usb_guid<< _usb_info.manufacturer<< _usb_info.device_version;for (int i = 0; i < usb_info_list.size(); ++i){device_info_table->insertRow(rowCount + i);device_info_table->setItem(rowCount + i, 0, new QTableWidgetItem(usb_info_list.at(i)));device_info_table->setItem(rowCount + i, 1, new QTableWidgetItem(usb_info_list2.at(i)));}//device_info_table->resizeColumnsToContents();
}DeviceInfo DeviceListDockWidget::GetDeviceInfo(QString _camera_name)
{DeviceInfo device_info;if ("GigECamera1" == _camera_name || "GigECamera2" == _camera_name){if ("GigECamera1" == _camera_name)device_info.gige_info.device_name = "GigECamera1";else if ("GigECamera2" == _camera_name)device_info.gige_info.device_name = "GigECamera2";device_info.gige_info.physical_address = "ff:ff:ff:ff:ff:ff"; device_info.gige_info.ip_address = "10.1.1.111";device_info.gige_info.net_mask = "255.255.0.0";device_info.gige_info.gateway = "0.0.0.0";device_info.gige_info.manufacturer = "--------------";device_info.gige_info.device_model = "-------------";device_info.gige_info.serial_num = "-------";device_info.gige_info.device_version = "-------";device_info.gige_info.occupant_ip = "0.0.0.0";}else if ("USBCamera1" == _camera_name || "USBCamera2" == _camera_name){if ("USBCamera1" == _camera_name)device_info.usb_info.device_name = "USBCamera1";else if ("USBCamera2" == _camera_name)device_info.usb_info.device_name = "USBCamera2";device_info.usb_info.device_model = "-----";device_info.usb_info.serial_num = "-----";device_info.usb_info.usb_guid = "-----";device_info.usb_info.manufacturer = "U3V";device_info.usb_info.device_version = "-----";}return device_info;
}void DeviceListDockWidget::SlotClickedDeviceList(QTreeWidgetItem* _item)
{QString item_name = _item->text(0);RefreshDeviceInfoTable(item_name,GetDeviceInfo(item_name));
}void DeviceListDockWidget::SlotShowMenuPos(const QPoint &pos)
{QTableWidgetItem* item = device_info_table->itemAt(pos);if (item != nullptr) {if (item->column() == 1){copy_menu->exec(QCursor::pos());}}
}void DeviceListDockWidget::SlotMenu(QAction* _action)
{if (_action == copy_select){QStringList select_strs;QList<QTableWidgetItem *> select_items = device_info_table->selectedItems();for (auto item:select_items){select_strs.append(item->text());}QString select_str = select_strs.join('\n');// 将数据放入剪切板QApplication::clipboard()->setText(select_str);}else if (_action == copy_all){QStringList select_strs;for (int i=1;i<device_info_table->rowCount();++i){auto item = device_info_table->item(i, 1);select_strs.append(item->text());}QString select_str = select_strs.join('\n');// 将数据放入剪切板QApplication::clipboard()->setText(select_str);}
}
Struct.h

设备列表显示信息结构体构建

#pragma oncestruct GigEDeviceInfo
{QString device_name;		// 设备名称QString physical_address;	// 物理地址QString ip_address;			// IP地址QString net_mask;			// 子网掩码QString gateway;			// 网关QString manufacturer;		// 厂商QString device_model;		// 型号QString serial_num;			// 序列号QString device_version;		// 设备版本QString occupant_ip;		// 占用者IPGigEDeviceInfo(){device_name = "";physical_address = "";ip_address = "";net_mask = "";gateway = "";manufacturer = "";device_model = "";serial_num = "";device_version = "";occupant_ip = "";}
};struct USBDeviceInfo
{QString device_name;		// 设备名称QString device_model;		// 型号QString serial_num;			// 序列号QString usb_guid;			// GUIDQString manufacturer;		// 厂商QString device_version;		// 设备版本USBDeviceInfo(){device_name = "";device_model = "";serial_num = "";usb_guid = "";manufacturer = "";device_version = "";}
};struct DeviceInfo
{GigEDeviceInfo gige_info;USBDeviceInfo usb_info;
};

ImageShowDockWidget

图像显示区域,继承QDockWidget,包含子类OneImageWindow,用于多窗口显示,单窗口子类。
头文件

#pragma once
#include <QDockWidget>
#include <QGridLayout>
#include <qDebug>
#include "OneImageWindow.h"class ImageShowDockWidget : public QDockWidget
{Q_OBJECT
public:ImageShowDockWidget();~ImageShowDockWidget();private:void InitUI();private slots:void btnClicked(const QString &objName);private:QVector<OneImageWindow*> all_imagewindow_map;QGridLayout* main_layout;QWidget* main_widget;
};

源文件

#include "ImageShow.h"ImageShowDockWidget::ImageShowDockWidget()
{InitUI();
}ImageShowDockWidget::~ImageShowDockWidget()
{
}void ImageShowDockWidget::InitUI(){main_widget = new QWidget();main_layout = new QGridLayout();for (int i=0;i<4;++i){OneImageWindow* image_window = new OneImageWindow;image_window->setFlowEnable(true);connect(image_window, SIGNAL(btnClicked(QString)), this, SLOT(btnClicked(QString)));all_imagewindow_map.push_back(image_window);}main_layout->addWidget(all_imagewindow_map.at(0), 0, 0, 1, 1);main_layout->addWidget(all_imagewindow_map.at(1), 0, 1, 1, 1);main_layout->addWidget(all_imagewindow_map.at(2), 1, 0, 1, 1);main_layout->addWidget(all_imagewindow_map.at(3), 1, 1, 1, 1);main_widget->setLayout(main_layout);this->setWidget(main_widget);}void ImageShowDockWidget::btnClicked(const QString &objName){OneImageWindow *videoWindow = (OneImageWindow *)sender();QString str = QString("当前单击了控件 %1 的按钮 %2").arg(videoWindow->objectName()).arg(objName);//ui->label->setText(str);qDebug() << str;}
OneImageWindow

单窗口显示图像子类继承QWidget
头文件

#pragma once
#include <QWidget>
#include <QImage>
#include <QColor>
#include <QHBoxLayout>
#include <QFont>
#include <QFontDatabase>
#include <QPushButton>
#include <qDebug>
#include <QDropEvent>
#include <QDragEnterEvent>
#include <QPainter>class OneImageWindow : public QWidget
{Q_OBJECTpublic:explicit OneImageWindow(QWidget *parent = 0);~OneImageWindow();signals://工具栏单击void btnClicked(const QString &objName);public:QImage getImage()               const;public slots://设置是否启用悬浮条void setFlowEnable(bool flowEnable);protected:void resizeEvent(QResizeEvent *);void enterEvent(QEvent *);void leaveEvent(QEvent *);void dropEvent(QDropEvent *event);void dragEnterEvent(QDragEnterEvent *event);void paintEvent(QPaintEvent *);void drawBorder(QPainter *painter);void drawBg(QPainter *painter);void drawImg(QPainter *painter, QImage img);
private://初始化悬浮条void initFlowPanel();//初始化悬浮条样式void initFlowStyle();
private slots://处理按钮单击void btnClicked();private:QImage image;                   //要显示的图片QWidget *flowPanel;             //悬浮条面板bool copyImage;                 //是否拷贝图片bool drawImage;                 //是否绘制图片bool fillImage;                 //自动拉伸填充bool flowEnable;                //是否显示悬浮条QColor flowBgColor;             //悬浮条背景颜色QColor flowPressColor;          //悬浮条按下颜色int borderWidth;                //边框宽度QColor borderColor;             //边框颜色QColor focusColor;              //有焦点边框颜色QColor bgColor;                 //背景颜色QString bgText;                 //默认无图像显示文字QImage bgImage;                 //默认无图像背景图片
};

源文件

#include "OneImageWindow.h"OneImageWindow::OneImageWindow(QWidget *parent) : QWidget(parent)
{//设置强焦点setFocusPolicy(Qt::StrongFocus);//设置支持拖放setAcceptDrops(true);image = QImage();copyImage = false;drawImage = true;fillImage = true;flowEnable = false;flowBgColor = "#000000";flowPressColor = "#5EC7D9";borderWidth = 5;borderColor = "#000000";focusColor = "#22A3A9";bgColor = Qt::transparent;bgText = QStringLiteral("实时图像");bgImage = QImage();//初始化悬浮条this->initFlowPanel();//初始化悬浮条样式this->initFlowStyle();
}
OneImageWindow::~OneImageWindow()
{
}void OneImageWindow::setFlowEnable(bool flowEnable)
{this->flowEnable = flowEnable;
}void OneImageWindow::resizeEvent(QResizeEvent *)
{//重新设置顶部工具栏的位置和宽高,可以自行设置顶部显示或者底部显示int height = 20;flowPanel->setGeometry(borderWidth, borderWidth, this->width() - (borderWidth * 2), height);//flowPanel->setGeometry(borderWidth, this->height() - height - borderWidth, this->width() - (borderWidth * 2), height);
}void OneImageWindow::enterEvent(QEvent *)
{//这里还可以增加一个判断,是否获取了焦点的才需要显示//if (this->hasFocus()) {}if (flowEnable) {flowPanel->setVisible(true);}
}void OneImageWindow::leaveEvent(QEvent *)
{if (flowEnable) {flowPanel->setVisible(false);}
}void OneImageWindow::dropEvent(QDropEvent *event)
{//拖放完毕鼠标松开的时候执行
}void OneImageWindow::dragEnterEvent(QDragEnterEvent *event)
{//拖曳进来的时候先判断下类型,非法类型则不处理}void OneImageWindow::paintEvent(QPaintEvent *)
{//如果不需要绘制if (!drawImage) {return;}//qDebug() << TIMEMS << "paintEvent" << objectName();QPainter painter(this);painter.setRenderHints(QPainter::Antialiasing);//绘制边框drawBorder(&painter);if (!image.isNull()) {//绘制背景图片drawImg(&painter, image);}else {//绘制背景drawBg(&painter);}
}void OneImageWindow::drawBorder(QPainter *painter)
{painter->save();QPen pen;pen.setWidth(borderWidth);pen.setColor(hasFocus() ? focusColor : borderColor);//边框宽度=0则不绘制边框painter->setPen(borderWidth == 0 ? Qt::NoPen : pen);//顺带把背景颜色这里也一并处理if (bgColor != Qt::transparent) {painter->setBrush(bgColor);}painter->drawRect(rect());painter->restore();
}void OneImageWindow::drawBg(QPainter *painter)
{painter->save();//背景图片为空则绘制文字,否则绘制背景图片if (bgImage.isNull()) {painter->setFont(this->font());painter->setPen(palette().windowText().color());painter->drawText(rect(), Qt::AlignCenter, bgText);}else {//居中绘制int x = rect().center().x() - bgImage.width() / 2;int y = rect().center().y() - bgImage.height() / 2;QPoint point(x, y);painter->drawImage(point, bgImage);}painter->restore();
}void OneImageWindow::drawImg(QPainter *painter, QImage img)
{painter->save();int offset = borderWidth * 1 + 0;if (fillImage) {QRect rect(offset / 2, offset / 2, width() - offset, height() - offset);painter->drawImage(rect, img);}else {//按照比例自动居中绘制img = img.scaled(width() - offset, height() - offset, Qt::KeepAspectRatio);int x = rect().center().x() - img.width() / 2;int y = rect().center().y() - img.height() / 2;QPoint point(x, y);painter->drawImage(point, img);}painter->restore();
}void OneImageWindow::initFlowPanel()
{//顶部工具栏,默认隐藏,鼠标移入显示移除隐藏flowPanel = new QWidget(this);flowPanel->setObjectName("flowPanel");flowPanel->setVisible(false);//用布局顶住,左侧弹簧QHBoxLayout *layout = new QHBoxLayout;layout->setSpacing(2);layout->setContentsMargins(0, 0, 0, 0);layout->addStretch();flowPanel->setLayout(layout);//按钮集合名称,如果需要新增按钮则在这里增加即可QList<QString> btns;btns << "btnFlowVideo" << "btnFlowSnap" << "btnFlowSound" << "btnFlowAlarm" << "btnFlowClose";//有多种办法来设置图片,qt内置的图标+自定义的图标+图形字体//既可以设置图标形式,也可以直接图形字体设置文本
#if 0QList<QIcon> icons;icons << QApplication::style()->standardIcon(QStyle::SP_ComputerIcon);icons << QApplication::style()->standardIcon(QStyle::SP_FileIcon);icons << QApplication::style()->standardIcon(QStyle::SP_DirIcon);icons << QApplication::style()->standardIcon(QStyle::SP_DialogOkButton);icons << QApplication::style()->standardIcon(QStyle::SP_DialogCancelButton);
#elseQList<int> icons;icons << 0xe68d << 0xe672 << 0xe674 << 0xea36 << 0xe74c;//判断图形字体是否存在,不存在则加入QFont iconFont;QFontDatabase fontDb;if (!fontDb.families().contains("iconfont")) {int fontId = fontDb.addApplicationFont(":/font/iconfont.ttf");QStringList fontName = fontDb.applicationFontFamilies(fontId);if (fontName.count() == 0) {qDebug() << "load iconfont.ttf error";}}if (fontDb.families().contains("iconfont")) {iconFont = QFont("iconfont");iconFont.setPixelSize(17);
#if (QT_VERSION >= QT_VERSION_CHECK(4,8,0))iconFont.setHintingPreference(QFont::PreferNoHinting);
#endif}
#endif//循环添加顶部按钮for (int i = 0; i < btns.count(); ++i) {QPushButton *btn = new QPushButton;//绑定按钮单击事件,用来发出信号通知connect(btn, SIGNAL(clicked(bool)), this, SLOT(btnClicked()));//设置标识,用来区别按钮btn->setObjectName(btns.at(i));//设置固定宽度btn->setFixedWidth(20);//设置拉伸策略使得填充btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);//设置焦点策略为无焦点,避免单击后焦点跑到按钮上btn->setFocusPolicy(Qt::NoFocus);#if 0//设置图标大小和图标btn->setIconSize(QSize(16, 16));btn->setIcon(icons.at(i));
#elsebtn->setFont(iconFont);//btn->setText((QChar)icons.at(i));btn->setText(btns.at(i));
#endif//将按钮加到布局中layout->addWidget(btn);}
}void OneImageWindow::initFlowStyle()
{//设置样式以便区分,可以自行更改样式,也可以不用样式QStringList qss;QString rgba = QString("rgba(%1,%2,%3,150)").arg(flowBgColor.red()).arg(flowBgColor.green()).arg(flowBgColor.blue());qss.append(QString("#flowPanel{background:%1;border:none;}").arg(rgba));qss.append(QString("QPushButton{border:none;padding:0px;background:rgba(0,0,0,0);}"));qss.append(QString("QPushButton:pressed{color:%1;}").arg(flowPressColor.name()));
}void OneImageWindow::btnClicked()
{QPushButton *btn = (QPushButton *)sender();Q_EMIT btnClicked(btn->objectName());
}QImage OneImageWindow::getImage() const
{return this->image;
}

AttributeListDockWidget

设备属性窗口
头文件

#pragma once
#include <QApplication>
#include <QClipboard>
#include <QDockWidget>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMenu>
#include <QMenuBar>
#include <QAction>
#include <QToolBar>
#include <QLabel>
#include <QTableWidget>
#include <QLineEdit>
#include <QTableWidgetItem>
#include <QSplitter>
#include <QHeaderView>
#include <QTextBrowser>class AttributeListDockWidget :public QDockWidget
{Q_OBJECT
public:AttributeListDockWidget();~AttributeListDockWidget();private:void Init();void InitSlot();void InitRootTree();private slots:private:QTreeWidget* root_tree;QTreeWidget* child_tree;QLineEdit* retrieval_lineEdit;QTextBrowser* retrieval_text;QTreeWidgetItem* feature_node;	// 属性树节点QTreeWidgetItem* common_features_node;	// 常用属性节点QTreeWidgetItem* trigger_node;	// 触发QTreeWidgetItem* advanced_features_node;	// 高级属性
};

源文件

#include "AttributeList.h"AttributeListDockWidget::AttributeListDockWidget()
{Init();InitSlot();
}AttributeListDockWidget::~AttributeListDockWidget()
{
}void AttributeListDockWidget::Init()
{QWidget* main_widget = new QWidget();this->setWidget(main_widget);QHBoxLayout* main_layout = new QHBoxLayout();main_widget->setLayout(main_layout);QVBoxLayout* root_list = new QVBoxLayout();QHBoxLayout* retrieval_layout = new QHBoxLayout();QLabel* retrieval_label = new QLabel(QStringLiteral("检索:"));retrieval_layout->addWidget(retrieval_label);retrieval_lineEdit = new QLineEdit();retrieval_layout->addWidget(retrieval_lineEdit);root_list->addLayout(retrieval_layout);InitRootTree();root_list->addWidget(root_tree);main_layout->addLayout(root_list);QSplitter* retrieval_splitter = new QSplitter(Qt::Vertical, nullptr);child_tree = new QTreeWidget();child_tree->setHeaderHidden(true);retrieval_splitter->addWidget(child_tree);retrieval_text = new QTextBrowser();retrieval_splitter->addWidget(retrieval_text);main_layout->addWidget(retrieval_splitter);
}void AttributeListDockWidget::InitSlot()
{}void AttributeListDockWidget::InitRootTree()
{root_tree = new QTreeWidget();root_tree->resize(350, 700);root_tree->setHeaderHidden(true);feature_node = new QTreeWidgetItem(root_tree);feature_node->setText(0, "Feature Tree");root_tree->addTopLevelItem(feature_node);common_features_node = new QTreeWidgetItem(root_tree);common_features_node->setText(0, "Common Features");root_tree->addTopLevelItem(common_features_node);trigger_node = new QTreeWidgetItem(root_tree);trigger_node->setText(0, "Trigger");root_tree->addTopLevelItem(trigger_node);advanced_features_node = new QTreeWidgetItem(root_tree);advanced_features_node->setText(0, "Advanced Features");root_tree->addTopLevelItem(advanced_features_node);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/408068.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[创业之路-141] :产品经理 - NPDP概述

目录 一、产品经理以及主要职责 1.1 概述 1、市场调研与需求分析 2、产品规划与设计 3、项目管理与协调 4、产品推广与销售支持 5、产品运营与维护 6、其他职责 1.2 产品经理与项目经理的职责分工 1.2.1 职责区别 产品经理 项目经理 1.2.2 合作方式 二、什么是NP…

EXCEL——Vlookup17个高级用法

大纲 一、基本语法 1、参数详解 二、入门篇 1、单条件查找 2、屏蔽查找返回的错误值 三、进阶篇 1、反向查找 2、包含查找 3、区间查找 4、含通配符查找 5、多列查找 6、多区域查找 四、高级篇 1、多条件查找 2、合并单元格查找 3、带合并单元格的多条件查找 …

[数据集][目标检测]夜间老鼠检测数据集VOC+YOLO格式316张1类别+视频文件1个

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;316 标注数量(xml文件个数)&#xff1a;316 标注数量(txt文件个数)&#xff1a;316 标注类别…

MATLAB进阶:矩阵代数

今天我们学习矩阵在MATLAB中的运算。 运算符 与数组运算相同&#xff1a; A. ’转罝 A’&#xff08;共轭&#xff09;转罝 共轭转置&#xff08;A’或A†&#xff09;&#xff1a; 对于一个复数矩阵A&#xff0c;其共轭转置记作A’或A†。共轭转置不仅将矩阵A的行和列互…

大话C语言:第46篇 C语言项目工程化之Makefile详解

1 Makefile概述 Makefile是一种用于自动化构建和管理程序的工具&#xff0c;以文本文件的形式存在。它主要记录了程序的编译规则、依赖关系和操作指令&#xff0c;使得在开发过程中能够轻松地进行代码的编译、链接和部署。 Makefile文件中的命令有一定规范&#xff0c;一旦该文…

Unity--XLua调用C#

Unity–XLua调用C# 由于Unity/C# 和lua是两种语言&#xff0c;两种语言的特性不一样&#xff0c;因此&#xff0c;如果要互相调用的话&#xff0c;需要第三方作桥梁. 因此&#xff0c;为了在Unity中/C#中使用lua的特性&#xff0c;需要在Unity中安装插件&#xff0c;Xlua/toLu…

【学习笔记】8、脉冲波形的变换与产生

本章简略记录。 8.1 单稳态触发器&#xff08;脉冲触发&#xff09; 单稳态触发器 应用于 &#xff1a;&#xff08;1&#xff09;脉冲整型&#xff08;2&#xff09;脉冲延时 &#xff08;3&#xff09;定时 单稳态触发器的工作特性&#xff1a; 没有触发脉冲作用时&#xf…

Flink入门(五)--Flink算子

Map DataStream → DataStream 一个接受一个元素并产生一个元素的函数。 示例 dataStream.map { x > x * 2 } FlatMap DataStream → DataStream 一个接受一个元素并产生零个、一个或多个元素的函数。 例如 dataStream.flatMap { str > str.split(" ") }…

besier打断和升阶,高阶性质

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 问题描述 对besier曲线在u处打断&#xff0c;生成两条besier曲线对besier曲线升阶处理 bezier高阶性质 求导推导 P ( t ) ∑ i 0 n B i n ( t ) b i \boldsymbol …

Python 爬虫入门(十二):正则表达式「详细介绍」

Python 爬虫入门&#xff08;十二&#xff09;&#xff1a;正则表达式 前言一、正则表达式的用途二、正则表达式的基本组成元素2.1 特殊字符2.2 量词2.3 位置锚点2.4 断言2.5 字符集2.6 字符类2.6.1 基本字符类2.6.2 常见字符类简写2.6.3 POSIX字符类2.6.4 组合使用 三、 正则表…

Datawhale X 李宏毅苹果书 AI夏令营 学习笔记(二)

自适应学习率 我们梯度下降在参数更新上&#xff0c;公式是 W t W t − 1 − η g t &#xff0c; η 是学习率&#xff0c; g t 是梯度 W_tW_{t-1}-\eta g_t&#xff0c;\eta是学习率&#xff0c;g_t是梯度 Wt​Wt−1​−ηgt​&#xff0c;η是学习率&#xff0c;gt​是梯度…

03_React 收集表单数据和 组件生命周期

React 收集表单数据和 组件生命周期 一、收集表单数据1、例子1.1 需求&#xff1a;定义一个包含表单的组件&#xff0c;输入用户名密码后&#xff0c;点击登录提示输入信息 2、理解&#xff1a;包含表单的组件分类2.1 受控组件2.2 非受控组件 二、高阶函数\_函数柯里化1、复习-…

9 正则表达式:Java爬虫和正则表达式、String中的正则表达式方法(基本语法7)

文章目录 前言一、正则表达式1 [ ] 语法(1)[ABC] 和 [^ABC](2)[A-Z]和[a-zA-Z]小总结2 特殊字符语法(\w 这些)3 数量符4 \ 、()、 |5 锚点 ^ 和 $,\b,\B6 (?i) : 忽略其后面的大小写 ---- 这个Java是可以的,其他语言我不知道(正则表达式虽然大多通用,但也有部分是…

zabbix5.0与7.0版本区别 切换建议

Zabbix5.0和Zabbix7.0的区别 1. 性能和扩展性优化 1.1 高效的数据处理和存储 优化的数据库性能&#xff1a; Zabbix 7.0 在数据库层面进行了多项优化&#xff0c;以减少查询延迟和提高数据处理速度。这包括对数据库结构的改进和索引优化&#xff0c;使得大规模数据的读取和写…

Spark-driver和executor启动过程

一、上下文 《Spark-SparkSubmit详细过程》详细分析了从脚本提交任务后driver是如何调用到自己编写的Spark代码的&#xff0c;而我们的Spark代码在运行前必须准备好分布式资源&#xff0c;接下来我们就分析下资源是如何分配的 二、Spark代码示例 我们以一个简单的WordCount程…

打卡学习Python爬虫第五天|Xpath解析的使用

什么是Xpath&#xff1f;是在XML文档中搜索内容的一门语言&#xff0c;HTML可以看作是xml的一个子集。 目录 1、安装lxml模块 2、导入lxml中的etree子模块 3、Xpath使用方法 3.1.选择节点 3.2.选择属性 3.3.选择文本内容 3.4.使用通配符*过滤节点 3.5.使用中括号[]索引…

Java学习_20_File以及IO流

文章目录 前言一、FileFile中常见的成员方法判断和获取创建和删除获取和遍历 二、IO流IO流体系结构字节流字节输出流&#xff1a;FileOutputStream字节输入流FileInputStrea文件拷贝try……catch异常处理中文乱码现象 字符流字符流读取FileReader字符流输出FileWriter底层原理 …

Linux 命令集合

1. linux 系统版本 1.1 linux系统的分类 linux系统&#xff0c;主要分Debian系和RedHat系&#xff0c;还有其它自由的发布版本。 1、Debian系主要有Debian&#xff0c;Ubuntu&#xff0c;Mint等及其衍生版本&#xff1b; 2、RedHat系主要有RedHat&#xff0c;Fedora&#xf…

Springsecurity 自定义AuthenticationManager

一、认证流程 1、当用户提交了一个他的凭证(用户名、密码) AbstractAuthenticationProcessingFilter 将会创建一个凭证信息&#xff0c;最终&#xff0c;该请求会被UsernamePasswordAuthenticationFilter 拦截将请求中用户名和密码&#xff0c;封装为 Authentication 对象&…

C++ | Leetcode C++题解之第365题水壶问题

题目&#xff1a; 题解&#xff1a; class Solution { public:bool canMeasureWater(int x, int y, int z) {if (x y < z) {return false;}if (x 0 || y 0) {return z 0 || x y z;}return z % gcd(x, y) 0;} };