【问题标题】:graphic drawing class organisation绘图班组织
【发布时间】:2016-02-08 11:00:28
【问题描述】:

我有一个基本的 4x20 字符 LCD,我想用它来显示带有按钮的菜单,使用 Arduino 作为驱动程序(有限的标准库支持)。

Example LCD menu and buttons

我正在考虑生成一个接口类 GraphicObject,然后所有图形对象都从该类继承(例如 Button、MenuItem 等)。 GraphicObject 类应该有一个可以被覆盖的 draw 方法似乎是合乎逻辑的。

目前,我有一个名为 Lcd 的课程,它涵盖了文本和字符定位的低级绘制。为了绘制任何东西,我需要访问这些 Lcd 对象之一。如果我在我的 GraphicObject 或派生对象中包含指向 Lcd 对象的指针,我会将它们耦合并使其成为仅 Lcd 对象。如果我更改显示设备的类型,这些类将不再适用。

如何组织这些类以保持它们松散耦合并允许在以后更改显示类型?我是否应该有 LCDButton LCDMenuItem,然后从 Button 和 MenuItem 接口继承,然后为其他显示设备 (OtherDisplayButton OtherDisplayMenuItem) 创建其他对象?

有什么推荐的读物吗?我看过很多例子,但似乎都没有详细介绍绘图方法的功能以及是直接访问设备还是通过另一个控制对象访问设备。

谢谢

编辑 1

简要代码思路概述

#include "Arduino.h"

class Lcd {
public:
  struct Parameters {
    uint_fast8_t numberLines;
    uint_fast8_t numberCharacters;
//  uint_fast8_t* lineOffsets;
    Print* serial; // Can be any Serial device (all inherit from Print).
  };

protected:
  Parameters parameters_;
  const uint_fast8_t escapeCode_ = 0x1B;
  const uint_fast8_t directCode_ = 0xFE;

  void sendCommand_(uint_fast8_t command, uint_fast8_t parameter = 0);
  void sendCommandDirect_(uint_fast8_t command);

public:
  Lcd(Parameters parameters);
  void clearDisplay(void);
  void moveCursor(uint_fast8_t line, uint_fast8_t character);
  void resetDisplay(void);
  void customCharacter(const uint_fast8_t address,
      const uint_fast8_t characterMap[8]);

  void write(uint8_t character);

  // Boilerplate print forwarders.
  void print(const char character);
  void print(const String &string);
  void print(const char string[]);

  // Boilerplate println forwarders.
  void println(const char character);
  void println(const String &string);
  void println(const char string[]);
  void println(void);
};

class GraphicObject {
  virtual void draw(void)=0;
};

class Button: public GraphicObject {
public:
  typedef void (*buttonAction)(void);
  virtual void setText(const String text)=0;
  virtual const String getText() =0;
  virtual bool isActive()=0;
  virtual void setActive(bool)=0;
  virtual void setAction(buttonAction action)=0;
};

class MenuItem: public Button {
public:
  typedef void (*menuAction)(void);
  virtual MenuItem* parentItem()=0;
  virtual const MenuItem* addItem(String text, menuAction action)=0;
};

class VScrollbar: public GraphicObject {
public:
  virtual void setAtTop(bool atTop);
  virtual void setAtBottom(bool atBottom);
};

class LcdButton: public Button {
private:
  Lcd* lcd_;
  String text_;bool active_;
public:
  LcdButton(Lcd* lcd);
  void draw(void);
  void setText(String text);
  const String getText();bool isActive();
  void setActive(bool);
  void setAction(Button::buttonAction action);
};

class LcdWindow: public GraphicObject {
private:
  LcdButton* lcdButtons_ = nullptr;
public:
  enum class Position
    : uint_fast8_t {
      LEFT,
    RIGHT
  };

  bool addButton(LcdButton* lcdButton, uint_fast8_t line, uint_fast8_t offset);

  bool addVScrollbar(VScrollbar* vScrollbar, Position position);
  void draw();
};

int main(void) {
  Lcd::Parameters lcdParameters;
  lcdParameters.numberCharacters = 20;
  lcdParameters.numberLines = 4;
  lcdParameters.serial = &Serial1;
  Lcd lcd = Lcd(lcdParameters);
  LcdButton myButton(&lcd);
  myButton.setText("Select");
  myButton.setActive(true);
  LcdWindow lcdWindow;
  lcdWindow.addButton(&myButton, 1, 1);
  lcdWindow.draw();
  while (1){}
  return 0;
}

【问题讨论】:

  • 你能发布一些你的代码吗?发布按钮的定义,然后声明和使用它。
  • 你可以看看现有的 arduino 的 lcd gui 实现,例如 m2tklib
  • @jabujavi 抱歉,直到一个小时后我才收到有关您评论的通知!添加的一些示例代码(希望)说明了我的想法。
  • @Lanting 谢谢。我会阅读这篇文章并希望能得到一些想法,尽管乍一看它看起来不像 OOP。

标签: c++ oop arduino embedded


【解决方案1】:

有不同的方法可以做到这一点。原则上,您应该为您的低级 LCD 驱动模块定义一个接口 (API),并且只调用您的低级 api 的函数来绘制一些东西。然后可以在不需要更改高级代码的情况下交换此 api 的实现。

最简单的方法是定义一个抽象的 c++ 基类,所有 lcd 驱动程序的实现都必须从该基类派生。基类应具有需要由派生实现重载的虚拟方法。

但有一点信息:c++ 类中的虚方法要求编译器为每个对象在实例化时创建的对象生成一个方法指针表;这需要更多的内存。此外,对这些类的对象的所有函数调用都是间接的(编译器生成的代码首先查找真正的函数指针,然后使用这个指针调用函数),这使得生成的代码稍微慢一些。

【讨论】:

  • 谢谢。我会再考虑一下。我最初试图做到这一点,以便将来可以将当前基于线条和字符的 LCD 换成具有像素和颜色的 LCD。虚拟表?一周前我读过这些(我只使用 C++ 大约 4-6 周)。代码的可扩展性可能会压倒性能损失,但我会记住这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-13
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多