qt "resource" string - string

I am wanting to have a place where i can store all the strings used in my applicaton, so i can modify them in one place and not all the places. Something like a resource file, where i can put a label on the strings and just call the label.
I am not aware of anything offered by QT for this, so would I just need to create a header file with all those strings and include it everywhere I need it? What is the appropriate way to do this and could you offer a small example?
Thanks!!

I haven't used it yet, but I think, that the Qt Internationalization would allow you to do something like this, since one of it's options is to take all strings out of the application code so they can be replaced by translations. Even if you don't want to use any other features of this module, it would allow you to solve your problem. Replacing a string for a label would look like this:
QLabel *label = new QLabel(tr("Password:"));
The tr() function is already part of the Qt classes and you get a few more functions and macros for free that help to search and replace strings.
The strings to be replaced can then be managed with QtLinguist.
You can find a more detailed explanation here: Internationalization with Qt

In the old days[1], when using Windows resources, people have been using:
// in your project_strings.h file
#define STRING_PASSWORD 1
...
// resources project.rc
#include "project_strings.h"
STRINGTABLE
BEGIN
STRING_PASSWORD "Password:"
...
END
// in some other file
#include "project_strings.h"
CString str(STRING_PASSWORD);
The CString knew about windows resources (ugly dependency) and could go and read the string password. The #define is definitively very ugly in modern C++, but resources would not understand a static const variable or an inline function.
The easiest way to replicate this in a somewhat similar way is to use a header file with string declarations and then reference those strings anywhere you need them.
// in your project_strings.h
namespace MyProjectStrings {
const char *password;
...
}
// the project_strings.cpp for the strings
#include "project_strings.h"
namespace MyProjectStrings {
const char *password = "Password:";
...
}
// some random user who needs that string
#include "project_strings.h"
std::string password(MyProjectStrings::password);
Now all your strings are in project_strings.cpp and you cannot as easily translate them with tr()... but you could transform all those strings declarations with functions:
// in your project_strings.h
namespace MyProjectStrings {
const char *password(); //[2]
...
}
// the project_strings.cpp for the strings
#include "project_strings.h"
namespace MyProjectStrings {
const char *password() { return QObject::tr("Password:"); }
...
}
// some random user who needs that string
#include "project_strings.h"
std::string password(MyProjectStrings::password()); //[3]
And VoilĂ ! You have a single long table of all your strings in one place and translatable.
[1] Many people still use that scheme!
[2] The function could return std::string to 100% prevent modifying the original.
[3] In this last example the string reference uses () since it's a function call.

Related

Multi-line wide string constant that allows single line comments in C++

This question of how to break up a (wide) string constant along multiple lines in code has been asked and answered multiple times on this platform (here, for example). I have been using the following approach to declare a static wide string in the class definition itself:
#include <Windows.h>
#include <iostream>
class Test
{
public:
static constexpr WCHAR TEST[] = L"The quick brown fox" \
L"jumped over the" \
L"lazy dog!";
/* ... */
};
int main ()
{
wprintf(Test::TEST);
return 1;
}
However, this approach does not work very well if you want to start commenting each line of your multi-line string. The only way you can achieve this is if you stick a multi-line comment in between the string and the backslash (\) like so:
class Test
{
public:
static constexpr WCHAR TEST[] = L"The quick brown fox" /* A comment */\
L"jumped over the" /* Another comment*/\
L"lazy dog!";
/* ... */
};
If you put a comment after the backslash (\), then a compiler error is raised. This means, you cannot use the traditional single line comment (//) with this method. As a matter of fact, if you put a single space after the backslash (\), then a compiler error is generated.
My question is as follows, is there a way to declare a wide string over multiple lines where you can use single line comments (//) to comment each line?
I am idling looking for something like this (similar to Java):
static constexpr ... = L"The quick brown fox" + // A little comment here...
L"jumped over the" + // A little comment there.
L"lazy dog!";
I understand things are incredibly different in Java (i.e. namely everything is an object), but I am just giving this as an example of what I am after.
Simply drop the backslashes:
static constexpr WCHAR TEST[] = L"The quick brown fox" // a comment
L"jumped over the" // another comment
L"lazy dog!"; // yet another comment
Comments are replaced by space characters in translation phase 3. Adjacent string literals are concatenated in translation phase 6.

Is there a way to make this crossplatform?

Im trying to get rid of a platform dependent code.
This code gets a string formated by a mask ("%Y-%m-%d %H:%M:%S") and convert it to std::tm struct and a std::time seconds.
I want to get rid of the need of preprocessor dependant blocks, as (imho) there must be a standard way of doing it in both platforms in the same way.
strptime does not exists in windows, std::get_time does not exists(?) on linux (g++ c++11).
Is there any way to make this code crossplatform (windows/linux) without using a factory pattern or preprocessor dependant blocks?
KDATETIME& KDATETIME::operator= (const char* k)
{
std::string smask;
smask = (std::string)this->mask;
std::string sk;
sk=k;
tm.tm_isdst=-1;
#ifdef WINDOWS <<---- THIS BLOCK
std::istringstream ss(sk);
ss >> std::get_time(&tm, smask.c_str());
#else
strptime(sk.c_str(), smask.c_str(), &tm);
#endif <<------
this->time = mktime(&tm); // t is now your desired time_t
[...]
}

C++ override quotes

Ok, so I'm using C++ to make a library that'd help me to print lines into a console.
So, I want to override " "(quote operators) to create an std::string instead of the string literal, to make it easier for me to append other data types to that string I want to output.
I've seen this done before in the wxWidgets with their wxString, but I have no idea how I can do that myself.
Is that possible and how would I go about doing it?
I've already tried using this code, but with no luck:
class PString{
std::string operator""(const char* text, std::size_t len) {
return std::string(text, len);
}
};
I get this error:
error: expected suffix identifier
std::string operator""(const char* text, std::size_t len) {
^~
which, I'd assume, want me to add a suffix after the "", but I don't want that. I want to only use ""(quotes).
Thanks!
You can't use "" without defining a suffix. "" is a const char* by itself either with a prefix (like L"", u"", U"", u8"", R"()") or followed by suffixes like (""s, ""sv, ...) which can be overloaded.
The way that wxString works is set and implicit constructor wxString::wxString(const char*); so that when you pass "some string" into a function it is essentially the same as wxString("some string").
Overriding operator ""X yields string literals as the other answer.

When does using RNGScope make a difference?

In Rcpp documentation, I often find the recommendation to place Rcpp::RNGScope scope; before using random draws within Rcpp. I wondered what exactly this does, because I've only ever seen it described as "ensures RNG state gets set/reset".
Then, I tested a bit, but I can't seem to come up with an example where doing this makes any difference. I used an example from here. My tests were:
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector noscope() {
Rcpp::Function rt("rt");
return rt(5, 3);
}
// [[Rcpp::export]]
NumericVector withscope() {
RNGScope scope;
Rcpp::Function rt("rt");
return rt(5, 3);
}
and then
set.seed(45)
noscope() # [1] 0.6438 -0.6082 -1.9710 -0.1402 -0.6482
set.seed(45)
withscope() # [1] 0.6438 -0.6082 -1.9710 -0.1402 -0.6482
set.seed(45)
rt(5, 3) # [1] 0.6438 -0.6082 -1.9710 -0.1402 -0.6482
So, my question is twofold. First, when does RNGScope make a difference, and what exactly does it do different from not using it? Second, does anyone have a code example which shows different results with and without it?
If RNGScope was deprecated in a newer release, then I'm sorry for asking.
When using Rcpp attributes, the automagically generated interface to your code will automatically insert the appropriate construction of the RNGScope object -- so it's already being done for you behind the scenes in this case. For example, if you write sourceCpp(..., verbose = TRUE), you'll see output like this:
Generated extern "C" functions
--------------------------------------------------------
#include <Rcpp.h>
RcppExport SEXP sourceCpp_38808_timesTwo(SEXP xSEXP) {
BEGIN_RCPP
Rcpp::RObject __result;
Rcpp::RNGScope __rngScope;
Rcpp::traits::input_parameter< NumericVector >::type x(xSEXP);
__result = Rcpp::wrap(timesTwo(x));
return __result;
END_RCPP
}
Note the automatic construction of the RNGScope object.
You only need to construct that object manually if you are operating outside of the realm of Rcpp attributes.
This all becomes a little clearer once you read the original documentation in the Writing R Extensions manual, Section 6.3, "Random Numbers".
All that RNGScope scope does is the automagic calls to "get" and "put" in order to keep the state of the RNG sane.
The problem with your test code, as explained by Kevin, is that it already happens for you. So you can only test by going through .Call() by hand, in which case you will for sure leave the RNG in a mess if you use it and do not get/put properly.

Listing files in directory

I have created a windows form in c++ which, upon a button click, opens a dialog box for folder selection.
Now what I would like to do is get the list of files in that directory so that I can process them one by one.
I have googled it in many ways, and found many ways which include external libraries (such as boost and diren.h). I would not like to use external resources, but the ones at my disposal, the default ones.
I've read about FindFirstFile and FindNextFile, but couldnt get that combination to work.
Could you please assist?
Thanks a lot,
Idan.
Here is the updated code:
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
FolderBrowserDialog^ folderBrowserDialog1 = gcnew FolderBrowserDialog;
if (folderBrowserDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)
{
String ^ selected = folderBrowserDialog1->SelectedPath;
selected += "\\*";
char* stringPointer = (char*) Marshal::StringToHGlobalAnsi(selected).ToPointer();
hFind = FindFirstFile((LPCWSTR)stringPointer, &FindFileData);
while(hFind != INVALID_HANDLE_VALUE)
{
printf("Found file: %s\r\n", FindFileData.cFileName);
if(FindNextFile(hFind, &FindFileData) == FALSE)
break;
}
}
You obviously compile for UNICODE (wide char) since you need to cast the newStr for the lpFileName parameter of FindFirstFile. But since you pass an ANSI string, you probable won't get a useful result. Youd didn't write, what you expect to find.
In the code beforer FindFirstFile you manually convert the SelectedPath value to ANSI char. That makes no sense, when you need a wide char string anyway. Get the LPCWSTR from the String selected with the StringToHGlobalUni method. This looks somehow like this (not tested):
LPCWSTR stringPointer = Marshal::StringToHGlobalAnsi(selected).ToPointer();
hFind = FindFirstFile(stringPointer, &FindFileData);
In general: Don't use casts except when you need to adapt a bad designed interface. Use it only when you know exactly what you are doing.
Further you don't check the hFind result of FindFirstFile. It will be INVALID_HANDLE_VALUE if you pass a pointer to the wrong string format.

Resources