跟我一起学QT4:创建自定义窗口部件

0. 源代码下载

1. 自定义Qt窗口部件

https://github.com/leichaojian/qt/tree/master/Hexspinbox

2. 子类化QWidget

https://github.com/leichaojian/qt/tree/master/IconEditor


1. 自定义Qt窗口部件

1. 主要代码示例

Hexspinbox::Hexspinbox(QWidget *parent) :
    QSpinBox(parent),
    ui(new Ui::Hexspinbox)
{
    setRange(0, 255);
    //接收1~8个字符,每个字符均为十六进制数字
    validator = new QRegExpValidator(QRegExp("[0-9A-Fa-f]{1,8}"), this);
}

//判断输入的结果是否有效
QValidator::State Hexspinbox::validate(QString &text, int &pos) const
{
    return validator->validate(text, pos);
}

//将数值转换为一个字符串
QString Hexspinbox::textFromValue(int value) const
{
    return QString::number(value, 16).toUpper();
}

//将字符串转换为数值
int Hexspinbox::valueFromText(const QString &text) const
{
    bool ok;
    return text.toInt(&ok, 16);
}



2. 程序运行结果


2. 子类化QWidget

1. 主要示例代码

IconEditor::IconEditor(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::IconEditor)
{
    ui->setupUi(this);
    //保留原窗口内容,防止重绘
    setAttribute(Qt::WA_StaticContents);
    //已经设置了窗口的最小大小(窗口可拉伸)
    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

    //画笔的颜色设置为黑色
    curColor = Qt::black;
    //缩放因子设置为8,即每个像素会显示成一个8*8的正方形
    zoom = 8;

    //图标数据初始化为16*16的像素大小和32位的ARGB颜色格式
    image = QImage(16, 16, QImage::Format_ARGB32);
    //类似于RGB(0,0,0)的数据格式
    image.fill(qRgba(0, 0, 0, 0));
}

IconEditor::~IconEditor()
{
    delete ui;
}

QSize IconEditor::sizeHint() const
{
    //缩放因子*像素大小 = 窗口部件的理想大小
    QSize size = zoom * image.size();
    //如果缩放因子大于3,则增加一个额外的像素,用来容纳网格线
    if (zoom >= 3) {
        size += QSize(1, 1);
    }
    return size;
}

void IconEditor::setpenColor(const QColor &newColor)
{
    curColor = newColor;
}

//编辑图像
void IconEditor::seticonImage(const QImage &newImage)
{
    if (newImage != image) {
        image = newImage.convertToFormat(QImage::Format_ARGB32);
        //update会强制使用新的图像重绘窗口部件
        update();
        //通知窗口布局,窗口部件的大小已经改变了
        updateGeometry();
    }
}

//设置图像的缩放因子
void IconEditor::setzoomFactor(int newZoom)
{
    if (newZoom < 1) {
        newZoom = 1;
    }
    if (newZoom != zoom) {
        zoom = newZoom;
        update();
        updateGeometry();
    }
}

void IconEditor::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    //缩放因子大于3的情况下,重新画网格
    if (zoom >= 3) {
        //窗口部件的调色板palette
        painter.setPen(palette().foreground().color());
        for (int i = 0; i <= image.width(); ++i) {
            painter.drawLine(zoom * i, 0,
                             zoom * i, zoom * image.height());
        }
        for (int j = 0; j <= image.height(); ++j) {
            painter.drawLine(0, zoom * j,
                             zoom * image.width(), zoom * j);
        }
    }

    for (int i = 0; i < image.width(); ++i) {
        for (int j = 0; j < image.height(); ++j) {
            //返回像素坐标
            QRect rect = pixelRect(i, j);
            //绘制窗口颜色为白色
            if (!event->region().intersected(rect).isEmpty()) {
                QColor color = QColor::fromRgba(image.pixel(i, j));
                if (color.alpha() < 255) {
                    painter.fillRect(rect, Qt::white);
                }
                painter.fillRect(rect, color);
            }
        }
    }
}

QRect IconEditor::pixelRect(int i, int j) const
{
    if (zoom >= 3) {
        return QRect(zoom * i + 1, zoom * j + 1, zoom - 1, zoom - 1);
    } else {
        return QRect(zoom * i, zoom * j, zoom, zoom);
    }
}
void IconEditor::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        //把鼠标选中的像素设置成当前画笔的颜色
        setImagePixel(event->pos(), true);
    } else if (event->button() == Qt::RightButton) {
        //通过传递false,来清空这个像素
        setImagePixel(event->pos(), false);
    }
}

void IconEditor::mouseMoveEvent(QMouseEvent *event)
{
    if (event->button() & Qt::LeftButton) {
        //鼠标选中后连续的设置像素
        setImagePixel(event->pos(), true);
    } else if (event->button() & Qt::RightButton) {
        //鼠标选中后连续的清空像素
        setImagePixel(event->pos(), false);
    }
}

void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
{
    //这里必须除以zoom,因为image.rect()是返回格子范围16*16,而pos则为像素的范围,存在缩放因子,所以扩大了zoom倍
    int i = pos.x() / zoom;
    int j = pos.y() / zoom;

    if (image.rect().contains(i, j)) {
        if (opaque) {
            //设定一个像素
            image.setPixel(i, j, penColor().rgba());
        } else {
            //清除一个像素
            image.setPixel(i, j, qRgba(0, 0, 0, 0));
        }
        update(pixelRect(i, j));
    }
}



2. 程序运行结果

转载于:https://my.oschina.net/voler/blog/345133

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值