I'm receiving an unexpected behavior in my current project.
I use the DICOM library dcmtk to read information from some dicom files, and Qt to show the images.
During the information extraction, I have to convert fields of the format "<64bit float>\<64 bit float>" (Dicom Tag PixelSpacing). I split into 2 strings at "\" and convert the strings into a double. So far, everything works fine.
Well, almost: whenever I create a QApplication object before I convert the strings to doubles, it gives me integers instead of doubles.
The code looks like this:
// Faulty situation
Database db;
QApplication app(&argc, argv);
db.fill_from_source(source); // here i get ints instead of doubles
// Rearrange code and recompile:
Database db;
db.fill_from_source(source); // now it gets me doubles.
QApplication app(&argc, argv);
// The fill function looks like this (simplified)
void Database::fill_from_source(const Source& source){
string s = source.get_pixel_spacing_string();
vector<string> s2 = split(s, "\\");
// get the double, that should not be integers!
double a = stod(s2[0]);
double b = stod(s2[1]);
}
It confuses me even more, that it does work stepping through the code using QtCreator and GDB. However, when I run the executable, I get integers again.
So I tracked the issue down to the stod operation: I get the right strings out of the DICOM file, but after stod the numbers after the dot are just truncated. Same behavior with stdlib's strtod
Does the QApplication allocation does something with the std::stod function? Since everything happens while runtime, I do not understand how.
Replacing stod with QString::toDouble resolves the issue...
I'am using gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3), GNU ld (GNU Binutils for Ubuntu) 2.24.
Other code dependencies include Eigen3, Boost.Python. The code is built using a CMake project with QtCreator as IDE.
Has anyone an idea where this problem comes from? Is this a Qt bug?
Being one of the DCMTK developers, i.e. the DICOM toolkit you use, I wonder why you don't retrieve the floating point values directly from the DICOM data element "Pixel Spacing", I mean instead of retrieving the entire character string (including the backslash separator) first and then converting its components to individual floating point numbers. That way, there would be no problem at all with the current locale settings.
By the way, because of the locale settings issue we've introduced our own locale-independent OFStandard::atof() helper function :-)
std::stod behaviour depends on the currently installed C locale.
According to cppreference:
During program startup, the equivalent of std::setlocale(LC_ALL, "C"); is executed before any user code is run.
As pointed by #peppe in the comments, during QApplication's construction setlocale(LC_ALL, ""); is called on Unix, thus altering std::stod.
You can store the locale and set it back as follows:
std::string backup(
// pass a null pointer to query the current C locale without modifying it
std::setlocale(LC_ALL, nullptr)
);
QApplication app(&argc, argv);
// restore the locale
std::setlocale(LC_ALL, backup.c_str());
EDIT:
After rereading documentation for QCoreApplication, there is a paragraph about locale settings in detailed description:
On Unix/Linux Qt is configured to use the system locale settings by default. This can cause a conflict when using POSIX functions, for instance, when converting between data types such as floats and strings, since the notation may differ between locales. To get around this problem, call the POSIX function setlocale(LC_NUMERIC,"C") right after initializing QApplication, QGuiApplication or QCoreApplication to reset the locale that is used for number formatting to "C"-locale.
However #J.Riesmeier provided an interessant answer as one of the DCMTK developers.
Related
I work with both operation systems (windows and linux) and in linux (image 1) ElideRight is working well but in windows (image 2) is not working well. (...) supposed to be "a" instead.
I use the code below for "Eliding".
Also you need to know, this is happening in QListView.
ui->geometry_list->setTextElideMode(Qt::ElideRight);
I tried to reproduce OPs issue with the following MCVE testQListViewElide.cc:
// Qt header:
#include <QtWidgets>
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QApplication app(argc, argv);
// setup GUI
QListWidget qLst;
qLst.resize(200, 200);
qLst.setTextElideMode(Qt::ElideRight);
qLst.addItem(QString("A very long item text to make the elide feature visible"));
qLst.show();
// runtime loop
return app.exec();
}
My platform is Visual Studio 2019 on Windows 10.
Output:
Qt Version: 5.15.1
There are in fact no ellipses. However… Please, note the horizontal scrollbar.
So, I added one line to switch the scrollbar off:
qLst.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Output:
So, this is working in Windows in general. (I would have been surprised if not.)
The claim of OP that an à is shown instead of ellipses made me a bit suspicious. This could be a sign for encoding problems. However, as Qt is using Unicode in QString such issues are unlikely. (I never experienced such issues while developing with Qt in Windows in daily business.)
Just, out of curiosity, I compared the Windows 1252 encoding of à (224 = 0xE0) with the Unicode of ellipses (U+2026), in UTF-8 encoding: e2 80 a6, in UTF-16 encoding: 26 20 (LE) or 20 26 (BE).
This doesn't look like a mis-interpreted encoding – at least, no obvious. However, to sort this out, OP had to provide a little bit more info like e.g. an MCVE which makes the issue reproducible.
(Thus, OP could use my MCVE whether it reproduces the issue on OPs platform.)
I suspect that this an encoding problem but happening while the item texts are stored in QStrings. It's just the list view which exposes the broken item text. Thereby, consider that it's very likely that strings retrieved in Linux are already in UTF-8 encoding. If a QString is assigned from a std::string, UTF-8 encoding is assumed as well. (QString::fromStdString()).
This is different in Windows where the internal encoding is UTF-16 but these ANSI flavors of system functions (with different meanings of character values depending on current code page) are still available (which are always good for any encoding damage).
glfwSetWindowTitle(win, "Nämen");
Becomes "N?men", where '?' is in a little black, twisted square, indicating that the character could not be displayed.
How do I display 'ä'?
If you want to use non-ASCII letters in the window title, then the string has to be utf-8 encoded.
GLFW: Window title:
The window title is a regular C string using the UTF-8 encoding. This means for example that, as long as your source file is encoded as UTF-8, you can use any Unicode characters.
If you see a little black, twisted square then this indicates that the ä is encoded with some iso encoding that is not UTF-8, maybe something like latin1. To fix this you need to open it in the editor in which you can change the encoding of the file, change it to uft-8 (without BOM) and fix the ä in the title.
It seems like the GLFW implementation does not work according to the specification in this case. Probably the function still uses Latin-1 instead of UTF-8.
I had the same problem on GLFW 3.3 Windows 64 bit precompiled binaries and fixed it like this:
SetWindowTextA(glfwGetWin32Window(win),"Nämen")
The issue does not lie within GLFW but within the compiler. Encodings are handled by the major compilers as follows:
Good guy clang assumes that every file is encoded in UTF-8
Trusty gcc checks the system's settings1 and falls back on UTF-8, when it fails to determine one.
MSVC checks for BOM and uses the detected encoding; otherwise it assumes that file is encoded using the users current code page2.
You can determine your current code page by simply running chcp in your (Windows) console or PowerShell. For me, on a fresh install of Windows 11, it yields "850" (language: English; keyboard: German), which stands for Code Page 850.
To fix this issue you have several solutions:
Change your systems code page. Arguably the worst solution.
Prefix your strings with u8, escape all unicode literals and convert the string to wide char before passing Win32 functions; e.g.:
const char* title = u8"\u0421\u043b\u0430\u0432\u0430\u0020\u0423\u043a\u0440\u0430\u0457\u043d\u0456\u0021";
// This conversion is actually performed by GLFW; see footnote ^3
const int l = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
wchar_t* buf = _malloca(l * sizeof(wchar_t));
MultiByteToWideChar(CP_UTF8, 0, title, -1, buf, l);
SetWindowTextW(hWnd, buf);
_freea(buf);
Save your source files with UTF-8 encoding WITH BOM. This allows you to write your strings without having to escape them. You'll still need to convert the string to a wide char string using the method seen above.
Specify the /utf-8 flag when compiling; this has the same effect as the previous solution, but you don't need the BOM anymore.
The solutions stated above still require you convert your good and nice string to a big chunky wide string.
Another option would be to provide a manifest4 with the activeCodePage set to UTF-8. This way all Win32 functions with the A-suffix (e.g. SetWindowTextA) now accept and properly handle UTF-8 strings, if the running system is at least or newer than Windows Version 1903.
TL;DR
Compile your application with the /utf-8 flag active.
IMPORTANT: This works for the Win32 APIs. This doesn't let you magically write Unicode emojis to the console like a hipster JS developer.
1 I suppose it reads the LC_ALL setting on linux. In the last 6 years I have never seen a distribution, that does NOT specify UTF-8. However, take this information with a grain of salt; I might be entirely wrong on how gcc handles this now.
2 If no byte-order mark is found, it assumes that the source file is encoded in the current user code page [...].
3 GLFW performs the conversion as seen here.
4 More about Win32 ANSI-APIs, Manifest and UTF-8 can be found here.
I downloaded and studied a code in C++, where Caffe and OpenCV are used for Face Recognition. At the moment, the code is written as a Console Application, that opens a window with the "Livestream" of the webcam and the face recognition.
Now i read that if I want to add the program to WPF, I need to make the C++ part a DLL, that gets implemented into C#. But my problem atm is this code:
int init(int argc, const char** argv)
{
char acUserName[100];
string UserName;
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName)) {
UserName = acUserName;
string errorPath = "C:/Users/" + UserName + "/Desktop/ErrorLog.txt";
const char *errorChars = errorPath.c_str();
...
}
I found this code for getting the current username in c++, the init method is actually the main, just with a new name. But when I type this code in my DLL-version, Visual Studio gives the Error
argument of type "char*" is incompatible with parameter of type "LPWSTR"
and the "acUserName" in
if (GetUserName(acUserName, &nUserName))
is marked. How can I fix this?
(I'm beginner in C++, if you guys need more code, tell me)
It sounds like charset error.try to change charset to multibyte in VisualStudio Project Setting.
There are wide-string and ASCII versions for API functions, which have 'W' or 'A' appended to the function name respectively. The GetUserName uses the wide-string variant by default.
If you don't care about Multibyte character strings, you can use GetUserNameA, with the parameters: &UserName[0] and the predefined length of the string.
However if you do, then just change the type of UserName to a wstring, and then pass the parameters to the function in the same way. Don't forget to include 'wstring.h' as well.
I am having trouble with printing out korean.
I have tried various methods with no avail.
I have tried
1.
cout << "한글" << endl;
2.
wcout << "한글" << endl;
3.
wprintf(L"한글\n");
4.
setlocale(LC_ALL, "korean");
wprintf("한글");
and more. But all of those prints "한글".
I am using MinGW compiler, and my OS is windows 7.
P.S Strangely Java prints out Korean fine,
String kor = "한글";
System.out.println(kor);
works.
Set the console codepage to utf-8 before printing the text
::SetConsoleOutputCP(65001)
Since you are using Windows 7 you can use WriteConsoleW which is part of the windows API. #include <windows.h> and try the following code:
DWORD numCharsToWrite = str.length();
LPDWORD numCharsWritten = NULL;
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str.c_str(), numCharsToWrite, numCharsWritten, NULL);
where str is the is a std::wstring
More on WriteConsoleW: https://msdn.microsoft.com/en-us/library/windows/desktop/ms687401%28v=vs.85%29.aspx
After having tried other methods this worked for me.
Problem is that there are a lot of places where this could be broken.
Here is answer I've posted some time ago (covers Korean). Answear is for MSVC, but same applies to MinGW (compiler switches are different, locale name may be different).
Here are 5 traps which makes this hard:
Source code encoding. Source has to use encoding which supports all required characters. Nowadays UTF-8 is recommended. It is best to make sure your editor (IDE) is properly configure to enforce source encoding.
You have to inform compiler what is encoding of source file. For gcc it is: -finput-charset=utf-8 (it is default)
Encoding used by executable. You have to define what kind of encoding string literals should be encode in final executable. This encoding should also cover required characters. Here UTF-8 is also the best. Gcc option is -fexec-charset=utf-8
When you run application you have to inform standard library what kind of encoding your string literals are define in or what encoding in program logic is used. So somewhere in your code at beginning of execution you need something like this (here UTF-8 is enforced):
std::locale::global(std::locale{".utf-8"});
and finally you have to instruct stream what kind of encoding it should use. So for std::cout and std::cin you should set locale which is default for the system:
auto streamLocale = std::locale{""};
// this impacts date/time/floating point formats, so you may want tweak it just to use sepecyfic encoding and use C-loclae for formating
std::cout.imbue(streamLocale);
std::cin.imbue(streamLocale);
After this everything should work as desired without code which explicitly does conversions.
Since there are 5 places to make mistake, this is reason people have trouble with it and internet is full of "hack" solutions.
Note that if system is not configured for support all needed characters (for example wrong code page is set) then with thsi configuration characters which could not be converted will be replaced with question mark.
I have a very basic question: how can I enforce the use of points in floating-point numbers instead of a comma (I have a french version of my OS) in Qt?
Other question :is it possible to display numbers with space for thousands separators?
Try this:
QLocale loc = QLocale::system(); // current locale
loc.setNumberOptions(QLocale::c().numberOptions()); // borrow number options from the "C" locale
QLocale::setDefault(loc); // set as default
If you want all of the options as in the "C" locale, you can simply do
QLocale::setDefault(QLocale::c());
Regarding your second question: Qt does not support custom locales, but you can try setting the number options to, say, Hungary's locale (it should produce 1234 and 12 345.67 - I haven't tried it myself)
QLocale loc = QLocale::system(); // current locale
QLocale hungary(QLocale::Hungarian);
loc.setNumberOptions(hungary.numberOptions()); // borrow number options from the Hungarian locale
QLocale::setDefault(loc); // set as default
For Linux:
Since I live in Germany but want my system to use english messages, I have a mixed locale on my PC:
LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=de_DE.UTF-8
LC_TIME=de_DE.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=de_DE.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=de_DE.UTF-8
LC_NAME=de_DE.UTF-8
LC_ADDRESS=de_DE.UTF-8
LC_TELEPHONE=de_DE.UTF-8
LC_MEASUREMENT=de_DE.UTF-8
LC_IDENTIFICATION=de_DE.UTF-8
LC_ALL=
This caused some trouble with the representation of numbers.
Because I was new to QLocale and was on a time budget, I used a simple hack to "fix" the problem temporarily and it worked quite well for me:
int main(int argc, char *argv[]) {
// make numbers predictable
// a preliminary hack. Will be fixed with native language support
setenv("LC_NUMERIC", "C",1);
QApplication a(argc, argv);
...
This had the advantage, that numbers got unified in both, on-screen presentation and reading and writing from and to persistent storage. The latter one was the biggest issue as e.g. floats got written like '123,45' instead of '123.45'.
Not a native solution, but a viable trick to get ahead for the time being.
Just to be complete: The application was just for myself. So this trick does of course not claim any professionality.