04_Qt的画笔、作画和自定义控件

一、初试画笔

Qt的画笔在作画之前都是必须设置的,且都是叠加样式的;

#include "MyWidget.h"


MyWidget::MyWidget( QWidget *parent):QWidget( parent ) { }


MyWidget::~MyWidget(void) { }


void MyWidget::paintEvent( QPaintEvent * ) {

    QPixmap pixmap( this->size() ) ;
    QPainter p( &pixmap ) ;
    //p(this) ;也是可以的,只是每次都是画在widget(即this)上,有点麻烦;所以启用了一块画布pixmap来作画,
    //不过画完之后,这些动作都是在画布pixmap上的,要将动画显示出来,就要用到:p.end(),p.begin(),p.drawPixmap这三个函数将画布展现在widget上
    /*---------设置画笔------------*/
    p.translate( 100 , 100 ) ;//设置画笔的动作:移动,之后以(100,100)为原点作画
    p.scale(1.5,.8) ;//设置画笔的动作:缩放
    p.setPen( QPen(Qt::red,2,Qt::DashLine) ) ;//设置画笔的类型:笔头大小、划线类型、颜色
    p.setBrush( Qt::yellow ) ;//设置图形内部的填充颜色
    p.setFont(QFont("aaa", 40, 700, true));
    /*---------画图----------------*/
    p.drawLine( QPoint(50,50) , QPoint(200,200) ) ;//画直线
    p.drawText( QPoint(200,200) , "luck dog" ) ;//画文字
    p.drawRect( QRect(40,60,100,50) ) ;//画矩形
    p.drawRoundRect( QRect(150,60,100,50) ) ;//画圆角矩形
    p.drawEllipse(QPoint(95, 333), 50, 50);//画椭圆
    /*-----------画笔样式不叠加--------------*/
    QTransform transform ;
    transform.translate( -50 , -50 ) ;
    p.setTransform( transform , false ) ;//false:不叠加笔头样式;true:叠加
    p.drawLine( QPoint(50,50) , QPoint(200,150) ) ;//画直线
    QTransform transform2;
    transform2.scale(.5, .5);
    p.setTransform(transform2, false);//不叠加transform和transform2两个样式
    p.drawLine( QPoint(50,50) , QPoint(200,150) ) ;//画直线
    /*---------作画结束----------------*/
    p.end() ;//结束作画,这样画布上就有了图案

    p.begin(this) ;//画笔开始在this(即widget)作画,
    p.drawPixmap(0,0,pixmap) ;//将画布展现在widget上

    /*注意:每次作画完之前先设置笔的动作,在作画才能设置成功,不过样式是叠加上去的。
    **有没一种不叠加的方式呢?有,那就是p.transform*/
}

/*实现鼠标左击,保存当前图片*/
void MyWidget::mousePressEvent(QMouseEvent *ev ){

    if( ev->button()==Qt::LeftButton ) {
        QPixmap pixmap( this->size() ) ;
        QPainter painter( &pixmap ) ;
        this->render( &painter ) ;//通过这个函数局部的painter中的内容就可以被类中的painter赋值,所以pixmap中就有数据了
        pixmap.save( "./me.png" ) ;
        qDebug()<<"left button" ;
    }

}

二、在画布上作画

与鼠标的事件触发联系起来,实现一个小功能:类似window下的画画工具;

大概思路:
前面已经介绍了画笔painter的用法,这里就可以熟练使用了。我们只要把鼠标划过的点记录下来,然后调用update函数去回调paintEvent函数,在这个函数中就可以将刚才记录的点画出来了。
记录:用vector动态数组保存数据。

#include "mywidget.h"


MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent) { }


MyWidget::~MyWidget() { }


void MyWidget::mousePressEvent( QMouseEvent *ev ) { 

    QVector<QPoint> line ;
    _lines.append( line ) ;

    line.append( ev->pos() ) ;
    //_line.append( ev->pos() ) ;
} 


void MyWidget::mouseReleaseEvent( QMouseEvent *ev ) { 

    QVector<QPoint> &line = _lines.last() ;
    line.append(ev->pos()) ;
    //_line.append( ev->pos() ) ;
}


void MyWidget::mouseMoveEvent( QMouseEvent *ev ) {

    if( _lines.size()==0 ){
        QVector<QPoint> line ;
        _lines.append( line ) ;
    }//如果这个widget上放了其他控件,例如button,当程序启动鼠标直接从button划到当前这个widget时,由于这个widget没收到鼠标按下的消息,所以还没能在vector中添加数据,此时从vector中获取数据会出错。
    QVector<QPoint> &line = _lines.last() ;
    line.append(ev->pos()) ;
    //_line.append( ev->pos() ) ;
    update() ;
}


void MyWidget::paintEvent( QPaintEvent * ) {

    QPixmap pixmap( QSize(200,200) ) ;
    QPainter painter( &pixmap ) ;
    painter.setPen( QPen(Qt::red,5,Qt::DashLine) ) ;
    painter.setBrush( Qt::yellow ) ;
    /*这里重绘想要的图案,刚才已经通过鼠标的响应事件将鼠标滑过的位置保存在vector中了*/
    /*这个是画一条连续线的代码
    for( int i=0 ; i<_line.size()-1 ; ++i ){
        painter.drawLine( _line.at(i) , _line.at(i+1) ) ;
    }*/
    QVector<QPoint> line ;
    for( int i=0 ; i<_lines.size() ; ++i ) {
        line = _lines.at(i) ;
        for( int j=0 ; j<line.size()-1;++j ){
            painter.drawLine( line.at(j) , line.at(j+1) ) ;
        }
    }
    painter.end() ;

    painter.begin( this ) ;
    painter.drawPixmap( 0,0,pixmap ) ;
}

三、自定义控件

自定义控件,说白了就是继承widget类,然后再里面作画。然后书写鼠标的响应事件,但是鼠标的响应事件是针对这整个widget窗口的,所以必须在鼠标单击时判断鼠标点击的区域是不是画布上按钮所在的位置,如果是再执行点击事件。

#include "MyButton.h"


MyButton::MyButton(QWidget *parent):QWidget(parent),_rect(50, 50, 100, 30)  { 

    this->setGeometry( _rect ) ;
}


MyButton::MyButton( const QString &text , QWidget *parent ):QWidget(parent),_rect(0, 0, 100, 30),_size(100,100) {

    _text = text ;
    _press = false ;
    this->setGeometry( _rect ) ;
    if( 0!=parent ) {
        _size = parent->size() ;
    }
    this->setMinimumSize( _size ) ;
    qDebug()<<_size<<endl ;
}


MyButton::~MyButton(void) { }


void MyButton::paintEvent(QPaintEvent *) {

    QPixmap pixmap( _size ) ;
    QPainter painter( &pixmap ) ;
    if( _press ){
        painter.setBrush( Qt::yellow) ;
        painter.drawPixmap( QPoint(50,50) , QPixmap("./2.png") ) ;
    }else{
        painter.setBrush( Qt::blue ) ;
        painter.drawPixmap( QPoint(50,50) , QPixmap("./1.png") ) ;
    }
    painter.drawRect(_rect);
    painter.drawText(_rect, _text, QTextOption(Qt::AlignCenter)) ;
    painter.end() ;

    painter.begin(this) ;
    painter.drawPixmap( 0 , 0 , pixmap ) ;
}


void MyButton::mousePressEvent( QMouseEvent *ev) {


    if(_rect.contains(ev->pos())) {
        qDebug()<<"button press" ;
        _press = true ;
        update() ;
    }
}


void MyButton::mouseReleaseEvent( QMouseEvent *ev) {

    if(_rect.contains(ev->pos())) {
        qDebug()<<"rect:"<<_rect<<"---pos:"<<"--size"<<_size<<ev->pos()  ;
        _press = false ;
        update() ;
    }
}

bool MyButton::event( QEvent *ev ) {

    ev->ignore();//这个测试qt的事件传递机制,widget中的消息通过event获取,之后再分类转发到相应的函数中,这个event相当于一个总代理。事件的处理有三种情况ignore、accept、reject,分别是告诉父类我对对于这种情况是进行了怎样的处理操作。父类再根据子类做出的动作进行相应的处理。
    return QWidget::event(ev) ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值