I am trying to use a rich edit control to output some text on the screen:
Monday Press 1.
Your day is Monday
Tuesday Press 2.
I can't really find any simple examples of how to do this. all i have been able to sort out is setting the window text (setWindowText), but everything else is escaping me.
Any short examples?
Despite the comments, I'm going to answer the question you asked, about how to format data in a Rich Edit control. A few years ago, I had to do this, and came up with something that I could treat a little like an IOstream (if I were doing it today, I'd probably do it a bit differently, but such is life).
First, code to act like an IOstream, but write to a rich-edit control:
// rich_stream.h:
#ifndef RICH_STREAM_H
#define RICH_STREAM_H
class rich_stream {
CRichEditCtrl &ctrl;
public:
rich_stream(CRichEditCtrl &ctrl_) : ctrl(ctrl_) { }
void add_text(char const *txt) {
ctrl.SetSel(-1,-1);
ctrl.ReplaceSel(txt);
}
void add_int(int val) {
CString temp;
temp.Format("%d", val);
add_text(temp);
}
void set_char_format(CHARFORMAT &fmt) {
ctrl.SetSelectionCharFormat(fmt);
}
};
inline rich_stream &operator<<(rich_stream &s, char const *t) {
s.add_text(t);
return s;
}
inline rich_stream &operator<<(rich_stream &s, CHARFORMAT &fmt) {
s.set_char_format(fmt);
return s;
}
inline CString nl() {
return CString("\n\n");
}
inline rich_stream &operator<<(rich_stream &s, CString (*f)()) {
s.add_text(f());
return s;
}
inline rich_stream &operator<<(rich_stream &s, int val) {
s.add_int(val);
return s;
}
#endif
Then, I'd use this something like:
CHARFORMAT bold;
memset(&bold, 0, sizeof(bold));
bold.cbSize = sizeof(bold);
bold.dwMask = CFM_BOLD | CFM_FACE | CFM_SIZE;
bold.dwEffects = CFE_BOLD;
strcpy(bold.szFaceName, "Times");
bold.yHeight = 14 * 20;
CHARFORMAT normal;
memset(&normal, 0, sizeof(normal));
normal.cbSize = sizeof(normal);
normal.dwMask = CFM_BOLD | CFM_FACE | CFM_SIZE;
normal.dwEffects = 0;
strcpy(normal.szFaceName, "Times");
normal.yHeight = 14 * 20;
// ...
rich_stream txt(GetRichEditCtrl());
txt << bold << "Heading 1: " << normal << info1 << nl
<< bold << "Heading 2: " << normal << info2 << nl
<< bold << "Heading 3: " << normal << info3;
If I were doing this today, I'd almost certainly create a small class as a wrapper for a CHARFORMAT so I could construct the formatting objects a little more cleanly. I'd probably also at least think hard about implementing it as a normal iostream with a stream buffer that inserted data into the rich edit control (but at the time I didn't know streams well enough to know I should do that).
Glancing at it, there are a few other things that aren't really exactly right either -- add_text uses SetSel(-1, -1);. This should really retrieve the current length of the text (e.g., with GetWindowTextLength, and set the selection to just after the end.
Use Wordpad, it's an RichEdit control too. It will generate your RTF in a way that's naturally compatible with your control.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
How to make the c ++ application work with the browser. I mean a program that retrieves data from a given page (let's assume that the page displays a string) and then performs some reaction on the page. For example, the page displays a random string, and the program enters the length of the string into the form.
I am a novice programmer, so I care about information and advice on where to start. Thanks in advance for any help.
As I already promised to OP in comments, posting Partial answer, which doesn't answer all questions, but only provides handy tool to wrap (call) any Python code inside C++ program.
In my code snippet I don't even do anything with browsers, but instead show only example of computing Greatest Common Divisor using Python's standard function math.gcd().
I decided to introduce this Python-in-C++ bridge only because there exist many beautiful Python modules that work with browsers or with parsing/composing HTML, hence it is much easier to write such tools in Python instead of C++.
But expert without knowledge of default Python C API, it is not that easy to implement even simple use case - compile text of Python code, pass to it any arguments from C++, receive response arguments, return arguments back to C++. Only these simple actions need usage of a dozen of different Python C API functions. That's why I decided to show how to do it, as I know.
I implemented from scratch (specifically for OP's question) handy class PyRunner which does all the magic, usage of this class is simple:
PyRunner pyrun;
std::string code = R"(
def gcd(a, b):
import math
return math.gcd(a, b)
res = gcd(*arg)
print('GCD of', arg[0], 'and', arg[1], 'is', res, flush = True)
)";
std::cout << pyrun.Run(code, "(2 * 3 * 5, 2 * 3 * 7)") << std::endl;
std::cout << pyrun.Run(code, "(5 * 7 * 11, 5 * 7 * 13)") << std::endl;
Basically you just pass any Python code snippet to PyRunner::Run() method and also any argument (represented as Python object converted to string). Result of this call is also a returned Python object converted to string. You can also use JSON to pass any large argument as string and parse returned argument, as any JSON string is also a valid stringized Python object.
Of course you need a knowledge of Python to be able to write complex code snippets inside C++.
One drawback of my PyRunner class is that for some reason (that I didn't yet understand), you can't import Python module inside global scope, as you can see I did import math within function scope. But this is not a big deal, I think, and maybe some experts will clarify the reason.
To compile and run code you need to have pre-installed Python, and pass Python's include folder and library file as compiler arguments. For example in Windows CLang you do following:
clang.exe -std=c++20 -O3 -Id:/bin/Python39/include/ d:/bin/Python39/libs/python39.lib prog.cpp
and in Linux:
clang -std=c++20 -O3 -I/usr/include/ -lpython3.9 prog.cpp
To run the program either you should provide environment variables PYTHONHOME or PYTHONPATH or run program from Python folder (like d:/bin/Python39/) or do sys.path.append("d:/bin/Python39/") on first lines of Python code snippet embedded in C++. Without these paths Python can't find location of its standard library.
PyRunner class is thread-safe, but only single-threaded always. It means that two calls to .Run() inside two threads will be exclusively blocked by mutex. I use std::mutex instead of Python's GIL to protect from multi-threading, because it is quite alright (and faster), if you don't use Python C API in any other threads simultaneously. Also it is not allowed right now to have two instances of PyRunner objects as it does Py_Initialize() and Py_FinalizeEx() in constructor and destructor, which should be done globally only once. Hence PyRunner should be a singleton.
Below is full C++ code with implementation of PyRunner class and its usage (usage is inside main()). See console output after code below. Click Try it online! link to see compile/run of this code on free GodBolt online Linux servers.
Try it online!
#include <iostream>
#include <functional>
#include <string>
#include <string_view>
#include <stdexcept>
#include <memory>
#include <mutex>
#include <Python.h>
#define ASSERT_MSG(cond, msg) { if (!(cond)) throw std::runtime_error("Assertion (" #cond ") failed at line " + std::to_string(__LINE__) + "! Msg: '" + std::string(msg) + "'."); }
#define ASSERT(cond) ASSERT_MSG(cond, "")
#define PY_ASSERT_MSG(cond, msg) { if (!(cond) || PyErr_Occurred()) { PyErr_Print(); ASSERT_MSG(false && #cond, msg); } }
#define PY_ASSERT(cond) PY_ASSERT_MSG(cond, "")
#define LN { std::cout << "LN " << __LINE__ << std::endl << std::flush; }
class PyRunner {
private:
class PyObj {
public:
PyObj(PyObject * pobj, bool inc_ref = false) : p_(pobj) {
if (inc_ref)
Py_XINCREF(p_);
PY_ASSERT_MSG(p_, "NULL PyObject* passed!");
}
PyObject * Get() { return p_; }
~PyObj() {
Py_XDECREF(p_);
p_ = nullptr;
}
private:
PyObject * p_ = nullptr;
};
public:
PyRunner() {
Py_SetProgramName(L"prog.py");
Py_Initialize();
}
~PyRunner() {
codes_.clear();
Py_FinalizeEx();
}
std::string Run(std::string code, std::string const & arg = "None") {
std::unique_lock<std::mutex> lock(mutex_);
code = StrUnIndent(code);
if (!codes_.count(code))
codes_.insert(std::pair{code, std::make_shared<PyObj>(Py_CompileString(code.c_str(), "script.py", Py_file_input))});
PyObj & compiled = *codes_.at(code);
PyObj globals_arg_mod = PyModule_New("arg"), globals_arg = PyModule_GetDict(globals_arg_mod.Get()), locals_arg = PyDict_New(),
globals_mod = PyModule_New("__main__"), globals = PyModule_GetDict(globals_mod.Get()), locals = PyDict_New();
// py_arg = PyUnicode_FromString(arg.c_str()),
PyObj py_arg = PyRun_String(arg.c_str(), Py_eval_input, globals_arg.Get(), locals_arg.Get());
PY_ASSERT(PyDict_SetItemString(locals.Get(), "arg", py_arg.Get()) == 0);
#if 0
PyObj result = PyEval_EvalCode(compiled.Get(), globals.Get(), locals.Get());
#else
PyObj builtins(PyEval_GetBuiltins(), true), exec(PyDict_GetItemString(builtins.Get(), "exec"), true);
PyObj exec_args = PyTuple_Pack(3, compiled.Get(), globals.Get(), locals.Get());
PyObj result = PyObject_CallObject(exec.Get(), exec_args.Get());
#endif
PyObj res(PyDict_GetItemString(locals.Get(), "res"), true), res_str = PyObject_Str(res.Get());
char const * cres = nullptr;
PY_ASSERT(cres = PyUnicode_AsUTF8(res_str.Get()));
return cres;
}
private:
static std::string StrUnIndent(std::string_view const & s) {
auto lines = StrSplit(s, "\n");
size_t min_off = size_t(-1);
for (auto const & line: lines) {
if (StrTrim(line).empty())
continue;
min_off = std::min<size_t>(min_off, line.find_first_not_of("\t\n\v\f\r "));
}
ASSERT(min_off < 10000ULL);
std::string res;
for (auto const & line: lines)
res += line.substr(std::min<size_t>(min_off, line.size())) + "\n";
return res;
}
static std::string StrTrim(std::string s) {
s.erase(0, s.find_first_not_of("\t\n\v\f\r ")); // left trim
s.erase(s.find_last_not_of("\t\n\v\f\r ") + 1); // right trim
return s;
}
static std::vector<std::string> StrSplit(std::string_view const & s, std::string_view const & delim) {
std::vector<std::string> res;
size_t start = 0;
while (true) {
size_t pos = s.find(delim, start);
if (pos == std::string::npos)
pos = s.size();
res.emplace_back(s.substr(start, pos - start));
if (pos >= s.size())
break;
start = pos + delim.size();
}
return res;
}
private:
std::unordered_map<std::string, std::shared_ptr<PyObj>> codes_;
std::mutex mutex_;
};
int main() {
try {
PyRunner pyrun;
std::string code = R"(
def gcd(a, b):
import math
return math.gcd(a, b)
res = gcd(*arg)
print('GCD of', arg[0], 'and', arg[1], 'is', res, flush = True)
)";
std::cout << pyrun.Run(code, "(2 * 3 * 5, 2 * 3 * 7)") << std::endl;
std::cout << pyrun.Run(code, "(5 * 7 * 11, 5 * 7 * 13)") << std::endl;
return 0;
} catch (std::exception const & ex) {
std::cout << "Exception: " << ex.what() << std::endl;
return -1;
}
}
Console output:
GCD of 30 and 42 is 6
6
GCD of 385 and 455 is 35
35
In some testing code there's a helper function like this:
auto make_condiment(bool salt, bool pepper, bool oil, bool garlic) {
// assumes that first bool is salt, second is pepper,
// and so on...
//
// Make up something according to flags
return something;
};
which essentially builds up something based on some boolean flags.
What concerns me is that the meaning of each bool is hardcoded in the name of the parameters, which is bad because at the call site it's hard to remember which parameter means what (yeah, the IDE can likely eliminate the problem entirely by showing those names when tab completing, but still...):
// at the call site:
auto obj = make_condiment(false, false, true, true); // what ingredients am I using and what not?
Therefore, I'd like to pass a single object describing the settings. Furthermore, just aggregating them in an object, e.g. std::array<bool,4>.
I would like, instead, to enable a syntax like this:
auto obj = make_smart_condiment(oil + garlic);
which would generate the same obj as the previous call to make_condiment.
This new function would be:
auto make_smart_condiment(Ingredients ingredients) {
// retrieve the individual flags from the input
bool salt = ingredients.hasSalt();
bool pepper = ingredients.hasPepper();
bool oil = ingredients.hasOil();
bool garlic = ingredients.hasGarlic();
// same body as make_condiment, or simply:
return make_condiment(salt, pepper, oil, garlic);
}
Here's my attempt:
struct Ingredients {
public:
enum class INGREDIENTS { Salt = 1, Pepper = 2, Oil = 4, Garlic = 8 };
explicit Ingredients() : flags{0} {};
explicit Ingredients(INGREDIENTS const& f) : flags{static_cast<int>(f)} {};
private:
explicit Ingredients(int fs) : flags{fs} {}
int flags; // values 0-15
public:
bool hasSalt() const {
return flags % 2;
}
bool hasPepper() const {
return (flags / 2) % 2;
}
bool hasOil() const {
return (flags / 4) % 2;
}
bool hasGarlic() const {
return (flags / 8) % 2;
}
Ingredients operator+(Ingredients const& f) {
return Ingredients(flags + f.flags);
}
}
salt{Ingredients::INGREDIENTS::Salt},
pepper{Ingredients::INGREDIENTS::Pepper},
oil{Ingredients::INGREDIENTS::Oil},
garlic{Ingredients::INGREDIENTS::Garlic};
However, I have the feeling that I am reinventing the wheel.
Is there any better, or standard, way of accomplishing the above?
Is there maybe a design pattern that I could/should use?
I think you can remove some of the boilerplate by using a std::bitset. Here is what I came up with:
#include <bitset>
#include <cstdint>
#include <iostream>
class Ingredients {
public:
enum Option : uint8_t {
Salt = 0,
Pepper = 1,
Oil = 2,
Max = 3
};
bool has(Option o) const { return value_[o]; }
Ingredients(std::initializer_list<Option> opts) {
for (const Option& opt : opts)
value_.set(opt);
}
private:
std::bitset<Max> value_ {0};
};
int main() {
Ingredients ingredients{Ingredients::Salt, Ingredients::Pepper};
// prints "10"
std::cout << ingredients.has(Ingredients::Salt)
<< ingredients.has(Ingredients::Oil) << "\n";
}
You don't get the + type syntax, but it's pretty close. It's unfortunate that you have to keep an Option::Max, but not too bad. Also I decided to not use an enum class so that it can be accessed as Ingredients::Salt and implicitly converted to an int. You could explicitly access and cast if you wanted to use enum class.
If you want to use enum as flags, the usual way is merge them with operator | and check them with operator &
#include <iostream>
enum Ingredients{ Salt = 1, Pepper = 2, Oil = 4, Garlic = 8 };
// If you want to use operator +
Ingredients operator + (Ingredients a,Ingredients b) {
return Ingredients(a | b);
}
int main()
{
using std::cout;
cout << bool( Salt & Ingredients::Salt ); // has salt
cout << bool( Salt & Ingredients::Pepper ); // doesn't has pepper
auto sp = Ingredients::Salt + Ingredients::Pepper;
cout << bool( sp & Ingredients::Salt ); // has salt
cout << bool( sp & Ingredients::Garlic ); // doesn't has garlic
}
note: the current code (with only the operator +) would not work if you mix | and + like (Salt|Salt)+Salt.
You can also use enum class, just need to define the operators
I would look at a strong typing library like:
https://github.com/joboccara/NamedType
For a really good video talking about this:
https://www.youtube.com/watch?v=fWcnp7Bulc8
When I first saw this, I was a little dismissive, but because the advice came from people I respected, I gave it a chance. The video convinced me.
If you look at CPP Best Practices and dig deeply enough, you'll see the general advice to avoid boolean parameters, especially strings of them. And Jonathan Boccara gives good reasons why your code will be stronger if you don't directly use the raw types, for the very reason that you've already identified.
I am new to g3log. I compiled and ran one of the examples I found in the repo, but was not able to ,modify it to print the log messages to the console rather than a file.
The following lines from the example set the logger:
auto worker = g3::LogWorker::createLogWorker();
auto handle= worker->addDefaultLogger(argv[0], path_to_log_file);
g3::initializeLogging(worker.get());
Where the line in the middle sets the prefix of the log and gives the path where the log file should be created.
How can I modify this code to print to the console\both the console and the file?
Thanks,
Omer.
You could define a customized sink class with a message receiver function that forward the
stripped message to console without formatting. Below is simplest form of the implementation:
class CustomSink {
public:
void forwardLogToStdout(g3::LogMessageMover logEntry) {
std::cout << logEntry.get().message() << std::endl;
}
};
So, in your code, you only need to replacing the worker->addDefaultLogger(...) by this snippet:
auto handle = worker->addSink(std::make_unique<CustomSink>(), &CustomSink::forwardLogToStdout);
from g3log github to implement colored console output you need:
struct ColorCoutSink {
// Linux xterm color
// http://stackoverflow.com/questions/2616906/how-do-i-output-coloured-text-to-a-linux-terminal
enum FG_Color {YELLOW = 33, RED = 31, GREEN=32, WHITE = 97};
FG_Color GetColor(const LEVELS level) const
{
if (level.value == WARNING.value) { return YELLOW; }
if (level.value == DEBUG.value) { return GREEN; }
if (g3::internal::wasFatal(level)) { return RED; }
return WHITE;
}
void ReceiveLogMessage(g3::LogMessageMover logEntry)
{
auto level = logEntry.get()._level;
auto color = GetColor(level);
std::cout << "\033[" << color << "m" << logEntry.get().toString() << "\033[m" << std::endl;
}
};
// in main.cpp, main() function
auto sinkHandle = logworker->addSink(std::make_unique<CustomSink>(),
&CustomSink::ReceiveLogMessage);
So if you remove color "things", the logger will output to console
I've settled on using lua as my config management for my programs after seeing posts like this and loving the syntax, and sol2 recently got released so I'm using that.
So my question is, how can I grab all the variables in my lua state and spit them out in a file?
say,
sol::state lua;
lua["foo"]["bar"] = 2;
lua["foo"]["foobar"] = lua.create_table();
would, in turn, eventually spit out
foo = {
bar = 2
foobar = {}
}
Is this at all possible and if so, how?
I used this serializer to serialize my table and print it out, really quite easy!
This is what I came up with
std::string save_table(const std::string& table_name, sol::state& lua)
{
auto table = lua["serpent"];
if (!table.valid()) {
throw std::runtime_error("Serpent not loaded!");
}
if (!lua[table_name].valid()) {
throw std::runtime_error(table_name + " doesn't exist!");
}
std::stringstream out;
out << table_name << " = ";
sol::function block = table["block"];
std::string cont = block(lua[table_name]);
out << cont;
return std::move(out.str());
}
I just read Joel's blog post on unicode, and found the characters the I want to use to draw boxes in the console in this pdf from the unicode website.
Displaying these characters is simple enough when done directly with cout, i.e. the following does what it is supposed to do..
cout << u8"\u256C";
However, I am doing some overloading as shown in the following snippets, and I cannot figure out how to get the box characters to display correctly.
I render my data like so ...
// This is the main rendering code
ostream& operator<<(ostream& os, const DataGrid& dg)
{
for(auto row : dg.data)
{
string tmp; //Make empty string
for(auto col : row)
tmp.append( 1, dg.gfxString[col] );
os << tmp << endl;
}
return os;
}
Make it friends with my data model...
class DataGrid
{
public:
friend ostream& operator<<(ostream& os, const DataGrid& dg);
//EDIT: rest of class added on request
DataGrid(Rectangle _rect = Rectangle(Point(0,0), Point(5,5))) :
rect(_rect),
data ( vector<vector<p_t>> (_rect.getHeight(), vector<p_t>(_rect.getWidth(), p_t::EMPTY)) ){}
void addPoint(Point p, p_t type)
{
data[p.getY()][p.getX()] = type;
}
void addBorder()
{
//Top and bottom
fill_n(data[0].begin()+1, rect.getWidth()-2, p_t::BORDER_T);
fill_n(data[rect.getBtm()].begin()+1, rect.getWidth()-2, p_t::BORDER_B);
//Left and right hand border edges
for (int nn=1; nn<rect.getHeight()-1; ++nn){
addPoint(Point(rect.getLeft(), nn), p_t::BORDER_L);
addPoint(Point(rect.getRight(), nn), p_t::BORDER_R);
}
//Corners
addPoint(rect.getTL(), p_t::BORDER_TL);
addPoint(rect.getTR(), p_t::BORDER_TR);
addPoint(rect.getBL(), p_t::BORDER_BL);
addPoint(rect.getBR(), p_t::BORDER_BR);
}
private:
Rectangle rect;
vector<vector<p_t>> data; //p_t is an enum
//string gfxString = " abcdefghijklmnop"; //This works fine
string gfxString = u8"\u256C\u256C\u256C\u256C\u256C\u256C\u256C\u256C"; //Nope
};
Then attempt to render it with the following, but get gibberish ...
DataGrid p = DataGrid(Rectangle(Point(0,0), 40, 10));
p.addBorder();
cout << p;
If anyone can spot a fix, then that would be great. Thanks for reading.
I'd change gfxString to a vector of std::strings (or even a std::array):
// Probably in the final code, these are not all the same value
std::array<std::string, 8> gfxString = {
{ u8"\u256C"
, u8"\u256C"
, u8"\u256C"
, u8"\u256C"
, u8"\u256C"
, u8"\u256C"
, u8"\u256C"
, u8"\u256C"
}};
Or even just an array of const char*.