Qt软件开发文档14---聊天窗口的实现,对QlistWidget点击item项隐藏虚线框的实现

要实现如下对话窗口:
这里写图片描述
先声明一个封装类FeedBackListItem
feedbacklistitem.h

#ifndef FeedBackListItem_H
#define FeedBackListItem_H

#define     COLOR_WHITE         Qt::white
#define     ITEM_HEIGHT         40
#define     ITEM_SPACE          5
#define     HeaderBgColor       QColor(219, 238, 252)
#define     HeaderTextColor     QColor(55, 100, 151)
#define     COLOR_BLACK         Qt::black
#define     HEAD_W_H            40
#define     TEACHER_HEAR        QString::fromLocal8Bit("医生")
#define     DAFENQI_HEAD        QString::fromLocal8Bit("达芬奇")

enum Orientation{
    None,
    Left,
    Right
};

#include <QWidget>
#include <QPainter>
#include <QEvent>
#include <QDateTime>
class FeedBackListItem : public QWidget
{
    Q_OBJECT

public:
    FeedBackListItem(QWidget *parent,QString text,int Ori);
    ~FeedBackListItem();

private:
    QString     m_text;
    int         m_width;
    int         m_oritation;
    QWidget     *m_parent;
    QSize       getItemSize(int ,int );
    void        drawBg(QPainter* painter);
    void        drawItems(QPainter* painter);
signals:
    void sendItemSize(int,int);
protected:
    bool eventFilter(QObject *, QEvent *);

};

#endif // FeedBackListItem_H

在类FeedBackListItem中利用Qpainter 绘制气泡,文本,头像信息

#include "feedbacklistitem.h"

FeedBackListItem::FeedBackListItem(QWidget *parent,QString text,int Ori) :
    QWidget(parent),m_text(text),m_width(0),m_oritation(Ori)
{
    m_parent = parent;
    this->installEventFilter(this);
}
bool FeedBackListItem::eventFilter(QObject *obj, QEvent *event)
{
    if((obj == this)&&(event->type()==QEvent::Paint))
    {
        QPainter painter(this);
        painter.setRenderHints(QPainter::HighQualityAntialiasing|QPainter::Antialiasing);
        drawBg(&painter);
        drawItems(&painter);
        return QWidget::eventFilter(obj,event);
    }else{
        return false;
    }
}

//BG COLOR
void FeedBackListItem::drawBg(QPainter *painter)
{
    painter->save();
    // painter->setPen(Qt::NoPen);
    painter->setBrush(COLOR_WHITE);
    painter->setPen(COLOR_WHITE);
    painter->drawRect(rect());
    painter->restore();
}

QSize FeedBackListItem::getItemSize(int width,int height)
{
    return QSize(width,height);
}

void FeedBackListItem::drawItems(QPainter *painter)
{
    // 绘制item区域
    painter->save();

    int nItemY = 0;
    int nWidth = this->width();
    nWidth = (0 == nWidth % 2) ? nWidth : nWidth + 1;

    //top Y
    QPointF topLeft(0,nItemY+30);
    QPointF bottomRight(nWidth,nItemY + ITEM_HEIGHT + ITEM_SPACE);
    QRectF  ItemRect(topLeft,bottomRight);

    painter->save();
    QTransform t;
    t.translate(ItemRect.center().x(),ItemRect.center().y());
    //进入样式
    // t.scale(m_IIVec.at(nIndex).getZoomingFactor(),m_IIVec.at(nIndex).getZoomingFactor());
    painter->setTransform(t);

    QPointF rectTopLeft;
    QPointF rectBottomRight;
    QRectF textRect(rectTopLeft,rectBottomRight);

    QFont font("幼圆", 10);
    painter->setFont(font);

    QPainterPath path;
    // 计算文字的宽度
    QFontMetrics fm(font);
    int pixelsWide = fm.width(m_text);
    int pixelsHigh = fm.height();
    int m_wf = nWidth * 2 / 3;
    pixelsHigh = pixelsWide < (m_wf*8/9) ?  ITEM_HEIGHT : (((pixelsWide / (nWidth / 2)) + 2) * ITEM_HEIGHT*2/5);
    pixelsWide = pixelsWide < (m_wf*8/9) ?  pixelsWide  : (m_wf*8/9);

    if (Right == m_oritation)
    {
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(HeaderBgColor);
        // 绘制边框  头像边框
        painter->drawRoundedRect(nWidth / 2 - 55, -ITEM_HEIGHT / 2, HEAD_W_H, HEAD_W_H, 2, 2);
        // 绘制头像
        painter->setPen(HeaderTextColor);
        //painter->drawPixmap(nWidth / 2 - 54, -ITEM_HEIGHT / 2 + 1, 48, 48, QPixmap(""));
        painter->drawText(nWidth / 2 - 54, -ITEM_HEIGHT / 2 + 1, HEAD_W_H, HEAD_W_H,Qt::AlignCenter,TEACHER_HEAR);
        painter->restore();


        // 计算右边的宽度x
        int nX = (nWidth / 2) - 85 - pixelsWide;
        if (nX < 0) {
            nX = -pixelsWide - 85 + nWidth / 2;
        }
        painter->save();

        // 计算气泡框
        textRect = QRectF(nX, -ITEM_HEIGHT / 2, pixelsWide + 20, pixelsHigh);
#if 1
        // 计算气泡右边的三角   三角内颜色
        path.addRoundedRect(textRect, 3, 3);    //聊天框弧度
        path.moveTo(nWidth / 2 - 65, -ITEM_HEIGHT / 2 + 12);
        path.lineTo(nWidth / 2 - 55, -ITEM_HEIGHT / 2 + 18);
        path.lineTo(nWidth / 2 - 65, -ITEM_HEIGHT / 2 + 21);
        painter->setPen(QColor(140, 170, 202));
        painter->drawPath(path);

        //painter->fillPath(path,HeaderTextColor);
#else
        painter->drawPixmap(nX + 10, -ITEM_HEIGHT / 2, pixelsWide, pixelsHigh, QPixmap(""));
#endif
        painter->restore();
        painter->setPen(Qt::white);
        // 重新调整文字区域
        textRect = QRectF(nX + 10, -ITEM_HEIGHT / 2, pixelsWide, pixelsHigh);
    }
    else {

        // 绘制气泡区域
        painter->save();
        textRect = QRectF(-nWidth / 2 + 59, -ITEM_HEIGHT / 2, pixelsWide + 20, pixelsHigh);
        // 左边三角
        path.addRoundedRect(textRect, 3, 3);
        path.moveTo(-nWidth / 2 + 59, -ITEM_HEIGHT / 2 + 12);
        path.lineTo(-nWidth / 2 + 49, -ITEM_HEIGHT / 2 + 18);
        path.lineTo(-nWidth / 2 + 59, -ITEM_HEIGHT / 2 + 21);
        painter->setPen(QColor(140, 170, 202));
        painter->drawPath(path);
        painter->restore();

        // 绘制头像
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(HeaderBgColor);
        QRectF  leftRect(-nWidth / 2 + 5, -ITEM_HEIGHT / 2, HEAD_W_H, HEAD_W_H);
        painter->drawRect(leftRect);
        painter->setPen(HeaderTextColor);
        painter->drawText(leftRect, Qt::AlignCenter,DAFENQI_HEAD);
        painter->restore();

        painter->setPen(COLOR_BLACK);
        // 绘制文字区域
        textRect = QRectF(-nWidth / 2 + 59 + 10, -ITEM_HEIGHT / 2, pixelsWide, pixelsHigh);
    }

    //设置text颜色
    painter->setPen(Qt::red);
    painter->drawText(textRect, m_text, Qt::AlignVCenter |Qt::AlignLeft);
    painter->restore();

    /// increment nItemY    item高度设置
    if(pixelsHigh <= HEAD_W_H){
        pixelsHigh = HEAD_W_H;
        nItemY += pixelsHigh + ITEM_SPACE;   //head height + ITEMSPACING
    }else{
        nItemY += pixelsHigh + ITEM_SPACE;
    }
    //QSize(width(),height)
    emit sendItemSize(width(),pixelsHigh + ITEM_SPACE+30);
}

FeedBackListItem::~FeedBackListItem()
{

}

声明一个FeedBackUI类,在其中绘制出整体界面以及对item项的调用
feedbackui.h

#ifndef FEEDBACKUI_H
#define FEEDBACKUI_H

#define  StrSubmitSuggestion        QString::fromLocal8Bit("提交意见")
#define  StrTextEdtPlaceHoderText   QString::fromLocal8Bit("请在此输入修改意见:")

#include "feedbacklistitem.h"
#include "nofocusdelegate.h"
#include <QLabel>
#include <QWidget>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QStandardItem>
#include <QAbstractItemModel>
#include <QListWidget>
class FeedBackUI : public QWidget
{
    Q_OBJECT

public:
    FeedBackUI(QWidget *parent = 0);
    ~FeedBackUI();

private:
    QVBoxLayout         *m_mainLayout;
    QPushButton         *m_submitBtn;
    FeedBackListItem    *feedItem;
    QListWidget         *m_listWgt;
    QTextEdit           *m_textEdt;
    QListWidgetItem     *item;
    QListWidgetItem     *itemTime;
    QLabel              *timeLabel;
private:

    void    initWgt();
    QSize   setItemSize(int, int);
    int     wf;
    int     hf;
protected:
    void    resizeEvent(QResizeEvent *);
private slots:
    void    sltBtnSubmitClicked(bool);
    void    getItemSize(int,int);

};

#endif // FEEDBACKUI_H

feedbackui.cpp

#include "feedbackui.h"

FeedBackUI::FeedBackUI(QWidget *parent)
    : QWidget(parent),wf(1),hf(1)
{
    initWgt();
}
void FeedBackUI::initWgt()
{
    this->setMaximumWidth(1200);
    this->setFixedHeight(777);
    this->setMinimumWidth(632);
   // this->setWindowFlags(Qt::FramelessWindowHint);

    this->setStyleSheet(
                        "QListWidget{"
                            "border:        1px solid #8AA0B8;"
                        "}"
                        "QTextEdit{"
                            "border-top:    0px solid #8AA0B8;"
                            "border-right:  1px solid #8AA0B8;"
                            "border-bottom: 1px solid #8AA0B8;"
                            "border-left:   1px solid #8AA0B8;"
                        "}"
                        "QPushButton{"
                            "background-color:#3F70AB;"
                            "color:white;"
                            "border:0px;"
                        "}"
                        "QPushButton:pressed{"
                            "background-color:#214285;"
                        "}"
                        );
    m_mainLayout        = new QVBoxLayout(this);
    m_textEdt           = new QTextEdit(this);
    m_submitBtn         = new QPushButton(this);
    m_listWgt           = new QListWidget(this);

    m_mainLayout        ->addWidget(m_listWgt);
    m_mainLayout        ->addWidget(m_textEdt);

    m_textEdt           ->setPlaceholderText(StrTextEdtPlaceHoderText);
    m_submitBtn         ->setText(StrSubmitSuggestion);
    m_textEdt           ->setFixedHeight(180*hf);

    m_mainLayout        ->setContentsMargins(0,0,0,0);
    m_mainLayout        ->setSpacing(0);

    m_listWgt   ->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_listWgt   ->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    m_listWgt   ->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
    //m_listWgt   ->setSelectionMode(QAbstractItemView::NoSelection);
    //m_listWgt   ->setItemDelegate(new NoFocusDelegate());
    connect(m_submitBtn,SIGNAL(clicked(bool)),this,SLOT(sltBtnSubmitClicked(bool)));
}

void FeedBackUI::sltBtnSubmitClicked(bool)
{
    // 1 is left    2 is right
    //m_bubbleList->addItem(m_textEdt->toPlainText(),qrand()%2+1);
    QString test(m_textEdt->toPlainText());
    feedItem                = new FeedBackListItem(this,test,qrand()%2+1);
    QDateTime time = QDateTime::currentDateTime();//获取系统现在的时间
    QString str = time.toString("yyyy-MM-dd hh:mm:ss"); //设置显示格式
    timeLabel   = new QLabel(m_listWgt);
    timeLabel   ->setText(str);
    timeLabel   ->setFixedHeight(30);
    timeLabel   ->setAlignment(Qt::AlignCenter);
    itemTime    = new QListWidgetItem(m_listWgt);
    item        = new QListWidgetItem(m_listWgt);
    item->setSizeHint(QSize(this->width() - 10, this->height()));
    m_listWgt   ->setItemWidget(itemTime,timeLabel);
    m_listWgt   ->setItemWidget(item,feedItem);

    m_listWgt   ->scrollToBottom();

    connect(feedItem,SIGNAL(sendItemSize(int,int)),this,SLOT(getItemSize(int,int)));
}
void FeedBackUI::getItemSize(int w, int h)
{
    item->setSizeHint(QSize(w,h));
}
void FeedBackUI::resizeEvent(QResizeEvent *)
{
    QRect rect  = this->rect();
    m_submitBtn ->setGeometry(rect.right()-77*wf,rect.bottom()-39*hf,68*wf,31*hf);
    m_listWgt   ->setGeometry(0,0,this->width(),this->height()-m_textEdt->height());
}

FeedBackUI::~FeedBackUI()
{

}

qrand()%2+1 生成的随机数, 1时生成的对话框在右侧,2时,在左侧。

以上有给listWidget 设置delegate

m_listWgt   ->setItemDelegate(new NoFocusDelegate());

其作用是点击item项隐藏虚线框
具体实现:

#ifndef NOFOCUSDELEGATE_H
#define NOFOCUSDELEGATE_H

#include <QPainter>
#include <QStyleOptionViewItem>
#include <QModelIndex>
#include <QStyledItemDelegate>
class NoFocusDelegate:public QStyledItemDelegate
{
public:
    NoFocusDelegate();

protected:
    void paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex &index) const;
};

#endif // NOFOCUSDELEGATE_H
#include "nofocusdelegate.h"

NoFocusDelegate::NoFocusDelegate()
{

}
void NoFocusDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem itemOption(option);
    if (itemOption.state & QStyle::State_HasFocus)
    {
        itemOption.state = itemOption.state ^ QStyle::State_HasFocus;
    }
    QStyledItemDelegate::paint(painter, itemOption, index);
}
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值