要实现如下对话窗口:
先声明一个封装类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);
}