Qt 自定义导航窗口

Qt 实现的导航窗口,样式还不错,以后可以在项目中集成

为了方便,直接贴代码了:

/**
   The MIT License (MIT)

   Copyright (c) 2014 thelostcode

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
   */

#ifndef DMS_NAVIGATION_H
#define DMS_NAVIGATION_H

#include <QWidget>
#include <QStackedWidget>

class QEvent;
class QPaintEvent;
class QMouseEvent;

class DMSNavigationBar;
class DMSNavigation : public QWidget
{
   Q_OBJECT
   Q_ENUMS(HorizontalAlignment)
   Q_PROPERTY(HorizontalAlignment horizonalAlignment READ horizontalAlignment WRITE setHorizontalAlignment)
   Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex)
   Q_PROPERTY(int cound READ count)

public:
   explicit DMSNavigation(QWidget* parent = NULL, Qt::WindowFlags flags = 0);
   ~DMSNavigation();

   int addTab(QWidget* widget, const QString& text);
   int addTab(QWidget* widget, const QIcon& icon, const QString& text);

   int insertTab(int index, QWidget* widget, const QString& text);
   int insertTab(int index, QWidget* widget, const QIcon& icon, const QString& text);

   void removeTab(int index);

   QString tabText(int index) const;
   void setTabText(int index, const QString& text);

   QIcon tabIcon(int index) const;
   void setTabIcon(int index, const QIcon& icon);

   enum HorizontalAlignment { AlignLeft, AlignCenter, AlignRight };

   HorizontalAlignment horizontalAlignment() const;
   void setHorizontalAlignment(HorizontalAlignment alignment);

   int count() const;
   int currentIndex() const;

public slots:
   void setCurrentIndex(int index);

signals:
   void currentChanged(int index);

private:
   Q_DISABLE_COPY(DMSNavigation)

private:
   QStackedWidget stacked;
   DMSNavigationBar* navigation;

};

#endif
/**
   The MIT License (MIT)

   Copyright (c) 2014 thelostcode

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
 */

#include "DMSNavigation.h"

#include <QIcon>
#include <QPainter>
#include <QVBoxLayout>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QFontMetrics>

const int CONTENT_MARGIN_LEFT = 16;
const int CONTENT_MARGIN_RIGHT = 16;
const int CONTENT_MARGIN = CONTENT_MARGIN_LEFT + CONTENT_MARGIN_RIGHT;
const int DMS_ITEM_MINIMUM_SIZE = 40 + CONTENT_MARGIN;
const int DMS_ITEM_MAXIMUM_SIZE = 120 + CONTENT_MARGIN;
const int DMS_ITEM_ICON_MARGIN = 8;

namespace PNG
{
   const unsigned char Body[215] =
   {
	   0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,
	   0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,
	   0x00,0x26,0x08,0x02,0x00,0x00,0x00,0x8A,0xDE,0x66,0x50,
	   0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,
	   0x1C,0xE9,0x00,0x00,0x00,0x04,0x67,0x41,0x4D,0x41,0x00,
	   0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00,0x00,0x09,
	   0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,
	   0xC3,0x01,0xC7,0x6F,0xA8,0x64,0x00,0x00,0x00,0x1A,0x74,
	   0x45,0x58,0x74,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,
	   0x00,0x50,0x61,0x69,0x6E,0x74,0x2E,0x4E,0x45,0x54,0x20,
	   0x76,0x33,0x2E,0x35,0x2E,0x31,0x31,0x47,0xF3,0x42,0x37,
	   0x00,0x00,0x00,0x46,0x49,0x44,0x41,0x54,0x18,0x57,0x63,
	   0x30,0xB5,0xB4,0x64,0x08,0x0C,0x0B,0x67,0x70,0xF3,0xF6,
	   0x61,0x70,0xF3,0xF2,0x66,0x70,0x45,0xC7,0x9E,0x5E,0x0C,
	   0x2E,0xC8,0xD8,0xC3,0x13,0x8C,0x9D,0x91,0xB1,0xBB,0x07,
	   0x18,0x3B,0xC1,0xB0,0x9B,0x3B,0x1C,0x3B,0xC2,0xB0,0xAB,
	   0x1B,0x1C,0x3B,0x80,0xB0,0x8B,0x2B,0x0A,0xB6,0x07,0x61,
	   0x67,0x17,0x30,0xD6,0x33,0x34,0x04,0x00,0x5C,0x76,0x1E,
	   0xCF,0x7D,0xBC,0xF8,0x0F,0x00,0x00,0x00,0x00,0x49,0x45,
	   0x4E,0x44,0xAE,0x42,0x60,0x82
   };

   const unsigned char BorderLeft[215] =
   {
	   0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,
	   0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,
	   0x00,0x26,0x08,0x02,0x00,0x00,0x00,0x8A,0xDE,0x66,0x50,
	   0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,
	   0x1C,0xE9,0x00,0x00,0x00,0x04,0x67,0x41,0x4D,0x41,0x00,
	   0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00,0x00,0x09,
	   0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,
	   0xC3,0x01,0xC7,0x6F,0xA8,0x64,0x00,0x00,0x00,0x1A,0x74,
	   0x45,0x58,0x74,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,
	   0x00,0x50,0x61,0x69,0x6E,0x74,0x2E,0x4E,0x45,0x54,0x20,
	   0x76,0x33,0x2E,0x35,0x2E,0x31,0x31,0x47,0xF3,0x42,0x37,
	   0x00,0x00,0x00,0x46,0x49,0x44,0x41,0x54,0x18,0x57,0x63,
	   0x30,0xB5,0xB4,0x64,0x88,0x4E,0x48,0x64,0x08,0x0C,0x0B,
	   0x67,0x08,0x0C,0x0D,0x63,0x08,0x40,0xC7,0x21,0xA1,0x0C,
	   0xFE,0xC8,0x38,0x38,0x04,0x8C,0xFD,0x90,0x71,0x50,0x30,
	   0x18,0xFB,0xC2,0x70,0x60,0x10,0x1C,0xFB,0xC0,0x70,0x40,
	   0x20,0x1C,0x7B,0x83,0xB0,0x7F,0x00,0x0A,0xF6,0x02,0x61,
	   0x3F,0x7F,0x30,0xD6,0x33,0x34,0x04,0x00,0xBB,0x7F,0x23,
	   0x70,0x3D,0x75,0xDA,0x5F,0x00,0x00,0x00,0x00,0x49,0x45,
	   0x4E,0x44,0xAE,0x42,0x60,0x82
   };

   const unsigned char BorderRight[208] =
   {
	   0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,
	   0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,
	   0x00,0x26,0x08,0x02,0x00,0x00,0x00,0x8A,0xDE,0x66,0x50,
	   0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,
	   0x1C,0xE9,0x00,0x00,0x00,0x04,0x67,0x41,0x4D,0x41,0x00,
	   0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00,0x00,0x09,
	   0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,
	   0xC3,0x01,0xC7,0x6F,0xA8,0x64,0x00,0x00,0x00,0x1A,0x74,
	   0x45,0x58,0x74,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,
	   0x00,0x50,0x61,0x69,0x6E,0x74,0x2E,0x4E,0x45,0x54,0x20,
	   0x76,0x33,0x2E,0x35,0x2E,0x31,0x31,0x47,0xF3,0x42,0x37,
	   0x00,0x00,0x00,0x3F,0x49,0x44,0x41,0x54,0x18,0x57,0x65,
	   0xC3,0xC9,0x09,0xC0,0x20,0x14,0x05,0xC0,0x57,0x91,0xE0,
	   0xF6,0x17,0x97,0x83,0x87,0xA4,0xFF,0x92,0x44,0x45,0xC1,
	   0x64,0x60,0x10,0x55,0xD1,0x9E,0x17,0x52,0x2A,0x24,0x17,
	   0xF0,0x77,0xCA,0xA0,0x6B,0xFA,0xD7,0x35,0xEE,0xA2,0x67,
	   0xD8,0x59,0x4E,0x3F,0x12,0x5F,0xDD,0x4C,0xB3,0xB1,0xB6,
	   0x03,0x90,0x17,0x18,0xDF,0x51,0xCA,0x88,0xA5,0x00,0x00,
	   0x00,0x00,0x49,0x45,0x4E,0x44,0xAE,0x42,0x60,0x82
   };

   const unsigned char BodyHover[226] =
   {
	   0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,
	   0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,
	   0x00,0x26,0x08,0x02,0x00,0x00,0x00,0x8A,0xDE,0x66,0x50,
	   0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,
	   0x1C,0xE9,0x00,0x00,0x00,0x04,0x67,0x41,0x4D,0x41,0x00,
	   0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00,0x00,0x09,
	   0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,
	   0xC3,0x01,0xC7,0x6F,0xA8,0x64,0x00,0x00,0x00,0x1A,0x74,
	   0x45,0x58,0x74,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,
	   0x00,0x50,0x61,0x69,0x6E,0x74,0x2E,0x4E,0x45,0x54,0x20,
	   0x76,0x33,0x2E,0x35,0x2E,0x31,0x31,0x47,0xF3,0x42,0x37,
	   0x00,0x00,0x00,0x51,0x49,0x44,0x41,0x54,0x18,0x57,0x4D,
	   0xC6,0xB9,0x0D,0xC0,0x30,0x08,0x40,0x51,0x26,0x8A,0xE4,
	   0x22,0x85,0x27,0xF0,0x01,0xF8,0x8C,0x94,0x26,0xD9,0x7F,
	   0x8D,0x00,0x05,0x4A,0xF1,0xF5,0x3E,0x9C,0x31,0xC2,0xFD,
	   0xBC,0xC0,0x6B,0x43,0xDB,0x97,0x69,0xCD,0x65,0x92,0x2A,
	   0xD1,0x98,0xF6,0xF8,0x57,0xC2,0x3E,0xEC,0xAB,0x2A,0xD5,
	   0xD6,0xED,0x8B,0x2A,0x15,0x6E,0xAE,0x96,0x89,0xDD,0x2C,
	   0x26,0x55,0x4A,0x48,0xEE,0x11,0xC2,0x07,0x57,0x24,0x22,
	   0x24,0xCE,0xB6,0x33,0xC8,0x00,0x00,0x00,0x00,0x49,0x45,
	   0x4E,0x44,0xAE,0x42,0x60,0x82
   };

   unsigned char BodyClicked[237] =
   {
	   0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A,0x00,0x00,0x00,
	   0x0D,0x49,0x48,0x44,0x52,0x00,0x00,0x00,0x01,0x00,0x00,
	   0x00,0x26,0x08,0x02,0x00,0x00,0x00,0x8A,0xDE,0x66,0x50,
	   0x00,0x00,0x00,0x01,0x73,0x52,0x47,0x42,0x00,0xAE,0xCE,
	   0x1C,0xE9,0x00,0x00,0x00,0x04,0x67,0x41,0x4D,0x41,0x00,
	   0x00,0xB1,0x8F,0x0B,0xFC,0x61,0x05,0x00,0x00,0x00,0x09,
	   0x70,0x48,0x59,0x73,0x00,0x00,0x0E,0xC3,0x00,0x00,0x0E,
	   0xC3,0x01,0xC7,0x6F,0xA8,0x64,0x00,0x00,0x00,0x1A,0x74,
	   0x45,0x58,0x74,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,
	   0x00,0x50,0x61,0x69,0x6E,0x74,0x2E,0x4E,0x45,0x54,0x20,
	   0x76,0x33,0x2E,0x35,0x2E,0x31,0x31,0x47,0xF3,0x42,0x37,
	   0x00,0x00,0x00,0x5C,0x49,0x44,0x41,0x54,0x18,0x57,0x3D,
	   0xC9,0xD1,0x0D,0x40,0x30,0x00,0x05,0xC0,0xB7,0x84,0x98,
	   0x82,0x28,0x8A,0x6A,0x29,0x5A,0x54,0x4D,0x6A,0x0B,0xA3,
	   0x91,0x97,0xF0,0x71,0x5F,0x07,0xA9,0x14,0x5C,0x38,0xC8,
	   0x1F,0x11,0xEE,0xE5,0xE3,0xF9,0xFB,0x6E,0xDE,0x03,0x4D,
	   0xEB,0x46,0xD6,0xAF,0x34,0x2C,0x8E,0xCC,0xBC,0x90,0xB6,
	   0x13,0xA9,0xD1,0x52,0x67,0x06,0x6A,0xB5,0x41,0xD3,0x6B,
	   0x54,0x6D,0x47,0x42,0x36,0x28,0x6A,0x89,0xAC,0x2C,0x91,
	   0xA4,0x29,0xC2,0x75,0xFF,0x72,0x21,0x1E,0xD2,0x08,0x1E,
	   0x83,0x94,0x8C,0x15,0x5A,0x00,0x00,0x00,0x00,0x49,0x45,
	   0x4E,0x44,0xAE,0x42,0x60,0x82
   };

   const unsigned int BodySize = 215;
   const unsigned int BorderLeftSize = 215;
   const unsigned int BorderRightSize = 208;
   const unsigned int BodyHoverSize = 226;
   const unsigned int BodyClickedSize = 237;
}

//-----------------------------------------------------------------------------
// DMSItem
//-----------------------------------------------------------------------------
class DMSItem 
{
public:
   DMSItem()
      : isClicked(false)
   {
   }

   QString title;
   bool isClicked;
   QRect lastRect;
   QPixmap icon;

public:
   inline int width(const QFontMetrics& fontMetrics) 
   { return fontMetrics.width(title); }
};

//-----------------------------------------------------------------------------
// DMSNavigationBar
//-----------------------------------------------------------------------------
class DMSNavigationBar : public QWidget
{
public:
   explicit DMSNavigationBar(DMSNavigation* q, QWidget* parent = NULL, Qt::WindowFlags flags = 0);
   ~DMSNavigationBar();

   int addTab(const QString& text);
   int addTab(const QIcon& icon, const QString& text);

   int insertTab(int index, const QString& text);
   int insertTab(int index, const QIcon& icon, const QString& text);

   void removeTab(int index);

   QString tabText(int index) const;
   void setTabText(int index, const QString& text);

   QIcon tabIcon(int index) const;
   void setTabIcon(int index, const QIcon& icon);

   DMSNavigation::HorizontalAlignment horizontalAlignment() const;
   void setHorizontalAlignment(DMSNavigation::HorizontalAlignment alignment);

   int count() const;
   int currentIndex() const;

public slots:
   void setCurrentIndex(int index);

protected:
   virtual void enterEvent(QEvent* event);
   virtual void leaveEvent(QEvent* event);
   virtual void paintEvent(QPaintEvent* event);
   virtual void mouseMoveEvent(QMouseEvent* event);
   virtual void mousePressEvent(QMouseEvent* event);

private:
   void paintItem(const QRectF& rect, QPainter* painter, int index, int reserved);
   void paintContent(const QRectF& rect, QPainter* painter, int index, int reserved);
   void paintLeftBorder(const QRectF& rect, QPainter* painter);
   void paintRightBorder(const QRectF& rect, QPainter* painter);

   int indexByPosition(const QPoint& position);
   int navigationWidth();
   int navigationItemWidth(int index, int reserved);

protected:
   DMSNavigation* q_ptr;

private:
   int m_nCurrentIndex;
   QList<DMSItem*> m_itemList;
   DMSNavigation::HorizontalAlignment m_alignment;
};

//-----------------------------------------------------------------------------
// DMSNavigation
//-----------------------------------------------------------------------------
DMSNavigation::DMSNavigation(QWidget* parent, Qt::WindowFlags flags)
   : QWidget(parent, flags)
   , navigation(new DMSNavigationBar(this, 0))
{
   QVBoxLayout *vl = new QVBoxLayout();
   vl->setMargin(0);
   vl->setSpacing(0);
   vl->addWidget(navigation, 0, Qt::AlignTop);
   vl->addWidget(&stacked, 1);
   setLayout(vl);
}

DMSNavigation::~DMSNavigation()
{
   delete navigation;
}

int DMSNavigation::addTab(QWidget* widget, const QString& text)
{
   stacked.addWidget(widget);
   int r = navigation->addTab(text);
   if (count() == 1) setCurrentIndex(0);
   return r;
}

int DMSNavigation::addTab(QWidget* widget, const QIcon& icon, const QString& text)
{
   stacked.addWidget(widget);
   int r = navigation->addTab(icon, text);
   if (count() == 1) setCurrentIndex(0);
   return r;
}

int DMSNavigation::insertTab(int index, QWidget* widget, const QString& text)
{
   stacked.insertWidget(index, widget);
   return navigation->insertTab(index, text);
}

int DMSNavigation::insertTab(int index, QWidget* widget, const QIcon& icon, const QString& text)
{
   stacked.insertWidget(index, widget);
   return navigation->insertTab(index, icon, text);
}

void DMSNavigation::removeTab(int index)
{
   navigation->removeTab(index);
   stacked.removeWidget(stacked.widget(index));
}

QString DMSNavigation::tabText(int index) const
{
   return navigation->tabText(index);
}

void DMSNavigation::setTabText(int index, const QString& text)
{
   navigation->setTabText(index, text);
}

QIcon DMSNavigation::tabIcon(int index) const
{
   return navigation->tabIcon(index);
}

void DMSNavigation::setTabIcon(int index, const QIcon& icon)
{
   navigation->setTabIcon(index, icon);
}

DMSNavigation::HorizontalAlignment DMSNavigation::horizontalAlignment() const
{
   return navigation->horizontalAlignment();
}

void DMSNavigation::setHorizontalAlignment(DMSNavigation::HorizontalAlignment alignment)
{
   navigation->setHorizontalAlignment(alignment);
}

int DMSNavigation::count() const
{
   return navigation->count();
}

int DMSNavigation::currentIndex() const
{
   return navigation->currentIndex();
}

void DMSNavigation::setCurrentIndex(int index)
{
   int current = navigation->currentIndex();
   navigation->setCurrentIndex(index);
   if (current != navigation->currentIndex())
   {
      stacked.setCurrentIndex(index);
      emit currentChanged(index);
   }
}

//-----------------------------------------------------------------------------
// DMSNavigationBar
//-----------------------------------------------------------------------------
DMSNavigationBar::DMSNavigationBar(DMSNavigation* q, QWidget* parent, Qt::WindowFlags flags)
   : QWidget(parent, flags)
   , m_nCurrentIndex(-1)
   , m_itemList(QList<DMSItem*>())
   , m_alignment(DMSNavigation::AlignCenter)
   , q_ptr(q)
{
   setMouseTracking(true);
   setFixedHeight(38);
}

DMSNavigationBar::~DMSNavigationBar()
{
   qDeleteAll(m_itemList);
}

int DMSNavigationBar::addTab(const QString& text)
{
   return addTab(QIcon(), text);
}

int DMSNavigationBar::addTab(const QIcon& icon, const QString& text)
{
   DMSItem* item = new DMSItem();
   item->icon = icon.pixmap(QSize(16, 16));
   item->title = text;
   m_itemList.append(item);
   update();
   return count() - 1;
}

int DMSNavigationBar::insertTab(int index, const QString& text)
{
   return insertTab(index, QIcon(), text);
}

int DMSNavigationBar::insertTab(int index, const QIcon& icon, const QString& text)
{
   DMSItem* item = new DMSItem();
   item->icon = icon.pixmap(QSize(16, 16));
   item->title = text;
   m_itemList.insert(index, item);
   update();
   return index;
}

void DMSNavigationBar::removeTab(int index)
{
   delete m_itemList.takeAt(index);
   update();
}

QString DMSNavigationBar::tabText(int index) const
{
   return m_itemList[index]->title;
}

void DMSNavigationBar::setTabText(int index, const QString& text)
{
   m_itemList[index]->title = text;
   update();
}

QIcon DMSNavigationBar::tabIcon(int index) const
{
   return m_itemList[index]->icon;
}

void DMSNavigationBar::setTabIcon(int index, const QIcon& icon)
{
   m_itemList[index]->icon = icon.pixmap(QSize(16, 16));
   update();
}

DMSNavigation::HorizontalAlignment DMSNavigationBar::horizontalAlignment() const
{
   return m_alignment;
}

void DMSNavigationBar::setHorizontalAlignment(DMSNavigation::HorizontalAlignment alignment)
{
   m_alignment = alignment;
   update();
}

int DMSNavigationBar::count() const
{
   return m_itemList.count();
}

int DMSNavigationBar::currentIndex() const
{
   return m_nCurrentIndex;
}

void DMSNavigationBar::setCurrentIndex(int index)
{
   if (index != -1 && index != m_nCurrentIndex)
   {
      if (m_nCurrentIndex != -1)
         m_itemList[m_nCurrentIndex]->isClicked = false;

      m_itemList[index]->isClicked = true;
      m_nCurrentIndex = index;
      update();
   }
}

void DMSNavigationBar::enterEvent(QEvent* event)
{
   QWidget::enterEvent(event);
   update();
}

void DMSNavigationBar::leaveEvent(QEvent* event)
{
   QWidget::enterEvent(event);
   update();
}

void DMSNavigationBar::paintEvent(QPaintEvent*)
{
   QPainter p(this);

   // background
   static QPixmap pixContent;
   if (pixContent.isNull())
      pixContent.loadFromData(PNG::Body, PNG::BodySize);
   p.drawPixmap(rect(), pixContent);

   int navWidth = navigationWidth();
   const int navHeight = rect().height();

   int margin = 0;
   switch (m_alignment)
   {
   case DMSNavigation::AlignLeft:
      margin = 0;
      break;
   case DMSNavigation::AlignRight:
      margin = rect().width() - navWidth;
   default:
      margin = rect().width() / 2 - navWidth / 2;
      break;
   }

   double x = margin;

   // outer - inner look & feel
   if (count())
      paintRightBorder(QRectF(x - 1, 0, 1, navHeight), &p);

   // content
   for (int i = 0; i < m_itemList.count(); i++)
   {
      int itemWidth = navigationItemWidth(i, x);
      paintItem(QRectF(x, 0, itemWidth, navHeight), &p, i, x);
      x += itemWidth;
   }

   // outer - inner look & feel
   if (count())
      paintLeftBorder(QRectF(x, 0, 1, navHeight), &p);
}

void DMSNavigationBar::mouseMoveEvent(QMouseEvent* event)
{
   QWidget::mouseMoveEvent(event);
   update();
}

void DMSNavigationBar::mousePressEvent(QMouseEvent* event)
{
   QWidget::mousePressEvent(event);
   if (event->button() != Qt::LeftButton)
      return;

   int index = indexByPosition(event->pos());
   q_ptr->setCurrentIndex(index);
}

void DMSNavigationBar::paintItem(const QRectF& rect, QPainter* painter, int index, int reserved)
{
   paintLeftBorder(QRectF(rect.x(), rect.top(), 1, rect.height()), painter);
   paintContent(QRectF(rect.x() + 1, rect.top(), rect.width() - 2, rect.height()), painter, index, reserved);
   paintRightBorder(QRectF(rect.x() + rect.width() - 1, rect.top(), 1, rect.height()), painter);
   m_itemList[index]->lastRect = rect.toRect();
}

void DMSNavigationBar::paintLeftBorder(const QRectF& rect, QPainter* painter)
{
   static QPixmap pixLeft;
   if (pixLeft.isNull())
      pixLeft.loadFromData(PNG::BorderLeft, PNG::BorderLeftSize);
   painter->drawPixmap(rect.toRect(), pixLeft);
}

void DMSNavigationBar::paintContent(const QRectF& rect, QPainter* painter, int index, int reserved)
{
   bool isClicked = m_itemList[index]->isClicked;

   if (isClicked || !rect.contains(mapFromGlobal(QCursor::pos())))
   {
      if (isClicked)
      {
         static QPixmap pixContent;
         if (pixContent.isNull())
            pixContent.loadFromData(PNG::BodyClicked, PNG::BodyClickedSize);
         painter->drawPixmap(rect.toRect(), pixContent);
      }
      else
      {
         static QPixmap pixContent;
         if (pixContent.isNull())
            pixContent.loadFromData(PNG::Body, PNG::BodySize);
         painter->drawPixmap(rect.toRect(), pixContent);
      }
   }
   else
   {
      static QPixmap pixContent;
      if (pixContent.isNull())
         pixContent.loadFromData(PNG::BodyHover, PNG::BodyHoverSize);
      painter->drawPixmap(rect.toRect(), pixContent);
   }


   QString strText = m_itemList[index]->title;

   QRectF textTargetRect = rect;
   QRectF iconTargetRect = rect;
   if (!m_itemList[index]->icon.isNull())
   {
      iconTargetRect.setX(iconTargetRect.x() + DMS_ITEM_ICON_MARGIN / 2 + m_itemList[index]->icon.width() / 2);
      iconTargetRect.setY(iconTargetRect.y() + rect.height() / 2 - m_itemList[index]->icon.height() / 2);
      
      iconTargetRect.setWidth(m_itemList[index]->icon.width());
      iconTargetRect.setHeight(m_itemList[index]->icon.height());
      
      textTargetRect.setX(iconTargetRect.right() - DMS_ITEM_ICON_MARGIN);
      
      painter->drawPixmap(iconTargetRect.toRect(), m_itemList[index]->icon);
   }

   if (textTargetRect.width() < navigationItemWidth(index, reserved))
      strText = fontMetrics().elidedText(strText, Qt::TextElideMode::ElideRight, textTargetRect.width() - CONTENT_MARGIN);

   painter->setPen(Qt::white);
   painter->drawText(textTargetRect, strText, QTextOption(Qt::AlignCenter));
}

void DMSNavigationBar::paintRightBorder(const QRectF& rect, QPainter* painter)
{
   static QPixmap pixRight;
   if (pixRight.isNull())
      pixRight.loadFromData(PNG::BorderRight, PNG::BorderRightSize);
   painter->drawPixmap(rect.toRect(), pixRight);
}

int DMSNavigationBar::indexByPosition(const QPoint& position)
{
   for (int i = 0; i < m_itemList.count(); i++)
   {
      if (m_itemList[i]->lastRect.contains(position))
         return i;
   }
   return -1;
}

int DMSNavigationBar::navigationWidth()
{
   int result = 0;
   for (int i = 0; i < m_itemList.count(); i++)
   {
      result += navigationItemWidth(i, result);
   }

   return result;
}

int DMSNavigationBar::navigationItemWidth(int index, int reserved)
{
   DMSItem *item = m_itemList[index];
   int result = item->width(fontMetrics());

   int available = rect().width() - reserved;
   
   int iconWidth = 0;
   if (!item->icon.isNull())
      iconWidth = item->icon.width() + DMS_ITEM_ICON_MARGIN;

   result = result + CONTENT_MARGIN_LEFT + CONTENT_MARGIN_RIGHT + iconWidth;
   result = qMax(DMS_ITEM_MINIMUM_SIZE, result);
   result = qMin(DMS_ITEM_MAXIMUM_SIZE, result);
   result = qMin(result, available);

   return result;
}
int main(int argc, char** argv)
{
   QApplication app(argc, argv);

   DMSNavigation navi;
   navi.resize(600, 50);
   navi.show();

   navi.addTab(new QTextEdit("The first."), "Text 1");
   navi.addTab(new QTextEdit("The second."), "Text 2");
   navi.addTab(new QTextEdit("The third."), "Text 3");

   return app.exec();
}

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值