学习自定义Widget组件,书中的案例:
// 自定义QmyBattery组件
// QmyBattery.c++
#include "qmybattery.h"
QmyBattery::QmyBattery(QWidget *parent) : QWidget(parent)
{
}
/*
* 1.QPainter的viewport()与window()分别代表着物理坐标与逻辑坐标区域,默认两个区域是重合的,也就是用户指定的rect区域在两者上是同样的大小、位置。
2.setWindow()可以设置你想指定的rect区域,比如rect=(-50,-50,100,100),此时你定义的逻辑区域左上坐标(-50,-50),右下坐标(50,50),大小(100X100),
最重要的是QPainter的drawLine、drawRect或者其它draw操作都是以这个逻辑坐标区域为准来绘制图像的,也就是此时的坐标系原点(0,0)就是(-50,-50)了。
3.SetViewport()设置的是物理坐标区域,它代表着实际显示的区域,切记这只是用户规定的画图区域而不是画图的坐标直接以它为准,你画的图像还是以window()
区域的坐标系为准,最终是要将winodw()逻辑区域映射到viewport()物理区域的,这样以后在使用QPainter进行绘制图形时就可以通过设置这两个方法去放大、
平移图像了,比如保持window()逻辑坐标不变,将viewport()物理坐标区域大小变为之前的2倍,那么实际显示的图像也会自动放大2倍了,至于平移也差不多,我懒得算了。
*/
void QmyBattery::paintEvent(QPaintEvent *event) {
Q_UNUSED(event)
QPainter painter(this);// 画家
qDebug() << "width = "< mWarnLevel) {
brush.setColor(mColorPower);
pen.setColor(mColorPower);
} else {
brush.setColor(mColorWarning);
pen.setColor(mColorWarning);
}
painter.setBrush(brush);
painter.setPen(pen);
if (mPowerLevel > 0) {
rect.setRect(5,5,mPowerLevel,40);
painter.drawRect(rect);
}
QFontMetrics textSize(this->font());
QString powStr = QString::asprintf("%d%%",mPowerLevel);
QRect textRect = textSize.boundingRect(powStr);
painter.setFont(this->font());
pen.setColor(mColorBorder);
painter.setPen(pen);
painter.drawText(55-textRect.width()/2,23+textRect.height()/2,powStr);
}
void QmyBattery::setPowerLevel(int power) {
mPowerLevel = power;
emit powerLevelChanged(power);
repaint();
}
int QmyBattery::powerLevel() {
return mPowerLevel;
}
void QmyBattery::setWarnLevel(int warn) {
mWarnLevel = warn;
repaint();
}
int QmyBattery::warnLevel() {
return mWarnLevel;
}
QSize QmyBattery::siezeHint() {
int H = this->height();
int W = H *12/5;
QSize size(W,H);
return size;
}
// QmyBattery.h
#ifndef QMYBATTERY_H
#define QMYBATTERY_H
#include
#include
#include
class QmyBattery : public QWidget
{
Q_OBJECT
private:
QColor mColorBack = Qt::white;
QColor mColorBorder = Qt::black;
QColor mColorPower = Qt::green;
QColor mColorWarning = Qt::red;
int mPowerLevel = 60;
int mWarnLevel = 20;
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
public:
explicit QmyBattery(QWidget *parent = nullptr);
void setPowerLevel(int power);
int powerLevel();
void setWarnLevel(int warn);
int warnLevel();
QSize siezeHint();
signals:
void powerLevelChanged(int);
public slots:
};
#endif // QMYBATTERY_H
// 使用 MainWindow.c++
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->battery->setPowerLevel(10);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_slider_valueChanged(int value){
qDebug() << "value = " <battery->setPowerLevel(value);
}
效果图:
二、创建动态库
1、创建工程
(1)
(2)
(3)创建工程名称mySharedLib,选择工程路径。
(4 )添加类名称,我的为QmyBattery选择类型。选择模块为Widgets。动态库选择:
静态库选择:
工程新建成功之后,工程目录如下:
2、自动生成的.pro文件如下:
QT += widgets
TARGET = mySharedLib
TEMPLATE = lib
DEFINES += MYSHAREDLIB_LIBRARY
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
qmybattery.cpp
HEADERS += \
mySharedLib_global.h \
qmybattery.h
# Default rules for deployment.
unix {
target.path = /usr/lib
}
!isEmpty(target.path): INSTALLS += target
3、添加代码,完成qmybattery.cpp,qmybattery.h文件。
// qmybattery.cpp
#include "qmybattery.h"
QmyBattery::QmyBattery(QWidget *parent) : QWidget(parent)
{
}
/*
* 1.QPainter的viewport()与window()分别代表着物理坐标与逻辑坐标区域,默认两个区域是重合的,也就是用户指定的rect区域在两者上是同样的大小、位置。
2.setWindow()可以设置你想指定的rect区域,比如rect=(-50,-50,100,100),此时你定义的逻辑区域左上坐标(-50,-50),右下坐标(50,50),大小(100X100),
最重要的是QPainter的drawLine、drawRect或者其它draw操作都是以这个逻辑坐标区域为准来绘制图像的,也就是此时的坐标系原点(0,0)就是(-50,-50)了。
3.SetViewport()设置的是物理坐标区域,它代表着实际显示的区域,切记这只是用户规定的画图区域而不是画图的坐标直接以它为准,你画的图像还是以window()
区域的坐标系为准,最终是要将winodw()逻辑区域映射到viewport()物理区域的,这样以后在使用QPainter进行绘制图形时就可以通过设置这两个方法去放大、
平移图像了,比如保持window()逻辑坐标不变,将viewport()物理坐标区域大小变为之前的2倍,那么实际显示的图像也会自动放大2倍了,至于平移也差不多,我懒得算了。
*/
void QmyBattery::paintEvent(QPaintEvent *event) {
Q_UNUSED(event)
QPainter painter(this);// 画家
qDebug() << "width = "< mWarnLevel) {
brush.setColor(mColorPower);
pen.setColor(mColorPower);
} else {
brush.setColor(mColorWarning);
pen.setColor(mColorWarning);
}
painter.setBrush(brush);
painter.setPen(pen);
if (mPowerLevel > 0) {
rect.setRect(5,5,mPowerLevel,40);
painter.drawRect(rect);
}
QFontMetrics textSize(this->font());
QString powStr = QString::asprintf("%d%%",mPowerLevel);
QRect textRect = textSize.boundingRect(powStr);
painter.setFont(this->font());
pen.setColor(mColorBorder);
painter.setPen(pen);
painter.drawText(55-textRect.width()/2,23+textRect.height()/2,powStr);
}
void QmyBattery::setPowerLevel(int power) {
mPowerLevel = power;
emit powerLevelChanged(power);
repaint();
}
int QmyBattery::powerLevel() {
return mPowerLevel;
}
void QmyBattery::setWarnLevel(int warn) {
mWarnLevel = warn;
repaint();
}
int QmyBattery::warnLevel() {
return mWarnLevel;
}
QSize QmyBattery::siezeHint() {
int H = this->height();
int W = H *12/5;
QSize size(W,H);
return size;
}
// qmybattery.h
#ifndef QMYBATTERY_H
#define QMYBATTERY_H
#include
#include
#include
#include "mySharedLib_global.h"
class MYSHAREDLIB_EXPORT QmyBattery: public QWidget
{
Q_OBJECT
private:
QColor mColorBack = Qt::white;
QColor mColorBorder = Qt::black;
QColor mColorPower = Qt::green;
QColor mColorWarning = Qt::red;
int mPowerLevel = 60;
int mWarnLevel = 20;
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
public:
explicit QmyBattery(QWidget *parent = nullptr);
void setPowerLevel(int power);
int powerLevel();
void setWarnLevel(int warn);
int warnLevel();
QSize siezeHint();
signals:
void powerLevelChanged(int);
public slots:
};
#endif // QMYBATTERY_H
3、构建生成so文件。
三、使用动态库
1、新建一个工程useShare。
2、把so文件及.h文件拷贝到工程下。注意去掉so后面的1.0.0
3、添加库
(1)
(2)
(3)我是将程序运行到板子里,所以选linux
添加完成后.pro文件:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
unix:!macx: LIBS += -L$$PWD/./ -lmySharedLib
INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.
4、添加.h文件。只选择qmybattery.h文件。
5、加载QmyBatter组件。
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QmyBattery *battery = new QmyBattery(this);
battery->setParent(this);
battery->move(100,100);
battery->show();
battery->setPowerLevel(50);
}
MainWindow::~MainWindow()
{
delete ui;
}
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include "qmybattery.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
编译运行代码。因为程序在板子里面运行需要把libmySharedLib.so.1.0.0文件push到板子/usr/lib路径下。
静态库的生成和使用 比较简单。不做记录。