QT:使用「狀態模式」繪製界面 參考的一種面向對象的繪製圖片的方法

 QT與不少GUI庫不一樣(如MFC),它不能隨時隨地地在界面上畫圖,只能在界面類的painterEvent中畫圖,如此一來,想在繪製QT界面時使用狀態模式(GOF的23種設計模式之一)就有點困難了,做爲解決方案,我先把要界面上的圖片繪製在一張圖片上(QPixmap),而後再在painterEvent中將Pixmap「畫」到界面上。如下是這種方法的一個小例子。設計模式

#include <QtGui>

//狀態類的基類,定義了各個公用接口,
//其中,SetPixmap是一個純虛接口
class BasePen
{
protected:
	//這三個類成員理應是BasePen的私有成員,而後經過接口訪問
	//我這裏爲了方便,直接把它們設爲保護成員了
	QPixmap m_Pixmap;
	QPoint m_StartPoint;
	QPoint m_EndPoint;
	virtual void SetPixmap() = 0;
public:
	BasePen()
	{ 
		m_StartPoint = m_EndPoint = QPoint(0, 0);
		m_Pixmap = QPixmap(500, 500);
	}
	void SetStartPoint(QPoint point) { m_StartPoint = point; }
	void SetEndPoint(QPoint point)
	{ 
		m_EndPoint = point; 
		SetPixmap();
	}
	QPixmap GetPixmap() { return m_Pixmap; }
};

//矩形類,在界面上畫一個紅色的矩形
class RectPen : public BasePen
{
protected:
	void SetPixmap()
	{
		m_Pixmap.fill(Qt::white);
		QPainter painter(&m_Pixmap);
		QRect rect(m_StartPoint, m_EndPoint);
		painter.setPen(Qt::red);
		painter.drawRect(rect);
	}
};

//直線類,在界面上畫一條藍色的直線
class LinePen : public BasePen
{
protected:
	void SetPixmap()
	{
		m_Pixmap.fill(Qt::white);
		QPainter painter(&m_Pixmap);
		painter.setPen(Qt::blue);
		painter.drawLine(m_StartPoint, m_EndPoint);
	}
};

//圓形類,在界面上畫一個綠色的橢圓
class CirclePen : public BasePen
{
protected:
	void SetPixmap()
	{
		m_Pixmap.fill(Qt::white);
		QPainter painter(&m_Pixmap);
		QRect rect(m_StartPoint, m_EndPoint);
		painter.setPen(Qt::green);
		painter.drawEllipse(rect);
	}
};

class Widget : public QWidget
{
	Q_OBJECT
private:
	bool m_MouseDown;
	BasePen *m_BasePen;
	RectPen *m_RectPen;
	LinePen *m_LinePen;
	CirclePen *m_CirclePen;
	//在界面上放三個按鈕,用來控制畫圖狀態
	QRadioButton *m_LineButton;
	QRadioButton *m_RectButton;
	QRadioButton *m_CircleButton;
protected:
	void mousePressEvent(QMouseEvent *event);
	void mouseMoveEvent(QMouseEvent *event);
	void mouseReleaseEvent(QMouseEvent *event);
	void paintEvent(QPaintEvent *event);
public:
	Widget(QWidget *parent = 0);
	~Widget();
	private slots:
		void ClickedLineButton() { m_BasePen = m_LinePen; }
		void ClickedRectButton() { m_BasePen = m_RectPen; }
		void ClickedCircleButton() { m_BasePen = m_CirclePen; }
};

Widget::Widget(QWidget *parent /* = 0 */)
: QWidget(parent)
{
	m_MouseDown = false;
	m_RectPen = new RectPen;
	m_LinePen = new LinePen;
	m_CirclePen = new CirclePen;
	m_LineButton = new QRadioButton("Line", this);
	m_RectButton = new QRadioButton("Rect", this);
	m_CircleButton = new QRadioButton("Circle", this);
	m_LineButton->move(10, 10);
	m_RectButton->move(100, 10);
	m_CircleButton->move(200, 10);
	connect(m_LineButton, SIGNAL(clicked()), this, SLOT(ClickedLineButton()));
	connect(m_RectButton, SIGNAL(clicked()), this, SLOT(ClickedRectButton()));
	connect(m_CircleButton, SIGNAL(clicked()), this, SLOT(ClickedCircleButton()));
	m_BasePen = m_LinePen;
	m_LineButton->setChecked(true);
	setFixedSize(500, 500);
}

Widget::~Widget()
{
	delete m_LinePen;
	delete m_RectPen;
	delete m_CirclePen;
}

void Widget::mousePressEvent(QMouseEvent *event)
{
	if( event->button() == Qt::LeftButton )
	{
		m_MouseDown = true;
		m_BasePen->SetStartPoint(event->pos());
	}
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
	if( m_MouseDown )
	{
		m_BasePen->SetEndPoint(event->pos());
		update();
	}
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
	if( event->button() == Qt::LeftButton )
	{
		m_MouseDown = false;
	}
}

void Widget::paintEvent(QPaintEvent *event)
{
	QPixmap temp = m_BasePen->GetPixmap();
	QPainter painter(this);
	painter.drawPixmap(0, 0, temp);
}

#include "main.moc"

int main(int argc, char **argv)
{
	QApplication app(argc, argv);
	Widget *ww = new Widget;
	ww->show();
	return app.exec();
}
相關文章
相關標籤/搜索