1. 程式人生 > >04_Qt的畫筆、作畫和自定義控制元件

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) ;
}