> Свободная база знаний SFML > SFML-Документация > Системный модуль - System Module > Потоки - Threads > Урок 2. mcText - многострочный цветной текст
Проблема: в SFML есть класс sf::Text который предоставляет возможность целиком окрасить текст только в один цвет.
Доп. проблема: многострочность текста.
Исходя из этих проблем, существовало два выхода:
1. Поискать в великом Интернете.
2. Писать самому.
Поиск в интернете дал один результат, но он годиться только для SFML2, поэтому пришлось велосипедить.
Потребность в подобном классе возникла при создании интерфейса для отображения описания артефактов в игровом окне.
Сейчас он выглядит примерно так:
Данный класс не идеален и требует доработки, но в общих чертах он отражает суть решаемой проблемы.
Листинги класса mcText
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
#include "stdafx.h" #pragma once ///////////////////////////////// // multiline colored text // mcText ///////////////////////////////// // структура содержащая информацию о тексте struct mcTextInfo { sf::String str; // Строка sf::Color color; // Цвет int w; // ширина текста int h; // высота текста int dx; // смещение текста по X int dy; // смещение текста по Y mcTextInfo() { data(); } void data() { w = 0; h = 0; dx = 0; dy = 0; color = sf::Color::Black; } }; class mcText { public: bool isLimitW; // нужно ли учитывать ограничение по ширине int dx; // меняется в программе автоматически int dy; // меняется в программе автоматически int limitW; // ограничение по ширине sf::Font* font; // ссылка на шрифт int charSize; // размер символа std::vector<mcTextInfo*> vecInfo; // вектор содержащий описания текстов std::vector<sf::Text> vecText; // вектор содержащий сами тексты void data(); // задаёт начальную информацию public: mcText(sf::Font* f); ~mcText(void); void setLimit(bool flag, int num); void add(sf::String str); void add(sf::String str, sf::Color color); void add2(sf::String str); void enter(); void space(int value); void spaceY(int value); void move(float dx, float dy); void setPosition(float x, float y); void draw(sf::RenderWindow* window); std::vector<sf::String> scanWords(sf::String str); std::vector<sf::String> scanString(int w, std::vector<sf::String> vecWords_, sf::Text* text); void clear(); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
#include "mcText.h" void mcText::data() { dx = 0; dy = 0; charSize = 16; setLimit(false, 0); add(""); } mcText::mcText(sf::Font* f) { font = f; data(); } mcText::~mcText(void) { } // установить ограничение по горизонтали void mcText::setLimit(bool flag, int num) { isLimitW = flag; limitW = num; } // добавить небольшую строку void mcText::add(sf::String str) { add(str, sf::Color::Black); } // доавить небольшую цветную строку void mcText::add(sf::String str, sf::Color color) { mcTextInfo* t = new mcTextInfo(); t->color = color; t->str = str; // Создаём текст sf::Text text; text.setFont(*font); text.setCharacterSize(charSize); text.setColor(t->color); text.setString(t->str); // Как всё гениально и просто, я аж сам офигел когда придумал t->w = text.getLocalBounds().width; t->h = text.getLocalBounds().height; t->dx = dx; dx += t->w; t->dy = dy; // Если включено ограничение по W if(isLimitW && (t->dx + t->w > limitW)) { enter(); t->dx = dx; t->dy = dy; } text.move(t->dx, t->dy); vecInfo.push_back(t); vecText.push_back(text); } // Добавление большого многострочного текста void mcText::add2(sf::String str) { std::vector<sf::String> vecWords; std::vector<sf::String> vecStrings; sf::Text text = vecText[0]; //режем текст на слова vecWords = scanWords(str); //распределяем слова по строкам (учитывая ограничение) vecStrings = scanString(limitW, vecWords, &text); //добавляем строки в основной вектор строк for(int i=0; i<vecStrings.size(); i++) { add(vecStrings[i]); enter(); } }; // Переход на следующую строку void mcText::enter() { dx = 0; dy += charSize; } // отступит на value пикселей по горизонтали void mcText::space(int value) { dx += value; } // отступит на value пикселей по вертикали void mcText::spaceY(int value) { dy += value; } // переместить весь текст на dx:dy void mcText::move(float dx, float dy) { for(std::vector<sf::Text>::iterator it = vecText.begin(); it != vecText.end(); it++) (*it).move(dx, dy); } // переместить весь текст в координаты x:y void mcText::setPosition(float x, float y) { for(int i=0; i<vecText.size(); i++) vecText[i].setPosition(x + vecInfo[i]->dx, y + vecInfo[i]->dy); } // отрисовать во входящем окне void mcText::draw(sf::RenderWindow* window) { for(std::vector<sf::Text>::iterator it = vecText.begin(); it != vecText.end(); it++) window->draw(*it); } // Возвращает вектор слов без пробелов | принимает текст std::vector<sf::String> mcText::scanWords(sf::String str) { std::vector<sf::String> vecStr; sf::String buff; for(int i=0; i<str.getSize(); i++) if(str[i] != ' ') buff += str[i]; else if(buff != "") { vecStr.push_back(buff); buff = ""; } vecStr.push_back(buff); return vecStr; } // Возвращает вектор готовых строк | Принимает ширину и вектор слов и НАСТРОЕННЫЙ текст (с шрифтом и размером) std::vector<sf::String> mcText::scanString(int w, std::vector<sf::String> vecWords_, sf::Text* text) { std::vector<sf::String> vecStr; sf::String buff; sf::String buff2; for(int i=0; i<vecWords_.size(); i++) { buff = buff2; if(buff2 == "") buff2 += vecWords_[i]; else buff2 += " " + vecWords_[i]; text->setString(buff2); // делаем строку чтобы измерить ширину строки if(text->getLocalBounds().width > w) {// Если при добавлении слова ширина стала больше нужной vecStr.push_back(buff); // добавляем в вектор строк буфер1 (не содержит последнего слова) buff = ""; // чистим буфер1 buff2 = vecWords_[i]; // в буфер2 засовываем последнее слово (т.к. перенос на след. строку) } } vecStr.push_back(buff2); return vecStr; } // Полностью очистить текст void mcText::clear() { vecInfo.clear(); vecText.clear(); data(); } |
Архив с исходными файлами и проектом
mcText_test