【发布时间】:2016-02-08 11:00:28
【问题描述】:
我有一个基本的 4x20 字符 LCD,我想用它来显示带有按钮的菜单,使用 Arduino 作为驱动程序(有限的标准库支持)。
我正在考虑生成一个接口类 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。