實現 Button 與 Label 類似,差別在於 Button 擁有 Normal、Hover、Pressed 三種狀態,針對三種狀態分別實現即可。支援三種樣式:純圖標、純文字、圖文混排(文字在圖標旁或下)。
class ShowButton : public QGraphicsWidget {
Q_OBJECT
public:
enum State { NormalState, HoverState, PressedState };
enum Style { TextOnly, IconOnly, TextBesidesIcon, TextUnderIcon };
ShowButton(const QPixmap&, const QPixmap&, const QPixmap&);
void setText(const QString&, const QFont&, const QColor&);
void setIcon(const QPixmap&);
void setStyle(Style);
QString getText();
signals:
void clicked();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent*);
void mouseReleaseEvent(QGraphicsSceneMouseEvent*);
void hoverEnterEvent(QGraphicsSceneHoverEvent*);
void hoverLeaveEvent(QGraphicsSceneHoverEvent*);
virtual QRectF boundingRect();
virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget* = 0);
private:
void setPixmap(State);
// 成員變數:三種狀態圖片、圖標、文字、字體、顏色、樣式等
};
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 && 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(); }
}
void ShowButton::paint(QPainter* painter, ...) {
QRect rect = boundingRect().toRect();
setPreferredSize(rect.width(), rect.height());
painter->drawPixmap(rect, m_pixmap); // 畫背景
// 僅圖標 / 僅文字
if (m_iconOn && !m_icon.isNull()) { ... }
else if (m_textOn && !m_text.isEmpty()) { ... }
// 圖文混排
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_style 計算總寬高:文字尺寸 + 圖標尺寸
// TextBesidesIcon: 寬 = 文字寬 + 圖標寬,高 = max(文字高, 圖標高)
// TextUnderIcon: 寬 = max(文字寬, 圖標寬),高 = 文字高 + 圖標高
return QRectF(0, 0, totalWidth, totalHeight);
}
Button 僅發射 clicked() 信號,具體業務邏輯封裝於 ClickHandler 類:
class ClickHandler : public QObject {
Q_OBJECT
public: ClickHandler(QObject* parent);
private slots:
void on_linkOpen(); // 開啟網址
void on_messageBox(); // 彈出訊息框
};
ShowButton *btn1 = new ShowButton(normal, hover, pressed);
btn1->setStyle(ShowButton::IconOnly);
btn1->setIcon(icon); btn1->setMaximumSize(icon.size());
ShowButton *btn2 = new ShowButton(normal, hover, pressed);
btn2->setStyle(ShowButton::TextOnly);
btn2->setText("YY", font, color);
btn2->setMaximumSize(textWidth, textHeight);
ShowButton *btn3 = new ShowButton(normal, hover, pressed);
btn3->setStyle(ShowButton::TextUnderIcon);
btn3->setText("YY", font, color);
btn3->setIcon(icon);
btn3->setMaximumSize(textWidth + icon.width(), textHeight + icon.height());
// 佈局
QGraphicsWidget *widget = new QGraphicsWidget;
QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical);
layout->addItem(btn1); layout->addItem(btn2); layout->addItem(btn3);
widget->setLayout(layout);
scene->addItem(widget);
本文出自「賣萌程序員」博客,轉載請保留出處:https://7677869.blog.51cto.com/7667869/1265278