所以我正在创建一个图形计算器。我有一个输入字符串s。从字符串中,我可以使用SFML对其进行绘图。我从MIN X坐标到MAX X坐标开始,从EvaluateString()方法获得对应的y,所有坐标都到VertexArray v。我已经编写了我的方法和制图方法,并且都运行良好
但是,我有一个小问题。我想在屏幕上输入我的字符串,例如“ sin(cos(tan(x)))”。我正在努力寻找一种方法来做到这一点。我有点想出它与事件TextEntered有关,但仍然无法完全找到任何东西。
请给我建议一个方法。
class Calculator{
public:
void main();
private:
WindowSize DefaultWindow;
sf::RenderWindow window;
Cartesian vertexX[2],vertexY[2];
sf::Vertex axis[4];
const double MAX = 10;
const double MIN = -10;
const double INCREMENT = 0.001;
};
int main(){
DefaultWindow.Max = Cartesian(10,10);
DefaultWindow.Min = Cartesian(-10,-10);
DefaultWindow.plane.width=1500;
DefaultWindow.plane.height=1500;
// Set up x and y-axis
vertexX[0] = Cartesian(-100,0);
vertexX[1] = Cartesian(100, 0);
vertexY[0] = Cartesian(0,-100);
vertexY[1] = Cartesian(0,100);
axis[0] = sf::Vertex(convertCartesiantoWindow(vertexX[0],DefaultWindow));
axis[1] = sf::Vertex(convertCartesiantoWindow(vertexX[1],DefaultWindow));
axis[2] = sf::Vertex(convertCartesiantoWindow(vertexY[0],DefaultWindow));
axis[3] = sf::Vertex(convertCartesiantoWindow(vertexY[1],DefaultWindow));
// Set up the window
window.create(sf::VideoMode(1500, 1500), "Graphing calculator");
// Input string
string s = "sin(cos(tan(x)))";
// Stack c contains all the Cartesian coordinate vertices
// Cartesian is a struct which contains x and y coordinates
Stack<Cartesian> c;
sf::VertexArray v;
// For a certain function in string s, I evaluate it
// and return the y_coordinate from the function EvaluateString (s, i)
// Push each (x,y) evaluated in the Stack c
for (double i = MIN; i <= MAX; i+= INCREMENT)
c.Push(Cartesian(i,EvaluateString(s,i)));
// v is VertexArray which contains all the vertices (x,y)
v = plot(DefaultWindow, c);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
window.close();
break;
}
}
}
// Draw the graph
window.clear(sf::Color::Black);
window.draw(axis,4,sf::Lines);
window.draw(v);
window.display();
}
答案 0 :(得分:11)
像@super suggest一样,使用一个库将是一个很好的解决方案,并且肯定比我的要好,但是只要满足您的需求,我就实现了 super basic {{1} }类。
可能有很多错误,但可以为您提供有关如何归档该功能的想法。
TextField
只不过是包含文本的矩形。由于它将具有TextField
,因此必须具有sf::Text
。另外,我限制它将包含的字符数。为了让我们在sf::Font
内书写,我们必须知道是否已选中它,即它是否具有 focus 。因此,第一种方法可能是:
TextField
我们需要一个用于此类的构造函数:
class TextField : public sf::Transformable, public sf::Drawable{
private:
unsigned int m_size;
sf::Font m_font;
std::string m_text;
sf::RectangleShape m_rect;
bool m_hasfocus;
};
我们还需要一些基本方法,我们想在其中获取文本:
class TextField : public sf::Transformable, public sf::Drawable{
public:
TextField(unsigned int maxChars) :
m_size(maxChars),
m_rect(sf::Vector2f(15 * m_size, 20)), // 15 pixels per char, 20 pixels height, you can tweak
m_hasfocus(false)
{
m_font.loadFromFile("C:/Windows/Fonts/Arial.ttf"); // I'm working on Windows, you can put your own font instead
m_rect.setOutlineThickness(2);
m_rect.setFillColor(sf::Color::White);
m_rect.setOutlineColor(sf::Color(127,127,127));
m_rect.setPosition(this->getPosition());
}
private:
unsigned int m_size;
sf::Font m_font;
std::string m_text;
sf::RectangleShape m_rect;
bool m_hasfocus;
};
并移动它,将其放置在我们的窗口内:
const std::string sf::TextField::getText() const{
return m_text;
}
这是一个棘手的问题。我们正在覆盖void sf::TextField::setPosition(float x, float y){
sf::Transformable::setPosition(x, y);
m_rect.setPosition(x, y);
}
中的setPosition
method,因为我们需要更新自己的sf::Transformable
。
此外,我们需要知道盒子内是否有点:
m_rect
非常简单,我们使用sfml中已有的bool sf::TextField::contains(sf::Vector2f point) const{
return m_rect.getGlobalBounds().contains(point);
}
的{{1}}方法。
设置(或取消设置)焦点于cointains
:
sf::RectangleShape
容易的。为了美观,我们还会在聚焦时更改框的轮廓颜色。
最后但并非最不重要的一点是,我们的TextField
必须在收到输入(也称为void sf::TextField::setFocus(bool focus){
m_hasfocus = focus;
if (focus){
m_rect.setOutlineColor(sf::Color::Blue);
}
else{
m_rect.setOutlineColor(sf::Color(127, 127, 127)); // Gray color
}
}
)时采取某种方式:
TextField
我知道删除键检查有点脏。也许您可以找到更好的解决方案。
仅此而已!现在sf::Event
看起来像:
void sf::TextField::handleInput(sf::Event e){
if (!m_hasfocus || e.type != sf::Event::TextEntered)
return;
if (e.text.unicode == 8){ // Delete key
m_text = m_text.substr(0, m_text.size() - 1);
}
else if (m_text.size() < m_size){
m_text += e.text.unicode;
}
}
概念证明:
答案 1 :(得分:-1)
std::string str;
sf::String text;
// In event loop...
if (event.Type == sf::Event::TextEntered)
{
// Handle ASCII characters only
if (event.Text.Unicode < 128)
{
str += static_cast<char>(event.Text.Unicode);
text.SetText(str);
}
}
// In main loop...
window.Draw(text);
这应该创建一个sf :: Event :: TextEntered输入,并创建一个sf :: String输出