第五章 创建自定义窗口部件

对已经存在的Qt窗口进行子类化或者直接对QWidget子类化可以快速创建自己的自定义窗口部件。


一、自定义窗口部件 十六进制的QSpinBox 

本来QSpinBox仅支持十进制数据的,现在子类化接收并显示十六进制数值。

头文件

hexspinbox.h

#ifndef HEXSPINBOX_H
#define HEXSPINBOX_H

#include <QSpinBox>

class QRegExpValidator;

class HexSpinBox : public QSpinBox
{
	Q_OBJECT

public:
	HexSpinBox(QWidget *parent = 0);

protected:
	QValidator::State validate(QString &text, int &pos) const;
	int valueFromText(const QString &text) const;
	QString textFromValue(int value) const;

private:
	QRegExpValidator *validator;
};

#endif


hexspinbox.cpp

#include <QtGui>

#include "hexspinbox.h"

HexSpinBox::HexSpinBox(QWidget *parent)
	: QSpinBox(parent)
{
	//设置默认接收数据范围
	setRange(0, 255);

	//正则表达式限制接收数据格式为十六进制
	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);
}

int HexSpinBox::valueFromText(const QString &text) const
{
	//数值型字符串转换成整型
	bool ok;
	return text.toInt(&ok, 16);
}

QString HexSpinBox::textFromValue(int value) const
{
	//把一个字符串转换成整数值
	return QString::number(value, 16).toUpper();
}

main.cpp

#include <QApplication>
#include <QHBoxLayout>

#include "hexspinbox.h"

int main(int argc, char *argv[])
{
	QApplication app(argc, argv);
	HexSpinBox spinBox;
	spinBox.setWindowTitle(QObject::tr("Hex Spin Box"));
	spinBox.show();
	return app.exec();
}


二、子类化QWidget (IconEdit鼠标图片编辑控件)

iconEditor.h

#ifndef ICONEDITOR_H
#define ICONEDITOR_H

#include <QColor>
#include <QImage>
#include <QWidget>
#include <QRegion>
class IconEditor : public QWidget
{
    Q_OBJECT
	//定义三个宏,实现三个自定义属性
    Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor)
    Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
    Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)

public:
    IconEditor(QWidget *parent = 0);

    void setPenColor(const QColor &newColor);
    QColor penColor() const { return curColor; }
    void setZoomFactor(int newZoom);
    int zoomFactor() const { return zoom; }
    void setIconImage(const QImage &newImage);
    QImage iconImage() const { return image; }
    QSize sizeHint() const;

protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void paintEvent(QPaintEvent *event);

private:
    void setImagePixel(const QPoint &pos, bool opaque);
    QRect pixelRect(int i, int j) const;

    QColor curColor;
    QImage image;
    int zoom;
};

#endif


iconEditor.cpp

#include <QtGui>
#include "iconeditor.h"

IconEditor::IconEditor(QWidget *parent)
    : QWidget(parent)
{
    setAttribute(Qt::WA_StaticContents);
    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

    curColor = Qt::black;	//画笔颜色
    zoom = 8;				//缩放因子为8

	//加载的图片
    image = QImage(16, 16, QImage::Format_ARGB32);
    image.fill(qRgba(0, 0, 0, 0));
}

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

void IconEditor::setZoomFactor(int newZoom)
{
    if (newZoom < 1)
        newZoom = 1;

    if (newZoom != zoom) {
        zoom = newZoom;
        update();
        updateGeometry();
    }
}

void IconEditor::setIconImage(const QImage &newImage)
{
    if (newImage != image) {
        image = newImage.convertToFormat(QImage::Format_ARGB32);
        update();
        updateGeometry();
    }
}

QSize IconEditor::sizeHint() const
{
	//图片放大
    QSize size = zoom * image.size();
    if (zoom >= 3)
        size += QSize(1, 1);
    return size;
}

void IconEditor::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        setImagePixel(event->pos(), true);
    } else if (event->button() == Qt::RightButton) {
        setImagePixel(event->pos(), false);
    }
}

void IconEditor::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        setImagePixel(event->pos(), true);
    } else if (event->buttons() & Qt::RightButton) {
        setImagePixel(event->pos(), false);
    }
}

void IconEditor::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    if (zoom >= 3) {
        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()./*intersect*/intersected(rect).isEmpty()) {
                QColor color = QColor::fromRgba(image.pixel(i, j));
                if (color.alpha() < 255)
                    painter.fillRect(rect, Qt::white);
                painter.fillRect(rect, color);
            }
        }
    }
}

void IconEditor::setImagePixel(const QPoint &pos, bool opaque)
{
    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));
    }
}

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


update();
强制产生一个绘制事件,repaint()也可以实现重绘功能,但是它是即时绘制,而update是在Qt下一次绘制时才开始,如果下一次绘制前有多个update()则会融合成一个单一的绘制事件,可以避免闪烁。

pos指的是鼠标的实时位置,就可以方便的获取到绘制图形的位置了。


构造函数的这句话是为了控制窗口部件的内容不变,效果如图所示

setAttribute(Qt::WA_StaticContents);

绘制事件的区域会被严格限制在之前没有显示的像素部分上。这就意味即时窗口比内容小也不会触发绘制事件。还挺有意思的诶


三、在Qt Designer中自定义窗口部件

在自定义之前,应该让Qt Designer察觉到他们的存在,改进法和插件法;

改进法比较简单,选择一个内置Qt窗口部件,接口与自己的需求当然类似才好用。

改进法使用方法:

*在Qt Designer 中拖进一个QSpinBox控件;

*右击选择“提升为...”(提升的窗口部件或者成为改进程自定义窗口部件)

*HexSpixBox作为类名,hexspinbox.h作为头文件名

缺点是无法对部件特定的属性进行访问。


插件法:需要创建一个插件库,Qt设计师会在运行时加载这个库,并且可以利用该库创建窗口部件的实例。

首先必须对QDesignerCustomWidgetInterface进行子类化,并且需要重新实现一些虚函数。假设源代码在iconeditorplugin文件夹中,并且IconEdit的源代码放在iconeditorplugin文件夹同一级iconedit目录中。

类定义:

iconeditorplugin.h

#ifndef ICONEDITORPLUGIN_H
#define ICONEDITORPLUGIN_H

#include <QDesignerCustomWidgetInterface>

class IconEditorPlugin : public QObject,
                         public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetInterface)

public:
    IconEditorPlugin(QObject *parent = 0);

    QString name() const;
    QString includeFile() const;
    QString group() const;
    QIcon icon() const;
    QString toolTip() const;
    QString whatsThis() const;
    bool isContainer() const;
    QWidget *createWidget(QWidget *parent);
};

#endif

IconEditorPlugin子类是一个封装了这个IconEdit窗口部件的工厂类。


iconeditorplugin.cpp

#include <QtPlugin>

#include "../iconeditor/iconeditor.h"
#include "iconeditorplugin.h"

IconEditorPlugin::IconEditorPlugin(QObject *parent)
    : QObject(parent)
{
}

QString IconEditorPlugin::name() const
{
    return "IconEditor";
}

QString IconEditorPlugin::includeFile() const
{
    return "iconeditor.h";
}

QString IconEditorPlugin::group() const
{
    return tr("Image Manipulation Widgets");
}

QIcon IconEditorPlugin::icon() const
{
    return QIcon("iconeditor.png");
}

QString IconEditorPlugin::toolTip() const
{
    return tr("An icon editor widget");
}

QString IconEditorPlugin::whatsThis() const
{
    return tr("This widget is presented in Chapter 5 of <i>C++ GUI "
              "Programming with Qt 4</i> as an example of a custom Qt "
              "widget.");
}

bool IconEditorPlugin::isContainer() const
{
    return false;
}

QWidget *IconEditorPlugin::createWidget(QWidget *parent)
{
    return new IconEditor(parent);
}

Q_EXPORT_PLUGIN2(iconeditorplugin, IconEditorPlugin)

QWidget *IconEditorPlugin::createWidget(QWidget *parent)
Qt设计师会调用该函数,利用给定的父对象创建该窗口部件类的一个实例。

Q_EXPORT_PLUGIN2(iconeditorplugin, IconEditorPlugin)
实现该插件类的源文件末尾必须使用该宏,这让他可以在Qt设计师中使用哦~

这一部分还未验证通过,在VS工具中还在研究怎么添加控件到设计师。

不过可以参考http://blog.csdn.net/panshun888/article/details/51923927

学习继续中...




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在PyQt5中嵌入PPT窗口,你可以使用QAxContainer模块来实现。首先,确保已经安装了PyQt5和pywin32模块。 以下是一个简单的示例代码,展示了如何创建一个PyQt5应用程序,并将PPT文件嵌入到窗口中: ```python import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QAxWidget class MainWindow(QMainWindow): def __init__(self): super().__init__() # 创建QAxWidget对象 self.axWidget = QAxWidget(self) self.axWidget.setControl("PowerPoint.Application") # 加载PPT文件 self.axWidget.dynamicCall("SetVisible (bool Visible)", "false") # 隐藏PPT窗口 self.axWidget.setProperty("DisplayAlerts", False) self.axWidget.dynamicCall("SetSlideShowView (int index)", 1) # 设置为幻灯片视图 self.axWidget.dynamicCall("SetCurrentShowPosition (int position)", 1) # 显示第一张幻灯片 # 将QAxWidget对象添加到主窗口 self.setCentralWidget(self.axWidget) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ``` 在这个示例中,我们创建了一个名为MainWindow的自定义窗口类,继承自QMainWindow。在构造函数中,我们创建了一个QAxWidget对象并设置其控制为"PowerPoint.Application",表示要嵌入PowerPoint应用程序。 然后,我们加载PPT文件并设置一些属性,如隐藏PPT窗口、不显示警告信息、设置为幻灯片视图,并显示第一张幻灯片。 最后,我们将QAxWidget对象设置为主窗口的中心部件,并显示主窗口。 请注意,这个示例只是一个简单的演示,你可能需要根据自己的需求进行更多的定制和错误处理。 希望这可以帮助到你!如果有任何问题,请随时问我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值