實現button和實現label功能相似,只是button有三種狀態,normal,hover,pressed,只要對這三種狀態進行不同的實現就可以了。
這裡還設計了三種不同的button,可以只顯示圖標,只顯示文字,同時顯示文字和圖標
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene *scene = new QGraphicsScene;
QGraphicsView *view = new QGraphicsView(scene);
scene->setSceneRect(0, 0, 300, 300);
QPixmap normalPixmap("images/button_normal.png");
QPixmap hoverPixmap("images/button_hover.png");
QPixmap pressedPixmap("images/button_pressdown.png");
ShowButton *showbutton1 = new ShowButton(normalPixmap, hoverPixmap, pressedPixmap);
......
}這裡同樣是基於QGraphicsWidget的,所以要先創建場景scene,然後要讀取三張不同的圖片作為三種不同狀態時候button的背景圖。
這裡的ShowButton就是我們要實現的控件,下面給出控件的頭文件
showbutton.h
#ifndef SHOWBUTTON_H
#define SHOWBUTTON_H
#include <QGraphicsWidget>
class QGraphicsSceneMouseEvent;
class QGraphicsSceneHoverEvent;
class ShowButton: public QGraphicsWidget
{
Q_OBJECT
public:
enum State { NormalState, HoverState, PressedState };
enum Style { TextOnly, IconOnly, TextBesidesIcon, TextUnderIcon};
public:
ShowButton(const QPixmap &, const QPixmap &, const QPixmap &);
void setText(const QString &, const QFont &, const QColor &);
void setIcon(const QPixmap& icon);
void setStyle(Style style);
QString getText();
signals:
void clicked();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *e);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *e);
void hoverEnterEvent(QGraphicsSceneHoverEvent *e);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *);
protected:
virtual QRectF boundingRect();
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
private:
void setPixmap(State state);
private:
int m_cnt;
bool m_isPressed;
bool m_iconOn;
bool m_textOn;
QPixmap m_pixmap;
QPixmap m_normalPixmap;
QPixmap m_hoverPixmap;
QPixmap m_pressedPixmap;
QPixmap m_icon;
QString m_text;
QSize m_size;
QFont m_font;
QColor m_color;
Style m_style;
};
#endif // SHOWBUTTON_H這裡之所以把setPixmap(State state)作為私有的是因為這個函數並不對外提供接口,只是內部進行button背景圖片設置的時候會用到。
有關函數的具體實現如下,
showbutton.cpp
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneHoverEvent>
#include "showbutton.h"
#include "clickhandler.h"
ShowButton::ShowButton(const QPixmap &normalPixmap, const QPixmap &hoverPixmap, const QPixmap &pressedPixmap)
: m_isPressed(false), m_iconOn(false), m_textOn(false)
{
m_cnt = 0;
m_text = "";
m_icon = NULL;
m_pixmap = normalPixmap;
m_normalPixmap = normalPixmap;
m_hoverPixmap = hoverPixmap;
m_pressedPixmap = pressedPixmap;
setAcceptHoverEvents(true);
}
void ShowButton::setStyle( Style style )
{
if ( style == m_style)
{
return;
}
m_style = style;
if (IconOnly == style)
{
m_iconOn = true;
m_textOn = false;
}
else if (TextOnly == style)
{
m_iconOn = false;
m_textOn = true;
}
else
{
m_iconOn = true;
m_textOn = true;
}
}
void ShowButton::setText(const QString &string, const QFont &font, const QColor &color)
{
m_text = string;
m_textOn = true;
m_font = font;
m_color = color;
}
void ShowButton::setIcon( const QPixmap &icon )
{
m_icon = icon;
m_iconOn = true;
}
void ShowButton::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
const QRect &rect = boundingRect().toRect();
setPreferredSize(rect.width(), rect.height());
//畫button的背景
painter->drawPixmap(rect, m_pixmap);
if (m_iconOn && !m_icon.isNull())
{
QRect iconRect(0, 0, m_icon.size().width(), m_icon.size().height());
painter->drawPixmap(iconRect, m_icon);
}
else if (m_textOn && !m_text.isEmpty())
{
QFontMetrics metrics(m_font);
qreal width = metrics.width(m_text);
qreal height = metrics.height();
QRect textRect(0, 0, width, height);
painter->drawText(textRect, Qt::AlignCenter, m_text);
}
//圖標和文本都有
if (m_textOn && m_iconOn && !m_icon.isNull() && !m_text.isEmpty())
{
//文字在圖標旁邊
if(TextBesidesIcon == m_style)
{
QRect mixRect(0, 0, m_icon.size().width(), rect.height());
painter->drawPixmap(mixRect, m_icon);
QRect textRect(m_icon.size().width(), 0, rect.width() - m_icon.size().width(), rect.height());
painter->drawText(textRect, Qt::AlignCenter, m_text);
}
//文字在圖標下面
if (TextUnderIcon == m_style)
{
QRect mixRect(0, 0, rect.width(), m_icon.size().height());
painter->drawPixmap(mixRect, m_icon);
QRect textRect(0, m_icon.size().height(), rect.width(), rect.height() - m_icon.size().height());
painter->drawText(textRect, Qt::AlignCenter, m_text);
}
}
}
QRectF ShowButton::boundingRect()
{
m_size = m_pixmap.size();
qreal widthText;
qreal heightText;
QSize iconSize;
qreal totalWidth;
qreal totalHeight;
//獲取文本信息的寬高
if (m_textOn)
{
QFontMetrics metrics(m_font);
widthText = metrics.width(m_text);
heightText = metrics.height();
//return QRectF(0, 0, widthText, heightText);
}
//獲取圖標的寬高
if (m_iconOn)
{
iconSize = m_icon.size();
}
if (2 == m_style)
{
totalWidth = widthText + iconSize.width();
totalHeight = heightText > iconSize.height() ? heightText : iconSize.height();
}
else if (3 == m_style)
{
totalWidth = widthText > iconSize.width() ? widthText : iconSize.width();
totalHeight = heightText + iconSize.height();
}
else
{
totalWidth = widthText + iconSize.width();
totalHeight = heightText + iconSize.height();
}
return QRectF(0, 0, totalWidth, totalHeight);
}
void ShowButton::setPixmap( State state)
{
switch (state)
{
case NormalState: m_pixmap = m_normalPixmap;
break;
case HoverState: m_pixmap = m_hoverPixmap;
break;
case PressedState: m_pixmap = m_pressedPixmap;
break;
}
}
void ShowButton::mousePressEvent( QGraphicsSceneMouseEvent *e )
{
if (e->button() == Qt::LeftButton)
{
m_isPressed = true;
setPixmap(PressedState);
update();
}
}
void ShowButton::mouseReleaseEvent( QGraphicsSceneMouseEvent *e )
{
if (e->button() == Qt::LeftButton)
{
if (m_isPressed)
{
m_cnt++;
m_isPressed = false;
setPixmap(NormalState);
update();
emit clicked();
}
}
}
void ShowButton::hoverEnterEvent( QGraphicsSceneHoverEvent * )
{
if (!m_isPressed)
{
setPixmap(HoverState);
update();
}
}
void ShowButton::hoverLeaveEvent(QGraphicsSceneHoverEvent *)
{
if (!m_isPressed)
{
setPixmap(NormalState);
update();
}
}
QString ShowButton::getText()
{
return m_text;
}需要引起注意的是ShowButton::mouseReleaseEvent這個函數,這個函數本身並不實現響應,只是發送一個clicked()的信號,而有關消息的響應,也就是信號對應的槽將單獨封裝在一個類中,這樣有利於實現不同的消息響應,這個處理消息響應的槽所構成的類的實現如下
clickhandler.h
#include <QUrl>
class ClickHandler : public QObject
{
Q_OBJECT;
public:
ClickHandler(QObject* parent);
private slots:
void on_linkOpen();
void on_messageBox();
};clickhandler.cpp
#include <QDesktopServices>
#include <QMessageBox>
#include "showbutton.h"
#include "clickhandler.h"
void ClickHandler::on_linkOpen()
{
ShowButton* button = qobject_cast<ShowButton*>(sender());
QString text = button->getText();
text = "www.hao123.com";
QDesktopServices::openUrl(text);
}
void ClickHandler::on_messageBox()
{
ShowButton* button = qobject_cast<ShowButton*>(sender());
QString text = button->getText();
QMessageBox::about(NULL, "msg box", text);
}
ClickHandler::ClickHandler( QObject* parent )
: QObject(parent)
{
}這個請注意ClickHandler::on_linkOpen()這個函數,這個函數式能夠自動獲取button中的文本信息的,並將文本轉化成URL地址然後打開,這裡為了方便沒有寫有關文本信息不實地址的代碼,有興趣的讀者可以自行加上,最後程序的源代碼將放在附件中。這裡同時用到了之前提到的自定義控件布局的實現,有關問題請參考之前的文章。
main.cpp
ShowButton *showbutton1 = new ShowButton(normalPixmap, hoverPixmap, pressedPixmap);
showbutton1->setStyle(ShowButton::IconOnly);
QPixmap icon = ("images/yyboy16.ico");
showbutton1->setIcon(icon);
showbutton1->setMaximumSize(icon.size());
ShowButton *showbutton2 = new ShowButton(normalPixmap, hoverPixmap, pressedPixmap);
showbutton2->setStyle(ShowButton::TextOnly);
QFont font("times", 20, QFont::Bold, true);
QColor color(255, 0, 0);
QString str("YY");
showbutton2->setText(str, font, color);
QFontMetrics metrics(font);
qreal wid = metrics.width(str);
qreal hei = metrics.height();
showbutton2->setMaximumSize(wid, hei);
ShowButton *showbutton3 = new ShowButton(normalPixmap, hoverPixmap, pressedPixmap);
showbutton3->setStyle(ShowButton::TextUnderIcon);
showbutton3->setText(str, font, color);
showbutton3->setIcon(icon);
showbutton3->setMaximumSize(wid + icon.size().width(), hei + icon.size().height());
ClickHandler *clickHandler = new ClickHandler(view);
QObject::connect(showbutton1, SIGNAL(clicked()), clickHandler, SLOT(on_linkOpen()));
QObject::connect(showbutton2, SIGNAL(clicked()), clickHandler, SLOT(on_messageBox()));
QGraphicsWidget *widget = new QGraphicsWidget;
QGraphicsLinearLayout *linearLayout = new QGraphicsLinearLayout(Qt::Vertical);
linearLayout->addItem(showbutton1);
linearLayout->addItem(showbutton2);
linearLayout->addItem(showbutton3);
widget->setLayout(linearLayout);
scene->addItem(widget);
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->resize(300, 300);
view->setWindowTitle(QObject::tr("My hao123 Button"));
view->show();
app.exec();
}本文出自 “賣萌程序員” 博客,請務必保留此出處http://7677869.blog.51cto.com/7667869/1265278