在控制台中打印时,如何将循环打印出来的形状移动到文本中

时间:2016-05-06 00:36:21

标签: c++ console output

我一直在做很多阅读,并且在C ++中没有找到任何良好的控制台输出格式。我正在打印一个带有循环的三角形,我知道如何打印它,但我想在控制台中移动它,所以我可以在cathetus旁边有文字。

所以我希望我的输出像

                             *
                             * *
                8.5 inches   *   *
                             *     *                           
                             *********

这是绘制三角形的函数:

void Triangle::DisplayTriangle() {


    for (int x = 0; x <= 10; x++) {
        setprecision(2);

        for (int j = x; j > 10; j++)    cout << " ";
        for (int z = 0; z <= x; z++) {
            if (x == 10) {
                cout << '*';
            }
            else if (z == 0 || z == x) cout << "*";
            else cout << " ";
        }
        for (int y = 0; y < x; y++) {
            cout << " ";
        }
            cout << endl;

    }
}

1 个答案:

答案 0 :(得分:1)

当目标输出变得更复杂时,手动循环绘制形状会变得非常困难。

所以在某些时候,你会想要使用一个文本绘图库(比如K. Shores提到的ncurses)。

然而,滚动你自己的简单绘图API不是脑部手术:

#include <iostream>

namespace auto_list_exploit {
    static auto li = {1,2};
    using initializer_list = decltype(li);
}

template <typename CT=char>
class TextSurface {
    using initializer_list = auto_list_exploit::initializer_list;
public:
    struct point {
        int x,y;
        point(int x=0, int y=0) : x(x), y(y) {}
        point(initializer_list list) : x((list.begin())[0]), y((list.begin())[1]) {}
    };
private:
    int m_width, m_height, m_data_count;
    CT* m_data;

    int OffsetOf(int x, int y) const { return y * m_width + x; }
    bool IsInside(int x, int y) { return x >= 0 && y>= 0 && x < m_width && y < m_height; }
    CT& at(int x, int y) { return m_data[OffsetOf(x,y)]; }
    CT at(int x, int y) const { return m_data[OffsetOf(x,y)]; }

    int Abs(int x) { return x < 0 ? -x : x; }

    void Poly(const point& pfirst, CT value, const point& plast) {
        Line(plast, pfirst, value);
    }
    template <typename ...Ts>
    void Poly(const point& pfirst, CT value, const point& p0, const point& p1, Ts...args) {
        Line(p0, p1, value);
        Poly(pfirst, value, p1, args...);
    }
public:
    TextSurface(int width=0, int height=0) : 
        m_width(height ? width : 0), 
        m_height(width ? height : 0),
        m_data_count(width * height)
    {
        m_data = m_data_count ? new CT[m_data_count] : nullptr;
        Clear();
    }
    // Cannot copy
    TextSurface(const TextSurface&) =delete;
    TextSurface& operator = (const TextSurface&) =delete;
    // Can return from functions
    TextSurface& operator = (TextSurface&& src) {
        delete [] m_data;
        m_width = src.m_width; m_height = src.m_height; m_data_count = src.m_data_count;
        m_data = src.m_data;
        src.m_data = nullptr;
        return *this;
    }
    TextSurface(TextSurface&& src) : m_data(nullptr) { operator = ((TextSurface&&)src); }
    ~TextSurface() { delete [] m_data; }

    int Width() const { return m_width; }
    int Height() const { return m_height; }
    void Clear(CT value=' ') {
        CT* p = m_data;
        CT* pe = p + m_data_count;
        while(p != pe) *(p++) = value;
    }
    void Line(int x0, int y0, int x1, int y1, CT value) {
        const int dx = x1-x0;
        const int dy = y1-y0;
        if(!dx && !dy) {
            if(IsInside(x0, y0)) { at(x0, y0) = value; }
            return;
        }
        const bool ymajor = Abs(dy) > Abs(dx);
        int x=x0, y=y0;
        int &mj = ymajor ? y : x;
        int &mn = ymajor ? x : y;
        const int mje = ymajor ? y1 : x1;
        const int mjst = mj < mje ? 1 : -1;
        double mnd = mn;
        double mnst = ymajor ? double(dx)/Abs(dy) : double(dy)/Abs(dx);
        do {
            mn = int(mnd + 0.5);
            if(IsInside(x,y)) { at(x,y) = value; }
            mj += mjst;
            mnd += mnst;
        } while(mj != mje+mjst);
    }
    void Line(const point& p0, const point& p1, CT value) { Line(p0.x, p0.y, p1.x, p1.y, value); }

    template <typename ...Ts>
    void Poly(CT value, const point& p0, const point& p1, Ts...args) {
        Line(p0, p1, value);
        Poly(p0, value, p1, args...);
    }
    // init-list overloads for triangle and quad (initializer_list can't be packed)
    void Poly(CT value, initializer_list l0, initializer_list l1, initializer_list l2) { Poly(value, point(l0), point(l1), point(l2)); }
    void Poly(CT value, initializer_list l0, initializer_list l1, initializer_list l2, initializer_list l3) { Poly(value, point(l0), point(l1), point(l2), point(l3)); }

    void Rect(int x, int y, int width, int height, CT value) {
        Poly(value, point(x,y), point(x+width-1, y), point(x+width-1, y+height-1), point(x, y+height-1));
    }
    // Label places text. xloc selects the meaning of the x coordinate.
    // Its value is between -1 and 1: -1 for x at the left of the text,
    // 0 for x in the middle, and 1 for x at the end of the text.
    void Label(const CT* text, int x, int y, double xloc=-1) {
        int len = 0;
        while(text[len]) { ++len; }
        x -= int((xloc + 1)/2 * (len - 1));
        for(int i=0; i<len; ++i) {
            if(IsInside(x,y)) { at(x,y) = text[i]; }
            ++x;
    }   }
    void Present() const {
        const CT* p = m_data; 
        for(int j=0; j<m_height; ++j) {
            std::cout.write(p, m_width);
            std::cout << '\n';
            p += m_width;
    }   }
};

typedef TextSurface<char> CharSurface;

int main() {
    CharSurface surf(60,20);
    surf.Poly('*', {20,2}, {34,16}, {20,16});
    surf.Label("14 ft", 18, 10, 1);
    surf.Label("9 ft", 26, 17, 0);
    surf.Present();
}

http://ideone.com/i03DV8

main()输出中的示例:

                *
                **
                * *
                *  *
                *   *
                *    *
                *     *
                *      *
          14 ft *       *
                *        *
                *         *
                *          *
                *           *
                *            *
                ***************
                     9 ft