使用QT开发的一个渐变颜色表控件

最近由于项目要求,需要开发一个渐变颜色表控件,实现曲线按颜色表进行渐变填充,由于在网上找不到合适的现成控件,只好自已造轮子,下图是控件效果。闲暇之余,本人会不定期发布一些自认为较好人自定义控件,请大家关注。

由于本人长期免费使用网络上的现成代码,深感内疚,所以分享本控件,填补我内心深处的愧疚感。以下是本控件的源代码:

colortable.h

#ifndef COLORTABLE_H
#define COLORTABLE_H
#include <QColor>
#include <QJsonArray>

class ColorValue{
public:
    ColorValue(double v, const QColor& c);
    ColorValue(const ColorValue& v);
public:
    ColorValue& operator=(const ColorValue& p);
    double _v;
    QColor _c;
};

class ColorTable
{
public:
    constexpr static const uint MajorVersion = 1;
    ColorTable();
    ColorTable(const QString& name, const QJsonArray& data);
    void setAs(ColorTable* table);
    void reverse();
    static QList<ColorTable*> loadDefaultTables();
    static QColor fromRgbString(const QString& rgbString);//255,255,255
    double minValue() const;
    double maxValue() const;
    double getValueLen();
    bool canDelete(int index);
    int getColor(double v, unsigned char alpha=255);
    QColor getQColor(double v, unsigned char alpha=255);
    qsizetype addValue(const ColorValue& v);
    qsizetype setValue(qsizetype i, const ColorValue& v);
    void delValue(qsizetype i);
    int getargb(double v,  const QColor& c1, const QColor& c2, double v1, double v2, unsigned char alpha=255);
    int getrgba(double v,  const QColor& c1, const QColor& c2, double v1, double v2, unsigned char alpha=255);
    QColor getQColor(double v,  const QColor& c1, const QColor& c2, double v1, double v2, unsigned char alpha=255);

    void save(QDataStream&) const;
    void load(QDataStream&);

    void setUserRange(double min, double max);
    double userMinValue();
    double userMaxValue();
public:
    QList<ColorValue> _colors;
    QString _name;
    bool _isLinearFill;//是线性渐变填充
private:
    double _k;
    double _userMinValue;
    double _userMaxValue;
};

#endif // COLORTABLE_H

colortable.cpp

#include "colortable.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include "Tools.h"

ColorValue::ColorValue(double v, const QColor& c){
    _v=v;
    _c=c;
}

ColorValue::ColorValue(const ColorValue& v){
    _v=v._v;
    _c=v._c;
}

ColorValue& ColorValue::operator=(const ColorValue& p){
    _v=p._v;
    _c=p._c;
    return *this;
}

ColorTable::ColorTable()
{
    _colors.append(ColorValue(0, Qt::white));
    _colors.append(ColorValue(100, Qt::black));
    _name="白-黑";
    _isLinearFill=true;
    _k=1;
    _userMinValue=0;
    _userMaxValue=0;
}

ColorTable::ColorTable(const QString& name, const QJsonArray& data){
    int sz=data.size();
    for(int i=0;i<sz;i++){
        const QJsonValue& v=data.at(i);
        const QJsonObject& obj=v.toObject();

        _colors.append(ColorValue(obj["value"].toDouble(), fromRgbString(obj["color"].toString())));
    }
    _name=name;
    _isLinearFill=true;
    _k=1;
    _userMinValue=0;
    _userMaxValue=0;
}


double ColorTable::userMinValue(){
    if(_userMinValue<_userMaxValue){
        return _userMinValue;
    }

    return minValue();
}
double ColorTable::userMaxValue(){
    if(_userMinValue<_userMaxValue){
        return _userMaxValue;
    }
    return maxValue();
}

void ColorTable::setAs(ColorTable* table){
    _colors = table->_colors;
    _name=table->_name;
}

void ColorTable::setUserRange(double min, double max){

    _userMinValue=min;
    _userMaxValue=max;
    if(_userMaxValue>_userMinValue){
        _k=(maxValue()-minValue())/(_userMaxValue-_userMinValue);
    } else {
        _k=1;
    }
}

void ColorTable::reverse(){
    int l=0;
    int r=_colors.size()-1;
    while(r>l){
        QColor c=_colors[l]._c;
        _colors[l]._c=_colors[r]._c;
        _colors[r]._c=c;
        l++;
        r--;
    }
}

QColor ColorTable::fromRgbString(const QString& rgbString){
    QStringList lst=rgbString.split(',');
    if(lst.size()==3){
        return QColor::fromRgb(lst[0].trimmed().toInt(),lst[1].trimmed().toInt(),lst[2].trimmed().toInt());
    }
    return Qt::white;
}

QList<ColorTable*> ColorTable::loadDefaultTables(){
    QList<ColorTable*> rets;
    QFile file(":/json/colortables");
    if (!file.open(QIODevice::ReadOnly|QIODevice::Text)){
        return rets;
    }
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
    if (error.error!=QJsonParseError::NoError){
        file.close();
        return rets;
    }

    const QJsonObject& root=doc.object();

    const QJsonArray& lists=root["lists"].toArray();

    foreach(const QJsonValue& v,lists){
        const QJsonObject& item=v.toObject();
        const QJsonValue& jsonName=item["name"];
        const QJsonValue& jsonTable=item["table"];
        rets.append(new ColorTable(jsonName.toString(), jsonTable.toArray()));
    }
    file.close();
    return rets;
}


double ColorTable::minValue() const{
    if (_colors.empty()){
        return 0;
    }

    return _colors[0]._v;
}

double ColorTable::maxValue() const{
    if (_colors.empty()){
        return 100;
    }

    return _colors.constLast()._v;
}

QColor ColorTable::getQColor(double v,  const QColor& c1, const QColor& c2, double v1, double v2, unsigned char alpha){
    if (c1==c2||v1==v2){
        return QColor::fromRgb(c1.red(),c1.green(),c1.blue(),alpha);
    }

    qreal k =  (v-v1) / (v2 - v1);
    unsigned char r = (c2.red()-c1.red())*k+c1.red();
    unsigned char g = (c2.green()-c1.green())*k+c1.green();
    unsigned char b = (c2.blue()-c1.blue())*k+c1.blue();
    return QColor::fromRgb(r,g,b,alpha);
}

int ColorTable::getrgba(double v,  const QColor& c1, const QColor& c2, double v1, double v2, unsigned char alpha){
    if (c1==c2||v1==v2){
        return alpha|((c1.rgba())&0xffffff00);
    }

    qreal k =  (v-v1) / (v2 - v1);
    unsigned char r = (c2.red()-c1.red())*k+c1.red();
    unsigned char g = (c2.green()-c1.green())*k+c1.green();
    unsigned char b = (c2.blue()-c1.blue())*k+c1.blue();
    return ((r<<24)&0xff000000)|((g<<16)&0xff0000)|((b<<8)&0xff00)|alpha;
}

int ColorTable::getargb(double v, const QColor& c1, const QColor& c2, double v1, double v2, unsigned char alpha){
    if (c1==c2||v1==v2){
        return (c1.rgb()&0x00ffffff)|((alpha<<24)&0xff000000);
    }

    qreal k =  (v-v1) / (v2 - v1);
    int r = (c2.red()-c1.red())*k+c1.red();
    int g = (c2.green()-c1.green())*k+c1.green();
    int b = (c2.blue()-c1.blue())*k+c1.blue();
    return ((r<<16)&0xff0000)|((g<<8)&0xff00)|(b&0xff)|((alpha<<24)&0xff000000);
}

QColor ColorTable::getQColor(double v, unsigned char alpha){
    double value=(v-_userMinValue)*_k+minValue();
    if(_colors.count()<2){
        return QColor::fromRgb(1,1,1,alpha);
    }
    if (_colors[0]._v>value){
        return QColor::fromRgb(_colors[0]._c.red(),_colors[0]._c.green(),_colors[0]._c.blue(),alpha);
    }
    qsizetype l=0;
    qsizetype r=_colors.count()-2;

    while(r>=l){
        qsizetype mid=(r+l)/2;
        const ColorValue& v=_colors[mid];
        const ColorValue& v1=_colors[mid+1];
        if (v._v<=value && v1._v>=value){
            if (_isLinearFill){
                return getQColor(value, v._c, v1._c, v._v, v1._v, alpha);
            }
            return QColor::fromRgba(alpha|((v._c.rgba())&0xffffff00));
        } else if (v._v<value){
            l=mid+1;
        } else if (v._v>value){
            r=mid-1;
        }
    }
    return QColor::fromRgba(((_colors.last()._c.rgba())&0xffffff00)|alpha);
}

int ColorTable::getColor(double v, unsigned char alpha){
    double value=(v-_userMinValue)*_k+minValue();
    if(_colors.count()<2){
        return 0x00ffffff|((alpha<<24)&0xff000000);
    }
    if (_colors[0]._v>value){
        return (_colors[0]._c.rgb()&0x00ffffff)|((alpha<<24)&0xff000000);
    }
    qsizetype l=0;
    qsizetype r=_colors.count()-2;

    while(r>=l){
        qsizetype mid=(r+l)/2;
        const ColorValue& v=_colors[mid];
        const ColorValue& v1=_colors[mid+1];
        if (v._v<=value && v1._v>=value){
            if (_isLinearFill){
                return getargb(value, v._c, v1._c, v._v, v1._v, alpha);
            }
            return ((alpha<<24)&0xff000000)|(v._c.rgb()&0x00ffffff);
        } else if (v._v<value){
            l=mid+1;
        } else if (v._v>value){
            r=mid-1;
        }
    }
    return (_colors.last()._c.rgb()&0x00ffffff)|((alpha<<24)&0xff000000);
}

bool ColorTable::canDelete(int index){
    return index>0 && index<_colors.size()-1;
}

double ColorTable::getValueLen(){
    if (_colors.count()>=2){
        return _colors.last()._v-_colors.first()._v;
    }
    _colors.clear();
    _colors.append(ColorValue(0, Qt::white));
    _colors.append(ColorValue(100, Qt::black));
    return 100;
}

qsizetype ColorTable::addValue(const ColorValue& v){
    for(int i=0;i<_colors.count();i++){
        if (_colors[i]._v==v._v)return i;
        if (_colors[i]._v>v._v){
            _colors.insert(i,v);
            return i;
        }
    }
    _colors.append(v);
    return _colors.count()-1;
}

void ColorTable::delValue(qsizetype i){
    _colors.removeAt(i);
}

qsizetype ColorTable::setValue(qsizetype i, const ColorValue& v){

    _colors.removeAt(i);
    return addValue(v);
}

void ColorTable::save(QDataStream& stream) const{
    Tools::save(stream, MajorVersion);
    Tools::saveqsizetype(stream,(qint64)_colors.count());
    for(qsizetype i=0;i<_colors.count();i++){
        Tools::save(stream, _colors[i]._c);
        Tools::save(stream, _colors[i]._v);
    }
    Tools::save(stream, _name);
    Tools::save(stream, _isLinearFill);
    Tools::save(stream, _userMinValue);
    Tools::save(stream, _userMaxValue);
}

void ColorTable::load(QDataStream& stream){
    uint major;
    _colors.clear();
    Tools::load(stream,major);
    qsizetype c=Tools::loadqsizetype(stream);
    for(qsizetype i=0;i<c;i++){
        double v;
        QColor c;
        Tools::load(stream, c);
        Tools::load(stream, v);
        _colors.append(ColorValue(v,c));
    }
    Tools::load(stream, _name);
    Tools::load(stream, _isLinearFill);
    Tools::load(stream, _userMinValue);
    Tools::load(stream, _userMaxValue);
    setUserRange(_userMinValue,_userMaxValue);
}

tqrangeeditor.h

#ifndef TQRANGEEDITOR_H
#define TQRANGEEDITOR_H

#include <QWidget>
#include <QLineEdit>
#include <QLabel>
#include <QToolButton>
#include <QCheckBox>
class ColorTable;

class TQRangeEditor : public QWidget
{
    Q_OBJECT
public:
    explicit TQRangeEditor(QWidget *parent = nullptr);

    void setTable(ColorTable* table);
public slots:
    void click();
    void linearFillChanged(bool isChecked);
signals:
    void isDirectChanged(bool isReverse);
    void valueChanged(double min, double max, bool isLinearFill);
    void isLinearFillChanged(bool isChecked);
private:
    QLineEdit *_tbMin;
    QLineEdit *_tbMax;
    QToolButton *_toolConfirm;
    QCheckBox *_cbIsLinearFill;
    bool _isInit;
};

#endif // TQRANGEEDITOR_H

tqrangeeditor.cpp

#include "tqrangeeditor.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include "tqalert.h"
#include "colortable.h"

TQRangeEditor::TQRangeEditor(QWidget *parent)
    : QWidget{parent}
{
    QHBoxLayout* layout=new QHBoxLayout;
    _tbMin=new QLineEdit();
    _tbMax=new QLineEdit();
    _toolConfirm=new QToolButton;
    _toolConfirm->setAutoRaise(true);
    _cbIsLinearFill=new QCheckBox(tr("渐变填充"));
    _toolConfirm->setIcon(QIcon(":/icons/accept"));
    QLabel *l=new QLabel("-");
    QLabel *t=new QLabel("值范围");

    layout->addWidget(t);
    layout->addWidget(_tbMin);
    layout->addWidget(l);
    layout->addWidget(_tbMax);
    layout->addWidget(_toolConfirm);

    QWidget *line0=new QWidget;
    line0->setLayout(layout);

    QVBoxLayout *vLayout=new QVBoxLayout;
    vLayout->addWidget(line0);
    vLayout->addWidget(_cbIsLinearFill);
    QCheckBox* cbReverse=new QCheckBox(tr("转换方向"));
    vLayout->addWidget(cbReverse);

    connect(cbReverse, &QCheckBox::toggled, this, [this](bool isReverse){
        emit isDirectChanged(isReverse);
    });

    this->setLayout(vLayout);

    connect(_toolConfirm,SIGNAL(clicked()), this, SLOT(click()));
    connect(_cbIsLinearFill,SIGNAL(toggled(bool)),this,SLOT(linearFillChanged(bool)));
}

void TQRangeEditor::setTable(ColorTable* table){
    _isInit=true;
    _tbMin->setText(QString::asprintf("%.2f", table->userMinValue()));
    _tbMax->setText(QString::asprintf("%.2f", table->userMaxValue()));
    _cbIsLinearFill->setCheckState(table->_isLinearFill?Qt::Checked:Qt::Unchecked);
    _isInit=false;
}

void TQRangeEditor::linearFillChanged(bool isChecked){
    if(_isInit){
        return;
    }

    emit isLinearFillChanged(isChecked);
}

void TQRangeEditor::click(){
    bool bOK;
    double min=_tbMin->text().toDouble(&bOK);
    if(!bOK){
        TQAlert::information(tr("请输入正确的最小值."));
        return;
    }
    double max=_tbMax->text().toDouble(&bOK);
    if(!bOK){
        TQAlert::information(tr("请输入正确的最大值."));
        return;
    }

    if(max<=min){
        TQAlert::information(tr("最大值必须大于最小值."));
        return;
    }

    emit valueChanged(min,max,_cbIsLinearFill->checkState()==Qt::Checked);
}

dialogcolorvalue.h

#ifndef DIALOGCOLORVALUE_H
#define DIALOGCOLORVALUE_H

#include <QDialog>
#include "../TitleDrawer/colortable.h"

namespace Ui {
class DialogColorValue;
}

class DialogColorValue : public QDialog
{
    Q_OBJECT

public:
    explicit DialogColorValue(QWidget *parent = nullptr);
    ~DialogColorValue();
    void setColorValue(int index, const ColorValue& v, bool canDel);
    ColorValue colorValue();
signals:
    void onColorChanged(int index, const ColorValue& newValue);
    void onColorDeleted(int index);
private slots:
    void on_etValue_textChanged(const QString &arg1);
    void on_tqFillColor_colorChanged(const QColor& oldColor, const QColor& newColor);
    void on_btDelete_clicked();

protected:
    void accept() override;
private:
    Ui::DialogColorValue *ui;
    bool _isInit;
    int _index;
};

#endif // DIALOGCOLORVALUE_H

dialogcolorvalue.cpp

#include "dialogcolorvalue.h"
#include "ui_dialogcolorvalue.h"
#include "tqconfirm.h"

DialogColorValue::DialogColorValue(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogColorValue)
{
    _isInit=true;
    ui->setupUi(this);
    this->setWindowTitle(tr("颜色设置"));
    this->setWindowIcon(QIcon(":/images/logo"));

    ui->tqFillColor->setSelectColorMode(TQColorComboBox::Click);
    ui->tqFillColor->setDisplayMode(TQColorComboBox::Brush);
    _isInit=false;
}

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

void DialogColorValue::accept(){
    emit onColorChanged(_index, colorValue());
    done(Accepted);
}

void DialogColorValue::setColorValue(int index, const ColorValue& v, bool canDel){
    _isInit=true;
    ui->etValue->setText(QString::asprintf("%.6f",v._v));
    ui->tqFillColor->setCurrentColor(v._c);
    ui->btDelete->setVisible(canDel);
    _index=index;
    _isInit=false;
}

ColorValue DialogColorValue::colorValue(){
    return ColorValue(ui->etValue->text().toDouble(), ui->tqFillColor->currentColor());
}

void DialogColorValue::on_tqFillColor_colorChanged(const QColor& oldColor, const QColor& newColor){
    emit onColorChanged(_index, colorValue());
}


void DialogColorValue::on_etValue_textChanged(const QString &arg1)
{
    if(_isInit)return;
    emit onColorChanged(_index, colorValue());
}


void DialogColorValue::on_btDelete_clicked()
{
    if (TQConfirm::confirm(tr("确认要删除当前颜色值吗?"))){
        emit onColorDeleted(_index);
        done(Accepted);
    }
}

colortableeditor.h

#ifndef COLORTABLEEDITOR_H
#define COLORTABLEEDITOR_H

#include <QWidget>
#include <QMenu>
class ColorTable;
class ColorValue;
class DialogColorValue;
class TQRangeEditor;
class ColorTableEditor : public QWidget
{
    Q_OBJECT
public:
    explicit ColorTableEditor(QWidget *parent = nullptr);
    ~ColorTableEditor();
    void setColorTable(ColorTable* table);
    QRectF displayArea();
    QRectF downArrowArea();
    QRectF downArrowHitArea();
    void setControlButtonSize(qreal w, qreal h);
protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mouseDoubleClickEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void paintEvent(QPaintEvent *event) override;
    void drawControl(QPainter *painter, ColorValue* value,  double minValue, const QRectF& rc, double tableLen, QList<QLineF>& lines);
    QPolygonF controlArea(ColorValue* value,  double minValue, const QRectF& rc, double tableLen);
    void drawTrig(QPainter* painter);
signals:
    void onValueChanged();
    void onUserRangeChanged();
    void onFillTypeChanged();
private slots:
    void onColorDeleted(int index);
    void onDirectChanged(bool isReverse);
    void onColorChanged(int index, const ColorValue& value);
    void rangeValueChanged(double min, double max, bool isLinearFill);
    void isLinearFillChanged(bool isLinearFill);
private:
    ColorTable* _table;
    qreal _downArrowWidth;
    qreal _controlWidth;
    qreal _controlHeight;
    QPointF _ptMouse;
    qsizetype _currentIndex;
    bool _bMousePressing;
    bool _bMouseMoving;
    DialogColorValue *_dlgColor;
    QMenu _menu;
    TQRangeEditor *_rgEditor;
    bool _isReverse;
};

#endif // COLORTABLEEDITOR_H

colortableeditor.cpp

#include "colortableeditor.h"
#include "colortable.h"
#include "dialogcolorvalue.h"
#include <QPainter>
#include <QLinearGradient>
#include <QMouseEvent>
#include <QWidgetAction>
#include <QGridLayout>
#include "tqrangeeditor.h"
#include "tqcolortableviewer.h"
#include <QPushButton>

ColorTableEditor::ColorTableEditor(QWidget *parent)
    : QWidget{parent}
{
    _table=nullptr;
    _controlWidth=10;
    _downArrowWidth=10;
    _controlHeight=15;
    _currentIndex=-1;
    _bMousePressing=false;
    this->setMouseTracking(true);
    _dlgColor=nullptr;

    QList<ColorTable*> rets=ColorTable::loadDefaultTables();

    QGridLayout *pGridLayout = new QGridLayout;
    pGridLayout->setAlignment(Qt::AlignCenter);
    pGridLayout->setContentsMargins(0, 0, 0, 0);
    pGridLayout->setSpacing(2);

    for(int i=0;i<rets.size();i++){
        int row=i/3;
        int col=i%3;
        TQColorTableViewer* viewer=new TQColorTableViewer();
        viewer->setColorTable(rets[i]);
        viewer->setFixedSize(70,18);

        pGridLayout->addWidget(viewer,row,col);
        connect(viewer,&TQColorTableViewer::clickColorTable,this,[this](ColorTable* table){
            if (_table!=nullptr){
                _table->setAs(table);
                if(_isReverse){
                    _table->reverse();
                }
                emit onValueChanged();
                update();
            }
        });
    }

    QWidget *widget = new QWidget;
    widget->setLayout(pGridLayout);

    _rgEditor=new TQRangeEditor;

    QVBoxLayout *pVLayout = new QVBoxLayout;
    pVLayout->addWidget(widget);
    pVLayout->addWidget(_rgEditor);
    pVLayout->setContentsMargins(0, 5, 0, 0);
    pVLayout->setSpacing(2);

    connect(_rgEditor, &TQRangeEditor::valueChanged, this, &ColorTableEditor::rangeValueChanged);
    connect(_rgEditor, &TQRangeEditor::isLinearFillChanged, this, &ColorTableEditor::isLinearFillChanged);
    connect(_rgEditor, &TQRangeEditor::isDirectChanged, this, &ColorTableEditor::onDirectChanged);
    _menu.setLayout(pVLayout);

    _isReverse=false;
}


ColorTableEditor::~ColorTableEditor(){
    disconnect();
    if(_dlgColor!=nullptr){
        _dlgColor->disconnect();
        delete _dlgColor;
    }
}

void ColorTableEditor::onDirectChanged(bool isReverse){
    if (_table!=nullptr){
        _table->reverse();
        _isReverse=isReverse;
        emit onValueChanged();
        update();
    }
}

void ColorTableEditor::isLinearFillChanged(bool isLinearFill){
    if (_table!=nullptr){
        _table->_isLinearFill=isLinearFill;
        emit onFillTypeChanged();
        update();
    }
}

void ColorTableEditor::rangeValueChanged(double min, double max, bool isLinearFill){
    if (_table!=nullptr){
        _table->setUserRange(min,max);
        emit onUserRangeChanged();
        update();
    }
}

void ColorTableEditor::setColorTable(ColorTable* table){
    _table=table;
    _rgEditor->setTable(table);
}

QPolygonF ColorTableEditor::controlArea(ColorValue* value,  double minValue, const QRectF& rc, double tableLen){
    qreal x=rc.left()+rc.width()*(value->_v-minValue)/tableLen;
    qreal y=rc.top();
    QPolygonF p;
    qreal w=_controlWidth/2.0;
    p.append(QPointF(x,y));
    p.append(QPointF(x-w,y-w));
    p.append(QPointF(x-w,y-_controlHeight));
    p.append(QPointF(x,y-_controlHeight));
    p.append(QPointF(x+w,y-_controlHeight));
    p.append(QPointF(x+w,y-w));
    return p;
}

void ColorTableEditor::drawControl(QPainter *painter, ColorValue* value, double minValue, const QRectF& rc, double tableLen, QList<QLineF>& lines){
    QPolygonF p=controlArea(value,minValue, rc,tableLen);

    painter->setBrush(value->_c);
    painter->drawPolygon(p);
    lines.append(QLineF(p[0], QPointF(p[0].x(), rc.bottom())));
}

QRectF ColorTableEditor::displayArea(){
    qreal w=_controlWidth/2.0+1;
    QRectF rc=this->rect();
    rc.adjust(w,_controlHeight+1,-w-_downArrowWidth,0);
    return rc;
}

QRectF ColorTableEditor::downArrowHitArea(){
    qreal w=_controlWidth/2.0+1+_downArrowWidth;
    return QRectF(rect().right()-w, rect().top()+_controlHeight,w, rect().height()-_controlHeight);
}

QRectF ColorTableEditor::downArrowArea(){
    return QRectF(rect().right()-_downArrowWidth, rect().top(),_downArrowWidth, rect().height());
}

void ColorTableEditor::setControlButtonSize(qreal w, qreal h){
    _controlWidth=w;
    _controlHeight=h;
    update();
}

void ColorTableEditor::drawTrig(QPainter* painter){
    qreal trignal=_downArrowWidth-3;
    QRectF rc=displayArea();
    QPointF pt(rc.right()+_downArrowWidth/2,rc.center().y()+trignal/2);

    QPolygonF trig;
    trig.append(pt);
    trig.append(pt-QPointF(trignal/2, trignal));
    trig.append(pt+QPointF(trignal/2, -trignal));

    painter->setBrush(Qt::black);
    painter->setPen(Qt::NoPen);

    painter->drawPolygon(trig);
}

void ColorTableEditor::paintEvent(QPaintEvent *event){
    if(_table==nullptr) return;
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing|QPainter::SmoothPixmapTransform);
    painter.setPen(Qt::black);
    QRectF rc=displayArea();
    double len=_table->getValueLen();
    double minValue=_table->minValue();
    QList<QLineF> lines;
    for(int i=0;i<_table->_colors.count();i++){
        ColorValue &v=_table->_colors[i];
        drawControl(&painter, &v, minValue, rc, len, lines);
    }

    if(_table->_isLinearFill){
        QLinearGradient linearGradient(rc.topLeft(), rc.topRight());
        if(len>0){
            for(int i=0;i<_table->_colors.count();i++){
                ColorValue &v=_table->_colors[i];
                double z=(v._v-minValue)/len;
                linearGradient.setColorAt(z,v._c);
            }
        }
        painter.setBrush(QBrush(linearGradient));
        painter.drawRect(rc);
    } else {
        if(len>0){
            qreal prevX=rc.left();
            for(int i=1;i<_table->_colors.count();i++){
                ColorValue &vPrev=_table->_colors[i-1];
                ColorValue &v=_table->_colors[i];
                double z=(v._v-vPrev._v)/len*rc.width();
                painter.fillRect(QRectF(prevX,rc.top(),z,rc.height()), vPrev._c);
                prevX+=z;
            }
        }
    }
    painter.drawLines(lines);

    drawTrig(&painter);

    if(rc.contains(_ptMouse)){
        painter.drawLine(QLineF(_ptMouse.x(), rc.top(), _ptMouse.x(), rc.bottom()));
    }
}

void ColorTableEditor::mousePressEvent(QMouseEvent *event){
    _bMouseMoving=false;
    _bMousePressing=false;
    if (event->button()==Qt::LeftButton){
        if(downArrowHitArea().contains(event->pos())){
            _menu.popup(event->globalPosition().toPoint());
        } else {
            _bMousePressing=true;
        }
    }
}
void ColorTableEditor::mouseReleaseEvent(QMouseEvent *event){
    _bMousePressing=false;
    if(_bMouseMoving){
        _bMouseMoving=false;
        emit onValueChanged();
    }
}
void ColorTableEditor::mouseDoubleClickEvent(QMouseEvent *event){
    _bMousePressing=false;
    _bMouseMoving=false;
    if (event->button()==Qt::LeftButton){
        if(_table!=nullptr){
            QRectF rc=displayArea();
            qreal z=(_ptMouse.x()-rc.left())/rc.width();

            if(_dlgColor==nullptr){
                _dlgColor=new DialogColorValue(this);
                connect(_dlgColor,&DialogColorValue::onColorChanged,this,&ColorTableEditor::onColorChanged);
                connect(_dlgColor,&DialogColorValue::onColorDeleted,this,&ColorTableEditor::onColorDeleted);
            }

            if (_currentIndex>=0){
                _dlgColor->setColorValue(_currentIndex, _table->_colors[_currentIndex], _table->canDelete(_currentIndex));
            }else{
                ColorValue v(_table->getValueLen()*z+_table->minValue(), Qt::black);
                _dlgColor->setColorValue(-1, v, false);
            }

            _dlgColor->show();
        }
    }
}

void ColorTableEditor::onColorDeleted(int index){
    if (index>0 && index<_table->_colors.size()-1){
        _table->delValue(index);
        emit onValueChanged();
        update();
    }
}

void ColorTableEditor::onColorChanged(int index, const ColorValue& value){

    if(index>=0){
        _table->setValue(index, value);
    } else {
        _currentIndex=_table->addValue(value);
        if(_dlgColor!=nullptr){
            _dlgColor->setColorValue(_currentIndex, value, _table->canDelete(_currentIndex));
        }
    }
    emit onValueChanged();
    update();
}

void ColorTableEditor::mouseMoveEvent(QMouseEvent *event){
    _ptMouse=event->pos();
    if(_table!=nullptr){
        double minValue=_table->minValue();
        double maxValue=_table->maxValue();
        QRectF rc=displayArea();
        double len=_table->getValueLen();
        if(_bMousePressing && _currentIndex>=1 && _currentIndex<_table->_colors.count()-1){
            qreal z=(_ptMouse.x()-rc.left())/rc.width();
            ColorValue v(_table->getValueLen()*z+minValue, _table->_colors[_currentIndex]._c);
            if (v._v>minValue && v._v<maxValue){
                _currentIndex=_table->setValue(_currentIndex, v);
                emit onValueChanged();
            }
            _bMouseMoving=true;
        } else{
            _currentIndex=-1;
            for(qsizetype i=0;i<_table->_colors.count();i++){
                ColorValue &v=_table->_colors[i];
                QPolygonF area=controlArea(&v, minValue, rc, len);
                if(area.containsPoint(_ptMouse, Qt::FillRule::WindingFill)){
                    this->setCursor(Qt::ClosedHandCursor);
                    _currentIndex=i;
                    break;
                }
            }

            if(this->cursor()!=Qt::ArrowCursor && _currentIndex<0){
                this->setCursor(Qt::ArrowCursor);
            }
        }
        update();
    }
}

tqcolortableviewer.h

#ifndef TQCOLORTABLEVIEWER_H
#define TQCOLORTABLEVIEWER_H

#include <QWidget>

class ColorTable;
class TQColorTableViewer : public QWidget
{
    Q_OBJECT
public:
    explicit TQColorTableViewer(QWidget *parent = nullptr);
    ~TQColorTableViewer();
    void setColorTable(ColorTable* table);
    ColorTable* colorTable();
protected:
    void paintEvent(QPaintEvent *event) override;
    bool event(QEvent *event) override;
signals:
    void clickColorTable(ColorTable* table);
private:
    ColorTable* _table;
    bool _isSelected;
};

#endif // TQCOLORTABLEVIEWER_H

tqcolortableviewer.cpp

#include "tqcolortableviewer.h"
#include <QPainter>
#include "colortable.h"
#include <QEvent>

TQColorTableViewer::TQColorTableViewer(QWidget *parent)
    : QWidget{parent}
{
    _table=nullptr;
    _isSelected=false;
}

TQColorTableViewer::~TQColorTableViewer(){
    if(_table!=nullptr){
        delete _table;
    }
}

void TQColorTableViewer::setColorTable(ColorTable* table){
    _table=table;
}

ColorTable* TQColorTableViewer::colorTable(){
    return _table;
}


bool TQColorTableViewer::event(QEvent *event){
    switch(event->type()){
    case QEvent::Enter:
    case QEvent::HoverEnter:{
        _isSelected=true;
        update();
    }
    break;
    case QEvent::MouseButtonPress:{
        emit clickColorTable(_table);
    }
    break;
    case QEvent::Leave:
    case QEvent::HoverLeave:
        _isSelected=false;
        update();
        break;
    default:
        break;
    }

    return QWidget::event(event);

}

void TQColorTableViewer::paintEvent(QPaintEvent *event){
    QPainter painter(this);
    if(_table!=nullptr){
        QRectF rc=rect();
        painter.setRenderHints(QPainter::Antialiasing|QPainter::SmoothPixmapTransform);
        QLinearGradient linearGradient(rc.topLeft(), rc.topRight());

        double len=_table->getValueLen();
        double minValue=_table->minValue();
        if(len>0){
            for(int i=0;i<_table->_colors.count();i++){
                ColorValue &v=_table->_colors[i];
                double z=(v._v-minValue)/len;
                linearGradient.setColorAt(z,v._c);
            }
        }

        painter.setBrush(QBrush(linearGradient));
        painter.setPen(_isSelected?Qt::red:Qt::black);
        painter.drawRect(rc);

    } else {
        painter.fillRect(rect(),Qt::white);
    }
}

tqalert.h

#ifndef TQALERT_H
#define TQALERT_H

#include <QDialog>

namespace Ui {
class TQAlert;
}

class TQAlert : public QDialog
{
    Q_OBJECT

public:
    explicit TQAlert(QWidget *parent = nullptr);
    explicit TQAlert(const QString& message, QWidget *parent = nullptr);
    ~TQAlert();

    void setText(const QString& text);
    static void information(const QString& message);
private slots:
    void on_btOK_clicked();

private:
    Ui::TQAlert *ui;
};

#endif // TQALERT_H

tqalert.cpp

#include "tqalert.h"
#include "ui_tqalert.h"

TQAlert::TQAlert(QWidget *parent):TQAlert("", parent){

}

TQAlert::TQAlert(const QString& message, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::TQAlert)
{
    ui->setupUi(this);
    this->setWindowTitle(tr("提示"));
    this->setWindowIcon(QIcon(":/images/logo"));

    ui->lbMsg->setText(message);
}

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

void TQAlert::setText(const QString& text){
    ui->lbMsg->setText(text);
}

void TQAlert::information(const QString& message){
    TQAlert dlg(message);
    dlg.exec();
}

void TQAlert::on_btOK_clicked()
{
    done(QDialog::Rejected);
}

colortables.json

{
    "lists":
    [
        {
            "name":"橙色",
            "table":
            [
                {"value":0, "color":"255,255,255"},
                {"value":10, "color":"255,255,107"},
                {"value":20, "color":"255,184,68"},
                {"value":30, "color":"255,163,0"},
                {"value":40, "color":"222,136,0"},
                {"value":50, "color":"190,108,0"},
                {"value":60, "color":"166,87,0"},
                {"value":70, "color":"133,59,0"},
                {"value":80, "color":"62,8,0"}
            ]
        },
        {
            "name":"彩虹色",
            "table":
            [
                {"value":0, "color":"255,0,179"},
                {"value":25, "color":"255,222,22"},
                {"value":50, "color":"37,179,62"},
                {"value":75, "color":"133,179,255"},
                {"value":100, "color":"230,230,230"}
            ]
        },
        {
            "name":"体积拾取均方根伽玛",
            "table":
            [
                {"value":0, "color":"148,0,0"},
                {"value":10, "color":"200,0,0"},
                {"value":20, "color":"255,0,0"},
                {"value":30, "color":"255,94,0"},
                {"value":40, "color":"255,176,0"},
                {"value":50, "color":"214,217,163"},
                {"value":60, "color":"255,255,255"}
            ]
        },
        {
            "name":"体积拾取伽玛",
            "table":
            [
                {"value":0, "color":"137,18,1"},
                {"value":10, "color":"211,28,1"},
                {"value":20, "color":"255,61,55"},
                {"value":30, "color":"255,153,128"},
                {"value":40, "color":"244,200,162"},
                {"value":50, "color":"250,227,207"},
                {"value":60, "color":"255,255,255"},
                {"value":70, "color":"226,230,254"},
                {"value":80, "color":"183,183,255"},
                {"value":90, "color":"100,100,255"},
                {"value":100, "color":"40,40,255"},
                {"value":110, "color":"20,20,200"},
                {"value":120, "color":"0,0,150"}
            ]
        },
        {
            "name":"原木黄色",
            "table":
            [
                {"value":0, "color":"2,2,2"},
                {"value":37.5, "color":"184,108,2"},
                {"value":50, "color":"239,78,2"},
                {"value":57.5, "color":"255,92,2"},
                {"value":100, "color":"230,230,230"}
            ]
        },
        {
            "name":"地震测井",
            "table":
            [
                {"value":0, "color":"0,0,255"},
                {"value":50, "color":"237,237,255"},
                {"value":57.5, "color":"255,237,237"},
                {"value":100, "color":"255,0,0"}
            ]
        },
        {
            "name":"log vdl",
            "table":
            [
                {"value":0, "color":"0,255,0"},
                {"value":31, "color":"190,255,84"},
                {"value":44, "color":"253,255,0"},
                {"value":56, "color":"0,233,255"},
                {"value":75, "color":"126,83,255"},
                {"value":82, "color":"126,0,255"},
                {"value":94, "color":"0,0,233"},
                {"value":100, "color":"0,0,190"}
            ]
        },
        {
            "name":"log sunbow",
            "table":
            [
                {"value":0, "color":"255,0,0"},
                {"value":50, "color":"16,237,0"},
                {"value":56, "color":"0,237,17"},
                {"value":100, "color":"0,0,255"}
            ]
        },
        {
            "name":"log sunbow",
            "table":
            [
                {"value":0, "color":"255,0,0"},
                {"value":50, "color":"16,237,0"},
                {"value":56, "color":"0,237,17"},
                {"value":100, "color":"0,0,255"}
            ]
        },
        {
            "name":"Log spreverse",
            "table":
            [
                {"value":0, "color":"255,0,0"},
                {"value":25, "color":"253,255,0"},
                {"value":56, "color":"20,255,255"},
                {"value":62.5, "color":"0,190,255"},
                {"value":62.5, "color":"0,190,255"},
                {"value":82, "color":"0,0,255"},
                {"value":87.5, "color":"0,0,204"},
                {"value":100, "color":"0,0,204"}
            ]
        },
        {
            "name":"Log sand and shale",
            "table":
            [
                {"value":0, "color":"51,0,0"},
                {"value":69, "color":"255,160,0"},
                {"value":82.5, "color":"255,190,99"},
                {"value":87.5, "color":"255,210,93"},
                {"value":100, "color":"255,255,255"}
            ]
        },
        {
            "name":"Log rainbow",
            "table":
            [
                {"value":0, "color":"0,0,255"},
                {"value":37.5, "color":"0,204,0"},
                {"value":50, "color":"68,255,0"},
                {"value":62.5, "color":"235,235,0"},
                {"value":75, "color":"159,133,0"},
                {"value":87.5, "color":"207,0,0"},
                {"value":100, "color":"255,255,255"}
            ]
        },
        {
            "name":"Log projection",
            "table":
            [
                {"value":0, "color":"126,126,255"},
                {"value":37.5, "color":"255,190,190"},
                {"value":50, "color":"190,255,204"},
                {"value":62.5, "color":"190,255,255"},
                {"value":75, "color":"241,255,204"},
                {"value":87.5, "color":"255,255,204"},
                {"value":100, "color":"255,255,255"}
            ]
        },
        {
            "name":"Hot",
            "table":
            [
                {"value":0, "color":"255,255,0"},
                {"value":20, "color":"255,147,0"},
                {"value":40, "color":"255,104,0"},
                {"value":60, "color":"255,0,0"},
                {"value":80, "color":"172,19,19"},
                {"value":100, "color":"0,0,0"}
            ]
        },
        {
            "name":"红-绿",
            "table":
            [
                {"value":0, "color":"255,0,0"},
                {"value":100, "color":"0,255,0"}
            ]
        },
        {
            "name":"金",
            "table":
            [
                {"value":0, "color":"51,0,0"},
                {"value":62.5, "color":"255,161,0"},
                {"value":75, "color":"255,191,100"},
                {"value":82.5, "color":"255,211,93"},
                {"value":95, "color":"255,255,255"},
                {"value":100, "color":"255,255,255"}
            ]
        },
        {
            "name":"白-黑",
            "table":
            [
                {"value":0, "color":"255,255,255"},
                {"value":100, "color":"0,0,0"}
            ]
        }
    ]
}

调用方式:

ColorTableEditor* editor=new ColorTableEditor(this);

editor->setControlButtonSize(6,10);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值