qt,QGraphicsView实现鼠标中键拖动图片,鼠标滚轮缩放、两个窗口联动左键选点等功能(c++&pyqt两个版本)

先看效果

(1)c++版本(一个动图)

(2)pyqt版本(一个图):与c++版本一毛一样,用的同一个ui文件,此处动图略

 实现关键点:1)拖动:重写QGraphicsView类,鼠标中键按下记录位置并更改鼠标样式为手型,鼠标中键弹起记录鼠标位置,并执行拖动,通过设置横竖滚动条位置实现拖动;2)缩放:重写鼠标滚轮滑动事件滚轮上滑放大,下滑缩小即可;3)联动:设置联动参数,一个当前缩放参数,两个当前横竖滚轮位置参数。通过这三个参数进行联动;4)选点:左键选点,左键勾勒区域折点,右键停止并自动封闭。

源代码——c++版本

步骤(关键在于QgraphicsView类的重写,所有功能的实现均封装在这个类里边

(1)打开qtcreater,新建一个空的qt Application项目,并添加两个QgraphicsView控件用于显示图片,与一个textedit控件用于输出选点内容,并设置好布局

qt,QGraphicsView实现鼠标中键拖动图片,鼠标滚轮缩放、两个窗口联动左键选点等功能(c++&pyqt两个版本)_第1张图片

(2)改写QGraphicsView类,新建一个MyQGraphicsView类,继承QGraphicsView类,新建的这个类对应的头文件MyQGraphicsView.h如下:

#ifndef MYQGRAPHICSVIEW_H
#define MYQGRAPHICSVIEW_H
#pragma execution_character_set("UTF-8")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

class MyQGraphicsView: public QGraphicsView
{
private:
    QPointF GetMeanPos(std::vector data);//获取一组点中间位置

protected:
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
private:
    double m_scalnum; //缩放系数
    QPointF m_startpos; //鼠标中建开始点
    QPointF m_endpos; //鼠标中建结束点
    double m_posx; //视图移动参数x
    double m_posy; //试图移动参数y
    int m_flag; //是否进行选点
    int m_linkflag; //是否进行联动
    MyQGraphicsView *m_linkgraphicsview; //进行联动的窗口
    std::vector m_points; //选择的点
    std::vector> m_allpoints; //选择的所有点

public:
    explicit MyQGraphicsView(QWidget *parent = 0);
    void SetImage(QImage img);
    // 设置是否进行联动
    void SetLinkFlag(int flag)
    {
        m_linkflag = flag;
    }
    //设置联动窗口
    void SetLinkWidget(MyQGraphicsView *graphicsview)
    {
        m_linkgraphicsview = graphicsview;
    }
    // 设置联动参数
    void SetLinkPara(double para[3]);
    // 获取联动参数
    double* GetLinkPara()
    {
        double *para = new double[3];
        para[0] = m_scalnum;
        para[1] = m_posx;
        para[2] = m_posy;
        return para;
    }
    // view初始化
    void InitializeView()
    {
        m_points.clear();
        m_allpoints.clear();
        m_flag = 0;
        m_scalnum = 1;
        this->setCursor(Qt::ArrowCursor);
    }
    //设置是否选点
    void SetChoosePoint(int flag)
    {
        m_flag = flag;
        if (flag == 0)
        {
            this->setCursor(Qt::ArrowCursor);
        }
        else if (flag == 1 || flag == 2)
        {
            this->setCursor(Qt::CrossCursor);
        }
    }
    //获取当前选点状态
    int GetFlag()
    {
        return m_flag;
    }
    //获取单个区域点集
    std::vector GetPoints()
    {
        return m_points;
    }
    //删除单个点集
    void ClearPoints()
    {
        m_points.clear();
    }
    //获取所有点集
    std::vector> GetAllPoints()
    {
        return m_allpoints;
    }
    //删除所有点集
    void CalerAllPoints()
    {
        m_allpoints.clear();
    }
};

#endif // MYQGRAPHICSVIEW_H

 新建的这个类对应的头文件MyQGraphicsView.cpp如下:

#include "MyQGraphicsView.h"
#include 

MyQGraphicsView::MyQGraphicsView(QWidget *parent):
    QGraphicsView(parent)
{
    //设置鼠标样式
//    setCursor(Qt::CrossCursor);
    //使用抗锯齿渲染
//    setRenderHint(QPainter::Antialiasing);
    //设置缓冲背景,加速渲染
//    setCacheMode(QGraphicsView::CacheBackground);
//    setStyleSheet("border: 1px solid black");
//    setAlignment(Qt::AlignVCenter | Qt::AlignTop);
//    this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//    this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_scalnum = 1.;
    m_flag = 0;
    setMouseTracking(true);
}

void MyQGraphicsView::SetLinkPara(double para[3])
{
    double scalenum = para[0];
    double posx = para[1];
    double posy = para[2];
    //设置缩放
    if (scalenum > m_scalnum)
    {
        this->scale(1.3, 1.3);
        m_scalnum *= 1.3;
    }
    else if (scalenum < m_scalnum)
    {
        this->scale(1/1.3, 1/1.3);
        m_scalnum /= 1.3;
    }
    //设置移动
    if (posx != m_posx && posy != m_posy)
    {
        this->horizontalScrollBar()->setValue(posx);
        this->verticalScrollBar()->setValue(posy);
        m_posx = posx;
        m_posy = posy;
    }
}

void MyQGraphicsView::wheelEvent(QWheelEvent *event)
{
    if(event->delta()>0)
    {
        this->scale(1.3, 1.3);
        m_scalnum *= 1.3;
    }
    else
    {
        this->scale(1/1.3, 1/1.3);
        m_scalnum /= 1.3;
    }
    if (m_linkflag == 1)
    {
        m_linkgraphicsview->SetLinkPara(this->GetLinkPara());
    }
    QGraphicsView::wheelEvent(event);
}


void MyQGraphicsView::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::MiddleButton)
    {
        this->setCursor(Qt::PointingHandCursor);
        m_startpos = mapToScene(event->pos());
    }
    //鼠标左键选点并画线
    else if (event->button() == Qt::LeftButton && m_flag == 1)
    {
        QPointF p = this->mapToScene(event->pos());
//        qDebug()<setColor(QColor(255, 0, 0));
        pen->setWidth(2);
        this->scene()->addEllipse(p.x()-1, p.y()-1, 2, 2, *pen);
        int num = m_points.size();
        //绘制线
        if (num >= 2)
        {
            pen->setColor(QColor(241, 89, 42));
            pen->setWidth(1);
            this->scene()->addLine(m_points[num-2].x(),
                                   m_points[num-2].y(),
                                   m_points[num-1].x(),
                                   m_points[num-1].y(),
                                   *pen);
        }
    }
    //鼠标左键只选点
    else if (event->button() == Qt::LeftButton && m_flag == 2)
    {
        QPointF p = this->mapToScene(event->pos());
        m_points.push_back(p);
        //画点
        QPen *pen = new QPen();
        pen->setColor(QColor(255, 0, 0));
        pen->setWidth(2);
        this->scene()->addEllipse(p.x()-1, p.y()-1, 4, 4, *pen);
        //添加文本
        QFont *font = new QFont("Roman times", 20, QFont::Bold);
        QGraphicsTextItem *text = new QGraphicsTextItem(QString::number(m_points.size()));
        text->setPos(p.x()-10, p.y()-10);
        text->setDefaultTextColor(QColor(248, 201, 0));
        text->setFont(*font);
        this->scene()->addItem(text);
    }
    //鼠标右键完成当前区域选点
    else if (event->button() == Qt::RightButton && m_flag == 1)
    {
        m_allpoints.push_back(m_points);
        //连接终点与起点
        QPen *pen = new QPen();
        pen->setColor(QColor(241, 89, 42));
        pen->setWidth(1);
        int num = m_points.size() - 1;
//        qDebug()<scene()->addLine(m_points[num].x(),
                               m_points[num].y(),
                               m_points[0].x(),
                               m_points[0].y(),
                               *pen);
        //添加文本
        QFont *font = new QFont("Roman times", 20, QFont::Bold);
        QGraphicsTextItem *text = new QGraphicsTextItem(QString::number(m_allpoints.size()));
        QPointF mpos = GetMeanPos(m_points);
        text->setPos(mpos.x()-20, mpos.y()-20);
        text->setDefaultTextColor(QColor(248, 201, 0));
        text->setFont(*font);
        this->scene()->addItem(text);
        //清除已经选好的点集
        m_points.clear();
    }
    QGraphicsView::mousePressEvent(event);
}


void MyQGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    //鼠标中建弹起进行视图移动
    if (event->button() == Qt::MiddleButton)
    {
        if (m_flag != 0)
            this->setCursor(Qt::CrossCursor);
        else
            this->setCursor(Qt::ArrowCursor);
        m_endpos = mapToScene(event->pos());
        //获取滚动条当前位置
        double oposx = this->horizontalScrollBar()->value();
        double oposy = this->verticalScrollBar()->value();
        //计算鼠标移动的距离
        QPointF offset = m_endpos - m_startpos;
        //计算新的滚轮位置
        double nposx = oposx-offset.x()*m_scalnum;
        double nposy = oposy-offset.y()*m_scalnum;
        //设置新的滚轮位置
        this->horizontalScrollBar()->setValue(nposx);
        this->verticalScrollBar()->setValue(nposy);
//        QPointF offset = -m_endpos + m_startpos;
//        this->scene()->setSceneRect(this->scene()->sceneRect().x()+offset.x(),
//                                    this->scene()->sceneRect().y()+offset.y(),
//                                    this->scene()->sceneRect().width(),
//                                    this->scene()->sceneRect().height());
        this->scene()->update();
        //记录备用
        m_posx = nposx;
        m_posy = nposy;
        //进行联动
        if (m_linkflag == 1)
        {
            m_linkgraphicsview->SetLinkPara(this->GetLinkPara());
        }
    }
    QGraphicsView::mouseReleaseEvent(event);
}


void MyQGraphicsView::SetImage(QImage img)
{
    //把影像添加到画布
    QPixmap Images = QPixmap::fromImage(img);
    QGraphicsPixmapItem *map = new QGraphicsPixmapItem(Images);
//    map = new QGraphicsPixmapItem(Images);
    map->setFlag(QGraphicsPixmapItem::ItemIsSelectable, true);
    map->setFlag(QGraphicsPixmapItem::ItemIsMovable, false);
    map->setFlag(QGraphicsPixmapItem::ItemSendsGeometryChanges,true);
    QGraphicsScene *scene = new QGraphicsScene(); //场景 = new QGraphicsScene();
    //画布添加至场景
    scene->addItem(map);
    //场景绑定到控件
    this->setScene(scene);
    this->show();
}

QPointF MyQGraphicsView::GetMeanPos(std::vector data)
{
    double sumx(0);
    double sumy(0);
    for (int i(0); i

(3)将原有新建的QGraphicsView控件提升为新建的类

qt,QGraphicsView实现鼠标中键拖动图片,鼠标滚轮缩放、两个窗口联动左键选点等功能(c++&pyqt两个版本)_第2张图片

qt,QGraphicsView实现鼠标中键拖动图片,鼠标滚轮缩放、两个窗口联动左键选点等功能(c++&pyqt两个版本)_第3张图片

 (4)在主窗体构造函数中添加以下内容:

QgraphicsViewTestGUI::QgraphicsViewTestGUI(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::QgraphicsViewTestGUI)
{
    ui->setupUi(this);
    //窗口最大化
    showMaximized();
    //设置事件过滤器,用于选点测试
    ui->graphicsView_LeftImage->viewport()->installEventFilter(this);
    ui->graphicsView_RightImage->viewport()->installEventFilter(this);
    //设置窗口比例
    ui->splitter->setStretchFactor(0, 4);
    ui->splitter->setStretchFactor(1, 1);
    //设置联动
    ui->graphicsView_LeftImage->SetLinkFlag(1);
    ui->graphicsView_RightImage->SetLinkFlag(1);
    ui->graphicsView_LeftImage->SetLinkWidget(ui->graphicsView_RightImage);
    ui->graphicsView_RightImage->SetLinkWidget(ui->graphicsView_LeftImage);
    //显示图片
    QImage img1("E:/smallthings/temp/QgraphicsViewTestGUI/testimg.jpg");
    QImage img2("E:/smallthings/temp/QgraphicsViewTestGUI/testimg.jpg");
    ui->graphicsView_LeftImage->SetImage(img1);
    ui->graphicsView_RightImage->SetImage(img2);
    //设置选点
    ui->graphicsView_LeftImage->SetChoosePoint(2);//左边窗口测试选点
    ui->graphicsView_RightImage->SetChoosePoint(1);//右边窗口测试选区域
}

(5)在主窗体类中添加两个函数

函数声明:

bool eventFilter(QObject* watched, QEvent* event);//事件过滤
void ShowMsg(QString msg);//显示日志

函数实现:

bool QgraphicsViewTestGUI::eventFilter(QObject* watched, QEvent* event)
{
    if (event->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent *mouseevent = static_cast(event);
        if(mouseevent->button() == Qt::LeftButton && watched == ui->graphicsView_LeftImage->viewport())
        {
            //左窗口测试选点(左键)
            std::vector ps = ui->graphicsView_LeftImage->GetPoints();
            if (ps.size() != 0)
            {
                QPointF nowp = ps.at(ps.size() - 1);
                ShowMsg("影像选点测试,影像上一个点第" +
                        QString::number(ps.size()) +
                        "个点,坐标为:(" +
                        QString::number(nowp.x(), 'f', 3) +
                        "," +
                        QString::number(nowp.y(), 'f', 3) + ")");
            }
        }
        else if(mouseevent->button() == Qt::RightButton && watched == ui->graphicsView_RightImage->viewport())
        {
            //右键测试选区域(右键)
            std::vector> areas = ui->graphicsView_RightImage->GetAllPoints();
            if (areas.size() != 0)
            {
                std::vector nowarea = areas.at(areas.size() - 1);
                QString coorstr = "";
                for (int i(0); itextBrowser_log->moveCursor(QTextCursor::End);
    ui->textBrowser_log->append(">>" + msg);
}

(6)愉快的运行

源代码——pyqt版本

依赖项

PyQt5 == 5.10.1

numpy == 1.21.4

qimage2ndarray == 1.8.3

步骤(关键在于QgraphicsView类的重写,所有功能的实现均封装在这个类里边

(1)新建一个python脚本,里边新建一个MyQgraphicsView类,继承QgraphicsView类,添加如下代码。注:pyqt版本支持的影像为numpy矩阵,可以是多通道的遥感影像,但默认前三个通道为RGB;数据类型可以不是uint8(比如uint16),会自动进行2%线性拉伸,去除过大、过小的异常值,同时数据拉伸到uint8范围内

# yangzhen
# 2021.12.04


from PyQt5 import QtCore as qc
from PyQt5 import QtGui as qg
from PyQt5 import QtWidgets as qw
import numpy as np
import copy

class MyQGraphicsView(qw.QGraphicsView):
    def __init__(self, parent):
        super(MyQGraphicsView, self).__init__(parent)
        self.setMouseTracking(True)

        self.points = [] # 选择的点
        self.allpoints = []
        self.startpos = qc.QPoint(0, 0) # 鼠标中键按下时起始点
        self.endpos = qc.QPoint(0, 0) # 鼠标中键弹起时终点
        self.scalenum = 1 # 缩放系数
        # self.scaleflag = 0 # 放大还是缩小(0:不动,1:放大,-1:缩小)
        self.nposx = 0 # 视图移动参数x
        self.nposy = 0 # 视图移动参数y
        # self.mindex = 1 # 当前区域编号
        self.flag = 0 # 是否进行选点的flag
        self.linkflag = 0 # 是否进行联动

    def SetLinkFlag(self, flag):
        """设置是否联动"""
        self.linkflag = flag

    def SetLinkWidget(self, mwidget):
        self.linkwidget = mwidget

    def SetLinkPara(self, para):
        """设置联动参数并作出联动操作"""
        scalenum = para[0]
        # print(scaleflag)
        nposx = para[1]
        nposy = para[2]
        # 设置缩放
        if scalenum > self.scalenum:
            self.scale(1.3, 1.3)
            self.scalenum = self.scalenum*1.3
            # self.scalflag = 1
        elif scalenum < self.scalenum:
            self.scale(1/1.3, 1/1.3)
            self.scalenum = self.scalenum/1.3
            # self.scalflag = -1
        # 设置移动
        if nposx != self.nposx and nposy != self.nposy:
            self.horizontalScrollBar().setValue(nposx)
            self.verticalScrollBar().setValue(nposy)
            self.nposx = nposx
            self.nposy = nposy

    def GetLinkPara(self):
        """获取联动参数"""
        para = []
        para.append(self.scalenum)
        para.append(self.nposx)
        para.append(self.nposy)
        return para

    def InitializeView(self):
        """View初始化"""
        self.points.clear()
        self.allpoints.clear()
        self.flag = 0
        self.scalenum = 1
        self.setCursor(qc.Qt.ArrowCursor)

    def SetChoosePoint(self, flag):
        """设置是否选点"""
        self.flag = flag
        if flag == 0:
            self.setCursor(qc.Qt.ArrowCursor)
        if flag == 1 or flag == 2:
            self.setCursor(qc.Qt.CrossCursor)

    def GetFlag(self):
        """获取当前是在做什么"""
        return self.flag

    def GetPoints(self):
        """获取点集"""
        return self.points

    def ClearPoints(self):
        """删除点集"""
        self.points.clear()

    def GetAllPoints(self):
        """获取所有区域点集"""
        return self.allpoints

    def ClearPoints(self):
        """删除所有区域点集合"""
        self.allpoints.clear()

    def PersentLiner(self, data, ratio):
        mdata = data.copy()
        rows, cols = data.shape[0:2]
        counts = rows*cols
        mdata = mdata.reshape(counts, 1)
        tdata = np.sort(mdata, axis=0)
        cutmin = tdata[int(counts*ratio), 0]
        cutmax = tdata[int(counts*(1-ratio)), 0]
        ndata = 255.0*(data.astype(np.float32) - cutmin)/float(cutmax-cutmin)
        ndata[data < cutmin] = 0
        ndata[data > cutmax] = 255
        return ndata

    def SetImage(self, data):
        """设置影像"""
        # if (data.type() == )
        dtp = data.dtype
        rows, cols, depth = data.shape
        # 如果通道数大于3个,只保留前边三个通道
        if depth > 3:
            img = data[:, :, 0:3].copy()
            img = img[:, :, ::-1]
        else:
            img = data.copy()
        rows, cols, depth = img.shape
        # 如果不是uint8的数据,需要先拉伸
        if dtp != np.uint8:
            for i in range(depth):
                img[:,:,i] = self.PersentLiner(img[:,:,i].copy(), 0.02)
            img = img.astype(np.uint8)
        # numpy矩阵转换成QImage
        if depth == 3:
            nimg = qg.QImage(img.data, cols, rows, cols*depth,\
                             qg.QImage.Format_RGB888)
        elif depth == 2:
            b1 = np.float32(img[:, :, 0])
            b2 = np.float32(img[:, :, 1])
            img = np.uint8((b1+b2)/2.)
            nimg = qg.QImage(img.data, cols, rows, cols*depth,\
                             qg.QImage.Format_Grayscale8)
        elif depth == 1:
            nimg = qg.QImage(img.data, cols, rows, cols*depth,\
                             qg.QImage.Format_Grayscale8)
        pix = qg.QPixmap.fromImage(nimg)
        item = qw.QGraphicsPixmapItem(pix)
        showscene = qw.QGraphicsScene()
        showscene.addItem(item)         
        self.setScene(showscene)
        self.setTransform(qg.QTransform())
    
    def wheelEvent(self, event):
        if (event.angleDelta().y() > 0.5):
            self.scale(1.3, 1.3)
            self.scalenum = self.scalenum * 1.3
            # self.scaleflag = 1
        elif (event.angleDelta().y() < 0.5):
            self.scale(1/1.3, 1/1.3)
            # self.scaleflag = -1
            self.scalenum = self.scalenum / 1.3
        if self.linkflag == 1:
            self.linkwidget.SetLinkPara(self.GetLinkPara())

    def mousePressEvent(self, event):
        button = event.button()
        modifier = event.modifiers()
        # 按住ctrl时变更鼠标样式
        if button == qc.Qt.MiddleButton:
            self.setCursor(qc.Qt.PointingHandCursor)
            self.startpos = self.mapToScene(event.pos())
            # print(self.startpos)
        # 鼠标左键进行选点
        elif button == qc.Qt.LeftButton and self.flag == 1:
            p = self.mapToScene(event.pos())
            self.points.append([p.x(), p.y()])
            # 画点
            pen = qg.QPen()
            pen.setColor(qg.QColor(255, 0, 0))
            pen.setWidth(2)
            self.scene().addEllipse(p.x()-1, p.y()-1, 2, 2, pen)
            num = len(self.points)
            # 画线
            if num>=2:
                pen.setColor(qg.QColor(241, 89, 42))
                pen.setWidth(1)
                self.scene().addLine(self.points[num-2][0], \
                                     self.points[num-2][1], \
                                     self.points[num-1][0], \
                                     self.points[num-1][1], pen)
        # 鼠标左键只选点
        elif button == qc.Qt.LeftButton and self.flag == 2:
            p = self.mapToScene(event.pos())
            self.points.append([p.x(), p.y()])
            # 画点
            pen = qg.QPen()
            pen.setColor(qg.QColor(255, 0, 0))
            pen.setWidth(2)
            self.scene().addEllipse(p.x()-1, p.y()-1, 4, 4, pen)
            # 添加文本
            font = qg.QFont("Roman times", 20, qg.QFont.Bold)
            text = qw.QGraphicsTextItem(str(len(self.points)))
            text.setPos(p.x()-10, p.y()-10)
            text.setDefaultTextColor(qg.QColor(248, 201, 0))
            text.setFont(font)
            self.scene().addItem(text)
        # 鼠标右键完成当前区域选点
        elif button == qc.Qt.RightButton and self.flag == 1:
            self.allpoints.append(copy.deepcopy(self.points))
            # 画线
            pen = qg.QPen()
            pen.setColor(qg.QColor(241, 89, 42))
            pen.setWidth(1)
            self.scene().addLine(self.points[-1][0], \
                                 self.points[-1][1], \
                                 self.points[0][0], \
                                 self.points[0][1], pen)
            # 添加文本
            tps = np.array(self.points)
            mps = np.mean(tps, axis=0)
            font = qg.QFont("Roman times", 20, qg.QFont.Bold)
            text = qw.QGraphicsTextItem(str(len(self.allpoints)))
            text.setPos(mps[0]-20, mps[1]-20)
            text.setDefaultTextColor(qg.QColor(248, 201, 0))
            text.setFont(font)
            self.scene().addItem(text)
            # 这个区域点压入集合
            self.points.clear()

    
    def mouseReleaseEvent(self, event):
        button = event.button()
        modifier = event.modifiers()
        # 鼠标中键弹起时进行视图移动
        if button == qc.Qt.MiddleButton:
            # 变更鼠标样式
            if self.flag == 0:
                self.setCursor(qc.Qt.ArrowCursor)
            elif self.flag == 1 or self.flag == 2:
                self.setCursor(qc.Qt.CrossCursor)
            # 记录当前点进行视图移动
            self.endpos = self.mapToScene(event.pos())
            # 获取滚动条当前位置
            oposx = self.horizontalScrollBar().value()
            oposy = self.verticalScrollBar().value()
            # 计算鼠标移动的距离
            offset = self.endpos - self.startpos
            # 根据移动的距离计算新的滚轮位置
            nposx = oposx - offset.x()*self.scalenum
            nposy = oposy - offset.y()*self.scalenum
            # 设置新的滚轮位置
            self.horizontalScrollBar().setValue(nposx)
            self.verticalScrollBar().setValue(nposy)
            # 记录一下备用
            self.nposx = nposx
            self.nposy = nposy
            # 进行联动
            if self.linkflag == 1:
                self.linkwidget.SetLinkPara(self.GetLinkPara())

(2)再新建一个python脚本,新建一个QgraphicsViewTestGUI类,继承QWidget类,代码如下:

# yangzhen
# 2021.12.04

from PyQt5 import QtCore, QtGui, QtWidgets
import ImageShow
import numpy as np
import qimage2ndarray


class QgraphicsViewTestGUI(QtWidgets.QWidget):
    def __init__(self):
        super(QgraphicsViewTestGUI, self).__init__()
        self.showMaximized()
        # 设置主布局为格网布局
        self.gridLayout = QtWidgets.QGridLayout(self)
        self.gridLayout.setObjectName("gridLayout")
        # 日志输出窗口与两个影像窗口为垂直分割布局
        self.splitter = QtWidgets.QSplitter(self)
        self.splitter.setOrientation(QtCore.Qt.Vertical)
        self.splitter.setObjectName("splitter")
        # 为两个影像显示窗口设置布局
        self.layoutWidget = QtWidgets.QWidget(self.splitter)
        self.layoutWidget.setObjectName("layoutWidget")
        self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        # 左影像显示窗口
        self.graphicsView_LeftImage = ImageShow.MyQGraphicsView(self.layoutWidget)
        self.graphicsView_LeftImage.setObjectName("graphicsView_LeftImage")
        self.horizontalLayout.addWidget(self.graphicsView_LeftImage)
        # 右影像显示窗口
        self.graphicsView_RightImage = ImageShow.MyQGraphicsView(self.layoutWidget)
        self.graphicsView_RightImage.setObjectName("graphicsView_RightImage")
        self.horizontalLayout.addWidget(self.graphicsView_RightImage)
        # 日志输出窗口
        self.textBrowser_log = QtWidgets.QTextBrowser(self.splitter)
        self.textBrowser_log.setStyleSheet("QTextBrowser\n"
                                            "{\n"
                                            "    background:white;\n"
                                            "    font-size:20px;\n"
                                            "    font-family:微软雅黑;\n"
                                            "    font-weight:bold;\n"
                                            "}")
        self.textBrowser_log.setObjectName("textBrowser_log")
        self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1)
        # 初始化窗口
        self.Initialize()

    def Initialize(self):
        """窗口初始化用于影像显示的测试"""
        # 设置事件过滤,用于选点测试
        self.graphicsView_LeftImage.viewport().installEventFilter(self)
        self.graphicsView_RightImage.viewport().installEventFilter(self)
        # 设置窗口比例
        self.splitter.setStretchFactor(0, 4)
        self.splitter.setStretchFactor(1, 1)
        # 设置联动
        self.graphicsView_LeftImage.SetLinkFlag(1)
        self.graphicsView_RightImage.SetLinkFlag(1)
        self.graphicsView_LeftImage.SetLinkWidget(self.graphicsView_RightImage)
        self.graphicsView_RightImage.SetLinkWidget(self.graphicsView_LeftImage)
        # 显示图片
        img1 = QtGui.QImage('E:/smallthings/temp/QgraphicsViewTestGUI/testimg.jpg')
        img2 = QtGui.QImage('E:/smallthings/temp/QgraphicsViewTestGUI/testimg.jpg')
        img1 = qimage2ndarray.rgb_view(img1)
        img2 = qimage2ndarray.rgb_view(img2)
        self.graphicsView_LeftImage.SetImage(img1)
        self.graphicsView_RightImage.SetImage(img2)
        # 设置选点
        self.graphicsView_LeftImage.SetChoosePoint(2)
        self.graphicsView_RightImage.SetChoosePoint(1)

    def eventFilter(self, watched, event):    
        """重写eventfilter事件"""
        if event.type() == QtCore.QEvent.MouseButtonPress:
            if event.button() == QtCore.Qt.LeftButton and watched == self.graphicsView_LeftImage.viewport():
                ps = self.graphicsView_LeftImage.GetPoints()
                if len(ps) != 0:
                    nowp = ps[-1]
                    self.ShowMsg("影像选点测试,影像上一个点第" +
                                 str(len(ps)) +
                                 "个点,坐标为:(" +
                                 str('%.3f'%nowp[0]) + ", " +
                                 str('%.3f'%nowp[1]) + ")")
            elif event.button() == QtCore.Qt.RightButton and watched == self.graphicsView_RightImage.viewport():
                areas = self.graphicsView_RightImage.GetAllPoints()
                if len(areas) != 0:
                    nowarea = areas[-1]
                    coorstr = ''
                    for coor in nowarea:
                        tstr = "(" + str('%.3f'%coor[0]) + ", " + str('%.3f'%coor[1]) + ")\n"
                        coorstr += tstr
                    self.ShowMsg("影像选区域测试,影像上一个区域第" +
                                 str(len(areas)) +
                                 "个区域,坐标集为:\n" + coorstr)
        return QtWidgets.QWidget.eventFilter(self, watched, event)

    def ShowMsg(self, msg):
        """追加的方式在ttextBrowser_log上写东西,为了日志的显示"""
        self.textBrowser_log.moveCursor(QtGui.QTextCursor.End)
        self.textBrowser_log.append('>>' + msg)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ui = QgraphicsViewTestGUI()
    ui.show()
    sys.exit(app.exec_())

(3)然后就可以愉快的运行了

qt,QGraphicsView实现鼠标中键拖动图片,鼠标滚轮缩放、两个窗口联动左键选点等功能(c++&pyqt两个版本)_第4张图片

后记

    两个版本的源代码也是有的:

qt,QGraphicsView实现鼠标中键拖动图片,鼠标滚轮缩放、两个窗口联动左键选点等功能(c++&pyqt两个版本)_第5张图片 链接:https://pan.baidu.com/s/18E_Ll-FYItklE4MiGrKosw 
提取码:1234

你可能感兴趣的:(图像处理代码,qt,c++,python)