首页 > 其他分享 >自定义的Qt时间轴控件

自定义的Qt时间轴控件

时间:2022-12-02 20:13:39浏览次数:37  
标签:控件 const 自定义 int top 时间轴 MTimeLinePrivate painter left

这是一个垂直的时间轴,显示效果非常简单,但不能显示有格式的文本。如果想显示有格式文本可以把右侧显示本文的位置换成QLabel控件去显示有格式文本。如果想改变文本行间距,根据我目前在网上搜索的答案,只能用QLabel配合qss样式表(即控件的styleSheet属性)实现。根据此控件可以学习Qt多行文本尺寸的测量和绘制方法。此控件使用方法是new MTimeLine,然后用append函数添加项,或removeAt函数删除项就可以了。此代码在VS2015和Qt5.9上测试通过。下面是效果图:

上代码,头文件:

class MTimeLinePrivate : public QWidget
{
    Q_OBJECT

public:
    MTimeLinePrivate(QWidget* parent = 0);
    void append(const QDate& date, const QString& str);
    void removeAt(int index);

private:
    void paintEvent(QPaintEvent *event) override;
    void resizeEvent(QResizeEvent*) override;
    void showEvent(QShowEvent*) override;
    QSize calcContentSize();
    QSize calcDateStringSize(const QFontMetrics& fm) const;
    void paintDateBkShape(QPainter* painter, const QRect& rect, int whereisy);
    void paintTextBkShape(QPainter* painter, const QRect& rect, int whereisy);

    struct EventInfo
    {
        QDate date;
        QString content;
    };

private:
    static const QMargins contentm; /* 控件内容的边距 */
    static const QMargins datep; /* 日期文本的边距 */
    static const QMargins datem; /* 日期文本背景矩形的外边距 */
    static const QMargins textp; /* 事件文本的边距 */
    static const QMargins textm; /* 事件文本背景矩形的外边距 */
    QVector<EventInfo> events;
};

class MTimeLine : public QWidget
{
    Q_OBJECT

public:
    MTimeLine(QWidget* parent = 0);
    void append(const QDate& date, const QString& str);
    void removeAt(int index);

private:
    MTimeLinePrivate* tlReal;
};

CPP文件:

const QMargins MTimeLinePrivate::contentm(10, 6, 10, 6);
const QMargins MTimeLinePrivate::datep(10, 10, 10, 10);
const QMargins MTimeLinePrivate::datem(0, 6, 14, 6);
const QMargins MTimeLinePrivate::textp(12, 12, 12, 12);
const QMargins MTimeLinePrivate::textm(14, 6, 0, 6);

MTimeLinePrivate::MTimeLinePrivate(QWidget* parent) :
    QWidget(parent)
{
}

void MTimeLinePrivate::append(const QDate& date, const QString& str)
{
    events.push_back({ date, str });
    if (isVisible())
    {
        QSize mini = calcContentSize();
        setMinimumSize(mini);
        update();
    }
}

void MTimeLinePrivate::removeAt(int index)
{
    events.remove(index);
    if (isVisible())
    {
        QSize mini = calcContentSize();
        setMinimumSize(mini);
        update();
    }
}

void MTimeLinePrivate::showEvent(QShowEvent*)
{
    QSize mini = calcContentSize();
    setMinimumSize(mini);
}

void MTimeLinePrivate::resizeEvent(QResizeEvent*)
{
    QSize mini = calcContentSize();
    setMinimumSize(mini);
}

QSize MTimeLinePrivate::calcContentSize()
{
    QFontMetrics fm = fontMetrics();
    QSize datesz = calcDateStringSize(fm);
    int ally = contentm.top();
    int datex = contentm.left();
    int midx = contentm.left() + datem.left() + datep.left() + datesz.width() + datep.right() + datem.right();
    int textx = midx;
    for (const auto &item : events)
    {
        QRect dateOuterRect;
        dateOuterRect.setX(datex + datem.left());
        dateOuterRect.setY(ally + datem.top());
        dateOuterRect.setWidth(datep.left() + datesz.width() + datep.right());
        dateOuterRect.setHeight(datep.top() + datesz.height() + datep.bottom());
        QRect dateRect;
        dateRect.setX(dateOuterRect.x() + datep.left());
        dateRect.setY(dateOuterRect.y() + datep.top());
        dateRect.setSize(datesz);

        int charx = textx + textp.left() + textm.left();
        int chary = ally + textm.top() + textp.top();
        int charw = width() - charx - (textp.right() + textm.right() + contentm.right());
        QRect textRect = fm.boundingRect(charx, chary, charw, 12000, Qt::TextWordWrap, item.content);
        QRect textOuterRect;
        textOuterRect.setX(textx + textm.left());
        textOuterRect.setY(ally + textm.top());
        textOuterRect.setWidth(textp.left() + textRect.width() + textp.right());
        textOuterRect.setHeight(textp.top() + textRect.height() + textp.bottom());

        int midh1 = datem.top() + dateOuterRect.height() + datem.bottom(); /* 左侧高度 */
        int midh2 = textm.top() + textOuterRect.height() + textm.bottom(); /* 右侧高度 */
        int midy2 = ally + qMax(midh1, midh2);

        ally = midy2;
    }
    return QSize(2 * midx, ally + contentm.bottom());
}

void MTimeLinePrivate::paintDateBkShape(QPainter* painter, const QRect& rect, int whereisy)
{
    const QPoint triangle[] =
    {
        { 0, -6 },
        { 7, 0 },
        { 0, 6 },
    };
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor(0x34, 0x98, 0xdb));
    painter->drawRoundedRect(rect, 6, 6);
    painter->save();
    painter->translate(rect.right(), whereisy);
    painter->drawPolygon(triangle, 3);
    painter->restore();
}

void MTimeLinePrivate::paintTextBkShape(QPainter* painter, const QRect& rect, int whereisy)
{
    const QPoint triangle[] =
    {
        { 0, -6 },
        { -7, 0 },
        { 0, 6 },
    };
    painter->setPen(Qt::NoPen);
    painter->setBrush(QColor(0xec, 0xf0, 0xf1));
    painter->drawRoundedRect(rect, 6, 6);
    painter->save();
    painter->translate(rect.x(), whereisy);
    painter->drawPolygon(triangle, 3);
    painter->restore();
}

QSize MTimeLinePrivate::calcDateStringSize(const QFontMetrics& fm) const
{
    QDate today = QDate::currentDate();
    QSize datesz = fm.size(0, today.toString(u8"yyyy年MM月dd日"));
    return datesz;
}

void MTimeLinePrivate::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.fillRect(0, 0, width(), height(), Qt::white); /* 白色背景 */
    QFontMetrics fm = painter.fontMetrics();
    QSize datesz = calcDateStringSize(fm);
    int ally = contentm.top();
    int datex = contentm.left();
    int midx = contentm.left() + datem.left() + datep.left() + datesz.width() + datep.right() + datem.right();
    int textx = midx;
    bool odd = true; /* 奇偶数,用来区分绘制点的样式 */
    for (const auto &item : events)
    {
        /* 绘制左侧日期 */
        QRect dateOuterRect;
        dateOuterRect.setX(datex + datem.left());
        dateOuterRect.setY(ally + datem.top());
        dateOuterRect.setWidth(datep.left() + datesz.width() + datep.right());
        dateOuterRect.setHeight(datep.top() + datesz.height() + datep.bottom());
        const int doty = dateOuterRect.center().y();
        paintDateBkShape(&painter, dateOuterRect, doty);
        QRect dateRect;
        dateRect.setX(dateOuterRect.x() + datep.left());
        dateRect.setY(dateOuterRect.y() + datep.top());
        dateRect.setSize(datesz);
        painter.setPen(Qt::black);
        painter.drawText(dateRect, 0, item.date.toString(u8"yyyy年MM月dd日"));
        /* 绘制右侧字符串 */
        int charx = textx + textp.left() + textm.left();
        int chary = ally + textm.top() + textp.top();
        int charw = width() - charx - (textp.right() + textm.right() + contentm.right());
        QRect textRect = fm.boundingRect(charx, chary, charw, 12000, Qt::TextWordWrap, item.content);
        QRect textOuterRect;
        textOuterRect.setX(textx + textm.left());
        textOuterRect.setY(ally + textm.top());
        textOuterRect.setWidth(textp.left() + textRect.width() + textp.right());
        textOuterRect.setHeight(textp.top() + textRect.height() + textp.bottom());
        paintTextBkShape(&painter, textOuterRect, doty);
        painter.setPen(Qt::black);
        painter.drawText(textRect, Qt::TextWordWrap, item.content);
        /* 绘制中间的线条和点 */
        int midh1 = datem.top() + dateOuterRect.height() + datem.bottom(); /* 左侧高度 */
        int midh2 = textm.top() + textOuterRect.height() + textm.bottom(); /* 右侧高度 */
        int midy2 = ally + qMax(midh1, midh2);
        painter.setPen(QPen(QColor(0, 170, 255), 2));
        painter.drawLine(QPoint(midx, ally), QPoint(midx, midy2));
        painter.setPen(QPen(QColor(0, 170, 255), 8, Qt::SolidLine, odd ? Qt::SquareCap : Qt::RoundCap));
        painter.drawPoint(midx, doty);

        odd = !odd;
        ally = midy2;
    }
}

/////////////////////////////////////////////////////////////////////////////////////////

MTimeLine::MTimeLine(QWidget* parent) :
    QWidget(parent)
{
    QGridLayout* lay = new QGridLayout(this);
    lay->setContentsMargins(0, 0, 0, 0);
    QScrollArea* area = new QScrollArea(this);
    tlReal = new MTimeLinePrivate(this);
    area->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    area->setWidget(tlReal);
    area->setWidgetResizable(true);
    lay->addWidget(area);
    setLayout(lay);
}

void MTimeLine::append(const QDate& date, const QString& str)
{
    tlReal->append(date, str);
}

void MTimeLine::removeAt(int index)
{
    tlReal->removeAt(index);
}

 

标签:控件,const,自定义,int,top,时间轴,MTimeLinePrivate,painter,left
From: https://www.cnblogs.com/mengxiangdu/p/16945503.html

相关文章

  • 自定义hooks
    importReact,{useState,useEffect}from'react';exportconstuseStateHooks=(val:any)=>{  let[value,setValue]=useState(val);  constsetFunc=(v:any)=......
  • 实现了Spring的Aware接口的自定义类什么时候执行的?
     在之前的内容中​​Spring的Aware接口有什么用?​​了解到用户可以通过实现相应的Aware接口来获取spring框架提供的能力,俗称“攀亲戚”以如下代码为例,自定义类MyAware实现......
  • IDEA自定义注释模板-版本2
    配置注释模板:1.类:Templatetext:/***@description:TODO*@authorliuyachao*@date$DATE$$TIME$*/Editvariables:2.方法:Templatetext:*$params$*......
  • 【FastDfs】Docker自定义构建ARM架构的FastDfs镜像
    由于服务器环境为ARM架构,在部署fastdfs时,发现网上的镜像几乎都是X86_64的,不同架构的镜像还不能通用,这个就有点烦了。。。。。由于之前没有从头编译制作过镜像,步步都是坑,在......
  • vue3自定义修饰符
    v-model 有一些内置的修饰符,例如 .trim,.number 和 .lazy都是对输入的数据做过滤处理vue也可以自定义实现创建一个自定义的修饰符 capitalize,它会自动将 v-model......
  • vue3 实现自定义 v-model
    在vue中,form表单输入可以通过v-model实现双向数据绑定,例如:<inputv-model="text"/>{{text}}在表单中输入时,页面展示的data-text也会相应改变如果是封装......
  • WPF学习之控件与布局
    1  控件到底是什么?程序的本质就是“数据+算法”------用户输入原始的数据,算法处理原始数据并得到结果数据。问题就在于程序如何将结果数据显示给用户。同样一组数据,你可......
  • .NET CORE读取自定义配置文件到Configuration中
    微软只提供了以下可以读取配置的方式,其中文件配置只能读取INI、JSON和XML文件,如果我想对其他自定义文件进行读取,那么我们可以使用自定义配置提供程序进行配置  比如,......
  • 用pageOffice控件实现 office word文档在线编辑 表格中写数据的方法
    PageOffice对Word文档中Table的操作,包括给单元格赋值和动态添加行的效果。 1应用场景OA办公中,经常要在文档的指定位置表格,填充后端指定数据。如word文档中,表格数据 ......
  • cxf中自定义拦截器限制IP
    importjava.util.List;importjavax.servlet.http.HttpServletRequest;importorg.apache.cxf.interceptor.Fault;importorg.apache.cxf.message.Message;importorg.apac......