通過 QPainter 繪畫實現,以本地圖片985*740爲例
轉載地址:https://www.cnblogs.com/lifexy/p/9057046.html
如下圖所示:
效果如下所示:
實現原理
主要通過以下函數實現:
void QPainter::drawTiledPixmap ( int x, int y, int w int h const QPixmap & pixmap, int sx = 0, int sy = 0 );
//平鋪顯示pixmap
//x y w h :表示繪畫區域
//sx sy :表示Qpixmap繪畫起始位置
只要算出x y w h sx sy就能實現超出窗口不顯示的效果
舉個例子,如下圖所示,居中顯示1200*1200時:
當圖片左偏移600時,也就是offset=-600時,則只能在窗口上顯示一半的圖片:
代碼實現
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtGui>
class Widget : public QWidget
{
Q_OBJECT
private :
QPixmap *pix;
int action; //動作(放大,縮小,移動...)
int pixW; //圖片寬
int pixH; //圖片高
QRect Paint; //繪畫區域
float ratio; //比例
QPoint offset; //一次的圖片偏移值
QPoint Alloffset; //總偏移
QLabel label;
QPushButton BigButton;
QPushButton LittleButton;
QPushButton LiftButton;
QPushButton RightButton;
QPushButton UpButton;
QPushButton DownButton;
void AddComboItem(QComboBox* cmbo);
bool event(QEvent * event);
void wheelEvent(QWheelEvent* e); //鼠標滑輪事件
private slots:
void onUpClicked();
void onDownClicked();
void OnLiftClicked();
void OnRightClicked();
void onLittleClicked();
void onBigClicked();
void paintEvent(QPaintEvent *event);
public:
explicit Widget();
enum Type {
None = 0,
Amplification ,
Shrink,
Lift,
Right,
Up,
Down,
Move
};
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
Widget::Widget():
BigButton("放大",this),
LittleButton("縮小",this),
LiftButton("向左",this),
RightButton("向右",this),
UpButton("向上",this),
DownButton("向下",this),
Paint(10,10,810,810),
Alloffset(0,0),
label("100%",this)
{
ratio= 1.0; //初始化圖片縮放比例
action = Widget::None;
pixW = 985; //設置圖片尺寸爲985*740
pixH = 740;
pix = new QPixmap;
pix->load(":/pic/img.jpg");
BigButton.setGeometry(822,10,60,25);
connect(&BigButton,SIGNAL(clicked()),this,SLOT(onBigClicked()));
LittleButton.setGeometry(822,40,60,25);
connect(&LittleButton,SIGNAL(clicked()),this,SLOT(onLittleClicked()));
LiftButton.setGeometry(822,70,60,25);
connect(&LiftButton,SIGNAL(clicked()),this,SLOT(OnLiftClicked()));
RightButton.setGeometry(822,100,60,25);
connect(&RightButton,SIGNAL(clicked()),this,SLOT(OnRightClicked()));
UpButton.setGeometry(822,130,60,25);
connect(&UpButton,SIGNAL(clicked()),this,SLOT(onUpClicked()));
DownButton.setGeometry(822,160,60,25);
connect(&DownButton,SIGNAL(clicked()),this,SLOT(onDownClicked()));
label.move(840,200);
resize(890,850);
}
bool Widget::event(QEvent * event)
{
static bool press=false;
static QPoint PreDot;
if(event->type() == QEvent::MouseButtonPress )
{
QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);
//判斷鼠標是否是左鍵按下,且鼠標位置是否在繪畫區域
if(mouse->button()==Qt::LeftButton &&Paint.contains(mouse->pos()))
{
press=true;
//QApplication::setOverrideCursor(Qt::OpenHandCursor); //設置鼠標樣式
this->setCursor(Qt::OpenHandCursor);
PreDot = mouse->pos();
}
}
else if(event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);
//判斷鼠標是否是左鍵釋放,且之前是在繪畫區域
if(mouse->button()==Qt::LeftButton && press )
{
//QApplication::setOverrideCursor(Qt::ArrowCursor); //改回鼠標樣式
this->setCursor((Qt::ArrowCursor));
press=false;
}
}
if(event->type() == QEvent::MouseMove) //移動圖片
{
if(press)
{
QMouseEvent *mouse = dynamic_cast<QMouseEvent* >(event);
offset.setX(mouse->x() - PreDot.x());
offset.setY(mouse->y() - PreDot.y());
PreDot = mouse->pos();
action = Widget::Move;
this->update();
}
}
return QWidget::event(event);
}
void Widget::wheelEvent(QWheelEvent* event) //鼠標滑輪事件
{
if (event->delta()>0) { //上滑,縮小
action=Widget::Shrink;
this->update();
} else { //下滑,放大
action=Widget::Amplification;
this->update();
}
event->accept();
}
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
int NowW = ratio *pixW;
int NowH = ratio *pixH;
if(action==Widget::Amplification) //縮小
{
ratio-=0.1*ratio;
if(ratio<0.018)
ratio = 0.01;
/*顯示比例*/
QString str;
str.sprintf("%.0f%",ratio*100);
label.setText(str) ;
}
else if(action==Widget::Shrink) //放大
{
ratio+=0.1*ratio;
if(ratio>4.5)
ratio = 5.000;
/*顯示比例*/
QString str;
str.sprintf("%.0f%",ratio*100);
label.setText(str);
}
if(action==Widget::Amplification || action==Widget::Shrink) //更新圖片
{
NowW = ratio *pixW;
NowH = ratio *pixH;
pix->load(":/pic/img.jpg"); //重新裝載,因爲之前的圖片已經被縮放過
*pix = pix->scaled(NowW, NowH,Qt::KeepAspectRatio);
action=Widget::None;
}
if(action==Widget::Move) //移動
{
int offsetx=Alloffset.x()+offset.x();
Alloffset.setX(offsetx);
int offsety=Alloffset.y()+offset.y();
Alloffset.setY(offsety);
action=Widget::None;
}
if(abs(Alloffset.x())>=(Paint.width()/2 + NowW/2 -10)) //限制X偏移值
{
if(Alloffset.x()>0)
Alloffset.setX(Paint.width()/2 + NowW/2 -10);
else
Alloffset.setX(-Paint.width()/2 + -NowW/2 +10);
}
if(abs(Alloffset.y())>=(Paint.height()/2 + NowH/2 -10)) //限制Y偏移值
{
if(Alloffset.y()>0)
Alloffset.setY(Paint.height()/2 + NowH/2 -10);
else
Alloffset.setY(-Paint.height()/2 + -NowH/2 +10);
}
int x = Paint.width()/2 + Alloffset.x() -NowW/2;
if(x<0)
x=0;
int y = Paint.height()/2 + Alloffset.y() -NowH/2;
if(y<0)
y=0;
int sx = NowW/2 - Paint.width()/2 - Alloffset.x();
if(sx<0)
sx=0;
int sy = NowH/2 - Paint.height()/2 - Alloffset.y();
if(sy<0)
sy=0;
int w =(NowW - sx)>Paint.width()? Paint.width() : (NowW - sx);
if(w>(Paint.width()-x))
w = Paint.width()-x;
int h =(NowH - sy)>Paint.height()? Paint.height() : (NowH - sy);
if(h>(Paint.height()-y))
h = Paint.height()-y;
painter.drawRect(Paint.x()-1,Paint.y()-1,Paint.width()+1,Paint.height()+1); //畫框
painter.drawTiledPixmap(x+Paint.x(),y+Paint.y(),w,h,*pix,sx,sy); //繪畫圖形
}
void Widget::onLittleClicked()
{
action=Widget::Amplification;
this->update();
}
void Widget::onBigClicked()
{
action=Widget::Shrink;
this->update();
}
void Widget::onUpClicked()
{
action=Widget::Move;
offset.setX(0);
offset.setY(-20);
this->update();
}
void Widget::onDownClicked()
{
action=Widget::Move;
offset.setX(0);
offset.setY(20);
this->update();
}
void Widget::OnLiftClicked()
{
action=Widget::Move;
offset.setX(-20);
offset.setY(0);
this->update();
}
void Widget::OnRightClicked()
{
action=Widget::Move;
offset.setX(20) ;
offset.setY(0) ;
this->update();
}
實現原理分析:
- 在event函數中,捕獲並響應鼠標左鍵按下,移動和釋放事件。
1) 判斷是否爲鼠標單擊事件,並將基本Qt事件投射到鼠標事件
判斷是否是左鍵按下,判斷鼠標是否在繪圖區域
若前述成立,設置鼠標按下標誌位爲true,改變鼠標樣式,記錄下鼠標當前座標
2)判斷是否爲鼠標按下事件,並將基本Qt事件投射到子類(鼠標事件)
判斷是否是鼠標左鍵按下,並讀取鼠標按下標誌位
若前述成立,則標誌着整個拖放事件完成,重設鼠標樣式,復位鼠標按下標誌位,即鼠標按下時,既可以響應拖放事件,也可以響應縮放事件
3)判斷鼠標移動事件
判斷鼠標按下標誌位,並將基本Qt事件投射到子類(鼠標事件)
若前述成立,根據鼠標左鍵按下事件和當前鼠標位置,設置鼠標偏移量。並更新記錄鼠標當前值,設置窗口重構事件爲移動事件,更新窗口顯示 - 在wheelEvent事件中,判斷滾輪滾動方向。設置窗口重構事件爲Shrink或者 Amplification。更新窗口顯示,結束滾輪事件。
- paintEvent用於響應窗口重構事件,更新窗口顯示
1)如果爲縮小放大事件,重新設置縮放率,並且重新載入圖片
2)如果爲移動事件,將偏移值傳遞給位置座標
3)最後需要設置x,y,w,h,sx,sy,其中x,y,w,h代表繪圖的區域,sx,sy代表從原始圖片中截取的左上角座標。