QT 5 - load images from the same folder as the stylesheet (.qss) - c++

In my QT app I allowed users to load .qss stylesheets as a custom theme.
This however is problematic since they could not load images in the styles initially.
After a bit of digging it happens that relative paths in the stylesheet are resolved towards the current working dir, and not towards the stylesheet path (which QT cannot know since we load it as a string).
So the only "hack" that I could come up with is to change the current working path to the folder where the stylesheet is located, like so:
if (KreatorSettings::instance().customTheme().isNull() == false) {
QString qsFileName(KreatorSettings::instance().customTheme());
QFile qfFile(qsFileName);
if (qfFile.exists()) {
if (qfFile.open(QFile::ReadOnly | QFile::Text)) {
QDir::setCurrent(QFileInfo(qsFileName).absolutePath()); // needed
qApp->setStyleSheet(QLatin1String(qfFile.readAll()));
loadedCustom = true;
}
}
This is an example of how the images are defined in the stylesheet:
QCheckBox::indicator:checked
{
image:url(icon_checkbox_checked.png);
}
This is obviously not the right way, since I need to keep that current working path for the "skin" to work.
Is there a way in qss to use path relative to the stylesheet or some other method to use paths that do not require either embedding resources or changing the current working dir? Maybe we can tell QT what is the stylesheet root folder so it resolves from there? I have no clue, so need your help.
I would hope there is something like in CSS, or else the QT team made some major mistake in the design making the *.qss files unfit for user customization.

Related

How to load multiple font of same familiy

I am writing an application using the Qt framework. In the display, I have to show multiple information, but using different types of font of the same family, Montserrat.
What I have done so far to load the fonts is:
int ultralightid = QFontDatabase::addApplicationFont(":/Montserrat_UltraLight.tff");
QString UltraFont= QFontDatabase::applicationFontFamilies(ultralightid ).at(0);
QFont font1(UltraFont,QFont::Normal);
font1.setPixelSize(50);
int lightid = QFontDatabase::addApplicationFont(":/Montserrat_Light.tff");
QString LightFont= QFontDatabase::applicationFontFamilies(lightid).at(0);
QFont font2(LightFont,QFont::Normal);
font2.setPixelSize(150);
label1->setFont(font1);
label2->setFont(font2);
label1->setText("bla bla");
label2->setText("bla bla");
The font sizes are correct, but the font itself it is not. From what I have noticed (trying with Hairline_Montserrat,Light_Montserrat,UltraLight_Montserrat), it is as if the fonts have a sort of priority. If I declare them all, all the fonts are the Light one, if I comment that font type, all of them are Hairline one, otherwise (last priority) the labels use the ultralight font.
I have tried adding other font type (from other families) and in that case my code works correctly.
If I use
qDebug()<<QFontDatabase::applicationFontFamilies(ultralightid);
qDebug()<<QFontDatabase::applicationFontFamilies(lightid);
both of them print the family "Montserrat".
I use the qrc file and the AUTORCC flag in the CMAKE (it should be similar using qmake) and all the file are uploaded correctly.
Do you know if there is another way to add fonts of the same family? Or is there something I am doing wrong?
Here are the fonts:
https://www.onlinewebfonts.com/download/9d31c906a6cc6064bbe7d33d51058317 light
https://it.allfont.net/download/montserrat-light/ ultralight
This is an old question but I was just struggling with exactly the same problem when trying to load normal, bold, ... versions of a font family in Qt.
I solved the problem (although in a somewhat hacky way) by simply giving each of the ttf files a different family name. I used Typograf, simply open the font, right click to open properties and then click rename. There are probably many other tools that do this too.
You don't need to manage font files from one family separatelly.
I suggest this solution:
Create a folder with all ttf's of the same family.
Load all files from the folder via id = QFontDatabase.addApplicationFont(path)
Collect all font families from these files via QFontDatabase.applicationFontFamilies(id)
Check if only one and desired family is loaded, and the family name is exactly the same as requested, or warn the user about these errors.
Create font object font = QFont(family)
Then for example, font.setItalic(True). If Italic version of family is loaded, it will be used, otherwise it will be created from Regular by QT.

Trouble with getting national characters in QFileDialog working

I'm trying to take start using Qt and decided to poke around this text editor first.
Everything goes fine except some strange behaviour of QFileDialog - I can not manage it to deal with national charset.
Here is what I see when running compiled binary and trying to open file:
I've tried to search the docs and qt wiki in order to get some clues, but there is nothing about i18n that could be readable for newbie like me.
So here is the problem code:
void TextEdit::fileOpen()
{
QString fn = QFileDialog::getOpenFileName(this, tr("Open File..."),
QString(), tr("HTML-Files (*.htm *.html);;All Files (*)"));
if (!fn.isEmpty())
load(fn);
}
I guess I should attach ::fromUtf8() here somehow, but have no understanding of how this should be done.
UPD
Tried to change default locale just as advised:
QLocale curLocale(QLocale("ru_RU"));
QLocale::setDefault(curLocale);
Also tried this variant:
QLocale::setDefault(QLocale(QLocale::Russian, QLocale::RussianFederation));
This did not help, problem persists.

Displaying picture that is not in resources of Qt

I am currently writing an application in Qt, which is basically a warehouse. An application reads CSV, enables user to process it and enables to show picture of each good. I tried displaying picture using QLabel and Pixmap, however nothing happens even though the file is in the same folder and the name provided is exactly as it should be. Is it the resources issue or my code fails somehow? Is there any possibility to display the image without adding it to resources in order to avoid adding many photos manually?
void ImageViewer::viewImage(QString imgName)
{
QString pathWithName = imgName;
pathWithName.append(".jpg");
ui->label->setPixmap( QPixmap(pathWithName) );
ui->label->show();
update();
}
Sorry for any mistakes in post creation or code displaying here- it's my first post.
Edit:
I am adding code from MainWindow (called CsvReader in my project) to how I'm invoking the method viewImage:
void CsvReader::on_imgView_clicked()
{
ImageViewer* img = new ImageViewer(this);
img->setModal(true);
img->exec();
QModelIndex List selInd ui->tableView->selectionModel()->selectedIndexes();
QString id = model->item(selInd.first().row(), 0)->text();
img->viewImage(id);
}
Edit 2:
Solved. Had to change path using QDir:
QDir* directory = new QDir("/home/kokos/Magazyn/photos");
QFileInfo checkFile(*directory, pathWithName);
Thanks in advance,
Kokos
Confirm your file's location and existence first. Add this;
QFileInfo checkFile(pathWithName);
if (checkFile.exists() && checkFile.isFile()) {
// your code
}

cocos2d-x 3.0 - Create sprite by relative path

How can I create a sprite with relative path? I mean I have several folder in Resources directory such as:
sd
hd
....
One of this directories is set as the place where resources should be looked up :
std::vector<std::string> resDirOrders;
if (device is hd)
resDirOrders.push_back("hd")
FileUtils::getInstance()->setSearchResolutionsOrder(resDirOrders);
Now in each of above mentioned directories I have lots of other directories such as:
intro_popup
outro_popup
main_menu
top_bar
ingame
....
In these directories I place the images. And the names of images can collide, as far as I can have coin.png in main_menu, in top_bar in ingame which are different images. Theretofore, I want to be able to create a sprite like this:
Sprite::create("ingame/coin.png");
Sprite::create("top_bar/coin.png");
But it does not work. It just does not find the file coin.png.
How I should solve this issue? I am on Windows with cocos2d-x 3.0, but it should be handled on iOS and Android too.
The folder structure must be like this :
Res/
----hd/
----sd/
----ingame/
----hd/
----sd/
----top_bar/
----hd/
----sd/
You should add the Res folder to the project, and make sure that "Create folder references for any added folders" is checked.
Set the search path and search resolution order:
Size screenSize = Director::getInstance()->getOpenGLView()->getFrameSize();
std::vector<std::string> resDirOrders;
std::vector<std::string> searchPaths = FileUtils::getInstance()->getSearchPaths();
searchPaths.insert(searchPaths.begin(), "Res");
FileUtils::getInstance()->setSearchPaths(searchPaths);
if (screenSize.width > 1024) {
resDirOrders.push_back("hd");
}
else{
resDirOrders.push_back("sd");
}
FileUtils::getInstance()->setSearchResolutionsOrder(resDirOrders);
Then you can create the sprite with Sprite::create("ingame/coin.png");

QFileSystemModel and QTreeView - strange behavior when resetting view

I wrote this on official forums of Qt, but it seems dead, so I am going to copy-paste it here.
I am writing small program for copying files. I use QTreeView and I have inherited from QFileSystemModel, so I was able to add checkboxes to every row in the QTreeView. I also use setNameFilters method connected with QLineEdit, so user can specify what file extensions he wants to display in the QTreeView. I have spotted the following behavior:
1) When I run the program and enter extensions to filter (without touching any node from the QTreeView) everything works fine and files with extensions I have provided are only displayed (and folders of course). When I change the extensions and the view is refreshed, on my "C:/" drive everything is updated and only new set of extensions is displayed. When I expand some other drive that I didn’t touch before, it also shows files correctly.
2) When I run the program and expand let say my "C:/" and "D:/" drives I see all directories and files (expected behavior). Then I write some extensions and the view is refreshed. I expand "C:/" drive and everything works fine, only files with extensions I have provided are displayed. Then I go to "D:/" drive and here is the problem. It displays all files. It ignores the filters I have provided. When I open the "E:/" drive that I have not opened before, the files are filtered correctly as in "C:/" drive.
I have concluded, that this behavior has something to do with setRootPath method, because for my QTreeView only in "C:/" drive the filters are working correctly. All other drives that were expanded before change of filters don’t work. Those not expanded work just fine.
The question is: How to get this working, so after user changes the filters and reset() method is fired, the whole QTreeView is refreshed and not only root path and not-expanded elements? Maybe there exists some root path that have all the drives as children and it will work as expected? Or maybe I should make some virtual folder in the QTreeView called "MyComputer" and set it to be a parent for all the drives? But how to get list of all the available drives?
I hope that what I wrote is clear for you and you can help me to get this working.
Edit:
Adding some code that is relevant. If you need more just ask.
//setting up the model and view
QString rPath = "C:/";
rTree_model = new TreeModel(this); //TreeModel inherits from QFileSystemModel
rTree_model->setRootPath(rPath);
ui->rTree->setModel(rTree_model); //applies the model for the qtreeview (ui->rTree)
//(...)
//action when extensions were provided by user
QString extensions = QString(ui->extensionBox->text()); //gets extensions provided by user
QStringList filters;
if(extensions.length() > 0) {
filters = extensions.split(";", QString::SkipEmptyParts); //splits extensions provided with ';' as separator
rTree_model->setNameFilters(filters); //applies filters
ui->rTree->reset(); //resets the view
}
Try changing your root path to My Computer instead of C:/. It seems to work with QFileSystemModel in Windows 7 x64 and Qt 4.8.2, but I can't guarantee anything for other platforms.
rTree_model = new TreeModel(this);
QString rPath = model->myComputer().toString(); //causes the QFileSystemWatcher to watch every drive?
rTree_model->setRootPath(rPath);
ui->rTree->setModel(rTree_model);