QT:使用“状态模式”绘制界面

QT与很多GUI库不同(如MFC),它不能随时随地地在界面上画图,只能在界面类的painterEvent中画图,如此一来,想在绘制QT界面时使用状态模式(GOF的23种设计模式之一)就有点困难了,作为解决方案,我先把要界面上的图片绘制在一张图片上(QPixmap),然后再在painterEvent中将Pixmap“画”到界面上。以下是这种方法的一个小例子。

截图:

源代码:

[cpp] view plaincopyprint?

  1. #include <QtGui>
  2. //状态类的基类,定义了各个公用接口,
  3. //其中,SetPixmap是一个纯虚接口
  4. class BasePen
  5. {
  6. protected:
  7. //这三个类成员理应是BasePen的私有成员,然后通过接口访问
  8. //我这里为了方便,直接把它们设为保护成员了
  9. QPixmap m_Pixmap;
  10. QPoint m_StartPoint;
  11. QPoint m_EndPoint;
  12. virtual void SetPixmap() = 0;
  13. public:
  14. BasePen()
  15. {
  16. m_StartPoint = m_EndPoint = QPoint(0, 0);
  17. m_Pixmap = QPixmap(500, 500);
  18. }
  19. void SetStartPoint(QPoint point) { m_StartPoint = point; }
  20. void SetEndPoint(QPoint point)
  21. {
  22. m_EndPoint = point;
  23. SetPixmap();
  24. }
  25. QPixmap GetPixmap() { return m_Pixmap; }
  26. };
  27. //矩形类,在界面上画一个红色的矩形
  28. class RectPen : public BasePen
  29. {
  30. protected:
  31. void SetPixmap()
  32. {
  33. m_Pixmap.fill(Qt::white);
  34. QPainter painter(&m_Pixmap);
  35. QRect rect(m_StartPoint, m_EndPoint);
  36. painter.setPen(Qt::red);
  37. painter.drawRect(rect);
  38. }
  39. };
  40. //直线类,在界面上画一条蓝色的直线
  41. class LinePen : public BasePen
  42. {
  43. protected:
  44. void SetPixmap()
  45. {
  46. m_Pixmap.fill(Qt::white);
  47. QPainter painter(&m_Pixmap);
  48. painter.setPen(Qt::blue);
  49. painter.drawLine(m_StartPoint, m_EndPoint);
  50. }
  51. };
  52. //圆形类,在界面上画一个绿色的椭圆
  53. class CirclePen : public BasePen
  54. {
  55. protected:
  56. void SetPixmap()
  57. {
  58. m_Pixmap.fill(Qt::white);
  59. QPainter painter(&m_Pixmap);
  60. QRect rect(m_StartPoint, m_EndPoint);
  61. painter.setPen(Qt::green);
  62. painter.drawEllipse(rect);
  63. }
  64. };
  65. class Widget : public QWidget
  66. {
  67. Q_OBJECT
  68. private:
  69. bool m_MouseDown;
  70. BasePen *m_BasePen;
  71. RectPen *m_RectPen;
  72. LinePen *m_LinePen;
  73. CirclePen *m_CirclePen;
  74. //在界面上放三个按钮,用来控制画图状态
  75. QRadioButton *m_LineButton;
  76. QRadioButton *m_RectButton;
  77. QRadioButton *m_CircleButton;
  78. protected:
  79. void mousePressEvent(QMouseEvent *event);
  80. void mouseMoveEvent(QMouseEvent *event);
  81. void mouseReleaseEvent(QMouseEvent *event);
  82. void paintEvent(QPaintEvent *event);
  83. public:
  84. Widget(QWidget *parent = 0);
  85. ~Widget();
  86. private slots:
  87. void ClickedLineButton() { m_BasePen = m_LinePen; }
  88. void ClickedRectButton() { m_BasePen = m_RectPen; }
  89. void ClickedCircleButton() { m_BasePen = m_CirclePen; }
  90. };
  91. Widget::Widget(QWidget *parent /* = 0 */)
  92. : QWidget(parent)
  93. {
  94. m_MouseDown = false;
  95. m_RectPen = new RectPen;
  96. m_LinePen = new LinePen;
  97. m_CirclePen = new CirclePen;
  98. m_LineButton = new QRadioButton("Line", this);
  99. m_RectButton = new QRadioButton("Rect", this);
  100. m_CircleButton = new QRadioButton("Circle", this);
  101. m_LineButton->move(10, 10);
  102. m_RectButton->move(100, 10);
  103. m_CircleButton->move(200, 10);
  104. connect(m_LineButton, SIGNAL(clicked()), this, SLOT(ClickedLineButton()));
  105. connect(m_RectButton, SIGNAL(clicked()), this, SLOT(ClickedRectButton()));
  106. connect(m_CircleButton, SIGNAL(clicked()), this, SLOT(ClickedCircleButton()));
  107. m_BasePen = m_LinePen;
  108. m_LineButton->setChecked(true);
  109. setFixedSize(500, 500);
  110. }
  111. Widget::~Widget()
  112. {
  113. delete m_LinePen;
  114. delete m_RectPen;
  115. delete m_CirclePen;
  116. }
  117. void Widget::mousePressEvent(QMouseEvent *event)
  118. {
  119. if( event->button() == Qt::LeftButton )
  120. {
  121. m_MouseDown = true;
  122. m_BasePen->SetStartPoint(event->pos());
  123. }
  124. }
  125. void Widget::mouseMoveEvent(QMouseEvent *event)
  126. {
  127. if( m_MouseDown )
  128. {
  129. m_BasePen->SetEndPoint(event->pos());
  130. update();
  131. }
  132. }
  133. void Widget::mouseReleaseEvent(QMouseEvent *event)
  134. {
  135. if( event->button() == Qt::LeftButton )
  136. {
  137. m_MouseDown = false;
  138. }
  139. }
  140. void Widget::paintEvent(QPaintEvent *event)
  141. {
  142. QPixmap temp = m_BasePen->GetPixmap();
  143. QPainter painter(this);
  144. painter.drawPixmap(0, 0, temp);
  145. }
  146. #include "main.moc"
  147. int main(int argc, char **argv)
  148. {
  149. QApplication app(argc, argv);
  150. Widget *ww = new Widget;
  151. ww->show();
  152. return app.exec();
  153. }

http://blog.csdn.net/small_qch/article/details/7632226

时间: 2025-01-17 15:16:21

QT:使用“状态模式”绘制界面的相关文章

有限状态机与状态模式

状态机 在理解状态机之前,总是把状态里简单地理解为状态模式,最近,我仔细分析了状态机的实现机制,发现状态机和状态模式还是有很大的不同. 一,状态模式是具体的,针对每个需求有一个状态集,并为其实现特有的迁移机制.状态机是抽象的,不是针对特定的需求,而是对各种与相关的问题的进一步抽象,那么用状态机回头去实现状态模式的时候,只需要关注问题本身,而不用去关心如何实现,也就是说你只需要绘制出状态迁移图,状态机就能帮你去实现. 二,状态模式的是命令式的,我们必须一步一步地去实现状态之间如何迁移,以及迁移过程

用错的状态模式?

突然有些明白了小说里世界上最牛逼的两个人为什么一定要在结尾干一架 因为他们真的都认为自己是正确的 并且深信不疑 而菜鸡(比如博主之流),有时候也是偏执狂 写在前面的话 这是一个两只猿类关于状态模式实现方式撕逼的故事.简要记录如下: 时间:2016年11月16日21:13:49 人物:博主和长脸先生同学. 起因:我们指定了一个这样的场景:用状态模式实现搜狗输入法输出中文.英文.大写三种状态的切换.然后我们分别写出了自己认为正确的代码,又为了证明自己的代码是正确的,开始撕逼. 经过:刀光剑影,刷刷刷

Qt之图形(绘制文本)

简述 前面我们讲解了Qt图形的基本绘制,其中包括: 绘制文本.直线.直线.矩形.弧线.椭圆.多边形.图片,以及其它一些高级用法,比如:渐变.转换等. 本节我们来详细讲解文字的绘制.主要通过QPainter的darwText()函数来实现,里面包含多个重载函数,其中,可以通过QRect来指定绘制的区域,也可以通过QPoint来指定绘制的起始点. QFont类可以辅助设置文本的大小.粗细.字符间距等,然后使用setFont()来设置. QFontInfo类用来获取字体的信息,可以通过fontInfo

Java状态模式(State模式)

State的定义:不同的状态,不同的行为:或者说,每个状态有着相应的行为. 何时使用状态模式 State模式在实际使用中比较多,适合"状态的切换".因为我们经常会使用If elseif else 进行状态切换, 如果针对状态的这样判断切换反复出现,我们就要联想到是否可以采取State模式了. 不只是根据状态,也有根据属性.如果某个对象的属性不同,对象的行为就不一样,这点在数据库系统中出现频率比较高,我们经常会在一个数据表的尾部,加上property属性含义的字段,用以标识记录中一些特殊

设计模式 ( 十八 ):State状态模式 -- 行为型

1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ellse语句来做状态判断来进行不同情况的处理.但是对复杂状态的判断就显得“力不从心了”.随着增加新的状态或者修改一个状体(if else(或switch case)语句的增多或者修改)可能会引起很大的修改,而程序的可读性,扩展性也会变得很弱.维护也会很麻烦.那么我就考虑只修改自身状态的模式. 例子1:按钮来控制一个电梯的状态,一个电梯开们,关门,停,

Unity客户端框架笔记(状态模式和策略模式在游戏中的应用)

最近花了几天时间梳理了一下新游戏的客户端框架,虽然本身就有相对明确的方向,但是在一开始写的时候还是有些混乱,不过最终梳理完成后,个人感觉代码清爽很多. 这篇文章不是设计模式的教学,而是自己的一些想法和实践,我把代码梳理成自己喜欢的结构,保证逻辑和结构的清晰,但是这并不意味者它是符合所有人习惯的. 我之前有写过一两篇文章讨论客户端的结构,也吐槽过一些其他人的设计.可以说我在写代码之初就有一个相对明确的方向,多年的经验也可以告诉我什么样的代码是漂亮的,什么样的代码是有坏味道的. 首先我把客户端结构分

设计模式 ( 十七) 状态模式State(对象行为型)

1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ellse语句来做状态判断来进行不同情况的处理.但是对复杂状态的判断就显得“力不从心了”.随着增加新的状态或者修改一个状体(if else(或switch case)语句的增多或者修改)可能会引起很大的修改,而程序的可读性,扩展性也会变得很弱.维护也会很麻烦.那么我就考虑只修改自身状态的模式. 例子1:按钮来控制一个电梯的状态,一个电梯开们,关门,停,

JavaScript中的设计模式:状态模式

前几天写了一个贪吃蛇小游戏,正好用到了状态模式. 定义 当一个对象内部状态发生改变时候,会导致其行为的改变,这看起来像是改变了对象. 简单的例子 如果一个函数要更具某一个对象的状态来判断该对象应该执行的方法,那么这个函数中会增加很多if判断分支,并且,如果要增加这个对象的一种状态,那么就要在原来的代码中添加一些判断,比较麻烦.例如,贪吃蛇有移动.吃食物.死亡等状态,如果我在处理这些状态的时候这么写代码(如下面) this.process = function(point){ if (this.i

设计模式之状态模式(State)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以