效果如图:
图像显示窗口元素组成:
图像显示窗口整体构成:
长度测量窗口ui:
思路:
首先自定了一个RulerWidget,其中有一个布局,布局中包含自定义的水平Ruler、自定义垂直Ruler、单位QLabel以及空白的QWidget。将这个空白的QWidget设置为不可见,避免遮挡图像显示区域上的图片。
然后将该RulerWidget放置在图像显示区域的前端。
长度测量中的像素坐标,是鼠标点击在图像显示区域的坐标映射到原图像的坐标。
相关代码:
#ifndef RULERWIDGET_H
#define RULERWIDGET_H
#include <QWidget>
#include <QLabel>
#include <QLayout>
#include <QPaintEvent>
#include <QPainter>
#include "measurewidget.h"
class Ruler : public QWidget
{
Q_OBJECT
public:
explicit Ruler(Qt::Orientations orientation, QWidget *parent = nullptr);
~Ruler();
void UpdateImgSize(QSize size);
void UpdatePixel(double pixel);
protected:
void paintEvent(QPaintEvent *event)override;
private:
QColor backgroundColor{"#F2F2F2"};//背景色
QColor textAndLineColor{Qt::black};//文本和刻度颜色
QFont font{"微软雅黑",7};
Qt::Orientations orientation;
QSize imgSize;
double pixelLen;
};
class RulerWidget : public QWidget
{
Q_OBJECT
public:
explicit RulerWidget(QWidget *parent=nullptr);
~RulerWidget();
void setVisible(bool visible) override;
void UpdateRulerSize(QSize size);
signals:
void sig_wid_ruler_hide();
void sig_wid_measure_update_pos(int, int, int, int);
public slots:
void slot_wid_measure_pos(int, int, int, int);
private:
Ruler *horizontal_ruler;
Ruler *vertical_ruler;
QLabel *unit_lab;
QWidget *empty_wid;
MeasureWidget *measure_wid; //标尺测量数据窗口
};
#endif // RULERWIDGET_H
#include "rulerwidget.h"
Ruler::Ruler(Qt::Orientations orientation,QWidget *parent)
: QWidget(parent),
orientation(orientation)
{
orientation == Qt::Horizontal ? setFixedHeight(30) : setFixedWidth(30);
pixelLen = 1.0;
}
Ruler::~Ruler()
{
}
void Ruler::UpdateImgSize(QSize size)
{
imgSize = size;
update();
}
void Ruler::UpdatePixel(double pixel)
{
pixelLen = pixel;
update();
}
void Ruler::paintEvent(QPaintEvent *event)
{
auto rect = event->rect();
auto height = rect.height();
auto width = rect.width();
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.fillRect(rect,backgroundColor);
//绘制刻度
painter.save();
auto length = orientation == Qt::Horizontal ? rect.width() : rect.height();
double scale = orientation == Qt::Horizontal ? ((double)imgSize.width() / length) : ((double)imgSize.height() / length);
painter.setPen(QPen(textAndLineColor,1));
painter.setFont(font);
if(orientation == Qt::Horizontal)
{
auto shortLine_y = height * 0.75;
auto longLine_y = height * 0.5;
auto middleLine_y = height * 0.625;
auto halfHeight = height / 2;
int temp = 0;
for(int i = 0;i < length;i+=10)
{
if(temp % 10 == 0)//画中线
{
painter.drawLine(QPointF(i,middleLine_y),QPointF(i,height));
}
else if(temp % 5 == 0)//画长线
{
painter.drawLine(QPointF(i,longLine_y),QPointF(i,height));
painter.drawText(QRectF(i-50,0,100,halfHeight),Qt::AlignCenter | Qt::TextWordWrap, QString::asprintf("%.1f", i*scale*pixelLen));
}
else//画短线
{
painter.drawLine(QPointF(i,shortLine_y),QPointF(i,height));
}
++temp;
}
}
else
{
auto shortLineWidth = width * 0.25;
auto longLineWidth = width * 0.5;
auto middleLineWidth = width * 0.375;
auto harfWidth = width / 2;
int temp = 0;
for(int i = 0;i < length;i+=10)
{
if(temp % 10 == 0)
{
painter.drawLine(QPointF(middleLineWidth,i),QPointF(0,i));
}
else if(temp % 5 == 0)
{
painter.drawLine(QPointF(longLineWidth,i),QPointF(0,i));
painter.rotate(90);
painter.drawText(i-10, -harfWidth-5, QString::asprintf("%.1f", i*scale*pixelLen));
painter.rotate(-90);
}
else
{
painter.drawLine(QPointF(shortLineWidth,i),QPointF(0,i));
}
++temp;
}
}
painter.drawRect(0,0, this->width(), this->height());
painter.restore();
QWidget::paintEvent(event);
}
RulerWidget::RulerWidget(QWidget *parent)
: QWidget(parent)
{
horizontal_ruler = new Ruler(Qt::Horizontal, this);
vertical_ruler = new Ruler(Qt::Vertical, this);
unit_lab = new QLabel("um", this);
unit_lab->setStyleSheet("background-color:#F2F2F2;color:black;");
empty_wid = new QWidget(this);
empty_wid->setVisible(false);
QGridLayout *grid_layout = new QGridLayout(this);
grid_layout->addWidget(unit_lab,0,0,1,1);
grid_layout->addWidget(vertical_ruler,1,0,1,1);
grid_layout->addWidget(horizontal_ruler,0,1,1,1);
grid_layout->addWidget(empty_wid,1,1,1,1);
grid_layout->setSpacing(0);
measure_wid = new MeasureWidget(this);
measure_wid->hide();
connect(this, SIGNAL(sig_wid_measure_update_pos(int,int,int,int)), measure_wid, SLOT(slot_pos_update(int,int,int,int)));
connect(measure_wid, &MeasureWidget::sig_close, this, [=](){
this->setVisible(false);
emit sig_wid_ruler_hide();
});
connect(measure_wid, &MeasureWidget::sig_set, this, [=](QString unit, QString pixel){
unit_lab->setText(unit);
if(pixel.toDouble()>0){
horizontal_ruler->UpdatePixel(pixel.toDouble());
vertical_ruler->UpdatePixel(pixel.toDouble());
}
});
this->setVisible(false);
}
RulerWidget::~RulerWidget()
{
delete horizontal_ruler;
delete vertical_ruler;
delete unit_lab;
delete empty_wid;
delete measure_wid;
}
void RulerWidget::setVisible(bool visible)
{
measure_wid->setVisible(visible);
QWidget::setVisible(visible);
}
void RulerWidget::UpdateRulerSize(QSize size)
{
horizontal_ruler->UpdateImgSize(size);
vertical_ruler->UpdateImgSize(size);
}
void RulerWidget::slot_wid_measure_pos(int StartX, int StartY, int endX, int endY)
{
emit sig_wid_measure_update_pos(StartX, StartY, endX, endY);
}
#ifndef MEASUREWIDGET_H
#define MEASUREWIDGET_H
#include <QWidget>
namespace Ui {
class MeasureWidget;
}
class MeasureWidget : public QWidget
{
Q_OBJECT
public:
explicit MeasureWidget(QWidget *parent = nullptr);
~MeasureWidget();
protected:
void closeEvent(QCloseEvent *e);
void changeEvent(QEvent *event);
signals:
void sig_close();
void sig_set(QString unit, QString pixel);
private slots:
void slot_btn_set_clicked();
public slots:
void slot_pos_update(int pos1_x, int pos1_y, int pos2_x, int pos2_y);
private:
Ui::MeasureWidget *ui;
double pixel = 1.0;
double len_h = 0.0;
double len_v = 0.0;
double len_c = 0.0;
};
#endif // MEASUREWIDGET_H
#include "measurewidget.h"
#include "ui_measurewidget.h"
MeasureWidget::MeasureWidget(QWidget *parent)
: QWidget(parent),
ui(new Ui::MeasureWidget)
{
ui->setupUi(this);
this->setFixedSize(400,300);
this->setWindowIcon(QIcon(":/icon/logo/res/icon/logo/logo.ico"));
this->setAttribute(Qt::WA_QuitOnClose, false);
this->setWindowFlag(Qt::Window);
ui->com_unit->insertItems(0, QStringList()<< "um" << "mm" << "cm");
ui->com_unit->setCurrentIndex(0);
connect(ui->btn_set, SIGNAL(clicked()), this, SLOT(slot_btn_set_clicked()));
}
MeasureWidget::~MeasureWidget()
{
}
void MeasureWidget::closeEvent(QCloseEvent *e)
{
emit sig_close();
QWidget::closeEvent(e);
}
void MeasureWidget::changeEvent(QEvent *event)
{
if(event->type() == QEvent::LanguageChange){
this->ui->retranslateUi(this);
}
QWidget::changeEvent(event);
}
void MeasureWidget::slot_btn_set_clicked()
{
if(!ui->ledit_pixel->text().isEmpty()){
pixel = ui->ledit_pixel->text().toDouble();
if(pixel > 0){
ui->lab_len_horizontal->setText(QString::asprintf("%.2f", len_h * pixel));
ui->lab_len_vertical->setText(QString::asprintf("%.2f", len_v * pixel));
ui->lab_len_cartesian->setText(QString::asprintf("%.2f", len_c * pixel));
emit sig_set(ui->com_unit->currentText(), ui->ledit_pixel->text());
}
}
}
void MeasureWidget::slot_pos_update(int pos1_x, int pos1_y, int pos2_x, int pos2_y)
{
len_h = abs(pos1_x - pos2_x)+1;
len_v = abs(pos1_y - pos2_y)+1;
len_c = sqrt(pow(len_h,2) + pow(len_v,2));
ui->lab_pos_start->setText(QString("(%1,%2)").arg(pos1_x).arg(pos1_y));
ui->lab_pos_end->setText(QString("(%1,%2)").arg(pos2_x).arg(pos2_y));
ui->lab_len_horizontal->setText(QString::asprintf("%.2f", len_h * pixel));
ui->lab_len_vertical->setText(QString::asprintf("%.2f", len_v * pixel));
ui->lab_len_cartesian->setText(QString::asprintf("%.2f", len_c * pixel));
}