最近由于项目要求,需要开发一个渐变颜色表控件,实现曲线按颜色表进行渐变填充,由于在网上找不到合适的现成控件,只好自已造轮子,下图是控件效果。闲暇之余,本人会不定期发布一些自认为较好人自定义控件,请大家关注。
由于本人长期免费使用网络上的现成代码,深感内疚,所以分享本控件,填补我内心深处的愧疚感。以下是本控件的源代码:
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);