• Subclassing QWidget


    iconeditor.h
     1 #ifndef ICONEDITOR_H
     2 #define ICONEDITOR_H
     3 
     4 #include <QColor>
     5 #include <QImage>
     6 #include <QWidget>
     7 
     8 class IconEditor : public QWidget
     9 {
    10     Q_OBJECT
    11     Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
    12     Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
    13     Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)
    14 
    15 public:
    16     IconEditor(QWidget *parent = 0);
    17 
    18     void setPenColor(const QColor &newColor);
    19     QColor penColor() const { return curColor; }
    20     void setZoomFactor(int newZoom);
    21     int zoomFactor() const { return zoom; }
    22     void setIconImage(const QImage &newImage);
    23     QImage iconImage() const { return image; }
    24     QSize sizeHint() const;
    25 
    26 protected:
    27     void mousePressEvent(QMouseEvent *event);
    28     void mouseMoveEvent(QMouseEvent *event);
    29     void paintEvent(QPaintEvent *event);
    30 
    31 private:
    32     void setImagePixel(const QPoint &pos, bool opaque);
    33     QRect pixelRect(int i, int j) const;
    34 
    35     QColor curColor;
    36     QImage image;
    37     int zoom;
    38 };
    39 #endif

      Q_PROPERTY宏声明三个自定义属性:penColor,iconImage,zoomFactor。每一个属性都有一个数据类型,一个“读”函数,和一个可以选的“写”函数。比如:penColor类型是QColor,可以用penColor()和setPenColor函数进行读写。

    Q_PROPERTY(...)被用在类中声明继承自QObject的属性。这些属性就像类的数据成员一样,但是他们通过Meta-Object System具有附加的特性。

     Q_PROPERTY(type name
                READ getFunction
                [WRITE setFunction]
                [RESET resetFunction]
                [NOTIFY notifySignal]
                [DESIGNABLE bool]
                [SCRIPTABLE bool]
                [STORED bool]
                [USER bool]
                [CONSTANT]
                [FINAL])
    
    
    属性名字、类型和READ函数是必须的。类型可以是任何QVariant支持的类型,或用户自定义类型。其他项是可选的,但是通常都有WRITE函数。这些属性的默认值都为true,除了USER是false。

    The Meta-Object System

    Meta-Object系统基于以下三点:

    1、QObject类为目标类提供基类以支持这个目标类利用Meta-Object系统。

    2、类声明中必须有O_OBJECT宏,使能Meta-Object的属性,如:动态属性、信号、槽。

    3、Meta-Object Compiler(moc)为每个QObject的子类华提供必要代码以实现meta-object特性。

      IconEditor重实现了三个QWidget的protected function:mousePressEven,mouseMoveEvent,paintEvent。 三个私有变量保存前面定义的三个属性的值。

    iconeditor.cpp
     1 #include <QtGui>
     2 
     3 #include "iconeditor.h"
     4 
     5 IconEditor::IconEditor(QWidget *parent)
     6     : QWidget(parent)
     7 {
     8     setAttribute(Qt::WA_StaticContents);
     9     setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    10 
    11     curColor = Qt::black;
    12     zoom = 8;
    13 
    14     image = QImage(16, 16, QImage::Format_ARGB32);
    15     image.fill(qRgba(0, 0, 0, 0));
    16 }

      pen color设为黑色,zoom设为8,意味着在icon中每个像素为8X8的正方形。

      icon数据保存在i,mage成员变量中,可以通过setIconImage()、iconImage()函数访问。一个icon编辑程序通常在打开一个icon文件时调用setIconImage(),在保存时调用iconImage()去读回icon(原句retrieve the icon)。

      QImage可以把图像存为1-bit,8-bit,32-bit depth。 32位用8位分别表示红、绿、蓝,剩下的8位表示透明度。比如纯红色:255,0,0,255。

    QRgb red = qRgba(255, 0, 0, 255);

    或者颜色为不透明的

    QRgb red = qRgb(255, 0, 0);

    QRgb即是unsigned int, qRgb() 和 qRgb()都是用来把它们组成一个32位的ARGB整数值的内嵌函数。也可以写成如下形式:

    QRgb red = 0xFFFF0000;

    Qt提供QRgb 和QColor两种类型存储颜色。但是QRgb只用在QImage中存储32位像素的别名,QColor用途则更广泛。

    iconeditor.cpp
     1 QSize IconEditor::sizeHint() const
     2 {
     3     QSize size = zoom * image.size();
     4     if (zoom >= 3)
     5         size += QSize(1, 1);
     6     return size;
     7 }
     8 
     9 void IconEditor::setPenColor(const QColor &newColor)
    10 {
    11     curColor = newColor;
    12 }
    13 
    14 void IconEditor::setIconImage(const QImage &newImage)
    15 {
    16     if (newImage != image) {
    17         image = newImage.convertToFormat(QImage::Format_ARGB32);
    18         update();
    19         updateGeometry();
    20     }
    21 }
    22 
    23 void IconEditor::setZoomFactor(int newZoom)
    24 {
    25     if (newZoom < 1)
    26         newZoom = 1;
    27 
    28     if (newZoom != zoom) {
    29         zoom = newZoom;
    30         update();
    31         updateGeometry();
    32     }
    33 }

    sizeHint()是从QWidget中重新实现的。用图像的大小乘以缩放因子作为窗口部件的理想大小,如果缩放因子大于等于3,则向每个方向增加一个像素,以容纳网格线(如果是2或1则网络线会占据大部分空间,以至像素可以忽略)。
    QWidget::update() 使用新的图像强制重绘这个窗口部件,但是这个函数不立即重绘,而是产生一人下paint event ,让Qt返回主事件循环时执行。

    QWidget::updateGeometry()告诉包含这个窗口部件的任意布局,这个窗口大小已经改变。

    iconeditor.cpp
     1 void IconEditor::paintEvent(QPaintEvent *event)
     2 {
     3     QPainter painter(this);
     4     if (zoom >= 3) {
     5         painter.setPen(palette().foreground().color());
     6         for (int i = 0; i <= image.width(); ++i)
     7             painter.drawLine(zoom * i, 0,
     8                              zoom * i, zoom * image.height());
     9         for (int j = 0; j <= image.height(); ++j)
    10             painter.drawLine(0, zoom * j,
    11                              zoom * image.width(), zoom * j);
    12     }
    13     for (int i = 0; i < image.width(); ++i) {
    14         for (int j = 0; j < image.height(); ++j) {
    15             QRect rect = pixelRect(i, j);
    16             if (!event->region().intersect(rect).isEmpty()) {
    17                 QColor color = QColor::fromRgba(image.pixel(i, j));
    18                 if (color.alpha() < 255)
    19                     painter.fillRect(rect, Qt::white);
    20                 painter.fillRect(rect, color);
    21             }
    22         }
    23     }
    24 }
    25 
    26 QRect IconEditor::pixelRect(int i, int j) const
    27 {
    28     if (zoom >= 3) {
    29         return QRect(zoom * i + 1, zoom * j + 1, zoom - 1, zoom - 1);
    30     } else {
    31         return QRect(zoom * i, zoom * j, zoom, zoom);
    32     }
    33 }

    Qt中很多情况下都会产生绘制事件,调用paintEvent()函数:

    1.         当控件第一次显示时,Qt自动产生绘制事件强制控件绘制自身。
    2.         当控件尺寸发生变化时,系统产生绘制事件
    3.         如果控件被其他的窗口遮住,窗口移走再现时,产生绘制被遮住部分的事件。

    一个窗口部件的调色板由三个颜色组构成:Active, Inactive, Disabled 

    Active 可用于当前激活窗口中的那些窗口部件。

    Inactive可用于其他窗口中的那些窗口头部件。

    Disabled可用于任意窗口中的那些不可用的窗口部件。

    QWidgt::paletet()函数返回窗口部件的调色板,它是一个QPalette型对象。

    foreground()是Qt3支持的QColorGroup成员,QPalette::foreground()返回一个画笔。

    IconEditor::pixelRect()返回一个QRect,其中定义了需要重新绘制的区域。

    const QRegion & QPaintEvent::region() const返回一个需要更新的区域。

    QRegion QRegion::intersect ( const QRegion & r ) const

    intersect()是QRegion废弃的成员,新的为:

    QRegion QRegion::intersected ( const QRect & rect ) const

    返回该区域与给定Rect相交的部分。

    bool QRegion::isEmpty () const

    QRegion r1(10, 10, 20, 29);

    r1.isEmpty();                             //false

    QRegion r3;

    r3.isEmpty();          // true

    QRegionr2(40, 40, 20, 20);

    r3 = r1.intersected(r2);      //r3: intersection(交叉) of r1 and r2

    r3.isEmpty();          //false

    r3 = r1.united(r2);       // r3:union of r1 and r2

    r3.isEmpty();          /false

    QColor QColor::fromRgba ( QRgb rgba ) [static]

    把rgba值变成QColor ,QRgb QImage::piixel(const QPoint & position) const 返回给定位置像素的颜色,如果该位置无效,则返回值未定义。

    void QPainter::fillRect ( const QRectF & rectangle, const QBrush & brush )

    用指定的brush填充指定的区域。painter.fillRect(rect,color);即是将载入的图像画在窗口部件指定区域上。

       综上所述,只需要void IconEditor::setIconImage(const QImage &newImage);    void paintEvent(QPaintEvent *event);   QRect pixelRect(inti, intj) const; 就可以把":/images/mouse.png"显示在窗口部件上:

      1、main函数中调用 setIconImage()载入图片。

      2、在第一次显示窗口时产生paint event。

      3、主程序循环时,处理paint event,调用paintEvent()绘图(在这个函数中用到pixelRect()定位要绘制的区域)。

    iconeditor.cpp
     1 void IconEditor::mousePressEvent(QMouseEvent *event)
     2 {
     3     if (event->button() == Qt::LeftButton) {
     4         setImagePixel(event->pos(), true);
     5     } else if (event->button() == Qt::RightButton) {
     6         setImagePixel(event->pos(), false);
     7     }
     8 }
     9 
    10 void IconEditor::mouseMoveEvent(QMouseEvent *event)
    11 {
    12     if (event->buttons() & Qt::LeftButton) {
    13         setImagePixel(event->pos(), true);
    14     } else if (event->buttons() & Qt::RightButton) {
    15         setImagePixel(event->pos(), false);
    16     }
    17 }
    18 
    19 void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
    20 {
    21     int i = pos.x() / zoom;
    22     int j = pos.y() / zoom;
    23 
    24     if (image.rect().contains(i, j)) {
    25         if (opaque) {
    26             image.setPixel(i, j, penColor().rgba());
    27         } else {
    28             image.setPixel(i, j, qRgba(0, 0, 0, 0));
    29         }
    30         update(pixelRect(i, j));
    31     }
    32 }

      以上三个函数用于响应鼠标事件,用鼠标绘制图

    main.cpp
     1 #include <QApplication>
     2 
     3 #include "iconeditor.h"
     4 
     5 int main(int argc, char *argv[])
     6 {
     7     QApplication app(argc, argv);
     8     IconEditor iconEditor;
     9     iconEditor.setWindowTitle(QObject::tr("Icon Editor"));
    10     iconEditor.setIconImage(QImage(":/images/mouse.png"));
    11     iconEditor.show();
    12     return app.exec();
    13 }

     

     

  • 相关阅读:
    多按键设计的标准思路
    与,非,或门总结
    i2c中应答信号信号总结
    i2c中start和restart的区别
    poj 1631 Bridging signals
    poj 2533 Longest Ordered Subsequence
    poj 1887 Testing the CATCHER
    poj 1088 滑雪
    poj 1014 Dividing
    babel转码时generator的regeneratorRuntime
  • 原文地址:https://www.cnblogs.com/lucheng/p/2820756.html
Copyright © 2020-2023  润新知